ImagingFmx.pas 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. {
  2. Vampyre Imaging Library
  3. by Marek Mauder
  4. https://github.com/galfar/imaginglib
  5. https://imaginglib.sourceforge.io
  6. - - - - -
  7. This Source Code Form is subject to the terms of the Mozilla Public
  8. License, v. 2.0. If a copy of the MPL was not distributed with this
  9. file, You can obtain one at https://mozilla.org/MPL/2.0.
  10. }
  11. {
  12. Functions and classes for interoperability between Imaging and
  13. FireMonkey framework.
  14. Currently has conversion functions between FMX TBitmap (RGBA and BGRA pixel formats)
  15. and Imaging's TImageData and TBaseImage.
  16. }
  17. unit ImagingFmx;
  18. {$I ImagingOptions.inc}
  19. {$IF not Defined (DCC) or (CompilerVersion < 25.0)}
  20. {$MESSAGE FATAL 'Needs at least Delphi XE4, probably higher'}
  21. {$IFEND}
  22. interface
  23. uses
  24. Types,
  25. SysUtils,
  26. ImagingTypes,
  27. Imaging,
  28. ImagingFormats,
  29. ImagingClasses,
  30. ImagingUtility,
  31. UITypes,
  32. UIConsts,
  33. FMX.Types,
  34. FMX.Utils,
  35. FMX.Graphics;
  36. { Converts image from TImageData record to FMX bitmap. Bitmap must be already instantiated.}
  37. procedure ConvertImageDataToFmxBitmap(const Image: TImageData; Bitmap: TBitmap);
  38. { Converts FMX bitmap to TImageData. Image must be already initialized.}
  39. procedure ConvertFmxBitmapToImageData(const Bitmap: TBitmap; Image: TImageData);
  40. { Converts image from TBaseImage instance to FMX bitmap. Bitmap must be already instantiated.}
  41. procedure ConvertImageToFmxBitmap(Image: TBaseImage; Bitmap: TBitmap);
  42. { Converts FMX bitmap to TBaseImage. Image must be already instantiated.}
  43. procedure ConvertFmxBitmapToImage(const Bitmap: TBitmap; Image: TBaseImage);
  44. { Copies rectangular area of pixels from TImageData record to existing FMX bitmap.}
  45. procedure CopyRectToFmxBitmap(const Image: TImageData; Bitmap: TBitmap;
  46. SrcX, SrcY, Width, Height, DstX, DstY: LongInt); overload;
  47. { Copies rectangular area of pixels from TBaseImage instance to existing FMX bitmap.}
  48. procedure CopyRectToFmxBitmap(Image: TBaseImage; Bitmap: TBitmap;
  49. SrcX, SrcY, Width, Height, DstX, DstY: LongInt); overload;
  50. implementation
  51. procedure ConvertFmxBitmapToImageData(const Bitmap: TBitmap; Image: TImageData);
  52. var
  53. Color32: TColor32Rec;
  54. MapData: TBitmapData;
  55. SourceData: PAlphaColorRec;
  56. TargetData: PByte;
  57. X, Y, Bpp, SrcWidthBytes: Integer;
  58. TargetInfo: TImageFormatInfo;
  59. begin
  60. Assert(TestImage(Image) and not Bitmap.IsEmpty);
  61. Bitmap.Map(TMapAccess.Read, MapData);
  62. GetImageFormatInfo(Image.Format, TargetInfo);
  63. Bpp := TargetInfo.BytesPerPixel;
  64. SrcWidthBytes := Image.Width * Bpp;
  65. TargetData := @PByteArray(Image.Bits)[0];
  66. for Y := 0 to Bitmap.Height - 1 do
  67. for X := 0 to Bitmap.Width - 1 do
  68. begin
  69. SourceData:= @PAlphaColorRecArray(MapData.Data)[Y * (MapData.Pitch div 4) + X];
  70. case TargetInfo.Format of
  71. ifIndex8:
  72. begin
  73. Image.Palette[TargetData^].R := SourceData^.R;
  74. Image.Palette[TargetData^].G := SourceData^.G;
  75. Image.Palette[TargetData^].B := SourceData^.B;
  76. Image.Palette[TargetData^].A := SourceData^.A;
  77. end;
  78. ifGray8:
  79. TargetData^ := SourceData.R;
  80. ifA8Gray8:
  81. begin
  82. TargetData^ := SourceData.R;
  83. PWordRec(TargetData).High := SourceData.A;
  84. end;
  85. ifGray16:
  86. PWord(TargetData)^ := SourceData.R;
  87. ifR8G8B8:
  88. begin
  89. PColor24Rec(TargetData)^.R := SourceData.R;
  90. PColor24Rec(TargetData)^.G := SourceData.G;
  91. PColor24Rec(TargetData)^.B := SourceData.B;
  92. end;
  93. ifA8R8G8B8:
  94. begin
  95. PColor32Rec(TargetData)^.A := SourceData^.B;
  96. PColor32Rec(TargetData)^.G := SourceData^.R;
  97. PColor32Rec(TargetData)^.R := SourceData^.G;
  98. PColor32Rec(TargetData)^.B := SourceData^.A;
  99. end;
  100. ifR16G16B16:
  101. begin
  102. PColor48Rec(TargetData).R := Round(SourceData.R * $FFFF / 255);
  103. PColor48Rec(TargetData).G := Round(SourceData.G * $FFFF / 255);
  104. PColor48Rec(TargetData).B := Round(SourceData.B * $FFFF / 255);
  105. end;
  106. ifA16R16G16B16:
  107. begin
  108. PColor64Rec(TargetData).R := Round(SourceData.R * $FFFF / 255);
  109. PColor64Rec(TargetData).G := Round(SourceData.G * $FFFF / 255);
  110. PColor64Rec(TargetData).B := Round(SourceData.B * $FFFF / 255);
  111. PColor64Rec(TargetData).A := Round(SourceData.A * $FFFF / 255);
  112. end;
  113. else
  114. Color32.R := SourceData^.R;
  115. Color32.G := SourceData^.G;
  116. Color32.B := SourceData^.B;
  117. Color32.A := SourceData^.A;
  118. TargetInfo.SetPixel32(TargetData,@TargetInfo, Image.Palette,Color32);
  119. end;
  120. Inc(TargetData, Bpp);
  121. end;
  122. Bitmap.Unmap(MapData);
  123. end;
  124. procedure ConvertFmxBitmapToImage(const Bitmap: TBitmap; Image: TBaseImage);
  125. begin
  126. ConvertFmxBitmapToImageData(Bitmap, Image.ImageDataPointer^);
  127. end;
  128. procedure ConvertImageDataToFmxBitmap(const Image: TImageData; Bitmap: TBitmap);
  129. begin
  130. Assert(TestImage(Image));
  131. Bitmap.SetSize(Image.Width, Image.Height);
  132. CopyRectToFmxBitmap(Image, Bitmap, 0, 0, Image.Width, Image.Height, 0, 0);
  133. end;
  134. procedure ConvertImageToFmxBitmap(Image: TBaseImage; Bitmap: TBitmap);
  135. begin
  136. ConvertImageDataToFmxBitmap(Image.ImageDataPointer^, Bitmap);
  137. end;
  138. procedure ConvertToAlphaColorRec(SrcPix: PByte; DestPix: PAlphaColorRec;
  139. const SrcInfo: TImageFormatInfo; SrcPalette: PPalette32);
  140. var
  141. Color32: TColor32Rec;
  142. begin
  143. case SrcInfo.Format of
  144. ifIndex8:
  145. begin
  146. DestPix.R := SrcPalette[SrcPix^].R;
  147. DestPix.G := SrcPalette[SrcPix^].G;
  148. DestPix.B := SrcPalette[SrcPix^].B;
  149. DestPix.A := SrcPalette[SrcPix^].A;
  150. end;
  151. ifGray8:
  152. begin
  153. DestPix.R := SrcPix^;
  154. DestPix.G := SrcPix^;
  155. DestPix.B := SrcPix^;
  156. DestPix.A := 255;
  157. end;
  158. ifR8G8B8:
  159. begin
  160. PColor24Rec(DestPix)^ := PColor24Rec(SrcPix)^;
  161. DestPix.A := 255;
  162. end;
  163. ifA8R8G8B8:
  164. PColor32Rec(DestPix)^ := PColor32Rec(SrcPix)^;
  165. else
  166. PColor32Rec(DestPix)^ := SrcInfo.GetPixel32(SrcPix, @SrcInfo, SrcPalette);
  167. end;
  168. end;
  169. procedure CopyRectToFmxBitmap(const Image: TImageData; Bitmap: TBitmap;
  170. SrcX, SrcY, Width, Height, DstX, DstY: LongInt);
  171. var
  172. TempImage: TImageData;
  173. X, Y, Bpp, SrcLineBytes: Integer;
  174. SrcPtr: PByte;
  175. Info: TImageFormatInfo;
  176. MapData: TBitmapData;
  177. DstPtr: PAlphaColorRec;
  178. BGRA: TAlphaColorRec;
  179. begin
  180. Assert(TestImage(Image) and not Bitmap.IsEmpty);
  181. if not (Bitmap.PixelFormat in [TPixelFormat.RGBA, TPixelFormat.BGRA]) then
  182. raise Exception.CreateFmt('Unsupported FMX TBitmap pixel format "%s"', [PixelFormatToString(Bitmap.PixelFormat)]);
  183. ClipCopyBounds(SrcX, SrcY, Width, Height, DstX, DstY, Image.Width,
  184. Image.Height, Rect(0, 0, Bitmap.Width, Bitmap.Height));
  185. GetImageFormatInfo(Image.Format, Info);
  186. if not Info.IsSpecial then
  187. begin
  188. Bpp := Info.BytesPerPixel;
  189. SrcLineBytes := Image.Width * Bpp;
  190. Bitmap.Map(TMapAccess.Write, MapData);
  191. for Y := 0 to Height - 1 do
  192. begin
  193. SrcPtr := @PByteArray(Image.Bits)[(SrcY + Y) * SrcLineBytes + SrcX * Bpp];
  194. DstPtr := @PAlphaColorRecArray(MapData.GetScanline(DstY + Y))[DstX];
  195. for X := 0 to Width - 1 do
  196. begin
  197. if Info.Format = ifA8R8G8B8 then
  198. BGRA := PAlphaColorRec(SrcPtr)^
  199. else
  200. ConvertToAlphaColorRec(SrcPtr, @BGRA, Info, Image.Palette);
  201. if MapData.PixelFormat = TPixelFormat.RGBA then
  202. SwapValues(BGRA.R, BGRA.B);
  203. // Alpha premultiplication is needed for FMX bitmaps to display correctly in TImage etc.
  204. DstPtr.Color := PremultiplyAlpha(BGRA.Color);
  205. Inc(SrcPtr, Bpp);
  206. Inc(DstPtr);
  207. end;
  208. end;
  209. end
  210. else
  211. begin
  212. InitImage(TempImage);
  213. CloneImage(Image, TempImage);
  214. ConvertImage(TempImage, ifA8R8G8B8);
  215. try
  216. CopyRectToFmxBitmap(TempImage, Bitmap, SrcX, SrcY, Width, Height, DstX, DstY);
  217. finally
  218. FreeImage(TempImage);
  219. end;
  220. end;
  221. Bitmap.Unmap(MapData);
  222. end;
  223. procedure CopyRectToFmxBitmap(Image: TBaseImage; Bitmap: TBitmap;
  224. SrcX, SrcY, Width, Height, DstX, DstY: LongInt);
  225. begin
  226. CopyRectToFmxBitmap(Image.ImageDataPointer^, Bitmap,
  227. SrcX, SrcY, Width, Height, DstX, DstY);
  228. end;
  229. end.