GR32.ImageFormats.TGraphic.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. unit GR32.ImageFormats.TGraphic;
  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 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. uses
  36. Classes,
  37. Graphics,
  38. SysUtils,
  39. GR32,
  40. GR32_Backends,
  41. GR32.ImageFormats;
  42. //------------------------------------------------------------------------------
  43. //
  44. // TCustomImageFormatAdapterTGraphic
  45. //
  46. //------------------------------------------------------------------------------
  47. // Implements IImageFormatAdapter for the TGraphic class.
  48. //------------------------------------------------------------------------------
  49. type
  50. TCustomImageFormatAdapterTGraphic = class(TCustomImageFormatAdapter,
  51. IImageFormatAdapter)
  52. strict private
  53. FGraphicClass: TGraphicClass;
  54. protected
  55. class procedure AssignFromGraphicMasked(TargetBitmap: TCustomBitmap32; SrcGraphic: TGraphic);
  56. class procedure AssignFromGraphicPlain(TargetBitmap: TCustomBitmap32; SrcGraphic: TGraphic; FillColor: TColor32;
  57. ResetAlphaAfterDrawing: Boolean);
  58. strict protected
  59. // IImageFormatAdapter
  60. function CanAssignFrom(Source: TPersistent): boolean; override;
  61. function AssignFrom(Dest: TCustomBitmap32; Source: TPersistent): boolean; override;
  62. function CanAssignTo(Dest: TPersistent): boolean; override;
  63. function AssignTo(Source: TCustomBitmap32; Dest: TPersistent): boolean; override;
  64. protected
  65. property GraphicClass: TGraphicClass read FGraphicClass;
  66. public
  67. constructor Create; overload;
  68. constructor Create(AGraphicClass: TGraphicClass); overload;
  69. end;
  70. //------------------------------------------------------------------------------
  71. //
  72. // TImageFormatReaderTGraphic
  73. // TImageFormatReaderWriterTGraphic
  74. //
  75. //------------------------------------------------------------------------------
  76. // Implements file related interfaces for the TGraphic class.
  77. //------------------------------------------------------------------------------
  78. // Note: A default implementation of the IImageFormatWriter interface is
  79. // provided but descedant classes has to declare implicit support for the
  80. // interface if they actually support it. The TImageFormatReaderWriterTGraphic
  81. // class does this.
  82. // This is because not all TGraphic implementations support writing data (e.g.
  83. // most of the GraphicEx library).
  84. //------------------------------------------------------------------------------
  85. type
  86. TImageFormatReaderTGraphic = class(TCustomImageFormatAdapterTGraphic,
  87. IImageFormatAdapter,
  88. IImageFormatFileInfo,
  89. IImageFormatReader)
  90. strict private
  91. FDescription: string;
  92. FFileTypes: TFileTypes;
  93. private
  94. // IImageFormatFileInfo
  95. function ImageFormatDescription: string;
  96. function ImageFormatFileTypes: TFileTypes;
  97. strict protected
  98. // IImageFormatReader
  99. function CanLoadFromStream(AStream: TStream): boolean; virtual;
  100. function LoadFromStream(ADest: TCustomBitmap32; AStream: TStream): boolean; virtual;
  101. strict protected
  102. // IImageFormatWriter
  103. procedure SaveToStream(ASource: TCustomBitmap32; AStream: TStream); virtual;
  104. public
  105. constructor Create(AGraphicClass: TGraphicClass; const ADescription: string; const AFileTypes: TFileTypes = nil);
  106. end;
  107. TImageFormatReaderWriterTGraphic = class(TImageFormatReaderTGraphic, IImageFormatWriter)
  108. end;
  109. //------------------------------------------------------------------------------
  110. //------------------------------------------------------------------------------
  111. //------------------------------------------------------------------------------
  112. implementation
  113. uses
  114. Types;
  115. type
  116. TGraphicCracker = class(TGraphic);
  117. //------------------------------------------------------------------------------
  118. //
  119. // TCustomImageFormatAdapterTGraphic
  120. //
  121. //------------------------------------------------------------------------------
  122. constructor TCustomImageFormatAdapterTGraphic.Create(AGraphicClass: TGraphicClass);
  123. begin
  124. inherited Create;
  125. FGraphicClass := AGraphicClass;
  126. end;
  127. constructor TCustomImageFormatAdapterTGraphic.Create;
  128. begin
  129. Create(TGraphic);
  130. end;
  131. //------------------------------------------------------------------------------
  132. // IImageFormatAdapter
  133. //------------------------------------------------------------------------------
  134. function TCustomImageFormatAdapterTGraphic.CanAssignFrom(Source: TPersistent): boolean;
  135. begin
  136. Result := Source.ClassType.InheritsFrom(GraphicClass);
  137. end;
  138. function TCustomImageFormatAdapterTGraphic.AssignFrom(Dest: TCustomBitmap32; Source: TPersistent): boolean;
  139. begin
  140. if (Source.ClassType.InheritsFrom(GraphicClass)) then
  141. begin
  142. Result := True;
  143. AssignFromGraphicPlain(Dest, TGraphic(Source), clWhite32, True);
  144. end else
  145. Result := inherited;
  146. end;
  147. //------------------------------------------------------------------------------
  148. class procedure TCustomImageFormatAdapterTGraphic.AssignFromGraphicPlain(TargetBitmap: TCustomBitmap32;
  149. SrcGraphic: TGraphic; FillColor: TColor32; ResetAlphaAfterDrawing: Boolean);
  150. var
  151. SavedBackend: TCustomBackend;
  152. Canvas: TCanvas;
  153. DeviceContextSupport: IDeviceContextSupport;
  154. CanvasSupport: ICanvasSupport;
  155. InteroperabilitySupport: IInteroperabilitySupport;
  156. begin
  157. if not Assigned(SrcGraphic) then
  158. Exit;
  159. RequireBackendSupport(TargetBitmap, [IDeviceContextSupport, ICanvasSupport,
  160. IInteroperabilitySupport], romOr, True, SavedBackend);
  161. try
  162. TargetBitmap.SetSize(SrcGraphic.Width, SrcGraphic.Height);
  163. if TargetBitmap.Empty then Exit;
  164. TargetBitmap.Clear(FillColor);
  165. if Supports(TargetBitmap.Backend, IInteroperabilitySupport, InteroperabilitySupport) then
  166. begin
  167. InteroperabilitySupport.CopyFrom(SrcGraphic);
  168. InteroperabilitySupport := nil;
  169. end else
  170. if Supports(TargetBitmap.Backend, ICanvasSupport, CanvasSupport) then
  171. begin
  172. TGraphicCracker(SrcGraphic).Draw(CanvasSupport.Canvas,
  173. MakeRect(0, 0, TargetBitmap.Width, TargetBitmap.Height));
  174. CanvasSupport := nil;
  175. end else
  176. if Supports(TargetBitmap.Backend, IDeviceContextSupport, DeviceContextSupport) then
  177. begin
  178. Canvas := TCanvas.Create;
  179. try
  180. Canvas.Lock;
  181. try
  182. Canvas.Handle := DeviceContextSupport.Handle;
  183. TGraphicCracker(SrcGraphic).Draw(Canvas,
  184. MakeRect(0, 0, TargetBitmap.Width, TargetBitmap.Height));
  185. finally
  186. Canvas.Unlock;
  187. end;
  188. finally
  189. Canvas.Free;
  190. end;
  191. DeviceContextSupport := nil;
  192. end else
  193. raise Exception.Create(RCStrInpropriateBackend);
  194. if ResetAlphaAfterDrawing then
  195. TargetBitmap.ResetAlpha;
  196. finally
  197. RestoreBackend(TargetBitmap, SavedBackend);
  198. end;
  199. end;
  200. class procedure TCustomImageFormatAdapterTGraphic.AssignFromGraphicMasked(TargetBitmap: TCustomBitmap32; SrcGraphic: TGraphic);
  201. var
  202. TempBitmap: TCustomBitmap32;
  203. I: integer;
  204. DstP, SrcP: PColor32;
  205. DstColor: TColor32;
  206. begin
  207. AssignFromGraphicPlain(TargetBitmap, SrcGraphic, clWhite32, False); // mask on white
  208. if TargetBitmap.Empty then
  209. begin
  210. TargetBitmap.Clear;
  211. Exit;
  212. end;
  213. if TargetBitmap.Backend <> nil then
  214. // Use the same backend type as the target. See Issue #127
  215. TempBitmap := TCustomBitmap32.Create(TCustomBackendClass(TargetBitmap.Backend.ClassType))
  216. else
  217. TempBitmap := TCustomBitmap32.Create;
  218. try
  219. AssignFromGraphicPlain(TempBitmap, SrcGraphic, clRed32, False); // mask on red
  220. DstP := @TargetBitmap.Bits[0];
  221. SrcP := @TempBitmap.Bits[0];
  222. for I := 0 to TargetBitmap.Width * TargetBitmap.Height - 1 do
  223. begin
  224. DstColor := DstP^ and $00FFFFFF;
  225. // this checks for transparency by comparing the pixel-color of the
  226. // temporary bitmap (red masked) with the pixel of our
  227. // bitmap (white masked). if they match, make that pixel opaque
  228. if DstColor = (SrcP^ and $00FFFFFF) then
  229. DstP^ := DstColor or $FF000000
  230. else
  231. // if the colors do not match (that is the case if there is a
  232. // match "is clRed32 = clWhite32 ?"), just make that pixel
  233. // transparent:
  234. DstP^ := DstColor;
  235. Inc(SrcP); Inc(DstP);
  236. end;
  237. finally
  238. TempBitmap.Free;
  239. end;
  240. end;
  241. //------------------------------------------------------------------------------
  242. function TCustomImageFormatAdapterTGraphic.CanAssignTo(Dest: TPersistent): boolean;
  243. begin
  244. // Assume we can't assign unless we have an explicit class (i.e. not the default TGraphic)
  245. Result := (GraphicClass <> TGraphic) and Dest.ClassType.InheritsFrom(GraphicClass);
  246. end;
  247. function TCustomImageFormatAdapterTGraphic.AssignTo(Source: TCustomBitmap32; Dest: TPersistent): boolean;
  248. var
  249. Bitmap: TBitmap;
  250. begin
  251. if (Dest.ClassType.InheritsFrom(GraphicClass)) then
  252. begin
  253. // Give it a go via TBitmap
  254. Bitmap := TBitmap.Create;
  255. try
  256. Bitmap.Assign(Source);
  257. Dest.Assign(Bitmap);
  258. finally
  259. Bitmap.Free;
  260. end;
  261. Result := True;
  262. end else
  263. Result := inherited;
  264. end;
  265. //------------------------------------------------------------------------------
  266. //
  267. // TImageFormatReaderTGraphic
  268. //
  269. //------------------------------------------------------------------------------
  270. constructor TImageFormatReaderTGraphic.Create(AGraphicClass: TGraphicClass;
  271. const ADescription: string; const AFileTypes: TFileTypes);
  272. var
  273. FileType: string;
  274. begin
  275. inherited Create(AGraphicClass);
  276. FDescription := ADescription;
  277. FFileTypes := AFileTypes;
  278. if (Length(FFileTypes) = 0) then
  279. begin
  280. FileType := GraphicExtension(GraphicClass);
  281. if (FileType <> '') then
  282. begin
  283. SetLength(FFileTypes, 1);
  284. FFileTypes[0] := FileType;
  285. end;
  286. end;
  287. end;
  288. //------------------------------------------------------------------------------
  289. // IImageFormatFileInfo
  290. //------------------------------------------------------------------------------
  291. function TImageFormatReaderTGraphic.ImageFormatFileTypes: TFileTypes;
  292. begin
  293. Result := FFileTypes;
  294. end;
  295. function TImageFormatReaderTGraphic.ImageFormatDescription: string;
  296. begin
  297. Result := FDescription;
  298. end;
  299. //------------------------------------------------------------------------------
  300. // IImageFormatReader
  301. //------------------------------------------------------------------------------
  302. function TImageFormatReaderTGraphic.CanLoadFromStream(AStream: TStream): boolean;
  303. begin
  304. {$ifdef LOADFROMSTREAM}
  305. Result := GraphicClass.CanLoadFromStream(AStream);
  306. {$else LOADFROMSTREAM}
  307. Result := False;
  308. {$endif LOADFROMSTREAM}
  309. end;
  310. function TImageFormatReaderTGraphic.LoadFromStream(ADest: TCustomBitmap32; AStream: TStream): boolean;
  311. var
  312. Graphic: TGraphic;
  313. begin
  314. {$ifdef LOADFROMSTREAM}
  315. if (not GraphicClass.CanLoadFromStream(AStream)) then
  316. Exit(False);
  317. {$endif LOADFROMSTREAM}
  318. Graphic := GraphicClass.Create;
  319. try
  320. {$ifdef LOADFROMSTREAM}
  321. Graphic.LoadFromStream(AStream);
  322. {$else LOADFROMSTREAM}
  323. try
  324. Graphic.LoadFromStream(AStream);
  325. except
  326. on E: EInvalidGraphic do
  327. Exit(False);
  328. end;
  329. {$endif LOADFROMSTREAM}
  330. ADest.Assign(Graphic);
  331. finally
  332. Graphic.Free;
  333. end;
  334. Result := True;
  335. end;
  336. //------------------------------------------------------------------------------
  337. // IImageFormatWriter
  338. //------------------------------------------------------------------------------
  339. procedure TImageFormatReaderTGraphic.SaveToStream(ASource: TCustomBitmap32; AStream: TStream);
  340. var
  341. Graphic: TGraphic;
  342. begin
  343. Graphic := GraphicClass.Create;
  344. try
  345. Graphic.Assign(ASource);
  346. Graphic.SaveToStream(AStream);
  347. finally
  348. Graphic.Free;
  349. end;
  350. end;
  351. //------------------------------------------------------------------------------
  352. //------------------------------------------------------------------------------
  353. //------------------------------------------------------------------------------
  354. var
  355. ImageFormatHandle: integer = 0;
  356. initialization
  357. ImageFormatHandle := ImageFormatManager.RegisterImageFormat(TCustomImageFormatAdapterTGraphic.Create, ImageFormatPriorityWorse);
  358. finalization
  359. ImageFormatManager.UnregisterImageFormat(ImageFormatHandle);
  360. end.