GR32.ImageFormats.PNG.pas 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. unit GR32.ImageFormats.PNG;
  2. (* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1 or LGPL 2.1 with linking exception
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * Alternatively, the contents of this file may be used under the terms of the
  16. * Free Pascal modified version of the GNU Lesser General Public License
  17. * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
  18. * of this license are applicable instead of those above.
  19. * Please see the file LICENSE.txt for additional information concerning this
  20. * license.
  21. *
  22. * The Original Code is PNG Image Format support for Graphics32
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Anders Melander <[email protected]>
  26. *
  27. * Portions created by the Initial Developer are Copyright (C) 2008-2022
  28. * the Initial Developer. All Rights Reserved.
  29. *
  30. * Contributor(s):
  31. *
  32. * ***** END LICENSE BLOCK ***** *)
  33. interface
  34. {$include GR32.inc}
  35. {$ifdef FPC}
  36. {$message WARN 'GR32.ImageFormats.PNG does not support FreePascal. Use the GR32.ImageFormats.PNG32 unit instead'}
  37. {$endif FPC}
  38. implementation
  39. {$ifdef FPC}
  40. // Make sure ImageFormats.PNG32 is referenced so the adapters are registered.
  41. // Beyond that, this unit does nothing on FPC.
  42. uses
  43. GR32.ImageFormats.PNG32;
  44. {$else FPC}
  45. uses
  46. Classes,
  47. PngImage,
  48. Graphics,
  49. GR32,
  50. GR32.ImageFormats;
  51. const
  52. PngSignature: AnsiString = #$89#$50#$4e#$47#$0d#$0a#$1a#$0a;
  53. PngSignatureMask: AnsiString = #$ff#$ff#$ff#$ff#$ff#$ff#$ff#$ff;
  54. //------------------------------------------------------------------------------
  55. //
  56. // TImageFormatAdapterPNG
  57. //
  58. //------------------------------------------------------------------------------
  59. // Implements IImageFormatAdapter for the PNG image format using the standard
  60. // Delphi TPNGImage class.
  61. //------------------------------------------------------------------------------
  62. type
  63. TImageFormatAdapterPNG = class(TCustomImageFormatAdapter,
  64. IImageFormatAdapter,
  65. IImageFormatFileInfo,
  66. IImageFormatReader,
  67. IImageFormatWriter)
  68. strict protected
  69. // IImageFormatAdapter
  70. function CanAssignFrom(Source: TPersistent): boolean; override;
  71. function AssignFrom(Dest: TCustomBitmap32; Source: TPersistent): boolean; override;
  72. function CanAssignTo(Dest: TPersistent): boolean; override;
  73. function AssignTo(Source: TCustomBitmap32; Dest: TPersistent): boolean; override;
  74. private
  75. // IImageFormatFileInfo
  76. function ImageFormatDescription: string;
  77. function ImageFormatFileTypes: TFileTypes;
  78. private
  79. // IImageFormatReader
  80. function CanLoadFromStream(AStream: TStream): boolean;
  81. function LoadFromStream(ADest: TCustomBitmap32; AStream: TStream): boolean;
  82. private
  83. // IImageFormatWriter
  84. procedure SaveToStream(ASource: TCustomBitmap32; AStream: TStream);
  85. end;
  86. //------------------------------------------------------------------------------
  87. // IImageFormatAdapter
  88. //------------------------------------------------------------------------------
  89. function TImageFormatAdapterPNG.CanAssignFrom(Source: TPersistent): boolean;
  90. begin
  91. Result := (Source is TPNGImage);
  92. end;
  93. function TImageFormatAdapterPNG.AssignFrom(Dest: TCustomBitmap32; Source: TPersistent): boolean;
  94. var
  95. Bitmap: TBitmap;
  96. Row, Col: integer;
  97. Alpha: PByte;
  98. Src: PColor32Entry;
  99. Dst: PColor32Entry;
  100. begin
  101. if (not (Source is TPNGImage)) then
  102. begin
  103. Result := inherited;
  104. exit;
  105. end;
  106. if (TPNGImage(Source).Header.ColorType <> COLOR_RGBALPHA) then
  107. begin
  108. // Defer to default assign mechanism via TBitmap
  109. Bitmap := TBitmap.Create;
  110. try
  111. Bitmap.Assign(Source);
  112. Dest.Assign(Bitmap);
  113. finally
  114. Bitmap.Free;
  115. end;
  116. end else
  117. begin
  118. Bitmap := TBitmap.Create;
  119. try
  120. // Unfortunately the conversion from TPNGImage to TBitmap sets the
  121. // AlphaFormat to afDefined which in turn premultiplies the bitmap.
  122. // We need it unpremultiplied but changing AlphaFormat to unpremultiply
  123. // unavoidably loses information. The only way to avoid this is to
  124. // not use TBitmap...
  125. Bitmap.Assign(Source);
  126. // Make sure bitmap is 32-bits
  127. Bitmap.PixelFormat := pf32bit;
  128. // Unpremultiply :-(
  129. Bitmap.AlphaFormat := afIgnored;
  130. Dest.SetSize(Bitmap.Width, Bitmap.Height);
  131. // Copy RGB values. We will copy the Alpha separately below.
  132. Dst := PColor32Entry(Dest.Bits);
  133. for Row := 0 to Dest.Height-1 do
  134. begin
  135. Src := PColor32Entry(Bitmap.Scanline[Row]);
  136. Move(Src^, Dst^, SizeOf(TColor32)*Dest.Width);
  137. Inc(Dst, Dest.Width);
  138. end;
  139. finally
  140. Bitmap.Free;
  141. end;
  142. // Copy Alpha from PNG
  143. if (TPNGImage(Source).TransparencyMode = ptmPartial) then
  144. begin
  145. Dst := PColor32Entry(Dest.Bits);
  146. for Row := 0 to Dest.Height-1 do
  147. begin
  148. Alpha := PByte(TPNGImage(Source).AlphaScanline[Row]);
  149. for Col := 0 to Dest.Width-1 do
  150. begin
  151. Dst.A := Alpha^;
  152. Inc(Alpha);
  153. Inc(Dst);
  154. end;
  155. end;
  156. end;
  157. end;
  158. Result := True;
  159. end;
  160. //------------------------------------------------------------------------------
  161. function TImageFormatAdapterPNG.CanAssignTo(Dest: TPersistent): boolean;
  162. begin
  163. Result := (Dest is TPNGImage);
  164. end;
  165. function TImageFormatAdapterPNG.AssignTo(Source: TCustomBitmap32; Dest: TPersistent): boolean;
  166. var
  167. Bitmap: TBitmap;
  168. Row, Col: integer;
  169. Dst: PByte;
  170. Src: PColor32Entry;
  171. begin
  172. if (not(Dest is TPNGImage)) then
  173. begin
  174. Result := inherited;
  175. exit;
  176. end;
  177. // Convert to TPNGImage via TBitmap
  178. Bitmap := TBitmap.Create;
  179. try
  180. Bitmap.Assign(Source);
  181. TPNGImage(Dest).Assign(Bitmap);
  182. finally
  183. Bitmap.Free;
  184. end;
  185. // Copy alpha
  186. TPNGImage(Dest).CreateAlpha;
  187. Src := PColor32Entry(Source.Bits);
  188. for Row := 0 to Source.Height-1 do
  189. begin
  190. Dst := PByte(TPNGImage(Dest).AlphaScanline[Row]);
  191. for Col := 0 to TPNGImage(Dest).Width-1 do
  192. begin
  193. Dst^ := Src.A;
  194. inc(Dst);
  195. inc(Src);
  196. end;
  197. end;
  198. Result := True;
  199. end;
  200. //------------------------------------------------------------------------------
  201. // IImageFormatFileInfo
  202. //------------------------------------------------------------------------------
  203. function TImageFormatAdapterPNG.ImageFormatFileTypes: TFileTypes;
  204. begin
  205. Result := ['png'];
  206. end;
  207. function TImageFormatAdapterPNG.ImageFormatDescription: string;
  208. resourcestring
  209. sImageFormatPNGName = 'PNG images';
  210. begin
  211. Result := sImageFormatPNGName;
  212. end;
  213. //------------------------------------------------------------------------------
  214. // IImageFormatReader
  215. //------------------------------------------------------------------------------
  216. function TImageFormatAdapterPNG.CanLoadFromStream(AStream: TStream): boolean;
  217. begin
  218. {$ifdef LOADFROMSTREAM}
  219. Result := TPNGImage.CanLoadFromStream(AStream);
  220. {$else LOADFROMSTREAM}
  221. Result := CheckFileSignature(AStream, FileSignaturePNG, FileSignaturePNGMask);
  222. {$endif LOADFROMSTREAM}
  223. end;
  224. function TImageFormatAdapterPNG.LoadFromStream(ADest: TCustomBitmap32; AStream: TStream): boolean;
  225. var
  226. PNGImage: TPNGImage;
  227. begin
  228. PNGImage := TPNGImage.Create;
  229. try
  230. PNGImage.LoadFromStream(AStream);
  231. ADest.Assign(PNGImage);
  232. finally
  233. PNGImage.Free;
  234. end;
  235. Result := True;
  236. end;
  237. //------------------------------------------------------------------------------
  238. // IImageFormatWriter
  239. //------------------------------------------------------------------------------
  240. procedure TImageFormatAdapterPNG.SaveToStream(ASource: TCustomBitmap32; AStream: TStream);
  241. var
  242. PNGImage: TPNGImage;
  243. begin
  244. PNGImage := TPNGImage.Create;
  245. try
  246. PNGImage.Assign(ASource);
  247. PNGImage.SaveToStream(AStream);
  248. finally
  249. PNGImage.Free;
  250. end;
  251. end;
  252. //------------------------------------------------------------------------------
  253. //------------------------------------------------------------------------------
  254. //------------------------------------------------------------------------------
  255. {$endif FPC}
  256. var
  257. ImageFormatHandle: integer = 0;
  258. initialization
  259. {$ifndef FPC}
  260. ImageFormatHandle := ImageFormatManager.RegisterImageFormat(TImageFormatAdapterPNG.Create, ImageFormatPriorityWorse);
  261. {$endif FPC}
  262. finalization
  263. ImageFormatManager.UnregisterImageFormat(ImageFormatHandle);
  264. end.