Ignore:
Timestamp:
Apr 17, 2019, 12:58:41 AM (5 years ago)
Author:
chronos
Message:
  • Modified: Propagate project build mode options to used packages.
  • Added: Check memory leaks using heaptrc.
  • Modified: Update BGRABitmap package.
Location:
GraphicTest
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • GraphicTest

    • Property svn:ignore
      •  

        old new  
        88GraphicTest.lps
        99GraphicTest.dbg
         10heaptrclog.trc
  • GraphicTest/Packages/bgrabitmap/bgraanimatedgif.pas

    r494 r521  
    3939
    4040    procedure CheckFrameIndex(AIndex: integer);
     41    function GetAverageDelayMs: integer;
    4142    function GetCount: integer;
    4243    function GetFrameDelayMs(AIndex: integer): integer;
     
    8182    EraseColor:     TColor;
    8283    BackgroundMode: TGifBackgroundMode;
    83 
    84     constructor Create(filenameUTF8: string);
    85     constructor Create(stream: TStream);
    86     constructor Create; override;
     84    LoopCount:      Word;
     85    LoopDone:       Integer;
     86
     87    constructor Create(filenameUTF8: string); overload;
     88    constructor Create(stream: TStream); overload;
     89    constructor Create(stream: TStream; AMaxImageCount: integer); overload;
     90    constructor Create; overload; override;
    8791    function Duplicate: TBGRAAnimatedGif;
    8892    function AddFrame(AImage: TFPCustomImage; X,Y: integer; ADelayMs: integer;
    8993      ADisposeMode: TDisposeMode = dmErase; AHasLocalPalette: boolean = false) : integer;
    90     procedure InsertFrame(AIndex: integer; AImage: TBGRABitmap; X,Y: integer; ADelayMs: integer;
     94    procedure InsertFrame(AIndex: integer; AImage: TFPCustomImage; X,Y: integer; ADelayMs: integer;
    9195      ADisposeMode: TDisposeMode = dmErase; AHasLocalPalette: boolean = false);
     96    procedure DeleteFrame(AIndex: integer; AEnsureNextFrameDoesNotChange: boolean);
     97
     98    //add a frame that replaces completely the previous one
     99    function AddFullFrame(AImage: TFPCustomImage; ADelayMs: integer;
     100                          AHasLocalPalette: boolean = true): integer;
     101    procedure InsertFullFrame(AIndex: integer;
     102                              AImage: TFPCustomImage; ADelayMs: integer;
     103                              AHasLocalPalette: boolean = true);
     104    procedure ReplaceFullFrame(AIndex: integer;
     105                              AImage: TFPCustomImage; ADelayMs: integer;
     106                              AHasLocalPalette: boolean = true);
    92107
    93108    {TGraphic}
    94     procedure LoadFromStream(Stream: TStream); override;
    95     procedure SaveToStream(Stream: TStream); override;
     109    procedure LoadFromStream(Stream: TStream); overload; override;
     110    procedure LoadFromStream(Stream: TStream; AMaxImageCount: integer); overload;
     111    procedure LoadFromResource(AFilename: string);
     112    procedure SaveToStream(Stream: TStream); overload; override;
    96113    procedure LoadFromFile(const AFilenameUTF8: string); override;
    97114    procedure SaveToFile(const AFilenameUTF8: string); override;
     
    100117    procedure SetSize(AWidth,AHeight: integer); virtual;
    101118    procedure SaveToStream(Stream: TStream; AQuantizer: TBGRAColorQuantizerAny;
    102       ADitheringAlgorithm: TDitheringAlgorithm); virtual; overload;
     119      ADitheringAlgorithm: TDitheringAlgorithm); overload; virtual;
    103120    procedure Clear; override;
    104121    destructor Destroy; override;
     
    126143    property AspectRatio: single read FAspectRatio write SetAspectRatio;
    127144    property TotalAnimationTimeMs: Int64 read FTotalAnimationTime;
     145    property AverageDelayMs: integer read GetAverageDelayMs;
    128146  end;
    129147
     
    184202  data.BackgroundColor := BackgroundColor;
    185203  data.Images := FImages;
     204  data.LoopCount := LoopCount;
    186205  GIFSaveToStream(data, Stream, AQuantizer, ADitheringAlgorithm);
    187206end;
     
    233252      Inc(nextImage);
    234253      if nextImage >= Count then
    235         nextImage := 0;
     254      begin
     255        if (LoopCount > 0) and (LoopDone >= LoopCount-1) then
     256        begin
     257          LoopDone := LoopCount;
     258          dec(nextImage);
     259          break;
     260        end else
     261        begin
     262          nextImage := 0;
     263          inc(LoopDone);
     264        end;
     265      end;
    236266
    237267      if nextImage = previousImage then
    238268      begin
    239         Inc(nextImage);
    240         if nextImage >= Count then
    241           nextImage := 0;
     269        if not ((LoopCount > 0) and (LoopDone >= LoopCount-1)) then
     270        begin
     271          Inc(nextImage);
     272          if nextImage >= Count then
     273            nextImage := 0;
     274        end;
    242275        break;
    243276      end;
     
    370403end;
    371404
     405function TBGRAAnimatedGif.GetAverageDelayMs: integer;
     406var sum: int64;
     407  i: Integer;
     408begin
     409  if Count > 0 then
     410  begin
     411    sum := 0;
     412    for i := 0 to Count-1 do
     413      inc(sum, FrameDelayMs[i]);
     414    result := sum div Count;
     415  end else
     416    result := 100; //default
     417end;
     418
    372419function TBGRAAnimatedGif.GetCount: integer;
    373420begin
     
    437484end;
    438485
     486constructor TBGRAAnimatedGif.Create(stream: TStream; AMaxImageCount: integer);
     487begin
     488  inherited Create;
     489  Init;
     490  LoadFromStream(stream, AMaxImageCount);
     491end;
     492
    439493constructor TBGRAAnimatedGif.Create;
    440494begin
     
    478532end;
    479533
    480 procedure TBGRAAnimatedGif.InsertFrame(AIndex: integer; AImage: TBGRABitmap; X,
     534procedure TBGRAAnimatedGif.InsertFrame(AIndex: integer; AImage: TFPCustomImage; X,
    481535  Y: integer; ADelayMs: integer; ADisposeMode: TDisposeMode;
    482536  AHasLocalPalette: boolean);
     
    491545  with FImages[AIndex] do
    492546  begin
    493     Image := AImage.Duplicate as TBGRABitmap;
     547    Image := TBGRABitmap.Create(AImage);
    494548    Position := Point(x,y);
    495549    DelayMs := ADelayMs;
     
    500554end;
    501555
     556function TBGRAAnimatedGif.AddFullFrame(AImage: TFPCustomImage;
     557  ADelayMs: integer; AHasLocalPalette: boolean): integer;
     558begin
     559  if (AImage.Width <> Width) or (AImage.Height <> Height) then
     560    raise exception.Create('Size mismatch');
     561  if Count > 0 then
     562    FrameDisposeMode[Count-1] := dmErase;
     563  result := AddFrame(AImage, 0,0, ADelayMs, dmErase, AHasLocalPalette);
     564end;
     565
     566procedure TBGRAAnimatedGif.InsertFullFrame(AIndex: integer;
     567  AImage: TFPCustomImage; ADelayMs: integer; AHasLocalPalette: boolean);
     568var nextImage: TBGRABitmap;
     569begin
     570  if (AIndex < 0) or (AIndex > Count) then
     571    raise ERangeError.Create('Index out of bounds');
     572
     573  if AIndex = Count then
     574    AddFullFrame(AImage, ADelayMs, AHasLocalPalette)
     575  else
     576  begin
     577    //if previous image did not clear up, ensure that
     578    //next image will stay the same
     579    if (AIndex > 0) and (FrameDisposeMode[AIndex-1] <> dmErase) then
     580    begin
     581      CurrentImage := AIndex;
     582      nextImage := MemBitmap.Duplicate as TBGRABitmap;
     583      FrameImagePos[AIndex] := Point(0,0);
     584      FrameImage[AIndex] := nextImage;
     585      FrameHasLocalPalette[AIndex] := true;
     586      FreeAndNil(nextImage);
     587
     588      FrameDisposeMode[AIndex-1] := dmErase;
     589    end;
     590
     591    InsertFrame(AIndex, AImage, 0,0, ADelayMs, dmErase, AHasLocalPalette);
     592  end;
     593end;
     594
     595procedure TBGRAAnimatedGif.ReplaceFullFrame(AIndex: integer;
     596  AImage: TFPCustomImage; ADelayMs: integer; AHasLocalPalette: boolean);
     597begin
     598  DeleteFrame(AIndex, True);
     599  if AIndex > 0 then FrameDisposeMode[AIndex-1] := dmErase;
     600  InsertFrame(AIndex, AImage, 0,0, ADelayMs, dmErase, AHasLocalPalette);
     601end;
     602
     603procedure TBGRAAnimatedGif.DeleteFrame(AIndex: integer;
     604  AEnsureNextFrameDoesNotChange: boolean);
     605var
     606  nextImage: TBGRABitmap;
     607  i: Integer;
     608begin
     609  CheckFrameIndex(AIndex);
     610
     611  //if this frame did not clear up, ensure that
     612  //next image will stay the same
     613  if AEnsureNextFrameDoesNotChange and
     614    ((AIndex < Count-1) and (FrameDisposeMode[AIndex] <> dmErase)) then
     615  begin
     616    CurrentImage := AIndex+1;
     617    nextImage := MemBitmap.Duplicate as TBGRABitmap;
     618    FrameImagePos[AIndex+1] := Point(0,0);
     619    FrameImage[AIndex+1] := nextImage;
     620    FrameHasLocalPalette[AIndex+1] := true;
     621    FreeAndNil(nextImage);
     622  end;
     623
     624  dec(FTotalAnimationTime, FImages[AIndex].DelayMs);
     625
     626  FImages[AIndex].Image.FreeReference;
     627  for i := AIndex to Count-2 do
     628    FImages[i] := FImages[i+1];
     629  SetLength(FImages, Count-1);
     630
     631  if (CurrentImage >= Count) then
     632    CurrentImage := 0;
     633end;
     634
    502635procedure TBGRAAnimatedGif.LoadFromStream(Stream: TStream);
     636begin
     637  LoadFromStream(Stream, maxLongint);
     638end;
     639
     640procedure TBGRAAnimatedGif.LoadFromStream(Stream: TStream;
     641  AMaxImageCount: integer);
    503642var data: TGIFData;
    504643  i: integer;
    505644begin
    506   data := GIFLoadFromStream(Stream);
     645  data := GIFLoadFromStream(Stream, AMaxImageCount);
    507646
    508647  ClearViewer;
     
    512651  FBackgroundColor := data.BackgroundColor;
    513652  FAspectRatio:= data.AspectRatio;
     653  LoopDone := 0;
     654  LoopCount := data.LoopCount;
    514655
    515656  SetLength(FImages, length(data.Images));
     
    519660    FImages[i] := data.Images[i];
    520661    FTotalAnimationTime += FImages[i].DelayMs;
     662  end;
     663end;
     664
     665procedure TBGRAAnimatedGif.LoadFromResource(AFilename: string);
     666var
     667  stream: TStream;
     668begin
     669  stream := BGRAResource.GetResourceStream(AFilename);
     670  try
     671    LoadFromStream(stream);
     672  finally
     673    stream.Free;
    521674  end;
    522675end;
     
    658811    FImages[i].Image.FreeReference;
    659812  FImages := nil;
     813  LoopDone := 0;
     814  LoopCount := 0;
    660815end;
    661816
     
    9591114begin
    9601115  BackgroundMode := gbmSaveBackgroundOnce;
     1116  LoopCount := 0;
     1117  LoopDone := 0;
    9611118end;
    9621119
     
    9811138  Mem:  TBGRABitmap;
    9821139begin
    983   gif := TBGRAAnimatedGif.Create(Str);
     1140  gif := TBGRAAnimatedGif.Create(Str, 1);
    9841141  Mem := gif.MemBitmap;
    9851142  if Img is TBGRABitmap then
Note: See TracChangeset for help on using the changeset viewer.