PngImageList.pas 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303
  1. unit PngImageList;
  2. {$IF RTLVersion < 15.0 }
  3. This unit only compiles with Delphi 7 and higher!
  4. {$IFEND}
  5. interface
  6. uses
  7. Windows, Classes, SysUtils, Controls, Graphics, ImgList, PngImage,
  8. PngFunctions;
  9. type
  10. TPngImageCollection = class;
  11. TPngImageCollectionItem = class;
  12. TPngImageCollectionItems = class;
  13. TPngImageList = class(TImageList)
  14. private
  15. FEnabledImages: Boolean;
  16. FLocked: Integer;
  17. FPngImages: TPngImageCollectionItems;
  18. FPngOptions: TPngOptions;
  19. class var
  20. FIDE_WriteData_Hack: Boolean;
  21. function GetHeight: Integer;
  22. function GetWidth: Integer;
  23. procedure SetHeight(const Value: Integer);
  24. procedure SetPngOptions(const Value: TPngOptions);
  25. procedure SetWidth(const Value: Integer);
  26. protected
  27. procedure AssignTo(Dest: TPersistent); override;
  28. procedure CopyPngs; virtual;
  29. procedure DoDraw(Index: Integer; Canvas: TCanvas; X, Y: Integer; Style: Cardinal; Enabled: Boolean = True); override;
  30. procedure InternalInsertPng(Index: Integer; const Png: TPngImage; Background:
  31. TColor = clNone);
  32. procedure InternalAddPng(const Png: TPngImage; Background: TColor = clNone);
  33. function PngToIcon(const Png: TPngImage; Background: TColor = clNone): HICON;
  34. procedure ReadData(Stream: TStream); override;
  35. procedure SetEnabledImages(const Value: Boolean); virtual;
  36. procedure SetPngImages(const Value: TPngImageCollectionItems); virtual;
  37. procedure WriteData(Stream: TStream); override;
  38. public
  39. constructor Create(AOwner: TComponent); override;
  40. destructor Destroy; override;
  41. //Patched methods
  42. function Add(Image, Mask: TBitmap): Integer; virtual;
  43. function AddIcon(Image: TIcon): Integer; virtual;
  44. function AddPng(Image: TPngImage; Background: TColor = clNone): Integer;
  45. function AddImage(Value: TCustomImageList; Index: Integer): Integer; virtual;
  46. procedure AddImages(Value: TCustomImageList); virtual;
  47. function AddMasked(Image: TBitmap; MaskColor: TColor): Integer; virtual;
  48. procedure BeginUpdate;
  49. procedure Clear; virtual;
  50. procedure Delete(Index: Integer); virtual;
  51. procedure EndUpdate(Update: Boolean = True);
  52. procedure Insert(Index: Integer; Image, Mask: TBitmap); virtual;
  53. procedure InsertIcon(Index: Integer; Image: TIcon); virtual;
  54. procedure InsertPng(Index: Integer; Image: TPngImage; Background: TColor =
  55. clNone);
  56. procedure InsertMasked(Index: Integer; Image: TBitmap; MaskColor: TColor); virtual;
  57. procedure Move(CurIndex, NewIndex: Integer); virtual;
  58. procedure Replace(Index: Integer; Image, Mask: TBitmap); virtual;
  59. procedure ReplaceIcon(Index: Integer; Image: TIcon); virtual;
  60. procedure ReplaceMasked(Index: Integer; NewImage: TBitmap; MaskColor: TColor); virtual;
  61. class property IDE_WriteData_Hack: Boolean read FIDE_WriteData_Hack write
  62. FIDE_WriteData_Hack;
  63. published
  64. property EnabledImages: Boolean read FEnabledImages write SetEnabledImages default True;
  65. property Height read GetHeight write SetHeight default 16;
  66. property PngImages: TPngImageCollectionItems read FPngImages write SetPngImages;
  67. property PngOptions: TPngOptions read FPngOptions write SetPngOptions default [pngBlendOnDisabled];
  68. property Width read GetWidth write SetWidth default 16;
  69. end;
  70. TPngImageCollection = class(TComponent)
  71. private
  72. FItems: TPngImageCollectionItems;
  73. public
  74. constructor Create(AOwner: TComponent); override;
  75. destructor Destroy; override;
  76. published
  77. property Items: TPngImageCollectionItems read FItems write FItems;
  78. end;
  79. TPngImageCollectionItems = class(TCollection)
  80. private
  81. FOwner: TPersistent;
  82. function GetItem(Index: Integer): TPngImageCollectionItem;
  83. procedure SetItem(Index: Integer; const Value: TPngImageCollectionItem);
  84. protected
  85. function GetOwner: TPersistent; override;
  86. procedure Update(Item: TCollectionItem); override;
  87. public
  88. constructor Create(AOwner: TPersistent);
  89. function Add(DontCreatePNG: Boolean = False): TPngImageCollectionItem; reintroduce;
  90. procedure Assign(Source: TPersistent); override;
  91. function Insert(Index: Integer; DontCreatePNG: Boolean = False): TPngImageCollectionItem; reintroduce;
  92. property Items[index: Integer]: TPngImageCollectionItem read GetItem write SetItem; default;
  93. end;
  94. TPngImageCollectionItem = class(TCollectionItem)
  95. private
  96. FBackground: TColor;
  97. FName: string;
  98. FPngImage: TPngImage;
  99. procedure SetBackground(const Value: TColor);
  100. procedure SetPngImage(const Value: TPngImage);
  101. protected
  102. procedure AssignTo(Dest: TPersistent); override;
  103. function GetDisplayName: string; override;
  104. public
  105. constructor Create(Collection: TCollection); overload; override;
  106. constructor Create(Collection: TCollection; DontCreatePNG: Boolean = False); reintroduce; overload;
  107. destructor Destroy; override;
  108. procedure Assign(Source: TPersistent); override;
  109. function Duplicate: TPngImage;
  110. published
  111. property Background: TColor read FBackground write SetBackground default clBtnFace;
  112. property Name: string read FName write FName;
  113. property PngImage: TPngImage read FPngImage write SetPngImage;
  114. end;
  115. implementation
  116. uses
  117. Math, Contnrs, CommCtrl, ComCtrls;
  118. var
  119. ImageListCount: Integer = 0;
  120. MethodPatches: TObjectList = nil;
  121. type
  122. TMethodPatch = class
  123. private
  124. Name: string;
  125. OldBody: packed array[0..4] of Byte;
  126. OldPointer: Pointer;
  127. NewPointer: Pointer;
  128. public
  129. constructor Create;
  130. destructor Destroy; override;
  131. procedure BeginInvokeOldMethod;
  132. procedure FinishInvokeOldMethod;
  133. function PatchBack: Boolean;
  134. end;
  135. { Global }
  136. function FindMethodPatch(const Name: string): TMethodPatch;
  137. var
  138. I: Integer;
  139. begin
  140. Result := nil;
  141. for I := 0 to MethodPatches.Count - 1 do begin
  142. if TMethodPatch(MethodPatches[I]).Name = Name then begin
  143. Result := TMethodPatch(MethodPatches[I]);
  144. Break;
  145. end;
  146. end;
  147. end;
  148. {$IF RTLVersion > 18.0 }
  149. {$POINTERMATH ON}
  150. {$IFEND}
  151. function PatchPtr(OldPtr, NewPtr: Pointer; const Name: string; Patch: TMethodPatch): Boolean;
  152. var
  153. Access: Cardinal;
  154. memSize: Integer;
  155. opCode: PByte;
  156. operand: PInteger;
  157. begin
  158. Result := False;
  159. Patch.Name := Name;
  160. if OldPtr <> NewPtr then begin
  161. Patch.OldPointer := OldPtr;
  162. Patch.NewPointer := NewPtr;
  163. opCode := OldPtr;
  164. operand := OldPtr;
  165. Inc(PByte(operand));
  166. memSize := SizeOf(Patch.OldBody);
  167. Move(opCode^, Patch.OldBody[0], memSize);
  168. if VirtualProtect(OldPtr, 16, PAGE_EXECUTE_READWRITE, @Access) then begin
  169. opCode^ := $E9; // Near jump
  170. {$IF RTLVersion > 18.0 }
  171. operand^ := PByte(NewPtr) - PByte(OldPtr) - 5;
  172. {$ELSE}
  173. operand^ := PChar(NewPtr) - PChar(OldPtr) - 5;
  174. {$IFEND}
  175. VirtualProtect(OldPtr, 16, Access, @Access);
  176. // {$IF not (defined(CPU386) or defined(CPUX86) or defined(CPUX64)) }
  177. // FlushInstructionCache(GetCurrentProcess, OldPtr, memSize);
  178. // {$IFEND}
  179. Result := True;
  180. end;
  181. end;
  182. if not Result then
  183. Patch.OldPointer := nil;
  184. end;
  185. {$IF RTLVersion > 18.0 }
  186. {$POINTERMATH OFF}
  187. {$IFEND}
  188. procedure ApplyMethodPatches;
  189. type
  190. TPointerCombo = record
  191. OldPtr: Pointer;
  192. NewPtr: Pointer;
  193. Name: string;
  194. end;
  195. function Combo(const OldPtr, NewPtr: Pointer; const Name: string): TPointerCombo;
  196. begin
  197. Result.OldPtr := OldPtr;
  198. Result.NewPtr := NewPtr;
  199. Result.Name := Name;
  200. end;
  201. const
  202. EmptyCombo: TPointerCombo = (OldPtr: nil; NewPtr: nil; Name: '');
  203. var
  204. Pointers: array of TPointerCombo;
  205. Patch: TMethodPatch;
  206. I: Integer;
  207. begin
  208. if ImageListCount = 0 then begin
  209. SetLength(Pointers, 14);
  210. Pointers[0] := Combo(@TCustomImageList.Add, @TPngImageList.Add, 'Add');
  211. Pointers[1] := Combo(@TCustomImageList.AddIcon, @TPngImageList.AddIcon, 'AddIcon');
  212. Pointers[2] := Combo(@TCustomImageList.AddImage, @TPngImageList.AddImage, 'AddImage');
  213. Pointers[3] := Combo(@TCustomImageList.AddImages, @TPngImageList.AddImages, 'AddImages');
  214. Pointers[4] := Combo(@TCustomImageList.AddMasked, @TPngImageList.AddMasked, 'AddMasked');
  215. Pointers[5] := Combo(@TCustomImageList.Clear, @TPngImageList.Clear, 'Clear');
  216. Pointers[6] := Combo(@TCustomImageList.Delete, @TPngImageList.Delete, 'Delete');
  217. Pointers[7] := Combo(@TCustomImageList.Insert, @TPngImageList.Insert, 'Insert');
  218. Pointers[8] := Combo(@TCustomImageList.InsertIcon, @TPngImageList.InsertIcon, 'InsertIcon');
  219. Pointers[9] := Combo(@TCustomImageList.InsertMasked, @TPngImageList.InsertMasked, 'InsertMasked');
  220. Pointers[10] := Combo(@TCustomImageList.Move, @TPngImageList.Move, 'Move');
  221. Pointers[11] := Combo(@TCustomImageList.Replace, @TPngImageList.Replace, 'Replace');
  222. Pointers[12] := Combo(@TCustomImageList.ReplaceIcon, @TPngImageList.ReplaceIcon, 'ReplaceIcon');
  223. Pointers[13] := Combo(@TCustomImageList.ReplaceMasked, @TPngImageList.ReplaceMasked, 'ReplaceMasked');
  224. MethodPatches := TObjectList.Create;
  225. for I := Low(Pointers) to High(Pointers) do begin
  226. if Pointers[I].OldPtr <> nil then begin
  227. Patch := TMethodPatch.Create;
  228. if PatchPtr(Pointers[I].OldPtr, Pointers[I].NewPtr, Pointers[I].Name, Patch) then
  229. begin
  230. MethodPatches.Add(Patch)
  231. end
  232. else
  233. begin
  234. Patch.Free;
  235. end;
  236. end;
  237. end;
  238. end;
  239. end;
  240. procedure RevertPatchedMethods;
  241. begin
  242. if ImageListCount = 0 then
  243. begin
  244. FreeAndNil(MethodPatches);
  245. end;
  246. end;
  247. { TMethodPatch }
  248. constructor TMethodPatch.Create;
  249. begin
  250. inherited Create;
  251. OldPointer := nil;
  252. end;
  253. destructor TMethodPatch.Destroy;
  254. begin
  255. if OldPointer <> nil then
  256. begin
  257. PatchBack;
  258. end;
  259. inherited Destroy;
  260. end;
  261. procedure TMethodPatch.BeginInvokeOldMethod;
  262. begin
  263. PatchBack;
  264. end;
  265. procedure TMethodPatch.FinishInvokeOldMethod;
  266. begin
  267. PatchPtr(OldPointer, NewPointer, Name, Self);
  268. end;
  269. function TMethodPatch.PatchBack: Boolean;
  270. var
  271. Access: Cardinal;
  272. begin
  273. Result := False;
  274. if VirtualProtect(OldPointer, 16, PAGE_EXECUTE_READWRITE, @Access) then begin
  275. Move(OldBody[0], OldPointer^, SizeOf(OldBody));
  276. VirtualProtect(OldPointer, 16, Access, @Access);
  277. Result := True;
  278. end;
  279. end;
  280. constructor TPngImageList.Create(AOwner: TComponent);
  281. begin
  282. inherited Create(AOwner);
  283. if ImageListCount = 0 then
  284. ApplyMethodPatches;
  285. Inc(ImageListCount);
  286. FEnabledImages := True;
  287. FPngOptions := [pngBlendOnDisabled];
  288. FPngImages := TPngImageCollectionItems.Create(Self);
  289. FLocked := 0;
  290. end;
  291. destructor TPngImageList.Destroy;
  292. begin
  293. FPngImages.Free;
  294. Dec(ImageListCount);
  295. if ImageListCount = 0 then
  296. RevertPatchedMethods;
  297. inherited Destroy;
  298. end;
  299. //--- Patched methods ---
  300. function TPngImageList.Add(Image, Mask: TBitmap): Integer;
  301. var
  302. Patch: TMethodPatch;
  303. Png: TPngImage;
  304. begin
  305. if TObject(Self) is TPngImageList then begin
  306. Png := TPngImage.Create;
  307. try
  308. CreatePNG(Image, Mask, Png);
  309. result := AddPng(Png);
  310. finally
  311. Png.Free;
  312. end;
  313. end
  314. else begin
  315. Patch := FindMethodPatch('Add');
  316. if Patch <> nil then begin
  317. Patch.BeginInvokeOldMethod;
  318. try
  319. Result := TCustomImageList(Self).Add(Image, Mask);
  320. finally
  321. Patch.FinishInvokeOldMethod;
  322. end;
  323. end
  324. else
  325. Result := -1;
  326. end;
  327. end;
  328. function TPngImageList.AddIcon(Image: TIcon): Integer;
  329. var
  330. Patch: TMethodPatch;
  331. Png: TPngImage;
  332. begin
  333. if TObject(Self) is TPngImageList then begin
  334. Png := TPngImage.Create;
  335. try
  336. ConvertToPNG(Image, Png);
  337. result := AddPng(Png);
  338. finally
  339. Png.Free;
  340. end;
  341. end
  342. else begin
  343. Patch := FindMethodPatch('AddIcon');
  344. if Patch <> nil then begin
  345. Patch.BeginInvokeOldMethod;
  346. try
  347. Result := TCustomImageList(Self).AddIcon(Image);
  348. finally
  349. Patch.FinishInvokeOldMethod;
  350. end;
  351. end
  352. else
  353. Result := -1;
  354. end;
  355. end;
  356. function TPngImageList.AddPng(Image: TPngImage; Background: TColor = clNone):
  357. Integer;
  358. var
  359. Item: TPngImageCollectionItem;
  360. begin
  361. Result := -1;
  362. if Image = nil then Exit;
  363. BeginUpdate;
  364. try
  365. Item := FPngImages.Add(True);
  366. Item.PngImage := Image;
  367. Item.Background := Background;
  368. Result := Item.Index;
  369. InternalAddPng(Item.PngImage, Item.Background);
  370. Change;
  371. finally
  372. EndUpdate(false);
  373. end;
  374. end;
  375. function TPngImageList.AddImage(Value: TCustomImageList; Index: Integer): Integer;
  376. var
  377. Patch: TMethodPatch;
  378. Png: TPngImage;
  379. begin
  380. if TObject(Self) is TPngImageList then begin
  381. Png := TPngImage.Create;
  382. try
  383. CopyImageFromImageList(Png, Value, Index);
  384. result := AddPng(Png);
  385. finally
  386. Png.Free;
  387. end;
  388. end
  389. else begin
  390. Patch := FindMethodPatch('AddImage');
  391. if Patch <> nil then begin
  392. Patch.BeginInvokeOldMethod;
  393. try
  394. Result := TCustomImageList(Self).AddImage(Value, Index);
  395. finally
  396. Patch.FinishInvokeOldMethod;
  397. end;
  398. end
  399. else
  400. Result := -1;
  401. end;
  402. end;
  403. procedure TPngImageList.AddImages(Value: TCustomImageList);
  404. var
  405. Patch: TMethodPatch;
  406. I: Integer;
  407. Png: TPngImage;
  408. begin
  409. if TObject(Self) is TPngImageList then begin
  410. BeginUpdate;
  411. try
  412. //Copy every image from Value into this imagelist.
  413. Png := TPngImage.Create;
  414. try
  415. for I := 0 to Value.Count - 1 do begin
  416. CopyImageFromImageList(Png, Value, I);
  417. AddPng(Png);
  418. end;
  419. finally
  420. Png.Free;
  421. end;
  422. finally
  423. EndUpdate;
  424. end;
  425. end
  426. else begin
  427. Patch := FindMethodPatch('AddImages');
  428. if Patch <> nil then begin
  429. Patch.BeginInvokeOldMethod;
  430. try
  431. TCustomImageList(Self).AddImages(Value);
  432. finally
  433. Patch.FinishInvokeOldMethod;
  434. end;
  435. end;
  436. end;
  437. end;
  438. function TPngImageList.AddMasked(Image: TBitmap; MaskColor: TColor): Integer;
  439. var
  440. Patch: TMethodPatch;
  441. Png: TPngImage;
  442. begin
  443. if TObject(Self) is TPngImageList then begin
  444. // MP
  445. Png := nil;
  446. try
  447. CreatePNGMasked(Image, MaskColor, Png);
  448. result := AddPng(Png);
  449. finally
  450. if Assigned(Png) then Png.Free;
  451. end;
  452. end
  453. else begin
  454. Patch := FindMethodPatch('AddMasked');
  455. if Patch <> nil then begin
  456. Patch.BeginInvokeOldMethod;
  457. try
  458. Result := TCustomImageList(Self).AddMasked(Image, MaskColor);
  459. finally
  460. Patch.FinishInvokeOldMethod;
  461. end;
  462. end
  463. else
  464. Result := -1;
  465. end;
  466. end;
  467. procedure TPngImageList.AssignTo(Dest: TPersistent);
  468. begin
  469. inherited;
  470. if Dest is TPngImageList then begin
  471. TPngImageList(Dest).PngImages := FPngImages;
  472. TPngImageList(Dest).EnabledImages := FEnabledImages;
  473. end;
  474. end;
  475. procedure TPngImageList.BeginUpdate;
  476. begin
  477. Inc(FLocked);
  478. end;
  479. procedure TPngImageList.Clear;
  480. var
  481. Patch: TMethodPatch;
  482. begin
  483. if TObject(Self) is TPngImageList then begin
  484. //Clear the PngImages collection and the internal imagelist.
  485. BeginUpdate;
  486. try
  487. FPngImages.Clear;
  488. ImageList_Remove(Handle, -1);
  489. Change;
  490. finally
  491. EndUpdate(False);
  492. end;
  493. end
  494. else begin
  495. Patch := FindMethodPatch('Clear');
  496. if Patch <> nil then begin
  497. Patch.BeginInvokeOldMethod;
  498. try
  499. TCustomImageList(Self).Clear;
  500. finally
  501. Patch.FinishInvokeOldMethod;
  502. end;
  503. end;
  504. end;
  505. end;
  506. procedure TPngImageList.CopyPngs;
  507. var
  508. I: Integer;
  509. Png: TPngImage;
  510. Icon: HIcon;
  511. item: TPngImageCollectionItem;
  512. begin
  513. //Are we adding a bunch of images?
  514. if FLocked > 0 then
  515. Exit;
  516. //Copy PNG images to the imagelist. These images will not be stored in the DFM.
  517. ImageList_Remove(Handle, -1);
  518. Handle := ImageList_Create(Width, Height, ILC_COLOR32 or (Integer(Masked) *
  519. ILC_MASK), 0, AllocBy);
  520. Png := TPngImage.Create;
  521. try
  522. for I := 0 to FPngImages.Count - 1 do begin
  523. item := FPngImages.Items[I];
  524. if (item.PngImage = nil) or item.PngImage.Empty then
  525. Continue;
  526. if FEnabledImages or (FPngOptions = []) then begin
  527. Icon := PngToIcon(item.PngImage, item.Background);
  528. end
  529. else begin
  530. //Basically the same as in the DrawPNG function
  531. Png.Assign(item.PngImage);
  532. if pngBlendOnDisabled in FPngOptions then
  533. MakeImageBlended(Png);
  534. if pngGrayscaleOnDisabled in FPngOptions then
  535. MakeImageGrayscale(Png);
  536. Icon := PngToIcon(Png);
  537. end;
  538. ImageList_AddIcon(Handle, Icon);
  539. DestroyIcon(Icon);
  540. end;
  541. finally
  542. Png.Free;
  543. end;
  544. end;
  545. procedure TPngImageList.Delete(Index: Integer);
  546. var
  547. Patch: TMethodPatch;
  548. begin
  549. if TObject(Self) is TPngImageList then begin
  550. //Delete an image from the PngImages collection and from the internal imagelist.
  551. if (Index >= 0) and (Index < Count) then begin
  552. BeginUpdate;
  553. try
  554. FPngImages.Delete(Index);
  555. ImageList_Remove(Handle, Index);
  556. Change;
  557. finally
  558. EndUpdate(False);
  559. end;
  560. end;
  561. end
  562. else begin
  563. Patch := FindMethodPatch('Delete');
  564. if Patch <> nil then begin
  565. Patch.BeginInvokeOldMethod;
  566. try
  567. TCustomImageList(Self).Delete(Index);
  568. finally
  569. Patch.FinishInvokeOldMethod;
  570. end;
  571. end;
  572. end;
  573. end;
  574. //--- End of patched methods ---
  575. procedure TPngImageList.DoDraw(Index: Integer; Canvas: TCanvas; X, Y: Integer; Style: Cardinal; Enabled: Boolean);
  576. var
  577. PaintRect: TRect;
  578. Options: TPngOptions;
  579. Png: TPngImageCollectionItem;
  580. begin
  581. //Draw a PNG directly to the Canvas. This is the preferred method to call,
  582. //because this omits the API calls that use a fixed background.
  583. PaintRect := Bounds(X, Y, Width, Height);
  584. if Enabled then
  585. Options := []
  586. else
  587. Options := FPngOptions;
  588. Png := FPngImages.Items[Index];
  589. if Png <> nil then
  590. DrawPNG(Png.PngImage, Canvas, PaintRect, Options);
  591. end;
  592. procedure TPngImageList.EndUpdate(Update: Boolean);
  593. begin
  594. Dec(FLocked);
  595. if Update and (FLocked = 0) then
  596. CopyPngs;
  597. end;
  598. function TPngImageList.GetHeight: Integer;
  599. begin
  600. Result := inherited Height;
  601. end;
  602. function TPngImageList.GetWidth: Integer;
  603. begin
  604. Result := inherited Width;
  605. end;
  606. procedure TPngImageList.Insert(Index: Integer; Image, Mask: TBitmap);
  607. var
  608. Patch: TMethodPatch;
  609. Png: TPngImage;
  610. begin
  611. if TObject(Self) is TPngImageList then begin
  612. //Insert a new PNG based on the image and its mask.
  613. if Image <> nil then begin
  614. Png := TPngImage.Create;
  615. try
  616. CreatePNG(Image, Mask, Png);
  617. InsertPng(Index, Png);
  618. finally
  619. Png.Free;
  620. end;
  621. end;
  622. end
  623. else begin
  624. Patch := FindMethodPatch('Insert');
  625. if Patch <> nil then begin
  626. Patch.BeginInvokeOldMethod;
  627. try
  628. TCustomImageList(Self).Insert(Index, Image, Mask);
  629. finally
  630. Patch.FinishInvokeOldMethod;
  631. end;
  632. end;
  633. end;
  634. end;
  635. procedure TPngImageList.InsertIcon(Index: Integer; Image: TIcon);
  636. var
  637. Patch: TMethodPatch;
  638. Png: TPngImage;
  639. begin
  640. if TObject(Self) is TPngImageList then begin
  641. //Insert a new PNG based on the image.
  642. if Image <> nil then begin
  643. Png := TPngImage.Create;
  644. try
  645. ConvertToPNG(Image, Png);
  646. InsertPng(Index, Png);
  647. finally
  648. Png.Free;
  649. end;
  650. end;
  651. end
  652. else begin
  653. Patch := FindMethodPatch('InsertIcon');
  654. if Patch <> nil then begin
  655. Patch.BeginInvokeOldMethod;
  656. try
  657. TCustomImageList(Self).InsertIcon(Index, Image);
  658. finally
  659. Patch.FinishInvokeOldMethod;
  660. end;
  661. end;
  662. end;
  663. end;
  664. procedure TPngImageList.InsertPng(Index: Integer; Image: TPngImage; Background:
  665. TColor = clNone);
  666. var
  667. Item: TPngImageCollectionItem;
  668. begin
  669. if Image <> nil then begin
  670. BeginUpdate;
  671. try
  672. Item := PngImages.Insert(Index, True);
  673. Item.PngImage := Image;
  674. Item.Background := Background;
  675. InternalInsertPng(Index, Item.PngImage, Item.Background);
  676. Change;
  677. finally
  678. EndUpdate(False);
  679. end;
  680. end;
  681. end;
  682. procedure TPngImageList.InsertMasked(Index: Integer; Image: TBitmap; MaskColor: TColor);
  683. var
  684. Patch: TMethodPatch;
  685. Png: TPngImage;
  686. begin
  687. if TObject(Self) is TPngImageList then begin
  688. //Insert a new PNG based on the image and a colored mask.
  689. if Image <> nil then begin
  690. Png := TPngImage.Create;
  691. try
  692. CreatePNGMasked(Image, MaskColor, Png);
  693. InsertPng(Index, Png);
  694. finally
  695. Png.Free;
  696. end;
  697. end;
  698. end
  699. else begin
  700. Patch := FindMethodPatch('InsertMasked');
  701. if Patch <> nil then begin
  702. Patch.BeginInvokeOldMethod;
  703. try
  704. TCustomImageList(Self).InsertMasked(Index, Image, MaskColor);
  705. finally
  706. Patch.FinishInvokeOldMethod;
  707. end;
  708. end;
  709. end;
  710. end;
  711. procedure TPngImageList.InternalInsertPng(Index: Integer; const Png: TPngImage;
  712. Background: TColor);
  713. var
  714. I: Integer;
  715. Icon: HICON;
  716. TempList: TPngImageList;
  717. begin
  718. TempList := TPngImageList(TComponentClass(ClassType).Create(nil));
  719. try
  720. TempList.Assign(Self);
  721. ImageList_RemoveAll(Handle);
  722. for I := 0 to Index - 1 do begin
  723. Icon := ImageList_GetIcon(TempList.Handle, I, ILD_NORMAL);
  724. ImageList_AddIcon(Handle, Icon);
  725. DestroyIcon(Icon);
  726. end;
  727. Icon := PngToIcon(Png, Background);
  728. ImageList_AddIcon(Handle, Icon);
  729. DestroyIcon(Icon);
  730. for I := Index to TempList.Count - 1 do begin
  731. Icon := ImageList_GetIcon(TempList.Handle, I, ILD_NORMAL);
  732. ImageList_AddIcon(Handle, Icon);
  733. DestroyIcon(Icon);
  734. end;
  735. finally
  736. TempList.Free;
  737. end;
  738. end;
  739. procedure TPngImageList.InternalAddPng(const Png: TPngImage; Background: TColor
  740. = clNone);
  741. var
  742. Icon: HICON;
  743. begin
  744. Icon := PngToIcon(Png, Background);
  745. try
  746. ImageList_AddIcon(Handle, Icon);
  747. finally
  748. DestroyIcon(Icon);
  749. end;
  750. end;
  751. procedure TPngImageList.Move(CurIndex, NewIndex: Integer);
  752. var
  753. Patch: TMethodPatch;
  754. begin
  755. if TObject(Self) is TPngImageList then begin
  756. //Move an image from one position to another. Don't try doing so in the internal
  757. //imagelist, just recreate it, since this method won't be called very often.
  758. BeginUpdate;
  759. try
  760. ImageList_Remove(Handle, CurIndex);
  761. InternalInsertPng(NewIndex, FPngImages[CurIndex].PngImage,
  762. FPngImages[CurIndex].Background);
  763. FPngImages[CurIndex].Index := NewIndex;
  764. Change;
  765. finally
  766. EndUpdate(False);
  767. end;
  768. end
  769. else begin
  770. Patch := FindMethodPatch('Move');
  771. if Patch <> nil then begin
  772. Patch.BeginInvokeOldMethod;
  773. try
  774. TCustomImageList(Self).Move(CurIndex, NewIndex);
  775. finally
  776. Patch.FinishInvokeOldMethod;
  777. end;
  778. end;
  779. end;
  780. end;
  781. function TPngImageList.PngToIcon(const Png: TPngImage; Background: TColor): HICON;
  782. const
  783. MaxRGBQuads = MaxInt div SizeOf(TRGBQuad) - 1;
  784. type
  785. TRGBQuadArray = array[0..MaxRGBQuads] of TRGBQuad;
  786. PRGBQuadArray = ^TRGBQuadArray;
  787. TBitmapInfo4 = packed record
  788. bmiHeader: TBitmapV4Header;
  789. bmiColors: array[0..0] of TRGBQuad;
  790. end;
  791. function PngToIcon32(Png: TPngImage): HIcon;
  792. var
  793. ImageBits: PRGBQuadArray;
  794. BitmapInfo: TBitmapInfo4;
  795. IconInfo: TIconInfo;
  796. AlphaBitmap: HBitmap;
  797. MaskBitmap: TBitmap;
  798. X, Y: Integer;
  799. AlphaLine: PByteArray;
  800. HasAlpha, HasBitmask: Boolean;
  801. Color, TransparencyColor: TColor;
  802. begin
  803. //Convert a PNG object to an alpha-blended icon resource
  804. ImageBits := nil;
  805. //Allocate a DIB for the color data and alpha channel
  806. with BitmapInfo.bmiHeader do begin
  807. bV4Size := SizeOf(BitmapInfo.bmiHeader);
  808. bV4Width := Png.Width;
  809. bV4Height := Png.Height;
  810. bV4Planes := 1;
  811. bV4BitCount := 32;
  812. bV4V4Compression := BI_BITFIELDS;
  813. bV4SizeImage := 0;
  814. bV4XPelsPerMeter := 0;
  815. bV4YPelsPerMeter := 0;
  816. bV4ClrUsed := 0;
  817. bV4ClrImportant := 0;
  818. bV4RedMask := $00FF0000;
  819. bV4GreenMask := $0000FF00;
  820. bV4BlueMask := $000000FF;
  821. bV4AlphaMask := $FF000000;
  822. end;
  823. AlphaBitmap := CreateDIBSection(0, PBitmapInfo(@BitmapInfo)^,
  824. DIB_RGB_COLORS, Pointer(ImageBits), 0, 0);
  825. try
  826. //Spin through and fill it with a wash of color and alpha.
  827. AlphaLine := nil;
  828. HasAlpha := Png.Header.ColorType in [COLOR_GRAYSCALEALPHA,
  829. COLOR_RGBALPHA];
  830. HasBitmask := Png.TransparencyMode = ptmBit;
  831. TransparencyColor := Png.TransparentColor;
  832. for Y := 0 to Png.Height - 1 do begin
  833. if HasAlpha then
  834. AlphaLine := Png.AlphaScanline[Png.Height - Y - 1];
  835. for X := 0 to Png.Width - 1 do begin
  836. Color := Png.Pixels[X, Png.Height - Y - 1];
  837. ImageBits^[Y * Png.Width + X].rgbRed := Color and $FF;
  838. ImageBits^[Y * Png.Width + X].rgbGreen := Color shr 8 and $FF;
  839. ImageBits^[Y * Png.Width + X].rgbBlue := Color shr 16 and $FF;
  840. if HasAlpha then
  841. ImageBits^[Y * Png.Width + X].rgbReserved := AlphaLine^[X]
  842. else if HasBitmask then
  843. ImageBits^[Y * Png.Width + X].rgbReserved := Integer(Color <>
  844. TransparencyColor) * 255;
  845. end;
  846. end;
  847. //Create an empty mask
  848. MaskBitmap := TBitmap.Create;
  849. try
  850. MaskBitmap.Width := Png.Width;
  851. MaskBitmap.Height := Png.Height;
  852. MaskBitmap.PixelFormat := pf1bit;
  853. MaskBitmap.Canvas.Brush.Color := clBlack;
  854. MaskBitmap.Canvas.FillRect(Rect(0, 0, MaskBitmap.Width,
  855. MaskBitmap.Height));
  856. //Create the alpha blended icon
  857. IconInfo.fIcon := True;
  858. IconInfo.hbmColor := AlphaBitmap;
  859. IconInfo.hbmMask := MaskBitmap.Handle;
  860. Result := CreateIconIndirect(IconInfo);
  861. finally
  862. MaskBitmap.Free;
  863. end;
  864. finally
  865. DeleteObject(AlphaBitmap);
  866. end;
  867. end;
  868. function PngToIcon24(Png: TPngImage; Background: TColor): HIcon;
  869. var
  870. ColorBitmap, MaskBitmap: TBitmap;
  871. X, Y: Integer;
  872. AlphaLine: PByteArray;
  873. IconInfo: TIconInfo;
  874. TransparencyColor: TColor;
  875. begin
  876. ColorBitmap := TBitmap.Create;
  877. MaskBitmap := TBitmap.Create;
  878. try
  879. ColorBitmap.Width := Png.Width;
  880. ColorBitmap.Height := Png.Height;
  881. ColorBitmap.PixelFormat := pf32bit;
  882. MaskBitmap.Width := Png.Width;
  883. MaskBitmap.Height := Png.Height;
  884. MaskBitmap.PixelFormat := pf32bit;
  885. //Draw the color bitmap
  886. ColorBitmap.Canvas.Brush.Color := Background;
  887. ColorBitmap.Canvas.FillRect(Rect(0, 0, Png.Width, Png.Height));
  888. Png.Draw(ColorBitmap.Canvas, Rect(0, 0, Png.Width, Png.Height));
  889. //Create the mask bitmap
  890. if Png.Header.ColorType in [COLOR_GRAYSCALEALPHA, COLOR_RGBALPHA] then
  891. for Y := 0 to Png.Height - 1 do begin
  892. AlphaLine := Png.AlphaScanline[Y];
  893. for X := 0 to Png.Width - 1 do
  894. if AlphaLine^[X] = 0 then
  895. SetPixelV(MaskBitmap.Canvas.Handle, X, Y, clWhite)
  896. else
  897. SetPixelV(MaskBitmap.Canvas.Handle, X, Y, clBlack);
  898. end
  899. else if Png.TransparencyMode = ptmBit then begin
  900. TransparencyColor := Png.TransparentColor;
  901. for Y := 0 to Png.Height - 1 do
  902. for X := 0 to Png.Width - 1 do
  903. if Png.Pixels[X, Y] = TransparencyColor then
  904. SetPixelV(MaskBitmap.Canvas.Handle, X, Y, clWhite)
  905. else
  906. SetPixelV(MaskBitmap.Canvas.Handle, X, Y, clBlack);
  907. end;
  908. //Create the icon
  909. IconInfo.fIcon := True;
  910. IconInfo.hbmColor := ColorBitmap.Handle;
  911. IconInfo.hbmMask := MaskBitmap.Handle;
  912. Result := CreateIconIndirect(IconInfo);
  913. finally
  914. ColorBitmap.Free;
  915. MaskBitmap.Free;
  916. end;
  917. end;
  918. begin
  919. if GetComCtlVersion >= ComCtlVersionIE6 then begin
  920. //Windows XP or later, using the modern method: convert every PNG to
  921. //an icon resource with alpha channel
  922. Result := PngToIcon32(Png);
  923. end
  924. else begin
  925. //No Windows XP, using the legacy method: copy every PNG to a normal
  926. //bitmap using a fixed background color
  927. Result := PngToIcon24(Png, Background);
  928. end;
  929. end;
  930. procedure TPngImageList.ReadData(Stream: TStream);
  931. begin
  932. // if not (csReading in ComponentState) then
  933. // inherited;
  934. //Make sure nothing gets read from the DFM
  935. end;
  936. procedure TPngImageList.Replace(Index: Integer; Image, Mask: TBitmap);
  937. var
  938. Item: TPngImageCollectionItem;
  939. Patch: TMethodPatch;
  940. Icon: HICON;
  941. begin
  942. if TObject(Self) is TPngImageList then begin
  943. //Replace an existing PNG based with a new image and its mask.
  944. if Image <> nil then begin
  945. BeginUpdate;
  946. try
  947. Item := FPngImages[Index];
  948. Item.FPngImage.Free;
  949. CreatePNG(Image, Mask, Item.FPngImage);
  950. Icon := PngToIcon(Item.PngImage, Item.Background);
  951. ImageList_ReplaceIcon(Handle, Index, Icon);
  952. DestroyIcon(Icon);
  953. Change;
  954. finally
  955. EndUpdate(False);
  956. end;
  957. end;
  958. end
  959. else begin
  960. Patch := FindMethodPatch('Replace');
  961. if Patch <> nil then begin
  962. Patch.BeginInvokeOldMethod;
  963. try
  964. TCustomImageList(Self).Replace(Index, Image, Mask);
  965. finally
  966. Patch.FinishInvokeOldMethod;
  967. end;
  968. end;
  969. end;
  970. end;
  971. procedure TPngImageList.ReplaceIcon(Index: Integer; Image: TIcon);
  972. var
  973. Item: TPngImageCollectionItem;
  974. Patch: TMethodPatch;
  975. Icon: HICON;
  976. begin
  977. if TObject(Self) is TPngImageList then begin
  978. //Replace an existing PNG based with a new image.
  979. if Image <> nil then begin
  980. BeginUpdate;
  981. try
  982. Item := FPngImages[Index];
  983. Item.FPngImage.Free;
  984. ConvertToPNG(Image, Item.FPngImage);
  985. Icon := PngToIcon(Item.PngImage, Item.Background);
  986. ImageList_ReplaceIcon(Handle, Index, Icon);
  987. DestroyIcon(Icon);
  988. Change;
  989. finally
  990. EndUpdate(False);
  991. end;
  992. end
  993. end
  994. else begin
  995. Patch := FindMethodPatch('ReplaceIcon');
  996. if Patch <> nil then begin
  997. Patch.BeginInvokeOldMethod;
  998. try
  999. TCustomImageList(Self).ReplaceIcon(Index, Image);
  1000. finally
  1001. Patch.FinishInvokeOldMethod;
  1002. end;
  1003. end;
  1004. end;
  1005. end;
  1006. procedure TPngImageList.ReplaceMasked(Index: Integer; NewImage: TBitmap; MaskColor: TColor);
  1007. var
  1008. Item: TPngImageCollectionItem;
  1009. Patch: TMethodPatch;
  1010. Icon: HICON;
  1011. begin
  1012. if TObject(Self) is TPngImageList then begin
  1013. //Replace an existing PNG based with a new image and a colored mask.
  1014. if NewImage <> nil then begin
  1015. BeginUpdate;
  1016. try
  1017. Item := FPngImages[Index];
  1018. Item.FPngImage.Free;
  1019. CreatePNGMasked(NewImage, MaskColor, Item.FPngImage);
  1020. Icon := PngToIcon(Item.PngImage, Item.Background);
  1021. ImageList_ReplaceIcon(Handle, Index, Icon);
  1022. DestroyIcon(Icon);
  1023. Change;
  1024. finally
  1025. EndUpdate(False);
  1026. end;
  1027. end
  1028. end
  1029. else begin
  1030. Patch := FindMethodPatch('ReplaceMasked');
  1031. if Patch <> nil then begin
  1032. Patch.BeginInvokeOldMethod;
  1033. try
  1034. TCustomImageList(Self).ReplaceMasked(Index, NewImage, MaskColor);
  1035. finally
  1036. Patch.FinishInvokeOldMethod;
  1037. end;
  1038. end;
  1039. end;
  1040. end;
  1041. procedure TPngImageList.SetEnabledImages(const Value: Boolean);
  1042. begin
  1043. if FEnabledImages xor Value then begin
  1044. FEnabledImages := Value;
  1045. CopyPngs;
  1046. end;
  1047. end;
  1048. procedure TPngImageList.SetHeight(const Value: Integer);
  1049. begin
  1050. if inherited Height <> Value then begin
  1051. inherited Height := Value;
  1052. Clear;
  1053. end;
  1054. end;
  1055. procedure TPngImageList.SetPngImages(const Value: TPngImageCollectionItems);
  1056. begin
  1057. if FPngImages <> Value then begin
  1058. FPngImages.Assign(Value);
  1059. Change;
  1060. end;
  1061. end;
  1062. procedure TPngImageList.SetPngOptions(const Value: TPngOptions);
  1063. begin
  1064. if FPngOptions <> Value then begin
  1065. FPngOptions := Value;
  1066. CopyPngs;
  1067. end;
  1068. end;
  1069. procedure TPngImageList.SetWidth(const Value: Integer);
  1070. begin
  1071. if inherited Width <> Value then begin
  1072. inherited Width := Value;
  1073. Clear;
  1074. end;
  1075. end;
  1076. procedure TPngImageList.WriteData(Stream: TStream);
  1077. begin
  1078. if IDE_WriteData_Hack and not (csWriting in ComponentState) then
  1079. inherited;
  1080. //Make sure nothing gets written to the DFM
  1081. end;
  1082. { TPngImageCollection }
  1083. constructor TPngImageCollection.Create(AOwner: TComponent);
  1084. begin
  1085. inherited Create(AOwner);
  1086. FItems := TPngImageCollectionItems.Create(Self);
  1087. end;
  1088. destructor TPngImageCollection.Destroy;
  1089. begin
  1090. FItems.Free;
  1091. inherited Destroy;
  1092. end;
  1093. { TPngImageCollectionItems }
  1094. constructor TPngImageCollectionItems.Create(AOwner: TPersistent);
  1095. begin
  1096. inherited Create(TPngImageCollectionItem);
  1097. FOwner := AOwner;
  1098. end;
  1099. function TPngImageCollectionItems.Add(DontCreatePNG: Boolean = False): TPngImageCollectionItem;
  1100. begin
  1101. {$WARN SYMBOL_DEPRECATED OFF}
  1102. Result := TPngImageCollectionItem.Create(Self, DontCreatePNG);
  1103. Added(TCollectionItem(Result));
  1104. end;
  1105. procedure TPngImageCollectionItems.Assign(Source: TPersistent);
  1106. begin
  1107. inherited Assign(Source);
  1108. Update(nil);
  1109. end;
  1110. function TPngImageCollectionItems.GetItem(Index: Integer): TPngImageCollectionItem;
  1111. begin
  1112. if (Index >= 0) and (Index < Count) then
  1113. Result := TPngImageCollectionItem(inherited Items[Index])
  1114. else
  1115. Result := nil;
  1116. end;
  1117. function TPngImageCollectionItems.GetOwner: TPersistent;
  1118. begin
  1119. Result := FOwner;
  1120. end;
  1121. function TPngImageCollectionItems.Insert(Index: Integer; DontCreatePNG: Boolean = False): TPngImageCollectionItem;
  1122. begin
  1123. Result := Add(DontCreatePNG);
  1124. Result.Index := Index;
  1125. end;
  1126. procedure TPngImageCollectionItems.SetItem(Index: Integer; const Value: TPngImageCollectionItem);
  1127. begin
  1128. if (Index >= 0) and (Index < Count) then
  1129. inherited Items[Index] := Value;
  1130. end;
  1131. procedure TPngImageCollectionItems.Update(Item: TCollectionItem);
  1132. begin
  1133. inherited Update(Item);
  1134. if FOwner is TPngImageList then
  1135. TPngImageList(FOwner).CopyPngs;
  1136. end;
  1137. constructor TPngImageCollectionItem.Create(Collection: TCollection);
  1138. begin
  1139. inherited Create(Collection);
  1140. FPngImage := TPngImage.Create;
  1141. FName := Format('PngImage%d', [Index]);
  1142. FBackground := clBtnFace;
  1143. end;
  1144. constructor TPngImageCollectionItem.Create(Collection: TCollection; DontCreatePNG: Boolean = False);
  1145. begin
  1146. inherited Create(Collection);
  1147. if DontCreatePng then
  1148. FPngImage := nil
  1149. else
  1150. FPngImage := TPngImage.Create;
  1151. FName := Format('PngImage%d', [Index]);
  1152. FBackground := clBtnFace;
  1153. end;
  1154. destructor TPngImageCollectionItem.Destroy;
  1155. begin
  1156. FPngImage.Free;
  1157. inherited Destroy;
  1158. end;
  1159. procedure TPngImageCollectionItem.Assign(Source: TPersistent);
  1160. begin
  1161. if Source is TPngImageCollectionItem then begin
  1162. PngImage.Assign(TPngImageCollectionItem(Source).PngImage);
  1163. Background := TPngImageCollectionItem(Source).Background;
  1164. Name := TPngImageCollectionItem(Source).Name;
  1165. end
  1166. else
  1167. inherited Assign(Source);
  1168. end;
  1169. { TPngImageCollectionItem }
  1170. procedure TPngImageCollectionItem.AssignTo(Dest: TPersistent);
  1171. begin
  1172. inherited AssignTo(Dest);
  1173. if (Dest is TPngImageCollectionItem) then
  1174. TPngImageCollectionItem(Dest).PngImage := PngImage;
  1175. end;
  1176. function TPngImageCollectionItem.Duplicate: TPngImage;
  1177. begin
  1178. Result := TPngImage.Create;
  1179. Result.Assign(FPngImage);
  1180. end;
  1181. function TPngImageCollectionItem.GetDisplayName: string;
  1182. begin
  1183. if Length(FName) = 0 then
  1184. Result := inherited GetDisplayName
  1185. else
  1186. Result := FName;
  1187. end;
  1188. procedure TPngImageCollectionItem.SetBackground(const Value: TColor);
  1189. begin
  1190. if FBackground <> Value then begin
  1191. FBackground := Value;
  1192. Changed(False);
  1193. end;
  1194. end;
  1195. procedure TPngImageCollectionItem.SetPngImage(const Value: TPngImage);
  1196. begin
  1197. if FPngImage = nil then
  1198. FPngImage := TPngImage.Create;
  1199. FPngImage.Assign(Value);
  1200. Changed(False);
  1201. end;
  1202. initialization
  1203. finalization
  1204. MethodPatches.Free;
  1205. end.