Browse Source

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 months ago
parent
commit
d586f4f7cc

+ 72 - 39
bgraflashprogressbar.pas

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

+ 208 - 2
bgraimagemanipulation.pas

@@ -81,6 +81,7 @@ unit BGRAImageManipulation;
       -08    - Removed EmptyImage.Allow, so is always allowed
       -08    - Removed EmptyImage.Allow, so is always allowed
                CopyPropertiesToArea and Icons in NewCropAreaDefault
                CopyPropertiesToArea and Icons in NewCropAreaDefault
                Updated Component icon
                Updated Component icon
+  2025-01    - Added Load/Save and their events
   ============================================================================
   ============================================================================
 }
 }
 
 
@@ -353,6 +354,19 @@ type
   TBGRAIMContextPopupEvent = procedure(Sender: TBGRAImageManipulation; CropArea: TCropArea;
   TBGRAIMContextPopupEvent = procedure(Sender: TBGRAImageManipulation; CropArea: TCropArea;
                                        AnchorSelected :TDirection; MousePos: TPoint; var Handled: Boolean) of object;
                                        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)
   TBGRAImageManipulation = class(TBGRAGraphicCtrl)
   private
   private
@@ -374,7 +388,8 @@ type
     fSizeLimits: TSizeLimits;
     fSizeLimits: TSizeLimits;
     fImageBitmap, fResampledBitmap, fBackground, fVirtualScreen: TBGRABitmap;
     fImageBitmap, fResampledBitmap, fBackground, fVirtualScreen: TBGRABitmap;
     rNewCropAreaDefault: TBGRANewCropAreaDefault;
     rNewCropAreaDefault: TBGRANewCropAreaDefault;
-    rOnContextPopup: TBGRAIMContextPopupEvent;
+    rOnBitmapSaveAfter: TBGRAIMBitmapSaveAfter;
+    rOnBitmapSaveBefore: TBGRAIMBitmapSaveBefore;
 
 
     function getAnchorSize: byte;
     function getAnchorSize: byte;
     function getPixelsPerInch: Integer;
     function getPixelsPerInch: Integer;
@@ -400,6 +415,9 @@ type
     rOnSelectedCropAreaChanged: TCropAreaEvent;
     rOnSelectedCropAreaChanged: TCropAreaEvent;
     rOnCropAreaLoad: TCropAreaLoadEvent;
     rOnCropAreaLoad: TCropAreaLoadEvent;
     rOnCropAreaSave: TCropAreaSaveEvent;
     rOnCropAreaSave: TCropAreaSaveEvent;
+    rOnBitmapLoadBefore: TBGRAIMBitmapLoadBefore;
+    rOnBitmapLoadAfter: TBGRAIMBitmapLoadAfter;
+    rOnContextPopup: TBGRAIMContextPopupEvent;
     rEmptyImage: TBGRAEmptyImage;
     rEmptyImage: TBGRAEmptyImage;
     rLoading: Boolean;
     rLoading: Boolean;
     rOpacity: Byte;
     rOpacity: Byte;
@@ -454,6 +472,19 @@ type
     procedure SetEmptyImageSizeToNull;
     procedure SetEmptyImageSizeToNull;
     procedure SetEmptyImageSize(AResolutionUnit: TResolutionUnit; AResolutionWidth, AResolutionHeight: Single);
     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 SelectedCropArea :TCropArea read rSelectedCropArea write setSelectedCropArea;
     property CropAreas :TCropAreaList read rCropAreas;
     property CropAreas :TCropAreaList read rCropAreas;
     property PixelsPerInch: Integer read getPixelsPerInch;
     property PixelsPerInch: Integer read getPixelsPerInch;
@@ -490,6 +521,11 @@ type
     property OnDragDrop: TDragDropEvent;
     property OnDragDrop: TDragDropEvent;
     property OnDragOver: TDragOverEvent;
     property OnDragOver: TDragOverEvent;
     property OnEndDrag: TEndDragEvent;*)
     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;
   end;
 
 
 
 
@@ -501,7 +537,7 @@ procedure PixelXResolutionUnitConvert(var resX, resY:Single; fromRes, toRes:TRes
 
 
 implementation
 implementation
 
 
-uses Math, ExtCtrls;
+uses Math, ExtCtrls, BGRAUTF8, UniversalDrawer, BGRAWritePNG, FPWritePNM;
 
 
 resourcestring
 resourcestring
   SAnchorSizeIsTooLarge =
   SAnchorSizeIsTooLarge =
@@ -3498,6 +3534,176 @@ begin
   Resize;
   Resize;
 end;
 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);
 procedure TBGRAImageManipulation.setBorderSize(const Value: byte);
 const
 const
   MinSize = 2;
   MinSize = 2;

+ 1 - 1
test/test_bgraimagemanipulation/unitbgraimagemanipulationdemo.lfm

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

+ 3 - 1
test/test_bgraimagemanipulation/unitbgraimagemanipulationdemo.pas

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

+ 58 - 0
test/test_progressbar/umain.lfm

@@ -6,6 +6,7 @@ object Form1: TForm1
   Caption = 'Form1'
   Caption = 'Form1'
   ClientHeight = 452
   ClientHeight = 452
   ClientWidth = 523
   ClientWidth = 523
+  LCLVersion = '4.99.0.0'
   OnClose = FormClose
   OnClose = FormClose
   OnCreate = FormCreate
   OnCreate = FormCreate
   OnShow = FormShow
   OnShow = FormShow
@@ -214,6 +215,63 @@ object Form1: TForm1
         Value = 30
         Value = 30
         OnChange = edValueChange
         OnChange = edValueChange
       end
       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
     end
     object TabMultiProgress: TTabSheet
     object TabMultiProgress: TTabSheet
       Tag = 1
       Tag = 1

+ 23 - 1
test/test_progressbar/umain.pas

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