ImagingComponents.pas 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400
  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. { This unit contains VCL/LCL TGraphic descendant which uses Imaging library
  12. for saving and loading.}
  13. unit ImagingComponents;
  14. {$I ImagingOptions.inc}
  15. interface
  16. {$IF Defined(FPC) and Defined(LCL)}
  17. {$DEFINE COMPONENT_SET_LCL}
  18. {$ELSEIF Defined(DELPHI)}
  19. {$DEFINE COMPONENT_SET_VCL}
  20. {$IFEND}
  21. {$IF not Defined(COMPONENT_SET_LCL) and not Defined(COMPONENT_SET_VCL)}
  22. // If no component sets should be used just include empty unit.
  23. implementation
  24. {$ELSE}
  25. uses
  26. {$IFDEF MSWINDOWS}
  27. Windows,
  28. {$ENDIF}
  29. SysUtils, Types, Classes,
  30. {$IFDEF COMPONENT_SET_VCL}
  31. Graphics,
  32. {$ENDIF}
  33. {$IFDEF COMPONENT_SET_LCL}
  34. GraphType,
  35. Graphics,
  36. LCLType,
  37. LCLIntf,
  38. {$ENDIF}
  39. ImagingTypes, Imaging, ImagingClasses;
  40. type
  41. { Graphic class which uses Imaging to load images.
  42. It has standard TBitmap class as ancestor and it can
  43. Assign also to/from TImageData structures and TBaseImage
  44. classes. If you want to perfectly preserve the original pixel format
  45. of the source image then these classes may not for you.
  46. This class is automatically registered to TPicture for all
  47. file extensions supported by Imaging (useful only for loading).
  48. If you just want to load images in various formats you can use this
  49. class or simply use TPicture.LoadFromXXX which will create this class
  50. automatically.
  51. For saving it always uses PNG fallback.
  52. For TGraphic classes that save in different formats look
  53. at TImagingGraphicForSave class.}
  54. TImagingGraphic = class(TBitmap)
  55. protected
  56. procedure AssignTo(Dest: TPersistent); override;
  57. { Called by TFiler when reading and writing TPicture.Data property.
  58. We need to override ReadData+WriteData otherwise inherited ones from
  59. TBitmap would be called resulting in errors.}
  60. procedure ReadData(Stream: TStream); override;
  61. procedure WriteData(Stream: TStream); override;
  62. public
  63. constructor Create; override;
  64. { Loads new image from the stream. It can load all image
  65. file formats supported by Imaging (and enabled of course)
  66. even though it is called by descendant class capable of
  67. saving only one file format.}
  68. procedure LoadFromStream(Stream: TStream); override;
  69. { Always saves as PNG.}
  70. procedure SaveToStream(Stream: TStream); override;
  71. { Copies the image contained in Source to this graphic object.
  72. Supports also TBaseImage descendants from ImagingClasses unit. }
  73. procedure Assign(Source: TPersistent); override;
  74. { Copies the image contained in TBaseImage to this graphic object.}
  75. procedure AssignFromImage(Image: TBaseImage);
  76. { Copies the current image to TBaseImage object.}
  77. procedure AssignToImage(Image: TBaseImage);
  78. { Copies the image contained in TImageData structure to this graphic object.}
  79. procedure AssignFromImageData(const ImageData: TImageData);
  80. { Copies the current image to TImageData structure.}
  81. procedure AssignToImageData(var ImageData: TImageData);
  82. {$IFDEF COMPONENT_SET_LCL}
  83. { Needed for TGraphic.LoadFromResourceName() to work.
  84. We return RT_RCDATA here. Also for TImagingBitmap since
  85. RT_BITMAP is stored differently than bitmap on disk (no BITMAPFILEHEADER).}
  86. function GetResourceType: TResourceType; override;
  87. { Used by TPicture.LoadFromStream to find the right TGraphic class for streams. }
  88. class function IsStreamFormatSupported(Stream: TStream): boolean; override;
  89. {$ENDIF}
  90. end;
  91. TImagingGraphicClass = class of TImagingGraphic;
  92. { Base (abstract) class for file format specific TGraphic classes that use
  93. Imaging for saving. Each descendant class can load all file formats
  94. supported by Imaging but save only one format (TImagingBitmap
  95. for *.bmp, TImagingJpeg for *.jpg). The image is saved in this one file
  96. format regardless of the extension you request).
  97. Format specific classes also allow easy access to Imaging options that
  98. affect saving of files (they are properties here).}
  99. TImagingGraphicForSave = class(TImagingGraphic)
  100. protected
  101. FDefaultFileExt: string;
  102. FSavingFormat: TImageFormat;
  103. procedure WriteData(Stream: TStream); override;
  104. public
  105. constructor Create; override;
  106. { Saves the current image to the stream. It is saved in the
  107. file format according to the DefaultFileExt property.
  108. So each descendant class can save some other file format.}
  109. procedure SaveToStream(Stream: TStream); override;
  110. { Returns TImageFileFormat descendant for this graphic class.}
  111. class function GetFileFormat: TImageFileFormat; virtual; abstract;
  112. {$IFDEF COMPONENT_SET_LCL}
  113. { Returns file extensions of this graphic class.}
  114. class function GetFileExtensions: string; override;
  115. { Returns default MIME type of this graphic class.}
  116. function GetMimeType: string; override;
  117. {$ENDIF}
  118. { Default (the most common) file extension of this graphic class.}
  119. property DefaultFileExt: string read FDefaultFileExt;
  120. end;
  121. TImagingGraphicForSaveClass = class of TImagingGraphicForSave;
  122. {$IFNDEF DONT_LINK_BITMAP}
  123. { TImagingGraphic descendant for loading/saving Windows bitmaps.
  124. VCL/LCL both have native support for bitmaps so you might
  125. want to disable this class (although you can save bitmaps with
  126. RLE compression with this class).}
  127. TImagingBitmap = class(TImagingGraphicForSave)
  128. protected
  129. FUseRLE: Boolean;
  130. public
  131. constructor Create; override;
  132. procedure SaveToStream(Stream: TStream); override;
  133. class function GetFileFormat: TImageFileFormat; override;
  134. { See ImagingBitmapRLE option for details.}
  135. property UseRLE: Boolean read FUseRLE write FUseRLE;
  136. end;
  137. {$ENDIF}
  138. {$IFNDEF DONT_LINK_JPEG}
  139. { TImagingGraphic descendant for loading/saving JPEG images.}
  140. TImagingJpeg = class(TImagingGraphicForSave)
  141. protected
  142. FQuality: LongInt;
  143. FProgressive: Boolean;
  144. public
  145. constructor Create; override;
  146. procedure SaveToStream(Stream: TStream); override;
  147. class function GetFileFormat: TImageFileFormat; override;
  148. {$IFDEF COMPONENT_SET_LCL}
  149. function GetMimeType: string; override;
  150. {$ENDIF}
  151. { See ImagingJpegQuality option for details.}
  152. property Quality: LongInt read FQuality write FQuality;
  153. { See ImagingJpegProgressive option for details.}
  154. property Progressive: Boolean read FProgressive write FProgressive;
  155. end;
  156. {$ENDIF}
  157. {$IFNDEF DONT_LINK_PNG}
  158. { TImagingGraphic descendant for loading/saving PNG images.}
  159. TImagingPNG = class(TImagingGraphicForSave)
  160. protected
  161. FPreFilter: LongInt;
  162. FCompressLevel: LongInt;
  163. public
  164. constructor Create; override;
  165. procedure SaveToStream(Stream: TStream); override;
  166. class function GetFileFormat: TImageFileFormat; override;
  167. { See ImagingPNGPreFilter option for details.}
  168. property PreFilter: LongInt read FPreFilter write FPreFilter;
  169. { See ImagingPNGCompressLevel option for details.}
  170. property CompressLevel: LongInt read FCompressLevel write FCompressLevel;
  171. end;
  172. {$ENDIF}
  173. {$IFNDEF DONT_LINK_GIF}
  174. { TImagingGraphic descendant for loading/saving GIF images.}
  175. TImagingGIF = class(TImagingGraphicForSave)
  176. public
  177. class function GetFileFormat: TImageFileFormat; override;
  178. end;
  179. {$ENDIF}
  180. {$IFNDEF DONT_LINK_TARGA}
  181. { TImagingGraphic descendant for loading/saving Targa images.}
  182. TImagingTarga = class(TImagingGraphicForSave)
  183. protected
  184. FUseRLE: Boolean;
  185. public
  186. constructor Create; override;
  187. procedure SaveToStream(Stream: TStream); override;
  188. class function GetFileFormat: TImageFileFormat; override;
  189. { See ImagingTargaRLE option for details.}
  190. property UseRLE: Boolean read FUseRLE write FUseRLE;
  191. end;
  192. {$ENDIF}
  193. {$IFNDEF DONT_LINK_DDS}
  194. { Compression type used when saving DDS files by TImagingDds.}
  195. TDDSCompression = (dcNone, dcDXT1, dcDXT3, dcDXT5);
  196. { TImagingGraphic descendant for loading/saving DDS images.}
  197. TImagingDDS = class(TImagingGraphicForSave)
  198. protected
  199. FCompression: TDDSCompression;
  200. public
  201. constructor Create; override;
  202. procedure SaveToStream(Stream: TStream); override;
  203. class function GetFileFormat: TImageFileFormat; override;
  204. { You can choose compression type used when saving DDS file.
  205. dcNone means that file will be saved in the current bitmaps pixel format.}
  206. property Compression: TDDSCompression read FCompression write FCompression;
  207. end;
  208. {$ENDIF}
  209. {$IFNDEF DONT_LINK_MNG}
  210. { TImagingGraphic descendant for loading/saving MNG images.}
  211. TImagingMNG = class(TImagingGraphicForSave)
  212. protected
  213. FLossyCompression: Boolean;
  214. FLossyAlpha: Boolean;
  215. FPreFilter: LongInt;
  216. FCompressLevel: LongInt;
  217. FQuality: LongInt;
  218. FProgressive: Boolean;
  219. public
  220. constructor Create; override;
  221. procedure SaveToStream(Stream: TStream); override;
  222. class function GetFileFormat: TImageFileFormat; override;
  223. {$IFDEF COMPONENT_SET_LCL}
  224. function GetMimeType: string; override;
  225. {$ENDIF}
  226. { See ImagingMNGLossyCompression option for details.}
  227. property LossyCompression: Boolean read FLossyCompression write FLossyCompression;
  228. { See ImagingMNGLossyAlpha option for details.}
  229. property LossyAlpha: Boolean read FLossyAlpha write FLossyAlpha;
  230. { See ImagingMNGPreFilter option for details.}
  231. property PreFilter: LongInt read FPreFilter write FPreFilter;
  232. { See ImagingMNGCompressLevel option for details.}
  233. property CompressLevel: LongInt read FCompressLevel write FCompressLevel;
  234. { See ImagingMNGQuality option for details.}
  235. property Quality: LongInt read FQuality write FQuality;
  236. { See ImagingMNGProgressive option for details.}
  237. property Progressive: Boolean read FProgressive write FProgressive;
  238. end;
  239. {$ENDIF}
  240. {$IFNDEF DONT_LINK_JNG}
  241. { TImagingGraphic descendant for loading/saving JNG images.}
  242. TImagingJNG = class(TImagingGraphicForSave)
  243. protected
  244. FLossyAlpha: Boolean;
  245. FAlphaPreFilter: LongInt;
  246. FAlphaCompressLevel: LongInt;
  247. FQuality: LongInt;
  248. FProgressive: Boolean;
  249. public
  250. constructor Create; override;
  251. procedure SaveToStream(Stream: TStream); override;
  252. class function GetFileFormat: TImageFileFormat; override;
  253. { See ImagingJNGLossyAlpha option for details.}
  254. property LossyAlpha: Boolean read FLossyAlpha write FLossyAlpha;
  255. { See ImagingJNGPreFilter option for details.}
  256. property AlphaPreFilter: LongInt read FAlphaPreFilter write FAlphaPreFilter;
  257. { See ImagingJNGCompressLevel option for details.}
  258. property AlphaCompressLevel: LongInt read FAlphaCompressLevel write FAlphaCompressLevel;
  259. { See ImagingJNGQuality option for details.}
  260. property Quality: LongInt read FQuality write FQuality;
  261. { See ImagingJNGProgressive option for details.}
  262. property Progressive: Boolean read FProgressive write FProgressive;
  263. end;
  264. {$ENDIF}
  265. { Returns bitmap pixel format with the closest match with given data format.}
  266. function DataFormatToPixelFormat(Format: TImageFormat): TPixelFormat;
  267. { Returns data format with closest match with given bitmap pixel format.}
  268. function PixelFormatToDataFormat(Format: TPixelFormat): TImageFormat;
  269. { Converts TImageData structure to VCL/CLX/LCL bitmap.}
  270. procedure ConvertDataToBitmap(const Data: TImageData; Bitmap: TBitmap);
  271. { Converts VCL/CLX/LCL bitmap to TImageData structure.}
  272. procedure ConvertBitmapToData(Bitmap: TBitmap; var Data: TImageData);
  273. { Converts TBaseImage instance to VCL/CLX/LCL bitmap.}
  274. procedure ConvertImageToBitmap(Image: TBaseImage; Bitmap: TBitmap);
  275. { Converts VCL/CLX/LCL bitmap to TBaseImage. Image must exist before
  276. procedure is called. It overwrites its current image data.
  277. When Image is TMultiImage only the current image level is overwritten.}
  278. procedure ConvertBitmapToImage(Bitmap: TBitmap; Image: TBaseImage);
  279. { Displays image onto TCanvas to rectangle DstRect. This procedure
  280. draws image without converting from Imaging format to TBitmap.
  281. Only [ifA8R8G8B8, ifX8R8G8B8] image formats are supported. Use this
  282. when you want displaying images that change frequently (because converting to
  283. TBitmap by ConvertImageDataToBitmap is generally slow).}
  284. procedure DisplayImageData(DstCanvas: TCanvas; const DstRect: TRect; const ImageData: TImageData); overload;
  285. { Displays image stored in TImageData structure onto TCanvas. This procedure
  286. draws image without converting from Imaging format to TBitmap.
  287. Only [ifA8R8G8B8, ifX8R8G8B8] image formats are supported. Use this
  288. when you want displaying images that change frequently (because converting to
  289. TBitmap by ConvertImageDataToBitmap is generally slow). Dest and Src
  290. rectangles represent coordinates in the form (X1, Y1, X2, Y2).}
  291. procedure DisplayImageData(DstCanvas: TCanvas; const DstRect: TRect; const ImageData: TImageData; const SrcRect: TRect); overload;
  292. { Displays image onto TCanvas at position [DstX, DstY]. This procedure
  293. draws image without converting from Imaging format to TBitmap.
  294. Only [ifA8R8G8B8, ifX8R8G8B8] image formats are supported. Use this
  295. when you want displaying images that change frequently (because converting to
  296. TBitmap by ConvertImageDataToBitmap is generally slow).}
  297. procedure DisplayImage(DstCanvas: TCanvas; DstX, DstY: LongInt; Image: TBaseImage); overload;
  298. { Displays image onto TCanvas to rectangle DstRect. This procedure
  299. draws image without converting from Imaging format to TBitmap.
  300. Only [ifA8R8G8B8, ifX8R8G8B8] image formats are supported. Use this
  301. when you want displaying images that change frequently (because converting to
  302. TBitmap by ConvertImageDataToBitmap is generally slow).}
  303. procedure DisplayImage(DstCanvas: TCanvas; const DstRect: TRect; Image: TBaseImage); overload;
  304. { Displays part of the image specified by SrcRect onto TCanvas to rectangle DstRect.
  305. This procedure draws image without converting from Imaging format to TBitmap.
  306. Only [ifA8R8G8B8, ifX8R8G8B8] image formats are supported. Use this
  307. when you want displaying images that change frequently (because converting to
  308. TBitmap by ConvertImageDataToBitmap is generally slow).}
  309. procedure DisplayImage(DstCanvas: TCanvas; const DstRect: TRect; Image: TBaseImage; const SrcRect: TRect); overload;
  310. {$IFDEF MSWINDOWS}
  311. { Displays image stored in TImageData structure onto Windows device context.
  312. Behaviour is the same as of DisplayImageData.}
  313. procedure DisplayImageDataOnDC(DC: HDC; const DstRect: TRect; const ImageData: TImageData; const SrcRect: TRect);
  314. {$ENDIF}
  315. procedure RegisterTypes;
  316. implementation
  317. uses
  318. {$IF Defined(LCL)}
  319. InterfaceBase,
  320. {$IF Defined(LCLGTK2)}
  321. GLib2, GDK2, GTK2, GTK2Def, GTK2Proc,
  322. {$ELSEIF Defined(LCLqt5)}
  323. Qt5, qtobjects,
  324. {$ELSEIF Defined(LCLcocoa)}
  325. CocoaGDIObjects, CocoaUtils,
  326. {$IFEND}
  327. {$IFEND}
  328. {$IFNDEF DONT_LINK_BITMAP}
  329. ImagingBitmap,
  330. {$ENDIF}
  331. {$IFNDEF DONT_LINK_JPEG}
  332. ImagingJpeg,
  333. {$ENDIF}
  334. {$IFNDEF DONT_LINK_GIF}
  335. ImagingGif,
  336. {$ENDIF}
  337. {$IFNDEF DONT_LINK_TARGA}
  338. ImagingTarga,
  339. {$ENDIF}
  340. {$IFNDEF DONT_LINK_DDS}
  341. ImagingDds,
  342. {$ENDIF}
  343. {$IF not Defined(DONT_LINK_PNG) or not Defined(DONT_LINK_MNG) or not Defined(DONT_LINK_JNG)}
  344. ImagingNetworkGraphics,
  345. {$IFEND}
  346. ImagingFormats, ImagingUtility;
  347. resourcestring
  348. SBadFormatDataToBitmap = 'Cannot find compatible bitmap format for image %s';
  349. SBadFormatBitmapToData = 'Cannot find compatible data format for bitmap %p';
  350. SBadFormatDisplay = 'Unsupported image format passed';
  351. SUnsupportedLCLWidgetSet = 'This function is not implemented for current LCL widget set';
  352. SImagingGraphicName = 'Imaging Graphic AllInOne';
  353. var
  354. RegisteredFormats: TList;
  355. RegisteredGraphicsClasses: Boolean = False;
  356. { Registers types to VCL/LCL.
  357. In some cases (base+ext package installed in Lazarus) RegisterTypes can be
  358. called twice so must keep track of which formats were already registered. }
  359. procedure RegisterTypes;
  360. var
  361. I: LongInt;
  362. procedure RegisterFileFormatAllInOne(Format: TImageFileFormat);
  363. var
  364. I: LongInt;
  365. begin
  366. if RegisteredFormats.IndexOf(Format) >= 0 then
  367. Exit;
  368. for I := 0 to Format.Extensions.Count - 1 do
  369. begin
  370. TPicture.RegisterFileFormat(Format.Extensions[I], SImagingGraphicName,
  371. TImagingGraphic);
  372. end;
  373. RegisteredFormats.Add(Format);
  374. end;
  375. procedure RegisterFileFormat(AClass: TImagingGraphicForSaveClass);
  376. var
  377. I: LongInt;
  378. begin
  379. for I := 0 to AClass.GetFileFormat.Extensions.Count - 1 do
  380. TPicture.RegisterFileFormat(AClass.GetFileFormat.Extensions[I],
  381. AClass.GetFileFormat.Name, AClass);
  382. end;
  383. begin
  384. for I := Imaging.GetFileFormatCount - 1 downto 0 do
  385. RegisterFileFormatAllInOne(Imaging.GetFileFormatAtIndex(I));
  386. Classes.RegisterClass(TImagingGraphic);
  387. if RegisteredGraphicsClasses then
  388. Exit;
  389. {$IFNDEF DONT_LINK_TARGA}
  390. RegisterFileFormat(TImagingTarga);
  391. Classes.RegisterClass(TImagingTarga);
  392. {$ENDIF}
  393. {$IFNDEF DONT_LINK_DDS}
  394. RegisterFileFormat(TImagingDDS);
  395. Classes.RegisterClass(TImagingDDS);
  396. {$ENDIF}
  397. {$IFNDEF DONT_LINK_JNG}
  398. RegisterFileFormat(TImagingJNG);
  399. Classes.RegisterClass(TImagingJNG);
  400. {$ENDIF}
  401. {$IFNDEF DONT_LINK_MNG}
  402. RegisterFileFormat(TImagingMNG);
  403. Classes.RegisterClass(TImagingMNG);
  404. {$ENDIF}
  405. {$IFNDEF DONT_LINK_GIF}
  406. RegisterFileFormat(TImagingGIF);
  407. Classes.RegisterClass(TImagingGIF);
  408. {$ENDIF}
  409. {$IFNDEF DONT_LINK_PNG}
  410. {$IFDEF COMPONENT_SET_LCL}
  411. // Unregister Lazarus default PNG loader which crashes on some PNG files
  412. TPicture.UnregisterGraphicClass(TPortableNetworkGraphic);
  413. {$ENDIF}
  414. RegisterFileFormat(TImagingPNG);
  415. Classes.RegisterClass(TImagingPNG);
  416. {$ENDIF}
  417. {$IFNDEF DONT_LINK_JPEG}
  418. RegisterFileFormat(TImagingJpeg);
  419. Classes.RegisterClass(TImagingJpeg);
  420. {$ENDIF}
  421. {$IFNDEF DONT_LINK_BITMAP}
  422. RegisterFileFormat(TImagingBitmap);
  423. Classes.RegisterClass(TImagingBitmap);
  424. {$ENDIF}
  425. RegisteredGraphicsClasses := True;
  426. end;
  427. { Unregisters types from VCL/LCL.}
  428. procedure UnRegisterTypes;
  429. begin
  430. {$IFNDEF DONT_LINK_BITMAP}
  431. TPicture.UnregisterGraphicClass(TImagingBitmap);
  432. Classes.UnRegisterClass(TImagingBitmap);
  433. {$ENDIF}
  434. {$IFNDEF DONT_LINK_JPEG}
  435. TPicture.UnregisterGraphicClass(TImagingJpeg);
  436. Classes.UnRegisterClass(TImagingJpeg);
  437. {$ENDIF}
  438. {$IFNDEF DONT_LINK_PNG}
  439. TPicture.UnregisterGraphicClass(TImagingPNG);
  440. Classes.UnRegisterClass(TImagingPNG);
  441. {$ENDIF}
  442. {$IFNDEF DONT_LINK_GIF}
  443. TPicture.UnregisterGraphicClass(TImagingGIF);
  444. Classes.UnRegisterClass(TImagingGIF);
  445. {$ENDIF}
  446. {$IFNDEF DONT_LINK_TARGA}
  447. TPicture.UnregisterGraphicClass(TImagingTarga);
  448. Classes.UnRegisterClass(TImagingTarga);
  449. {$ENDIF}
  450. {$IFNDEF DONT_LINK_DDS}
  451. TPicture.UnregisterGraphicClass(TImagingDDS);
  452. Classes.UnRegisterClass(TImagingDDS);
  453. {$ENDIF}
  454. TPicture.UnregisterGraphicClass(TImagingGraphic);
  455. Classes.UnRegisterClass(TImagingGraphic);
  456. end;
  457. function DataFormatToPixelFormat(Format: TImageFormat): TPixelFormat;
  458. begin
  459. case Format of
  460. {$IFDEF COMPONENT_SET_VCL}
  461. ifIndex8: Result := pf8bit;
  462. ifR5G6B5: Result := pf16bit;
  463. ifR8G8B8: Result := pf24bit;
  464. {$ENDIF}
  465. ifA8R8G8B8,
  466. ifX8R8G8B8: Result := pf32bit;
  467. else
  468. Result := pfCustom;
  469. end;
  470. end;
  471. function PixelFormatToDataFormat(Format: TPixelFormat): TImageFormat;
  472. begin
  473. case Format of
  474. pf8bit: Result := ifIndex8;
  475. pf15bit: Result := ifA1R5G5B5;
  476. pf16bit: Result := ifR5G6B5;
  477. pf24bit: Result := ifR8G8B8;
  478. pf32bit: Result := ifA8R8G8B8;
  479. else
  480. Result := ifUnknown;
  481. end;
  482. end;
  483. procedure ConvertDataToBitmap(const Data: TImageData; Bitmap: TBitmap);
  484. var
  485. PF: TPixelFormat;
  486. Info: TImageFormatInfo;
  487. WorkData: TImageData;
  488. {$IFDEF COMPONENT_SET_VCL}
  489. I, LineBytes: LongInt;
  490. LogPalette: TMaxLogPalette;
  491. {$ENDIF}
  492. {$IFDEF COMPONENT_SET_LCL}
  493. RawImage: TRawImage;
  494. ImgHandle, ImgMaskHandle: HBitmap;
  495. {$ENDIF}
  496. begin
  497. PF := DataFormatToPixelFormat(Data.Format);
  498. GetImageFormatInfo(Data.Format, Info);
  499. if (PF = pf8bit) and PaletteHasAlpha(Data.Palette, Info.PaletteEntries) then
  500. begin
  501. // Some indexed images may have valid alpha data, don't lose it!
  502. // (e.g. transparent 8bit PNG or GIF images)
  503. PF := pfCustom;
  504. end;
  505. if PF = pfCustom then
  506. begin
  507. // Convert from formats not supported by Graphics unit
  508. Imaging.InitImage(WorkData);
  509. Imaging.CloneImage(Data, WorkData);
  510. if Info.IsFloatingPoint or Info.HasAlphaChannel or Info.IsSpecial then
  511. Imaging.ConvertImage(WorkData, ifA8R8G8B8)
  512. else
  513. begin
  514. {$IFDEF COMPONENT_SET_VCL}
  515. if Info.IsIndexed or Info.HasGrayChannel then
  516. Imaging.ConvertImage(WorkData, ifIndex8)
  517. else if Info.UsePixelFormat then
  518. Imaging.ConvertImage(WorkData, ifR5G6B5)
  519. else
  520. Imaging.ConvertImage(WorkData, ifR8G8B8);
  521. {$ELSE}
  522. Imaging.ConvertImage(WorkData, ifA8R8G8B8);
  523. {$ENDIF}
  524. end;
  525. PF := DataFormatToPixelFormat(WorkData.Format);
  526. GetImageFormatInfo(WorkData.Format, Info);
  527. end
  528. else
  529. WorkData := Data;
  530. if PF = pfCustom then
  531. RaiseImaging(SBadFormatDataToBitmap, [ImageToStr(WorkData)]);
  532. {$IFDEF COMPONENT_SET_VCL}
  533. Bitmap.Width := WorkData.Width;
  534. Bitmap.Height := WorkData.Height;
  535. Bitmap.PixelFormat := PF;
  536. if (PF = pf8bit) and (WorkData.Palette <> nil) then
  537. begin
  538. // Copy palette, this must be done before copying bits
  539. FillChar(LogPalette, SizeOf(LogPalette), 0);
  540. LogPalette.palVersion := $300;
  541. LogPalette.palNumEntries := Info.PaletteEntries;
  542. for I := 0 to Info.PaletteEntries - 1 do
  543. with LogPalette do
  544. begin
  545. palPalEntry[I].peRed := WorkData.Palette[I].R;
  546. palPalEntry[I].peGreen := WorkData.Palette[I].G;
  547. palPalEntry[I].peBlue := WorkData.Palette[I].B;
  548. end;
  549. Bitmap.Palette := CreatePalette(PLogPalette(@LogPalette)^);
  550. end;
  551. // Copy scanlines
  552. LineBytes := WorkData.Width * Info.BytesPerPixel;
  553. for I := 0 to WorkData.Height - 1 do
  554. Move(PByteArray(WorkData.Bits)[I * LineBytes], Bitmap.Scanline[I]^, LineBytes);
  555. // Delphi 2009 and newer support alpha transparency for TBitmap
  556. {$IF Defined(DELPHI) and (CompilerVersion >= 20.0)}
  557. if Bitmap.PixelFormat = pf32bit then
  558. Bitmap.AlphaFormat := afDefined;
  559. {$IFEND}
  560. {$ENDIF}
  561. {$IFDEF COMPONENT_SET_LCL}
  562. // Create 32bit raw image from image data
  563. FillChar(RawImage, SizeOf(RawImage), 0);
  564. with RawImage.Description do
  565. begin
  566. Width := WorkData.Width;
  567. Height := WorkData.Height;
  568. BitsPerPixel := 32;
  569. Format := ricfRGBA;
  570. LineEnd := rileDWordBoundary;
  571. BitOrder := riboBitsInOrder;
  572. ByteOrder := riboLSBFirst;
  573. LineOrder := riloTopToBottom;
  574. AlphaPrec := 8;
  575. RedPrec := 8;
  576. GreenPrec := 8;
  577. BluePrec := 8;
  578. AlphaShift := 24;
  579. RedShift := 16;
  580. GreenShift := 8;
  581. BlueShift := 0;
  582. Depth := 32; // Must be 32 for alpha blending (and for working in MacOSX Carbon)
  583. end;
  584. RawImage.Data := WorkData.Bits;
  585. RawImage.DataSize := WorkData.Size;
  586. // Create bitmap from raw image
  587. if RawImage_CreateBitmaps(RawImage, ImgHandle, ImgMaskHandle) then
  588. begin
  589. Bitmap.Handle := ImgHandle;
  590. Bitmap.MaskHandle := ImgMaskHandle;
  591. end;
  592. {$ENDIF}
  593. if WorkData.Bits <> Data.Bits then
  594. Imaging.FreeImage(WorkData);
  595. end;
  596. procedure ConvertBitmapToData(Bitmap: TBitmap; var Data: TImageData);
  597. var
  598. I, LineBytes: LongInt;
  599. Format: TImageFormat;
  600. Info: TImageFormatInfo;
  601. {$IFDEF COMPONENT_SET_VCL}
  602. Colors: Word;
  603. LogPalette: TMaxLogPalette;
  604. {$ENDIF}
  605. {$IFDEF COMPONENT_SET_LCL}
  606. RawImage: TRawImage;
  607. LineLazBytes: LongInt;
  608. {$ENDIF}
  609. begin
  610. Format := ifUnknown;
  611. {$IFDEF COMPONENT_SET_LCL}
  612. // In the current Lazarus 0.9.10 Bitmap.PixelFormat property is useless.
  613. // We cannot change bitmap's format by changing it (it will just release
  614. // old image but not convert it to new format) nor we can determine bitmaps's
  615. // current format (it is usually set to pfDevice). So bitmap's format is obtained
  616. // trough RawImage api and cannot be changed to mirror some Imaging format
  617. // (so formats with no corresponding Imaging format cannot be saved now).
  618. if RawImage_DescriptionFromBitmap(Bitmap.Handle, RawImage.Description) then
  619. case RawImage.Description.BitsPerPixel of
  620. 8: Format := ifIndex8;
  621. 16:
  622. if RawImage.Description.Depth = 15 then
  623. Format := ifA1R5G5B5
  624. else
  625. Format := ifR5G6B5;
  626. 24: Format := ifR8G8B8;
  627. 32: Format := ifA8R8G8B8;
  628. 48: Format := ifR16G16B16;
  629. 64: Format := ifA16R16G16B16;
  630. end;
  631. {$ELSE}
  632. Format := PixelFormatToDataFormat(Bitmap.PixelFormat);
  633. if Format = ifUnknown then
  634. begin
  635. // Convert from formats not supported by Imaging (1/4 bit)
  636. if Bitmap.PixelFormat < pf8bit then
  637. Bitmap.PixelFormat := pf8bit
  638. else
  639. Bitmap.PixelFormat := pf32bit;
  640. Format := PixelFormatToDataFormat(Bitmap.PixelFormat);
  641. end;
  642. {$ENDIF}
  643. if Format = ifUnknown then
  644. RaiseImaging(SBadFormatBitmapToData, []);
  645. Imaging.NewImage(Bitmap.Width, Bitmap.Height, Format, Data);
  646. GetImageFormatInfo(Data.Format, Info);
  647. LineBytes := Data.Width * Info.BytesPerPixel;
  648. {$IFDEF COMPONENT_SET_VCL}
  649. if (Format = ifIndex8) and (GetObject(Bitmap.Palette, SizeOf(Colors),
  650. @Colors) <> 0) then
  651. begin
  652. // Copy palette
  653. GetPaletteEntries(Bitmap.Palette, 0, Colors, LogPalette.palPalEntry);
  654. if Colors > Info.PaletteEntries then
  655. Colors := Info.PaletteEntries;
  656. for I := 0 to Colors - 1 do
  657. with LogPalette do
  658. begin
  659. Data.Palette[I].A := $FF;
  660. Data.Palette[I].R := palPalEntry[I].peRed;
  661. Data.Palette[I].G := palPalEntry[I].peGreen;
  662. Data.Palette[I].B := palPalEntry[I].peBlue;
  663. end;
  664. end;
  665. // Copy scanlines
  666. for I := 0 to Data.Height - 1 do
  667. Move(Bitmap.ScanLine[I]^, PByteArray(Data.Bits)[I * LineBytes], LineBytes);
  668. {$ENDIF}
  669. {$IFDEF COMPONENT_SET_LCL}
  670. // Get raw image from bitmap (mask handle must be 0 or expect violations)
  671. if RawImage_FromBitmap(RawImage, Bitmap.Handle, 0, nil) then
  672. begin
  673. LineLazBytes := GetBytesPerLine(Data.Width, RawImage.Description.BitsPerPixel,
  674. RawImage.Description.LineEnd);
  675. // Copy scanlines
  676. for I := 0 to Data.Height - 1 do
  677. begin
  678. Move(PByteArray(RawImage.Data)[I * LineLazBytes],
  679. PByteArray(Data.Bits)[I * LineBytes], LineBytes);
  680. end;
  681. // May need to swap RB order, depends on widget set
  682. if RawImage.Description.BlueShift > RawImage.Description.RedShift then
  683. SwapChannels(Data, ChannelRed, ChannelBlue);
  684. RawImage.FreeData;
  685. end;
  686. {$ENDIF}
  687. end;
  688. procedure ConvertImageToBitmap(Image: TBaseImage; Bitmap: TBitmap);
  689. begin
  690. ConvertDataToBitmap(Image.ImageDataPointer^, Bitmap);
  691. end;
  692. procedure ConvertBitmapToImage(Bitmap: TBitmap; Image: TBaseImage);
  693. begin
  694. ConvertBitmapToData(Bitmap, Image.ImageDataPointer^);
  695. end;
  696. {$IFDEF MSWINDOWS}
  697. procedure DisplayImageDataOnDC(DC: HDC; const DstRect: TRect; const ImageData: TImageData; const SrcRect: TRect);
  698. var
  699. OldMode: Integer;
  700. BitmapInfo: Windows.TBitmapInfo;
  701. Bmp: TBitmap;
  702. begin
  703. if TestImage(ImageData) then
  704. begin
  705. Assert(ImageData.Format in [ifA8R8G8B8, ifX8R8G8B8], SBadFormatDisplay);
  706. OldMode := Windows.SetStretchBltMode(DC, COLORONCOLOR);
  707. FillChar(BitmapInfo, SizeOf(BitmapInfo), 0);
  708. with BitmapInfo.bmiHeader do
  709. begin
  710. biSize := SizeOf(TBitmapInfoHeader);
  711. biPlanes := 1;
  712. biBitCount := 32;
  713. biCompression := BI_RGB;
  714. biWidth := ImageData.Width;
  715. biHeight := -ImageData.Height;
  716. biSizeImage := ImageData.Size;
  717. biXPelsPerMeter := 0;
  718. biYPelsPerMeter := 0;
  719. biClrUsed := 0;
  720. biClrImportant := 0;
  721. end;
  722. try
  723. with SrcRect, ImageData do
  724. if Windows.StretchDIBits(DC, DstRect.Left, DstRect.Top,
  725. DstRect.Right - DstRect.Left, DstRect.Bottom - DstRect.Top, Left,
  726. Top, Right - Left, Bottom - Top, Bits, BitmapInfo, DIB_RGB_COLORS, SRCCOPY) <> Height then
  727. begin
  728. // StretchDIBits may fail on some occasions (error 487, http://support.microsoft.com/kb/269585).
  729. // This fallback is slow but works every time. Thanks to Sergey Galezdinov for the fix.
  730. Bmp := TBitmap.Create;
  731. try
  732. ConvertDataToBitmap(ImageData, Bmp);
  733. StretchBlt(DC, DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left, DstRect.Bottom - DstRect.Top,
  734. Bmp.Canvas.Handle, 0, 0, Width, Height, SRCCOPY);
  735. finally
  736. Bmp.Free;
  737. end;
  738. end;
  739. finally
  740. Windows.SetStretchBltMode(DC, OldMode);
  741. end;
  742. end;
  743. end;
  744. {$ENDIF}
  745. procedure DisplayImageData(DstCanvas: TCanvas; const DstRect: TRect; const ImageData: TImageData);
  746. begin
  747. DisplayImageData(DstCanvas, DstRect, ImageData, Rect(0, 0, ImageData.Width, ImageData.Height));
  748. end;
  749. procedure DisplayImageData(DstCanvas: TCanvas; const DstRect: TRect; const ImageData: TImageData; const SrcRect: TRect);
  750. {$IF Defined(DCC) or Defined(LCLWIN32)} // Delphi or LCL Win32
  751. begin
  752. DisplayImageDataOnDC(DstCanvas.Handle, DstRect, ImageData, SrcRect);
  753. end;
  754. {$ELSEIF Defined(LCLGTK2)}
  755. procedure GDKDrawBitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY,
  756. SrcWidth, SrcHeight: Integer; ImageData: TImageData);
  757. var
  758. P: TPoint;
  759. begin
  760. P := TGtkDeviceContext(Dest).Offset;
  761. Inc(DstX, P.X);
  762. Inc(DstY, P.Y);
  763. if ImageData.Format = ifR8G8B8 then
  764. begin
  765. gdk_draw_rgb_image(TGtkDeviceContext(Dest).Drawable, TGtkDeviceContext(Dest).GC,
  766. DstX, DstY, SrcWidth, SrcHeight, GDK_RGB_DITHER_NONE,
  767. @PUInt32Array(ImageData.Bits)[SrcY * ImageData.Width + SrcX], ImageData.Width * 3);
  768. end
  769. else
  770. begin
  771. gdk_draw_rgb_32_image(TGtkDeviceContext(Dest).Drawable, TGtkDeviceContext(Dest).GC,
  772. DstX, DstY, SrcWidth, SrcHeight, GDK_RGB_DITHER_NONE,
  773. @PUInt32Array(ImageData.Bits)[SrcY * ImageData.Width + SrcX], ImageData.Width * 4);
  774. end;
  775. end;
  776. var
  777. DisplayImage: TImageData;
  778. NewWidth, NewHeight: Integer;
  779. SrcBounds, DstBounds, DstClip: TRect;
  780. begin
  781. if TestImage(ImageData) then
  782. begin
  783. if not (ImageData.Format in [ifR8G8B8, ifA8R8G8B8, ifX8R8G8B8]) then
  784. raise EImagingError.Create(SBadFormatDisplay);
  785. InitImage(DisplayImage);
  786. SrcBounds := RectToBounds(SrcRect);
  787. DstBounds := RectToBounds(DstRect);
  788. WidgetSet.GetClipBox(DstCanvas.Handle, @DstClip);
  789. ClipStretchBounds(SrcBounds.Left, SrcBounds.Top, SrcBounds.Right, SrcBounds.Bottom,
  790. DstBounds.Left, DstBounds.Top, DstBounds.Right, DstBounds.Bottom, ImageData.Width,
  791. ImageData.Height, DstClip);
  792. NewWidth := DstBounds.Right;
  793. NewHeight := DstBounds.Bottom;
  794. if (NewWidth > 0) and (NewHeight > 0) then
  795. begin
  796. if (SrcBounds.Right = NewWidth) and (SrcBounds.Bottom = NewHeight) then
  797. try
  798. CloneImage(ImageData, DisplayImage);
  799. // Swap R-B channels for GTK display compatibility!
  800. SwapChannels(DisplayImage, ChannelRed, ChannelBlue);
  801. GDKDrawBitmap(DstCanvas.Handle, DstBounds.Left, DstBounds.Top,
  802. SrcBounds.Left, SrcBounds.Top, NewWidth, NewHeight, DisplayImage);
  803. finally
  804. FreeImage(DisplayImage);
  805. end
  806. else
  807. try
  808. // Create new image with desired dimensions
  809. NewImage(NewWidth, NewHeight, ImageData.Format, DisplayImage);
  810. // Stretch pixels from old image to new one TResizeFilter = (rfNearest, rfBilinear, rfBicubic);
  811. StretchRect(ImageData, SrcBounds.Left, SrcBounds.Top, SrcBounds.Right,
  812. SrcBounds.Bottom, DisplayImage, 0, 0, NewWidth, NewHeight, rfNearest);
  813. // Swap R-B channels for GTK display compatibility!
  814. SwapChannels(DisplayImage, ChannelRed, ChannelBlue);
  815. GDKDrawBitmap(DstCanvas.Handle, DstBounds.Left, DstBounds.Top, 0, 0,
  816. NewWidth, NewHeight, DisplayImage);
  817. finally
  818. FreeImage(DisplayImage);
  819. end
  820. end;
  821. end;
  822. end;
  823. {$ELSEIF Defined(LCLqt5)}
  824. var
  825. QImage: TQtImage;
  826. Context: TQtDeviceContext;
  827. begin
  828. if TestImage(ImageData) then
  829. begin
  830. if not (ImageData.Format in [ifA8R8G8B8, ifX8R8G8B8]) then
  831. raise EImagingError.Create(SBadFormatDisplay);
  832. Context := TQtDeviceContext(DstCanvas.Handle);
  833. // QImage directly uses the image memory, there is no copy done
  834. QImage := TQtImage.Create(ImageData.Bits, ImageData.Width, ImageData.Height,
  835. ImageData.Width * 4, QImageFormat_ARGB32, False);
  836. try
  837. QPainter_drawImage(Context.Widget, PRect(@DstRect), QImage.Handle, @SrcRect, QtAutoColor);
  838. finally
  839. QImage.Free;
  840. end;
  841. end;
  842. end;
  843. {$ELSEIF Defined(LCLcocoa)}
  844. var
  845. CocoaBmp: TCocoaBitmap;
  846. Context: TCocoaContext;
  847. begin
  848. if TestImage(ImageData) then
  849. begin
  850. if not (ImageData.Format in [ifA8R8G8B8, ifX8R8G8B8]) then
  851. raise EImagingError.Create(SBadFormatDisplay);
  852. Context := CheckDC(DstCanvas.Handle);
  853. // We copy the data since it needs R/B swap and potentially alpha pre-multiply
  854. CocoaBmp := TCocoaBitmap.Create(ImageData.Width, ImageData.Height, 32, 32,
  855. cbaDWord, cbtBGRA, ImageData.Bits, True);
  856. try
  857. Context.DrawImageRep(RectToNSRect(DstRect), RectToNSRect(SrcRect), CocoaBmp.ImageRep);
  858. finally
  859. CocoaBmp.Free;
  860. end;
  861. end;
  862. end;
  863. {$ELSE}
  864. begin
  865. raise EImagingError.Create(SUnsupportedLCLWidgetSet);
  866. end;
  867. {$IFEND}
  868. procedure DisplayImage(DstCanvas: TCanvas; DstX, DstY: LongInt; Image: TBaseImage);
  869. begin
  870. DisplayImageData(DstCanvas, BoundsToRect(DstX, DstY, Image.Width, Image.Height),
  871. Image.ImageDataPointer^, Image.BoundsRect);
  872. end;
  873. procedure DisplayImage(DstCanvas: TCanvas; const DstRect: TRect; Image: TBaseImage);
  874. begin
  875. DisplayImageData(DstCanvas, DstRect, Image.ImageDataPointer^, Image.BoundsRect);
  876. end;
  877. procedure DisplayImage(DstCanvas: TCanvas; const DstRect: TRect; Image: TBaseImage; const SrcRect: TRect);
  878. begin
  879. DisplayImageData(DstCanvas, DstRect, Image.ImageDataPointer^, SrcRect);
  880. end;
  881. { TImagingGraphic class implementation }
  882. constructor TImagingGraphic.Create;
  883. begin
  884. inherited Create;
  885. PixelFormat := pf24Bit;
  886. end;
  887. procedure TImagingGraphic.ReadData(Stream: TStream);
  888. begin
  889. // Here we need to skip ReadData+WriteData of TBitmap (and LCL TRasterBitmap)
  890. // and go to the basics in TGraphic's ReadData+WriteData with just LoadFromStream
  891. // and SaveToStream.
  892. // Some VCL/LCL TGraphic classes also store size of the written data
  893. // before the stream contents. However, the stream passed here
  894. // from TReader.DefineBinaryProperty is already
  895. // a memory stream capped to the size of binary property data.
  896. // Picture.Data = <vaBinary><Size(TWriter)><TGraphicClassName(TPicture)><ImageBits(TImagingGraphicForSave)>
  897. LoadFromStream(Stream);
  898. end;
  899. procedure TImagingGraphic.WriteData(Stream: TStream);
  900. begin
  901. // This can happen when streaming some of the formats that don't have
  902. // TImagingGraphicForSave descendant.
  903. SaveToStream(Stream);
  904. end;
  905. procedure TImagingGraphic.LoadFromStream(Stream: TStream);
  906. var
  907. Image: TSingleImage;
  908. begin
  909. Image := TSingleImage.Create;
  910. try
  911. Image.LoadFromStream(Stream);
  912. Assign(Image);
  913. finally
  914. Image.Free;
  915. end;
  916. end;
  917. procedure TImagingGraphic.SaveToStream(Stream: TStream);
  918. var
  919. Image: TSingleImage;
  920. begin
  921. Image := TSingleImage.Create;
  922. try
  923. Image.Assign(Self);
  924. Image.SaveToStream('png', Stream);
  925. finally
  926. Image.Free;
  927. end;
  928. end;
  929. procedure TImagingGraphic.AssignTo(Dest: TPersistent);
  930. var
  931. Arr: TDynImageDataArray;
  932. begin
  933. if Dest is TSingleImage then
  934. begin
  935. AssignToImage(TSingleImage(Dest))
  936. end
  937. else if Dest is TMultiImage then
  938. begin
  939. SetLength(Arr, 1);
  940. AssignToImageData(Arr[0]);
  941. TMultiImage(Dest).CreateFromArray(Arr);
  942. Imaging.FreeImagesInArray(Arr);
  943. end
  944. else
  945. inherited AssignTo(Dest);
  946. end;
  947. {$IFDEF COMPONENT_SET_LCL}
  948. function TImagingGraphic.GetResourceType: TResourceType;
  949. begin
  950. Result := RT_RCDATA;
  951. end;
  952. class function TImagingGraphic.IsStreamFormatSupported(Stream: TStream): Boolean;
  953. begin
  954. Result := DetermineStreamFormat(Stream) <> '';
  955. end;
  956. {$ENDIF}
  957. procedure TImagingGraphic.Assign(Source: TPersistent);
  958. begin
  959. if Source is TBaseImage then
  960. AssignFromImage(TBaseImage(Source))
  961. else
  962. inherited Assign(Source);
  963. end;
  964. procedure TImagingGraphic.AssignFromImage(Image: TBaseImage);
  965. begin
  966. if (Image <> nil) and Image.Valid then
  967. AssignFromImageData(Image.ImageDataPointer^);
  968. end;
  969. procedure TImagingGraphic.AssignToImage(Image: TBaseImage);
  970. begin
  971. if (Image <> nil) and (Image.ImageDataPointer <> nil) then
  972. AssignToImageData(Image.ImageDataPointer^);
  973. end;
  974. procedure TImagingGraphic.AssignFromImageData(const ImageData: TImageData);
  975. begin
  976. if Imaging.TestImage(ImageData) then
  977. ConvertDataToBitmap(ImageData, Self);
  978. end;
  979. procedure TImagingGraphic.AssignToImageData(var ImageData: TImageData);
  980. begin
  981. Imaging.FreeImage(ImageData);
  982. ConvertBitmapToData(Self, ImageData);
  983. end;
  984. { TImagingGraphicForSave class implementation }
  985. constructor TImagingGraphicForSave.Create;
  986. begin
  987. inherited Create;
  988. FDefaultFileExt := GetFileFormat.Extensions[0];
  989. FSavingFormat := ifUnknown;
  990. GetFileFormat.CheckOptionsValidity;
  991. end;
  992. procedure TImagingGraphicForSave.WriteData(Stream: TStream);
  993. begin
  994. SaveToStream(Stream);
  995. end;
  996. procedure TImagingGraphicForSave.SaveToStream(Stream: TStream);
  997. var
  998. Image: TSingleImage;
  999. begin
  1000. if FDefaultFileExt <> '' then
  1001. begin
  1002. Image := TSingleImage.Create;
  1003. try
  1004. Image.Assign(Self);
  1005. if FSavingFormat <> ifUnknown then
  1006. Image.Format := FSavingFormat;
  1007. Image.SaveToStream(FDefaultFileExt, Stream);
  1008. finally
  1009. Image.Free;
  1010. end;
  1011. end;
  1012. end;
  1013. {$IFDEF COMPONENT_SET_LCL}
  1014. class function TImagingGraphicForSave.GetFileExtensions: string;
  1015. begin
  1016. Result := StringReplace(GetFileFormat.Extensions.CommaText, ',', ';', [rfReplaceAll]);
  1017. end;
  1018. function TImagingGraphicForSave.GetMimeType: string;
  1019. begin
  1020. Result := 'image/' + FDefaultFileExt;
  1021. end;
  1022. {$ENDIF}
  1023. {$IFNDEF DONT_LINK_BITMAP}
  1024. constructor TImagingBitmap.Create;
  1025. begin
  1026. inherited Create;
  1027. FUseRLE := (GetFileFormat as TBitmapFileFormat).UseRLE;
  1028. end;
  1029. class function TImagingBitmap.GetFileFormat: TImageFileFormat;
  1030. begin
  1031. Result := FindImageFileFormatByClass(TBitmapFileFormat);
  1032. end;
  1033. procedure TImagingBitmap.SaveToStream(Stream: TStream);
  1034. begin
  1035. Imaging.PushOptions;
  1036. Imaging.SetOption(ImagingBitmapRLE, Ord(FUseRLE));
  1037. inherited SaveToStream(Stream);
  1038. Imaging.PopOptions;
  1039. end;
  1040. {$ENDIF}
  1041. {$IFNDEF DONT_LINK_JPEG}
  1042. constructor TImagingJpeg.Create;
  1043. begin
  1044. inherited Create;
  1045. FQuality := (GetFileFormat as TJpegFileFormat).Quality;
  1046. FProgressive := (GetFileFormat as TJpegFileFormat).Progressive;
  1047. end;
  1048. class function TImagingJpeg.GetFileFormat: TImageFileFormat;
  1049. begin
  1050. Result := FindImageFileFormatByClass(TJpegFileFormat);
  1051. end;
  1052. {$IFDEF COMPONENT_SET_LCL}
  1053. function TImagingJpeg.GetMimeType: string;
  1054. begin
  1055. Result := 'image/jpeg';
  1056. end;
  1057. {$ENDIF}
  1058. procedure TImagingJpeg.SaveToStream(Stream: TStream);
  1059. begin
  1060. Imaging.PushOptions;
  1061. Imaging.SetOption(ImagingJpegQuality, FQuality);
  1062. Imaging.SetOption(ImagingJpegProgressive, Ord(FProgressive));
  1063. inherited SaveToStream(Stream);
  1064. Imaging.PopOptions;
  1065. end;
  1066. {$ENDIF}
  1067. {$IFNDEF DONT_LINK_PNG}
  1068. constructor TImagingPNG.Create;
  1069. begin
  1070. inherited Create;
  1071. FPreFilter := (GetFileFormat as TPNGFileFormat).PreFilter;
  1072. FCompressLevel := (GetFileFormat as TPNGFileFormat).CompressLevel;
  1073. end;
  1074. class function TImagingPNG.GetFileFormat: TImageFileFormat;
  1075. begin
  1076. Result := FindImageFileFormatByClass(TPNGFileFormat);
  1077. end;
  1078. procedure TImagingPNG.SaveToStream(Stream: TStream);
  1079. begin
  1080. Imaging.PushOptions;
  1081. Imaging.SetOption(ImagingPNGPreFilter, FPreFilter);
  1082. Imaging.SetOption(ImagingPNGCompressLevel, FCompressLevel);
  1083. inherited SaveToStream(Stream);
  1084. Imaging.PopOptions;
  1085. end;
  1086. {$ENDIF}
  1087. {$IFNDEF DONT_LINK_GIF}
  1088. class function TImagingGIF.GetFileFormat: TImageFileFormat;
  1089. begin
  1090. Result := FindImageFileFormatByClass(TGIFFileFormat);
  1091. end;
  1092. {$ENDIF}
  1093. {$IFNDEF DONT_LINK_TARGA}
  1094. constructor TImagingTarga.Create;
  1095. begin
  1096. inherited Create;
  1097. FUseRLE := (GetFileFormat as TTargaFileFormat).UseRLE;
  1098. end;
  1099. class function TImagingTarga.GetFileFormat: TImageFileFormat;
  1100. begin
  1101. Result := FindImageFileFormatByClass(TTargaFileFormat);
  1102. end;
  1103. procedure TImagingTarga.SaveToStream(Stream: TStream);
  1104. begin
  1105. Imaging.PushOptions;
  1106. Imaging.SetOption(ImagingTargaRLE, Ord(FUseRLE));
  1107. inherited SaveToStream(Stream);
  1108. Imaging.PopOptions;
  1109. end;
  1110. {$ENDIF}
  1111. {$IFNDEF DONT_LINK_DDS}
  1112. constructor TImagingDDS.Create;
  1113. begin
  1114. inherited Create;
  1115. FCompression := dcNone;
  1116. end;
  1117. class function TImagingDDS.GetFileFormat: TImageFileFormat;
  1118. begin
  1119. Result := FindImageFileFormatByClass(TDDSFileFormat);
  1120. end;
  1121. procedure TImagingDDS.SaveToStream(Stream: TStream);
  1122. begin
  1123. case FCompression of
  1124. dcNone: FSavingFormat := ifUnknown;
  1125. dcDXT1: FSavingFormat := ifDXT1;
  1126. dcDXT3: FSavingFormat := ifDXT3;
  1127. dcDXT5: FSavingFormat := ifDXT5;
  1128. end;
  1129. Imaging.PushOptions;
  1130. Imaging.SetOption(ImagingDDSSaveCubeMap, Ord(False));
  1131. Imaging.SetOption(ImagingDDSSaveVolume, Ord(False));
  1132. Imaging.SetOption(ImagingDDSSaveMipMapCount, 1);
  1133. Imaging.SetOption(ImagingDDSSaveDepth, 1);
  1134. inherited SaveToStream(Stream);
  1135. Imaging.PopOptions;
  1136. end;
  1137. {$ENDIF}
  1138. {$IFNDEF DONT_LINK_MNG}
  1139. constructor TImagingMNG.Create;
  1140. begin
  1141. inherited Create;
  1142. FLossyCompression := (GetFileFormat as TMNGFileFormat).LossyCompression;
  1143. FLossyAlpha := (GetFileFormat as TMNGFileFormat).LossyAlpha;
  1144. FPreFilter := (GetFileFormat as TMNGFileFormat).PreFilter;
  1145. FCompressLevel := (GetFileFormat as TMNGFileFormat).CompressLevel;
  1146. FQuality := (GetFileFormat as TMNGFileFormat).Quality;
  1147. FProgressive := (GetFileFormat as TMNGFileFormat).Progressive;
  1148. end;
  1149. class function TImagingMNG.GetFileFormat: TImageFileFormat;
  1150. begin
  1151. Result := FindImageFileFormatByClass(TMNGFileFormat);
  1152. end;
  1153. {$IFDEF COMPONENT_SET_LCL}
  1154. function TImagingMNG.GetMimeType: string;
  1155. begin
  1156. Result := 'video/mng';
  1157. end;
  1158. {$ENDIF}
  1159. procedure TImagingMNG.SaveToStream(Stream: TStream);
  1160. begin
  1161. Imaging.PushOptions;
  1162. Imaging.SetOption(ImagingMNGLossyCompression, Ord(FLossyCompression));
  1163. Imaging.SetOption(ImagingMNGLossyAlpha, Ord(FLossyAlpha));
  1164. Imaging.SetOption(ImagingMNGPreFilter, FPreFilter);
  1165. Imaging.SetOption(ImagingMNGCompressLevel, FCompressLevel);
  1166. Imaging.SetOption(ImagingMNGQuality, FQuality);
  1167. Imaging.SetOption(ImagingMNGProgressive, Ord(FProgressive));
  1168. inherited SaveToStream(Stream);
  1169. Imaging.PopOptions;
  1170. end;
  1171. {$ENDIF}
  1172. {$IFNDEF DONT_LINK_JNG}
  1173. constructor TImagingJNG.Create;
  1174. begin
  1175. inherited Create;
  1176. FLossyAlpha := (GetFileFormat as TJNGFileFormat).LossyAlpha;
  1177. FAlphaPreFilter := (GetFileFormat as TJNGFileFormat).PreFilter;
  1178. FAlphaCompressLevel := (GetFileFormat as TJNGFileFormat).CompressLevel;
  1179. FQuality := (GetFileFormat as TJNGFileFormat).Quality;
  1180. FProgressive := (GetFileFormat as TJNGFileFormat).Progressive;
  1181. end;
  1182. class function TImagingJNG.GetFileFormat: TImageFileFormat;
  1183. begin
  1184. Result := FindImageFileFormatByClass(TJNGFileFormat);
  1185. end;
  1186. procedure TImagingJNG.SaveToStream(Stream: TStream);
  1187. begin
  1188. Imaging.PushOptions;
  1189. Imaging.SetOption(ImagingJNGLossyALpha, Ord(FLossyAlpha));
  1190. Imaging.SetOption(ImagingJNGAlphaPreFilter, FAlphaPreFilter);
  1191. Imaging.SetOption(ImagingJNGAlphaCompressLevel, FAlphaCompressLevel);
  1192. Imaging.SetOption(ImagingJNGQuality, FQuality);
  1193. Imaging.SetOption(ImagingJNGProgressive, Ord(FProgressive));
  1194. inherited SaveToStream(Stream);
  1195. Imaging.PopOptions;
  1196. end;
  1197. {$ENDIF}
  1198. initialization
  1199. RegisteredFormats := TList.Create;
  1200. RegisterTypes;
  1201. finalization
  1202. UnRegisterTypes;
  1203. RegisteredFormats.Free;
  1204. {$IFEND} // {$IF not Defined(COMPONENT_SET_LCL) and not Defined(COMPONENT_SET_VCL)}
  1205. {
  1206. File Notes:
  1207. -- 0.77.1 ---------------------------------------------------
  1208. - Fixed bug in ConvertBitmapToData causing images from GTK2 bitmaps
  1209. to have swapped RB channels.
  1210. - LCL: Removed GTK1 support (deprecated).
  1211. -- 0.26.3 Changes/Bug Fixes ---------------------------------
  1212. - Transparency of 8bit images (like loaded from 8bit PNG or GIF) is
  1213. kept intact during conversion to TBitmap in ConvertDataToBitmap
  1214. (32bit bitmap is created).
  1215. -- 0.26.3 Changes/Bug Fixes ---------------------------------
  1216. - Setting AlphaFormat property of TBitmap in ConvertDataToBitmap
  1217. when using Delphi 2009+.
  1218. - Fixed garbled LCL TBitmaps created by ConvertDataToBitmap
  1219. in Mac OS X (Carbon).
  1220. -- 0.26.1 Changes/Bug Fixes ---------------------------------
  1221. - Added some more IFDEFs for Lazarus widget sets.
  1222. - Removed CLX code.
  1223. - GTK version of Unix DisplayImageData only used with LCL GTK so the
  1224. the rest of the unit can be used with Qt or other LCL interfaces.
  1225. - Fallback mechanism for DisplayImageDataOnDC, it may fail on occasions.
  1226. - Changed file format conditional compilation to reflect changes
  1227. in LINK symbols.
  1228. - Lazarus 0.9.26 compatibility changes.
  1229. -- 0.24.1 Changes/Bug Fixes ---------------------------------
  1230. - Fixed wrong IFDEF causing that Imaging wouldn't compile in Lazarus
  1231. with GTK2 target.
  1232. - Added comments with code for Lazarus rev. 11861+ regarding
  1233. RawImage interface. Replace current code with that in comments
  1234. if you use Lazarus from SVN. New RawImage interface will be used by
  1235. default after next Lazarus release.
  1236. -- 0.23 Changes/Bug Fixes -----------------------------------
  1237. - Added TImagingGIF.
  1238. -- 0.21 Changes/Bug Fixes -----------------------------------
  1239. - Uses only high level interface now (except for saving options).
  1240. - Slightly changed class hierarchy. TImagingGraphic is now only for loading
  1241. and base class for savers is new TImagingGraphicForSave. Also
  1242. TImagingGraphic is now registered with all supported file formats
  1243. by TPicture's format support.
  1244. -- 0.19 Changes/Bug Fixes -----------------------------------
  1245. - added DisplayImage procedures (thanks to Paul Michell, modified)
  1246. - removed RegisterTypes and UnRegisterTypes from interface section,
  1247. they are called automatically
  1248. - added procedures: ConvertImageToBitmap and ConvertBitmapToImage
  1249. -- 0.17 Changes/Bug Fixes -----------------------------------
  1250. - LCL data to bitmap conversion didn't work in Linux, fixed
  1251. - added MNG file format
  1252. - added JNG file format
  1253. -- 0.15 Changes/Bug Fixes -----------------------------------
  1254. - made it LCL compatible
  1255. - made it CLX compatible
  1256. - added all initial stuff
  1257. }
  1258. end.