PngFunctions.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. unit PngFunctions;
  2. interface
  3. uses
  4. Windows, Graphics, ImgList, Contnrs, pngimage;
  5. {$IF RTLVersion < 20.0 }
  6. {$IF RTLVersion < 15.0 }
  7. PngComponents are only compatible with Delphi 7 and higher!
  8. {$IFEND}
  9. type
  10. TPngImage = TPNGObject;
  11. {$IFEND}
  12. type
  13. TPngOption = (pngBlendOnDisabled, pngGrayscaleOnDisabled);
  14. TPngOptions = set of TPngOption;
  15. TRGBLine = array[Word] of TRGBTriple;
  16. PRGBLine = ^TRGBLine;
  17. TRGBALine = array[Word] of TRGBQuad;
  18. PRGBALine = ^TRGBALine;
  19. procedure MakeImageBlended(Image: TPngImage; Amount: Byte = 127);
  20. procedure MakeImageGrayscale(Image: TPngImage; Amount: Byte = 255);
  21. procedure DrawPNG(Png: TPngImage; Canvas: TCanvas; const ARect: TRect; const Options: TPngOptions);
  22. procedure ConvertToPNG(Source: TGraphic; Dest: TPngImage);
  23. procedure CreatePNG(Color, Mask: TBitmap; Dest: TPngImage; InverseMask: Boolean = False);
  24. procedure CreatePNGMasked(Bitmap: TBitmap; Mask: TColor; Dest: TPngImage);
  25. procedure CopyImageFromImageList(Dest: TPngImage; ImageList: TCustomImageList; Index: Integer);
  26. procedure SlicePNG(JoinedPNG: TPngImage; Columns, Rows: Integer; out SlicedPNGs: TObjectList);
  27. implementation
  28. uses
  29. SysUtils, PngImageList;
  30. function ColorToTriple(Color: TColor): TRGBTriple;
  31. var
  32. ColorRGB: Longint;
  33. begin
  34. ColorRGB := ColorToRGB(Color);
  35. Result.rgbtBlue := ColorRGB shr 16 and $FF;
  36. Result.rgbtGreen := ColorRGB shr 8 and $FF;
  37. Result.rgbtRed := ColorRGB and $FF;
  38. end;
  39. procedure MakeImageBlended(Image: TPngImage; Amount: Byte = 127);
  40. procedure ForceAlphachannel(BitTransparency: Boolean; TransparentColor: TColor);
  41. var
  42. Assigner: TBitmap;
  43. Temp: TPngImage;
  44. X, Y: Integer;
  45. Line: pngimage.PByteArray;
  46. Current: TColor;
  47. begin
  48. //Not all formats of PNG support an alpha-channel (paletted images for example),
  49. //so with this function, I simply recreate the PNG as being 32-bits, effectivly
  50. //forcing an alpha-channel on it.
  51. Temp := TPngImage.Create;
  52. try
  53. Assigner := TBitmap.Create;
  54. try
  55. Assigner.Width := Image.Width;
  56. Assigner.Height := Image.Height;
  57. Temp.Assign(Assigner);
  58. finally
  59. Assigner.Free;
  60. end;
  61. Temp.CreateAlpha;
  62. for Y := 0 to Image.Height - 1 do begin
  63. Line := Temp.AlphaScanline[Y];
  64. for X := 0 to Image.Width - 1 do begin
  65. Current := Image.Pixels[X, Y];
  66. Temp.Pixels[X, Y] := Current;
  67. if BitTransparency and (Current = TransparentColor) then
  68. Line[X] := 0
  69. else
  70. Line[X] := Amount;
  71. end;
  72. end;
  73. Image.Assign(Temp);
  74. finally
  75. Temp.Free;
  76. end;
  77. end;
  78. var
  79. X, Y: Integer;
  80. Line: pngimage.PByteArray;
  81. Forced: Boolean;
  82. TransparentColor: TColor;
  83. BitTransparency: Boolean;
  84. begin
  85. //If the PNG doesn't have an alpha channel, then add one
  86. BitTransparency := Image.TransparencyMode = ptmBit;
  87. TransparentColor := Image.TransparentColor;
  88. Forced := False;
  89. if not (Image.Header.ColorType in [COLOR_RGBALPHA, COLOR_GRAYSCALEALPHA]) then begin
  90. Forced := Image.Header.ColorType in [COLOR_GRAYSCALE, COLOR_PALETTE];
  91. if Forced then
  92. ForceAlphachannel(BitTransparency, TransparentColor)
  93. else
  94. Image.CreateAlpha;
  95. end;
  96. //Divide the alpha values by 2
  97. if not Forced and (Image.Header.ColorType in [COLOR_RGBALPHA, COLOR_GRAYSCALEALPHA]) then begin
  98. for Y := 0 to Image.Height - 1 do begin
  99. Line := Image.AlphaScanline[Y];
  100. for X := 0 to Image.Width - 1 do begin
  101. if BitTransparency and (Image.Pixels[X, Y] = TransparentColor) then
  102. Line[X] := 0
  103. else
  104. Line[X] := Round(Line[X] / 256 * (Amount + 1));
  105. end;
  106. end;
  107. end;
  108. end;
  109. procedure MakeImageGrayscale(Image: TPngImage; Amount: Byte = 255);
  110. procedure GrayscaleRGB(var R, G, B: Byte);
  111. { Performance optimized version without floating point operations by Christian Budde }
  112. var
  113. X: Byte;
  114. begin
  115. X := (R * 77 + G * 150 + B * 29) shr 8;
  116. R := ((R * (255 - Amount)) + (X * Amount) + 128) shr 8;
  117. G := ((G * (255 - Amount)) + (X * Amount) + 128) shr 8;
  118. B := ((B * (255 - Amount)) + (X * Amount) + 128) shr 8;
  119. (* original code
  120. X := Round(R * 0.30 + G * 0.59 + B * 0.11);
  121. R := Round(R / 256 * (256 - Amount - 1)) + Round(X / 256 * (Amount + 1));
  122. G := Round(G / 256 * (256 - Amount - 1)) + Round(X / 256 * (Amount + 1));
  123. B := Round(B / 256 * (256 - Amount - 1)) + Round(X / 256 * (Amount + 1));
  124. *)
  125. end;
  126. var
  127. X, Y, PalCount: Integer;
  128. Line: PRGBLine;
  129. PaletteHandle: HPalette;
  130. Palette: array[Byte] of TPaletteEntry;
  131. begin
  132. //Don't do anything if the image is already a grayscaled one
  133. if not (Image.Header.ColorType in [COLOR_GRAYSCALE, COLOR_GRAYSCALEALPHA]) then begin
  134. if Image.Header.ColorType = COLOR_PALETTE then begin
  135. //Grayscale every palette entry
  136. PaletteHandle := Image.Palette;
  137. PalCount := GetPaletteEntries(PaletteHandle, 0, 256, Palette);
  138. for X := 0 to PalCount - 1 do
  139. GrayscaleRGB(Palette[X].peRed, Palette[X].peGreen, Palette[X].peBlue);
  140. SetPaletteEntries(PaletteHandle, 0, PalCount, Palette);
  141. Image.Palette := PaletteHandle;
  142. end
  143. else begin
  144. //Grayscale every pixel
  145. for Y := 0 to Image.Height - 1 do begin
  146. Line := Image.Scanline[Y];
  147. for X := 0 to Image.Width - 1 do
  148. GrayscaleRGB(Line[X].rgbtRed, Line[X].rgbtGreen, Line[X].rgbtBlue);
  149. end;
  150. end;
  151. end;
  152. end;
  153. procedure DrawPNG(Png: TPngImage; Canvas: TCanvas; const ARect: TRect; const Options: TPngOptions);
  154. var
  155. PngCopy: TPngImage;
  156. begin
  157. if Options <> [] then begin
  158. PngCopy := TPngImage.Create;
  159. try
  160. PngCopy.Assign(Png);
  161. if pngBlendOnDisabled in Options then
  162. MakeImageBlended(PngCopy);
  163. if pngGrayscaleOnDisabled in Options then
  164. MakeImageGrayscale(PngCopy);
  165. PngCopy.Draw(Canvas, ARect);
  166. finally
  167. PngCopy.Free;
  168. end;
  169. end
  170. else begin
  171. Png.Draw(Canvas, ARect);
  172. end;
  173. end;
  174. procedure ConvertToPNG(Source: TGraphic; Dest: TPngImage);
  175. var
  176. MaskLines: array of pngimage.PByteArray;
  177. function ColorToTriple(const Color: TColor): TRGBTriple;
  178. begin
  179. Result.rgbtBlue := Color shr 16 and $FF;
  180. Result.rgbtGreen := Color shr 8 and $FF;
  181. Result.rgbtRed := Color and $FF;
  182. end;
  183. procedure GetAlphaMask(SourceColor: TBitmap);
  184. type
  185. TBitmapInfoV4 = packed record
  186. bmiHeader: TBitmapV4Header; //Otherwise I may not get per-pixel alpha values.
  187. bmiColors: array[0..2] of TRGBQuad; // reserve space for color lookup table
  188. end;
  189. var
  190. Bits: PRGBALine;
  191. { The BitmapInfo parameter to GetDIBits is delared as var parameter. So instead of casting around, we simply use
  192. the absolute directive to refer to the same memory area. }
  193. BitmapInfo: TBitmapInfoV4;
  194. BitmapInfoFake: TBitmapInfo absolute BitmapInfo;
  195. I, X, Y: Integer;
  196. HasAlpha: Boolean;
  197. BitsSize: Integer;
  198. bmpDC: HDC;
  199. bmpHandle: HBITMAP;
  200. begin
  201. BitsSize := 4 * SourceColor.Width * SourceColor.Height;
  202. Bits := AllocMem(BitsSize);
  203. try
  204. FillChar(BitmapInfo, SizeOf(BitmapInfo), 0);
  205. BitmapInfo.bmiHeader.bV4Size := SizeOf(BitmapInfo.bmiHeader);
  206. BitmapInfo.bmiHeader.bV4Width := SourceColor.Width;
  207. BitmapInfo.bmiHeader.bV4Height := -SourceColor.Height; //Otherwise the image is upside down.
  208. BitmapInfo.bmiHeader.bV4Planes := 1;
  209. BitmapInfo.bmiHeader.bV4BitCount := 32;
  210. BitmapInfo.bmiHeader.bV4V4Compression := BI_BITFIELDS;
  211. BitmapInfo.bmiHeader.bV4SizeImage := BitsSize;
  212. BitmapInfo.bmiColors[0].rgbRed := 255;
  213. BitmapInfo.bmiColors[1].rgbGreen := 255;
  214. BitmapInfo.bmiColors[2].rgbBlue := 255;
  215. { Getting the bitmap Handle will invalidate the Canvas.Handle, so it is important to retrieve them in the correct
  216. order. As parameter evaluation order is undefined and differs between Win32 and Win64, we get invalid values
  217. for Canvas.Handle when we use those properties directly in the call to GetDIBits. }
  218. bmpHandle := SourceColor.Handle;
  219. bmpDC := SourceColor.Canvas.Handle;
  220. if GetDIBits(bmpDC, bmpHandle, 0, SourceColor.Height, Bits, BitmapInfoFake, DIB_RGB_COLORS) > 0 then begin
  221. //Because Win32 API is a piece of crap when it comes to icons, I have to check
  222. //whether an has an alpha-channel the hard way.
  223. HasAlpha := False;
  224. for I := 0 to (SourceColor.Height * SourceColor.Width) - 1 do begin
  225. if Bits[I].rgbReserved <> 0 then begin
  226. HasAlpha := True;
  227. Break;
  228. end;
  229. end;
  230. if HasAlpha then begin
  231. //OK, so not all alpha-values are 0, which indicates the existence of an
  232. //alpha-channel.
  233. I := 0;
  234. for Y := 0 to SourceColor.Height - 1 do
  235. for X := 0 to SourceColor.Width - 1 do begin
  236. MaskLines[Y][X] := Bits[I].rgbReserved;
  237. Inc(I);
  238. end;
  239. end;
  240. end;
  241. finally
  242. FreeMem(Bits, BitsSize);
  243. end;
  244. end;
  245. function WinXPOrHigher: Boolean;
  246. var
  247. Info: TOSVersionInfo;
  248. begin
  249. Info.dwOSVersionInfoSize := SizeOf(Info);
  250. GetVersionEx(Info);
  251. Result := (Info.dwPlatformId = VER_PLATFORM_WIN32_NT) and
  252. ((Info.dwMajorVersion > 5) or
  253. ((Info.dwMajorVersion = 5) and (Info.dwMinorVersion >= 1)));
  254. end;
  255. var
  256. Temp, SourceColor, SourceMask: TBitmap;
  257. X, Y: Integer;
  258. Line: PRGBLine;
  259. MaskLine, AlphaLine: pngimage.PByteArray;
  260. TransparentColor, CurrentColor: TColor;
  261. IconInfo: TIconInfo;
  262. AlphaNeeded: Boolean;
  263. begin
  264. Assert(Dest <> nil, 'Dest is nil!');
  265. //A PNG does not have to be converted
  266. if Source is TPngImage then begin
  267. Dest.Assign(Source);
  268. Exit;
  269. end;
  270. AlphaNeeded := False;
  271. Temp := TBitmap.Create;
  272. SetLength(MaskLines, Source.Height);
  273. for Y := 0 to Source.Height - 1 do begin
  274. MaskLines[Y] := AllocMem(Source.Width);
  275. FillMemory(MaskLines[Y], Source.Width, 255);
  276. end;
  277. try
  278. //Initialize intermediate color bitmap
  279. Temp.Width := Source.Width;
  280. Temp.Height := Source.Height;
  281. Temp.PixelFormat := pf24bit;
  282. //Now figure out the transparency
  283. if Source is TBitmap then begin
  284. if Source.Transparent then begin
  285. //TBitmap is just about comparing the drawn colors against the TransparentColor
  286. if TBitmap(Source).TransparentMode = tmFixed then
  287. TransparentColor := TBitmap(Source).TransparentColor
  288. else
  289. TransparentColor := TBitmap(Source).Canvas.Pixels[0, Source.Height - 1];
  290. for Y := 0 to Temp.Height - 1 do begin
  291. Line := Temp.ScanLine[Y];
  292. MaskLine := MaskLines[Y];
  293. for X := 0 to Temp.Width - 1 do begin
  294. CurrentColor := GetPixel(TBitmap(Source).Canvas.Handle, X, Y);
  295. if CurrentColor = TransparentColor then begin
  296. MaskLine^[X] := 0;
  297. AlphaNeeded := True;
  298. end;
  299. Line[X] := ColorToTriple(CurrentColor);
  300. end;
  301. end;
  302. end
  303. else begin
  304. Temp.Canvas.Draw(0, 0, Source);
  305. end;
  306. end
  307. else if Source is TIcon then begin
  308. //TIcon is more complicated, because there are bitmasked (classic) icons and
  309. //alphablended (modern) icons. Not to forget about the "inverse" color.
  310. GetIconInfo(TIcon(Source).Handle, IconInfo);
  311. SourceColor := TBitmap.Create;
  312. SourceMask := TBitmap.Create;
  313. try
  314. SourceColor.Handle := IconInfo.hbmColor;
  315. SourceMask.Handle := IconInfo.hbmMask;
  316. Temp.Canvas.Draw(0, 0, SourceColor);
  317. for Y := 0 to Temp.Height - 1 do begin
  318. MaskLine := MaskLines[Y];
  319. for X := 0 to Temp.Width - 1 do begin
  320. if GetPixel(SourceMask.Canvas.Handle, X, Y) <> 0 then begin
  321. MaskLine^[X] := 0;
  322. AlphaNeeded := True;
  323. end;
  324. end;
  325. end;
  326. if (GetDeviceCaps(SourceColor.Canvas.Handle, BITSPIXEL) = 32) and WinXPOrHigher then begin
  327. //This doesn't neccesarily mean we actually have 32bpp in the icon, because the
  328. //bpp of an icon is always the same as the display settings, regardless of the
  329. //actual color depth of the icon :(
  330. AlphaNeeded := True;
  331. GetAlphaMask(SourceColor);
  332. end;
  333. //This still doesn't work for alphablended icons...
  334. finally
  335. SourceColor.Free;
  336. SourceMask.Free
  337. end;
  338. end;
  339. //And finally, assign the destination PNG image
  340. Dest.Assign(Temp);
  341. if AlphaNeeded then begin
  342. Dest.CreateAlpha;
  343. for Y := 0 to Dest.Height - 1 do begin
  344. AlphaLine := Dest.AlphaScanline[Y];
  345. CopyMemory(AlphaLine, MaskLines[Y], Temp.Width);
  346. end;
  347. end;
  348. finally
  349. for Y := 0 to Source.Height - 1 do
  350. FreeMem(MaskLines[Y], Source.Width);
  351. Temp.Free;
  352. end;
  353. end;
  354. procedure CreatePNG(Color, Mask: TBitmap; Dest: TPngImage; InverseMask: Boolean = False);
  355. var
  356. Temp: TBitmap;
  357. Line: pngimage.PByteArray;
  358. X, Y: Integer;
  359. begin
  360. Assert(Dest <> nil, 'Dest is nil!');
  361. //Create a PNG from two separate color and mask bitmaps. InverseMask should be
  362. //True if white means transparent, and black means opaque.
  363. if not (Color.PixelFormat in [pf24bit, pf32bit]) then begin
  364. Temp := TBitmap.Create;
  365. try
  366. Temp.Assign(Color);
  367. Temp.PixelFormat := pf24bit;
  368. Dest.Assign(Temp);
  369. finally
  370. Temp.Free;
  371. end;
  372. end
  373. else begin
  374. Dest.Assign(Color);
  375. end;
  376. //Copy the alpha channel.
  377. Dest.CreateAlpha;
  378. for Y := 0 to Dest.Height - 1 do begin
  379. Line := Dest.AlphaScanline[Y];
  380. for X := 0 to Dest.Width - 1 do begin
  381. if InverseMask then
  382. Line[X] := 255 - (GetPixel(Mask.Canvas.Handle, X, Y) and $FF)
  383. else
  384. Line[X] := GetPixel(Mask.Canvas.Handle, X, Y) and $FF;
  385. end;
  386. end;
  387. end;
  388. procedure CreatePNGMasked(Bitmap: TBitmap; Mask: TColor; Dest: TPngImage);
  389. var
  390. Temp: TBitmap;
  391. Line: pngimage.PByteArray;
  392. X, Y: Integer;
  393. begin
  394. Assert(Dest <> nil, 'Dest is nil!');
  395. //Create a PNG from two separate color and mask bitmaps. InverseMask should be
  396. //True if white means transparent, and black means opaque.
  397. if not (Bitmap.PixelFormat in [pf24bit, pf32bit]) then begin
  398. Temp := TBitmap.Create;
  399. try
  400. Temp.Assign(Bitmap);
  401. Temp.PixelFormat := pf24bit;
  402. Dest.Assign(Temp);
  403. finally
  404. Temp.Free;
  405. end;
  406. end
  407. else begin
  408. Dest.Assign(Bitmap);
  409. end;
  410. //Copy the alpha channel.
  411. Dest.CreateAlpha;
  412. for Y := 0 to Dest.Height - 1 do begin
  413. Line := Dest.AlphaScanline[Y];
  414. for X := 0 to Dest.Width - 1 do
  415. Line[X] := Integer(TColor(GetPixel(Bitmap.Canvas.Handle, X, Y)) <> Mask) * $FF;
  416. end;
  417. end;
  418. procedure CopyImageFromImageList(Dest: TPngImage; ImageList: TCustomImageList; Index: Integer);
  419. var
  420. Icon: TIcon;
  421. IconInfo: TIconInfo;
  422. ColorBitmap, MaskBitmap: TBitmap;
  423. X, Y: Integer;
  424. AlphaLine: pngimage.PByteArray;
  425. Png: TPngImageCollectionItem;
  426. begin
  427. if ImageList is TPngImageList then begin
  428. //This is easy, just copy the PNG object from the imagelist to the PNG object
  429. //from the button
  430. Png := TPNGImageList(ImageList).PngImages[Index];
  431. if Png <> nil then
  432. Dest.Assign(Png.PngImage);
  433. end
  434. else begin
  435. Icon := TIcon.Create;
  436. ColorBitmap := TBitmap.Create;
  437. MaskBitmap := TBitmap.Create;
  438. try
  439. //Try to copy an icon to a PNG object, including transparency
  440. ImageList.GetIcon(Index, Icon);
  441. if GetIconInfo(Icon.Handle, IconInfo) then begin
  442. //First, pump the colors into the PNG object
  443. ColorBitmap.Handle := IconInfo.hbmColor;
  444. ColorBitmap.PixelFormat := pf24bit;
  445. Dest.Assign(ColorBitmap);
  446. //Finally, copy the transparency
  447. Dest.CreateAlpha;
  448. MaskBitmap.Handle := IconInfo.hbmMask;
  449. for Y := 0 to Dest.Height - 1 do begin
  450. AlphaLine := Dest.AlphaScanline[Y];
  451. for X := 0 to Dest.Width - 1 do
  452. AlphaLine^[X] := Integer(GetPixel(MaskBitmap.Canvas.Handle, X, Y) = COLORREF(clBlack)) * $FF;
  453. end;
  454. end;
  455. finally
  456. MaskBitmap.Free;
  457. ColorBitmap.Free;
  458. Icon.Free;
  459. end;
  460. end;
  461. end;
  462. procedure SlicePNG(JoinedPNG: TPngImage; Columns, Rows: Integer; out SlicedPNGs: TObjectList);
  463. var
  464. X, Y, ImageX, ImageY, OffsetX, OffsetY: Integer;
  465. Width, Height: Integer;
  466. Bitmap: TBitmap;
  467. BitmapLine: PRGBLine;
  468. AlphaLineA, AlphaLineB: pngimage.PByteArray;
  469. PNG: TPngImage;
  470. begin
  471. //This function slices a large PNG file (e.g. an image with all images for a
  472. //toolbar) into smaller, equally-sized pictures.
  473. SlicedPNGs := TObjectList.Create(False);
  474. Width := JoinedPNG.Width div Columns;
  475. Height := JoinedPNG.Height div Rows;
  476. //Loop through the columns and rows to create each individual image
  477. for ImageY := 0 to Rows - 1 do begin
  478. for ImageX := 0 to Columns - 1 do begin
  479. OffsetX := ImageX * Width;
  480. OffsetY := ImageY * Height;
  481. Bitmap := TBitmap.Create;
  482. try
  483. Bitmap.Width := Width;
  484. Bitmap.Height := Height;
  485. Bitmap.PixelFormat := pf24bit;
  486. //Copy the color information into a temporary bitmap. We can't use TPngImage.Draw
  487. //here, because that would combine the color and alpha values.
  488. for Y := 0 to Bitmap.Height - 1 do begin
  489. BitmapLine := Bitmap.Scanline[Y];
  490. for X := 0 to Bitmap.Width - 1 do
  491. BitmapLine[X] := ColorToTriple(JoinedPNG.Pixels[X + OffsetX, Y + OffsetY]);
  492. end;
  493. PNG := TPngImage.Create;
  494. PNG.Assign(Bitmap);
  495. if JoinedPNG.Header.ColorType in [COLOR_GRAYSCALEALPHA, COLOR_RGBALPHA] then begin
  496. //Copy the alpha channel
  497. PNG.CreateAlpha;
  498. for Y := 0 to PNG.Height - 1 do begin
  499. AlphaLineA := JoinedPNG.AlphaScanline[Y + OffsetY];
  500. AlphaLineB := PNG.AlphaScanline[Y];
  501. for X := 0 to PNG.Width - 1 do
  502. AlphaLineB[X] := AlphaLineA[X + OffsetX];
  503. end;
  504. end;
  505. SlicedPNGs.Add(PNG);
  506. finally
  507. Bitmap.Free;
  508. end;
  509. end;
  510. end;
  511. end;
  512. {$IF RTLVersion >= 20.0 }
  513. type
  514. TPNGObject = class(TPngImage);
  515. initialization
  516. TPicture.RegisterFileFormat('', '', TPNGObject);
  517. finalization
  518. TPicture.UnregisterGraphicClass(TPNGObject);
  519. {$IFEND}
  520. end.