bgraimagelist.pas 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040
  1. // SPDX-License-Identifier: LGPL-3.0-linking-exception
  2. { This component partialy solve problem with no alpha in lazarus GTK.
  3. It is using BGRABitmap library for drawing icons.
  4. originally written in 2011 by Krzysztof Dibowski dibowski at interia.pl
  5. }
  6. (******************************** CONTRIBUTOR(S) ******************************
  7. - Edivando S. Santos Brasil | [email protected]
  8. (Compatibility with delphi VCL 11/2018) { #note -oMaxM : VCL Compatibility? }
  9. - Massimo Magnano
  10. 2024/12
  11. Added Before/AfterDraw events (don't works with Widgetsets)
  12. Added UseBGRADraw ( " )
  13. Added Proportionally add methods
  14. 2025/01
  15. Added Indexed image reading/writing and Load/SaveFile
  16. ***************************** END CONTRIBUTOR(S) *****************************)
  17. unit BGRAImageList;
  18. {$I bgracontrols.inc}
  19. interface
  20. uses
  21. Classes, SysUtils,
  22. {$ifdef FPC}
  23. LResources, LCLVersion,
  24. {$endif}
  25. Controls, Graphics,
  26. GraphType, BGRABitmap, BGRABitmapTypes, {%H-}ImgList;
  27. {$ifdef LCLgtk or LCLgtk2}
  28. { $DEFINE BGRA_DRAW}
  29. {$endif}
  30. const
  31. { #note -oMaxM : redeclared because are not public consts }
  32. SIG_LAZ1 = #1#0;
  33. SIG_LAZ2 = 'li';
  34. SIG_LAZ3 = 'Li';
  35. SIG_LAZ4 = 'Lz';
  36. SIG_D3 = 'IL';
  37. sInvalidIndex = 'Invalid ImageList Index';
  38. sInvalidFormat ='Invalid Stream Format Signature';
  39. type
  40. TImageListSignature = array[0..1] of char; { #note -oMaxM : redeclared because is not a public type }
  41. { TBGRAImageListResolution }
  42. TBGRAImageListResolution = class(TDragImageListResolution)
  43. protected
  44. {$if lcl_fullversion >= 4990000}
  45. procedure ReadData(AStream: TStream; AIndex: Integer;
  46. StartStreamPos: Int64=0; CalcPos: Boolean=True); virtual; overload;
  47. procedure WriteData(AStream: TStream; AIndex: Integer;
  48. StartStreamPos: Int64=0; CalcPos: Boolean=True); virtual; overload;
  49. {$endif}
  50. public
  51. procedure BGRADraw(ACanvas: TCanvas; ARect: TRect; AIndex: Integer; AOverlay: TOverlay;
  52. ADrawingStyle: TDrawingStyle; AImageType: TImageType;
  53. ADrawEffect: TGraphicsDrawEffect; ABkColor, ABlendColor: TColor; AStretch: Boolean=False); virtual;
  54. procedure Draw(ACanvas: TCanvas; AX, AY, AIndex: integer; ADrawingStyle: TDrawingStyle; AImageType: TImageType;
  55. ADrawEffect: TGraphicsDrawEffect); override;
  56. procedure DrawOverlay(ACanvas: TCanvas; AX, AY, AIndex: Integer; AOverlay: TOverlay; ADrawingStyle:
  57. TDrawingStyle; AImageType: TImageType; ADrawEffect: TGraphicsDrawEffect); overload;
  58. procedure StretchDrawOverlay(ACanvas: TCanvas; AIndex: Integer; ARect: TRect; AOverlay: TOverlay;
  59. AEnabled: Boolean = True); virtual;
  60. end;
  61. { TBGRAImageList }
  62. TBGRAImageList = class;
  63. //Return True whether the default draw should be called
  64. TCustomImageListBeforeDraw= function (Sender: TBGRAImageList;
  65. ACanvas: TCanvas; var ARect: TRect; var AIndex: Integer;
  66. var ADrawingStyle: TDrawingStyle; var AImageType: TImageType;
  67. var ADrawOverlay: Boolean; var AOverlay: TOverlay;
  68. var ADrawEffect: TGraphicsDrawEffect): Boolean of object;
  69. TCustomImageListAfterDraw= procedure (Sender: TBGRAImageList;
  70. ACanvas: TCanvas; ARect: TRect; AIndex: Integer;
  71. ADrawingStyle: TDrawingStyle; AImageType: TImageType;
  72. ADrawOverlay: Boolean; AOverlay: TOverlay;
  73. ADrawEffect: TGraphicsDrawEffect) of object;
  74. {$if lcl_fullversion < 4990000}
  75. TOverlaysArray = array[TOverlay] of Integer;
  76. {$endif}
  77. TBGRAImageList = class(TImageList)
  78. private
  79. rUseBGRADraw: Boolean;
  80. FBGRA: TBGRABitmap;
  81. FBmp: TBitmap;
  82. procedure SetUseBGRADraw(AValue: Boolean);
  83. protected
  84. FOnBeforeDraw: TCustomImageListBeforeDraw;
  85. FOnAfterDraw: TCustomImageListAfterDraw;
  86. {$if lcl_fullversion < 4990000}
  87. { #note -oMaxM : we keep our copy of the FOverlays array since it is declared private without any logic,
  88. so derived classes cannot use it in any way also because there is no property to read them
  89. see merged code freepascal.org/lazarus/lazarus!429
  90. }
  91. rOverlays: TOverlaysArray;
  92. {$endif}
  93. function GetResolution(AImageWidth: Integer): TBGRAImageListResolution;
  94. function CreateEmptyBitmap(AImageWidth, AImageHeight: Integer;
  95. AHorizAlign: TAlignment; AVertAlign: TTextLayout;
  96. var imgRect: TRect): TBitmap;
  97. public
  98. constructor Create(AOwner: TComponent); override;
  99. destructor Destroy; override;
  100. function GetResolutionClass: TCustomImageListResolutionClass; override;
  101. procedure ReadData(AStream: TStream); override; overload;
  102. {$if lcl_fullversion >= 4990000}
  103. //Read/Write AIndex image from Stream without read/write all the images
  104. procedure ReadData(AStream: TStream; AIndex: Integer;
  105. StartStreamPos: Int64=0; CalcPos: Boolean=True); virtual; overload;
  106. procedure WriteData(AStream: TStream); override; overload;
  107. procedure WriteData(AStream: TStream; AIndex: Integer;
  108. StartStreamPos: Int64=0; CalcPos: Boolean=True); virtual; overload;
  109. //Read/Write from File
  110. procedure LoadFromFile(const AFilename: string; AIndex: Integer;
  111. StartStreamPos: Int64=0; CalcPos: Boolean=True); overload;
  112. procedure LoadFromFileUTF8(const AFilenameUTF8: string; AIndex: Integer;
  113. StartStreamPos: Int64=0; CalcPos: Boolean=True); overload;
  114. procedure SaveToFile(const AFilename: string; AIndex: Integer;
  115. StartStreamPos: Int64=0; CalcPos: Boolean=True); overload;
  116. procedure SaveToFileUTF8(const AFilenameUTF8: string; AIndex: Integer;
  117. StartStreamPos: Int64=0; CalcPos: Boolean=True); overload;
  118. {$else}
  119. procedure Overlay(AIndex: Integer; AOverlay: TOverlay);
  120. property Overlays: TOverlaysArray read rOverlays;
  121. {$endif}
  122. procedure LoadFromFile(const AFilename: string); overload;
  123. procedure LoadFromFileUTF8(const AFilenameUTF8: string); overload;
  124. procedure SaveToFile(const AFilename: string); overload;
  125. procedure SaveToFileUTF8(const AFilenameUTF8: string); overload;
  126. function CreateProportionalImage(AImage: TCustomBitmap;
  127. AHorizAlign: TAlignment; AVertAlign: TTextLayout): TBitmap; overload;
  128. function CreateProportionalImage(AImageFileName: String;
  129. AHorizAlign: TAlignment; AVertAlign: TTextLayout): TBitmap; overload;
  130. function CreateMaskImage(AImage: TCustomBitmap; MaskColor: TColor): TBitmap; overload;
  131. function CreateMaskImage(AImageFileName: String; MaskColor: TColor): TBitmap; overload;
  132. function CreateProportionalMaskImage(AImage: TCustomBitmap; MaskColor: TColor;
  133. AHorizAlign: TAlignment; AVertAlign: TTextLayout): TBitmap; overload;
  134. function CreateProportionalMaskImage(AImageFileName: String; MaskColor: TColor;
  135. AHorizAlign: TAlignment; AVertAlign: TTextLayout): TBitmap; overload;
  136. procedure StretchDrawOverlay(ACanvas: TCanvas; AIndex: Integer; ARect: TRect; AOverlay: TOverlay; AEnabled: Boolean = True);
  137. function AddProportionally(Image: TCustomBitmap; Mask: TCustomBitmap=nil;
  138. AHorizAlign: TAlignment=taCenter; AVertAlign: TTextLayout=tlCenter): Integer; overload;
  139. function AddProportionally(AImageFileName: String; AMaskFileName: String='';
  140. AHorizAlign: TAlignment=taCenter; AVertAlign: TTextLayout=tlCenter): Integer; overload;
  141. function AddMaskedProportionally(Image: TCustomBitmap; MaskColor: TColor;
  142. AHorizAlign: TAlignment=taCenter; AVertAlign: TTextLayout=tlCenter): Integer; overload;
  143. function AddMaskedProportionally(AImageFileName: String; MaskColor: TColor;
  144. AHorizAlign: TAlignment=taCenter; AVertAlign: TTextLayout=tlCenter): Integer; overload;
  145. procedure InsertProportionally(AIndex: Integer; AImage: TCustomBitmap; AMask: TCustomBitmap=nil;
  146. AHorizAlign: TAlignment=taCenter; AVertAlign: TTextLayout=tlCenter); overload;
  147. procedure InsertProportionally(AIndex: Integer; AImageFileName: String; AMaskFileName: String='';
  148. AHorizAlign: TAlignment=taCenter; AVertAlign: TTextLayout=tlCenter); overload;
  149. procedure InsertMaskedProportionally(AIndex: Integer; AImage: TCustomBitmap; MaskColor: TColor;
  150. AHorizAlign: TAlignment=taCenter; AVertAlign: TTextLayout=tlCenter); overload;
  151. procedure InsertMaskedProportionally(AIndex: Integer; AImageFileName: String; MaskColor: TColor;
  152. AHorizAlign: TAlignment=taCenter; AVertAlign: TTextLayout=tlCenter); overload;
  153. procedure ReplaceProportionally(AIndex: Integer; AImage: TCustomBitmap; AMask: TCustomBitmap=nil;
  154. const AllResolutions: Boolean = True;
  155. AHorizAlign: TAlignment=taCenter; AVertAlign: TTextLayout=tlCenter); overload;
  156. procedure ReplaceProportionally(AIndex: Integer; AImageFileName: String; AMaskFileName: String='';
  157. const AllResolutions: Boolean = True;
  158. AHorizAlign: TAlignment=taCenter; AVertAlign: TTextLayout=tlCenter); overload;
  159. procedure ReplaceMaskedProportionally(AIndex: Integer; AImage: TCustomBitmap; MaskColor: TColor;
  160. const AllResolutions: Boolean = True;
  161. AHorizAlign: TAlignment=taCenter; AVertAlign: TTextLayout=tlCenter); overload;
  162. procedure ReplaceMaskedProportionally(AIndex: Integer; AImageFileName: String; MaskColor: TColor;
  163. const AllResolutions: Boolean = True;
  164. AHorizAlign: TAlignment=taCenter; AVertAlign: TTextLayout=tlCenter); overload;
  165. published
  166. property UseBGRADraw: Boolean read rUseBGRADraw write SetUseBGRADraw;
  167. { #note -oMaxM : This Events don't works inside Widgetsets that use the imagelist handle
  168. but only if you draw directly on the Canvas using ImageList Draw methods }
  169. property OnBeforeDraw: TCustomImageListBeforeDraw read FOnBeforeDraw write FOnBeforeDraw;
  170. property OnAfterDraw: TCustomImageListAfterDraw read FOnAfterDraw write FOnAfterDraw;
  171. end;
  172. {$ifdef FPC}procedure Register;{$endif}
  173. implementation
  174. uses BGRAUTF8 {$ifdef FPC}, WSImgList{$endif};
  175. const
  176. EffectMap: array[Boolean] of TGraphicsDrawEffect = (
  177. gdeDisabled,
  178. gdeNormal
  179. );
  180. {$ifdef FPC}
  181. procedure Register;
  182. begin
  183. RegisterComponents('BGRA Controls', [TBGRAImageList]);
  184. end;
  185. {$endif}
  186. { TBGRAImageListResolution }
  187. {$if lcl_fullversion >= 4990000}
  188. procedure TBGRAImageListResolution.ReadData(AStream: TStream; AIndex: Integer;
  189. StartStreamPos: Int64; CalcPos: Boolean);
  190. var
  191. oStreamPos: Int64;
  192. Signature: TImageListSignature;
  193. datPos, sCount: Integer;
  194. begin
  195. if (AIndex<0) or (AIndex>=Count) then raise EInvalidOperation.Create(SInvalidIndex);
  196. oStreamPos:= AStream.Position;
  197. try
  198. AStream.Position:= StartStreamPos;
  199. datPos:= AIndex * Width * Height;
  200. if CalcPos
  201. then begin
  202. AStream.Read(Signature, SizeOf(Signature));
  203. if Signature = SIG_LAZ3
  204. then begin
  205. sCount:=ReadLRSInteger(AStream);
  206. if (AIndex>=sCount) then raise EInvalidOperation.Create(SInvalidIndex);
  207. AStream.Position:= oStreamPos+SizeOf(Signature)+(3*4)+(datPos*SizeOf(FData[0]));
  208. AStream.Read(FData[datPos], Width * Height * SizeOf(FData[0]));
  209. end
  210. else raise Exception.Create(sInvalidFormat+' '+Signature);
  211. end
  212. else AStream.Read(FData[datPos], Width * Height * SizeOf(FData[0]));
  213. if HandleAllocated
  214. then TWSCustomImageListResolutionClass(WidgetSetClass).Replace(Self, AIndex, @FData[datPos]);
  215. finally
  216. AStream.Position:= oStreamPos;
  217. end;
  218. end;
  219. procedure TBGRAImageListResolution.WriteData(AStream: TStream; AIndex: Integer;
  220. StartStreamPos: Int64; CalcPos: Boolean);
  221. var
  222. oStreamPos: Int64;
  223. Signature: TImageListSignature;
  224. datPos: Integer;
  225. begin
  226. if (AIndex<0) or (AIndex>=Count) then raise EInvalidOperation.Create(SInvalidIndex);
  227. oStreamPos:= AStream.Position;
  228. try
  229. AStream.Position:= StartStreamPos;
  230. datPos:= AIndex * Width * Height;
  231. if CalcPos
  232. then begin
  233. AStream.Read(Signature, SizeOf(Signature));
  234. if Signature = SIG_LAZ3
  235. then begin
  236. WriteLRSInteger(AStream, Count);
  237. AStream.Position:= oStreamPos+SizeOf(Signature)+(3*4)+(datPos*SizeOf(FData[0]));
  238. AStream.Write(FData[datPos], Width * Height * SizeOf(FData[0]));
  239. end
  240. else raise Exception.Create(sInvalidFormat+' '+Signature);
  241. end
  242. else AStream.Write(FData[datPos], Width * Height * SizeOf(FData[0]));
  243. finally
  244. AStream.Position:= oStreamPos;
  245. end;
  246. end;
  247. {$endif}
  248. procedure TBGRAImageListResolution.BGRADraw(ACanvas: TCanvas; ARect: TRect; AIndex: Integer; AOverlay: TOverlay;
  249. ADrawingStyle: TDrawingStyle; AImageType: TImageType;
  250. ADrawEffect: TGraphicsDrawEffect; ABkColor, ABlendColor: TColor; AStretch: Boolean);
  251. var
  252. bmpDrawEffect: TGraphicsDrawEffect;
  253. OverlayI: Integer;
  254. begin
  255. if (AIndex < 0) or (AIndex >= Count) then Exit;
  256. ReferenceNeeded;
  257. with TBGRAImageList(ImageList) do
  258. begin
  259. if (FBGRA = nil) then FBGRA:= TBGRABitmap.Create;
  260. if (FBmp = nil) then FBmp:= TBitmap.Create;
  261. {*** BGRA Drawing *** }
  262. if (ADrawEffect = gdeDisabled)
  263. then bmpDrawEffect:= gdeNormal
  264. else bmpDrawEffect:= ADrawEffect;
  265. {$ifdef FPC}
  266. GetBitmap(AIndex, FBmp, bmpDrawEffect);
  267. {$else}
  268. GetBitmapRaw(AIndex, FBmp, bmpDrawEffect);
  269. {$endif}
  270. FBGRA.Assign(FBmp);
  271. if (AOverlay > 0) then
  272. begin
  273. OverlayI := Overlays[AOverlay];
  274. if (OverlayI in [0..Count-1]) then
  275. begin
  276. {$ifdef FPC}
  277. GetBitmap(OverlayI, FBmp, bmpDrawEffect);
  278. {$else}
  279. GetBitmapRaw(OverlayI, FBmp, bmpDrawEffect);
  280. {$endif}
  281. FBmp.Mask(ImageList.BkColor);
  282. FBGRA.PutImage(0, 0, FBmp, dmLinearBlend);
  283. end;
  284. end;
  285. if (ADrawEffect = gdeDisabled) then BGRAReplace(FBGRA, FBGRA.FilterGrayscale);
  286. if (ADrawingStyle in [dsFocus, dsSelected]) then FBGRA.ApplyGlobalOpacity(128);
  287. if AStretch
  288. then FBGRA.Draw(ACanvas, ARect, (ABkColor <> clNone))
  289. else FBGRA.Draw(ACanvas, ARect.Left, ARect.Top, (ABkColor <> clNone));
  290. end;
  291. end;
  292. procedure TBGRAImageListResolution.Draw(ACanvas: TCanvas; AX, AY, AIndex: integer; ADrawingStyle: TDrawingStyle;
  293. AImageType: TImageType; ADrawEffect: TGraphicsDrawEffect);
  294. var
  295. vRect: TRect;
  296. vIndex: Integer;
  297. vDrawingStyle: TDrawingStyle;
  298. vImageType: TImageType;
  299. vDrawOverlay,
  300. stdDraw: Boolean;
  301. vOverlay: TOverlay;
  302. vDrawEffect: TGraphicsDrawEffect;
  303. rImageList: TBGRAImageList;
  304. begin
  305. if (AIndex < 0) or (AIndex >= Count) then Exit;
  306. ReferenceNeeded;
  307. rImageList:= TBGRAImageList(ImageList);
  308. //Copy Parameters to vars
  309. vRect:= Rect(AX, AY, Width, Height);
  310. vIndex:= AIndex;
  311. vDrawingStyle:= ADrawingStyle;
  312. vImageType:= AImageType;
  313. vDrawOverlay:= False;
  314. vOverlay:= 0;
  315. vDrawEffect:= ADrawEffect;
  316. stdDraw:= True;
  317. if Assigned(rImageList.FOnBeforeDraw)
  318. then stdDraw:= rImageList.FOnBeforeDraw(rImageList, ACanvas, vRect, vIndex, vDrawingStyle, vImageType,
  319. vDrawOverlay, vOverlay, vDrawEffect);
  320. if stdDraw then
  321. begin
  322. if not(vDrawOverlay) then vOverlay:= 0;
  323. if rImageList.rUseBGRADraw
  324. then BGRADraw(ACanvas, vRect, vIndex, vOverlay, vDrawingStyle, vImageType, vDrawEffect,
  325. rImageList.BkColor, rImageList.BlendColor)
  326. else begin
  327. if vDrawOverlay
  328. then inherited DrawOverlay(ACanvas, vRect.Left, vRect.Top, vIndex, vOverlay, vDrawingStyle, vImageType, vDrawEffect)
  329. else inherited Draw(ACanvas, vRect.Left, vRect.Top, vIndex, vDrawingStyle, vImageType, vDrawEffect);
  330. end;
  331. end;
  332. if Assigned(rImageList.FOnAfterDraw)
  333. then rImageList.FOnAfterDraw(rImageList, ACanvas, vRect, vIndex, vDrawingStyle, vImageType,
  334. vDrawOverlay, vOverlay, vDrawEffect);
  335. end;
  336. procedure TBGRAImageListResolution.DrawOverlay(ACanvas: TCanvas; AX, AY, AIndex: Integer; AOverlay: TOverlay;
  337. ADrawingStyle: TDrawingStyle; AImageType: TImageType; ADrawEffect: TGraphicsDrawEffect);
  338. var
  339. vRect: TRect;
  340. vIndex: Integer;
  341. vDrawingStyle: TDrawingStyle;
  342. vImageType: TImageType;
  343. vDrawOverlay,
  344. stdDraw: Boolean;
  345. vOverlay: TOverlay;
  346. vDrawEffect: TGraphicsDrawEffect;
  347. rImageList: TBGRAImageList;
  348. begin
  349. if (AIndex < 0) or (AIndex >= Count) then Exit;
  350. ReferenceNeeded;
  351. rImageList:= TBGRAImageList(ImageList);
  352. //Copy Parameters to vars
  353. vRect:= Rect(AX, AY, Width, Height);
  354. vIndex:= AIndex;
  355. vDrawingStyle:= ADrawingStyle;
  356. vImageType:= AImageType;
  357. vDrawOverlay:= True;
  358. vOverlay:= AOverlay;
  359. vDrawEffect:= ADrawEffect;
  360. stdDraw:= True;
  361. if Assigned(rImageList.FOnBeforeDraw)
  362. then stdDraw:= rImageList.FOnBeforeDraw(rImageList, ACanvas, vRect, vIndex, vDrawingStyle, vImageType,
  363. vDrawOverlay, vOverlay, vDrawEffect);
  364. if stdDraw then
  365. begin
  366. if not(vDrawOverlay) then vOverlay:= 0;
  367. if rImageList.rUseBGRADraw
  368. then BGRADraw(ACanvas, vRect, vIndex, vOverlay, vDrawingStyle, vImageType, vDrawEffect,
  369. rImageList.BkColor, rImageList.BlendColor)
  370. else begin
  371. if vDrawOverlay
  372. then inherited DrawOverlay(ACanvas, vRect.Left, vRect.Top, vIndex, vOverlay, vDrawingStyle, vImageType, vDrawEffect)
  373. else inherited Draw(ACanvas, vRect.Left, vRect.Top, vIndex, vDrawingStyle, vImageType, vDrawEffect);
  374. end;
  375. end;
  376. if Assigned(TBGRAImageList(ImageList).FOnAfterDraw)
  377. then TBGRAImageList(ImageList).FOnAfterDraw(TBGRAImageList(ImageList), ACanvas, vRect, vIndex, vDrawingStyle, vImageType,
  378. vDrawOverlay, vOverlay, vDrawEffect);
  379. end;
  380. procedure TBGRAImageListResolution.StretchDrawOverlay(ACanvas: TCanvas; AIndex: Integer; ARect: TRect;
  381. AOverlay: TOverlay; AEnabled: Boolean);
  382. var
  383. Bmp: TBitmap;
  384. vRect: TRect;
  385. OverlayI,
  386. vIndex: Integer;
  387. vDrawingStyle: TDrawingStyle;
  388. vImageType: TImageType;
  389. vDrawOverlay,
  390. stdDraw: Boolean;
  391. vOverlay: TOverlay;
  392. vDrawEffect: TGraphicsDrawEffect;
  393. rImageList: TBGRAImageList;
  394. begin
  395. if ((ARect.Right-ARect.Left)=Width) and ((ARect.Bottom-ARect.Top)=Height) then
  396. DrawOverlay(ACanvas, ARect.Left, ARect.Top, AIndex, AOverlay, AEnabled)
  397. else
  398. begin
  399. rImageList:= TBGRAImageList(ImageList);
  400. //Copy Parameters to vars
  401. vRect:= ARect;
  402. vIndex:= AIndex;
  403. vDrawingStyle:= rImageList.DrawingStyle;
  404. vImageType:= rImageList.ImageType;
  405. vDrawOverlay:= True;
  406. vOverlay:= AOverlay;
  407. vDrawEffect:= EffectMap[AEnabled];
  408. stdDraw:= True;
  409. if Assigned(rImageList.FOnBeforeDraw)
  410. then stdDraw:= rImageList.FOnBeforeDraw(rImageList, ACanvas, vRect, vIndex, vDrawingStyle, vImageType,
  411. vDrawOverlay, vOverlay, vDrawEffect);
  412. if stdDraw then
  413. begin
  414. if not(vDrawOverlay) then vOverlay:= 0;
  415. if rImageList.rUseBGRADraw
  416. then BGRADraw(ACanvas, vRect, vIndex, vOverlay, vDrawingStyle, vImageType, vDrawEffect,
  417. rImageList.BkColor, rImageList.BlendColor, True)
  418. else begin
  419. try
  420. Bmp := TBitmap.Create;
  421. {$ifdef FPC}
  422. GetBitmap(vIndex, Bmp, vDrawEffect);
  423. {$else}
  424. GetBitmapRaw(vIndex, Bmp, vDrawEffect);
  425. {$endif}
  426. ACanvas.StretchDraw(vRect, Bmp);
  427. if vDrawOverlay and (vOverlay > 0) then
  428. begin
  429. OverlayI := rImageList.Overlays[vOverlay];
  430. {$ifdef FPC}
  431. GetBitmap(OverlayI, Bmp, vDrawEffect);
  432. {$else}
  433. GetBitmapRaw(OverlayI, Bmp, vDrawEffect);
  434. {$endif}
  435. Bmp.Mask(rImageList.BkColor);
  436. ACanvas.StretchDraw(vRect, Bmp);
  437. end;
  438. finally
  439. Bmp.Free;
  440. end;
  441. end;
  442. end;
  443. if Assigned(rImageList.FOnAfterDraw)
  444. then rImageList.FOnAfterDraw(rImageList, ACanvas, vRect, vIndex, vDrawingStyle, vImageType,
  445. vDrawOverlay, vOverlay, vDrawEffect);
  446. end;
  447. end;
  448. procedure TBGRAImageList.SetUseBGRADraw(AValue: Boolean);
  449. begin
  450. if (rUseBGRADraw<>AValue) then
  451. begin
  452. rUseBGRADraw:=AValue;
  453. if Assigned(OnChange) then OnChange(Self);
  454. end;
  455. end;
  456. function TBGRAImageList.GetResolution(AImageWidth: Integer): TBGRAImageListResolution;
  457. begin
  458. Result := TBGRAImageListResolution(inherited GetResolution(AImageWidth));
  459. end;
  460. function TBGRAImageList.CreateEmptyBitmap(AImageWidth, AImageHeight: Integer; AHorizAlign: TAlignment;
  461. AVertAlign: TTextLayout; var imgRect: TRect): TBitmap;
  462. var
  463. rW, rH:Single;
  464. newWidth,
  465. newHeight:Integer;
  466. begin
  467. if (AImageWidth > 0) and (AImageHeight > 0) then
  468. begin
  469. imgRect.Left:= 0;
  470. imgRect.Top:= 0;
  471. rW := AImageWidth / Width;
  472. rH := AImageHeight / Height;
  473. if (rW > rH)
  474. then begin
  475. newHeight:= round(AImageHeight / rW);
  476. newWidth := Width;
  477. end
  478. else begin
  479. newWidth := round(AImageWidth / rH);
  480. newHeight := Height;
  481. end;
  482. case AHorizAlign of
  483. taCenter: imgRect.Left:= (Width-newWidth) div 2;
  484. taRightJustify: imgRect.Left:= Width-newWidth;
  485. end;
  486. case AVertAlign of
  487. tlCenter: imgRect.Top:= (Height-newHeight) div 2;
  488. tlBottom: imgRect.Top:= Height-newHeight;
  489. end;
  490. imgRect.Right:= imgRect.Left+newWidth;
  491. imgRect.Bottom:= imgRect.Top+newHeight;
  492. Result := TBitmap.Create;
  493. if (BkColor = clNone) then
  494. begin
  495. Result.Transparent:= True;
  496. Result.TransparentColor:= clNone;
  497. end;
  498. Result.SetSize(Width, Height);
  499. Result.Canvas.Brush.Color := BkColor;
  500. Result.Canvas.FillRect(0, 0, Width, Height);
  501. end;
  502. end;
  503. function TBGRAImageList.CreateProportionalImage(AImage: TCustomBitmap;
  504. AHorizAlign: TAlignment; AVertAlign: TTextLayout): TBitmap;
  505. var
  506. imgRect: TRect;
  507. Bitmap, BitmapR :TBGRABitmap;
  508. begin
  509. Result:= nil;
  510. if (AImage <> nil) and (AImage.Width > 0) and (AImage.Height > 0) then
  511. try
  512. Result:= CreateEmptyBitmap(AImage.Width, AImage.Height, AHorizAlign, AVertAlign, imgRect);
  513. //Use our Stretch since TBitmap's one sucks
  514. Bitmap := TBGRABitmap.Create;
  515. Bitmap.Assign(AImage);
  516. BitmapR :=Bitmap.Resample(imgRect.Width, imgRect.Height);
  517. BitmapR.Draw(Result.Canvas, imgRect, False);
  518. finally
  519. Bitmap.Free;
  520. BitmapR.Free;
  521. end;
  522. end;
  523. function TBGRAImageList.CreateProportionalImage(AImageFileName: String;
  524. AHorizAlign: TAlignment; AVertAlign: TTextLayout): TBitmap;
  525. var
  526. pict: TPicture;
  527. begin
  528. Result:= nil;
  529. if FileExists(AImageFileName) then
  530. try
  531. pict:= TPicture.Create;
  532. pict.LoadFromFile(AImageFileName);
  533. Result:= CreateProportionalImage(pict.Bitmap, AHorizAlign, AVertAlign);
  534. finally
  535. pict.Free;
  536. end;
  537. end;
  538. function TBGRAImageList.CreateMaskImage(AImage: TCustomBitmap; MaskColor: TColor): TBitmap;
  539. begin
  540. Result:= nil;
  541. if (AImage <> nil) and (AImage.Width > 0) and (AImage.Height > 0) then
  542. begin
  543. Result := TBitmap.Create;
  544. Result.Assign(AImage);
  545. Result.TransparentColor := MaskColor;
  546. Result.TransparentMode := tmFixed;
  547. Result.Transparent := True;
  548. Result.Masked:= True;
  549. end;
  550. end;
  551. function TBGRAImageList.CreateMaskImage(AImageFileName: String; MaskColor: TColor): TBitmap;
  552. var
  553. //bmpBGRA: TBGRABitmap;
  554. pict: TPicture;
  555. begin
  556. Result:= nil;
  557. if FileExists(AImageFileName) then
  558. try
  559. (*bmpBGRA:= TBGRABitmap.Create;
  560. bmpBGRA.LoadFromFile(AImageFileName);
  561. Result := bmpBGRA.MakeBitmapCopy(MaskColor, False);
  562. *)
  563. pict:= TPicture.Create;
  564. pict.LoadFromFile(AImageFileName);
  565. Result:=TBitmap.Create;
  566. Result.Assign(pict.Bitmap);
  567. Result.TransparentColor := MaskColor;
  568. Result.TransparentMode := tmFixed;
  569. Result.Transparent := True;
  570. Result.Masked:= True;
  571. finally
  572. pict.Free;
  573. //bmpBGRA.Free;
  574. end;
  575. end;
  576. function TBGRAImageList.CreateProportionalMaskImage(AImage: TCustomBitmap; MaskColor: TColor;
  577. AHorizAlign: TAlignment; AVertAlign: TTextLayout): TBitmap;
  578. var
  579. MaskBmp: TBitmap;
  580. begin
  581. try
  582. MaskBmp:= CreateMaskImage(AImage, MaskColor);
  583. Result:= CreateProportionalImage(MaskBmp, AHorizAlign, AVertAlign);
  584. Result.TransparentColor:= MaskBmp.TransparentColor;
  585. finally
  586. MaskBmp.Free;
  587. end;
  588. end;
  589. function TBGRAImageList.CreateProportionalMaskImage(AImageFileName: String; MaskColor: TColor;
  590. AHorizAlign: TAlignment; AVertAlign: TTextLayout): TBitmap;
  591. var
  592. MaskBmp: TBitmap;
  593. begin
  594. try
  595. MaskBmp:= CreateMaskImage(AImageFileName, MaskColor);
  596. Result:= CreateProportionalImage(MaskBmp, AHorizAlign, AVertAlign);
  597. Result.TransparentColor:= MaskBmp.TransparentColor;
  598. finally
  599. MaskBmp.Free;
  600. end;
  601. end;
  602. function TBGRAImageList.GetResolutionClass: TCustomImageListResolutionClass;
  603. begin
  604. Result := TBGRAImageListResolution;
  605. end;
  606. procedure TBGRAImageList.ReadData(AStream: TStream);
  607. begin
  608. inherited ReadData(AStream);
  609. end;
  610. procedure TBGRAImageList.LoadFromFile(const AFilename: string);
  611. begin
  612. LoadFromFileUTF8(SysToUtf8(AFilename));
  613. end;
  614. procedure TBGRAImageList.LoadFromFileUTF8(const AFilenameUTF8: string);
  615. var
  616. stream: TFileStreamUTF8;
  617. begin
  618. stream := TFileStreamUTF8.Create(AFilenameUTF8, fmOpenRead or fmShareDenyWrite);
  619. try
  620. ReadData(stream);
  621. finally
  622. stream.Free;
  623. end;
  624. end;
  625. procedure TBGRAImageList.SaveToFile(const AFilename: string);
  626. begin
  627. SaveToFileUTF8(SysToUtf8(AFilename));
  628. end;
  629. procedure TBGRAImageList.SaveToFileUTF8(const AFilenameUTF8: string);
  630. var
  631. stream: TFileStreamUTF8;
  632. begin
  633. stream := TFileStreamUTF8.Create(AFilenameUTF8, fmCreate);
  634. try
  635. WriteData(stream);
  636. finally
  637. stream.Free;
  638. end;
  639. end;
  640. {$if lcl_fullversion>=4990000}
  641. procedure TBGRAImageList.ReadData(AStream: TStream; AIndex: Integer;
  642. StartStreamPos: Int64; CalcPos: Boolean);
  643. begin
  644. GetResolution(Width).ReadData(AStream, AIndex, StartStreamPos, CalcPos);
  645. end;
  646. procedure TBGRAImageList.WriteData(AStream: TStream);
  647. begin
  648. if (csDesigning in ComponentState)
  649. then inherited WriteData(AStream)
  650. else GetResolution(Width).WriteData(AStream, False); // don't compress data so we can write the image n without rewriting everything.
  651. end;
  652. procedure TBGRAImageList.WriteData(AStream: TStream; AIndex: Integer;
  653. StartStreamPos: Int64; CalcPos: Boolean);
  654. begin
  655. GetResolution(Width).WriteData(AStream, AIndex, StartStreamPos, CalcPos);
  656. end;
  657. procedure TBGRAImageList.LoadFromFile(const AFilename: string; AIndex: Integer;
  658. StartStreamPos: Int64; CalcPos: Boolean);
  659. begin
  660. LoadFromFileUTF8(SysToUtf8(AFilename), AIndex, StartStreamPos, CalcPos);
  661. end;
  662. procedure TBGRAImageList.LoadFromFileUTF8(const AFilenameUTF8: string; AIndex: Integer;
  663. StartStreamPos: Int64; CalcPos: Boolean);
  664. var
  665. stream: TFileStreamUTF8;
  666. begin
  667. stream := TFileStreamUTF8.Create(AFilenameUTF8, fmOpenRead or fmShareDenyWrite);
  668. try
  669. ReadData(stream, AIndex, StartStreamPos, CalcPos);
  670. finally
  671. stream.Free;
  672. end;
  673. end;
  674. procedure TBGRAImageList.SaveToFile(const AFilename: string; AIndex: Integer;
  675. StartStreamPos: Int64; CalcPos: Boolean);
  676. begin
  677. SaveToFileUTF8(SysToUtf8(AFilename), AIndex, StartStreamPos, CalcPos);
  678. end;
  679. procedure TBGRAImageList.SaveToFileUTF8(const AFilenameUTF8: string; AIndex: Integer;
  680. StartStreamPos: Int64; CalcPos: Boolean);
  681. var
  682. stream: TFileStreamUTF8;
  683. begin
  684. stream := TFileStreamUTF8.Create(AFilenameUTF8, fmOpenReadWrite);
  685. try
  686. WriteData(stream, AIndex, StartStreamPos, CalcPos);
  687. finally
  688. stream.Free;
  689. end;
  690. end;
  691. {$else}
  692. procedure TBGRAImageList.Overlay(AIndex: Integer; AOverlay: TOverlay);
  693. begin
  694. TImageList(Self).Overlay(AIndex, AOverlay);
  695. rOverlays[AOverlay] := AIndex;
  696. end;
  697. {$endif}
  698. procedure TBGRAImageList.StretchDrawOverlay(ACanvas: TCanvas; AIndex: Integer; ARect: TRect; AOverlay: TOverlay;
  699. AEnabled: Boolean);
  700. begin
  701. GetResolution(Width).StretchDrawOverlay(ACanvas, AIndex, ARect, AOverlay, AEnabled);
  702. end;
  703. function TBGRAImageList.AddProportionally(Image: TCustomBitmap; Mask: TCustomBitmap; AHorizAlign: TAlignment;
  704. AVertAlign: TTextLayout): Integer;
  705. begin
  706. try
  707. Result:= Count;
  708. InsertProportionally(Result, Image, Mask, AHorizAlign, AVertAlign);
  709. except
  710. Result:= -1;
  711. end;
  712. end;
  713. function TBGRAImageList.AddProportionally(AImageFileName: String; AMaskFileName: String; AHorizAlign: TAlignment;
  714. AVertAlign: TTextLayout): Integer;
  715. begin
  716. try
  717. Result := Count;
  718. InsertProportionally(Result, AImageFileName, AMaskFileName, AHorizAlign, AVertAlign);
  719. except
  720. Result:= -1;
  721. end;
  722. end;
  723. function TBGRAImageList.AddMaskedProportionally(Image: TCustomBitmap; MaskColor: TColor; AHorizAlign: TAlignment;
  724. AVertAlign: TTextLayout): Integer;
  725. begin
  726. try
  727. Result := Count;
  728. InsertMaskedProportionally(Result, Image, MaskColor, AHorizAlign, AVertAlign);
  729. except
  730. Result:= -1;
  731. end;
  732. end;
  733. function TBGRAImageList.AddMaskedProportionally(AImageFileName: String; MaskColor: TColor; AHorizAlign: TAlignment;
  734. AVertAlign: TTextLayout): Integer;
  735. begin
  736. try
  737. Result := Count;
  738. InsertMaskedProportionally(Result, AImageFileName, MaskColor, AHorizAlign, AVertAlign);
  739. except
  740. Result:= -1;
  741. end;
  742. end;
  743. procedure TBGRAImageList.InsertProportionally(AIndex: Integer; AImage: TCustomBitmap; AMask: TCustomBitmap;
  744. AHorizAlign: TAlignment; AVertAlign: TTextLayout);
  745. var
  746. Bmp,
  747. BmpMask: TBitmap;
  748. begin
  749. try
  750. BmpMask := CreateProportionalImage(AMask, AHorizAlign, AVertAlign);
  751. Bmp := CreateProportionalImage(AImage, AHorizAlign, AVertAlign);
  752. Insert(AIndex, Bmp, BmpMask);
  753. finally
  754. BmpMask.Free;
  755. Bmp.Free;
  756. end;
  757. end;
  758. procedure TBGRAImageList.InsertProportionally(AIndex: Integer; AImageFileName: String; AMaskFileName: String;
  759. AHorizAlign: TAlignment; AVertAlign: TTextLayout);
  760. var
  761. Bmp,
  762. BmpMask: TBitmap;
  763. begin
  764. try
  765. BmpMask := CreateProportionalImage(AMaskFileName, AHorizAlign, AVertAlign);
  766. Bmp := CreateProportionalImage(AImageFileName, AHorizAlign, AVertAlign);
  767. Insert(AIndex, Bmp, BmpMask);
  768. finally
  769. BmpMask.Free;
  770. Bmp.Free;
  771. end;
  772. end;
  773. procedure TBGRAImageList.InsertMaskedProportionally(AIndex: Integer; AImage: TCustomBitmap; MaskColor: TColor;
  774. AHorizAlign: TAlignment; AVertAlign: TTextLayout);
  775. var
  776. BmpMask: TBitmap;
  777. begin
  778. try
  779. BmpMask := CreateProportionalMaskImage(AImage, MaskColor, AHorizAlign, AVertAlign);
  780. InsertMasked(AIndex, BmpMask, MaskColor);
  781. finally
  782. BmpMask.Free;
  783. end;
  784. end;
  785. procedure TBGRAImageList.InsertMaskedProportionally(AIndex: Integer; AImageFileName: String; MaskColor: TColor;
  786. AHorizAlign: TAlignment; AVertAlign: TTextLayout);
  787. var
  788. BmpMask: TBitmap;
  789. begin
  790. try
  791. BmpMask:= CreateProportionalMaskImage(AImageFileName, MaskColor, AHorizAlign, AVertAlign);
  792. InsertMasked(AIndex, BmpMask, MaskColor);
  793. finally
  794. BmpMask.Free;
  795. end;
  796. end;
  797. procedure TBGRAImageList.ReplaceProportionally(AIndex: Integer; AImage: TCustomBitmap; AMask: TCustomBitmap;
  798. const AllResolutions: Boolean; AHorizAlign: TAlignment; AVertAlign: TTextLayout);
  799. var
  800. Bmp,
  801. BmpMask: TBitmap;
  802. begin
  803. try
  804. BmpMask := CreateProportionalImage(AMask, AHorizAlign, AVertAlign);
  805. Bmp := CreateProportionalImage(AImage, AHorizAlign, AVertAlign);
  806. Replace(AIndex, Bmp, BmpMask, AllResolutions);
  807. finally
  808. BmpMask.Free;
  809. Bmp.Free;
  810. end;
  811. end;
  812. procedure TBGRAImageList.ReplaceProportionally(AIndex: Integer; AImageFileName: String; AMaskFileName: String;
  813. const AllResolutions: Boolean; AHorizAlign: TAlignment; AVertAlign: TTextLayout);
  814. var
  815. Bmp,
  816. BmpMask: TBitmap;
  817. begin
  818. try
  819. BmpMask := CreateProportionalImage(AMaskFileName, AHorizAlign, AVertAlign);
  820. Bmp := CreateProportionalImage(AImageFileName, AHorizAlign, AVertAlign);
  821. Replace(AIndex, Bmp, BmpMask, AllResolutions);
  822. finally
  823. BmpMask.Free;
  824. Bmp.Free;
  825. end;
  826. end;
  827. procedure TBGRAImageList.ReplaceMaskedProportionally(AIndex: Integer; AImage: TCustomBitmap; MaskColor: TColor;
  828. const AllResolutions: Boolean; AHorizAlign: TAlignment; AVertAlign: TTextLayout);
  829. var
  830. BmpMask: TBitmap;
  831. begin
  832. try
  833. BmpMask := CreateProportionalMaskImage(AImage, MaskColor, AHorizAlign, AVertAlign);
  834. ReplaceMasked(AIndex, BmpMask, MaskColor, AllResolutions);
  835. finally
  836. BmpMask.Free;
  837. end;
  838. end;
  839. procedure TBGRAImageList.ReplaceMaskedProportionally(AIndex: Integer; AImageFileName: String; MaskColor: TColor;
  840. const AllResolutions: Boolean; AHorizAlign: TAlignment; AVertAlign: TTextLayout);
  841. var
  842. BmpMask: TBitmap;
  843. begin
  844. try
  845. BmpMask := CreateProportionalMaskImage(AImageFileName, MaskColor, AHorizAlign, AVertAlign);
  846. ReplaceMasked(AIndex, BmpMask, MaskColor, AllResolutions);
  847. finally
  848. BmpMask.Free;
  849. end;
  850. end;
  851. constructor TBGRAImageList.Create(AOwner: TComponent);
  852. begin
  853. inherited Create(AOwner);
  854. {$ifdef BGRA_DRAW}
  855. rUseBGRADraw:= True;
  856. {$endif}
  857. end;
  858. destructor TBGRAImageList.Destroy;
  859. begin
  860. if (FBGRA <> nil) then FBGRA.Free;
  861. if (FBmp <> nil) then FBmp.Free;
  862. inherited Destroy;
  863. end;
  864. end.