6

around png image appears strange rectangle on Load image or when image is moved.

Rectangle appears rarely in 24bit PNG, or jpg, but with 32bit PNG is problem. Does anyone know what causes it? PNG are created in Photoshop. I tried also gimp but same problem.

24BitPNG-BetterResult

32BitPNG-BAD-BUG

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, pngimage, jpeg, ExtCtrls, StdCtrls;

type
  TForm1 = class(TForm)
    Image1: TImage;
    Image2: TImage;
    Timer1: TTimer;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Label1: TLabel;
    procedure Timer1Timer(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure Button4Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  png:TPngImage;
  rs:TResourceStream;
  ms:TMemoryStream;

implementation

{$R *.dfm}
{$R FB.RES}

procedure TForm1.Button1Click(Sender: TObject);
begin
 rs:=TResourceStream.Create(hInstance,'24bitpng',RT_RCDATA);
 png:=TPngImage.Create;
 png.LoadFromStream(rs);
 Image1.Picture.Graphic:=png;
 rs.Free;
 Label1.Caption:=Button1.Caption;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 rs:=TResourceStream.Create(hInstance,'32bitpng',RT_RCDATA);
 png:=TPngImage.Create;
 png.LoadFromStream(rs);
 Image1.Picture.Graphic:=png;
 rs.Free;
 Label1.Caption:=Button2.Caption;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
Form1.Close;
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
Timer1.Enabled:=True;
Image2.Left:=0;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
DoubleBuffered:=True;  //This did the job, now no flickering around

Form1.BorderStyle:=bsnone;
Form1.Position:=poScreenCenter;
Label1.Caption:=Button1.Caption;
end;

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
    Screen.Cursor:=crSizeAll;
    ReleaseCapture;
    SendMessage(Form1.Handle, WM_SYSCOMMAND, 61458, 0) ;
    Screen.Cursor:=crDefault;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
 if image2.Left<300 then
 image2.Left:=image2.Left+2
 else
 Timer1.Enabled:=False;

end;

end.

This i tried.

...
protected
    procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;

...

begin

procedure TForm1.WMEraseBkgnd(var Message: TWMEraseBkgnd);
begin
  Message.Result := 1;
end;


end.
Nafalem
  • 261
  • 5
  • 16
  • 4
    You simply should **not** do animations by moving VCL controls around! Instead, draw manually using GDI in `OnPaint`. [Examples](http://stackoverflow.com/a/16948704/282848) – Andreas Rejbrand Mar 11 '14 at 13:09
  • here is source + compiled binary https://www.copy.com/s/FSczlwV4C0X0NEi6/FootBall-PNG.rar – Nafalem Mar 11 '14 at 13:09
  • Set DoubleBuffered on the form. Or implement your own off screen processing. – Sertac Akyuz Mar 11 '14 at 13:11
  • Andreas is correct. Render the background in response to `WM_ERASEBKGND`, and the foreground in response to `WM_PAINT`. – David Heffernan Mar 11 '14 at 13:11
  • @SertacAkyuz You should not need to double buffer. If you do it right. – David Heffernan Mar 11 '14 at 13:12
  • 1
    @David - DoubleBuffering, or in general, off screen image rendering is not wrong. Although it may not be desirable sometimes, I don't think this would be one case. You are not supposed to play kick-off in a terminal session after all. – Sertac Akyuz Mar 11 '14 at 13:17
  • @SertacAkyuz There are times when off screen rendering is good. I do so myself in my app. But my instincts tell me that this animation can be flicker free without the extra overhead of off screen rendering. – David Heffernan Mar 11 '14 at 13:20

1 Answers1

4

Your basic approach is flawed. You are not expected to use TImage controls to show animations. These controls are designed for displaying static images. As a crude solution you could enable double buffering for the form. Do this by setting DoubleBuffered to True. This has side-effects that may be undesirable. In any case, the entire approach should make you feel queasy.

The right approach is to render the entire image to a drawing surface. In an ideal world you would have a single windowed control that rendered the background in response to WM_ERASEBKGND, and then painted the dynamic content in response to WM_PAINT. This is what I would do.

As a simpler half way house you could use a TPaintBox or perhaps even the form's OnPaint handler. These approaches would have you painting the entire image in response to WM_PAINT. That should be free of flicker. If not then perhaps you'll need to resort to painting to an off-screen bitmap and then blitting that to the paint surface.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • I tried WM_ERASEBKGND first but it does a black backgrond around i need custom shape form http://i.imgur.com/lHL3WEq.jpg, then i set DoubleBuffered:=True; now no flickering around – Nafalem Mar 11 '14 at 14:08
  • @Nafelem You did not implement a handler for WM_ERASEBKGND correctly. You've rejected that approach for erroneous reasons. On the other hand, unless you are experienced in Win32 it's going to be hard for you to go that way. Double buffered is fine is you can stand feeling a bit queasy. – David Heffernan Mar 11 '14 at 14:11
  • I tried implement a handler for WM_ERASEBKGND (edited code above). – Nafalem Mar 11 '14 at 14:19
  • You are meant to render the background in response to `WM_ERASEBKGND`. That's what I said in the answer. I'm not sure you've really understood my point. The idea is the second part of the answer, beginning with *"the right approach"* is that you throw away what you currently have. Get rid of the two `TImage` controls. And paint directly onto a windowed control. – David Heffernan Mar 11 '14 at 14:22