Bläddra i källkod

FlashProgress Changed Bar Animation; ImageManipulation Added Load/Save and their events.

FlashProgress Changed Bar Animation;
ImageManipulation Added Load/Save and their events.
Massimo Magnano 11 månader sedan
förälder
incheckning
d586f4f7cc

+ 72 - 39
bgraflashprogressbar.pas

@@ -29,6 +29,8 @@ unit BGRAFlashProgressBar;
 
 interface
 
+//{$define TESTS}
+
 uses
   Classes, {$IFDEF BGRABITMAP_USE_MSEGUI} mclasses, {$ENDIF}
   SysUtils, Types, Forms, Controls, Graphics,
@@ -138,6 +140,7 @@ type
     marqueeBouncing: Boolean;
     marqueeCurMode: TBGRAPBarMarqueeDirection;
     internalTimer: TFPTimer;
+    closing: Boolean;
     GraphValues: TGraphValues;  //array of Real Graph Values
     GraphPoints: array of TPointF; //array of Calculated xpos and ypos
 
@@ -151,6 +154,11 @@ type
     procedure TimerOnTimer(Sender: TObject);
 
   public
+    {$ifdef TESTS}
+    p1, p2:TPointF;
+    pT: TGradientType;
+    {$endif}
+
     constructor Create(AOwner: TComponent); override;
     destructor Destroy; override;
 
@@ -248,6 +256,14 @@ implementation
 
 uses DateUtils, BGRATextFX;
 
+const
+  BAR_ANIM_TIMER = 20;
+  BAR_ANIM_INC = 4;
+  MARQUEE_TIMER_SLOW = 50;
+  MARQUEE_TIMER_MED  = 20;
+  MARQUEE_TIMER_FAST = 10;
+  MARQUEE_INC = 2;
+
 {$IFDEF FPC}
 procedure Register;
 begin
@@ -410,8 +426,8 @@ begin
      not(csLoading in ComponentState) and
      not(csDesigning in ComponentState) then
   begin
-    barAnimLeft:= 2;
-    if FShowBarAnimation then internalTimer.Interval:= 20;
+    barAnimLeft:= 0;
+    if FShowBarAnimation then internalTimer.Interval:= BAR_ANIM_TIMER;
     internalTimer.Enabled:= FShowBarAnimation;
   end;
 
@@ -454,9 +470,9 @@ procedure TBGRAFlashProgressBar.SetMarqueeSpeed(AValue: TBGRAPBarMarqueeSpeed);
 begin
   FMarqueeSpeed:=AValue;
   case FMarqueeSpeed of
-  pbmsSlow: internalTimer.Interval:= 50;
-  pbmsMedium: internalTimer.Interval:= 20;
-  pbmsFast: internalTimer.Interval:= 10;
+  pbmsSlow: internalTimer.Interval:= MARQUEE_TIMER_SLOW;
+  pbmsMedium: internalTimer.Interval:= MARQUEE_TIMER_MED;
+  pbmsFast: internalTimer.Interval:= MARQUEE_TIMER_FAST;
   end;
 end;
 
@@ -539,7 +555,8 @@ begin
            not(csLoading in ComponentState) and
            not(csDesigning in ComponentState)
         then begin
-               internalTimer.Interval:= 20;
+               barAnimLeft:= 0;
+               internalTimer.Interval:= BAR_ANIM_TIMER;
                internalTimer.Enabled:= True;
              end
         else internalTimer.Enabled:= False;
@@ -571,7 +588,7 @@ begin
            not(csLoading in ComponentState) and
            not(csDesigning in ComponentState)
         then begin
-               internalTimer.Interval:= 20;
+               internalTimer.Interval:= BAR_ANIM_TIMER;
                internalTimer.Enabled:= True;
              end
         else internalTimer.Enabled:= False;
@@ -608,15 +625,17 @@ end;
 
 procedure TBGRAFlashProgressBar.TimerOnTimer(Sender: TObject);
 begin
+  try
+  if closing then exit;
+
   Case FStyle of
     pbstNormal,
     pbstMultiProgress,
     pbstGraph: if FShowBarAnimation then begin
-      if (xpos > 8) then
-      begin
-        inc(barAnimLeft, 2);
-        if (barAnimLeft+4 > xpos) then barAnimLeft:= -6; //Wait 3 times after reached the end
-      end;
+        inc(barAnimLeft, BAR_ANIM_INC);
+
+        //Wait 16 times after reached the end
+        if (barAnimLeft+18 > xpos) then barAnimLeft:= -16*BAR_ANIM_INC;
     end;
     pbstMarquee: begin
       if (FMarqueeBounce > 0) then
@@ -648,8 +667,8 @@ begin
 
       //Move the bar 2 pixels
       if (marqueeCurMode = pbmdToRight)
-      then inc(marqueeLeft, 2)
-      else dec(marqueeLeft, 2);
+      then inc(marqueeLeft, MARQUEE_INC)
+      else dec(marqueeLeft, MARQUEE_INC);
     end;
     pbstTimer: begin
       { #note -oMaxM : If we had to be more precise we should keep the Start time and subtract the current time }
@@ -666,6 +685,10 @@ begin
   end;
 
   Invalidate;
+
+  except
+    //MaxM: Ignore Exception sometimes it happens when we are closing
+  end;
 end;
 
 {$hints off}
@@ -706,7 +729,7 @@ begin
     pbstNormal,
     pbstMultiProgress,
     pbstGraph: begin
-      if FShowBarAnimation then internalTimer.Interval:= 20;
+      if FShowBarAnimation then internalTimer.Interval:= BAR_ANIM_TIMER;
       internalTimer.Enabled:= FShowBarAnimation;
     end;
     pbstMarquee: begin
@@ -775,7 +798,7 @@ begin
   FShowDividers:= False;
   FGraphShowYDividers:= False;
   FShowBarAnimation:= False;
-  barAnimLeft:= 2;
+  barAnimLeft:= 0;
 
   //Marquee
   FMarqueeWidth:= 0; //AutoWidth
@@ -805,17 +828,19 @@ begin
 
   internalTimer:= TFPTimer.Create(Self);
   internalTimer.Enabled:= False;
-  internalTimer.Interval:= 20;
+  internalTimer.Interval:= MARQUEE_TIMER_MED;
   internalTimer.OnTimer:= TimerOnTimer;
+  closing:= False;
 end;
 
 destructor TBGRAFlashProgressBar.Destroy;
 begin
   //Avoid Exception when internalTimer is Enabled
+  closing:= True;
   internalTimer.Enabled:=False;
-  CheckSynchronize(100);
+  CheckSynchronize(40);
 
-  FreeAndNil(internalTimer);
+  internalTimer.Free;
   GraphValues:= nil;
   GraphPoints:= nil;
   FBGRA.Free;
@@ -891,6 +916,22 @@ var
       gdVertical, gdVertical, gdVertical, 0.53);
   end;
 
+  procedure DrawBarAnimation;
+  begin
+    {$ifdef TESTS}
+      ABitmap.GradientFill(4, content.Top, 4+36, content.Bottom,
+                           BGRA(255, 255, 255, 64), BGRA(255, 255, 255, 2), pT,
+                           p1, p2,
+                           dmLinearBlend);
+    {$else}
+    if FShowBarAnimation and (barAnimLeft >= 0)
+    then ABitmap.GradientFill(barAnimLeft, content.Top, barAnimLeft+36, content.Bottom,
+                              BGRA(255, 255, 255, 64), BGRA(255, 255, 255, 2), gtReflected,
+                              PointF(barAnimLeft+18, content.Bottom-content.Top/2), PointF(barAnimLeft+36, content.Bottom-content.Top/2),
+                              dmLinearBlend);
+    {$endif}
+  end;
+
   procedure DrawText(ACaption: String; AAlign: TAlignment);
   var
      fx: TBGRATextEffect;
@@ -1007,11 +1048,7 @@ var
       end;
     end;
 
-    if FShowBarAnimation and (barAnimLeft > 0)
-    then ABitmap.GradientFill(barAnimLeft, content.Top, barAnimLeft+4, content.Bottom,
-                              BGRA(255, 255, 255, 4), BGRA(255, 255, 255, 16), gtLinear,
-                              PointF(barAnimLeft, content.Bottom-content.Top/2), PointF(barAnimLeft+4, content.Bottom-content.Top/2),
-                              dmLinearBlend);
+    DrawBarAnimation; { #note -oMaxM : Evaluate how it seems }
 
     //Draw Value Text
     pStr:= '';
@@ -1024,6 +1061,7 @@ var
  end;
 
 begin
+  try
   ABitmap.FillTransparent;
   tx := ABitmap.Width;
   ty := ABitmap.Height;
@@ -1065,11 +1103,7 @@ begin
 
             if FShowDividers then DrawDividers(False);
 
-            if FShowBarAnimation and (barAnimLeft > 0)
-            then ABitmap.GradientFill(barAnimLeft, content.Top, barAnimLeft+4, content.Bottom,
-                                      BGRA(255, 255, 255, 4), BGRA(255, 255, 255, 16), gtLinear,
-                                      PointF(barAnimLeft, content.Bottom-content.Top/2), PointF(barAnimLeft+4, content.Bottom-content.Top/2),
-                                      dmLinearBlend);
+            DrawBarAnimation;
 
             //Draw Value Text
             pStr:= '';
@@ -1114,11 +1148,7 @@ begin
 
           if FShowDividers then DrawDividers(False);
 
-          if FShowBarAnimation and (barAnimLeft > 0)
-          then ABitmap.GradientFill(barAnimLeft, content.Top, barAnimLeft+4, content.Bottom,
-                                    BGRA(255, 255, 255, 4), BGRA(255, 255, 255, 16), gtLinear,
-                                    PointF(barAnimLeft, content.Bottom-content.Top/2), PointF(barAnimLeft+4, content.Bottom-content.Top/2),
-                                    dmLinearBlend);
+          DrawBarAnimation;
 
          //Draw Value Text
           pStr:= '';
@@ -1144,7 +1174,8 @@ begin
         if (marqueeCurMode = pbmdToRight)
         then begin
                //check if the whole bar is out put it back to the beginning
-               if (marqueeLeft >= content.Right) then marqueeLeft:= content.Left;
+               if (marqueeLeft >= content.Right)
+               then marqueeLeft:= content.Left;
 
                //Calculate the Right
                marqueeRight:= marqueeLeft+(rMarqueeWidth-1);
@@ -1166,10 +1197,8 @@ begin
              end
         else begin
                //check if the whole bar is out put it back to the end
-               if (marqueeLeft <= -rMarqueeWidth) then //(rMarqueeWidth+2)) then
-               begin
-                 marqueeLeft:= content.Right-rMarqueeWidth;
-               end;
+               if (marqueeLeft <= -rMarqueeWidth)
+               then marqueeLeft:= content.Right-rMarqueeWidth;
 
                //Calculate the Right
                marqueeRight:= marqueeLeft+(rMarqueeWidth-1);
@@ -1241,6 +1270,10 @@ begin
       pbstGraph: DrawG;
       end;
   end;
+
+  except
+    //MaxM: Ignore Exception sometimes it happens when the timer is active and we are closing
+  end;
 end;
 
 procedure TBGRAFlashProgressBar.SetValue(AValue: Double);

+ 208 - 2
bgraimagemanipulation.pas

@@ -81,6 +81,7 @@ unit BGRAImageManipulation;
       -08    - Removed EmptyImage.Allow, so is always allowed
                CopyPropertiesToArea and Icons in NewCropAreaDefault
                Updated Component icon
+  2025-01    - Added Load/Save and their events
   ============================================================================
 }
 
@@ -353,6 +354,19 @@ type
   TBGRAIMContextPopupEvent = procedure(Sender: TBGRAImageManipulation; CropArea: TCropArea;
                                        AnchorSelected :TDirection; MousePos: TPoint; var Handled: Boolean) of object;
 
+  TBGRAIMBitmapLoadBefore = procedure (Sender: TBGRAImageManipulation; AStream: TStream;
+                                 AFormat: TBGRAImageFormat; AHandler: TFPCustomImageReader;
+                                 var AOptions: TBGRALoadingOptions) of object;
+
+  TBGRAIMBitmapLoadAfter = procedure (Sender: TBGRAImageManipulation; AStream: TStream;
+                                 AFormat: TBGRAImageFormat; AHandler: TFPCustomImageReader;
+                                 AOptions: TBGRALoadingOptions) of object;
+
+  TBGRAIMBitmapSaveBefore = procedure (Sender: TBGRAImageManipulation; AStream: TStream;
+                                 AFormat: TBGRAImageFormat; AHandler: TFPCustomImageWriter) of object;
+
+  TBGRAIMBitmapSaveAfter = procedure (Sender: TBGRAImageManipulation; AStream: TStream;
+                                 AFormat: TBGRAImageFormat; AHandler: TFPCustomImageWriter) of object;
 
   TBGRAImageManipulation = class(TBGRAGraphicCtrl)
   private
@@ -374,7 +388,8 @@ type
     fSizeLimits: TSizeLimits;
     fImageBitmap, fResampledBitmap, fBackground, fVirtualScreen: TBGRABitmap;
     rNewCropAreaDefault: TBGRANewCropAreaDefault;
-    rOnContextPopup: TBGRAIMContextPopupEvent;
+    rOnBitmapSaveAfter: TBGRAIMBitmapSaveAfter;
+    rOnBitmapSaveBefore: TBGRAIMBitmapSaveBefore;
 
     function getAnchorSize: byte;
     function getPixelsPerInch: Integer;
@@ -400,6 +415,9 @@ type
     rOnSelectedCropAreaChanged: TCropAreaEvent;
     rOnCropAreaLoad: TCropAreaLoadEvent;
     rOnCropAreaSave: TCropAreaSaveEvent;
+    rOnBitmapLoadBefore: TBGRAIMBitmapLoadBefore;
+    rOnBitmapLoadAfter: TBGRAIMBitmapLoadAfter;
+    rOnContextPopup: TBGRAIMContextPopupEvent;
     rEmptyImage: TBGRAEmptyImage;
     rLoading: Boolean;
     rOpacity: Byte;
@@ -454,6 +472,19 @@ type
     procedure SetEmptyImageSizeToNull;
     procedure SetEmptyImageSize(AResolutionUnit: TResolutionUnit; AResolutionWidth, AResolutionHeight: Single);
 
+    procedure LoadFromFile(const AFilename: String); overload;
+    procedure LoadFromFile(const AFilename: String; AHandler:TFPCustomImageReader; AOptions: TBGRALoadingOptions); overload;
+    procedure LoadFromFileUTF8(const AFilenameUTF8: String); overload;
+    procedure LoadFromFileUTF8(const AFilenameUTF8: String; AHandler:TFPCustomImageReader; AOptions: TBGRALoadingOptions); overload;
+    procedure LoadFromStream(AStream: TStream); overload;
+    procedure LoadFromStream(AStream: TStream; AHandler:TFPCustomImageReader; AOptions: TBGRALoadingOptions); overload;
+
+    procedure SaveToFile(const AFilename: String); overload;
+    procedure SaveToFile(const AFilename: String; AFormat: TBGRAImageFormat; AHandler:TFPCustomImageWriter); overload;
+    procedure SaveToFileUTF8(const AFilenameUTF8: String); overload;
+    procedure SaveToFileUTF8(const AFilenameUTF8: String; AFormat: TBGRAImageFormat; AHandler:TFPCustomImageWriter); overload;
+    procedure SaveToStream(AStream: TStream; AFormat: TBGRAImageFormat; AHandler:TFPCustomImageWriter=nil); overload;
+
     property SelectedCropArea :TCropArea read rSelectedCropArea write setSelectedCropArea;
     property CropAreas :TCropAreaList read rCropAreas;
     property PixelsPerInch: Integer read getPixelsPerInch;
@@ -490,6 +521,11 @@ type
     property OnDragDrop: TDragDropEvent;
     property OnDragOver: TDragOverEvent;
     property OnEndDrag: TEndDragEvent;*)
+
+    property OnBitmapLoadBefore: TBGRAIMBitmapLoadBefore read rOnBitmapLoadBefore write rOnBitmapLoadBefore;
+    property OnBitmapLoadAfter: TBGRAIMBitmapLoadAfter read rOnBitmapLoadAfter write rOnBitmapLoadAfter;
+    property OnBitmapSaveBefore: TBGRAIMBitmapSaveBefore read rOnBitmapSaveBefore write rOnBitmapSaveBefore;
+    property OnBitmapSaveAfter: TBGRAIMBitmapSaveAfter read rOnBitmapSaveAfter write rOnBitmapSaveAfter;
   end;
 
 
@@ -501,7 +537,7 @@ procedure PixelXResolutionUnitConvert(var resX, resY:Single; fromRes, toRes:TRes
 
 implementation
 
-uses Math, ExtCtrls;
+uses Math, ExtCtrls, BGRAUTF8, UniversalDrawer, BGRAWritePNG, FPWritePNM;
 
 resourcestring
   SAnchorSizeIsTooLarge =
@@ -3498,6 +3534,176 @@ begin
   Resize;
 end;
 
+procedure TBGRAImageManipulation.LoadFromFile(const AFilename: String);
+begin
+  LoadFromFileUTF8(SysToUtf8(AFilename));
+end;
+
+procedure TBGRAImageManipulation.LoadFromFile(const AFilename: String; AHandler: TFPCustomImageReader;
+  AOptions: TBGRALoadingOptions);
+begin
+  LoadFromFileUTF8(SysToUtf8(AFilename), AHandler, AOptions);
+end;
+
+procedure TBGRAImageManipulation.LoadFromFileUTF8(const AFilenameUTF8: String);
+var
+  AStream: TStream;
+  AFormat: TBGRAImageFormat;
+  AHandler: TFPCustomImageReader;
+  AOptions: TBGRALoadingOptions;
+
+begin
+  try
+     AStream:= TFileStreamUTF8.Create(AFilenameUTF8, fmOpenRead or fmShareDenyWrite);
+     AFormat:= DetectFileFormat(AStream, ExtractFileExt(AFilenameUTF8));
+     AHandler:= CreateBGRAImageReader(AFormat);
+     AOptions:= [loKeepTransparentRGB];
+
+     if Assigned(rOnBitmapLoadBefore) then rOnBitmapLoadBefore(Self, AStream, AFormat, AHandler, AOptions);
+
+     fImageBitmap.LoadFromStream(AStream, AHandler, AOptions);
+
+     if Assigned(rOnBitmapLoadAfter) then rOnBitmapLoadAfter(Self, AStream, AFormat, AHandler, AOptions);
+
+  finally
+    AHandler.Free;
+    AStream.Free;
+  end;
+end;
+
+procedure TBGRAImageManipulation.LoadFromFileUTF8(const AFilenameUTF8: String; AHandler: TFPCustomImageReader;
+  AOptions: TBGRALoadingOptions);
+var
+  AStream: TStream;
+
+begin
+  try
+     AStream:= TFileStreamUTF8.Create(AFilenameUTF8, fmOpenRead or fmShareDenyWrite);
+     LoadFromStream(AStream, AHandler, AOptions);
+
+  finally
+    AStream.Free;
+  end;
+end;
+
+procedure TBGRAImageManipulation.LoadFromStream(AStream: TStream);
+var
+  AFormat: TBGRAImageFormat;
+  AHandler: TFPCustomImageReader;
+  AOptions: TBGRALoadingOptions;
+
+begin
+  try
+    AFormat:= DetectFileFormat(AStream);
+    AHandler:= CreateBGRAImageReader(AFormat);
+    AOptions:= [loKeepTransparentRGB];
+    LoadFromStream(AStream, AHandler, AOptions);
+
+  finally
+    AHandler.Free;
+  end;
+end;
+
+procedure TBGRAImageManipulation.LoadFromStream(AStream: TStream;
+                  AHandler: TFPCustomImageReader; AOptions: TBGRALoadingOptions);
+var
+  AFormat: TBGRAImageFormat;
+
+begin
+  AFormat:= DetectFileFormat(AStream);
+
+  if Assigned(rOnBitmapLoadBefore) then rOnBitmapLoadBefore(Self, AStream, AFormat, AHandler, AOptions);
+
+  fImageBitmap.LoadFromStream(AStream, AHandler, AOptions);
+
+  if Assigned(rOnBitmapLoadAfter) then rOnBitmapLoadAfter(Self, AStream, AFormat, AHandler, AOptions);
+end;
+
+procedure TBGRAImageManipulation.SaveToFile(const AFilename: String);
+begin
+  SaveToFileUTF8(SysToUtf8(AFilename));
+end;
+
+procedure TBGRAImageManipulation.SaveToFile(const AFilename: String; AFormat: TBGRAImageFormat;
+  AHandler: TFPCustomImageWriter);
+begin
+  SaveToFileUTF8(SysToUtf8(AFilename), AFormat, AHandler);
+end;
+
+procedure TBGRAImageManipulation.SaveToFileUTF8(const AFilenameUTF8: String);
+var
+  writer: TFPCustomImageWriter;
+  format: TBGRAImageFormat;
+  ext: String;
+
+begin
+  format := SuggestImageFormat(AFilenameUTF8);
+  if (format = ifXPixMap) and (fImageBitmap.NbPixels > 32768) then //xpm is slow so avoid big images
+    raise exception.Create('Image is too big to be saved as XPM');
+  writer := CreateBGRAImageWriter(Format, fImageBitmap.HasTransparentPixels);
+  if writer is TBGRAWriterPNG then
+  begin
+    if TUniversalDrawer.GetMaxColorChannelDepth(fImageBitmap) > 8 then TBGRAWriterPNG(writer).WordSized := true;
+  end;
+  if writer is TFPWriterPNM then
+  begin
+    ext := LowerCase(ExtractFileExt(AFilenameUTF8));
+    if ext = '.pbm' then TFPWriterPNM(writer).ColorDepth:= pcdBlackWhite else
+    if ext = '.pgm' then TFPWriterPNM(writer).ColorDepth:= pcdGrayscale else
+    if ext = '.ppm' then TFPWriterPNM(writer).ColorDepth:= pcdRGB;
+  end;
+  try
+    SaveToFileUTF8(AFilenameUTF8, format, writer);
+  finally
+    writer.free;
+  end;
+end;
+
+procedure TBGRAImageManipulation.SaveToFileUTF8(const AFilenameUTF8: String; AFormat: TBGRAImageFormat;
+  AHandler: TFPCustomImageWriter);
+var
+  AStream: TStream;
+
+begin
+  try
+     AStream:= TFileStreamUTF8.Create(AFilenameUTF8, fmCreate);
+     SaveToStream(AStream, AFormat, AHandler);
+
+  finally
+    AStream.Free;
+  end;
+end;
+
+procedure TBGRAImageManipulation.SaveToStream(AStream: TStream; AFormat: TBGRAImageFormat;
+  AHandler: TFPCustomImageWriter);
+var
+  HandlerNil: Boolean;
+
+begin
+  HandlerNil:= (AHandler = nil);
+
+  if HandlerNil then
+  begin
+    if (AFormat = ifXPixMap) and (fImageBitmap.NbPixels > 32768) then //xpm is slow so avoid big images
+      raise exception.Create('Image is too big to be saved as XPM');
+    AHandler := CreateBGRAImageWriter(AFormat, fImageBitmap.HasTransparentPixels);
+    if AHandler is TBGRAWriterPNG then
+    begin
+      if TUniversalDrawer.GetMaxColorChannelDepth(fImageBitmap) > 8 then TBGRAWriterPNG(AHandler).WordSized := true;
+    end;
+  end;
+  try
+     if Assigned(rOnBitmapSaveBefore) then rOnBitmapSaveBefore(Self, AStream, AFormat, AHandler);
+
+     TFPCustomImage(fImageBitmap).SaveToStream(AStream, AHandler);
+
+     if Assigned(rOnBitmapSaveAfter) then rOnBitmapSaveAfter(Self, AStream, AFormat, AHandler);
+
+  finally
+    if HandlerNil then AHandler.Free;
+  end;
+end;
+
 procedure TBGRAImageManipulation.setBorderSize(const Value: byte);
 const
   MinSize = 2;

+ 1 - 1
test/test_bgraimagemanipulation/unitbgraimagemanipulationdemo.lfm

@@ -7,7 +7,7 @@ object FormBGRAImageManipulationDemo: TFormBGRAImageManipulationDemo
   ClientHeight = 543
   ClientWidth = 926
   ShowHint = True
-  LCLVersion = '3.99.0.0'
+  LCLVersion = '4.99.0.0'
   OnCloseQuery = FormCloseQuery
   OnCreate = FormCreate
   object Background: TBCPanel

+ 3 - 1
test/test_bgraimagemanipulation/unitbgraimagemanipulationdemo.pas

@@ -214,12 +214,14 @@ begin
   // picture dialog to locate an image...
   if OpenPictureDialog.Execute then
   begin
-    // ...and create a new TBGRABitmap and load to it
+(*    // ...and create a new TBGRABitmap and load to it
     Bitmap := TBGRABitmap.Create;
     Bitmap.LoadFromFile(OpenPictureDialog.FileName);
     // Finally, associate the image into component
     BGRAImageManipulation.Bitmap := Bitmap;
     Bitmap.Free;
+*)
+    BGRAImageManipulation.LoadFromFile(OpenPictureDialog.FileName);
 
     lbResolution.Caption:='Resolution : '+#13#10+'  '+
           FloatToStrF(BGRAImageManipulation.Bitmap.ResolutionX, ffFixed, 15, 3)+' x '+

+ 58 - 0
test/test_progressbar/umain.lfm

@@ -6,6 +6,7 @@ object Form1: TForm1
   Caption = 'Form1'
   ClientHeight = 452
   ClientWidth = 523
+  LCLVersion = '4.99.0.0'
   OnClose = FormClose
   OnCreate = FormCreate
   OnShow = FormShow
@@ -214,6 +215,63 @@ object Form1: TForm1
         Value = 30
         OnChange = edValueChange
       end
+      object p1x: TSpinEdit
+        Left = 178
+        Height = 23
+        Top = 26
+        Width = 50
+        MaxValue = 400
+        TabOrder = 3
+        Value = 22
+        OnChange = p1xChange
+      end
+      object p2x: TSpinEdit
+        Left = 241
+        Height = 23
+        Top = 26
+        Width = 50
+        MaxValue = 400
+        TabOrder = 4
+        Value = 40
+        OnChange = p1xChange
+      end
+      object p1y: TSpinEdit
+        Left = 178
+        Height = 23
+        Top = 56
+        Width = 50
+        MaxValue = 400
+        TabOrder = 5
+        Value = 17
+        OnChange = p1xChange
+      end
+      object p2y: TSpinEdit
+        Left = 242
+        Height = 23
+        Top = 55
+        Width = 50
+        MaxValue = 400
+        TabOrder = 6
+        Value = 17
+        OnChange = p1xChange
+      end
+      object pType: TSpinEdit
+        Left = 216
+        Height = 23
+        Top = 82
+        Width = 50
+        MaxValue = 4
+        TabOrder = 7
+        Value = 1
+        OnChange = p1xChange
+      end
+      object Label23: TLabel
+        Left = 178
+        Height = 15
+        Top = 8
+        Width = 71
+        Caption = 'Internal Tests:'
+      end
     end
     object TabMultiProgress: TTabSheet
       Tag = 1

+ 23 - 1
test/test_progressbar/umain.pas

@@ -4,6 +4,8 @@ unit umain;
 
 interface
 
+//{$define TESTS}
+
 uses
   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ComCtrls, ExtCtrls, StdCtrls, Spin, EditBtn,
   ColorBox, BGRAFlashProgressBar, BCTrackbarUpdown, BGRASpeedButton, ColorSpeedButton, BGRABitmap, BGRABitmapTypes;
@@ -73,6 +75,7 @@ type
     Label20: TLabel;
     Label21: TLabel;
     Label22: TLabel;
+    Label23: TLabel;
     Label3: TLabel;
     Label4: TLabel;
     Label5: TLabel;
@@ -87,6 +90,11 @@ type
     rgCaptionAlignM: TRadioGroup;
     rgMarqueeDirection: TRadioGroup;
     rgMarqueeSpeed: TRadioGroup;
+    p1x: TSpinEdit;
+    p2x: TSpinEdit;
+    p1y: TSpinEdit;
+    p2y: TSpinEdit;
+    pType: TSpinEdit;
     TabNormal: TTabSheet;
     TabMarquee: TTabSheet;
     TabMultiProgress: TTabSheet;
@@ -127,6 +135,7 @@ type
     procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
     procedure FormCreate(Sender: TObject);
     procedure FormShow(Sender: TObject);
+    procedure p1xChange(Sender: TObject);
     procedure PageControl1Change(Sender: TObject);
     procedure rgCaptionAlignClick(Sender: TObject);
     procedure rgCaptionAlignMClick(Sender: TObject);
@@ -318,6 +327,9 @@ end;
 procedure TForm1.FormCreate(Sender: TObject);
 begin
   Closing:= False;
+  {$ifdef TESTS}
+  p1xChange(nil);
+  {$endif}
 end;
 
 procedure TForm1.FormShow(Sender: TObject);
@@ -325,6 +337,16 @@ begin
   PageControl1.ActivePage:= TabNormal;
 end;
 
+procedure TForm1.p1xChange(Sender: TObject);
+begin
+  {$ifdef TESTS}
+  BGRAMaxMProgress.pT:= TGradientType(pType.Value);
+  BGRAMaxMProgress.p1:=PointF(p1x.Value, p1y.Value);
+  BGRAMaxMProgress.p2:=PointF(p2x.Value, p2y.Value);
+  BGRAMaxMProgress.Invalidate;
+  {$endif}
+end;
+
 procedure TForm1.PageControl1Change(Sender: TObject);
 begin
   if (PageControl1.ActivePage.Tag = 4)
@@ -409,7 +431,7 @@ begin
   YVal:= 50;
   Randomize;
   i:= BGRAMaxMProgress.MinValue;
-  while (i <= BGRAMaxMProgress.MaxValue) do
+  while (i < BGRAMaxMProgress.MaxValue) do
   begin
     i:= i+iStep;