239 lines
5.7 KiB
ObjectPascal

unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls,
BGRABitmap, BGRAAnimatedGif, LCLType, StdCtrls;
type
{ TGifAnimationPanel }
TGifAnimationPanel = class(TPanel)
private
FOnRenderFrame: TNotifyEvent;
procedure SetImage(AValue: TBGRAAnimatedGif);
procedure SetOnRenderFrame(AValue: TNotifyEvent);
protected
FImage: TBGRAAnimatedGif;
FFirstPaint, FAnimatePaint: boolean;
FTimer: TTimer;
procedure Paint; override;
procedure EraseBackground(DC: HDC); override;
procedure ImageChanged(Sender: TObject);
procedure TimerTimer(Sender: TObject);
public
constructor Create(TheOwner: TComponent); override;
destructor Destroy; override;
property Image: TBGRAAnimatedGif read FImage;
property OnRenderFrame: TNotifyEvent read FOnRenderFrame write SetOnRenderFrame;
end;
{ TForm1 }
TForm1 = class(TForm)
SaveDialog1: TSaveDialog;
Timer1: TTimer;
Panel1: TPanel;
Label1: TLabel;
Label2: TLabel;
Button1: TButton;
Button2: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDropFiles(Sender: TObject; const FileNames: array of string);
protected
{ private declarations }
procedure GifAnimationPanelRenderFrame(Sender: TObject);
public
{ public declarations }
filename, error: string;
animationPanel: TGifAnimationPanel;
procedure LoadImage(AFilename: string);
procedure FillMemo;
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TGifAnimationPanel }
constructor TGifAnimationPanel.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
FFirstPaint:= true;
FAnimatePaint:= false;
BevelInner:= bvNone;
BevelOuter:= bvNone;
FImage := TBGRAAnimatedGif.Create;
FImage.OnChange := @ImageChanged;
FTimer := TTimer.Create(self);
FTimer.Enabled := false;
FTimer.OnTimer := @TimerTimer;
end;
destructor TGifAnimationPanel.Destroy;
begin
inherited Destroy;
end;
procedure TGifAnimationPanel.SetImage(AValue: TBGRAAnimatedGif);
begin
FImage.Free;
end;
procedure TGifAnimationPanel.SetOnRenderFrame(AValue: TNotifyEvent);
begin
if FOnRenderFrame=AValue then Exit;
FOnRenderFrame:=AValue;
end;
procedure TGifAnimationPanel.Paint;
var
waitTime: Integer;
begin
inherited Paint;
if FFirstPaint or not FAnimatePaint then
begin
Canvas.Brush.Assign(Brush);
Canvas.FillRect(ClientRect);
image.BackgroundMode := gbmEraseBackground;
image.EraseColor:= Color;
if Assigned(FImage) and (FImage.Count > 0) then
FImage.Show(Canvas, ClientRect);
end else
begin
if Assigned(FImage) and (FImage.Count > 0) then
FImage.Update(Canvas, ClientRect);
end;
FAnimatePaint := false;
FFirstPaint := false;
if Assigned(FOnRenderFrame) then
FOnRenderFrame(self);
if Assigned(FImage) and (FImage.Count > 1) then
begin
waitTime := Image.TimeUntilNextImageMs;
if waitTime < 15 then waitTime := 15;
FTimer.Interval := waitTime;
FTimer.Enabled := true;
end;
end;
procedure TGifAnimationPanel.EraseBackground(DC: HDC);
begin
// don't erase background
end;
procedure TGifAnimationPanel.ImageChanged(Sender: TObject);
begin
FTimer.Enabled:= false;
Invalidate;
end;
procedure TGifAnimationPanel.TimerTimer(Sender: TObject);
begin
FTimer.Enabled := false;
FAnimatePaint := true;
Refresh;
end;
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
begin
animationPanel := TGifAnimationPanel.Create(self);
animationPanel.OnRenderFrame := @GifAnimationPanelRenderFrame;
animationPanel.Left := 4;
animationPanel.Top := 4;
animationPanel.Color:= self.Color;
InsertControl(animationPanel, 0);
LoadImage(ConcatPaths([ExtractFilePath(Application.ExeName), 'waterdrops.gif']));
FillMemo;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
animationPanel.Refresh;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
try
if SaveDialog1.Execute then
animationPanel.Image.SaveToFile(SaveDialog1.FileName);
except
on ex: exception do
begin
error := ex.Message;
FillMemo;
end;
end;
end;
procedure TForm1.FormDropFiles(Sender: TObject; const FileNames: array of string);
begin
LoadImage(FileNames[0]);
end;
procedure TForm1.GifAnimationPanelRenderFrame(Sender: TObject);
begin
Label1.Caption := 'Frame: ' + inttostr(animationPanel.image.CurrentImage) +
', Wait: ' + inttostr(animationPanel.Image.TimeUntilNextImageMs);
end;
procedure TForm1.LoadImage(AFilename: string);
begin
filename := AFilename;
try
if not FileExists(filename) then
begin
animationPanel.Image.Clear;
error := 'Not found';
end else
begin
animationPanel.Image.LoadFromFile(filename);
error := 'Ok';
end;
except
on ex:Exception do
error := ex.Message;
end;
animationPanel.Width := animationPanel.Image.Width;
animationPanel.Height := animationPanel.Image.Height;
FillMemo;
end;
procedure TForm1.FillMemo;
var s: string;
i: Integer;
begin
with animationPanel do
begin
s := error + LineEnding +
ExtractFileName(filename) + LineEnding +
inttostr(image.Width)+'x'+inttostr(image.height) + LineEnding +
inttostr(image.Count)+' frames' + LineEnding;
if image.LoopCount = 0 then
s += 'infinite loop' + LineEnding
else
s += inttostr(image.LoopCount)+' loops' + LineEnding;
for i := 0 to image.Count-1 do
s += '#' + inttostr(i)+': '+inttostr(image.FrameDelayMs[i])+' ms, '+
inttostr(image.FrameImage[i].Width)+'x'+inttostr(image.FrameImage[i].Height) + LineEnding;
end;
Memo1.Text := s;
end;
end.