2
0
Эх сурвалжийг харах

UPD: Use GifView component instead GifAnim (fixes #814)

Alexander Koblov 2 сар өмнө
parent
commit
ceb271de20

+ 1 - 1
components/build.bat

@@ -13,7 +13,7 @@ lazbuild doublecmd\doublecmd_common.lpk %DC_ARCH%
 lazbuild Image32\Image32.lpk %DC_ARCH%
 lazbuild Image32\Image32.lpk %DC_ARCH%
 lazbuild KASToolBar\kascomp.lpk %DC_ARCH%
 lazbuild KASToolBar\kascomp.lpk %DC_ARCH%
 lazbuild viewer\viewerpackage.lpk %DC_ARCH%
 lazbuild viewer\viewerpackage.lpk %DC_ARCH%
-lazbuild gifanim\pkg_gifanim.lpk %DC_ARCH%
+lazbuild gifview\gifview.lpk %DC_ARCH%
 lazbuild synunihighlighter\synuni.lpk %DC_ARCH%
 lazbuild synunihighlighter\synuni.lpk %DC_ARCH%
 lazbuild virtualterminal\virtualterminal.lpk %DC_ARCH%
 lazbuild virtualterminal\virtualterminal.lpk %DC_ARCH%
 popd
 popd

+ 1 - 1
components/build.sh

@@ -31,7 +31,7 @@ $lazbuild doublecmd/doublecmd_common.lpk $DC_ARCH
 $lazbuild Image32/Image32.lpk $DC_ARCH
 $lazbuild Image32/Image32.lpk $DC_ARCH
 $lazbuild KASToolBar/kascomp.lpk $DC_ARCH
 $lazbuild KASToolBar/kascomp.lpk $DC_ARCH
 $lazbuild viewer/viewerpackage.lpk $DC_ARCH
 $lazbuild viewer/viewerpackage.lpk $DC_ARCH
-$lazbuild gifanim/pkg_gifanim.lpk $DC_ARCH
+$lazbuild gifview/gifview.lpk $DC_ARCH
 $lazbuild synunihighlighter/synuni.lpk $DC_ARCH
 $lazbuild synunihighlighter/synuni.lpk $DC_ARCH
 $lazbuild virtualterminal/virtualterminal.lpk $DC_ARCH
 $lazbuild virtualterminal/virtualterminal.lpk $DC_ARCH
 cd $basedir
 cd $basedir

+ 0 - 370
components/gifanim/doublecmd.diff

@@ -1,370 +0,0 @@
-Index: gifanim.pas
-===================================================================
---- gifanim.pas	(revision none)
-+++ gifanim.pas	(working copy)
-@@ -26,7 +26,7 @@
- 
- uses
-   Classes, LCLProc, Lresources, SysUtils, Controls, Graphics, ExtCtrls,
--  IntfGraphics, FPimage, Contnrs, GraphType, dialogs;
-+  IntfGraphics, FPimage, Contnrs, GraphType, dialogs, types;
- 
- const
- 
-@@ -193,7 +193,7 @@
-     procedure DoAutoSize; override;
-     procedure DoStartAnim;
-     procedure DoStopAnim;
--    class function GetControlClassDefaultSize: TPoint; override;
-+    class function GetControlClassDefaultSize: TSize; override;
-     procedure GifChanged;
-     procedure LoadFromFile(const Filename: string); virtual;
-     procedure Paint; override;
-@@ -203,6 +203,8 @@
-     { Public declarations }
-     constructor Create(AOwner: TComponent); override;
-     destructor Destroy; override;
-+    procedure NextFrame;
-+    procedure PriorFrame;
-     property Empty: boolean Read FEmpty;
-     property GifBitmaps: TGifList Read FGifBitmaps;
-     property GifIndex: integer Read FCurrentImage;
-@@ -237,28 +239,9 @@
- 
- implementation
- 
--uses LazIDEIntf, propedits;
--Type
--  TGifFileNamePropertyEditor=class(TFileNamePropertyEditor)
--  protected
--    function GetFilter: String; override;
--    function GetInitialDirectory: string; override;
--  end;
--function TGifFileNamePropertyEditor.GetFilter: String;
--begin
--  Result := 'GIF|*.gif';
--end;
--
--function TGifFileNamePropertyEditor.GetInitialDirectory: string;
--begin
--  Result:= ExtractFilePath(LazarusIDE.ActiveProject.ProjectInfoFile);
--end;
--
- procedure Register;
- begin
-   RegisterComponents('Wile64', [TGifAnim]);
--  RegisterPropertyEditor(TypeInfo(String),
--    TGifAnim, 'FileName', TGifFileNamePropertyEditor);
- end;
- 
- { TGifAnim }
-@@ -268,7 +251,7 @@
-   inherited Create(AOwner);
-   ControlStyle := [csCaptureMouse, csClickEvents, csDoubleClicks];
-   AutoSize     := True;
--  SetInitialBounds(0, 0, GetControlClassDefaultSize.X, GetControlClassDefaultSize.Y);
-+  SetInitialBounds(0, 0, GetControlClassDefaultSize.CX, GetControlClassDefaultSize.CY);
-   FEmpty      := True;
-   FCurrentImage := 0;
-   CurrentView := TBitmap.Create;
-@@ -295,6 +278,59 @@
-   CurrentView.Free;
- end;
- 
-+procedure TGifAnim.NextFrame;
-+begin
-+  if (not FEmpty) and Visible and (not FAnimate) then
-+  begin
-+    if FCurrentImage >= GifBitmaps.Count - 1 then
-+      FCurrentImage := 0
-+    else
-+      Inc(FCurrentImage);
-+    if Assigned(FOnFrameChanged) then
-+      FOnFrameChanged(Self);
-+    Repaint;
-+  end;
-+end;
-+
-+procedure TGifAnim.PriorFrame;
-+var
-+  DesiredImage: Integer;
-+begin
-+  if (not FEmpty) and Visible and (not FAnimate) then
-+  begin
-+    if FCurrentImage = 0 then
-+      DesiredImage:= GifBitmaps.Count - 1
-+    else
-+      DesiredImage:= FCurrentImage - 1;
-+    // For proper display repaint image from first frame to desired frame
-+    FCurrentImage:= 0;
-+    while FCurrentImage < DesiredImage do
-+    begin
-+      with GifBitmaps.Items[FCurrentImage] do
-+        begin
-+          BufferImg.Canvas.Brush.Color := (Self.Color);
-+          if FCurrentImage = 0 then
-+            BufferImg.Canvas.FillRect(Rect(0, 0, Width, Height));
-+          if Delay <> 0 then
-+            FWait.Interval := Delay * 10;
-+          BufferImg.Canvas.Draw(PosX, PosY, Bitmap);
-+          case Method of
-+            //0 : Not specified...
-+            //1 : No change Background
-+            2: BufferImg.Canvas.FillRect(
-+                Rect(PosX, PosY, Bitmap.Width + PosX, Bitmap.Height + PosY));
-+
-+            3: BufferImg.Canvas.FillRect(Rect(0, 0, Width, Height));
-+          end;
-+        end;
-+      Inc(FCurrentImage);
-+    end;
-+    if Assigned(FOnFrameChanged) then
-+      FOnFrameChanged(Self);
-+    Repaint;
-+  end;
-+end;
-+
- function TGifAnim.LoadFromLazarusResource(const ResName: String): boolean;
- var
-   GifLoader: TGifLoader;
-@@ -340,12 +376,13 @@
- begin
-   if (not Empty) and Visible then
-   begin
--    if FCurrentImage > GifBitmaps.Count - 1 then
--      FCurrentImage := 0;
--    if assigned(FOnFrameChanged) then
--      FOnFrameChanged(self);
--    Paint;
--    Inc(FCurrentImage);
-+    if FCurrentImage >= GifBitmaps.Count - 1 then
-+      FCurrentImage := 0
-+    else
-+      Inc(FCurrentImage);
-+    if Assigned(FOnFrameChanged) then
-+      FOnFrameChanged(Self);
-+    Repaint;
-   end;
- end;
- 
-@@ -365,27 +402,12 @@
- end;
- 
- procedure TGifAnim.SetFileName(const AValue: string);
--var
--  fn: string;
- begin
--
--  if (FFileName = AValue) then
--    exit;
-+  if (FFileName = AValue) then Exit;
-   FFileName := AValue;
-   ResetImage;
--  if (FFileName = '') then exit;
--  if (csDesigning in ComponentState) then
--  begin
--     fn:= ExtractFileName(AValue);
--     FFileName:= ExtractFilePath(AValue);
--     FFileName:= ExtractRelativepath(ExtractFilePath(LazarusIDE.ActiveProject.ProjectInfoFile) ,FFileName);
--     FFileName:=FFileName+fn;
--     LoadFromFile(FFileName+fn);
--  end
--  else begin
--     FFileName := AValue;
--     LoadFromFile(FFileName);
--  end;
-+  if (FFileName = '') then Exit;
-+  LoadFromFile(FFileName);
-   if not Empty then
-     GifChanged;
- end;
-@@ -441,10 +463,10 @@
-   end;
- end;
- 
--class function TGifAnim.GetControlClassDefaultSize: TPoint;
-+class function TGifAnim.GetControlClassDefaultSize: TSize;
- begin
--  Result.X := 90;
--  Result.Y := 90;
-+  Result.CX := 90;
-+  Result.CY := 90;
- end;
- 
- procedure TGifAnim.GifChanged;
-Index: gifanimdsgn.pas
-===================================================================
---- gifanimdsgn.pas	(revision 0)
-+++ gifanimdsgn.pas	(revision 0)
-@@ -0,0 +1,41 @@
-+unit GifAnimDsgn;
-+
-+{$mode objfpc}{$H+}
-+
-+interface
-+
-+uses
-+  LazIDEIntf, PropEdits;
-+
-+Type
-+  TGifFileNamePropertyEditor = class(TFileNamePropertyEditor)
-+  protected
-+    function GetFilter: String; override;
-+    function GetInitialDirectory: string; override;
-+  end;
-+
-+procedure Register;
-+
-+implementation
-+
-+uses
-+  SysUtils, GifAnim;
-+
-+function TGifFileNamePropertyEditor.GetFilter: String;
-+begin
-+  Result := 'GIF|*.gif';
-+end;
-+
-+function TGifFileNamePropertyEditor.GetInitialDirectory: string;
-+begin
-+  Result:= ExtractFilePath(LazarusIDE.ActiveProject.ProjectInfoFile);
-+end;
-+
-+procedure Register;
-+begin
-+  RegisterPropertyEditor(TypeInfo(String), TGifAnim,
-+                         'FileName', TGifFileNamePropertyEditor);
-+end;
-+
-+end.
-+
-Index: pkg_gifanim.lpk
-===================================================================
---- pkg_gifanim.lpk	(revision none)
-+++ pkg_gifanim.lpk	(working copy)
-@@ -1,15 +1,21 @@
--<?xml version="1.0"?>
-+<?xml version="1.0" encoding="UTF-8"?>
- <CONFIG>
--  <Package Version="3">
-+  <Package Version="4">
-     <PathDelim Value="\"/>
-     <Name Value="pkg_gifanim"/>
-+    <AddToProjectUsesSection Value="True"/>
-     <Author Value="Laurent Jacques"/>
-     <CompilerOptions>
--      <Version Value="8"/>
-+      <Version Value="11"/>
-       <PathDelim Value="\"/>
-       <SearchPaths>
--        <OtherUnitFiles Value="$(LazarusDir)\ide\"/>
-+        <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
-       </SearchPaths>
-+      <Linking>
-+        <Debugging>
-+          <DebugInfoType Value="dsDwarf2Set"/>
-+        </Debugging>
-+      </Linking>
-       <Other>
-         <CompilerPath Value="$(CompPath)"/>
-       </Other>
-@@ -33,15 +39,16 @@
-     <Type Value="RunAndDesignTime"/>
-     <RequiredPkgs Count="2">
-       <Item1>
--        <PackageName Value="FCL"/>
-+        <PackageName Value="LCL"/>
-         <MinVersion Major="1" Valid="True"/>
-       </Item1>
-       <Item2>
--        <PackageName Value="IDEIntf"/>
-+        <PackageName Value="FCL"/>
-+        <MinVersion Major="1" Valid="True"/>
-       </Item2>
-     </RequiredPkgs>
-     <UsageOptions>
--      <UnitPath Value="$(PkgOutDir)\"/>
-+      <UnitPath Value="$(PkgOutDir)"/>
-     </UsageOptions>
-     <PublishOptions>
-       <Version Value="2"/>
-Index: pkg_gifanim_dsgn.lpk
-===================================================================
---- pkg_gifanim_dsgn.lpk	(revision 0)
-+++ pkg_gifanim_dsgn.lpk	(revision 0)
-@@ -0,0 +1,49 @@
-+<?xml version="1.0" encoding="UTF-8"?>
-+<CONFIG>
-+  <Package Version="4">
-+    <PathDelim Value="\"/>
-+    <Name Value="pkg_gifanim_dsgn"/>
-+    <CompilerOptions>
-+      <Version Value="11"/>
-+      <PathDelim Value="\"/>
-+      <SearchPaths>
-+        <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
-+      </SearchPaths>
-+      <Linking>
-+        <Debugging>
-+          <DebugInfoType Value="dsDwarf2Set"/>
-+        </Debugging>
-+      </Linking>
-+      <Other>
-+        <CompilerMessages>
-+          <MsgFileName Value=""/>
-+        </CompilerMessages>
-+        <CompilerPath Value="$(CompPath)"/>
-+      </Other>
-+    </CompilerOptions>
-+    <License Value="GPL"/>
-+    <Version Major="1" Minor="4"/>
-+    <Files Count="1">
-+      <Item1>
-+        <Filename Value="gifanimdsgn.pas"/>
-+        <HasRegisterProc Value="True"/>
-+        <UnitName Value="GifAnimDsgn"/>
-+      </Item1>
-+    </Files>
-+    <Type Value="DesignTime"/>
-+    <RequiredPkgs Count="2">
-+      <Item1>
-+        <PackageName Value="IDEIntf"/>
-+      </Item1>
-+      <Item2>
-+        <PackageName Value="pkg_gifanim"/>
-+      </Item2>
-+    </RequiredPkgs>
-+    <UsageOptions>
-+      <UnitPath Value="$(PkgOutDir)"/>
-+    </UsageOptions>
-+    <PublishOptions>
-+      <Version Value="2"/>
-+    </PublishOptions>
-+  </Package>
-+</CONFIG>
-Index: pkg_gifanim_dsgn.pas
-===================================================================
---- pkg_gifanim_dsgn.pas	(revision 0)
-+++ pkg_gifanim_dsgn.pas	(revision 0)
-@@ -0,0 +1,21 @@
-+{ This file was automatically created by Lazarus. Do not edit!
-+  This source is only used to compile and install the package.
-+ }
-+
-+unit pkg_gifanim_dsgn;
-+
-+interface
-+
-+uses
-+  GifAnimDsgn, LazarusPackageIntf;
-+
-+implementation
-+
-+procedure Register;
-+begin
-+  RegisterUnit('GifAnimDsgn', @GifAnimDsgn.Register);
-+end;
-+
-+initialization
-+  RegisterPackage('pkg_gifanim_dsgn', @Register);
-+end.

+ 0 - 25
components/gifanim/gifanim.lrs

@@ -1,25 +0,0 @@
-LazarusResources.Add('tgifanim','XPM',[
-  '/* XPM */'#13#10'static char * gifanim_xpm[] = {'#13#10'"24 24 31 1",'#13#10
-  +'" '#9'c None",'#13#10'".'#9'c #959595",'#13#10'"+'#9'c #E1E1E1",'#13#10'"@'
-  +#9'c #919191",'#13#10'"#'#9'c #848484",'#13#10'"$'#9'c #888888",'#13#10'"%'#9
-  +'c #EEEEEE",'#13#10'"&'#9'c #E6E9EC",'#13#10'"*'#9'c #D6DFE8",'#13#10'"='#9
-  +'c #FFFFFF",'#13#10'"-'#9'c #E7F0F9",'#13#10'";'#9'c #3783CE",'#13#10'">'#9
-  +'c #FFF7F7",'#13#10'",'#9'c #FFEFEF",'#13#10'"'''#9'c #F7F2F5",'#13#10'")'#9
-  +'c #F7FAFD",'#13#10'"!'#9'c #FF5757",'#13#10'"~'#9'c #FFDFDF",'#13#10'"{'#9
-  +'c #FF4F4F",'#13#10'"]'#9'c #FFD7D7",'#13#10'"^'#9'c #FF4747",'#13#10'"/'#9
-  +'c #FF3F3F",'#13#10'"('#9'c #8D8D8D",'#13#10'"_'#9'c #EEE6E6",'#13#10'":'#9
-  +'c #EED6D6",'#13#10'"<'#9'c #EECECE",'#13#10'"['#9'c #FAFAFA",'#13#10'"}'#9
-  +'c #F2F2F2",'#13#10'"|'#9'c #F6F6F6",'#13#10'"1'#9'c #A2A2A2",'#13#10'"2'#9
-  +'c #FAF2F2",'#13#10'" .++@              @++. ",'#13#10'" @@@##$$$$$$$$$$$$##'
-  +'@@@ ",'#13#10'" .++$#$$$$$$$$$$$$#$++. ",'#13#10'" .++@+%%&**&&**&%%+@++. "'
-  +','#13#10'" @@@@%==-;;--;;-==%@@@@ ",'#13#10'" .++.%==-;;--;;-==%.++. ",'#13
-  +#10'" .++.%>,''--))--'',>%.++. ",'#13#10'" @@@@%,!~>====>~!,%@@@@ ",'#13#10
-  +'" .++.%>~{]~~~~]{~>%.++. ",'#13#10'" .++.%=>~^////^~>=%.++. ",'#13#10'" @@@'
-  +'(+%%_:<<<<:_%%+(@@@ ",'#13#10'" .++$#$$$$$$$$$$$$#$++. ",'#13#10'" .++$#$$$'
-  +'$$$$$$$$$#$++. ",'#13#10'" @@@(+%%&**&%%%%%%+(@@@ ",'#13#10'" .++.%==-;;-[}'
-  +'}[==%.++. ",'#13#10'" .++.%==-;;-|11|==%.++. ",'#13#10'" @@@@%>,''--)[}}2,>'
-  +'%@@@@ ",'#13#10'" .++.%,!~>====>~!,%.++. ",'#13#10'" .++.%>~{]~~~~]{~>%.++.'
-  +' ",'#13#10'" @@@@%=>~^////^~>=%@@@@ ",'#13#10'" .++@+%%_:<<<<:_%%+@++. ",'
-  +#13#10'" .++$#$$$$$$$$$$$$#$++. ",'#13#10'" @@@##$$$$$$$$$$$$##@@@ ",'#13#10
-  +'" .++@              @++. "};'#13#10
-]);

+ 0 - 1117
components/gifanim/gifanim.pas

@@ -1,1117 +0,0 @@
-{
-  Copyright (C) 2009 Laurent Jacques
-  Copyright (C) 2012-2022 Alexander Koblov
-
-  This source is free software; you can redistribute it and/or modify it under
-  the terms of the GNU General Public License as published by the Free
-  Software Foundation; either version 2 of the License, or (at your option)
-  any later version.
-
-  This code is distributed in the hope that it will be useful, but WITHOUT ANY
-  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
-  details.
-
-  A copy of the GNU General Public License is available on the World Wide Web
-  at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by writing
-  to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
-  MA 02111-1307, USA.
-}
-
-unit GifAnim;
-
-{$mode objfpc}{$H+}
-
-interface
-
-uses
-  Classes, LCLProc, Lresources, SysUtils, Controls, Graphics, ExtCtrls,
-  IntfGraphics, FPimage, Contnrs, GraphType, dialogs, types;
-
-const
-
-  EXT_INTRODUCER  = $21;
-  EXT_GRAPHICS_CONTROL = $F9;
-  EXT_PLAIN_TEXT  = $01;
-  EXT_APPLICATION = $FF;
-  EXT_COMMENT     = $FE;
-
-  DSC_LOCAL_IMAGE = $2C;
-
-  ID_TRANSPARENT = $01;
-  ID_COLOR_TABLE_SIZE = $07;
-  ID_SORT    = $20;
-  ID_INTERLACED = $40;
-  ID_COLOR_TABLE = $80;
-  ID_IMAGE_DESCRIPTOR = $2C;
-  ID_TRAILER = $3B;
-
-  CODE_TABLE_SIZE = 4096;
-
-type
-  TRGB = packed record
-    Red, Green, Blue: byte;
-  end;
-
-  TGIFHeader = packed record
-    Signature:    array[0..2] of char;  //* Header Signature (always "GIF") */
-    Version:      array[0..2] of char;  //* GIF format version("87a" or "89a") */
-    ScreenWidth:  word;                 //* Width of Display Screen in Pixels */
-    ScreenHeight: word;                 //* Height of Display Screen in Pixels */
-    Packedbit,                          //* Screen and Color Map Information */
-    BackgroundColor,                    //* Background Color Index */
-    AspectRatio:  byte;                 //* Pixel Aspect Ratio */
-  end;
-
-  TGifImageDescriptor = packed record
-    Left,                 //* X position of image on the display */
-    Top,                  //* Y position of image on the display */
-    Width,                //* Width of the image in pixels */
-    Height:    word;      //* Height of the image in pixels */
-    Packedbit: byte;      //* Image and Color Table Data Information */
-  end;
-
-  TGifGraphicsControlExtension = packed record
-    BlockSize,          //* Size of remaining fields (always 04h) */
-    Packedbit:  byte;   //* Method of graphics disposal to use */
-    DelayTime:  word;   //* Hundredths of seconds to wait  */
-    ColorIndex,         //* Transparent Color Index */
-    Terminator: byte;   //* Block Terminator (always 0) */
-  end;
-
-  TGifAnim = class;
-
-  { TGifImage }
-
-  TGifImage = class
-  private
-    FBitmap: TBitmap;
-    FPosX:   word;
-    FPosY:   word;
-    FDelay:  word;
-    FMethod: byte;
-  public
-    constructor Create;
-    destructor Destroy; override;
-    property Bitmap: TBitmap Read FBitmap;
-    property Delay: word Read FDelay;
-    property Method: byte Read FMethod;
-    property PosX: word Read FPosX;
-    property PosY: word Read FPosY;
-  end;
-
-  { TGifList }
-
-  TGifList = class(TObjectList)
-  private
-  protected
-    function GetItems(Index: integer): TGifImage;
-    procedure SetItems(Index: integer; AGifImage: TGifImage);
-  public
-    function Add(AGifImage: TGifImage): integer;
-    function Extract(Item: TGifImage): TGifImage;
-    function Remove(AGifImage: TGifImage): integer;
-    function IndexOf(AGifImage: TGifImage): integer;
-    function First: TGifImage;
-    function Last: TGifImage;
-    procedure Insert(Index: integer; AGifImage: TGifImage);
-    property Items[Index: integer]: TGifImage Read GetItems Write SetItems; default;
-  end;
-
-
-  { TGifLoader }
-
-  TGifLoader = class
-  private
-    FGifHeader:  TGIFHeader;
-    FGifDescriptor: TGifImageDescriptor;
-    FGifGraphicsCtrlExt: TGifGraphicsControlExtension;
-    FGifUseGraphCtrlExt: boolean;
-    FGifBackgroundColor: byte;
-    FInterlaced: boolean;
-    FScanLine:   PByte;
-    FLineSize:   integer;
-    FDisposalMethod: byte;
-    FEmpty:      boolean;
-    FFileName:   string;
-    FHeight:     integer;
-    FIsTransparent: boolean;
-    FWidth:      integer;
-    FPalette:    TFPPalette;
-    FLocalHeight: integer;
-    FLocalWidth: integer;
-    procedure ReadPalette(Stream: TStream; Size: integer);
-    procedure ReadScanLine(Stream: TStream);
-    procedure ReadHeader(Stream: TStream);
-    procedure ReadGlobalPalette(Stream: TStream);
-    procedure ReadGraphCtrlExt;
-    procedure SetInterlaced(const AValue: boolean);
-    procedure SetTransparent(const AValue: boolean);
-    function SkipBlock(Stream: TStream): byte;
-    procedure WriteScanLine(Img: TFPCustomImage);
-    procedure ReadGifBitmap(Stream: TStream);
-  public
-    constructor Create(const FileName: string);
-    destructor Destroy; override;
-    function LoadFromStream(GifStream: TStream; var AGifList: TGifList): boolean;
-    function LoadAllBitmap(var AGifList: TGifList): boolean;
-    function LoadFromLazarusResource(const ResName: String; var AGifList: TGifList): boolean;
-    function LoadFirstBitmap(var ABitmap: TBitmap): boolean;
-    property Empty: boolean Read FEmpty;
-    property Height: integer Read FHeight;
-    property Width: integer Read FWidth;
-    property IsTransparent: boolean Read FIsTransparent Write SetTransparent;
-    property Interlaced: boolean Read FInterlaced Write SetInterlaced;
-  end;
-
-  { TGifAnim }
-
-  TGifAnim = class(TGraphicControl)
-  private
-    { Private declarations }
-    FAnimate:   boolean;
-    FEmpty:     boolean;
-    FFileName:  string;
-    FGifBitmaps: TGifList;
-    FOnFrameChanged: TNotifyEvent;
-    FOnStart:   TNotifyEvent;
-    FOnStop:    TNotifyEvent;
-    FWait:      TTimer;
-    FCurrentImage: integer;
-    FGifHeight: integer;
-    FGifWidth:  integer;
-    procedure OnTime(Sender: TObject);
-    procedure SetAnimate(const AValue: boolean);
-    procedure SetFileName(const AValue: string);
-    procedure DefineSize(AWidth, AHeight: integer);
-  protected
-    { Protected declarations }
-    BufferImg:   TBitmap;
-    CurrentView: TBitmap;
-    procedure CalculatePreferredSize(
-      var PreferredWidth, PreferredHeight: integer;
-      WithThemeSpace: boolean); override;
-    procedure DoAutoSize; override;
-    procedure DoStartAnim;
-    procedure DoStopAnim;
-    class function GetControlClassDefaultSize: TSize; override;
-    procedure GifChanged;
-    procedure LoadFromFile(const Filename: string); virtual;
-    procedure Paint; override;
-    procedure ResetImage;
-    procedure SetColor(Value: TColor); override;
-  public
-    { Public declarations }
-    constructor Create(AOwner: TComponent); override;
-    destructor Destroy; override;
-    procedure NextFrame;
-    procedure PriorFrame;
-    property Empty: boolean Read FEmpty;
-    property GifBitmaps: TGifList Read FGifBitmaps;
-    property GifIndex: integer Read FCurrentImage;
-    function LoadFromLazarusResource(const ResName: String): boolean;
-  published
-    { Published declarations }
-    property Anchors;
-    property AutoSize default True;
-    property Animate: boolean Read FAnimate Write SetAnimate default True;
-    property BorderSpacing;
-    property Color default clBtnFace;
-    property Constraints;
-    property FileName: string Read FFileName Write SetFileName;
-    property Height;
-    property OnClick;
-    property OnDblClick;
-    property OnFrameChanged: TNotifyEvent Read FOnFrameChanged Write FOnFrameChanged;
-    property OnMouseDown;
-    property OnMouseEnter;
-    property OnMouseLeave;
-    property OnMouseMove;
-    property OnMouseUp;
-    property OnStartAnim: TNotifyEvent Read FOnStart Write FOnStart;
-    property OnStopAnim: TNotifyEvent Read FOnStop Write FOnStop;
-    property ParentShowHint;
-    property ShowHint;
-    property Visible;
-    property Width;
-  end;
-
-procedure Register;
-
-implementation
-
-procedure Register;
-begin
-  RegisterComponents('Wile64', [TGifAnim]);
-end;
-
-{ TGifAnim }
-
-constructor TGifAnim.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-  ControlStyle := [csCaptureMouse, csClickEvents, csDoubleClicks];
-  AutoSize     := True;
-  SetInitialBounds(0, 0, GetControlClassDefaultSize.CX, GetControlClassDefaultSize.CY);
-  FEmpty      := True;
-  FCurrentImage := 0;
-  CurrentView := TBitmap.Create;
-  if not (csDesigning in ComponentState) then
-  begin
-    BufferImg := TBitmap.Create;
-    FWait     := TTimer.Create(Self);
-    with FWait do
-    begin
-      Interval := 100;
-      OnTimer  := @OnTime;
-      Enabled  := False;
-    end;
-  end;
-  Animate := True;
-end;
-
-destructor TGifAnim.Destroy;
-begin
-  inherited Destroy;
-  if assigned(FGifBitmaps) then
-    FreeAndNil(FGifBitmaps);
-  BufferImg.Free;
-  CurrentView.Free;
-end;
-
-procedure TGifAnim.NextFrame;
-begin
-  if (not FEmpty) and Visible and (not FAnimate) then
-  begin
-    if FCurrentImage >= GifBitmaps.Count - 1 then
-      FCurrentImage := 0
-    else
-      Inc(FCurrentImage);
-    if Assigned(FOnFrameChanged) then
-      FOnFrameChanged(Self);
-    Repaint;
-  end;
-end;
-
-procedure TGifAnim.PriorFrame;
-var
-  DesiredImage: Integer;
-begin
-  if (not FEmpty) and Visible and (not FAnimate) then
-  begin
-    if FCurrentImage = 0 then
-      DesiredImage:= GifBitmaps.Count - 1
-    else
-      DesiredImage:= FCurrentImage - 1;
-    // For proper display repaint image from first frame to desired frame
-    FCurrentImage:= 0;
-    while FCurrentImage < DesiredImage do
-    begin
-      with GifBitmaps.Items[FCurrentImage] do
-        begin
-          BufferImg.Canvas.Brush.Color := (Self.Color);
-          if FCurrentImage = 0 then
-            BufferImg.Canvas.FillRect(Rect(0, 0, Width, Height));
-          if Delay <> 0 then
-            FWait.Interval := Delay * 10;
-          BufferImg.Canvas.Draw(PosX, PosY, Bitmap);
-          case Method of
-            //0 : Not specified...
-            //1 : No change Background
-            2: BufferImg.Canvas.FillRect(
-                Rect(PosX, PosY, Bitmap.Width + PosX, Bitmap.Height + PosY));
-
-            3: BufferImg.Canvas.FillRect(Rect(0, 0, Width, Height));
-          end;
-        end;
-      Inc(FCurrentImage);
-    end;
-    if Assigned(FOnFrameChanged) then
-      FOnFrameChanged(Self);
-    Repaint;
-  end;
-end;
-
-function TGifAnim.LoadFromLazarusResource(const ResName: String): boolean;
-var
-  GifLoader: TGifLoader;
-  StateAnimate: boolean;
-  Resource: TLResource;
-begin
-  Result:=false;
-  StateAnimate:= Animate;
-  FWait.Enabled:= false;
-  ResetImage;
-  Resource:=nil;
-  Resource:=LazarusResources.Find(ResName);
-  if Resource <> nil then
-  if CompareText(LazarusResources.Find(ResName).ValueType, 'gif')=0 then begin
-    GifLoader := TGifLoader.Create(Filename);
-    FEmpty := not GifLoader.LoadFromLazarusResource(ResName, FGifBitmaps);
-    DefineSize(GifLoader.Width, GifLoader.Height);
-    GifLoader.Free;
-    Result:= FEmpty;
-  end;
-  if not Empty then
-    GifChanged;
-  FWait.Enabled:= StateAnimate;
-end;
-
-procedure TGifAnim.LoadFromFile(const Filename: string);
-var
-  GifLoader: TGifLoader;
-begin
-  FEmpty    := True;
-  if not FileExists(Filename) then
-    Exit;
-  GifLoader := TGifLoader.Create(Filename);
-  if (csDesigning in ComponentState) then
-    FEmpty := not GifLoader.LoadFirstBitmap(CurrentView)
-  else
-    FEmpty := not GifLoader.LoadAllBitmap(FGifBitmaps);
-  DefineSize(GifLoader.Width, GifLoader.Height);
-  GifLoader.Free;
-end;
-
-procedure TGifAnim.OnTime(Sender: TObject);
-begin
-  if (not Empty) and Visible then
-  begin
-    if FCurrentImage >= GifBitmaps.Count - 1 then
-      FCurrentImage := 0
-    else
-      Inc(FCurrentImage);
-    if Assigned(FOnFrameChanged) then
-      FOnFrameChanged(Self);
-    Repaint;
-  end;
-end;
-
-procedure TGifAnim.SetAnimate(const AValue: boolean);
-begin
-  if FAnimate = AValue then
-    exit;
-  FAnimate := AValue;
-  if not (csDesigning in ComponentState) then
-  begin
-    FWait.Enabled := Animate;
-    if Animate then
-      DoStartAnim
-    else
-      DoStopAnim;
-  end;
-end;
-
-procedure TGifAnim.SetFileName(const AValue: string);
-begin
-  if (FFileName = AValue) then Exit;
-  FFileName := AValue;
-  ResetImage;
-  if (FFileName = '') then Exit;
-  LoadFromFile(FFileName);
-  if not Empty then
-    GifChanged;
-end;
-
-procedure TGifAnim.DefineSize(AWidth, AHeight: integer);
-begin
-  if (AWidth = FGifWidth) and (AHeight = FGifHeight) then
-    Exit;
-  FGifWidth  := AWidth;
-  FGifHeight := AHeight;
-  Height     := FGifHeight;
-  Width      := FGifWidth;
-  if not (csDesigning in ComponentState) then
-  begin
-    BufferImg.Height := Height;
-    BufferImg.Width  := Width;
-  end;
-end;
-
-procedure TGifAnim.CalculatePreferredSize(var PreferredWidth, PreferredHeight: integer;
-  WithThemeSpace: boolean);
-begin
-  PreferredWidth  := FGifWidth;
-  PreferredHeight := FGifHeight;
-end;
-
-procedure TGifAnim.DoAutoSize;
-var
-  ModifyWidth, ModifyHeight: boolean;
-  NewWidth:  integer;
-  NewHeight: integer;
-begin
-  if AutoSizing then
-    Exit;    // we shouldn't come here in the first place
-
-  BeginAutoSizing;
-  try
-    GetPreferredSize(NewWidth, NewHeight);
-    ModifyWidth  := [akLeft, akRight] * (Anchors + AnchorAlign[Align]) <> [akLeft, akRight];
-    ModifyHeight := [akTop, akBottom] * (Anchors + AnchorAlign[Align]) <> [akTop, akBottom];
-
-    if not ModifyWidth then
-      NewWidth := Width;
-    if not ModifyHeight then
-      NewHeight := Height;
-
-    if (NewWidth <> Width) or (NewHeight <> Height) then
-    begin
-      SetBounds(Left, Top, NewWidth, NewHeight);
-    end;
-  finally
-    EndAutoSizing;
-  end;
-end;
-
-class function TGifAnim.GetControlClassDefaultSize: TSize;
-begin
-  Result.CX := 90;
-  Result.CY := 90;
-end;
-
-procedure TGifAnim.GifChanged;
-begin
-  if not (csDesigning in ComponentState) then
-  begin
-    BufferImg.Canvas.Brush.Color := (self.Color);
-    BufferImg.Canvas.FillRect(Rect(0, 0, Width, Height));
-    with GifBitmaps.Items[FCurrentImage] do
-      BufferImg.Canvas.Draw(PosX, PosY, Bitmap);
-    CurrentView.Assign(BufferImg);
-  end;
-  InvalidatePreferredSize;
-  AdjustSize;
-end;
-
-procedure TGifAnim.Paint;
-begin
-  if (not Empty) and Visible then
-  begin
-    if not (csDesigning in ComponentState) then
-    begin
-      if (FCurrentImage < GifBitmaps.Count) then
-        with GifBitmaps.Items[FCurrentImage] do
-        begin
-          BufferImg.Canvas.Brush.Color := (self.Color);
-          if FCurrentImage = 0 then
-            BufferImg.Canvas.FillRect(Rect(0, 0, Width, Height));
-          if Delay <> 0 then
-            FWait.Interval := Delay * 10;
-          BufferImg.Canvas.Draw(PosX, PosY, Bitmap);
-          CurrentView.Assign(BufferImg);
-          case Method of
-            //0 : Not specified...
-            //1 : No change Background
-            2: BufferImg.Canvas.FillRect(
-                Rect(PosX, PosY, Bitmap.Width + PosX, Bitmap.Height + PosY));
-
-            3: BufferImg.Canvas.FillRect(Rect(0, 0, Width, Height));
-          end;
-        end;
-    end
-    else
-    begin
-      Canvas.Brush.Color := (self.Color);
-      Canvas.FillRect(Rect(0, 0, Width, Height));
-    end;
-    Canvas.Draw(0, 0, CurrentView);
-  end;
-  inherited Paint;
-end;
-
-procedure TGifAnim.ResetImage;
-begin
-  if assigned(FGifBitmaps) then
-    FreeAndNil(FGifBitmaps);
-  FCurrentImage:=0;
-  with CurrentView do
-  begin
-    Canvas.Brush.Color := (self.Color);
-    Canvas.FillRect(Rect(0, 0, Width, Height));
-  end;
-end;
-
-procedure TGifAnim.SetColor(Value: TColor);
-begin
-  inherited SetColor(Value);
-end;
-
-procedure TGifAnim.DoStartAnim;
-begin
-  if assigned(OnStartAnim) then
-    OnStartAnim(Self);
-end;
-
-procedure TGifAnim.DoStopAnim;
-begin
-  if assigned(OnStopAnim) then
-    OnStartAnim(Self);
-end;
-
-{ TGifLoader }
-
-constructor TGifLoader.Create(const FileName: string);
-begin
-  FFileName := FileName;
-  FGifUseGraphCtrlExt := False;
-  FPalette  := TFPPalette.Create(0);
-  FHeight   := 20;
-  FWidth    := 20;
-end;
-
-destructor TGifLoader.Destroy;
-begin
-  inherited Destroy;
-  FPalette.Free;
-end;
-
-function TGifLoader.LoadFromStream(GifStream: TStream; var AGifList: TGifList): boolean;
-var
-  Introducer: byte;
-  FPImage:    TLazIntfImage;
-  ImgFormatDescription: TRawImageDescription;
-  GifBitmap:  TGifImage;
-begin
-  Result := False;
-  if not Assigned(AGifList) then
-    AGifList := TGifList.Create(True);
-
-  GifStream.Position := 0;
-
-  ReadHeader(GifStream);
-  if (FGifHeader.Version <> '89a') then
-    Exit;
-
-  // skip first block extention if exist
-  repeat
-    Introducer := SkipBlock(GifStream);
-  until (Introducer = ID_IMAGE_DESCRIPTOR) or (Introducer = ID_TRAILER) or (GifStream.Position = GifStream.Size);
-
-  repeat
-    ReadGifBitmap(GifStream);
-    // decode Gif bitmap in Scanline buffer
-    ReadScanLine(GifStream);
-    // Create temp Fp Image for put scanline pixel
-    FPImage := TLazIntfImage.Create(FLocalWidth, FLocalHeight);
-    ImgFormatDescription.Init_BPP32_B8G8R8A8_BIO_TTB(FLocalWidth,
-      FLocalHeight);
-    FPImage.DataDescription := ImgFormatDescription;
-
-    WriteScanLine(FPImage);
-
-    GifBitmap := TGifImage.Create;
-    GifBitmap.FBitmap.LoadFromIntfImage(FPImage);
-    GifBitmap.FPosX   := FGifDescriptor.Left;
-    GifBitmap.FPosY   := FGifDescriptor.Top;
-    GifBitmap.FMethod := FDisposalMethod;
-    GifBitmap.FDelay  := FGifGraphicsCtrlExt.DelayTime;
-
-    AGifList.Add(GifBitmap);
-
-    FPImage.Free;
-    FreeMem(FScanLine, FLineSize);
-    // reset FGifUseGraphCtrlExt flag
-    FGifUseGraphCtrlExt := False;
-
-    repeat
-      Introducer := SkipBlock(GifStream);
-    until (Introducer = ID_IMAGE_DESCRIPTOR) or (Introducer = ID_TRAILER) or (GifStream.Position = GifStream.Size);
-
-  until (Introducer = ID_TRAILER) or (GifStream.Position = GifStream.Size);
-  Result := True;
-end;
-
-function TGifLoader.LoadAllBitmap(var AGifList: TGifList): boolean;
-var
-  GifStream:  TMemoryStream;
-begin
-  Result := False;
-  if not FileExists(FFileName) then
-    Exit;
-
-  GifStream := TMemoryStream.Create;
-  try
-    GifStream.LoadFromFile(FFileName);
-    Result := LoadFromStream(GifStream, AGifList);
-  finally
-    GifStream.Free;
-  end;
-end;
-
-function TGifLoader.LoadFromLazarusResource(const ResName: String; var AGifList: TGifList): boolean;
-var
-  GifStream:  TLazarusResourceStream;
-begin
-  Result := False;
-  GifStream := TLazarusResourceStream.Create(ResName, nil);
-  try
-    Result := LoadFromStream(GifStream, AGifList);
-  finally
-    GifStream.Free;
-  end;
-end;
-
-function TGifLoader.LoadFirstBitmap(var ABitmap: TBitmap): boolean;
-var
-  GifStream:  TMemoryStream;
-  Introducer: byte;
-  FPImage:    TLazIntfImage;
-  ImgFormatDescription: TRawImageDescription;
-begin
-  Result := False;
-  if not FileExists(FFileName) then
-    exit;
-  if not assigned(ABitmap) then
-    ABitmap := TBitmap.Create;
-
-  GifStream := TMemoryStream.Create;
-  GifStream.LoadFromFile(FFileName);
-  GifStream.Position := 0;
-
-  ReadHeader(GifStream);
-  if (FGifHeader.Version <> '89a') then
-    Exit;
-
-  // skip first block extention if exist
-  repeat
-    Introducer := SkipBlock(GifStream);
-  until (Introducer = ID_IMAGE_DESCRIPTOR) or (Introducer = ID_TRAILER);
-
-  ReadGifBitmap(GifStream);
-  // decode Gif bitmap in Scanline buffer
-  ReadScanLine(GifStream);
-  // Create temp Fp Image for put scanline pixel
-  FPImage := TLazIntfImage.Create(FLocalWidth, FLocalHeight);
-  ImgFormatDescription.Init_BPP32_B8G8R8A8_BIO_TTB(FLocalWidth,
-    FLocalHeight);
-  FPImage.DataDescription := ImgFormatDescription;
-
-  WriteScanLine(FPImage);
-
-  ABitmap.LoadFromIntfImage(FPImage);
-  FPImage.Free;
-  FreeMem(FScanLine, FLineSize);
-  // reset FGifUseGraphCtrlExt flag
-  FGifUseGraphCtrlExt := False;
-
-  GifStream.Free;
-  Result := True;
-end;
-
-procedure TGifLoader.SetTransparent(const AValue: boolean);
-begin
-  if FIsTransparent = AValue then
-    exit;
-  FIsTransparent := AValue;
-end;
-
-function TGifLoader.SkipBlock(Stream: TStream): byte;
-var
-  Introducer, Labels, SkipByte: byte;
-begin
-  Introducer := 0;
-  Labels     := 0;
-  SkipByte   := 0;
-  Stream.Read(Introducer, 1);
-  if Introducer = EXT_INTRODUCER then
-  begin
-    Stream.Read(Labels, 1);
-    case Labels of
-      EXT_COMMENT,
-      EXT_APPLICATION:
-        while True do
-        begin
-          Stream.Read(SkipByte, 1);
-          if SkipByte = 0 then
-            Break;
-          Stream.Seek(SkipByte, soFromCurrent);
-        end;
-      EXT_GRAPHICS_CONTROL:
-      begin
-        Stream.Read(FGifGraphicsCtrlExt, SizeOf(FGifGraphicsCtrlExt));
-        FGifUseGraphCtrlExt := True;
-      end;
-      EXT_PLAIN_TEXT:
-      begin
-        Stream.Read(SkipByte, 1);
-        Stream.Seek(SkipByte, soFromCurrent);
-        while True do
-        begin
-          Stream.Read(SkipByte, 1);
-          if SkipByte = 0 then
-            Break;
-          Stream.Seek(SkipByte, soFromCurrent);
-        end;
-      end;
-    end;
-  end;
-  Result := Introducer;
-end;
-
-procedure TGifLoader.ReadScanLine(Stream: TStream);
-var
-  OldPos, UnpackedSize, PackedSize: longint;
-  I:      integer;
-  Data, Bits, Code: cardinal;
-  SourcePtr: PByte;
-  InCode: cardinal;
-
-  CodeSize: cardinal;
-  CodeMask: cardinal;
-  FreeCode: cardinal;
-  OldCode:  cardinal;
-  Prefix:   array[0..CODE_TABLE_SIZE - 1] of cardinal;
-  Suffix, Stack: array [0..CODE_TABLE_SIZE - 1] of byte;
-  StackPointer: PByte;
-  DataComp, Target: PByte;
-  B, FInitialCodeSize, FirstChar: byte;
-  ClearCode, EOICode: word;
-
-begin
-  FInitialCodeSize := 0;
-  B := 0;
-  DataComp := nil;
-
-  // initialisation du dictionnaire de decompression
-  Stream.Read(FInitialCodeSize, 1);
-
-  // Recherche la taille des données compresser
-  OldPos     := Stream.Position;
-  PackedSize := 0;
-  repeat
-    Stream.Read(B, 1);
-    if B > 0 then
-    begin
-      Inc(PackedSize, B);
-      Stream.Seek(B, soFromCurrent);
-    end;
-  until B = 0;
-
-  Getmem(DataComp, PackedSize);
-  // lecture des données conpresser
-  SourcePtr := DataComp;
-  Stream.Position := OldPos;
-  repeat
-    Stream.Read(B, 1);
-    if B > 0 then
-    begin
-      Stream.ReadBuffer(SourcePtr^, B);
-      Inc(SourcePtr, B);
-    end;
-  until B = 0;
-
-  SourcePtr := DataComp;
-  Target    := FScanLine;
-  CodeSize  := FInitialCodeSize + 1;
-  ClearCode := 1 shl FInitialCodeSize;
-  EOICode   := ClearCode + 1;
-  FreeCode  := ClearCode + 2;
-  OldCode   := CODE_TABLE_SIZE;
-  CodeMask  := (1 shl CodeSize) - 1;
-  UnpackedSize := FLocalWidth * FLocalHeight;
-  for I := 0 to ClearCode - 1 do
-  begin
-    Prefix[I] := CODE_TABLE_SIZE;
-    Suffix[I] := I;
-  end;
-  StackPointer := @Stack;
-  FirstChar := 0;
-  Data := 0;
-  Bits := 0;
-  //Decompression LZW gif
-  while (UnpackedSize > 0) and (PackedSize > 0) do
-  begin
-    Inc(Data, SourcePtr^ shl Bits);
-    Inc(Bits, 8);
-    while Bits >= CodeSize do
-    begin
-      Code := Data and CodeMask;
-      Data := Data shr CodeSize;
-      Dec(Bits, CodeSize);
-      if Code = EOICode then
-        Break;
-      if Code = ClearCode then
-      begin
-        CodeSize := FInitialCodeSize + 1;
-        CodeMask := (1 shl CodeSize) - 1;
-        FreeCode := ClearCode + 2;
-        OldCode  := CODE_TABLE_SIZE;
-        Continue;
-      end;
-      if Code > FreeCode then
-        Break;
-      if OldCode = CODE_TABLE_SIZE then
-      begin
-        FirstChar := Suffix[Code];
-        Target^   := FirstChar;
-        Inc(Target);
-        Dec(UnpackedSize);
-        OldCode := Code;
-        Continue;
-      end;
-      InCode := Code;
-      if Code = FreeCode then
-      begin
-        StackPointer^ := FirstChar;
-        Inc(StackPointer);
-        Code := OldCode;
-      end;
-      while Code > ClearCode do
-      begin
-        StackPointer^ := Suffix[Code];
-        Inc(StackPointer);
-        Code := Prefix[Code];
-      end;
-      FirstChar     := Suffix[Code];
-      StackPointer^ := FirstChar;
-      Inc(StackPointer);
-      Prefix[FreeCode] := OldCode;
-      Suffix[FreeCode] := FirstChar;
-      if (FreeCode = CodeMask) and (CodeSize < 12) then
-      begin
-        Inc(CodeSize);
-        CodeMask := (1 shl CodeSize) - 1;
-      end;
-      if FreeCode < CODE_TABLE_SIZE - 1 then
-        Inc(FreeCode);
-      OldCode := InCode;
-      repeat
-        Dec(StackPointer);
-        Target^ := StackPointer^;
-        Inc(Target);
-        Dec(UnpackedSize);
-      until StackPointer = @Stack;
-    end;
-    Inc(SourcePtr);
-    Dec(PackedSize);
-  end;
-  FreeMem(DataComp);
-end;
-
-procedure TGifLoader.ReadHeader(Stream: TStream);
-begin
-  Stream.Read(FGifHeader, SizeOf(FGifHeader));
-
-  with FGifHeader do
-  begin
-    FGifBackgroundColor := BackgroundColor;
-
-    FWidth  := ScreenWidth;
-    FHeight := ScreenHeight;
-
-    FLocalWidth  := ScreenWidth;
-    FLocalHeight := ScreenHeight;
-
-    IsTransparent := False;
-  end;
-  ReadGlobalPalette(Stream);
-end;
-
-procedure TGifLoader.ReadGlobalPalette(Stream: TStream);
-var
-  ColorTableSize: integer;
-begin
-  if (FGifHeader.Packedbit and ID_COLOR_TABLE) <> 0 then
-  begin
-    ColorTableSize := FGifHeader.Packedbit and ID_COLOR_TABLE_SIZE + 1;
-    ReadPalette(Stream, 1 shl ColorTableSize);
-  end;
-end;
-
-procedure TGifLoader.ReadGraphCtrlExt;
-var
-  C: TFPColor;
-begin
-  IsTransparent := (FGifGraphicsCtrlExt.Packedbit and ID_TRANSPARENT) <> 0;
-
-  FDisposalMethod := (FGifGraphicsCtrlExt.Packedbit and $1C) shr 2;
-
-  if IsTransparent then
-  begin
-    // if Transparent bitmap change alpha channel
-    FGifBackgroundColor := FGifGraphicsCtrlExt.ColorIndex;
-    C := FPalette[FGifBackgroundColor];
-    C.alpha := alphaTransparent;
-    FPalette[FGifBackgroundColor] := C;
-  end;
-end;
-
-procedure TGifLoader.SetInterlaced(const AValue: boolean);
-begin
-  if FInterlaced = AValue then
-    exit;
-  FInterlaced := AValue;
-end;
-
-procedure TGifLoader.ReadPalette(Stream: TStream; Size: integer);
-var
-  RGBEntry: TRGB;
-  I: integer;
-  C: TFPColor;
-begin
-  FPalette.Clear;
-  FPalette.Count := 0;
-  Fillchar(RGBEntry, SizeOf(RGBEntry), 0);
-  for I := 0 to Size - 1 do
-  begin
-    Stream.Read(RGBEntry, SizeOf(RGBEntry));
-    with C do
-    begin
-      Red   := RGBEntry.Red or (RGBEntry.Red shl 8);
-      Green := RGBEntry.Green or (RGBEntry.Green shl 8);
-      Blue  := RGBEntry.Blue or (RGBEntry.Blue shl 8);
-      Alpha := alphaOpaque;
-    end;
-    FPalette.Add(C);
-  end;
-end;
-
-procedure TGifLoader.WriteScanLine(Img: TFPCustomImage);
-var
-  Row, Col: integer;
-  Pass, Every: byte;
-  P: PByte;
-begin
-  P := FScanLine;
-  if Interlaced then
-  begin
-    for Pass := 1 to 4 do
-    begin
-      case Pass of
-        1:
-        begin
-          Row   := 0;
-          Every := 8;
-        end;
-        2:
-        begin
-          Row   := 4;
-          Every := 8;
-        end;
-        3:
-        begin
-          Row   := 2;
-          Every := 4;
-        end;
-        4:
-        begin
-          Row   := 1;
-          Every := 2;
-        end;
-      end;
-      repeat
-        for Col := 0 to FLocalWidth - 1 do
-        begin
-          Img.Colors[Col, Row] := FPalette[P^];
-          Inc(P);
-        end;
-        Inc(Row, Every);
-      until Row >= FLocalHeight;
-    end;
-  end
-  else
-  begin
-    for Row := 0 to FLocalHeight - 1 do
-      for Col := 0 to FLocalWidth - 1 do
-      begin
-        Img.Colors[Col, Row] := FPalette[P^];
-        Inc(P);
-      end;
-  end;
-end;
-
-procedure TGifLoader.ReadGifBitmap(Stream: TStream);
-var
-  ColorTableSize: integer;
-begin
-  Stream.Read(FGifDescriptor, SizeOf(FGifDescriptor));
-
-  with FGifDescriptor do
-  begin
-    FLocalWidth  := Width;
-    FLocalHeight := Height;
-    Interlaced   := (Packedbit and ID_INTERLACED = ID_INTERLACED);
-  end;
-
-  FLineSize := FLocalWidth * (FLocalHeight + 1);
-  GetMem(FScanLine, FLineSize);
-
-  if (FGifDescriptor.Packedbit and ID_COLOR_TABLE) <> 0 then
-  begin
-    ColorTableSize := FGifDescriptor.Packedbit and ID_COLOR_TABLE_SIZE + 1;
-    ReadPalette(Stream, 1 shl ColorTableSize);
-  end;
-  if FGifUseGraphCtrlExt then
-    ReadGraphCtrlExt;
-
-end;
-
-{ TGifImage }
-
-constructor TGifImage.Create;
-begin
-  FBitmap := TBitmap.Create;
-  FPosX   := 0;
-  FPosY   := 0;
-  FDelay  := 0;
-  FMethod := 0;
-end;
-
-destructor TGifImage.Destroy;
-begin
-  inherited Destroy;
-  FBitmap.Free;
-end;
-
-{ TGifList }
-
-function TGifList.GetItems(Index: integer): TGifImage;
-begin
-  Result := TGifImage(inherited Items[Index]);
-end;
-
-procedure TGifList.SetItems(Index: integer; AGifImage: TGifImage);
-begin
-  Put(Index, AGifImage);
-end;
-
-function TGifList.Add(AGifImage: TGifImage): integer;
-begin
-  Result := inherited Add(AGifImage);
-end;
-
-function TGifList.Extract(Item: TGifImage): TGifImage;
-begin
-  Result := TGifImage(inherited Extract(Item));
-end;
-
-function TGifList.Remove(AGifImage: TGifImage): integer;
-begin
-  Result := inherited Remove(AGifImage);
-end;
-
-function TGifList.IndexOf(AGifImage: TGifImage): integer;
-begin
-  Result := inherited IndexOf(AGifImage);
-end;
-
-function TGifList.First: TGifImage;
-begin
-  Result := TGifImage(inherited First);
-end;
-
-function TGifList.Last: TGifImage;
-begin
-  Result := TGifImage(inherited Last);
-end;
-
-procedure TGifList.Insert(Index: integer; AGifImage: TGifImage);
-begin
-  inherited Insert(Index, AGifImage);
-end;
-
-initialization
-{$I gifanim.lrs}
-
-end.

+ 0 - 41
components/gifanim/gifanimdsgn.pas

@@ -1,41 +0,0 @@
-unit GifAnimDsgn;
-
-{$mode objfpc}{$H+}
-
-interface
-
-uses
-  LazIDEIntf, PropEdits;
-
-Type
-  TGifFileNamePropertyEditor = class(TFileNamePropertyEditor)
-  protected
-    function GetFilter: String; override;
-    function GetInitialDirectory: string; override;
-  end;
-
-procedure Register;
-
-implementation
-
-uses
-  SysUtils, GifAnim;
-
-function TGifFileNamePropertyEditor.GetFilter: String;
-begin
-  Result := 'GIF|*.gif';
-end;
-
-function TGifFileNamePropertyEditor.GetInitialDirectory: string;
-begin
-  Result:= ExtractFilePath(LazarusIDE.ActiveProject.ProjectInfoFile);
-end;
-
-procedure Register;
-begin
-  RegisterPropertyEditor(TypeInfo(String), TGifAnim,
-                         'FileName', TGifFileNamePropertyEditor);
-end;
-
-end.
-

+ 0 - 58
components/gifanim/pkg_gifanim.lpk

@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<CONFIG>
-  <Package Version="4">
-    <PathDelim Value="\"/>
-    <Name Value="pkg_gifanim"/>
-    <AddToProjectUsesSection Value="True"/>
-    <Author Value="Laurent Jacques"/>
-    <CompilerOptions>
-      <Version Value="11"/>
-      <PathDelim Value="\"/>
-      <SearchPaths>
-        <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
-      </SearchPaths>
-      <Linking>
-        <Debugging>
-          <DebugInfoType Value="dsDwarf2Set"/>
-        </Debugging>
-      </Linking>
-      <Other>
-        <CompilerPath Value="$(CompPath)"/>
-      </Other>
-    </CompilerOptions>
-    <Description Value="Show Gif Animation
-"/>
-    <License Value="GPL
-"/>
-    <Version Major="1" Minor="5"/>
-    <Files Count="2">
-      <Item1>
-        <Filename Value="gifanim.pas"/>
-        <HasRegisterProc Value="True"/>
-        <UnitName Value="GifAnim"/>
-      </Item1>
-      <Item2>
-        <Filename Value="gifanim.lrs"/>
-        <Type Value="LRS"/>
-      </Item2>
-    </Files>
-    <Type Value="RunAndDesignTime"/>
-    <RequiredPkgs Count="2">
-      <Item1>
-        <PackageName Value="LCL"/>
-        <MinVersion Major="1" Valid="True"/>
-      </Item1>
-      <Item2>
-        <PackageName Value="FCL"/>
-        <MinVersion Major="1" Valid="True"/>
-      </Item2>
-    </RequiredPkgs>
-    <UsageOptions>
-      <UnitPath Value="$(PkgOutDir)"/>
-    </UsageOptions>
-    <PublishOptions>
-      <Version Value="2"/>
-      <IgnoreBinaries Value="False"/>
-    </PublishOptions>
-  </Package>
-</CONFIG>

+ 0 - 21
components/gifanim/pkg_gifanim.pas

@@ -1,21 +0,0 @@
-{ This file was automatically created by Lazarus. Do not edit!
-  This source is only used to compile and install the package.
- }
-
-unit pkg_gifanim;
-
-interface
-
-uses
-  GifAnim, LazarusPackageIntf;
-
-implementation
-
-procedure Register;
-begin
-  RegisterUnit('GifAnim', @GifAnim.Register);
-end;
-
-initialization
-  RegisterPackage('pkg_gifanim', @Register);
-end.

+ 0 - 49
components/gifanim/pkg_gifanim_dsgn.lpk

@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<CONFIG>
-  <Package Version="4">
-    <PathDelim Value="\"/>
-    <Name Value="pkg_gifanim_dsgn"/>
-    <CompilerOptions>
-      <Version Value="11"/>
-      <PathDelim Value="\"/>
-      <SearchPaths>
-        <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
-      </SearchPaths>
-      <Linking>
-        <Debugging>
-          <DebugInfoType Value="dsDwarf2Set"/>
-        </Debugging>
-      </Linking>
-      <Other>
-        <CompilerMessages>
-          <MsgFileName Value=""/>
-        </CompilerMessages>
-        <CompilerPath Value="$(CompPath)"/>
-      </Other>
-    </CompilerOptions>
-    <License Value="GPL"/>
-    <Version Major="1" Minor="4"/>
-    <Files Count="1">
-      <Item1>
-        <Filename Value="gifanimdsgn.pas"/>
-        <HasRegisterProc Value="True"/>
-        <UnitName Value="GifAnimDsgn"/>
-      </Item1>
-    </Files>
-    <Type Value="DesignTime"/>
-    <RequiredPkgs Count="2">
-      <Item1>
-        <PackageName Value="IDEIntf"/>
-      </Item1>
-      <Item2>
-        <PackageName Value="pkg_gifanim"/>
-      </Item2>
-    </RequiredPkgs>
-    <UsageOptions>
-      <UnitPath Value="$(PkgOutDir)"/>
-    </UsageOptions>
-    <PublishOptions>
-      <Version Value="2"/>
-    </PublishOptions>
-  </Package>
-</CONFIG>

+ 0 - 21
components/gifanim/pkg_gifanim_dsgn.pas

@@ -1,21 +0,0 @@
-{ This file was automatically created by Lazarus. Do not edit!
-  This source is only used to compile and install the package.
- }
-
-unit pkg_gifanim_dsgn;
-
-interface
-
-uses
-  GifAnimDsgn, LazarusPackageIntf;
-
-implementation
-
-procedure Register;
-begin
-  RegisterUnit('GifAnimDsgn', @GifAnimDsgn.Register);
-end;
-
-initialization
-  RegisterPackage('pkg_gifanim_dsgn', @Register);
-end.

+ 0 - 5
components/gifanim/readme.txt

@@ -1,5 +0,0 @@
-GifAnim
-http://wile64.perso.neuf.fr/download/download.php?cat=4&id=8
-Version 1.4 (14/09/2009)
-
-Some modifications done for Double Commander (see doublecmd.diff).

+ 0 - 28
components/gifanim/ressource-file.txt

@@ -1,28 +0,0 @@
-
-1) Gif in ressource file
--------------------------
-
-- Create ressource file with lazres ex : lazres mygif.lrs gif1.gif gif2.gif
-- Put TGifAnim on your form 
-- In the FormCreate add (see down)
-
-[code]
-
-procedure TForm1.FormCreate(Sender: TObject);
-begin
-  GifAnim1.LoadFromLazarusResource('gif1');
-  GifAnim2.LoadFromLazarusResource('gif2');
-end;
-
-[/code]
-
-- And insert ressouce file in initialization section (see down)
-
-[code]
-
-initialization
-  {$I unit1.lrs}
-  {$I mesgif.lrs}
-
-[/code]
-

+ 0 - 58
components/gifanim/tgifanim.xpm

@@ -1,58 +0,0 @@
-/* XPM */
-static char * gifanim_xpm[] = {
-"24 24 31 1",
-" 	c None",
-".	c #959595",
-"+	c #E1E1E1",
-"@	c #919191",
-"#	c #848484",
-"$	c #888888",
-"%	c #EEEEEE",
-"&	c #E6E9EC",
-"*	c #D6DFE8",
-"=	c #FFFFFF",
-"-	c #E7F0F9",
-";	c #3783CE",
-">	c #FFF7F7",
-",	c #FFEFEF",
-"'	c #F7F2F5",
-")	c #F7FAFD",
-"!	c #FF5757",
-"~	c #FFDFDF",
-"{	c #FF4F4F",
-"]	c #FFD7D7",
-"^	c #FF4747",
-"/	c #FF3F3F",
-"(	c #8D8D8D",
-"_	c #EEE6E6",
-":	c #EED6D6",
-"<	c #EECECE",
-"[	c #FAFAFA",
-"}	c #F2F2F2",
-"|	c #F6F6F6",
-"1	c #A2A2A2",
-"2	c #FAF2F2",
-" .++@              @++. ",
-" @@@##$$$$$$$$$$$$##@@@ ",
-" .++$#$$$$$$$$$$$$#$++. ",
-" .++@+%%&**&&**&%%+@++. ",
-" @@@@%==-;;--;;-==%@@@@ ",
-" .++.%==-;;--;;-==%.++. ",
-" .++.%>,'--))--',>%.++. ",
-" @@@@%,!~>====>~!,%@@@@ ",
-" .++.%>~{]~~~~]{~>%.++. ",
-" .++.%=>~^////^~>=%.++. ",
-" @@@(+%%_:<<<<:_%%+(@@@ ",
-" .++$#$$$$$$$$$$$$#$++. ",
-" .++$#$$$$$$$$$$$$#$++. ",
-" @@@(+%%&**&%%%%%%+(@@@ ",
-" .++.%==-;;-[}}[==%.++. ",
-" .++.%==-;;-|11|==%.++. ",
-" @@@@%>,'--)[}}2,>%@@@@ ",
-" .++.%,!~>====>~!,%.++. ",
-" .++.%>~{]~~~~]{~>%.++. ",
-" @@@@%=>~^////^~>=%@@@@ ",
-" .++@+%%_:<<<<:_%%+@++. ",
-" .++$#$$$$$$$$$$$$#$++. ",
-" @@@##$$$$$$$$$$$$##@@@ ",
-" .++@              @++. "};

+ 373 - 0
components/gifview/LICENSE.txt

@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+    means each individual or legal entity that creates, contributes to
+    the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+    means the combination of the Contributions of others (if any) used
+    by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+    means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+    means Source Code Form to which the initial Contributor has attached
+    the notice in Exhibit A, the Executable Form of such Source Code
+    Form, and Modifications of such Source Code Form, in each case
+    including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+    means
+
+    (a) that the initial Contributor has attached the notice described
+        in Exhibit B to the Covered Software; or
+
+    (b) that the Covered Software was made available under the terms of
+        version 1.1 or earlier of the License, but not also under the
+        terms of a Secondary License.
+
+1.6. "Executable Form"
+    means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+    means a work that combines Covered Software with other material, in
+    a separate file or files, that is not Covered Software.
+
+1.8. "License"
+    means this document.
+
+1.9. "Licensable"
+    means having the right to grant, to the maximum extent possible,
+    whether at the time of the initial grant or subsequently, any and
+    all of the rights conveyed by this License.
+
+1.10. "Modifications"
+    means any of the following:
+
+    (a) any file in Source Code Form that results from an addition to,
+        deletion from, or modification of the contents of Covered
+        Software; or
+
+    (b) any new file in Source Code Form that contains any Covered
+        Software.
+
+1.11. "Patent Claims" of a Contributor
+    means any patent claim(s), including without limitation, method,
+    process, and apparatus claims, in any patent Licensable by such
+    Contributor that would be infringed, but for the grant of the
+    License, by the making, using, selling, offering for sale, having
+    made, import, or transfer of either its Contributions or its
+    Contributor Version.
+
+1.12. "Secondary License"
+    means either the GNU General Public License, Version 2.0, the GNU
+    Lesser General Public License, Version 2.1, the GNU Affero General
+    Public License, Version 3.0, or any later versions of those
+    licenses.
+
+1.13. "Source Code Form"
+    means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+    means an individual or a legal entity exercising rights under this
+    License. For legal entities, "You" includes any entity that
+    controls, is controlled by, or is under common control with You. For
+    purposes of this definition, "control" means (a) the power, direct
+    or indirect, to cause the direction or management of such entity,
+    whether by contract or otherwise, or (b) ownership of more than
+    fifty percent (50%) of the outstanding shares or beneficial
+    ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+    Licensable by such Contributor to use, reproduce, make available,
+    modify, display, perform, distribute, and otherwise exploit its
+    Contributions, either on an unmodified basis, with Modifications, or
+    as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+    for sale, have made, import, and otherwise transfer either its
+    Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+    or
+
+(b) for infringements caused by: (i) Your and any other third party's
+    modifications of Covered Software, or (ii) the combination of its
+    Contributions with other software (except as part of its Contributor
+    Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+    its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+    Form, as described in Section 3.1, and You must inform recipients of
+    the Executable Form how they can obtain a copy of such Source Code
+    Form by reasonable means in a timely manner, at a charge no more
+    than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+    License, or sublicense it under different terms, provided that the
+    license for the Executable Form does not attempt to limit or alter
+    the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+*                                                                      *
+*  6. Disclaimer of Warranty                                           *
+*  -------------------------                                           *
+*                                                                      *
+*  Covered Software is provided under this License on an "as is"       *
+*  basis, without warranty of any kind, either expressed, implied, or  *
+*  statutory, including, without limitation, warranties that the       *
+*  Covered Software is free of defects, merchantable, fit for a        *
+*  particular purpose or non-infringing. The entire risk as to the     *
+*  quality and performance of the Covered Software is with You.        *
+*  Should any Covered Software prove defective in any respect, You     *
+*  (not any Contributor) assume the cost of any necessary servicing,   *
+*  repair, or correction. This disclaimer of warranty constitutes an   *
+*  essential part of this License. No use of any Covered Software is   *
+*  authorized under this License except under this disclaimer.         *
+*                                                                      *
+************************************************************************
+
+************************************************************************
+*                                                                      *
+*  7. Limitation of Liability                                          *
+*  --------------------------                                          *
+*                                                                      *
+*  Under no circumstances and under no legal theory, whether tort      *
+*  (including negligence), contract, or otherwise, shall any           *
+*  Contributor, or anyone who distributes Covered Software as          *
+*  permitted above, be liable to You for any direct, indirect,         *
+*  special, incidental, or consequential damages of any character      *
+*  including, without limitation, damages for lost profits, loss of    *
+*  goodwill, work stoppage, computer failure or malfunction, or any    *
+*  and all other commercial damages or losses, even if such party      *
+*  shall have been informed of the possibility of such damages. This   *
+*  limitation of liability shall not apply to liability for death or   *
+*  personal injury resulting from such party's negligence to the       *
+*  extent applicable law prohibits such limitation. Some               *
+*  jurisdictions do not allow the exclusion or limitation of           *
+*  incidental or consequential damages, so this exclusion and          *
+*  limitation may not apply to You.                                    *
+*                                                                      *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+  This Source Code Form is subject to the terms of the Mozilla Public
+  License, v. 2.0. If a copy of the MPL was not distributed with this
+  file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+  This Source Code Form is "Incompatible With Secondary Licenses", as
+  defined by the Mozilla Public License, v. 2.0.

+ 15 - 0
components/gifview/README.txt

@@ -0,0 +1,15 @@
+GifView
+
+Animated GIF Viewer Component
+
+Copyright (C) 2025 Alexander Koblov
+
+License:
+  MPL 2.0
+
+Based on:
+  TGIFViewer
+  https://github.com/jdelauney/TGIFViewer
+
+Original author:
+  Copyright (C) 2018 J.Delauney (BeanzMaster)

+ 56 - 0
components/gifview/gifview.lpk

@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <Package Version="5">
+    <PathDelim Value="\"/>
+    <Name Value="GifView"/>
+    <Type Value="RunAndDesignTime"/>
+    <Author Value="Jérôme Delauney (BeanzMaster), Alexander Koblov"/>
+    <CompilerOptions>
+      <Version Value="11"/>
+      <PathDelim Value="\"/>
+      <SearchPaths>
+        <OtherUnitFiles Value="source"/>
+        <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
+      </SearchPaths>
+      <Linking>
+        <Debugging>
+          <DebugInfoType Value="dsDwarf2Set"/>
+        </Debugging>
+      </Linking>
+    </CompilerOptions>
+    <Description Value="GIF Viewer"/>
+    <License Value="MPL-2.0"/>
+    <Version Major="1"/>
+    <Files>
+      <Item>
+        <Filename Value="source\GifViewerStrConsts.pas"/>
+        <UnitName Value="GifViewerStrConsts"/>
+      </Item>
+      <Item>
+        <Filename Value="source\uFastBitmap.pas"/>
+        <UnitName Value="uFastBitmap"/>
+      </Item>
+      <Item>
+        <Filename Value="source\uGifViewer.pas"/>
+        <HasRegisterProc Value="True"/>
+        <UnitName Value="uGifViewer"/>
+      </Item>
+    </Files>
+    <RequiredPkgs>
+      <Item>
+        <PackageName Value="LCL"/>
+        <MinVersion Major="2" Minor="2" Valid="True"/>
+      </Item>
+      <Item>
+        <PackageName Value="FCL"/>
+      </Item>
+    </RequiredPkgs>
+    <UsageOptions>
+      <UnitPath Value="$(PkgOutDir)"/>
+    </UsageOptions>
+    <PublishOptions>
+      <Version Value="2"/>
+      <UseFileFilters Value="True"/>
+    </PublishOptions>
+  </Package>
+</CONFIG>

+ 22 - 0
components/gifview/gifview.pas

@@ -0,0 +1,22 @@
+{ This file was automatically created by Lazarus. Do not edit!
+  This source is only used to compile and install the package.
+ }
+
+unit GifView;
+
+{$warn 5023 off : no warning about unused units}
+interface
+
+uses
+  GifViewerStrConsts, uFastBitmap, uGifViewer, LazarusPackageIntf;
+
+implementation
+
+procedure Register;
+begin
+  RegisterUnit('uGifViewer', @uGifViewer.Register);
+end;
+
+initialization
+  RegisterPackage('GifView', @Register);
+end.

BIN
components/gifview/gifview.res


+ 36 - 0
components/gifview/source/GifViewerStrConsts.pas

@@ -0,0 +1,36 @@
+Unit GifViewerStrConsts;
+
+{$mode objfpc}{$H+}
+
+Interface
+
+ResourceString
+  // Messages d'erreurs ou de notifications
+  // Error or notification messages
+  //uGifViewer
+  rsScreenBadColorSize       = 'Invalid number of colors in the global palette.';
+  rsImageBadColorSize        = 'Number of colors is invalid in local palette.';
+  rsBadSignature             = 'GIF invalid signature: %s';
+  rsBadScreenSize            = 'Invalid image size: %dx%d';
+  rsEmptyColorMap            = 'Error no palette of color available for this image!';
+  rsEmptyImage               = 'The picture is empty';
+  rsUnknownVersion           = 'Unknown GIF version';
+  rsFileNotFound             = 'The file %s  not found !';
+  rsResourceNotFound         = 'Resource %s not found!';
+  rsBufferOverFlow           = 'Image #%d: The decoder has been stopped to prevent a buffer overflow';
+  rsInvalidOutputBufferSize  = 'Image #%d: The size of the output buffer is invalid (size < = 0)';
+  rsInvalidInputBufferSize   = 'Image #%d: The size of the input buffer is invalid (size < = 0)';
+  rsInvalidBufferSize        = 'Image #%d: The size of the input and output buffer are invalid (size < = 0)';
+  rsLZWInternalErrorOutputBufferOverflow = 'Output buffer overflow in the GIF LZW decoder buffer. Report this bug. This is a serious bug!';
+  rsLZWInternalErrorInputBufferOverflow  = 'Input buffer overflow in the GIF LZW decoder. Report this bug. This is a serious bug!';
+  rsLZWInvalidInput         = 'Image #%d: The decoder encountered an invalid entry (corrupted data)';
+  rsLZWOutputBufferTooSmall  = 'Image #%d: The decoder could not decode all the data because the output buffer is too small';
+  rsAllFrameCorrupted        = 'All images in the GIF are corrupted. Unable to display GIF file.';
+  //uFastBitmap
+  rsBitmapCreateError = 'An Error occured while creating TBitmap';
+  rsBitmapScanlineOutOfRange = 'Scanline : Index Out of range';
+
+Implementation
+
+End.
+

+ 1048 - 0
components/gifview/source/uFastBitmap.pas

@@ -0,0 +1,1048 @@
+Unit uFastBitmap;
+(*==============================================================================
+ DESCRIPTION   : Classe de manipulation basique de bitmap en 32 bit.
+                 Basic Class for manipulating 32 bit Bitmap
+ DATE          : 17/06/2018
+ VERSION       : 1.0
+ AUTEUR        : J.Delauney (BeanzMaster)
+ LICENCE       : MPL
+================================================================================
+*)
+
+{$mode objfpc}{$H+}
+{$modeswitch advancedrecords}
+
+Interface
+
+Uses
+  LCLType, LCLIntf, Classes, SysUtils, GraphType, Graphics, Contnrs, Dialogs,
+  IntfGraphics, FPimage;
+
+Const
+  { Constantes utiles pour le calcul sur les masques de couleur }
+  { Useful constants for calculation on color masks }
+  {$IFDEF WINDOWS} // Format BGRA
+    cBlueOrder = 0;
+    cGreenOrder = 1;
+    cRedOrder = 2;
+    cAlphaOrder = 3;
+  {$ELSE} // Format RGBA
+    cRedOrder = 0;
+    cGreenOrder = 1;
+    cBlueOrder = 2;
+    cAlphaOrder = 3;
+  {$ENDIF}
+  cRedShift = cRedOrder * 8;
+  cGreenShift = cGreenOrder * 8;
+  cBlueShift = cBlueOrder * 8;
+  cAlphaShift = cAlphaOrder * 8;
+
+  maskRed = 1;
+  maskGreen = 2;
+  maskBlue = 4;
+  maskAlpha = 8;
+  maskRGB = maskRed Or maskGreen Or maskBlue;
+  maskRGBA = maskRGB Or maskAlpha;
+
+Type
+  { TColorRGB24 : Définition d'un pixel sur 24 bits au format RGB }
+  { TColorRGB24 : Definition of a 24-bit pixel in RGB format }
+  TColorRGB24Type = packed array[0..2] of byte;
+  TColorRGB24 = packed record
+    { Creation de la couleur / Create Color }
+    procedure Create(R,G,B : Byte); Overload;
+    procedure Create(Color:TColor); Overload;
+
+    { Conversion vers un TColor / Convert to TColor }
+    function ToColor : TColor;
+
+    Case Integer of
+     0 : (V:TColorRGB24Type);     // Acces via Tableau / Array
+     1 : (Red, Green, Blue:Byte); // Acces via Composantes / Channel
+  end;
+
+  { TColor32 : Définition d'un pixel sur 32 bits au format RGBA ou BGRA suivant l'OS }
+  { TColor32: Definition of a 32-bit pixel in RGBA or BGRA format depending on the OS }
+  TColor32Type = packed array[0..3] of byte;
+  TColor32 = Packed Record
+  private
+    function getColorComponent(Index : Integer): byte;
+    procedure SetColorComponent(Index : Integer; aValue:Byte);
+  public
+    { Creation de la couleur / Create Color }
+    procedure Create(R,G,B,A : Byte); Overload;
+    procedure Create(R,G,B : Byte);   Overload;
+    procedure Create(Color : TColor); Overload;
+    procedure Create(Color : TColorRGB24); Overload;
+
+    { Conversion vers un TColor / Convert to TColor }
+    function ToColor : TColor;
+    { Conversion vers un TColorRGB24 / Convert to TColorRGB24 }
+    function ToColorRGB24 : TColorRGB24;
+    { Conversion vers un TFPColor / Convert to TFPColor }
+    function ToFPColor : TFPColor;
+
+    { Mixage de la couleur courrante avec la couleur "Color" avec prise en charge du canal Alpha }
+    { Mix current color with 'Color' color with Alpha channel support }
+    function Blend(Color : TColor32): TColor32;
+
+    { Vérifie si 2 valeurs sont identiques / Check if 2 colors are equal }
+    class operator =(Color1,Color2 : TColor32):Boolean;
+
+    { Accès aux composantes de la couleur / Color channel access }
+    property Red:Byte Index cRedOrder read GetColorComponent Write SetColorComponent;
+    property Green:Byte Index cGreenOrder read GetColorComponent Write SetColorComponent;
+    property Blue:Byte Index cBlueOrder read GetColorComponent Write SetColorComponent;
+    property Alpha:Byte Index cAlphaOrder read GetColorComponent Write SetColorComponent;
+
+    Case Integer of
+     0 : (V:TColor32Type);  // Acces via tableau / Array
+     1 : (AsInteger : Integer); // Acces via Integer
+  End;
+  PColor32 = ^TColor32;
+
+  { TColor32Item : Objet persistant englobant une couleur de type TColor32 }
+  { TColor32Item: Persistent object that includes a TColor32 color }
+  TColor32Item = Class(TPersistent)
+  Private
+    FColor: TColor32;
+    FName:  String;
+    FTag:   Integer;
+
+    Procedure SetRed(Const AValue: Byte);
+    Procedure SetGreen(Const AValue: Byte);
+    Procedure SetBlue(Const AValue: Byte);
+    Procedure SetAlpha(Const AValue: Byte);
+    Procedure SetValue(Const AValue: TColor32);
+    Procedure SetColorName(Const aName: String);
+
+    Function getRed: Byte;
+    Function getGreen: Byte;
+    Function getBlue: Byte;
+    Function getAlpha: Byte;
+    Function getValue: TColor32;
+
+  Protected
+  Public
+    Constructor Create;
+    Destructor Destroy; override;
+
+    { Valeur de la couleur / Value of the color }
+    Property Value: TColor32 read getValue write setValue;
+    { Nom de la couleur eg : clrRed  / Name of the color}
+    Property Name: String read FName write setColorName;
+  Published
+    { Valeur du canal rouge / Red channel }
+    Property Red: Byte read getRed write setRed;
+    { Valeur du canal vert / Green channel }
+    Property Green: Byte read getRed write setGreen;
+    { Valeur du canal Bleu / Blue channel }
+    Property Blue: Byte read getRed write setBlue;
+    { Valeur du canal alpha pour la transparence / Alpha channel for transparency }
+    Property Alpha: Byte read getRed write setAlpha;
+    {  Valeur complémentaire personnel / User define value }
+    Property Tag: Integer read FTag write FTag;
+  End;
+
+  { TColor32List : Classe pour la gestion d'une palette (liste) de couleurs }
+  { TColor32List : Class for managing a palette (list) of colors }
+  TColor32List = Class(TObjectList)
+  Private
+  Protected
+    Function GetColorItem(index: Integer): TColor32Item;
+    Procedure SetColorItem(index: Integer; val: TColor32Item);
+  Public
+    { Efface la liste / Clear the list }
+    procedure Clear; override;
+    { Ajoute une couleur à la liste / Add a color to the list }
+    Function AddColor(Const aColor: TColor32): Integer; Overload;
+    { Ajoute une couleur à la liste /Add a color to the list }
+    Function AddColor(Const aName: String; Const aColor: TColor32): Integer; Overload;
+    { Ajoute une couleur à la liste / Add a color to the list}
+    Function AddColor(Const aColorItem: TColor32Item): Integer; Overload;
+    { Supprime une couleur de la liste / Delete a color of the list }
+    Procedure RemoveColor(Const aName: String);
+    { Recherche une couleur dans la liste / Search color in list }
+    Function FindColorByName(Const aName: String; Out Index: Integer):TColor32; Overload;
+    { Recherche une couleur dans la liste  / Search color in list }
+    Function FindColorByName(Const aName: String): TColor32; Overload;
+
+    { Colors : Acceder à la couleur "Index" de la liste / Color access with Index }
+    Property Colors[Index: Integer]: TColor32Item read GetColorItem write setColorItem;
+  End;
+
+Const
+  clrTransparent : TColor32 = (v:($00,$00,$00,$00));
+  clrBlack       : TColor32 = (v:($00,$00,$00,$FF));
+  clrWhite       : TColor32 = (v:($FF,$FF,$FF,$FF));
+
+
+Type
+  { TFastBitmapDrawMode : Mode d'Affichage pour la fonction PutImage de TFastBitmap }
+  { TFastBitmapDrawMode : Display Mode for the PutImage Function of TFastBitmap }
+  TFastBitmapDrawMode = ( dmSet, dmAlpha, dmAlphaCheck);
+
+  { TFastBitmap }
+  { Classe d'aide à la manipulation d'une image }
+  { Help class for image manipulation }
+  TFastBitmap = Class
+  Strict private
+    FTransparentColor : TColor; // Couleur transparent à pour l'affichage via TBitmap de la LCL si besoin / Transparent color for display via TBitmap of the LCL if needed
+
+    FData     : PDWord;    // Tampon de stockage des données d'un bitmap / Buffer for storing data from a bitmap
+    FWidth    : Integer;   // Largeur du bitmap / Width
+    FHeight   : Integer;   // Hauteur du Bitmap / Height
+    FSize     : Int64;     // Taille du tampon en octet / Size in byte
+
+  protected
+
+    procedure SetWidth(NewWidth : Integer);
+    procedure SetHeight(NewHeight : Integer);
+
+    function BuildBitmap : Graphics.TBitmap;
+    function IsClipped(X,Y:Integer) : Boolean;
+
+
+  Public
+    Constructor Create; Overload;
+    Constructor Create(NewWidth, NewHeight : Integer); Overload;
+    Destructor Destroy; Override;
+
+    { Assigne les donnée d'un autre TFastBitmap / Assign another TFastBitmap }
+    procedure Assign(aFastBitmap : TFastBitmap);
+    { Modifie les dimensions du bitmap / Change size of bitmap }
+    procedure SetSize(NewWidth, NewHeight : Integer);
+    { Importation des données d'un TRawImage. Retourne "TRUE" en cas de succès }
+    { Import from RawImage. Return TRUE on success }
+    function ImportFromRawImage(Const ARawImage : TRawImage):Boolean;
+    { Importation des données d'un TBitmap. Retourne "TRUE" en cas de succès }
+    { Import from TBitmap. Return TRUE on success }
+    function ImportFromBitmap(Const ABitmap :Graphics.TBitmap):Boolean;
+    { Efface le bitmap avec la couleur "Color" / Clear bitmap with Color }
+    procedure Clear(Color : TColor32);
+    { Retourne le tampon du bitmap / Return bitmap buffer }
+    function GetSurfaceBuffer : PColor32;
+    { Retourne l'adresse de la ligne "Y" dans le tampon / Return address in buffer of a line }
+    function GetScanLine(Y : Integer) : PColor32;
+    { Retourne l'adresse du pixel à la position "X,Y" dans le tampon / Return address at X,Y}
+    function GetPixelPtr(X, Y : Integer) : PColor32;
+    { Ecrit un pixel de couleur "Color" à la position "X,Y / Put pixel X,Y with Color }
+    procedure PutPixel(X,Y:Integer; Color : TColor32);
+    { Lit un pixel de couleur "Color" à la position "X,Y / Get color of pixel at X,Y }
+    function GetPixel(X,Y:Integer): TColor32;
+    { Ecrit un pixel de en mixant couleur "Color" avec la couleur du pixel présent dans le tampon à la position "X,Y }
+    { Writes a pixel by mixing 'Color' color with the color of the pixel present in the buffer at the 'X, Y' position }
+    procedure PutPixelBlend(X,Y : Integer; Color : TColor32);
+    { Copie une image source "Src" depuis la position "SrcX,SrcY" et de dimension "SrcWidthxSrcHeight" dans le bitmap à la position "DstX, DstY
+      et suivant le "Mode"
+       Mode : TFastBitmapDrawMode
+        - dmSet : Copie brute de l'image
+        - dmAlpha : Copie les pixel de l'image source en mixant les couleurs avec celles du bitmap en fonction de leur valeur Alpha
+        - dmAlphaCheck : Copie les pixels de l'image source seulement si le pixel est visible (Alpha <> 0)
+       Note : les dimensions et les positions entre le bitmap et l'image source sont automatiquement ajustées si besoin.
+
+    --------------------------
+      Copy a source image 'Src' from the position 'SrcX, SrcY' and dimension 'SrcWidthxSrcHeight' into the bitmap at the position 'DstX, DstY
+      and following the 'Mode'
+       Mode: TFastBitmapDrawMode
+        - dmSet: Raw copy of the image
+        - dmAlpha: Copy the pixels of the source image by mixing the colors with those of the bitmap according to their Alpha value
+        - dmAlphaCheck: Copy the pixels of the source image only if the pixel is invisible (Alpha <> 0)
+       Note: The dimensions and positions between the bitmap and the source image are automatically adjusted if necessary.
+    }
+    procedure PutImage(Src : TFastBitmap; SrcX, SrcY, SrcWidth, SrcHeight, DstX, DstY : Integer; Mode : TFastBitmapDrawMode);
+    { Creation  d'un clone du bitmap (nouvelle instance) / Create clone (new instance) }
+    function Clone : TFastBitmap;
+    { Retourne un bitmap de type LCL ==> Graphics.TBitmap / Return a TBitmap}
+    function GetBitmap : Graphics.TBitmap;
+    { Dessine le bitmap sur un canvas à la position "X,Y" / Draw the bitmap on a canvas }
+    procedure Draw(ACanvas : TCanvas; X,Y : Integer);  Overload;
+    { Dessine le bitmap sur un canvas délimité par "Rect" / Draw the bitmap on a canvas delimited by "Rect" }
+    procedure Draw(ACanvas : TCanvas; Rect : TRect);   Overload;
+    { Inverse les composante de couleur Rouge et Bleu du bitmap  / Swap Red and Blue channel }
+    procedure SwapRB;
+
+   // procedure HLine(X,Y,X2 : Integer; aColor : TColor32);
+    { Information sur la couleur assignée à la transparence (seulement valable si différent de clrTransparent) / Return the transparency color }
+    property TransparentColor : TColor Read FTransparentColor Write FTransparentColor;
+    { Largeur du bitmap / Width }
+    property Width : Integer Read FWidth Write SetWidth;
+    { Hauteur du bitmap / Height }
+    property Height : Integer Read FHeight Write SetHeight;
+    { Taille du tampon en octet / Size of the buffer }
+    property Size : Int64 Read FSize;
+  End;
+
+Implementation
+
+Uses Types, Math, GifViewerStrConsts;
+
+
+
+{%region=====[ TColorRGB24 ]====================================================}
+
+Procedure TColorRGB24.Create(R, G, B : Byte);
+Begin
+ Red := R;
+ Green := G;
+ Blue := B;
+End;
+
+Procedure TColorRGB24.Create(Color : TColor);
+Var
+  lr,lg,lb : Byte;
+Begin
+  lr := Color;
+  lg := Color shr 8;
+  lb := Color shr 16;
+  Create(lr,lg,lb);
+End;
+
+Function TColorRGB24.ToColor : TColor;
+Begin
+  Result := Red + (Green shl 8) + (Blue shl 16);
+End;
+
+{%endregion%}
+
+{%region=====[ TColor32 ]===================================================}
+
+function TColor32.getColorComponent(Index: Integer): byte;
+Begin
+  result := v[Index];
+End;
+
+procedure TColor32.SetColorComponent(Index: Integer; aValue: Byte);
+Begin
+  v[Index] := aValue;
+End;
+
+procedure TColor32.Create(R, G, B, A: Byte);
+Begin
+  Red := R;
+  Green := G;
+  Blue := B;
+  Alpha := A;
+End;
+
+procedure TColor32.Create(R, G, B: Byte);
+Begin
+  Create(R,G,B,255);
+End;
+
+procedure TColor32.Create(Color: TColor);
+Var
+  ColorRGB24 : TColorRGB24;
+Begin
+  {%H-}ColorRGB24.Create(Color);
+  Create(ColorRGB24);
+End;
+
+procedure TColor32.Create(Color: TColorRGB24);
+Begin
+  Create(Color.Red,Color.Green,Color.Blue);
+End;
+
+function TColor32.ToColor: TColor;
+Begin
+ Result := ToColorRGB24.ToColor;
+End;
+
+function TColor32.ToColorRGB24: TColorRGB24;
+Begin
+ Result.Red := Red;
+ Result.Green := Green;
+ Result.Blue := Blue;
+End;
+
+function TColor32.ToFPColor: TFPColor;
+begin
+  Result.Red   := Self.Red shl 8 + Self.Red;
+  Result.Green := Self.Green shl 8 + Self.Green;
+  Result.Blue  := Self.Blue shl 8 + Self.Blue;
+  Result.Alpha := Self.Alpha shl 8 + Self.Alpha;
+end;
+
+function TColor32.Blend(Color: TColor32): TColor32;
+var
+  factor, factor2:single;
+begin
+
+  if Color.Alpha = 255 then Result := Color
+  else  if (Color.Alpha = 0) or (Self = Color) then Result:= Self
+  else
+  begin
+    factor := Color.Alpha / 255;
+    factor2 := 1 - Factor;
+    Result.Red  := Round((Self.Red*Factor)+(Color.Red*factor2));
+    Result.Green  := Round((Self.Green*Factor)+(Color.Green*Factor2));
+    Result.Blue  := Round((Self.Blue*Factor)+(Color.Blue*Factor2));
+    Result.alpha := Round((Self.Alpha*Factor)+(Color.Alpha*Factor2));
+  End;
+end;
+
+class operator TColor32.=(Color1, Color2: TColor32): Boolean;
+Begin
+  Result := False;
+  if (Color1.Alpha = 0) and (Color2.Alpha = 0) then Result :=True
+  else Result := ((Color1.Red = Color2.Red) and (Color1.Green = Color2.Green) and (Color1.Blue = Color2.Blue) and (Color1.Alpha = Color2.Alpha))
+End;
+
+{%endregion%}
+
+{%region=====[ TColor32Item ]===============================================}
+
+Constructor TColor32Item.Create;
+Begin
+  Inherited Create;
+  FName := 'Black';
+  FColor.Create(0,0,0);
+  FTag := 0;
+End;
+
+Destructor TColor32Item.Destroy;
+Begin
+  Inherited Destroy;
+End;
+
+Procedure TColor32Item.SetRed(Const AValue: Byte);
+Begin
+  If AValue = FColor.red Then exit;
+  FColor.Red := AValue;
+End;
+
+Procedure TColor32Item.SetGreen(Const AValue: Byte);
+Begin
+  If AValue = FColor.Green Then exit;
+  FColor.Green := AValue;
+End;
+
+Procedure TColor32Item.SetBlue(Const AValue: Byte);
+Begin
+  If AValue = FColor.Blue Then exit;
+  FColor.Blue := AValue;
+End;
+
+Procedure TColor32Item.SetAlpha(Const AValue: Byte);
+Begin
+  If AValue = FColor.Alpha Then exit;
+  FColor.Alpha := AValue;
+End;
+
+Procedure TColor32Item.SetValue(Const AValue: TColor32);
+Begin
+  If AValue = FColor Then exit;
+  FColor := AValue;
+End;
+
+Function TColor32Item.getRed: Byte;
+Begin
+  Result := FColor.Red;
+End;
+
+Function TColor32Item.getGreen: Byte;
+Begin
+  Result := FColor.Green;
+End;
+
+Function TColor32Item.getBlue: Byte;
+Begin
+  Result := FColor.Blue;
+End;
+
+Function TColor32Item.getAlpha: Byte;
+Begin
+  Result := FColor.Alpha;
+End;
+
+Function TColor32Item.getValue: TColor32;
+Begin
+  Result := FColor;
+End;
+
+Procedure TColor32Item.SetColorName(Const aName: String);
+Begin
+  If FName = aName Then exit;
+  FName := aName;
+End;
+
+{%endregion%}
+
+{%region ====[ TColor32List ]===============================================}
+
+Function TColor32List.GetColorItem(index: Integer): TColor32Item;
+Begin
+  Result := TColor32Item(Get(Index));
+End;
+
+Procedure TColor32List.SetColorItem(index: Integer; val: TColor32Item);
+Begin
+  Put(Index, Val);
+End;
+
+procedure TColor32List.Clear;
+Var
+  anItem: TColor32Item;
+  i : Integer;
+Begin
+  inherited Clear;
+  If Count > 0 then
+  begin
+    For i :=Count -1 downto 0 do
+    begin
+      AnItem:= Colors[i];
+      if anItem<>nil then anItem.Free;
+    End;
+  End;
+End;
+
+Function TColor32List.AddColor(Const aColor: TColor32): Integer;
+Var
+  aColorItem: TColor32Item;
+Begin
+  aColorItem := TColor32Item.Create;
+  aColorItem.Value := aColor;
+  Result := Add(aColorItem);
+End;
+
+Function TColor32List.AddColor(Const aName: String; Const aColor: TColor32): Integer;
+Var
+  aColorItem: TColor32Item;
+Begin
+  aColorItem := TColor32Item.Create;
+  aColorItem.Value := aColor;
+  aColorItem.Name := aName;
+  Result := Add(aColorItem);
+End;
+
+Function TColor32List.AddColor(Const aColorItem: TColor32Item): Integer;
+Begin
+  Result := Add(aColorItem);
+End;
+
+Procedure TColor32List.RemoveColor(Const aName: String);
+Var
+  I:   Integer;
+  Col: TColor32Item;
+Begin
+  FindColorByName(aName, I);
+  If I > -1 Then
+  Begin
+    Col := GetColorItem(I);
+    If Assigned(Col) Then
+      Col.Free;
+    Delete(I);
+  End;
+End;
+
+Function TColor32List.FindColorByName(Const aName: String; Out Index: Integer): TColor32;
+Var
+  i: Integer;
+Begin
+  Result := clrTransparent;
+  Index := -1;
+  For i := 0 To Count - 1 Do
+    If TColor32Item(Items[i]).Name = aName Then
+    Begin
+      Index := I;
+      Result := TColor32Item(Items[i]).Value;
+      break;
+    End;
+End;
+
+Function TColor32List.FindColorByName(Const aName: String): TColor32;
+Var
+  i: Integer;
+Begin
+  Result := FindColorByName(aName, I);
+End;
+
+{%endregion%}
+
+{%region=====[ TFastBitmap ]====================================================}
+
+Constructor TFastBitmap.Create(NewWidth, NewHeight : Integer);
+Begin
+ inherited Create;
+  FWidth  := Max(1,NewWidth);
+  FHeight := Max(1,NewHeight);
+  FData := Nil;
+  FSize := (int64(FWidth) * int64(FHeight))*4;
+  ReAllocMem(FData,FSize);
+  FTransparentColor := clBlack;
+End;
+
+Constructor TFastBitmap.Create;
+Begin
+  Create(1,1);
+End;
+
+Destructor TFastBitmap.Destroy;
+Begin
+  FreeMem(FData);
+  FData := Nil;
+  inherited Destroy;
+End;
+
+Procedure TFastBitmap.SetWidth(NewWidth : Integer);
+Begin
+  if NewWidth = FWidth then Exit;
+  SetSize(NewWidth, FHeight);
+End;
+
+Procedure TFastBitmap.SetHeight(NewHeight : Integer);
+Begin
+  if NewHeight = FHeight then Exit;
+  SetSize(FWidth, NewHeight);
+End;
+
+Function TFastBitmap.BuildBitmap: Graphics.TBitmap;
+Var
+  Temp : Graphics.TBitmap;
+  IntfBmp : TLazIntfImage;
+  ImgFormatDescription: TRawImageDescription;
+  W,H,X,Y : Integer;
+  SrcPix : PColor32;
+Begin
+
+  (* /!\ Le code si dessous fonctionne parfaitement sous Windows et Mac.
+     Mais sous Linux ce code produit des erreur au niveau de la transparence
+
+    BmpHandle := 0;
+    MskHandle := 0;
+    W := FWidth;
+    H := FHeight;
+    Buffer := PByte(GetSurfaceBuffer);
+
+    RawImage.Init;
+    {$IFDEF WINDOWS}
+    RawImage.Description.Init_BPP32_B8G8R8A8_BIO_TTB(W,H);
+    {$ELSE}
+    RawImage.Description.Init_BPP32_R8G8B8A8_BIO_TTB(W,H);
+    {$ENDIF}
+
+    RawImage.Data := Buffer;
+    RawImage.DataSize := FSize;
+
+    if not RawImage_CreateBitmaps(RawImage, BmpHandle, MskHandle,False) then
+      Raise Exception.Create('Impossible de créer le TBitmap')
+    else
+    begin
+      Temp := Graphics.TBitmap.Create;
+      Temp.Width := W;
+      Temp.Height := H;
+      Temp.PixelFormat := pf32bit;
+      Temp.Handle := BmpHandle;
+      Temp.MaskHandle := MskHandle;
+      Temp.Transparent := True;
+      //Temp.TransparentColor := FTransparentColor;
+      //temp.TransparentMode := tmAuto;
+      Result := Temp;
+    End;
+  *)
+
+  Result := nil;
+
+  W := FWidth;
+  H := FHeight;
+
+  // Pour que la transparence soit gérée correctement sous Linux on est obligé de passer par TLazIntfImage
+  IntfBmp := TLazIntfImage.Create(W,H);
+  ImgFormatDescription.Init_BPP32_B8G8R8A8_BIO_TTB(W, H);
+  IntfBmp.DataDescription := ImgFormatDescription;
+
+  SrcPix := Self.GetSurfaceBuffer;
+  For Y:=0 to H-1 do
+    For X:=0 to W-1 do
+    begin
+      IntfBmp.Colors[x, y]:=SrcPix^.ToFPColor;
+      inc(SrcPix);
+    end;
+
+  begin
+    Temp := Graphics.TBitmap.Create;
+    Temp.LoadFromIntfImage(IntfBmp);
+    Result := Temp;
+    IntfBmp.Free;
+  End;
+  if Result = nil then
+    Raise Exception.Create(rsBitmapCreateError);
+End;
+
+Function TFastBitmap.IsClipped(X, Y : Integer) : Boolean;
+Begin
+  Result := ((X>=0) and (Y>=0) and (X<FWidth) and (Y<FHeight));
+End;
+
+Procedure TFastBitmap.SwapRB;
+var
+  Pixptr: PColor32;
+  AIntColor : Cardinal;
+  PixelCount : Integer;
+begin
+  PixPtr := GetSurfaceBuffer;
+  PixelCount := (FWidth * FHeight)-1;
+  while pixelCount > 0 do
+  begin
+    AIntColor := PixPtr^.AsInteger;
+    PixPtr^.AsInteger := AIntColor and $FF00FF00 or (AintColor and $000000FF SHL 16) or (AIntColor and $00FF0000 SHR 16);
+    Inc(PixPtr);
+    Dec(pixelCount);
+  end;
+end;
+
+Procedure TFastBitmap.Assign(aFastBitmap : TFastBitmap);
+Begin
+  SetSize(aFastBitMap.Width, aFastBitmap.Height);
+  Move(PByte(aFastBitmap.GetSurfaceBuffer)^, PByte(FData)^, FSize);
+End;
+
+Procedure TFastBitmap.SetSize(NewWidth, NewHeight : Integer);
+Begin
+  FWidth  := Max(1,NewWidth);
+  FHeight := Max(1,NewHeight);
+  FSize :=(int64(FWidth) * int64(FHeight))*4;
+  if (FData<>nil) then
+  begin
+    FreeMem(FData);
+    FData := Nil;
+  End;
+  ReAllocMem(FData,FSize);
+  Clear(clrTransparent);
+End;
+
+Function TFastBitmap.ImportFromRawImage(Const ARawImage: TRawImage): Boolean;
+var
+  BufferData : PByte;
+begin
+  SetSize(ARawImage.Description.Width,ARawImage.Description.Height);
+  result:=false;
+  // On verifie si la taille des deux tampons sont identique
+  // Si ce n'est pas le cas, cela veut dire que le TRawImage n'est pas au format 32bit
+  if (ARawImage.DataSize= FSize) then
+  begin
+    try
+      BufferData := PByte(Self.getSurfaceBuffer);
+      Move(ARawImage.Data^, BufferData^, self.Size);
+      {$IFDEF WINDOWS}
+        if (ARawImage.Description.RedShift = 0) and ((ARawImage.Description.BlueShift = 16)) then Self.SwapRB; // Le RawImage est-il en RGB, si oui on échange
+      {$ELSE}
+        if (ARawImage.Description.RedShift = 16) and ((ARawImage.Description.BlueShift = 0)) then Self.SwapRB; // Le RawImage est-il en BGR, si oui on échange
+      {$ENDIF}
+    finally
+      result:=true;
+    end;
+  end;
+End;
+
+Function TFastBitmap.ImportFromBitmap(Const ABitmap: Graphics.TBitmap): Boolean;
+var
+  LTempBitmap: Graphics.TBitmap;
+  ok,ResetAlpha:Boolean;
+
+  procedure SetAlpha(Value : Byte);
+  var
+    i : Integer;
+    PixPtr : PColor32;
+    maxi : Integer;
+  begin
+    i:=0;
+    Maxi := (FWidth * FHeight)-1;
+    PixPtr :=PColor32(FData);// Self.GetScanLine(0);
+    While i<Maxi do
+    begin
+      PixPtr^.Alpha:= Value;
+      inc(PixPtr);
+      inc(i);
+    end;
+  end;
+
+begin
+  ResetAlpha:=False;
+  result:=false;
+  if (ABitmap.PixelFormat <> pf32bit)  then
+  begin
+    LTempBitmap := Graphics.TBitmap.Create;
+    try
+      ResetAlpha:=True;
+      LTempBitmap.SetSize(ABitmap.Width, ABitmap.Height);
+      LTempBitmap.PixelFormat := pf32bit;
+      LTempBitmap.Canvas.Draw(0, 0, ABitmap);
+    finally
+      ok:=Self.ImportFromRawImage(LTempBitmap.RawImage);
+      if ResetAlpha then SetAlpha(255);
+      FreeAndNil(LTempBitmap);
+      result:=true and (ok);
+    end;
+  end
+  else
+  begin
+   ok:=Self.ImportFromRawImage(ABitmap.RawImage);
+   result:=true and (ok);
+  end;
+End;
+
+Procedure TFastBitmap.Clear(Color : TColor32);
+Begin
+  FillDWord(FData^,FWidth * FHeight, DWord(Color));
+End;
+
+Function TFastBitmap.GetSurfaceBuffer: PColor32;
+Begin
+   Result := PColor32(FData);
+End;
+
+Function TFastBitmap.GetScanLine(Y : Integer) : PColor32;
+Var
+  yy : DWord;
+Begin
+  If (Y<0) or (Y>=FHeight) then
+    Raise Exception.Create(rsBitmapScanlineOutOfRange)
+  else
+  begin
+    yy := DWord(FWidth) * DWord(Y);
+    Result := PColor32(FData + YY);
+  End;
+End;
+
+Function TFastBitmap.GetPixelPtr(X, Y : Integer) : PColor32;
+Begin
+  Result := nil;
+  if IsClipped(X,Y) then
+  Begin
+    Result := PColor32(FData + (FWidth * Y) + X);
+  End;
+End;
+
+Procedure TFastBitmap.PutPixel(X, Y : Integer; Color : TColor32);
+Var
+  PixelPtr : PColor32;
+Begin
+  if IsClipped(X,Y) then
+  Begin
+    PixelPtr := PColor32(FData + DWord(FWidth * Y));
+    Inc(PixelPtr,X);
+    PixelPtr^:= Color;
+  End;
+End;
+
+Function TFastBitmap.GetPixel(X, Y : Integer) : TColor32;
+Var
+  PixelPtr : PColor32;
+Begin
+  Result := clrTransparent;
+  if IsClipped(X,Y) then
+  Begin
+    PixelPtr := PColor32(FData + (FWidth * Y) + X);
+    Result := PixelPtr^;
+  End;
+End;
+
+Procedure TFastBitmap.PutPixelBlend(X, Y : Integer; Color : TColor32);
+Var
+  PixelPtr : PColor32;
+Begin
+  if IsClipped(X,Y) then
+  Begin
+    PixelPtr := PColor32(FData + (FWidth * Y) + X);
+    PixelPtr^:= PixelPtr^.Blend(Color);
+  End;
+End;
+
+Procedure TFastBitmap.PutImage(Src : TFastBitmap; SrcX, SrcY, SrcWidth, SrcHeight, DstX, DstY : Integer; Mode : TFastBitmapDrawMode);
+Var
+  SrcPtr, DstPtr : PColor32;
+  NextSrcLine, NextDstLine : Integer;
+  DstCol, SrcCol : TColor32;
+  LineSize,TotalSize,xx,yy,i : Integer;
+
+  Procedure ClipCopyRect(Var SrcX, SrcY, rWidth, rHeight, DstX, DstY: Integer; SrcImageWidth, SrcImageHeight: Integer; Const DstClip: Types.TRect);
+    Var
+      diff, OldDstPosX, OldDstPosY: Integer;
+    Begin
+      OldDstPosX := 0;
+      If (DstX < 0) Then OldDstPosX := DstX;
+      OldDstPosY := 0;
+      If (DstY < 0) Then OldDstPosY := DstY;
+
+      If DstX < DstClip.Left Then
+      Begin
+        Diff := DstClip.Left - DstX;
+        rWidth := rWidth - Diff;
+        SrcX := SrcX + Diff;
+        DstX := DstClip.Left;
+      End;
+
+      If DstY < DstClip.Top Then
+      Begin
+        Diff := DstClip.Top - DstY;
+        rHeight := rHeight - Diff;
+        SrcY := SrcY + Diff;
+        DstY := DstClip.Bottom;
+      End;
+
+      If SrcX < 0 Then
+      Begin
+        Width := Width + SrcX - OldDstPosX;
+        DstX := DstX - SrcX + OldDstPosX;
+        SrcX := 0;
+      End;
+      If SrcY < 0 Then
+      Begin
+        rHeight := rHeight + SrcX - OldDstPosY;
+        DstY := DstY - SrcY + OldDstPosY;
+        SrcY := 0;
+      End;
+
+      If ((SrcX + rWidth) > SrcImageWidth) Then rWidth := SrcImageWidth - SrcX;
+      If ((SrcY + rHeight) > SrcImageHeight) Then rHeight := SrcImageHeight - SrcY;
+
+      if DstX > FWidth then DstX := 0;
+      if DstY > FHeight then DstY := 0;
+
+      If ((DstX + rWidth) >  (DstClip.Right+1)) Then rWidth := DstClip.Right - DstX;
+      If ((DstY + rHeight) > (DstClip.Bottom+1)) Then rHeight := DstClip.Bottom - DstY;
+
+    End;
+Begin
+
+  if (SrcWidth = 0) and (SrcHeight = 0) then exit;
+  ClipCopyRect(SrcX, SrcY, SrcWidth,SrcHeight, DstX, DstY, Src.Width, Src.Height, Types.Rect(0,0,FWidth-1, FHeight-1));
+
+
+  if (SrcWidth = 1) and (SrcHeight = 1) then
+  begin
+    Case Mode of
+      dmSet :
+        begin
+          SrcCol := Src.GetPixel(0,0);
+          PutPixel(0,0,SrcCol);
+        End;
+      dmAlpha :
+      begin
+        SrcCol := Src.GetPixel(0,0);
+        DstCol := GetPixel(0,0);
+        PutPixel(0,0,DstCol.Blend(SrcCol));
+      End;
+      dmAlphaCheck :
+        begin
+          If SrcCol.Alpha > 0 Then
+          begin
+            SrcCol := Src.GetPixel(0,0);
+            DstCol := GetPixel(0,0);
+            PutPixel(0,0,DstCol.Blend(SrcCol));
+          End
+          Else
+          begin
+            DstCol := GetPixel(0,0);
+            PutPixel(0,0,DstCol);
+          End;
+        End;
+    End;
+    exit;
+  End;
+
+  SrcPtr := Src.GetPixelPtr(SrcX,SrcY);
+  DstPtr := GetPixelPtr(DstX, DstY);
+
+  if SrcWidth <= Src.Width then
+    nextSrcLine := Src.Width
+  else
+    nextSrcLine := SrcX + (Src.Width - (SrcX + SrcWidth));
+  if Mode = dmSet then
+  begin
+    if (((Src.Width = FWidth) and (Src.Height = FHeight)) and ((SrcWidth = FWidth) and (SrcHeight = FHeight))) then
+      Move(SrcPtr^,DstPtr^,DWord(Src.Size))
+    else
+    begin
+      LineSize := SrcWidth * 4;
+      For I := 0 to SrcHeight-1 do
+      begin
+        Move(SrcPtr^, DstPtr^, LineSize);
+        Inc(SrcPtr, NextSrcLine);
+        Inc(DstPtr, FWidth);
+      End;
+    End;
+  End
+  else
+  begin
+    totalsize := (Src.Width * Src.Height) - 1;
+    Dec(SrcHeight);
+    xx := 0;
+    Dec(SrcWidth);
+    nextSrcLine := SrcX + (Src.Width - (SrcX + SrcWidth));
+    nextDstLine := DstX + (FWidth - (DstX + SrcWidth));
+    yy := 0;
+    xx := 0;
+    SrcCol := clrTransparent;
+    DstCol := clrTransparent;
+    While (yy <= TotalSize) Do
+    Begin
+      DstCol := DstPtr^;
+      SrcCol := SrcPtr^;
+      Case Mode of
+        dmAlpha :
+        begin
+          DstPtr^ := DstCol.Blend(SrcCol);
+        End;
+        dmAlphaCheck :
+        begin
+          If SrcCol.Alpha > 0 Then
+            DstPtr^ := DstCol.Blend(SrcCol)
+          Else
+            DstPtr^ := DstCol;
+        End;
+      End;
+      Inc(xx);
+      Inc(yy);
+      If (xx > SrcWidth) Then
+      Begin
+        xx := 0;
+        Inc(DstPtr, NextDstLine);
+        Inc(SrcPtr, NextSrcLine);
+      End
+      Else
+      Begin
+         Inc(SrcPtr);
+         Inc(DstPtr);
+      End;
+    End;
+  End;
+End;
+
+Function TFastBitmap.Clone : TFastBitmap;
+Var
+  NewBmp : TFastBitmap;
+Begin
+ NewBmp := TFastBitmap.Create;
+ NewBmp.Assign(Self);
+ Result := NewBmp;
+End;
+
+Function TFastBitmap.GetBitmap : Graphics.TBitmap;
+Begin
+  Result := BuildBitmap;
+End;
+
+Procedure TFastBitmap.Draw(ACanvas : TCanvas; X, Y : Integer);
+Var
+  Tmp : Graphics.TBitmap;
+Begin
+  Tmp :=  BuildBitmap;
+  ACanvas.Draw(X,Y,Tmp);
+  FreeAndNil(Tmp);
+End;
+
+Procedure TFastBitmap.Draw(ACanvas : TCanvas; Rect : TRect);
+Var
+  Tmp : Graphics.TBitmap;
+Begin
+  Tmp :=  BuildBitmap;
+  ACanvas.StretchDraw(Rect, Tmp);
+  FreeAndNil(Tmp);
+End;
+
+{%endregion%}
+End.
+
+

+ 2785 - 0
components/gifview/source/uGifViewer.pas

@@ -0,0 +1,2785 @@
+Unit uGifViewer;
+
+(*==============================================================================
+ DESCRIPTION   : Visual component for displaying an animated image in the
+                 GIF (Graphic Interchange Format) format
+ DATE          : 17/06/2018
+ UPDATE        : 01/07/2025
+ VERSION       : 1.0
+ AUTHOR        : J.Delauney (BeanzMaster)
+ CONTRIBUTORS  : Jipete, Jurassik Pork, bpranoto, Alexander Koblov
+ LICENSE       : MPL 2.0
+================================================================================
+*)
+
+{$mode objfpc}{$H+}
+
+Interface
+
+Uses
+  Types, Classes, SysUtils, Graphics, Math, Contnrs, Dialogs,
+  Controls, ExtCtrls,
+  Lresources, GifViewerStrConsts,
+  uFastBitmap;
+
+{%region=====[ Définitions des types et constantes utiles pour le format GIF ]===================================}
+Const
+  GIF_MaxColors  : Integer    = 256;    // Nombre de couleurs maximum supportées. NE PAS TOUCHER A CETTE VALEUR
+  GIF_DelayFactor  : Integer  = 10;     // Facteur de multiplication pour les délais en ms entre chaque image de l'animation
+  GIF_DefaultDelay  : Integer = 100;    // 10*10
+
+Type
+  TGIFVersion    = (gvUnknown, gv87a, gv89a);
+  TGIFVersionRec = Array[0..2] Of AnsiChar;
+
+Const
+  GIFVersions  : Array[gv87a..gv89a] Of TGIFVersionRec = ('87a', '89a');
+
+Type
+  { En-tête }
+  TGIFFileHeader = Packed Record
+    Signature: Array[0..2] Of AnsiChar; // 'GIF'
+    Version:   TGIFVersionRec;          // '87a' ou '89a' }
+  End;
+
+  { Description globale de l'image }
+  TGIFLogicalScreenDescriptorRec = Packed Record
+    ScreenWidth:  Word;             // Largeur de l'image en pixels // Width
+    ScreenHeight: Word;             // Hauteur de l'image en pixels // Height
+    PackedFields: Byte;             // champs compactés // Compacted field
+    BackgroundColorIndex: Byte;     // Index globale de la couleur de fond // Index of background color
+    AspectRatio:  Byte;             // Ratio d'échelle = (AspectRatio + 15) / 64
+  End;
+
+  { Description d'une image }
+  TGIFImageDescriptorRec = Packed Record
+    //Separator: byte;    // On lis toujours un byte avant  // we always read it before
+    Left:   Word;         // Colonne en pixels par rapport au bord gauche de l'écran // Column in pixels from the left edge of the screen
+    Top:    Word;         // Rangée en pixels par rapport au haut de l'écran // Row in pixels from the top edge of the screen
+    Width:  Word;         // Largeur de l'image en cours en pixels // image width
+    Height: Word;         // Hauteur de l'image en cours pixels // Image height
+    PackedFields: Byte;   // Champs compactés // Compacted field
+  End;
+
+  { Graphic Control Extension bloc a.k.a GCE }
+  TGIFGraphicControlExtensionRec = Packed Record
+    // BlockSize: byte;           // Normalement toujours 4 octets // Always 4 bytes
+    PackedFields: Byte;           // Champs compacté // Compacted field
+    DelayTime:    Word;           // Délai entre chaque image en centième de secondes // Delay between each image in hundredths of a second
+    TransparentColorIndex: Byte;  // Index dans la palette si plus petit ou égale  // Delay between each image in hundredths of a second
+    // Terminator: Byte;          // Normalement toujours ZERO // Normally always ZERO
+  End;
+
+  TGIFDisposalFlag = (dmNone, dmKeep, dmErase, dmRestore); // Methodes pour l'affichage des images lors de l'animation
+
+  { Plain Text Extension }
+  TGIFPlainTextExtensionRec = Packed Record
+    // BlockSize: byte;              // Normalement égal à 12 octets // Normally equal to 12 bytes
+    Left, Top, Width, Height: Word;  // Positions et dimensions du texte  // position and dimension of text
+    CellWidth, CellHeight:    Byte;  // Dimensions d'une cellule dans l'image // Size of cell
+    TextFGColorIndex,                // Index de la couleur de fond dans la palette // Index of the background color
+    TextBGColorIndex:         Byte;  // Index de la couleur du texte dans la palette // Index of the text color
+  End;
+
+  { Application Extension }
+  TGIFApplicationExtensionRec = Packed Record
+    AppID: Array [0..7] Of AnsiChar;                  // Identification de l'application majoritairement 'NETSCAPE' ou ''
+    AppAuthenticationCode: Array [0..2] Of AnsiChar;  // Code d'authentification ou numero de version
+  End;
+
+  { Informations de "l'application extension" si disponible }
+  TGIFNSLoopExtensionRec = Packed Record
+    Loops:      Word;   // Nombre de boucle de l'animation 0 = infinie  // nb loop
+    BufferSize: DWord;  // Taille du tampon. Usage ?????
+  End;
+
+Const
+  // Description des masques pour la description globale de l'image
+  GIF_GLOBALCOLORTABLE = $80;        // Défini si la table de couleurs globale suit la description globale
+  GIF_COLORRESOLUTION = $70;         // Résolution de la couleur (BitsPerPixel) - 3 bits
+  GIF_GLOBALCOLORTABLESORTED = $08;  // Définit si la palette globale est triée - 1 bit
+  GIF_COLORTABLESIZE  = $07;         // Taille de la palette - 3 bits
+  GIF_RESERVED        = $0C;         // Réservé - doit être défini avec $00 - Taille des données = 2^value+1 - 3 bits
+
+  // Descption des masques pour les images
+  GIF_LOCALCOLORTABLE = $80;        // Défini si la table de couleurs locale suit la description de l'image
+  GIF_INTERLACED      = $40;        // Défini si l'image est entrelacée
+  GIF_LOCALCOLORTABLESORTED = $20;  // Définit si la palette locale est triée
+
+  // Identification des blocs
+  GIF_PLAINTEXT       = $01;
+  GIF_GRAPHICCONTROLEXTENSION = $F9;
+  GIF_COMMENTEXTENSION = $FE;
+  GIF_APPLICATIONEXTENSION = $FF;
+  GIF_IMAGEDESCRIPTOR = $2C;       // ','
+  GIF_EXTENSIONINTRODUCER = $21;   // '!'
+  GIF_TRAILER         = $3B;               // ';'
+
+  // Graphic Control Extension - Définition des masques pour les paramètres
+  GIF_NO_DISPOSAL     = $00;           // 0
+  GIF_DO_NOT_DISPOSE  = $04;           // 1
+  GIF_RESTORE_BACKGROUND_COLOR = $08;  // 2
+  GIF_RESTORE_PREVIOUS = $12;          // 3
+  GIF_DISPOSAL_ALL    = $1C;           // bits 2-4 ($1C)
+  GIF_USER_INPUT_FLAG = $02;
+  GIF_TRANSPARENT_FLAG = $01;
+  GIF_RESERVED_FLAG   = $E0;
+
+  // Identification des sous-blocs pour "Application Extension"
+  GIF_LOOPEXTENSION   = 1;
+  GIF_BUFFEREXTENSION = 2;
+
+Const
+  GifGCEDisposalModeStr  : Array[TGIFDisposalFlag] Of String = ('None', 'Keep', 'Erase', 'Restore');
+
+Type
+  { Informations sur une image de l'animation }
+  TGIFFrameInformations = Record
+    Left, Top,                          // Position de l'image
+    Width, Height:   Integer;           // Dimension de l'image
+    HasLocalPalette: Boolean;           // Palette locale disponible
+    IsTransparent:   Boolean;           // Image transparente
+    UserInput:       Boolean;           // Données personnelle
+    BackgroundColorIndex: Byte;         // Normalement seulement valide si une palette globale existe
+    TransparentColorIndex: Byte;        // Index de la couleur transparente
+    DelayTime:       Word;              // Délai d'animation
+    Disposal:        TGIFDisposalFlag;  // Methode d'affichage
+    Interlaced:      Boolean;           // Image entrelacée
+  End;
+  PGifFrameInformations = ^TGifFrameInformations;
+
+  {%endregion%}
+
+  { TGIFFastMemoryStream }
+  { Classe d'aide à la lecture des données dans un flux en mémoire }
+  TGIFFastMemoryStream = Class
+  Private
+    FBuffer:   PByte;
+    FPosition: Int64;
+    FBytesRead, FBytesLeft, FSize: Int64;
+  Public
+    Constructor Create(AStream : TStream);
+    Destructor Destroy; Override;
+
+    { Lit un Byte dans le tampon / Read a byte in buffer }
+    Function ReadByte: Byte;
+    { Lit un Word dans le tampon / Read a word in buffer}
+    Function ReadWord: Word;
+    { Lit un DWord dans le tampon / Read a DWord in buffer }
+    Function ReadDWord: DWord;
+    { Lit et retourne un tampon "Buffer" de taille "Count" octets / Read a buffer of size "count" }
+    Function Read(Var Buffer; Count : Int64): Int64;
+    { Déplacement dans le flux de "Offset" depuis  "Origin"
+      TSeekOrigin =
+        - soBeginning : Depuis le début du flux
+        - soCurrent   : a partir de la position courante
+        - soEnd       : A partir de la fin du flux
+    }
+    Function Seek(Const Offset : Int64; Origin : TSeekOrigin): Int64;
+    { Déplacement dans le flux vers l'avant de "Cnt" octet depuis la position courrante }
+    Procedure SeekForward(Cnt : Integer);
+    { Indique si la fin du flux est atteinte (EOS = End Of Stream) }
+    Function EOS: Boolean;
+
+    { Retourne la taille du flux en octet // Size in byte of the buffer}
+    Property Size: Int64 read FSize;
+    { Retourne la position courrante de lecture dans le tampon // Current position in buffer }
+    Property Position: Int64 read FPosition;
+  End;
+
+  { TGIFLoadErrorEvent : Fonction d'évènement levée en cas d'erreur(s) dans le chargement // Event raise on error }
+  TGIFLoadErrorEvent = Procedure(Sender : TObject; Const ErrorCount : Integer; Const ErrorList : TStringList) Of Object;
+
+  { TGIFImageListItem }
+  { Définition d'une image contenue dans le fichier GIF }
+  TGIFImageListItem = Class
+  Private
+    FBitmap:      TFastBitmap;
+    FDrawMode:    TGIFDisposalFlag;
+    FLeft, FTop:  Integer;
+    FComment:     TStringList;
+    FDelay:       Integer;
+    FTransparent: Boolean;
+    FIsCorrupted : Boolean;
+  Protected
+  Public
+    Constructor Create;
+    Destructor Destroy; Override;
+
+    { Objet contenant l'image }
+    Property Bitmap: TFastBitmap read FBitmap write FBitmap;
+    { Mode de rendu de l'image // Render Mode}
+    Property DrawMode: TGIFDisposalFlag read FDrawMode write FDrawMode;
+    { Position gauche de l'image }
+    Property Left: Integer read FLeft write FLeft;
+    { Position Haut de l'image }
+    Property Top: Integer read FTop write FTop;
+    { Temps d'attente entre deux image de l'animation }
+    Property Delay: Integer read FDelay write FDelay;
+    { Commentaire sur l'image }
+    Property Comment: TStringList read FComment write FComment;
+    { Retourne TRUE si l'image utilise la transparence }
+    Property IsTransparent: Boolean read FTransparent write FTransparent;
+    { Indique si l'image est corrompue }
+    property IsCorrupted : Boolean read FIsCorrupted write FIsCorrupted;
+  End;
+
+  { TGIFImageList }
+  { Classe d'aide à la gestion des images contenues dans le fichier GIF }
+  { Helper class for manage image in GIF }
+  TGIFImageList = Class(TObjectList)
+  Private
+  Protected
+    Function GetItems(Index : Integer): TGIFImageListItem;
+    Procedure SetItems(Index : Integer; AGifImage : TGIFImageListItem);
+  Public
+    { Efface la liste  }
+    Procedure Clear; Override;
+    { Ajoute une nouvelle image vide à la liste }
+    Function AddNewImage: TGIFImageListItem;
+    { Ajout d'une image dans la liste }
+    Function Add(AGifImage : TGIFImageListItem): Integer;
+    { Extraction d'une image de la liste }
+    Function Extract(Item : TGIFImageListItem): TGIFImageListItem;
+    { Effacement d'une image dans la liste }
+    Function Remove(AGifImage : TGIFImageListItem): Integer;
+    { Retourne l'index de l'image recherchée (retourne -1 si non trouvé) }
+    Function IndexOf(AGifImage : TGIFImageListItem): Integer;
+    { Retourne la première image }
+    Function First: TGIFImageListItem;
+    { Retourne la dernière image }
+    Function Last: TGIFImageListItem;
+    { Insertion d'une image à la position "Index" }
+    Procedure Insert(Index : Integer; AGifImage : TGIFImageListItem);
+
+    { Liste des images }
+    Property Items[Index: Integer]: TGIFImageListItem read GetItems write SetItems; Default;
+  End;
+
+  { TGIFImageLoader }
+  { Classe spécialisée pour la lecture d'une image au format GIF }
+  { Special class for read a GIF }
+  TGIFImageLoader = Class
+  Private
+    FCurrentLayerIndex: Integer;
+    FGIFFIleHeader: TGIFFileHeader;
+    FLogicalScreenChunk: TGIFLogicalScreenDescriptorRec;
+    FHasGlobalPalette: Boolean;
+    FTransparent: Boolean;
+    FGlobalPalette: TColor32List;
+    FVersion: String;
+
+    FWidth, FHeight:  Integer;
+    FBackgroundColor: TColor32;
+
+    FFrames: TGIFImageList;
+
+    FErrorList:   TStringList;
+    FErrorCount:  Integer;
+    FOnLoadError: TGIFLoadErrorEvent;
+    Procedure SetCurrentLayerIndex(AValue : Integer);
+
+  Protected
+    Memory: TGIFFastMemoryStream;
+
+    CurrentFrameInfos: TGifFrameInformations;
+
+    Function GetFrameCount: Integer;
+    Procedure LoadFromMemory();
+    Function CheckFormat(): Boolean;
+    Function ReadImageProperties: Boolean;
+    Procedure AddError(Msg : String);
+    Procedure NotifyError;
+  Public
+    Constructor Create;
+    Destructor Destroy; Override;
+
+    { LoadFromStream : Charge les données depuis un flux }
+    Procedure LoadFromStream(aStream : TStream); Virtual;
+    { LoadFromFile : Charge les données depuis un fichier physique }
+    Procedure LoadFromFile(Const FileName : String); Virtual;
+    { Chargement depuis une Resource Lazarus }
+    Procedure LoadFromResource(Const ResName : String);
+    { Retourne la version du fichier GIF }
+    Property Version: String read FVersion;
+    { Retourne la largeur de l'image GIF }
+    Property Width: Integer read FWidth;
+    { Retourne la hauteur de l'image GIF }
+    Property Height: Integer read FHeight;
+    { Retourne la couleur de l'image GIF si elle existe,. Sinon retourne une couleur transparente (clrTransparent) }
+    Property BackgroundColor: TColor32 read FBackgroundColor write FBackgroundColor;
+    { Prise en charge de la transparence dans l'image GIF  // Take transparency in account}
+    Property Transparent: Boolean read FTransparent write FTransparent;
+    { Retourne l'index courrant de l'image de l'animation traité  // Return the current index frame}
+    Property CurrentFrameIndex: Integer read FCurrentLayerIndex write SetCurrentLayerIndex;
+    { Liste des images de l'animation // List of frame}
+    Property Frames: TGIFImageList read FFrames;
+    { Nombre d'image de l'animation // Nb frames }
+    Property FrameCount: Integer read GetFrameCount;
+    { Nombre d'erreur produite loars d'un cahrgement ou d'un enregistrement // Nb error }
+    Property ErrorCount: Integer read FErrorCount;
+    { Liste des erreurs // List of error }
+    Property Errors: TStringList read FErrorList;
+
+    { Evenement pour intercepter les erreurs notifiées lors du chargement des données // Error Event }
+    Property OnLoadError: TGIFLoadErrorEvent read FOnLoadError write FOnLoadError;
+  End;
+
+  { TGIFRenderCacheListItem }
+  { Définition d'une image cache de l'animation }
+  { Image cache class }
+  TGIFRenderCacheListItem = Class
+  Private
+    FBitmap: Graphics.TBitmap;
+    FDelay:  Integer;
+    FIsCorrupted : Boolean;
+  Public
+    Constructor Create;
+    Destructor Destroy; Override;
+    { Image cache prérendu de l'animation }
+    Property Bitmap: Graphics.TBitmap read FBitmap write FBitmap;
+    { Temps d'attente en ms avec l'image suivante }
+    Property Delay: Integer read FDelay write FDelay;
+    { Indique si l'image est corrompue }
+    property IsCorrupted : Boolean read FIsCorrupted write FIsCorrupted;
+  End;
+
+  { TGIFRenderCacheList }
+  { Classe d'aide à la gestion des images rendues de l'animation }
+  { Helper class for manage list of image cache }
+  TGIFRenderCacheList = Class(TObjectList)
+  Private
+  Protected
+    Function GetItems(Index : Integer): TGIFRenderCacheListItem;
+    Procedure SetItems(Index : Integer; AGIFRenderCache : TGIFRenderCacheListItem);
+  Public
+    { Efface la liste }
+    Procedure Clear; Override;
+    { Ajoute un nouvel objet cache vide }
+    Function AddNewCache: TGIFRenderCacheListItem;
+    { Ajoute un nouveau cache }
+    Function Add(AGIFRenderCache : TGIFRenderCacheListItem): Integer;
+    { Extrait un cache de la liste }
+    Function Extract(Item : TGIFRenderCacheListItem): TGIFRenderCacheListItem;
+    { Supprime un cache de la liste }
+    Function Remove(AGIFRenderCache : TGIFRenderCacheListItem): Integer;
+    { Retourne l'index du cache recherchée (retourne -1 si non trouvé) }
+    Function IndexOf(AGIFRenderCache : TGIFRenderCacheListItem): Integer;
+    { Retourne le premier élément de la liste }
+    Function First: TGIFRenderCacheListItem;
+    { Retourne le dernier élément de la liste }
+    Function Last: TGIFRenderCacheListItem;
+    { Insertion d'un cache à la position "Index" }
+    Procedure Insert(Index : Integer; AGIFRenderCache : TGIFRenderCacheListItem);
+    { Vérifie si "anIndex" ne dépasse pas la nombre d'élément dans la liste. Retroune FALSE si l'index est hors limite }
+    { Check if 'anIndex' does not exceed the number of items in the list. Retrieve FALSE if the index is out of range }
+    function IsIndexOk(anIndex : Integer) : Boolean;
+    { Supprime les éléments dont le drapeau "IsCorrupted" est vrai  }
+    { Remove items wich "IsCorrupted" flag is on True }
+    procedure Pack;
+    { Liste des caches }
+    Property Items[Index: Integer]: TGIFRenderCacheListItem read GetItems write SetItems; Default;
+  End;
+
+  { TGIFAutoStretchMode
+    Mode de redimensionnement automatique}
+  TGIFAutoStretchMode = (smManual, smStretchAll, smStretchOnlyBigger, smStretchOnlySmaller );
+  TOnStretchChanged = procedure (Sender:TObject; IsStretched : Boolean) of object;
+  { TGIFViewer }
+  { Composant visuel pour afficher une image GIF animée }
+  { Visual component for display the animated GIF }
+  TGIFViewer = Class(TGraphicControl)
+  Private
+    FAutoStretchMode: TGIFAutoStretchMode;
+    FGIFLoader: TGIFImageLoader;
+    FLastDrawMode : TGIFDisposalFlag;
+    FFileName:  String;
+
+    FRestoreBitmap, FVirtualView: TFastBitmap;
+
+    FRenderCache:       TGIFRenderCacheList;
+    FCurrentFrameIndex: Integer;
+    FGIFWidth, FGIFHeight: Integer;
+    FCurrentView:       Graphics.TBitmap;
+
+    FAnimateTimer:     TTimer;
+    FAnimateSpeed:     Integer;
+    FAnimated, FPause: Boolean;
+    FAutoPlay:         Boolean;
+    FCache:            Boolean;
+
+    FDisplayInvalidFrames : Boolean;
+    FAutoRemoveInvalidFrame : Boolean;
+
+    FPainting:         Boolean;
+
+    FBorderShow:       Boolean;
+    FBorderColor:      TColor;
+    FBorderWidth:      Byte;
+    FBevelInner, FBevelOuter: TPanelBevel;
+    FBevelWidth:       TBevelWidth;
+    FBevelColor, FColor: TColor;
+
+    FCenter, FStretch, FTransparent: Boolean;
+
+    FOnStart, FOnStop, FOnPause, FOnFrameChange: TNotifyEvent;
+    FOnLoadError : TGIFLoadErrorEvent;
+    FOnStretchChanged : TOnStretchChanged;
+
+    Function GetCanvas: TCanvas;
+    Function GetFrameCount: Integer;
+    Function GetGIFVersion: String;
+    Function GetRawFrameItem(Index : Integer): TGIFImageListItem;
+    Procedure SetAutoStretchMode(AValue: TGIFAutoStretchMode);
+    Procedure SetCenter(Const Value : Boolean);
+    Procedure SetStretch(Const Value : Boolean);
+    Procedure SetPause(Const Value : Boolean);
+    Procedure SetFileName(Const Value : String);
+    Function GetFrame(Const Index : Integer): Graphics.TBitmap;
+    Procedure SetTransparent(Const Value : Boolean);
+    Procedure SetBevelInner(Const Value : TPanelBevel);
+    Procedure SetBevelOuter(Const Value : TPanelBevel);
+    Procedure SetBevelWidth(Const Value : TBevelWidth);
+
+    procedure ResetCurrentView;
+  Protected
+    Procedure DoInternalOnLoadError(Sender : TObject; Const ErrorCount : Integer; Const ErrorList : TStringList);
+    Procedure DoTimerAnimate(Sender : TObject);
+
+    { Rendu d'une image de l'animation }
+    procedure RenderFrame(Index : Integer); Virtual;
+    { Creation des image cache pour l'animation }
+    Procedure ComputeCache; Virtual;
+    { Calcul de la postion et de la dimension pour l'afficchage sur le "Canvas" }
+    Function DestRect: TRect; Virtual;
+
+    { Fonctions hérités }
+    Procedure CalculatePreferredSize(Var PreferredWidth, PreferredHeight : Integer; {%H-}WithThemeSpace : Boolean); Override;
+    Class Function GetControlClassDefaultSize: TSize; Override;
+    Procedure Paint; Override;
+    procedure Loaded; override;
+    procedure BeforeLoad;
+    procedure AfterLoad;
+  Public
+    { Création du composant }
+    Constructor Create(AOwner : TComponent); Override;
+    { Destruction du composant }
+    Destructor Destroy; Override;
+
+    { Mise à jour de la surface de dessin (Canvas) du composant }
+    Procedure Invalidate; Override;
+    { LoadFromStream : Charge les données depuis un flux }
+    Procedure LoadFromStream(aStream : TStream);
+    { Chargement depuis un fichier }
+    Procedure LoadFromFile(Const aFileName : String);
+    { Chargement depuis une Resource Lazarus }
+    Procedure LoadFromResource(Const ResName : String);
+    { Joue l'animation }
+    Procedure Start;
+    { Arrête l'animation }
+    Procedure Stop;
+    { Met en pause l'animation }
+    Procedure Pause;
+    Procedure NextFrame;
+    Procedure PriorFrame;
+    { Retourne l'image brute du GIF à la position Index }
+    Function GetRawFrame(Index : Integer): TBitmap;
+    { Affiche l'image de l'animation mise en cache à la position Index }
+    Procedure DisplayFrame(Index : Integer);
+    { Affiche l'image brute de l'animation à la position Index }
+    Procedure DisplayRawFrame(Index : Integer);
+    { Extrait l'image de l'animation mise en cache à la position Index vers un TBitmap }
+    procedure ExtractFrame(Index : Integer; Var bmp:TBitmap) ;
+    { Extrait l'image brute de l'animation à la position Index vers un TBitmap}
+    procedure ExtractRawFrame(Index : Integer; Var bmp:TBitmap);
+    { Retourne le Canvas du composant }
+    Property Canvas: TCanvas read GetCanvas;
+    { Retourne TRUE si l'animation est en pause }
+    Property Paused: Boolean read FPause;
+    { Retourne TRUE si l'animation est en cours }
+    Property Playing: Boolean read FAnimated;
+    { Retourne l'index actuel de l'image affichée // Current Index of displayed frame }
+    Property CurrentFrameIndex: Integer read FCurrentFrameIndex;
+    { Liste des images de l'animation // List of frame}
+    Property Frames[Index: Integer]: TBitmap read GetFrame;
+    { Retourne le nombre d'image de l'animation // Number of frames }
+    Property FrameCount: Integer read GetFrameCount;
+    { Retourne la version du fichier GIF chargé // version of the gif }
+    Property Version: String read GetGIFVersion;
+    { Image courante de l'animation affichée // Current displayed image }
+    Property CurrentView: Graphics.TBitmap read FCurrentView;
+
+    property RawFrames[Index : Integer] : TGIFImageListItem read GetRawFrameItem;
+  Published
+    Property Color: TColor read FColor write FColor;
+    { Bordure visible autour du composant // Border visible around component }
+    Property Border: Boolean read FBorderShow write FBorderShow;
+    { Couleur de la bordure // Color of border }
+    Property BorderColor: TColor read FBorderColor write FBorderColor;
+    { Epaisseur de la bordure // Width of border }
+    Property BorderWidth: Byte read FBorderWidth write FBorderWidth;
+
+    Property BevelColor: TColor read FBevelColor write FBevelColor;
+    Property BevelInner: TPanelBevel read FBevelInner write SetBevelInner Default bvNone;
+    Property BevelOuter: TPanelBevel read FBevelOuter write SetBevelOuter Default bvRaised;
+    Property BevelWidth: TBevelWidth read FBevelWidth write SetBevelWidth Default 1;
+
+    Property Cache: Boolean read FCache write FCache;
+    { Joue l'animation automatiquement lors du chargement d'une image GIF animée }
+    { Play animation automatically when loading an animated GIF image }
+    Property AutoPlay: Boolean read FAutoPlay write FAutoPlay;
+    { Affichage du GIF avec prise en charge de la transparence }
+    { GIF view with transparency support }
+    Property Transparent: Boolean read FTransparent write SetTransparent;
+    { Centrer l'affichage // Center display }
+    Property Center: Boolean read FCenter write SetCenter;
+    { Mode du redimensionnement // Automatic stretch mode
+      smManual             : Adpatation Manuelle via la propriété stretch
+      smStretchAll         : Adapte toute les images
+      smStretchOnlyBigger  : Adapte seulement les images plus grande
+      smStretchOnlySmaller : Adapte seulement les images plus petite
+     }
+    property AutoStretchMode : TGIFAutoStretchMode read FAutoStretchMode write SetAutoStretchMode;
+    { Redimensionner l'affichage proportionnellement // Resize the display proportionally }
+    Property Stretch: Boolean read FStretch write SetStretch;
+    { Nom du fichier à charger // Name of file to load }
+    Property FileName: String read FFileName write SetFileName;
+    { Définis si les images corrompues doivent être affichées. Si le GIF contient que une seule image ce paramètre n'est pas appliqué. Par defaut FALSE }
+    property DisplayInvalidFrames : Boolean read FDisplayInvalidFrames write FDisplayInvalidFrames;
+    { Définis si les images corrompues doivent être effacées de la liste de l'animation automatiquement. Par defaut TRUE }
+    property AutoRemoveInvalidFrame : Boolean Read FAutoRemoveInvalidFrame write FAutoRemoveInvalidFrame;
+
+    { Evènement déclenché lorsque l'animation débute }
+    { Event triggered when the animation starts }
+    Property OnStart: TNotifyEvent read FOnStart write FOnStart;
+    { Evènement déclenché lorsque l'animation s'arrête }
+    { Event triggered when the animation stops }
+    Property OnStop: TNotifyEvent read FOnStop write FOnStop;
+    { Evènement déclenché lorsque l'animation est mise en pause }
+    { Event triggered when the animation is paused }
+    Property OnPause: TNotifyEvent read FOnPause write FOnPause;
+    { Evènement déclenché lorsque une nouvelle image est affiché lors de l'animation }
+    { Event triggered when a new image is displayed during the animation }
+    Property OnFrameChange: TNotifyEvent read FOnFrameChange write FOnFrameChange;
+    { Evenement pour intercepter les erreurs notifiées lors du chargement des données }
+    Property OnLoadError: TGIFLoadErrorEvent read FOnLoadError write FOnLoadError;
+    { Evenement pour intercepter le changement du mode stretch. Uniquement si AutoStretchMode <> smManual }
+    { Event to intercept the change of the stretch mode. Only if AutoStretchMode <> smManual }
+    property OnStretchChanged : TOnStretchChanged read FOnStretchChanged write FOnStretchChanged;
+
+    { Propriétés héritées }
+    Property Align;
+    Property Anchors;
+    Property AutoSize;
+    Property Constraints;
+    Property BorderSpacing;
+    Property Visible;
+    Property ParentShowHint;
+    Property ShowHint;
+    { Evènements héritées }
+    Property OnClick;
+    Property OnMouseDown;
+    Property OnMouseEnter;
+    Property OnMouseLeave;
+    Property OnMouseMove;
+    Property OnMouseUp;
+    Property OnMouseWheel;
+    Property OnMouseWheelDown;
+    Property OnMouseWheelUp;
+
+  End;
+
+  TGIFView = Class(TGIFViewer);
+
+Procedure Register;
+
+Implementation
+
+Uses
+  GraphType;
+
+{$R ../gifview.res}
+
+{%region=====[ Constantes et types internes ]===================================}
+
+
+Type
+  // Statut de décodage / encodage LZW
+  TLZWDecoderStatus = (
+    dsOK,                     // Tout va bien
+    dsNotEnoughInput,         // Tampon d'entrée trop petit
+    dsOutputBufferTooSmall,   // Tampon de sortie trop petit
+    dsInvalidInput,           // Donnée corrompue
+    dsBufferOverflow,         // débordement de tampon
+    dsInvalidBufferSize,      // Taille d'un des tampons invalide
+    dsInvalidInputBufferSize, // Taille du tampon d'entrée invalide
+    dsInvalidOutputBufferSize,// Taille du tampon de sortie invalide
+    dsInternalError           // Erreur interne signifiant qu'il y a un défaut dans le code
+    );
+
+{%endregion%}
+
+{%region=====[ Fonctions utiles ]===============================================}
+
+Function FixPathDelimiter(S : String): String;
+Var
+  I: Integer;
+Begin
+  Result := S;
+  For I  := Length(Result) Downto 1 Do
+  Begin
+    If (Result[I] = '/') Or (Result[I] = '\') Then Result[I] := PathDelim;
+  End;
+End;
+
+Function CreateFileStream(Const fileName : String; mode : Word = fmOpenRead + fmShareDenyNone): TStream;
+Var
+  fn: String;
+Begin
+  fn := filename;
+  FixPathDelimiter(fn);
+  If ((mode And fmCreate) = fmCreate) Or FileExists(fn) Then Result := TFileStream.Create(fn, mode)
+  Else
+    Raise Exception.Create('Fichier non trouvé : "' + fn + '"');
+
+End;
+
+{%endregion%}
+
+{%region=====[ TGIFFastMemoryStream ]==============================================}
+
+Constructor TGIFFastMemoryStream.Create(AStream : TStream);
+Var
+  ms: TMemoryStream;
+Begin
+  ms := TMemoryStream.Create;
+  With ms Do
+  Begin
+    CopyFrom(aStream, 0);
+    Position := 0;
+  End;
+  FSize      := ms.Size;
+  FPosition  := 0;
+  FBytesLeft := FSize;
+  FBytesRead := 0;
+  FBuffer    := nil;
+  ReAllocMem(FBuffer, FSize);
+  Move(PByte(ms.Memory)^, FBuffer^, FSize);
+  FreeAndNil(ms);
+End;
+
+Destructor TGIFFastMemoryStream.Destroy;
+Begin
+  If FBuffer <> nil Then
+  Begin
+    FreeMem(FBuffer);
+    FBuffer := nil;
+  End;
+  Inherited Destroy;
+End;
+
+Function TGIFFastMemoryStream.ReadByte: Byte;
+Begin
+  Result := 0;
+  If FBytesLeft > 0 Then
+  Begin
+    Result := PByte(FBuffer + FPosition)^;
+    Inc(FPosition);
+    Inc(FBytesRead);
+    Dec(FBytesLeft);
+  End;
+End;
+
+Function TGIFFastMemoryStream.ReadWord: Word;
+Begin
+  Result := 0;
+  If (FBytesLeft >= 2) Then
+  Begin
+    Result := PWord(FBuffer + FPosition)^;
+    Inc(FPosition, 2);
+    Inc(FBytesRead, 2);
+    Dec(FBytesLeft, 2);
+  End;
+End;
+
+Function TGIFFastMemoryStream.ReadDWord: DWord;
+Begin
+  Result := 0;
+  If (FBytesLeft >= 4) Then
+  Begin
+    Result := PDWord(FBuffer + FPosition)^;
+    Inc(FPosition, 4);
+    Inc(FBytesRead, 4);
+    Dec(FBytesLeft, 4);
+  End;
+End;
+
+Function TGIFFastMemoryStream.Read(Var Buffer; Count : Int64): Int64;
+Var
+  NumOfBytesToCopy, NumOfBytesLeft: Longint;
+  CachePtr, BufferPtr: PByte;
+Begin
+  Result := 0;
+
+  If (Count > FBytesLeft) Then NumOfBytesLeft := FBytesLeft
+  Else
+    NumOfBytesLeft := Count;
+
+  BufferPtr := @Buffer;
+
+  While NumOfBytesLeft > 0 Do
+  Begin
+    // On copie les données
+    NumOfBytesToCopy := Min(FSize - FPosition, NumOfBytesLeft);
+    CachePtr         := FBuffer;
+    Inc(CachePtr, FPosition);
+
+    Move(CachePtr^, BufferPtr^, NumOfBytesToCopy);
+    Inc(Result, NumOfBytesToCopy);
+    Inc(FPosition, NumOfBytesToCopy);
+    Inc(BufferPtr, NumOfBytesToCopy);
+    // On met à jour les marqueur de notre tampon
+    Inc(FBytesRead, NumOfBytesToCopy);
+    Dec(FBytesLeft, NumOfBytesToCopy);
+    Dec(NumOfBytesLeft, NumOfBytesToCopy);
+
+  End;
+End;
+
+Function TGIFFastMemoryStream.Seek(Const Offset : Int64; Origin : TSeekOrigin): Int64;
+Var
+  NewPos: Integer;
+Begin
+  // Calcul de la nouvelle position
+  Case Origin Of
+    soBeginning: NewPos := Offset;
+    soCurrent: NewPos   := FPosition + Offset;
+    soEnd: NewPos       := pred(FSize) - Offset;
+    Else
+      Raise Exception.Create('TFastStream.Seek: Origine Invalide');
+  End;
+  Result := NewPos;
+  If Offset = 0 Then exit;
+
+  FPosition  := NewPos;
+  FBytesLeft := FSize - FPosition;
+  Result     := NewPos;
+End;
+
+Procedure TGIFFastMemoryStream.SeekForward(Cnt : Integer);
+Begin
+  Seek(Cnt, soCurrent);
+End;
+
+Function TGIFFastMemoryStream.EOS: Boolean;
+Begin
+  Result := ((FBytesLeft <= 0) Or (FPosition >= Pred(FSize)));
+End;
+
+{%endregion%}
+
+{%region=====[ TGIFImageListItem ]==============================================}
+
+Constructor TGIFImageListItem.Create;
+Begin
+  FBitmap   := TFastBitmap.Create;
+  FLeft     := 0;
+  FTop      := 0;
+  FDelay    := 0;
+  FDrawMode := dmNone;
+  FComment  := TStringList.Create;
+  FComment.Clear;
+  FIsCorrupted := False;
+End;
+
+Destructor TGIFImageListItem.Destroy;
+Begin
+  FreeAndNil(FComment);
+  FreeAndNil(FBitmap);
+  Inherited Destroy;
+End;
+
+{%endregion%}
+
+{%region=====[ TGIFImageList ]==================================================}
+
+Function TGIFImageList.GetItems(Index : Integer): TGIFImageListItem;
+Begin
+  Result := TGIFImageListItem(Inherited Items[Index]);
+End;
+
+Procedure TGIFImageList.SetItems(Index : Integer; AGifImage : TGIFImageListItem);
+Begin
+  Put(Index, AGifImage);
+End;
+
+Procedure TGIFImageList.Clear;
+Var
+  anItem: TGIFImageListItem;
+  i:      Integer;
+Begin
+  If Count > 0 Then
+  Begin
+    For i := Count - 1 Downto 0 do
+    Begin
+      AnItem := Items[i];
+      If anItem <> nil Then anItem.Free;
+    End;
+  End;
+  Inherited Clear;
+End;
+
+Function TGIFImageList.AddNewImage: TGIFImageListItem;
+Var
+  anItem: TGIFImageListItem;
+Begin
+  anitem := TGIFImageListItem.Create;
+  Add(anItem);
+  Result := Items[Self.Count - 1];
+End;
+
+Function TGIFImageList.Add(AGifImage : TGIFImageListItem): Integer;
+Begin
+  Result := Inherited Add(AGifImage);
+End;
+
+Function TGIFImageList.Extract(Item : TGIFImageListItem): TGIFImageListItem;
+Begin
+  Result := TGIFImageListItem(Inherited Extract(Item));
+End;
+
+Function TGIFImageList.Remove(AGifImage : TGIFImageListItem): Integer;
+Begin
+  Result := Inherited Remove(AGifImage);
+End;
+
+Function TGIFImageList.IndexOf(AGifImage : TGIFImageListItem): Integer;
+Begin
+  Result := Inherited IndexOf(AGifImage);
+End;
+
+Function TGIFImageList.First: TGIFImageListItem;
+Begin
+  Result := TGIFImageListItem(Inherited First);
+End;
+
+Function TGIFImageList.Last: TGIFImageListItem;
+Begin
+  Result := TGIFImageListItem(Inherited Last);
+End;
+
+Procedure TGIFImageList.Insert(Index : Integer; AGifImage : TGIFImageListItem);
+Begin
+  Inherited Insert(Index, AGifImage);
+End;
+
+{%endregion%}
+
+{%region=====[ TGIFImageLoader ]================================================}
+
+Constructor TGIFImageLoader.Create;
+Begin
+  Inherited Create;
+  FFrames        := TGIFImageList.Create(False);
+  FErrorList     := TStringList.Create;
+  FErrorCount    := 0;
+  FGlobalPalette := nil;
+  FTransparent   := True;
+  FBackgroundColor := clrTransparent;
+End;
+
+Destructor TGIFImageLoader.Destroy;
+Begin
+  FreeAndNil(FFrames);
+  FreeAndNil(FErrorList);
+  Inherited Destroy;
+End;
+
+Function TGIFImageLoader.CheckFormat(): Boolean;
+Begin
+  Result := False;
+  // Chargement de l'en-tête
+  Memory.Read(FGIFFileHeader, SizeOf(TGIFFileHeader));
+  // Vérification de quelques paramètres
+  Result := uppercase(String(FGIFFileHeader.Signature)) = 'GIF';
+  If Result Then
+  Begin
+    // Le fichier est valide
+    // On sauvegarde la version du GIF
+    FVersion := String(FGIFFileHeader.Version);
+    If (FVersion = GIFVersions[gv87a]) Or (FVersion = GIFVersions[gv89a]) Then Result := ReadImageProperties // On lit les propriétés
+    Else
+      Raise Exception.Create(rsUnknownVersion);
+  End
+  Else
+  Begin
+    // Signature du fichier GIF Invalide. On lève une exception
+    Raise Exception.Create(Format(rsBadSignature,[uppercase(String(FGIFFileHeader.Signature))]));
+  End;
+End;
+
+Function TGIFImageLoader.ReadImageProperties: Boolean;
+Begin
+  Result := False;
+
+  Memory.Read(FLogicalScreenChunk, SizeOf(TGIFLogicalScreenDescriptorRec));
+
+  // On sauvegarde en local les dimensions de l'image, pour plus tard
+  FWidth  := FLogicalScreenChunk.ScreenWidth;
+  FHeight := FLogicalScreenChunk.ScreenHeight;
+
+  If (FWidth < 1) Or (FHeight < 1) Then
+  Begin
+    // Dimensions incorrectes on lève une exception
+    Raise Exception.Create(Format(rsBadScreenSize,[FWidth,FHeight]));
+    exit;
+  End;
+  FHasGlobalPalette := (FLogicalScreenChunk.PackedFields And GIF_GLOBALCOLORTABLE) <> 0;
+
+  Result := True;
+End;
+
+Procedure TGIFImageLoader.AddError(Msg : String);
+Begin
+  FErrorList.Add(Msg);
+End;
+
+Procedure TGIFImageLoader.NotifyError;
+Begin
+  If FErrorList.Count > 0 Then
+  Begin
+    If Assigned(FOnLoadError) Then FOnLoadError(Self, FErrorList.Count, FErrorList);
+  End;
+End;
+
+Procedure TGIFImageLoader.LoadFromStream(aStream : TStream);
+Begin
+  If Memory <> nil Then FreeAndNil(Memory);
+  Memory := TGIFFastMemoryStream.Create(aStream);
+  If CheckFormat Then LoadFromMemory;
+  FreeAndNil(Memory);
+End;
+
+Procedure TGIFImageLoader.LoadFromFile(Const FileName : String);
+Var
+  Stream: TStream;
+Begin
+  FErrorList.Clear;
+  FErrorCOunt := 0;
+  Stream      := CreateFileStream(FileName);
+  Try
+    LoadFromStream(Stream);
+  Finally
+    FreeAndNil(Stream);
+  End;
+End;
+
+Procedure TGIFImageLoader.LoadFromResource(Const ResName : String);
+Var
+  Stream: TLazarusResourceStream;
+Begin
+  FErrorList.Clear;
+  FErrorCOunt := 0;
+  Stream      := TLazarusResourceStream.Create(ResName, nil);
+  Try
+    LoadFromStream(Stream);
+  Finally
+    FreeAndNil(Stream);
+  End;
+End;
+
+Function TGIFImageLoader.GetFrameCount: Integer;
+Begin
+  Result := FFrames.Count;
+End;
+
+Procedure TGIFImageLoader.SetCurrentLayerIndex(AValue : Integer);
+Begin
+  If FCurrentLayerIndex = AValue Then Exit;
+  FCurrentLayerIndex := AValue;
+End;
+
+Procedure TGIFImageLoader.LoadFromMemory();
+Var
+  aRGBColor: TColorRGB24;
+  aColor: TColor32;
+  PaletteCount: Integer;
+  Done: Boolean;
+  BlockID: Byte;
+  BlockSize: Byte;
+  Terminator{%H-}: Byte;
+  CurrentLayer: TGIFImageListItem;
+
+  ImageDescriptor: TGIFImageDescriptorRec;
+  GraphicControlExtensionChunk: TGIFGraphicControlExtensionRec;
+  ApplicationExtensionChunk: TGIFApplicationExtensionRec;
+  NSLoopExtensionChunk: TGIFNSLoopExtensionRec;
+  PlainTextChunk: TGIFPlainTextExtensionRec;
+
+  LocalPalette: TColor32List;
+  ColorCount: Integer;
+  DMode: Byte;
+  ret: TLZWDecoderStatus;
+
+  { Chargement palette globale }
+  Procedure LoadGlobalPalette;
+  Var
+    J: Byte;
+  Begin
+    If FHasGlobalPalette Then
+    Begin
+      // Remise à zero de la palette globale si elle existe sinon création de celle-ci
+      If FGlobalPalette = nil Then FGlobalPalette := TColor32List.Create
+      Else
+        FGlobalPalette.Clear;
+
+      PaletteCount := 2 Shl (FLogicalScreenChunk.PackedFields And GIF_COLORTABLESIZE);
+      // Le cas ou le nombre de couleurs serait plus grand que 256. On prend en charge.
+      If (PaletteCount < 2) Then //or (PaletteCount>256) then
+        Raise Exception.Create(rsScreenBadColorSize + ' : ' + IntToStr(PaletteCount));
+
+      // On charge la palette
+      For J := 0 To PaletteCount - 1 Do
+      Begin
+        Memory.Read(aRGBColor, SizeOF(TColorRGB24));
+        aColor.Create(aRGBColor);
+        FGlobalPalette.AddColor(aColor);
+      End;
+    End;
+  End;
+
+  { Chargement palette locale }
+  Procedure LoadLocalPalette;
+  Var
+    J: Byte;
+  Begin
+    // Aucune palette locale n'a été assignée. On en créer une nouvelle. Sinon on efface simplement son contenu.
+    If LocalPalette = nil Then LocalPalette := TColor32List.Create
+    Else
+      LocalPalette.Clear;
+
+    // On verifie que le nombre de couleur dans la palette est correcte
+    ColorCount := (2 Shl (ImageDescriptor.PackedFields And GIF_COLORTABLESIZE));
+    // Le cas ou le nombre de couleurs serait plus grand que 256. On prend en charge qudn même et on charge la palette.
+    If (ColorCount < 2) Then //or (ColorCount>256) then
+      Raise Exception.Create(rsImageBadColorSize + ' : ' + IntToStr(ColorCount));
+
+    // On charge la palette
+    For J := 0 To ColorCount - 1 Do
+    Begin
+      Memory.Read(aRGBColor, SizeOF(TColorRGB24));
+      aColor.Create(aRGBColor);
+      LocalPalette.AddColor(aColor);
+    End;
+  End;
+
+  { Lecture des extensions }
+  Procedure ReadExtension;
+  Var
+    ExtensionID, BlockType: Byte;
+    BufStr: Array[0..255] Of Char;
+    Loops:  Word;
+    CurrentExtension : String;
+  Begin
+    // On lit les extension jusqu'a ce qu'un bloc de description d'une image soit détecter ou que jusqu'a la fin du fichier
+    Repeat
+      //showmessage('Read extension at '+ Memory.Position.ToString);
+      ExtensionID := Memory.ReadByte;
+      CurrentExtension :='';
+      // Si c'est un  nouveau marqueur d'introduction d'extension. On lit le nouvel ID
+      If (ExtensionID = GIF_EXTENSIONINTRODUCER) Then ExtensionID := Memory.ReadByte;
+      If (ExtensionID = 0) Then
+      Begin
+        // On Saute les ID Nul
+        Repeat
+          ExtensionID := Memory.ReadByte;
+        Until (ExtensionID <> 0);
+      End;
+      Case ExtensionID Of
+        GIF_PLAINTEXT:
+        Begin
+          BlockSize   := Memory.ReadByte;
+          Memory.Read(PlainTextChunk, SizeOf(TGIFPlainTextExtensionRec));
+          Repeat
+            // On lit la taille du bloc. Si Zero alors fin des données de l'extension
+            BlockSize := Memory.ReadByte;
+            // On lit la chaine de caractères
+            If (BlockSize > 0) Then
+            Begin
+              fillchar({%H-}BufStr, 256, 0);
+              Memory.Read(BufStr, BlockSize);
+              BufStr[BlockSize] := #0;
+              // On place le texte dans les commentaires
+              CurrentLayer.Comment.Add(String(BufStr));
+            End;
+          Until (BlockSize = 0);
+          // On ajoute une ligne vide de séparation
+          CurrentLayer.Comment.Add('');
+        End;
+        GIF_COMMENTEXTENSION:
+        Begin
+          Repeat
+            // On lit la taille du commentaire. Si Zero alors fin des données de l'extension
+            BlockSize := Memory.ReadByte;
+            // On lit la chaine de caractères
+            If (BlockSize > 0) Then
+            Begin
+              Memory.Read(BufStr, BlockSize);
+              BufStr[BlockSize] := #0;
+              // On place le texte dans les commentaires
+              CurrentLayer.Comment.Add(String(BufStr));
+            End;
+          Until (BlockSize <= 0);
+          // On ajoute une ligne vide de séparation
+          CurrentLayer.Comment.Add('');
+        End;
+        GIF_APPLICATIONEXTENSION:
+        Begin
+
+          BlockSize := Memory.ReadByte;
+          // Certains vieux filtres d'exportation Adobe, ou d'autres logiciels utilisent par erreur une valeur de 10, ou plus petite ou trop grande
+          If (BlockSize <> 11) Then
+          Begin
+            FillChar(ApplicationExtensionChunk, SizeOf(TGIFApplicationExtensionRec), 0);
+          End;
+          //else if (BlockSize<11) then
+          //   Raise Exception.Create('Bad extension size' + ' : ' + inttostr(BlockSize) +' octets. ( Taille valide = 11 octets )');
+          Memory.Read(ApplicationExtensionChunk, SizeOf(TGIFApplicationExtensionRec));
+          CurrentExtension := ApplicationExtensionChunk.AppAuthenticationCode;
+          Repeat
+            // On lit la taille du  bloc. Zero si il n'y a pas de données supplémentaires
+            BlockSize := Memory.ReadByte;
+            If (BlockSize > 0) Then
+            Begin
+              if UpperCase(CurrentExtension) = 'NETSCAPE' then
+              begin
+                BlockType := Memory.ReadByte;
+                Dec(BlockSize);
+                Case (BlockType And $07) Of
+                  GIF_LOOPEXTENSION:
+                  Begin
+                    // Lecture du nombre de boucle, Si Zero alors boucle infinie
+                    Loops := Memory.ReadWord;
+                    If Loops > 0 Then Inc(NSLoopExtensionChunk.Loops);
+                    Dec(BlockSize, SizeOf(Loops));
+                  End;
+                  GIF_BUFFEREXTENSION:
+                  Begin
+                    // Lecture de la taille du tampon. Utilisé pour ??????
+                    NSLoopExtensionChunk.BufferSize := Memory.ReadDWord;
+                    Dec(BlockSize, SizeOF(NSLoopExtensionChunk.BufferSize));
+                  End;
+                  else // Extension NETSCAPE inconnue
+                    begin
+                      Memory.SeekForward(BlockSize);
+                      //BlockSize := 0;
+                    end;
+                End;
+              end
+              else
+              // On saute et on ignore les donnée non lues
+              If (BlockSize > 0) Then
+              Begin
+                Memory.SeekForward(BlockSize);
+                //BlockSize := 0;
+              End;
+            End;
+          Until (BlockSize = 0);
+        End;
+        GIF_GRAPHICCONTROLEXTENSION:
+        Begin
+          // On lit la taille de l'extension. Normalement 4 Octets. Cette valeur peut-être erronée. On en tient pas compte ici et on lit les données.
+          BlockSize := Memory.ReadByte;
+          //if BlockSize = 4 then
+          //begin
+          Memory.Read(GraphicControlExtensionChunk, SizeOf(TGIFGraphicControlExtensionRec));
+          // On renseigne notre tampon d'informations pour les prochaines images décodées
+          DMode     := ((GraphicControlExtensionChunk.PackedFields And GIF_DISPOSAL_ALL) Shr 2);
+          With CurrentFrameInfos Do
+          Begin
+            // Ces valeurs peuvent être utilisées pour plusieurs image. Elles restent valides jusqu'a la lecture du prochain "GCE" trouvé.
+            Disposal      := TGIFDisposalFlag(DMode);
+            IsTransparent := (GraphicControlExtensionChunk.PackedFields And GIF_TRANSPARENT_FLAG) <> 0;
+            UserInput     := (GraphicControlExtensionChunk.PackedFields And GIF_USER_INPUT_FLAG) <> 0;
+            TransparentColorIndex := GraphicControlExtensionChunk.TransparentColorIndex;
+            BackgroundColorIndex := FLogicalScreenChunk.BackgroundColorIndex;
+            DelayTime     := GraphicControlExtensionChunk.DelayTime;
+          End;
+          // Lecture de l'octet de fin de l'extension
+          Terminator := Memory.ReadByte;
+        End;
+      End;
+    Until (ExtensionID = GIF_IMAGEDESCRIPTOR) Or Memory.EOS;
+
+    // Si l'ID pour la description de l'image est détecter on revient en arrière pour la prise en charge par le traitement des données
+    If (ExtensionID = GIF_IMAGEDESCRIPTOR) Then Memory.Seek(-1, soCurrent);
+  End;
+
+  { Chargement d'une image }
+  Procedure LoadImage;
+  Var
+    DecoderStatus{%H-}: TLZWDecoderStatus;
+    BufferSize, TargetBufferSize, BytesRead: Int64;
+    InitCodeSize: Byte;
+    OldPosition: Int64;
+    Buffer, BufferPtr: PByte;
+    TargetBuffer, TargetBufferPtr: PByte;
+    LinePtr: PColor32;
+    Pass, Increment: Byte;
+    x:      Integer;
+    TargetColor: TColor32;
+    ColIdx: Byte;
+    CurrentLine: Integer;
+    OutBmp: TFastBitmap;
+
+    // Decodeur GIF LZW. Basé sour le code source de la bibliothèque GraphicEX pour Delphi
+    Function DecodeLZW(Var Source, Dest : Pointer; PackedSize, UnpackedSize : Integer): TLZWDecoderStatus;
+    Const
+      { Constantes pour la décompression LZW }
+      _LZWGIFCodeBits  = 12;    // Nombre maximal de bits par code d'un jeton (12 bits = 4095)
+      _LZWGIFCodeMax   = 4096; // Nombre maximum de jeton
+      _LZWGIFStackSize = (2 Shl _LZWGIFCodeBits);   // Taille de la pile de décompression
+      _LZWGIFTableSize = (1 Shl _LZWGIFCodeBits);   // Taille de la table de décompression
+
+    Var
+      J:         Integer;
+      Data,             // Données actuelle
+      Bits,             // Compteur de bit
+      Code:      Cardinal;   // Valeur courrante du Code
+      SourcePtr: PByte;
+      InCode:    Cardinal; // Tampon pour passé le Code
+
+      CodeSize:  Cardinal;
+      CodeMask:  Cardinal;
+      FreeCode:  Cardinal;
+      OldCode:   Cardinal;
+      Prefix:    Array[0.._LZWGIFTableSize] Of Cardinal; // LZW prefix
+      Suffix,                                         // LZW suffix
+      Stack:     Array [0.._LZWGIFStackSize] Of Byte;
+      StackPointer: PByte;
+      MaxStackPointer: PBYte;
+      Target:    PByte;
+      FirstChar: Byte;  // Tampon de décodage d'un octet
+      ClearCode, EOICode: Word;
+      MaxCode:   Boolean;
+
+    Begin
+      Result        := dsOk;
+      DecoderStatus := dsOk;
+      If (PackedSize <= 0) Or (UnpackedSize <= 0) Then
+      Begin
+        // Taille des tampons invalides
+        If (PackedSize <= 0) And (UnpackedSize <= 0) Then Result := dsInvalidBufferSize
+        Else If PackedSize <= 0 Then Result   := dsInvalidInputBufferSize
+        Else If UnpackedSize <= 0 Then Result := dsInvalidOutputBufferSize;
+        Exit;
+      End;
+
+      // Initialisation  des paramètres pour la décompression
+      CodeSize  := InitCodeSize + 1;
+      ClearCode := 1 Shl InitCodeSize;
+      EOICode   := ClearCode + 1;
+      FreeCode  := ClearCode + 2;
+      OldCode   := _LZWGIFCodeMax - 1;
+      CodeMask  := (1 Shl CodeSize) - 1;
+      MaxCode   := False;
+      Code      := 0;
+      Target    := PByte(Dest);
+      SourcePtr := PByte(Source);
+
+      // Initialisation des tables de Code
+      For J := 0 To _LZWGIFTableSize Do
+      Begin
+        Prefix[J] := _LZWGIFCodeMax;
+        Suffix[J] := J;
+      End;
+
+      // Initalisation de la pile
+      StackPointer    := @Stack;
+      MaxStackPointer := @Stack[_LZWGIFStackSize];
+      FirstChar       := 0;
+
+      Data := 0;
+      Bits := 0;
+      While (UnpackedSize > 0) And (PackedSize > 0) Do
+      Begin
+        // On lit le "Code" dans le tampon d'entrée
+        Inc(Data, SourcePtr^ Shl Bits);
+        Inc(Bits, 8);
+        While (Bits > CodeSize) And (UnpackedSize > 0) Do
+        Begin
+          // Code actuel
+          Code := Data And CodeMask;
+          // Préparation pour la donnée suivante
+          Data := Data Shr CodeSize;
+          Dec(Bits, CodeSize);
+
+          // Décompression finie ?
+          If Code = EOICode Then
+          Begin
+            // Si nous arrivons ici, il y a probablement quelque chose de suspect avec l'image GIF
+            // Car normalement on stoppe dès que le tampon de sortie est plein.
+            // Cela signifie que nous ne lirons jamais l'EOICode de fermeture dans les images normales.
+            // Comme l'état du buffer est déjà vérifié après la boucle principale, nous ne le ferons pas ici.
+            Break;
+          End;
+
+          // On vérifie s'il s'agit d'un code valide déjà enregistré
+          If Code > FreeCode Then
+          Begin
+            // Code ne peux à être supérieur à FreeCode. Nous avons donc une image cassée.
+            // On notifie l'erreur à l'utilisateur. Et on considère qu'il n'ya pas d'erreur.
+            DecoderStatus := dsInvalidInput;
+            AddError(Format(rsLZWInvalidInput,[CurrentFrameIndex]));
+            //NotifyUser('Le décodeur a rencontré une entrée invalide (données corrompues)');
+            Code :=  ClearCode;
+            //Break; //Ici, on continue le chargement du reste de l'image au lieu de le stopper
+          End;
+
+          // RAZ
+          If Code = ClearCode Then
+          Begin
+            // réinitialisation de toutes les variables
+            CodeSize := InitCodeSize + 1;
+            CodeMask := (1 Shl CodeSize) - 1; //CodeMasks[CodeSize];
+            FreeCode := ClearCode + 2;
+            OldCode  := _LZWGIFCodeMax;
+            MaxCode  := False;
+          End
+          Else If OldCode = _LZWGIFCodeMax Then
+          Begin
+            // Gestion du premier Code LZW : On le définit dans le tampon de sortie et on le conserve
+            FirstChar := Suffix[Code];
+            Target^   := FirstChar;
+            Inc(Target);
+            Dec(UnpackedSize);
+            OldCode   := Code;
+          End
+          Else
+          Begin
+            //On conserve le Code LZW actuel
+            InCode := Code;
+
+            // On place le nouveau code LZW sur la pile sauf quand nous avons déjà utilisé tous les codes disponibles
+            If (Code = FreeCode) And Not MaxCode Then
+            Begin
+              StackPointer^ := FirstChar;
+              Inc(StackPointer);
+              Code := OldCode;
+            End;
+
+            // boucle pour placer les octets décodés sur la pile
+            While Code > ClearCode Do
+            Begin
+              StackPointer^ := Suffix[Code];
+              If StackPointer >= MaxStackPointer Then
+              Begin
+                // Ne doit jamais arriver, c'est juste une précaution au cas ou.
+                Result := dsBufferOverflow;
+                break;
+              End;
+              Inc(StackPointer);
+              Code := Prefix[Code];
+            End;
+            If Result <> dsOK Then break; // Si il ya eu des erreurs on ne va pas plus loin
+
+            // Place le nouveau Code dans la table
+            FirstChar     := Suffix[Code];
+            StackPointer^ := FirstChar;
+            Inc(StackPointer);
+
+            //Transfert des données décodées vers notre tampon de sortie
+            Repeat
+              If UnpackedSize <= 0 Then
+              Begin
+                // Le tampon de sortie est trop petit. On ne va pas plus loin
+                // On notifie l'erreur à l'utilisateur. Et on considère qu'il n'ya pas d'erreur.
+                // Afin de pouvoir afficher le GIF et continuer le chargement des images suivantes
+                Result := dsOutputBufferTooSmall;
+                AddError(Format(rsLZWOutputBufferTooSmall,[CurrentFrameIndex]));
+                break;
+              End;
+              Dec(StackPointer);
+              Target^ := StackPointer^;
+              Inc(Target);
+              Dec(UnpackedSize);
+            Until StackPointer = @Stack;
+            If Result <> dsOK Then break;
+
+            If Not MaxCode Then
+            Begin
+              If FreeCode <= _LZWGIFCodeMax Then
+              Begin
+                Prefix[FreeCode] := OldCode;
+                Suffix[FreeCode] := FirstChar;
+              End
+              Else If FreeCode > _LZWGIFCodeMax Then
+              Begin
+                // On a intercepter une donnée corrompue. On continue quand la même décompression sans en tenir compte.
+                // On notifie juste l'erreur à l'utilisateur
+                DecoderStatus := dsInvalidInput;
+                AddError(Format(rsLZWInvalidInput,[CurrentFrameIndex]));
+                FreeCode :=  _LZWGIFCodeMax;
+                Prefix[FreeCode] := OldCode;
+                Suffix[FreeCode] := FirstChar;
+                //MaxCode       := True;
+              End;
+
+              // On augmente la taille du Code si nécessaire
+              If (FreeCode = CodeMask) And Not (MaxCode) Then
+              Begin
+                If (CodeSize < _LZWGIFCodeBits) Then
+                Begin
+                  Inc(CodeSize);
+                  CodeMask := (1 Shl CodeSize) - 1;//CodeMasks[CodeSize];
+                End
+                Else //On a atteind la limite maximum
+                  MaxCode  := True;
+              End;
+
+              If FreeCode < _LZWGIFTableSize Then Inc(FreeCode);
+            End;
+            OldCode := InCode;
+          End;
+        End;
+        Inc(SourcePtr);
+        Dec(PackedSize);
+        If (Result <> dsOK) Or (Code = EOICode) Then Break;
+      End;
+
+      If Result = dsOK Then
+      Begin
+        // On vérifie seulement si il n'ya pas eu d'erreur. Si ce n'est pas le cas, nous savons déjà que quelque chose ne va pas.
+        // Notez qu'il est normal que PackedSize soit un peu> 0 parce que nous pouvons
+        // pas lire l'EOICode mais arrêter dès que notre tampon de sortie est plein et
+        // qui devrait normalement être le code juste avant l'EOICode.
+        If PackedSize < 0 Then
+        Begin
+          Result := dsInternalError;
+          // C'est une erreur sérieuse : nous avons eu un dépassement de tampon d'entrée que nous aurions dû intercepter. Nous devons arrêter maintenant.
+          Raise Exception.Create(rsLZWInternalErrorInputBufferOverflow);
+          Exit;
+        End;
+        If UnpackedSize <> 0 Then
+        Begin
+          //if UnpackedSize > 0 then
+          //begin
+          //  //  Image corrompue
+          //  DecoderStatus := dsNotEnoughInput;
+          //  AddError('Image #'+CurrentFrameIndex)+' : Le décodeur n''a pas pu décoder toutes les données car le tampon d''entrée est trop petit');
+          //  //NotifyUser('Le décodeur  n''a pas pu décoder toutes les données car le tampon d''entrée est trop petit');
+          //End
+          //else
+          If UnpackedSize < 0 Then
+          Begin
+            Result := dsInternalError;
+            // C'est une erreur sérieuse : nous avons eu un dépassement de tampon de sortie que nous aurions dû intercepter. Nous devons arrêter maintenant.
+            Raise Exception.Create(rsLZWInternalErrorOutputBufferOverFlow);
+          End;
+        End;
+      End;
+    End;
+
+  Begin
+    BufferSize       := 0;
+    TargetBufferSize := 0;
+
+    // On lit la description de l'image
+    Memory.Read(ImageDescriptor, SizeOf(TGIFImageDescriptorRec));
+
+    // On vérifie que les dimensions sont correctes.
+    // Si on trouve des dimensions à zero, il se peut qu'il faudra traiter
+    // une extension PlainText et dessiner ce texte en fonction des paramètres
+    If (ImageDescriptor.Height = 0) Or (ImageDescriptor.Width = 0) Then
+    Begin
+      // On assigne les dimensions par défaut du GIF
+      ImageDescriptor.Width  := FLogicalScreenChunk.ScreenWidth;
+      ImageDescriptor.Height := FLogicalScreenChunk.ScreenHeight;
+      // On notifie à l'utilisateur que les dimensions de l'image sont erronée. Mais on tente le chargement quand même
+      // ShowMessage
+    End;
+
+    // Dans le cas ou les dimensions de l'image sont incorrectes dans "l'image descriptor". Ou que la taille des données compressées soit erronée.
+    If (ImageDescriptor.Width > FLogicalScreenChunk.ScreenWidth) Or (ImageDescriptor.Height > FLogicalScreenChunk.ScreenHeight) Then
+    Begin
+      // On assigne les dimensions par défaut du GIF
+      If (ImageDescriptor.Width > FLogicalScreenChunk.ScreenWidth) Then ImageDescriptor.Width := FLogicalScreenChunk.ScreenWidth;
+      If (ImageDescriptor.Height > FLogicalScreenChunk.ScreenHeight) Then ImageDescriptor.Height := FLogicalScreenChunk.ScreenHeight;
+      // On notifie à l'utilisateur que les dimensions de l'image sont erronée. Mais on tente le chargement quand même
+      // ShowMessage
+    End;
+
+    // On renseigne notre tampon d'informations
+    With CurrentFrameInfos Do
+    Begin
+      Left       := ImageDescriptor.Left;
+      Top        := ImageDescriptor.Top;
+      Width      := ImageDescriptor.Width;
+      Height     := ImageDescriptor.Height;
+      Interlaced := (ImageDescriptor.PackedFields And GIF_INTERLACED) = GIF_INTERLACED;
+      HasLocalPalette := (ImageDescriptor.PackedFields And GIF_LOCALCOLORTABLE) = GIF_LOCALCOLORTABLE;
+    End;
+
+    // L'image possède-t-elle sa propre palette de couleur ? Si oui on la charge.
+    If CurrentFrameInfos.HasLocalPalette Then LoadLocalPalette;
+
+    // Decompression de l'image
+
+    // On ajoute une nouvelle image si besoin
+    If (FCurrentLayerIndex > 0) And (FCurrentLayerIndex > FFrames.Count - 1) Then CurrentLayer := FFrames.AddNewImage;
+    // On assigne la nouvelle image au Bitmap de travail
+    OutBmp := FFrames.Items[CurrentFrameIndex].Bitmap;
+
+    // On met à jour les informations
+    With FFrames.Items[FCurrentLayerIndex] Do
+    Begin
+      Drawmode := CurrentFrameInfos.Disposal;
+     // Showmessage('#'+inttostr(FCurrentLayerIndex) + 'DrawMode : '+ GifGCEDisposalModeStr[Drawmode]);
+      Left     := CurrentFrameInfos.Left;
+      Top      := CurrentFrameInfos.Top;
+      IsTransparent := CurrentFrameInfos.IsTransparent;
+      If CurrentFrameInfos.DelayTime = 0 Then Delay := GIF_DefaultDelay
+      Else
+        Delay := CurrentFrameInfos.DelayTime * GIF_DelayFactor;
+    End;
+
+    // On lit le code d'initalisation de la compression LZW
+    InitCodeSize := Memory.ReadByte;
+    If InitCodeSize < 2 Then InitCodeSize := 2;
+    If InitCodeSize > 8 Then InitCodeSize := 8;
+
+    // On sauve la position actuelle dans le flux
+    OldPosition := Memory.position;
+
+    BufferSize := 0;
+
+    // 1) On comptabilise la taille totale des données compresser. Afin de les décompresser en une seule fois.
+    // On lit la taille du premier bloc
+    BlockSize := Memory.ReadByte;
+    While (BlockSize > 0) And Not (Memory.EOS) Do
+    Begin
+      Inc(BufferSize, BlockSize);
+      // On saute les données
+      Memory.SeekForward(BlockSize);
+      If Not (Memory.EOS) Then BlockSize := Memory.ReadByte
+      Else
+        blocksize := 0;
+    End;
+
+    // 2) On initalise notre bitmap avec les bonnes dimensions
+    OutBmp.SetSize(CurrentFrameInfos.Width, CurrentFrameInfos.Height);
+
+    BufferPtr := nil;
+    Buffer    := nil;
+    // 3) On alloue notre tampon pour les données compressées
+    If (BufferSize > 0) Then Reallocmem(Buffer, BufferSize);
+
+    // 4) On charge toutes les données dans notre tampon
+    // On se replace au début des données
+    Memory.Seek(OldPosition, soBeginning);
+    // On travail toujours sur une copie du "pointer"
+    BufferPtr := Buffer;
+    // On lit la taille du premier bloque
+    BlockSize := Memory.ReadByte;
+    While (BlockSize > 0) And Not (Memory.EOS) Do
+    Begin
+      // On charge les données dans le tampon. On previent des erreurs en cas de dépassements
+      BytesRead := Memory.Read(BufferPtr^, BlockSize);
+      Inc(BufferPtr, BytesRead);
+      If Not (Memory.EOS) Then BlockSize := Memory.ReadByte
+      Else
+        blocksize := 0;
+    End;
+    // On se replace au debut du tampon
+    BufferPtr := Buffer;
+    // 5) On decompresse les données
+    //  On initialise notre buffer ou seront décompressées les données
+    TargetBufferSize := Int64(CurrentFrameInfos.Width) * Int64(CurrentFrameInfos.Height);
+    TargetBufferPtr  := nil;
+    TargetBuffer     := nil;
+    // Si la taille est plus grande que zero, on alloue l'espace nécessaire à notre tampon
+    If (TargetBufferSize > 0) Then Reallocmem(TargetBuffer, TargetBufferSize);
+
+    // Décodage des données compressées
+    Ret := DecodeLZW(Buffer, TargetBuffer, BufferSize, TargetBufferSize);
+
+    // 6) On transfert les données de l'image vers notre bitmap. Si il n'y a pas eu d'erreurs
+    If (Ret = dsOk) Then
+    Begin
+      TargetBufferPtr := TargetBuffer;
+      OutBmp.Clear(clrTransparent);
+
+      // Image non entrelacée
+      If Not (CurrentFrameInfos.Interlaced) Then
+      Begin
+        CurrentLine := 0;
+        While (CurrentLine <= CurrentFrameInfos.Height - 1) Do
+        Begin
+          LinePtr  := OutBmp.GetScanLine(CurrentLine);// FFrames.Items[CurrentFrameIndex].Bitmap.GetScanLine(CurrentLine);
+          For x    := 0 To (CurrentFrameInfos.Width - 1) Do
+          Begin
+            // Lecture de l'index de la couleur dans la palette
+            ColIdx := TargetBufferPtr^;
+            // On utilise la palette de couleur locale
+            If CurrentFrameInfos.HasLocalPalette Then
+            Begin
+              If LocalPalette <> nil Then // La palette est-elle chargée ?
+              Begin
+                //if (ColIdx> ColorCount-1) then ColIdx := ColorCount -1;
+                If (ColIdx < ColorCount) Then TargetColor := LocalPalette.Colors[ColIdx].Value
+                Else
+                  TargetColor := clrTransparent;
+              End
+              Else If FGlobalPalette <> nil Then // Non, alors on utilise la palette globale si elle est présente
+              Begin
+                //if (ColIdx> PaletteCount-1) then ColIdx := PaletteCount -1;
+                If (ColIdx < PaletteCount) Then TargetColor := FGlobalPalette.Colors[ColIdx].Value
+                Else
+                  TargetColor := clrTransparent;
+              End
+              Else
+              Begin
+                AddError(rsEmptyColorMap);
+                Exit;
+              End;
+            End
+            Else // On utilise la palette de couleur globale
+            Begin
+              If FGlobalPalette <> nil Then
+              Begin
+                //if (ColIdx> PaletteCount-1) then ColIdx := PaletteCount -1;
+                If (ColIdx < PaletteCount) Then TargetColor := FGlobalPalette.Colors[ColIdx].Value
+                Else
+                  TargetColor := clrTransparent;
+              End
+              Else If LocalPalette <> nil Then
+              Begin
+                //if (ColIdx> ColorCount-1) then ColIdx := ColorCount -1;
+                If (ColIdx > ColorCount - 1) Then //ColIdx := ColorCount -1;
+                  TargetColor := LocalPalette.Colors[ColIdx].Value
+                Else
+                  TargetColor := clrTransparent;
+              End
+              Else
+              Begin
+                AddError(rsEmptyColorMap);
+                Exit;
+              End;
+            End;
+
+            If CurrentFrameInfos.IsTransparent Then
+            Begin
+              If FHasGlobalPalette Then If ColIdx < FGlobalPalette.Count Then OutBmp.TransparentColor := FGlobalPalette.Colors[ColIdx].Value.ToColor
+                Else If ColIdx < LocalPalette.Count Then OutBmp.TransparentColor := LocalPalette.Colors[ColIdx].Value.ToColor;
+
+              If (Self.FTransparent) Then
+              Begin
+                If (ColIdx = CurrentFrameInfos.TransparentColorIndex) Then
+                begin
+                  TargetColor.Alpha := 0; // clrTransparent;
+                end;
+                If (CurrentFrameInfos.TransparentColorIndex = CurrentFrameInfos.BackgroundColorIndex) Then FbackgroundColor.Alpha := 0; //clrTransparent;
+              End;
+            End;
+            LinePtr^ := TargetColor;
+            // On avance de 1 élément dans nos "pointer"
+            Inc(TargetBufferPtr);
+            Inc(LinePtr);
+          End;
+          Inc(CurrentLine);
+        End;
+      End
+      Else // Image entrelacée
+      Begin
+      CurrentLine := 0;
+      For pass    := 0 To 3 Do
+      Begin
+        Case Pass Of
+          0:
+          Begin
+            CurrentLine := 0;
+            Increment   := 8;
+          End;
+          1:
+          Begin
+            CurrentLine := 4;
+            Increment   := 8;
+          End;
+          2:
+          Begin
+            CurrentLine := 2;
+            Increment   := 4;
+          End;
+          Else
+          Begin
+            CurrentLine := 1;
+            Increment   := 2;
+          End;
+        End;
+        While (CurrentLine < CurrentFrameInfos.Height) Do
+        Begin
+          LinePtr  :=OutBmp.GetScanLine(CurrentLine); // FFrames.Items[CurrentFrameIndex].Bitmap
+          For x    := 0 To (FFrames.Items[CurrentFrameIndex].Bitmap.Width - 1) Do
+          Begin
+            // Lecture de l'index de la couleur dans la palette
+            ColIdx := TargetBufferPtr^;
+            // On utilise la palette de couleur locale
+            If CurrentFrameInfos.HasLocalPalette Then
+            Begin
+              If LocalPalette <> nil Then // La palette est-elle chargée ?
+              Begin
+                If (ColIdx < ColorCount) Then // Dans le cas contraire il s'agit d'un index pour la transparence
+                  TargetColor := LocalPalette.Colors[ColIdx].Value;
+              End
+              Else If FGlobalPalette <> nil Then // Non, alors on utilise la palette globale si elle est présente
+              Begin
+                If (ColIdx < PaletteCount) Then //if (ColIdx< PaletteCount-1) then ColIdx := PaletteCount -1;
+                  TargetColor := FGlobalPalette.Colors[ColIdx].Value;
+              End
+              Else
+              Begin
+                AddError(rsEmptyColorMap);
+                Exit;
+              End;
+            End
+            Else // On utilise la palette de couleur globale
+            Begin
+              If FGlobalPalette <> nil Then
+              Begin
+                If (ColIdx > PaletteCount - 1) Then ColIdx := PaletteCount - 1;
+                TargetColor := FGlobalPalette.Colors[ColIdx].Value;
+              End
+              Else If LocalPalette <> nil Then
+              Begin
+                If (ColIdx > ColorCount - 1) Then ColIdx := ColorCount - 1;
+                TargetColor := LocalPalette.Colors[ColIdx].Value;
+              End
+              Else
+              Begin
+                AddError(rsEmptyColorMap);
+                Exit;
+              End;
+            End;
+
+            If CurrentFrameInfos.IsTransparent Then
+            Begin
+              If FHasGlobalPalette Then If ColIdx < FGlobalPalette.Count Then OutBmp.TransparentColor := FGlobalPalette.Colors[ColIdx].Value.ToColor
+                Else If ColIdx < LocalPalette.Count Then OutBmp.TransparentColor := LocalPalette.Colors[ColIdx].Value.ToColor;
+              If (FTransparent) Then
+              Begin
+                If CurrentFrameInfos.TransparentColorIndex = colIdx Then
+                begin
+                   TargetColor.Alpha := 0; // := clrTransparent;
+                End;
+                If (CurrentFrameInfos.TransparentColorIndex = CurrentFrameInfos.BackgroundColorIndex) Then FBackgroundColor.Alpha := 0;
+              End;
+            End;
+
+            LinePtr^ := TargetColor;
+            Inc(TargetBufferPtr);
+            If (CurrentLine < CurrentFrameInfos.Height - 1) Then Inc(LinePtr);
+          End;
+          Inc(CurrentLine, Increment);
+        End;
+      End;
+    End;
+      if DecoderStatus <> dsOk then
+      begin
+        //outBmp.Clear(ClrTransparent);
+        FFrames.Items[FCurrentLayerIndex].IsCorrupted := True;
+        FFrames.Items[FCurrentLayerIndex].Delay:= 1;
+      End;
+      Inc(FCurrentLayerIndex);   // Index pour la prochaine image
+    End
+    Else
+    Begin
+      Case Ret Of
+        dsInvalidBufferSize: AddError(Format(rsInvalidBufferSize,[CurrentFrameIndex]));
+        dsInvalidInputBufferSize: AddError(Format(rsInvalidInputBufferSize,[CurrentFrameIndex]));
+        dsInvalidOutputBufferSize: AddError(Format(rsInvalidOutputBufferSize,[CurrentFrameIndex]));
+        dsBufferOverflow: AddError(Format(rsBufferOverFlow,[CurrentFrameIndex]));
+        dsOutputBufferTooSmall :
+         (* begin
+            // On supprime l'image. Le tampon de sortie étant trop petit, cela va générer des erreurs lors du transfert des données décompressées vers l'image
+            //FFrames.Delete(CurrentFrameIndex);
+
+          end;*)
+          dec(FCurrentLayerIndex);
+
+      End;
+      if Ret<>dsOutputBufferTooSmall then
+      begin
+        FFrames.Items[FCurrentLayerIndex].IsCorrupted := True;
+        FFrames.Items[FCurrentLayerIndex].Delay:= 1;
+      end;
+    End;
+
+    // On libére la mémoire allouée pour nos tampons
+    If (TargetBufferSize > 0) And (targetBuffer <> nil) Then FreeMem(TargetBuffer);
+    If (BufferSize > 0) And (Buffer <> nil) Then FreeMem(Buffer);
+  End;
+
+Begin
+  PaletteCount := 0;
+  ColorCount   := 0;
+  LocalPalette := nil;
+  FFrames.Clear;
+
+  // Par defaut, on considère que la couleur de fond est totalement transparente
+  FBackgroundColor := clrTransparent;
+  // Si une palette globale existe, alors on charge
+  LoadGlobalPalette;
+  If FHasGlobalPalette Then
+  Begin
+    If FLogicalScreenChunk.BackgroundColorIndex < PaletteCount - 1 Then FBackgroundColor := FGlobalPalette.Colors[FLogicalScreenChunk.BackgroundColorIndex].Value
+    Else
+    Begin
+      FBackgroundColor := clrTransparent; //FGlobalPalette.Colors[FLogicalScreenChunk.BackgroundColorIndex].Value;
+    End;
+  End;
+
+  // Les valeurs suivante seront renseignées lors du chargement d'une image
+  // On réinitialise juste les valeurs par défaut des informations de l'image en cours au cas ou il n'y aurait pas de GCE
+  With CurrentFrameInfos Do
+  Begin
+    Left       := 0;
+    Top        := 0;
+    Width      := FLogicalScreenChunk.ScreenWidth;
+    Height     := FLogicalScreenChunk.ScreenHeight;
+    Interlaced := False;
+    HasLocalPalette := False;
+    IsTransparent := False;
+  End;
+  // On ajoute l'image de départ afin de pouvoir assigner les valeurs des premières extensions (Extensions déclarées avant l'image)
+  CurrentLayer := FFrames.AddNewImage;
+  // On efface l'image avec la couleur de fond
+  //CurrentLayer.Bitmap.Clear(FBackgroundColor);
+  FCurrentLayerIndex := 0;
+  // On lit le 1er octet
+  Done := False;
+  While Not (Done) Do
+  Begin
+    // On verifie l'existence d'extensions avant les données de l'image (Application, Graphic Control, PlainText, Comment)
+    If Not (Memory.EOS) Then BlockID := Memory.ReadByte
+    Else
+      BlockID := GIF_Trailer;
+    If (BlockID = GIF_Trailer) Then
+    Begin
+      Done := True;
+    End;
+    If (BlockID = 0) Then
+    Begin
+      // On Saute les ID Nul
+      While (BlockId = 0) Do BlockId := Memory.ReadByte;
+    End
+    Else If (BlockID = GIF_IMAGEDESCRIPTOR) Then  // C'est une image
+    Begin
+      // On charge l'image
+      LoadImage;
+    End
+    Else If (BlockID = GIF_EXTENSIONINTRODUCER) Then // c'est une extension
+    Begin
+      ReadExtension; // On charge toutes les extensions qui sont à la suite
+    End
+    Else
+    Begin
+      // Extension inconnue on saute jusqu'a trouver un ZERO.
+      // A Verifier avec le flag UseInput dans le "Graphic Control Extension"
+      // Ici on ignore simplement les données
+      While BlockID <> 0 Do
+      Begin
+        BlockID := Memory.ReadByte;
+      End;
+    End;
+  End;
+  // Si il y a des erreurs elles seront notifier à l'utilisateur
+  NotifyError;
+
+  // Il n'y a aucune images on notifie l'erreur
+  If FFrames.Count = 0 Then Raise Exception.Create(rsEmptyImage);
+
+  // On libere la mémoire, prise par nos palettes de couleurs si besoin
+  If (LocalPalette <> nil) Then
+  Begin
+    FreeAndNil(LocalPalette);
+  End;
+  If (FGlobalPalette <> nil) Then
+  Begin
+    FreeAndNil(FGlobalPalette);
+  End;
+End;
+
+{%endregion%}
+
+{%region=====[ TGIFRenderCacheListItem ]========================================}
+
+Constructor TGIFRenderCacheListItem.Create;
+Begin
+  Inherited Create;
+  FBitmap := Graphics.TBitmap.Create;
+  FDelay  := 0;
+End;
+
+Destructor TGIFRenderCacheListItem.Destroy;
+Begin
+  FreeAndNil(FBitmap);
+  Inherited Destroy;
+End;
+
+{%endregion%}
+
+{%region=====[ TGIFRenderCacheList ]============================================}
+
+Function TGIFRenderCacheList.GetItems(Index : Integer): TGIFRenderCacheListItem;
+Begin
+  Result := TGIFRenderCacheListItem(Inherited Items[Index]);
+End;
+
+Procedure TGIFRenderCacheList.SetItems(Index : Integer; AGIFRenderCache : TGIFRenderCacheListItem);
+Begin
+  Put(Index, AGIFRenderCache);
+End;
+
+Procedure TGIFRenderCacheList.Clear;
+Var
+  anItem: TGIFRenderCacheListItem;
+  i:      Integer;
+Begin
+  If Count > 0 Then
+  Begin
+    For i := Count - 1 Downto 0 do
+    Begin
+      AnItem := Items[i];
+      If anItem <> nil Then anItem.Free;
+    End;
+  End;
+  Inherited Clear;
+End;
+
+Function TGIFRenderCacheList.AddNewCache: TGIFRenderCacheListItem;
+Var
+  anItem: TGIFRenderCacheListItem;
+Begin
+  anitem := TGIFRenderCacheListItem.Create;
+  Add(anItem);
+  Result := Items[Self.Count - 1];
+End;
+
+Function TGIFRenderCacheList.Add(AGIFRenderCache : TGIFRenderCacheListItem): Integer;
+Begin
+  Result := Inherited Add(AGIFRenderCache);
+End;
+
+Function TGIFRenderCacheList.Extract(Item : TGIFRenderCacheListItem): TGIFRenderCacheListItem;
+Begin
+  Result := TGIFRenderCacheListItem(Inherited Extract(Item));
+End;
+
+Function TGIFRenderCacheList.Remove(AGIFRenderCache : TGIFRenderCacheListItem): Integer;
+Begin
+  Result := Inherited Remove(AGIFRenderCache);
+End;
+
+Function TGIFRenderCacheList.IndexOf(AGIFRenderCache : TGIFRenderCacheListItem): Integer;
+Begin
+  Result := Inherited IndexOf(AGIFRenderCache);
+End;
+
+Function TGIFRenderCacheList.First: TGIFRenderCacheListItem;
+Begin
+  Result := TGIFRenderCacheListItem(Inherited First);
+End;
+
+Function TGIFRenderCacheList.Last: TGIFRenderCacheListItem;
+Begin
+  Result := TGIFRenderCacheListItem(Inherited Last);
+End;
+
+Procedure TGIFRenderCacheList.Insert(Index : Integer; AGIFRenderCache : TGIFRenderCacheListItem);
+Begin
+  Inherited Insert(Index, AGIFRenderCache);
+End;
+
+Function TGIFRenderCacheList.IsIndexOk(anIndex: Integer): Boolean;
+Begin
+  Result := True;
+  If (anIndex < 0) or (anIndex > Count-1) then result := False;
+End;
+
+Procedure TGIFRenderCacheList.Pack;
+Var
+  i: Integer;
+Begin
+  if Count>1 then
+  begin
+    I := 0;
+    While I<Count do
+    begin
+      if Items[I].IsCorrupted then
+      begin
+        Remove(Items[I]);
+        break;
+      End;
+      inc(I);
+    End;
+    if I<Count then Pack;
+  End;
+End;
+
+{%endregion%}
+
+{%region=====[ TGIFViewer ]=====================================================}
+
+Constructor TGIFViewer.Create(AOwner: TComponent);
+Begin
+  Inherited Create(AOwner);
+  ControlStyle := [csCaptureMouse, csClickEvents, csDoubleClicks];
+  AutoSize     := False;
+  FCenter      := False;
+  FStretch     := False;
+  FTransparent := True;
+  With GetControlClassDefaultSize Do SetInitialBounds(0, 0, CX, CY);
+  FRestoreBitmap := nil;
+  FRenderCache   := TGIFRenderCacheList.Create(False);
+  FGIFLoader     := TGIFImageLoader.Create;
+  FGIFLoader.OnLoadError := @DoInternalOnLoadError;
+  FVirtualView   := TFastBitmap.Create;
+  FCurrentView   := nil;
+  FCurrentView   := Graphics.TBitmap.Create;
+  FRestoreBitmap := nil;
+  FAutoPlay      := False;
+  FBorderShow    := False;
+  FBorderColor   := clBlack;
+  FBorderWidth   := 1;
+  FBevelInner    := bvNone;
+  FBevelOuter    := bvNone;
+  FBevelWidth    := 1;
+  FColor         := clNone;
+  FDisplayInvalidFrames := False;
+  FAutoRemoveInvalidFrame := True;
+  FLastDrawMode  := dmNone;
+
+  FAnimateTimer := TTimer.Create(nil);
+  With FAnimateTimer Do
+  Begin
+    Enabled  := False;
+    Interval := 1000;
+    OnTimer  := @DoTimerAnimate;
+  End;
+  FAnimateSpeed := 1;
+  FCurrentFrameIndex := 0;
+  FGIFWidth  := 90;
+  FGIFHeight := 90;
+  FAutoStretchMode := smManual;
+End;
+
+Destructor TGIFViewer.Destroy;
+Begin
+  FAnimateTimer.Enabled := False;
+
+  FreeAndNil(FAnimateTimer);
+  If FCurrentView <> nil Then FreeAndNil(FCurrentView);
+  If FRestoreBitmap <> nil Then FreeAndNil(FRestoreBitmap);
+  FreeAndNil(FVirtualView);
+  FRenderCache.Clear;
+  FreeAndNil(FRenderCache);
+  FreeAndNil(FGIFLoader);
+
+  Inherited Destroy;
+End;
+
+Procedure TGIFViewer.SetCenter(Const Value: Boolean);
+Begin
+  If Value = FCenter Then exit;
+  FCenter := Value;
+  Invalidate;
+End;
+
+Function TGIFViewer.GetCanvas: TCanvas;
+Begin
+  Result := Inherited Canvas;// FCurrentView.Canvas
+End;
+
+Function TGIFViewer.GetFrameCount: Integer;
+Begin
+  If FCache Then
+    Result := FRenderCache.Count
+  Else Begin
+    Result := FGifLoader.FrameCount;
+  End;
+End;
+
+Function TGIFViewer.GetGIFVersion: String;
+Begin
+  Result := FGIFLoader.Version;
+End;
+
+Function TGIFViewer.GetRawFrameItem(Index : Integer): TGIFImageListItem;
+Begin
+  Result := nil;
+  If (Index >= 0) And (Index < FGIFLoader.FrameCount) Then Result := FGIFLoader.Frames[Index];
+end;
+
+Procedure TGIFViewer.SetAutoStretchMode(AValue: TGIFAutoStretchMode);
+Begin
+  If FAutoStretchMode = AValue Then Exit;
+  FAutoStretchMode := AValue;
+  Invalidate;
+End;
+
+Procedure TGIFViewer.SetStretch(Const Value: Boolean);
+Begin
+  If Value = FStretch Then exit;
+  FStretch := Value;
+  Invalidate;
+End;
+
+Procedure TGIFViewer.SetPause(Const Value: Boolean);
+Begin
+  If Value = FPause Then exit;
+  FPause := Value;
+  If FPause Then FAnimateTimer.Enabled := False;
+  If Assigned(FOnPause) Then FOnPause(Self);
+End;
+
+Procedure TGIFViewer.SetFileName(Const Value: String);
+Begin
+  If Value = FFileName Then exit;
+  FFileName := Value;
+  LoadFromFile(FFileName);
+End;
+
+Function TGIFViewer.GetFrame(Const Index: Integer): Graphics.TBitmap;
+Begin
+  Result := nil;
+  If (Index >= 0) And (Index < FrameCount) Then Result := FRenderCache.Items[Index].Bitmap;
+End;
+
+Procedure TGIFViewer.SetTransparent(Const Value: Boolean);
+Begin
+  If FTransparent = Value Then exit;
+  FTransparent := Value;
+  FGIFLoader.Transparent := Value;
+  If FFileName <> '' Then LoadFromFile(FFileName);
+End;
+
+Procedure TGIFViewer.SetBevelWidth(Const Value: TBevelWidth);
+Begin
+  If FBevelWidth <> Value Then
+  Begin
+    FBevelWidth := Value;
+    Invalidate;
+  End;
+End;
+
+Procedure TGIFViewer.ResetCurrentView;
+Var
+  I: Integer;
+  Corrupted : Boolean;
+begin
+  if FRenderCache.Count>1 then
+  begin
+    if not(FDisplayInvalidFrames) then
+    begin
+      Corrupted := false;
+      i := 0;
+      Repeat
+        Corrupted := FRenderCache.Items[i].IsCorrupted;
+        inc(i);
+      until (i>FRenderCache.Count-1) or (Corrupted = false);
+      if (i>FRenderCache.Count-1) and (Corrupted = true) then
+      begin
+        Raise Exception.Create(rsAllFrameCorrupted);
+        exit;
+      end
+      else
+      begin
+        Dec(i);
+        FCurrentframeIndex     := i;
+        FAnimateTimer.Interval := FRenderCache.Items[i].Delay;
+        FCurrentView.Assign(FRenderCache.Items[i].Bitmap);
+      end;
+    end
+    else
+    begin
+      FAnimateTimer.Interval := FRenderCache.Items[0].Delay;
+      FCurrentView.Assign(FRenderCache.Items[0].Bitmap);
+    end;
+  end
+  else
+  begin
+    FCurrentView.Assign(FRenderCache.Items[0].Bitmap);
+  end;
+  FLastDrawMode := dmNone;
+End;
+
+Procedure TGIFViewer.SetBevelInner(Const Value: TPanelBevel);
+Begin
+  If BevelInner <> Value Then
+  Begin
+    FBevelInner := Value;
+    Invalidate;
+  End;
+End;
+
+Procedure TGIFViewer.SetBevelOuter(Const Value: TPanelBevel);
+Begin
+  If BevelOuter <> Value Then
+  Begin
+    FBevelOuter := Value;
+    Invalidate;
+  End;
+End;
+
+Procedure TGIFViewer.DoInternalOnLoadError(Sender: TObject; Const ErrorCount: Integer; Const ErrorList: TStringList);
+Begin
+  If Assigned(FOnLoadError) Then FOnloadError(Self, ErrorCount, ErrorList);
+End;
+
+Procedure TGIFViewer.DoTimerAnimate(Sender: TObject);
+Begin
+  Inc(FCurrentFrameIndex);
+  If FCurrentFrameIndex > (FGIFLoader.FrameCount - 1) Then FCurrentFrameIndex := 0;
+
+  If (not FCache) and (FCurrentFrameIndex >= FRenderCache.Count) Then
+  Begin
+    RenderFrame(FCurrentFrameIndex);
+  End;
+
+  If Assigned(FOnFrameChange) Then FOnFrameChange(Self);
+  if not(FDisplayInvalidFrames) then
+  begin
+    if not(FRenderCache.Items[FCurrentFrameIndex].IsCorrupted) then
+    begin
+      FAnimateTimer.Interval := FRenderCache.Items[FCurrentFrameIndex].Delay;
+      FCurrentView.Assign(FRenderCache.Items[FCurrentFrameIndex].Bitmap);
+    End
+    else FAnimateTimer.Interval := FRenderCache.Items[FCurrentFrameIndex].Delay;
+  end
+  else
+  begin
+    FAnimateTimer.Interval := FRenderCache.Items[FCurrentFrameIndex].Delay;
+    FCurrentView.Assign(FRenderCache.Items[FCurrentFrameIndex].Bitmap);
+  end;
+  Invalidate;
+End;
+
+Procedure TGIFViewer.RenderFrame(Index: Integer);
+Var
+  Src:         TFastBitmap;
+  pTop, pLeft: Integer;
+  iDrawMode:   TFastBitmapDrawMode;
+  TmpBmp : Graphics.TBitmap;
+Begin
+
+  Src   := FGIFLoader.Frames.Items[Index].Bitmap;
+  pLeft := FGIFLoader.Frames.Items[Index].Left;
+  pTop  := FGIFLoader.Frames.Items[Index].Top;
+
+  FRenderCache.AddNewCache;
+  FRenderCache.Items[Index].Delay  := FGIFLoader.Frames[Index].Delay * FAnimateSpeed;
+  FRenderCache.Items[Index].IsCorrupted  := FGIFLoader.Frames[Index].IsCorrupted;
+
+  If (FTransparent) Then
+  Begin
+    iDrawMode := dmAlphaCheck;
+  End
+  Else
+  Begin
+    iDrawMode := dmSet;
+  End;
+
+  If Index = 0 Then
+  Begin
+    If (FTransparent) Then
+    Begin
+      FVirtualView.Clear(clrTransparent);
+    End
+    Else
+    Begin
+      FVirtualView.Clear(FGIFLoader.BackgroundColor);
+    End;
+    FVirtualView.PutImage(Src, 0, 0, Src.Width, Src.Height, pLeft, pTop, dmSet);
+    if FGIFLoader.Frames.Items[0].DrawMode = dmKeep then begin
+      if Assigned( FRestoreBitmap) then begin
+        FRestoreBitmap.Free;
+      end;
+      FRestoreBitmap := FVirtualView.Clone;
+    end;
+  End
+  Else
+  Begin
+
+    With FGIFLoader.Frames.Items[Index] Do
+    Begin
+      Case DrawMode Of
+        dmNone:
+        Begin
+          FVirtualView.PutImage(Src, 0, 0, Src.Width, Src.Height, pLeft, pTop, iDrawMode);
+        End;
+        dmKeep:
+        Begin
+          if FLastDrawMode = dmErase then
+          begin
+            If (FGIFLoader.Frames.Items[Index].IsTransparent And FTransparent) Then FVirtualView.Clear(clrTransparent)
+            Else
+              FVirtualView.Clear(FGIFLoader.BackgroundColor);
+          end;
+          FVirtualView.PutImage(Src, 0, 0, Src.Width, Src.Height, pLeft, pTop, iDrawMode);
+          If Assigned(FRestoreBitmap) Then FreeAndNil(FRestoreBitmap);
+          FRestoreBitmap := FVirtualView.Clone;
+        End;
+        dmErase:
+        Begin
+          If (FGIFLoader.Frames.Items[Index].IsTransparent And FTransparent) Then FVirtualView.Clear(clrTransparent)
+          Else
+            FVirtualView.Clear(FGIFLoader.BackgroundColor);
+          FVirtualView.PutImage(Src, 0, 0, Src.Width, Src.Height, pLeft, pTop, iDrawMode);
+        End;
+        dmRestore:
+        Begin
+          if FLastDrawMode = dmErase then
+          begin
+            If (FGIFLoader.Frames.Items[Index].IsTransparent And FTransparent) Then FVirtualView.Clear(clrTransparent)
+            Else
+              FVirtualView.Clear(FGIFLoader.BackgroundColor);
+          End;
+
+          If Assigned(FRestoreBitmap) Then FVirtualView.PutImage(FRestoreBitmap, 0, 0, FRestoreBitmap.Width, FRestoreBitmap.Height, 0, 0, dmSet)
+          else
+          begin
+            If (FGIFLoader.Frames.Items[Index].IsTransparent And FTransparent) Then FVirtualView.Clear(clrTransparent)
+            Else
+              FVirtualView.Clear(FGIFLoader.BackgroundColor);
+          end;
+
+          FVirtualView.PutImage(Src, 0, 0, Src.Width, Src.Height, pLeft, pTop, iDrawMode);
+        End;
+        Else
+          FVirtualView.PutImage(Src, 0, 0, Src.Width, Src.Height, pLeft, pTop, dmSet);
+      End;
+      FLastDrawMode := DrawMode;
+    End;
+  End;
+  // Note : Sous MacOS on ne peux pas assigner FRenderCache.Items[Index].Bitmap directement avec
+  // FVirtualView.GetBitmap; On est obligé de créer le bitmap de destination et utiliser Assign.
+  // Dans le cas contraire seulment la première image sera affichée.
+  //TmpBmp := Graphics.TBitmap.Create; <== MEMORY LEAK
+  TmpBmp := FVirtualView.GetBitmap;
+  FRenderCache.Items[Index].Bitmap.Assign(TmpBmp);
+  FreeAndNil(TmpBmp);
+End;
+
+Procedure TGIFViewer.ComputeCache;
+Var
+  I: Integer;
+Begin
+  FCurrentFrameIndex := 0;
+  FRenderCache.Clear;
+  If FGIFLoader.FrameCount > 0 Then
+  Begin
+    For I := 0 To Pred(FGIFLoader.FrameCount) Do
+    Begin
+      RenderFrame(I);
+    End;
+  end;
+  if AutoRemoveInvalidFrame then FRenderCache.Pack;
+  ResetCurrentView;
+End;
+
+Procedure TGIFViewer.CalculatePreferredSize(Var PreferredWidth, PreferredHeight: Integer; WithThemeSpace: Boolean);
+Var
+  extraWidth: Integer;
+Begin
+  extraWidth := - 2;
+  if FBorderShow then extraWidth      := (FBorderWidth * 2) + (FBevelWidth * 2);
+  PreferredWidth  := FGIFWidth + extraWidth + 2;
+  PreferredHeight := FGIFHeight + extraWidth + 2;
+End;
+
+Class Function TGIFViewer.GetControlClassDefaultSize: TSize;
+Begin
+  Result.CX := 90; // = ClientWidth
+  Result.CY := 90; // = ClientHeight
+End;
+
+Function TGIFViewer.DestRect: TRect;
+Var
+  PicWidth, PicHeight: Integer;
+  ImgWidth, ImgHeight: Integer;
+  n: Integer;
+
+  procedure KeepAspectRatio( Var aWidth, aHeight : Integer; MaxWidth, MaxHeight : Integer);
+  var
+     w, h : Integer;
+  begin
+      w :=  MaxWidth;
+      h := (aHeight * w) Div aWidth;
+      If h > MaxHeight Then
+      Begin
+        h := MaxHeight;
+        w := (aWidth * h) Div aHeight;
+      End;
+      aWidth := w;
+      aHeight := h;
+  End;
+
+Begin
+  PicWidth  := FCurrentView.Width;
+  PicHeight := FCurrentView.Height;
+  ImgWidth  := ClientWidth;
+  ImgHeight := ClientHeight;
+  If (PicWidth = 0) Or (PicHeight = 0) Then Exit(Rect(0, 0, 0, 0));
+
+  if FAutoStretchMode <> smManual then
+  begin
+    Case FAutoStretchMode of
+     smStretchAll : FStretch := True;
+     smStretchOnlyBigger : if (PicWidth > ImgWidth) or (PicHeight > ImgHeight) then FStretch := True else FStretch := False;
+     smStretchOnlySmaller : if (PicWidth < ImgWidth) and (PicHeight < ImgHeight) then FStretch := True else FStretch := False;
+    end;
+    if Assigned(FOnStretchChanged) then FOnStretchChanged(Self,FStretch);
+  End;
+
+  If FStretch Then
+  Begin
+   KeepAspectRatio(PicWidth, PicHeight,ImgWidth, ImgHeight);
+  End;
+
+  n  := FBorderWidth + FBevelWidth;
+  If FBorderShow Then
+  Begin
+    Result := Rect(n, n, n + PicWidth, n + PicHeight);
+  End
+  Else
+    Result := Rect(0, 0, PicWidth, PicHeight);
+
+  If FCenter Then
+  Begin
+    If FBorderShow Then
+    Begin
+      Result.Left   := n + ((ClientWidth -(n+n))  - PicWidth)  shr 1;
+      Result.Top    := n + ((ClientHeight-(n+n))  - PicHeight) shr 1;
+    end
+    else
+    begin
+      Result.Left   := ((ClientWidth  - PicWidth) shr 1);
+      Result.Top    := ((ClientHeight - PicHeight) shr 1);
+    end;
+    Result.Right  := Result.Left + PicWidth;
+    Result.Bottom := Result.Top + PicHeight;
+  End;
+End;
+
+Procedure TGIFViewer.Paint;
+
+  Procedure DrawFrame;
+  Begin
+    With Inherited Canvas Do
+    Begin
+      Pen.Color := clBlack;
+      Pen.Style := psDash;
+      MoveTo(0, 0);
+      LineTo(Self.Width - 1, 0);
+      LineTo(Self.Width - 1, Self.Height - 1);
+      LineTo(0, Self.Height - 1);
+      LineTo(0, 0);
+    End;
+  End;
+
+Var
+  R:     TRect;
+  C:     TCanvas;
+  ARect: TRect;
+  w:     Integer;
+Begin
+
+  If csDesigning In ComponentState Then DrawFrame;
+
+  C         := Inherited Canvas;
+  FPainting := True;
+  R         := DestRect;
+  Try
+    C.Lock;
+    // Fond
+    If (FColor <> clNone) Then //and Not(FTransparent)
+    Begin
+      With C Do
+      Begin
+        Brush.Style := bsSolid;
+        Brush.Color := FColor;
+        FillRect(0, 0, ClientWidth, ClientHeight);
+      End;
+    End;
+
+    // Bitmap
+    FCurrentView.Transparent := FTransparent;
+    C.StretchDraw(R, FCurrentView);
+
+    // Bordures
+    If FBorderShow Then
+    Begin
+      ARect := rect(0, 0, ClientWidth, ClientHeight);
+      w     := FBevelWidth;
+      If (FBevelInner <> bvNone) And (w > 0) Then C.Frame3d(ARect, w, BevelInner); // Note: Frame3D inflates ARect
+      InflateRect(ARect, -(FBorderWidth + 1), -(FBorderWidth + 1));
+      If (FBevelOuter <> bvNone) And (w > 0) Then C.Frame3d(ARect, w, BevelOuter);
+
+      If FBorderWidth > 0 Then With C Do
+        Begin
+          Pen.Style   := psSolid;
+          Pen.Width   := FBorderWidth;
+          Pen.Color   := FBorderColor;
+          Brush.Style := bsClear;
+          Rectangle(0, 0, ClientWidth, ClientHeight);
+        End;
+    End;
+
+    C.UnLock;
+  Finally
+    FPainting := False;
+  End;
+
+  Inherited Paint;
+End;
+
+Procedure TGIFViewer.Loaded;
+begin
+  if FFileName<>'' then LoadFromFile(FFileName);
+  inherited Loaded;
+end;
+
+procedure TGIFViewer.BeforeLoad;
+begin
+  FAnimateTimer.Enabled := False;
+  FPause     := False;
+  FAnimated  := False;
+  FCurrentFrameIndex := 0;
+end;
+
+procedure TGIFViewer.AfterLoad;
+begin
+  FGIFWidth  := FGIFLoader.Width;
+  FGIFHeight := FGIFLoader.Height;
+  FVirtualView.SetSize(FGIFWidth, FGIFHeight);
+
+  if FCache then
+    ComputeCache
+  else begin
+    FRenderCache.Clear;
+    FCurrentFrameIndex := 0;
+    RenderFrame(0);
+    ResetCurrentView;
+  end;
+
+  If AutoSize Then
+  Begin
+    InvalidatePreferredSize;
+    AdjustSize;
+  End;
+  Invalidate;
+  If FAutoPlay Then Start;
+end;
+
+Procedure TGIFViewer.Invalidate;
+Begin
+  If FPainting Then exit;
+  Inherited Invalidate;
+End;
+
+Procedure TGIFViewer.LoadFromStream(aStream : TStream);
+Begin
+  BeforeLoad;
+  FGIFLoader.FErrorList.Clear;
+  FGIFLoader.FErrorCOunt := 0;
+  FGIFLoader.LoadFromStream(aStream);
+  AfterLoad;
+End;
+
+Procedure TGIFViewer.LoadFromFile(Const aFileName: String);
+Begin
+  BeforeLoad;
+  if Not(FileExists(aFileName)) then
+  begin
+    MessageDlg(Format(rsFileNotFound,[aFileName]), mtError, [mbOK],0);
+    Exit;
+  end;
+  FGIFLoader.LoadFromFile(aFileName);
+  FFileName  := aFileName;
+  AfterLoad;
+End;
+
+Procedure TGIFViewer.LoadFromResource(Const ResName: String);
+Var
+  Resource: TLResource;
+Begin
+  BeforeLoad;
+  Resource  := LazarusResources.Find(ResName);
+  If Resource = nil Then Raise Exception.Create(Format(rsResourceNotFound,[ResName]))
+  Else If CompareText(LazarusResources.Find(ResName).ValueType, 'gif') = 0 Then
+  Begin
+    FGIFLoader.LoadFromResource(ResName);
+    AfterLoad;
+  End;
+End;
+
+Procedure TGIFViewer.Start;
+Begin
+  If Not (FPause) Then FCurrentFrameIndex := 0;
+  FPause    := False;
+  FAnimated := True;
+  FAnimateTimer.Enabled := True;
+  If Assigned(FOnStart) Then FOnStart(Self);
+End;
+
+Procedure TGIFViewer.Stop;
+Begin
+  FAnimateTimer.Enabled := False;
+  FAnimated := False;
+  FPause    := False;
+  If Assigned(FOnStop) Then FOnStop(Self);
+  FCurrentframeIndex     := 0;
+  ResetCurrentView;
+  Invalidate;
+End;
+
+Procedure TGIFViewer.Pause;
+Begin
+  FAnimateTimer.Enabled := False;
+  FPause := True;
+End;
+
+Procedure TGIFViewer.NextFrame;
+begin
+  if FCurrentFrameIndex < FGifLoader.FrameCount - 1 then
+  begin
+    Inc(FCurrentFrameIndex);
+
+    repeat
+
+      If (not FCache) and (FCurrentFrameIndex >= FRenderCache.Count) Then
+      begin
+        RenderFrame(FCurrentFrameIndex);
+      end;
+
+      If Assigned(FOnFrameChange) Then FOnFrameChange(Self);
+
+      if not(FDisplayInvalidFrames) then
+      begin
+        if not(FRenderCache.Items[FCurrentFrameIndex].IsCorrupted) then
+        begin
+          FCurrentView.Assign(FRenderCache.Items[FCurrentFrameIndex].Bitmap);
+        End
+        Else If FCurrentFrameIndex > 0 Then
+        Begin
+          Inc(FCurrentFrameIndex);
+          Continue;
+        End;
+      end
+      else
+      begin
+        FCurrentView.Assign(FRenderCache.Items[FCurrentFrameIndex].Bitmap);
+      end;
+      Break;
+    until False;
+
+    FAnimateTimer.Interval := FRenderCache.Items[FCurrentFrameIndex].Delay;
+  end;
+  Invalidate;
+end;
+
+Procedure TGIFViewer.PriorFrame;
+begin
+  if FCurrentFrameIndex > 0 then
+  begin
+    Dec(FCurrentFrameIndex);
+
+    repeat
+      If Assigned(FOnFrameChange) Then FOnFrameChange(Self);
+
+      if not(FDisplayInvalidFrames) then
+      begin
+        if not(FRenderCache.Items[FCurrentFrameIndex].IsCorrupted) then
+        begin
+          FCurrentView.Assign(FRenderCache.Items[FCurrentFrameIndex].Bitmap);
+        End
+        Else If FCurrentFrameIndex > 0 Then
+        Begin
+          Dec(FCurrentFrameIndex);
+          Continue;
+        End;
+      end
+      else
+      begin
+        FCurrentView.Assign(FRenderCache.Items[FCurrentFrameIndex].Bitmap);
+      end;
+      Break;
+    until False;
+
+    FAnimateTimer.Interval := FRenderCache.Items[FCurrentFrameIndex].Delay;
+  end;
+  Invalidate;
+end;
+
+Function TGIFViewer.GetRawFrame(Index: Integer): TBitmap;
+Begin
+  Result := FGIFLoader.Frames[Index].Bitmap.GetBitmap;
+End;
+
+Procedure TGIFViewer.DisplayFrame(Index: Integer);
+Begin
+  If not(FRenderCache.IsIndexOk(Index)) then exit;
+  if Not(DisplayInvalidFrames) then
+  begin
+    if FRenderCache.Items[Index].IsCorrupted then
+    begin
+      inc(Index);
+      DisplayFrame(Index);
+    End
+    else
+    begin
+      FCurrentView.Assign(FRenderCache.Items[Index].Bitmap);
+    End;
+  end
+  else
+  begin
+    FCurrentView.Assign(FRenderCache.Items[Index].Bitmap);
+  End;
+  Invalidate;
+End;
+
+Procedure TGIFViewer.DisplayRawFrame(Index: Integer);
+Var
+  Tmp: Graphics.TBitmap;
+Begin
+  If not(FRenderCache.IsIndexOk(Index)) Then exit;
+  Tmp := GetRawFrame(Index);
+  FCurrentView.Assign(Tmp);
+  FreeAndNil(Tmp);
+  Invalidate;
+End;
+
+Procedure TGIFViewer.ExtractFrame(Index: Integer; Var bmp: TBitmap);
+Begin
+  If not(FRenderCache.IsIndexOk(Index)) then exit;
+  Bmp.Assign(FRenderCache.Items[Index].Bitmap);
+End;
+
+Procedure TGIFViewer.ExtractRawFrame(Index: Integer; Var bmp: TBitmap);
+Var
+  Tmp: Graphics.TBitmap;
+Begin
+  If not(FRenderCache.IsIndexOk(Index)) Then exit;
+  Tmp := GetRawFrame(Index);
+  Bmp.Assign(Tmp);
+  FreeAndNil(Tmp);
+End;
+
+{%endregion}
+
+Procedure Register;
+Begin
+  RegisterComponents('Misc', [TGIFView]);
+End;
+
+End.

BIN
components/gifview/tgifview.png


+ 1 - 1
doc/INSTALL.txt

@@ -15,7 +15,7 @@ directory of DC sources. You must open each .lpk package file:
 - multithreadprocs/multithreadprocslaz.lpk
 - multithreadprocs/multithreadprocslaz.lpk
 - kascrypt/kascrypt.lpk
 - kascrypt/kascrypt.lpk
 - doublecmd/doublecmd_common.lpk
 - doublecmd/doublecmd_common.lpk
-- gifanim/pkg_gifanim.lpk
+- gifview/gifview.lpk
 - KASToolBar/kascomp.lpk
 - KASToolBar/kascomp.lpk
 - synunihighlighter/synuni.lpk
 - synunihighlighter/synuni.lpk
 - viewer/viewerpackage.lpk
 - viewer/viewerpackage.lpk

+ 1 - 1
fpmake.pp

@@ -19,7 +19,7 @@ const
     'components\Image32\Image32.lpk',
     'components\Image32\Image32.lpk',
     'components\KASToolBar\kascomp.lpk',
     'components\KASToolBar\kascomp.lpk',
     'components\viewer\viewerpackage.lpk',
     'components\viewer\viewerpackage.lpk',
-    'components\gifanim\pkg_gifanim.lpk',
+    'components\gifview\gifview.lpk',
     'components\synunihighlighter\synuni.lpk',
     'components\synunihighlighter\synuni.lpk',
     'components\virtualterminal\virtualterminal.lpk'
     'components\virtualterminal\virtualterminal.lpk'
   );
   );

+ 1 - 2
src/doublecmd.lpi

@@ -299,8 +299,7 @@ end;"/>
         <MinVersion Valid="True"/>
         <MinVersion Valid="True"/>
       </Item5>
       </Item5>
       <Item6>
       <Item6>
-        <PackageName Value="pkg_gifanim"/>
-        <MinVersion Major="1" Minor="5" Valid="True"/>
+        <PackageName Value="GifView"/>
       </Item6>
       </Item6>
       <Item7>
       <Item7>
         <PackageName Value="VirtualTerminal"/>
         <PackageName Value="VirtualTerminal"/>

+ 13 - 3
src/fviewer.lfm

@@ -371,7 +371,6 @@ object frmViewer: TfrmViewer
     ParentFont = False
     ParentFont = False
     TabOrder = 3
     TabOrder = 3
     Visible = False
     Visible = False
-    OnResize = pnlImageResize
     object sboxImage: TScrollBox
     object sboxImage: TScrollBox
       Left = 0
       Left = 0
       Height = 307
       Height = 307
@@ -389,6 +388,7 @@ object frmViewer: TfrmViewer
       OnMouseEnter = sboxImageMouseEnter
       OnMouseEnter = sboxImageMouseEnter
       OnMouseLeave = sboxImageMouseLeave
       OnMouseLeave = sboxImageMouseLeave
       OnMouseMove = sboxImageMouseMove
       OnMouseMove = sboxImageMouseMove
+      OnResize = sboxImageResize
       object Image: TImage
       object Image: TImage
         Left = 56
         Left = 56
         Height = 288
         Height = 288
@@ -407,12 +407,22 @@ object frmViewer: TfrmViewer
         OnMouseWheelUp = ImageMouseWheelUp
         OnMouseWheelUp = ImageMouseWheelUp
         Proportional = True
         Proportional = True
       end
       end
-      object GifAnim: TGifAnim
+      object GifAnim: TGIFView
         Left = 0
         Left = 0
         Height = 90
         Height = 90
         Top = 0
         Top = 0
         Width = 106
         Width = 106
-        AutoSize = False
+        Border = False
+        BorderColor = clBlack
+        BorderWidth = 0
+        BevelOuter = bvNone
+        AutoPlay = False
+        Transparent = True
+        Center = False
+        AutoStretchMode = smManual
+        Stretch = True
+        DisplayInvalidFrames = False
+        AutoRemoveInvalidFrame = True
         OnMouseDown = GifAnimMouseDown
         OnMouseDown = GifAnimMouseDown
         OnMouseEnter = GifAnimMouseEnter
         OnMouseEnter = GifAnimMouseEnter
       end
       end

+ 83 - 53
src/fviewer.pas

@@ -58,7 +58,7 @@ interface
 uses
 uses
   SysUtils, Classes, Graphics, Controls, Forms, ExtCtrls, ComCtrls, LMessages,
   SysUtils, Classes, Graphics, Controls, Forms, ExtCtrls, ComCtrls, LMessages,
   LCLProc, Menus, Dialogs, ExtDlgs, StdCtrls, Buttons, SynEditHighlighter,
   LCLProc, Menus, Dialogs, ExtDlgs, StdCtrls, Buttons, SynEditHighlighter,
-  Grids, ActnList, viewercontrol, GifAnim, fFindView, WLXPlugin, uWLXModule,
+  Grids, ActnList, viewercontrol, uGifViewer, fFindView, WLXPlugin, uWLXModule,
   uFileSource, fModView, Types, uThumbnails, uFormCommands, uOSForms,Clipbrd,
   uFileSource, fModView, Types, uThumbnails, uFormCommands, uOSForms,Clipbrd,
   uExifReader, KASStatusBar, SynEdit, uShowForm, uRegExpr, uRegExprU,
   uExifReader, KASStatusBar, SynEdit, uShowForm, uRegExpr, uRegExprU,
   Messages, fEditSearch, uMasks, uSearchTemplate, uFileSourceOperation,
   Messages, fEditSearch, uMasks, uSearchTemplate, uFileSourceOperation,
@@ -159,7 +159,7 @@ type
     btnPrev1: TSpeedButton;
     btnPrev1: TSpeedButton;
     btnReload1: TSpeedButton;
     btnReload1: TSpeedButton;
     DrawPreview: TDrawGrid;
     DrawPreview: TDrawGrid;
-    GifAnim: TGifAnim;
+    GifAnim: TGIFView;
     memFolder: TMemo;
     memFolder: TMemo;
     mnuPlugins: TMenuItem;
     mnuPlugins: TMenuItem;
     miCode: TMenuItem;
     miCode: TMenuItem;
@@ -315,7 +315,6 @@ type
     procedure miPenClick(Sender: TObject);
     procedure miPenClick(Sender: TObject);
     procedure miLookBookClick(Sender: TObject);
     procedure miLookBookClick(Sender: TObject);
     procedure pmEditMenuPopup(Sender: TObject);
     procedure pmEditMenuPopup(Sender: TObject);
-    procedure pnlImageResize(Sender: TObject);
     procedure miPluginsClick(Sender: TObject);
     procedure miPluginsClick(Sender: TObject);
 
 
     procedure pnlTextMouseWheelUp(Sender: TObject; Shift: TShiftState;
     procedure pnlTextMouseWheelUp(Sender: TObject; Shift: TShiftState;
@@ -325,6 +324,7 @@ type
     procedure sboxImageMouseMove(Sender: TObject; Shift: TShiftState; X,
     procedure sboxImageMouseMove(Sender: TObject; Shift: TShiftState; X,
       Y: Integer);
       Y: Integer);
     procedure btnNextGifFrameClick(Sender: TObject);
     procedure btnNextGifFrameClick(Sender: TObject);
+    procedure sboxImageResize(Sender: TObject);
     procedure SplitterChangeBounds;
     procedure SplitterChangeBounds;
     procedure TimerReloadTimer(Sender: TObject);
     procedure TimerReloadTimer(Sender: TObject);
     procedure TimerScreenshotTimer(Sender: TObject);
     procedure TimerScreenshotTimer(Sender: TObject);
@@ -351,6 +351,7 @@ type
     procedure UpdateImagePlacement;
     procedure UpdateImagePlacement;
     procedure StartCalcFolderSize;
     procedure StartCalcFolderSize;
     procedure StopCalcFolderSize;
     procedure StopCalcFolderSize;
+    procedure UpdateAnimState;
 
 
   private
   private
     FFileName: String;
     FFileName: String;
@@ -2061,11 +2062,6 @@ begin
   end;
   end;
 end;
 end;
 
 
-procedure TfrmViewer.pnlImageResize(Sender: TObject);
-begin
-  if bImage then AdjustImageSize;
-end;
-
 procedure TfrmViewer.miPluginsClick(Sender: TObject);
 procedure TfrmViewer.miPluginsClick(Sender: TObject);
 var
 var
   ShowFlags: Integer;
   ShowFlags: Integer;
@@ -2117,10 +2113,27 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TfrmViewer.UpdateAnimState;
+begin
+  btnPrevGifFrame.Enabled:= GifAnim.Paused and (GifAnim.CurrentFrameIndex > 0);
+  btnNextGifFrame.Enabled:= GifAnim.Paused and (GifAnim.CurrentFrameIndex < GifAnim.FrameCount - 1);
+end;
+
+procedure TfrmViewer.btnPrevGifFrameClick(Sender: TObject);
+begin
+  GifAnim.PriorFrame;
+  UpdateAnimState;
+end;
+
 procedure TfrmViewer.btnNextGifFrameClick(Sender: TObject);
 procedure TfrmViewer.btnNextGifFrameClick(Sender: TObject);
 begin
 begin
-  GifAnim.Animate:=false;
   GifAnim.NextFrame;
   GifAnim.NextFrame;
+  UpdateAnimState;
+end;
+
+procedure TfrmViewer.sboxImageResize(Sender: TObject);
+begin
+  if bImage or bAnimation then AdjustImageSize;
 end;
 end;
 
 
 procedure TfrmViewer.SplitterChangeBounds;
 procedure TfrmViewer.SplitterChangeBounds;
@@ -2289,6 +2302,10 @@ begin
       UndoTmp;
       UndoTmp;
     end;
     end;
     AdjustImageSize;
     AdjustImageSize;
+  end
+  else if bAnimation then
+  begin
+    AdjustImageSize;
   end;
   end;
 end;
 end;
 
 
@@ -2414,8 +2431,6 @@ begin
 
 
   FixFormIcon(Handle);
   FixFormIcon(Handle);
 
 
-  GifAnim.Align:=alClient;
-
   for Index:= 1 to 25 do
   for Index:= 1 to 25 do
   begin
   begin
     MenuItem:= TMenuItem.Create(btnPenWidth);
     MenuItem:= TMenuItem.Create(btnPenWidth);
@@ -2521,24 +2536,26 @@ end;
 
 
 procedure TfrmViewer.btnGifMoveClick(Sender: TObject);
 procedure TfrmViewer.btnGifMoveClick(Sender: TObject);
 begin
 begin
-  GifAnim.Animate:=not GifAnim.Animate;
-  btnNextGifFrame.Enabled:= not GifAnim.Animate;
-  btnPrevGifFrame.Enabled:= not GifAnim.Animate;
-  if GifAnim.Animate then
-    btnGifMove.ImageIndex:= 11
+  if GifAnim.Paused then
+    GifAnim.Start
   else begin
   else begin
+    GifAnim.Pause;
+  end;
+  if GifAnim.Paused then
     btnGifMove.ImageIndex:= 12
     btnGifMove.ImageIndex:= 12
+  else begin
+    btnGifMove.ImageIndex:= 11
   end;
   end;
+  UpdateAnimState;
 end;
 end;
 
 
 procedure TfrmViewer.btnGifToBmpClick(Sender: TObject);
 procedure TfrmViewer.btnGifToBmpClick(Sender: TObject);
 begin
 begin
-  GifAnim.Animate:=False;
-  Image.Picture.Bitmap.Create;
-  Image.Picture.Bitmap.Width := GifAnim.Width;
-  Image.Picture.Bitmap.Height := GifAnim.Height;
-  Image.Picture.Bitmap.Canvas.CopyRect(Rect(0,0,GifAnim.Width,GifAnim.Height),GifAnim.Canvas,Rect(0,0,GifAnim.Width,GifAnim.Height));
+  GifAnim.Pause;
+  btnGifMove.ImageIndex:= 12;
+  Image.Picture.Bitmap:= GifAnim.CurrentView;
   cm_SaveAs(['']);
   cm_SaveAs(['']);
+  UpdateAnimState;
 end;
 end;
 
 
 procedure TfrmViewer.btnPaintHightlight(Sender: TObject);
 procedure TfrmViewer.btnPaintHightlight(Sender: TObject);
@@ -2602,12 +2619,6 @@ begin
   btnPenMode.Down:= not btnPenMode.Down;
   btnPenMode.Down:= not btnPenMode.Down;
 end;
 end;
 
 
-procedure TfrmViewer.btnPrevGifFrameClick(Sender: TObject);
-begin
-  GifAnim.Animate:=False;
-  GifAnim.PriorFrame;
-end;
-
 procedure TfrmViewer.btnRedEyeClick(Sender: TObject);
 procedure TfrmViewer.btnRedEyeClick(Sender: TObject);
 begin
 begin
   RedEyes;
   RedEyes;
@@ -2829,23 +2840,42 @@ procedure TfrmViewer.AdjustImageSize;
 const
 const
   fmtImageInfo = '%dx%d (%.0f %%)';
   fmtImageInfo = '%dx%d (%.0f %%)';
 var
 var
+  AControl: TControl;
   dScaleFactor : Double;
   dScaleFactor : Double;
+  ImgWidth, ImgHeight : Integer;
   iLeft, iTop, iWidth, iHeight : Integer;
   iLeft, iTop, iWidth, iHeight : Integer;
 begin
 begin
-  if (Image.Picture = nil) then Exit;
-  if (Image.Picture.Width = 0) or (Image.Picture.Height = 0) then Exit;
+  if not (bImage or bAnimation) then
+    Exit;
+
+  if bImage then
+  begin
+    if (Image.Picture = nil) then Exit;
+    ImgHeight:= Image.Picture.Height;
+    ImgWidth:= Image.Picture.Width;
+    AControl:= Image;
+  end
+  else if (bAnimation) then
+  begin
+    if GifAnim.CurrentView = nil then Exit;
+    ImgHeight:= GifAnim.CurrentView.Height;
+    ImgWidth:= GifAnim.CurrentView.Width;
+    AControl:= GifAnim;
+  end;
+
+  if (ImgWidth = 0) or (ImgHeight = 0) then Exit;
 
 
   dScaleFactor:= FZoomFactor / 100;
   dScaleFactor:= FZoomFactor / 100;
 
 
   // Place and resize image
   // Place and resize image
   if (FZoomFactor = 100) and (miStretch.Checked or miStretchOnlyLarge.Checked) then
   if (FZoomFactor = 100) and (miStretch.Checked or miStretchOnlyLarge.Checked) then
   begin
   begin
-    dScaleFactor:= Min(sboxImage.ClientWidth / Image.Picture.Width ,sboxImage.ClientHeight / Image.Picture.Height);
+    dScaleFactor:= Min(sboxImage.ClientWidth / ImgWidth, sboxImage.ClientHeight / ImgHeight);
     dScaleFactor:= IfThen((miStretchOnlyLarge.Checked) and (dScaleFactor > 1.0), 1.0, dScaleFactor);
     dScaleFactor:= IfThen((miStretchOnlyLarge.Checked) and (dScaleFactor > 1.0), 1.0, dScaleFactor);
   end;
   end;
 
 
-  iWidth:= Trunc(Image.Picture.Width * dScaleFactor);
-  iHeight:= Trunc(Image.Picture.Height * dScaleFactor);
+  iWidth:= Trunc(ImgWidth * dScaleFactor);
+  iHeight:= Trunc(ImgHeight * dScaleFactor);
   if (miCenter.Checked) then
   if (miCenter.Checked) then
   begin
   begin
     iLeft:= (sboxImage.ClientWidth - iWidth) div 2;
     iLeft:= (sboxImage.ClientWidth - iWidth) div 2;
@@ -2856,7 +2886,7 @@ begin
     iLeft:= 0;
     iLeft:= 0;
     iTop:= 0;
     iTop:= 0;
   end;
   end;
-  Image.SetBounds(Max(iLeft,0), Max(iTop,0), iWidth , iHeight);
+  AControl.SetBounds(Max(iLeft,0), Max(iTop,0), iWidth , iHeight);
 
 
   // Update scrollbars
   // Update scrollbars
   // TODO: fix - calculations are correct but it seems like scroll bars
   // TODO: fix - calculations are correct but it seems like scroll bars
@@ -2870,8 +2900,8 @@ begin
   end;
   end;
 
 
   // Update status bar
   // Update status bar
-  Status.Panels[sbpCurrentResolution].Text:= Format(fmtImageInfo, [iWidth,iHeight,  100.0 * dScaleFactor]);
-  Status.Panels[sbpFullResolution].Text:= Format(fmtImageInfo, [Image.Picture.Width,Image.Picture.Height, 100.0]);
+  Status.Panels[sbpCurrentResolution].Text:= Format(fmtImageInfo, [iWidth, iHeight,  100.0 * dScaleFactor]);
+  Status.Panels[sbpFullResolution].Text:= Format(fmtImageInfo, [ImgWidth, ImgHeight, 100.0]);
 end;
 end;
 
 
 function TfrmViewer.GetListerRect: TRect;
 function TfrmViewer.GetListerRect: TRect;
@@ -2957,7 +2987,6 @@ function TfrmViewer.LoadGraphics(const sFileName:String): Boolean;
     btnHightlight.Enabled:= bImage and (not miFullScreen.Checked);
     btnHightlight.Enabled:= bImage and (not miFullScreen.Checked);
     btnPaint.Enabled:= bImage and (not miFullScreen.Checked);
     btnPaint.Enabled:= bImage and (not miFullScreen.Checked);
     btnResize.Enabled:= bImage and (not miFullScreen.Checked);
     btnResize.Enabled:= bImage and (not miFullScreen.Checked);
-    miImage.Visible:= bImage;
     btnZoomIn.Enabled:= bImage;
     btnZoomIn.Enabled:= bImage;
     btnZoomOut.Enabled:= bImage;
     btnZoomOut.Enabled:= bImage;
     btn270.Enabled:= bImage;
     btn270.Enabled:= bImage;
@@ -2973,23 +3002,13 @@ function TfrmViewer.LoadGraphics(const sFileName:String): Boolean;
 
 
 var
 var
   sExt: String;
   sExt: String;
-  fsFileHandle: System.THandle;
-  fsFileStream: TFileStreamEx = nil;
-  gifHeader: array[0..5] of AnsiChar;
+  fsFileStream: TFileStreamEx;
 begin
 begin
   Result:= True;
   Result:= True;
   FZoomFactor:= 100;
   FZoomFactor:= 100;
   sExt:= ExtractOnlyFileExt(sFilename);
   sExt:= ExtractOnlyFileExt(sFilename);
-  if SameText(sExt, 'gif') then
+  if not SameText(sExt, 'gif') then
   begin
   begin
-    fsFileHandle:= mbFileOpen(sFileName, fmOpenRead or fmShareDenyNone);
-    if (fsFileHandle = feInvalidHandle) then Exit(False);
-    FileRead(fsFileHandle, gifHeader, SizeOf(gifHeader));
-    FileClose(fsFileHandle);
-  end;
-  // GifAnim supports only GIF89a
-  if gifHeader <> 'GIF89a' then
-    begin
       Image.Visible:= True;
       Image.Visible:= True;
       GifAnim.Visible:= False;
       GifAnim.Visible:= False;
       try
       try
@@ -3008,6 +3027,8 @@ begin
             end;
             end;
           end;
           end;
 {$ENDIF}
 {$ENDIF}
+          bImage:= True;
+          bAnimation:= False;
           UpdateToolbar(True);
           UpdateToolbar(True);
         finally
         finally
           FreeAndNil(fsFileStream);
           FreeAndNil(fsFileStream);
@@ -3016,7 +3037,6 @@ begin
         begin
         begin
           if FExif.LoadFromFile(sFileName) then
           if FExif.LoadFromFile(sFileName) then
           begin
           begin
-            bImage:= True;
             case FExif.Orientation of
             case FExif.Orientation of
               2: cm_MirrorHorz([]);
               2: cm_MirrorHorz([]);
               3: cm_Rotate180([]);
               3: cm_Rotate180([]);
@@ -3040,8 +3060,18 @@ begin
       GifAnim.Visible:= True;
       GifAnim.Visible:= True;
       Image.Visible:= False;
       Image.Visible:= False;
       try
       try
-        GifAnim.FileName:= sFileName;
-        UpdateToolbar(False);
+        fsFileStream:= TFileStreamEx.Create(sFileName, fmOpenRead or fmShareDenyNone);
+        try
+          GifAnim.LoadFromStream(fsFileStream);
+          bImage:= False;
+          bAnimation:= True;
+          UpdateToolbar(False);
+          AdjustImageSize;
+          GifAnim.Start;
+          UpdateAnimState;
+        finally
+          fsFileStream.Free;
+        end;
       except
       except
         on E: Exception do
         on E: Exception do
         begin
         begin
@@ -3591,7 +3621,7 @@ begin
   miGraphics.Checked   := (Panel = pnlImage);
   miGraphics.Checked   := (Panel = pnlImage);
   miEncoding.Visible   := (Panel = pnlText) or (Panel = pnlCode) or (bPlugin and FWlxModule.CanCommand);
   miEncoding.Visible   := (Panel = pnlText) or (Panel = pnlCode) or (bPlugin and FWlxModule.CanCommand);
   miAutoReload.Visible := (Panel = pnlText);
   miAutoReload.Visible := (Panel = pnlText);
-  miImage.Visible      := (bImage or (bPlugin and FWlxModule.CanCommand));
+  miImage.Visible      := (bImage or bAnimation or (bPlugin and FWlxModule.CanCommand));
   miRotate.Visible     := bImage;
   miRotate.Visible     := bImage;
   miZoomIn.Visible     := bImage;
   miZoomIn.Visible     := bImage;
   miZoomOut.Visible    := bImage;
   miZoomOut.Visible    := bImage;
@@ -3968,7 +3998,7 @@ begin
       if not bAnimation then
       if not bAnimation then
         Clipboard.Assign(Image.Picture)
         Clipboard.Assign(Image.Picture)
       else
       else
-        Clipboard.Assign(GifAnim.GifBitmaps[GifAnim.GifIndex].Bitmap);
+        Clipboard.Assign(GifAnim.CurrentView);
     end else
     end else
        ViewerControl.CopyToClipboard;
        ViewerControl.CopyToClipboard;
   end;
   end;