ImagingComponents.pas 74 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428
  1. {
  2. $Id: ImagingComponents.pas 148 2008-12-16 13:03:03Z galfar $
  3. Vampyre Imaging Library
  4. by Marek Mauder
  5. http://imaginglib.sourceforge.net
  6. The contents of this file are used with permission, subject to the Mozilla
  7. Public License Version 1.1 (the "License"); you may not use this file except
  8. in compliance with the License. You may obtain a copy of the License at
  9. http://www.mozilla.org/MPL/MPL-1.1.html
  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 for
  12. the specific language governing rights and limitations under the License.
  13. Alternatively, the contents of this file may be used under the terms of the
  14. GNU Lesser General Public License (the "LGPL License"), in which case the
  15. provisions of the LGPL License are applicable instead of those above.
  16. If you wish to allow use of your version of this file only under the terms
  17. of the LGPL License and not to allow others to use your version of this file
  18. under the MPL, indicate your decision by deleting the provisions above and
  19. replace them with the notice and other provisions required by the LGPL
  20. License. If you do not delete the provisions above, a recipient may use
  21. your version of this file under either the MPL or the LGPL License.
  22. For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
  23. }
  24. { This unit contains VCL/LCL TGraphic descendant which uses Imaging library
  25. for saving and loading.
  26. Note: This modified unit is part of ExtraGIF mod of Imaging library.}
  27. unit ImagingComponents;
  28. {$I ImagingOptions.inc}
  29. interface
  30. {$IFDEF LCL}
  31. {$DEFINE COMPONENT_SET_LCL}
  32. {$ENDIF}
  33. {$IF not Defined(COMPONENT_SET_LCL) and not Defined(COMPONENT_SET_VCL)}
  34. // If no component sets should be used just include empty unit.
  35. implementation
  36. {$ELSE}
  37. uses
  38. SysUtils, Types, Classes,
  39. {$IFDEF MSWINDOWS}
  40. Windows,
  41. {$ENDIF}
  42. {$IFDEF COMPONENT_SET_VCL}
  43. Graphics,
  44. {$ENDIF}
  45. {$IFDEF COMPONENT_SET_LCL}
  46. InterfaceBase,
  47. GraphType,
  48. Graphics,
  49. LCLType,
  50. LCLIntf,
  51. {$ENDIF}
  52. {$IFNDEF DONT_LINK_GIF}
  53. ImagingGif,
  54. {$ENDIF}
  55. ImagingTypes, Imaging, ImagingClasses, ImagingCanvases, ImagingFormats;
  56. type
  57. TRefMultiImage = class(TMultiImage)
  58. private
  59. FRefCount: Integer;
  60. public
  61. constructor Create; override;
  62. procedure ReferredFree(const DeleteFromList: Boolean = True);
  63. function GetCopy: TRefMultiImage;
  64. property RefCount: Integer read FRefCount;
  65. end;
  66. { Graphic class which uses Imaging to load images.
  67. It has standard TBitmap class as ancestor and it can
  68. Assign also to/from TImageData structres and TBaseImage
  69. classes. For saving is uses inherited TBitmap methods.
  70. This class is automatically registered to TPicture for all
  71. file extensions supported by Imaging (useful only for loading).
  72. If you just want to load images in various formats you can use this
  73. class or simply use TPicture.LoadFromXXX which will create this class
  74. automatically. For TGraphic class that saves with Imaging look
  75. at TImagingGraphicForSave class.}
  76. TLoadingState = (lsEmpty, lsLoading, lsLoaded);
  77. {$WARNINGS OFF}
  78. TImagingGraphic = class(TGraphic)
  79. private
  80. FMultImage: TRefMultiImage;
  81. FWaitCounter: Integer;
  82. FBackGroundBitmap: TBitmap;
  83. FBgColor: TColor;
  84. FSelfAnimated, FAddedToList: Boolean;
  85. FActiveImage: LongInt;
  86. FLoadState: TLoadingState;
  87. FLastCanvas: TCanvas;
  88. FLastRect: TRect;
  89. FReAnimate: Boolean;
  90. FBGShare: Boolean;
  91. FIsReferenced: Boolean;
  92. procedure SetSelfAnimated(const Value: Boolean);
  93. procedure SetBackGroundBitmap(const Value: TBitmap);
  94. procedure SetActiveImgIndex(const Value: Integer);
  95. procedure DoPrepareFrame(const FrameIndex: Integer; var Frame: TImageData; Back: PImageData);
  96. protected
  97. //done before LoadFromStream
  98. procedure BeforeLoad(Stream: TStream); virtual;
  99. //internal LoadFromStream according to Reference Count
  100. procedure ReadDataFromStream(Stream: TStream); virtual;
  101. //done after LoadFromStream
  102. procedure AfterLoad(Stream: TStream); virtual;
  103. procedure AssignTo(Dest: TPersistent); override;
  104. //call this method every time before Draw, in case of gif this will copy the palette to frame
  105. procedure PrepareFrame(const FrameIndex: Integer; var Frame: TImageData; Back: PImageData); virtual;
  106. procedure Draw(ACanvas: TCanvas; const ARect: TRect); override;
  107. function GetEmpty: Boolean; override;
  108. function GetHeight: Integer; override;
  109. function GetWidth: Integer; override;
  110. procedure SetHeight(Value: Integer); override;
  111. procedure SetWidth(Value: Integer); override;
  112. //those three methods are used when SelfAnimated switched on
  113. procedure DoPaintTriggered; virtual;
  114. function GetCurrentDelay: LongInt;
  115. procedure PaintTriggered;
  116. //workaround to reduce processor-time while graphic is invisible
  117. function ParentControlVisible: Boolean;
  118. public
  119. constructor Create; overload; override;
  120. constructor Create(const Referenced: Boolean); overload;
  121. destructor Destroy; override;
  122. procedure SaveToStream(Stream: TStream); override;
  123. { Loads new image from the stream. It can load all image
  124. file formats supported by Imaging (and enabled of course)
  125. even though it is called by descendant class capable of
  126. saving only one file format.}
  127. procedure LoadFromStream(Stream: TStream); override;
  128. { Copies the image contained in Source to this graphic object.
  129. Supports also TBaseImage descendants from ImagingClasses unit. }
  130. procedure Assign(Source: TPersistent); override;
  131. { Copies the image contained in TBaseImage to this graphic object.}
  132. procedure AssignFromImage(Image: TBaseImage);
  133. { Copies the current image to TBaseImage object.}
  134. procedure AssignToImage(Image: TBaseImage);
  135. { Copies the image contained in TImageData structure to this graphic object.}
  136. procedure AssignFromImageData(const ImageData: TImageData);
  137. { Copies the current image to TImageData structure.}
  138. procedure AssignToImageData(var ImageData: TImageData);
  139. { Returns TImageFileFormat descendant for this graphic class.}
  140. class function GetFileFormat: TImageFileFormat; virtual;
  141. {more fast way to resize the graphic}
  142. procedure SetSize(AWidth: Integer; AHeight: Integer); {$IF CompilerVersion >= 18}override;{$IFEND}
  143. {call this method before any change to MultiImage (so other copies won't be changed)}
  144. procedure UnRefImage;
  145. property Frames: TRefMultiImage read FMultImage;
  146. property ActiveIndex: Integer read FActiveImage write SetActiveImgIndex;
  147. //background for transparent drawing
  148. property BackGroundBitmap: TBitmap read FBackGroundBitmap write SetBackGroundBitmap;
  149. //set this property to True if you control BackgroundBitmap yourself
  150. property BackgroundSharing: Boolean read FBGShare write FBGShare default False;
  151. //if backgroundbitmap is nil, then this color is used for transparency
  152. property BackGroundColor: TColor read FBgColor write FBgColor;
  153. //this property forces the self-animation
  154. property SelfAnimated: Boolean read FSelfAnimated write SetSelfAnimated default True;
  155. //set this property to False after removing from animation List to avoid re-adding
  156. property ReAnimate: Boolean read FReAnimate write FReAnimate default True;
  157. property LoadState: TLoadingState read FLoadState;
  158. { TODO -oSega-Zero : make a code for ClipboardFormat recognition }
  159. procedure LoadFromClipboardFormat(AFormat: Word; AData: Cardinal;
  160. APalette: HPALETTE);
  161. procedure SaveToClipboardFormat(var AFormat: Word; var AData: Cardinal;
  162. var APalette: HPALETTE);
  163. end;
  164. {$WARNINGS ON}
  165. TImagingGraphicClass = class of TImagingGraphic;
  166. {$IFNDEF DONT_LINK_GIF}
  167. TImagingGifGraphic = class(TImagingGraphic)
  168. private
  169. FRepeatCount: Integer;
  170. FLastFrame: TImageData;
  171. FCacheIndex: Integer;
  172. procedure DoOverlay(const FrameIndex: Integer; var Frame, BG: TImageData);
  173. protected
  174. function GetHeight: Integer; override;
  175. function GetWidth: Integer; override;
  176. procedure AfterLoad(Stream: TStream); override;
  177. procedure PrepareFrame(const FrameIndex: Integer; var Frame: TImageData; Back: PImageData); override;
  178. procedure DoPaintTriggered; override;
  179. public
  180. {returns GIF Extra or nil if not found}
  181. function GifData(const Index: Integer): TGifExtraData;
  182. class function GetFileFormat: TImageFileFormat; override;
  183. destructor Destroy; override;
  184. end;
  185. TImagingGifGraphicClass = class of TImagingGifGraphic;
  186. TGIFImage = TImagingGifGraphic;
  187. {$ENDIF}
  188. { Base class for file format specific TGraphic classes that use
  189. Imaging for saving. Each descendant class can load all file formats
  190. supported by Imaging but save only one format (TImagingBitmap
  191. for *.bmp, TImagingJpeg for *.jpg). Format specific classes also
  192. allow easy access to Imaging options that affect saving of files
  193. (they are properties here).}
  194. TImagingGraphicForSave = class(TImagingGraphic)
  195. protected
  196. FDefaultFileExt: string;
  197. FSavingFormat: TImageFormat;
  198. procedure WriteDataToStream(Stream: TStream); virtual;
  199. public
  200. constructor Create; override;
  201. { Saves the current image to the stream. It is saved in the
  202. file format according to the DefaultFileExt property.
  203. So each descendant class can save some other file format.}
  204. procedure SaveToStream(Stream: TStream); override;
  205. {$IFDEF COMPONENT_SET_LCL}
  206. { Returns file extensions of this graphic class.}
  207. class function GetFileExtensions: string; override;
  208. { Returns default MIME type of this graphic class.}
  209. function GetMimeType: string; override;
  210. {$ENDIF}
  211. { Default (the most common) file extension of this graphic class.}
  212. property DefaultFileExt: string read FDefaultFileExt;
  213. end;
  214. TImagingGraphicForSaveClass = class of TImagingGraphicForSave;
  215. {$IFNDEF DONT_LINK_BITMAP}
  216. { TImagingGraphic descendant for loading/saving Windows bitmaps.
  217. VCL/CLX/LCL all have native support for bitmaps so you might
  218. want to disable this class (although you can save bitmaps with
  219. RLE compression with this class).}
  220. TImagingBitmap = class(TImagingGraphicForSave)
  221. protected
  222. FUseRLE: Boolean;
  223. public
  224. constructor Create; override;
  225. procedure SaveToStream(Stream: TStream); override;
  226. class function GetFileFormat: TImageFileFormat; override;
  227. { See ImagingBitmapRLE option for details.}
  228. property UseRLE: Boolean read FUseRLE write FUseRLE;
  229. end;
  230. {$ENDIF}
  231. {$IFNDEF DONT_LINK_JPEG}
  232. { TImagingGraphic descendant for loading/saving JPEG images.}
  233. TImagingJpeg = class(TImagingGraphicForSave)
  234. protected
  235. FQuality: LongInt;
  236. FProgressive: Boolean;
  237. public
  238. constructor Create; override;
  239. procedure SaveToStream(Stream: TStream); override;
  240. class function GetFileFormat: TImageFileFormat; override;
  241. {$IFDEF COMPONENT_SET_LCL}
  242. function GetMimeType: string; override;
  243. {$ENDIF}
  244. { See ImagingJpegQuality option for details.}
  245. property Quality: LongInt read FQuality write FQuality;
  246. { See ImagingJpegProgressive option for details.}
  247. property Progressive: Boolean read FProgressive write FProgressive;
  248. end;
  249. {$ENDIF}
  250. {$IFNDEF DONT_LINK_PNG}
  251. { TImagingGraphic descendant for loading/saving PNG images.}
  252. TImagingPNG = class(TImagingGraphicForSave)
  253. protected
  254. FPreFilter: LongInt;
  255. FCompressLevel: LongInt;
  256. public
  257. constructor Create; override;
  258. procedure SaveToStream(Stream: TStream); override;
  259. class function GetFileFormat: TImageFileFormat; override;
  260. { See ImagingPNGPreFilter option for details.}
  261. property PreFilter: LongInt read FPreFilter write FPreFilter;
  262. { See ImagingPNGCompressLevel option for details.}
  263. property CompressLevel: LongInt read FCompressLevel write FCompressLevel;
  264. end;
  265. {$ENDIF}
  266. {$IFNDEF DONT_LINK_TARGA}
  267. { TImagingGraphic descendant for loading/saving Targa images.}
  268. TImagingTarga = class(TImagingGraphicForSave)
  269. protected
  270. FUseRLE: Boolean;
  271. public
  272. constructor Create; override;
  273. procedure SaveToStream(Stream: TStream); override;
  274. class function GetFileFormat: TImageFileFormat; override;
  275. { See ImagingTargaRLE option for details.}
  276. property UseRLE: Boolean read FUseRLE write FUseRLE;
  277. end;
  278. {$ENDIF}
  279. {$IFNDEF DONT_LINK_DDS}
  280. { Compresssion type used when saving DDS files by TImagingDds.}
  281. TDDSCompresion = (dcNone, dcDXT1, dcDXT3, dcDXT5);
  282. { TImagingGraphic descendant for loading/saving DDS images.}
  283. TImagingDDS = class(TImagingGraphicForSave)
  284. protected
  285. FCompression: TDDSCompresion;
  286. public
  287. constructor Create; override;
  288. procedure SaveToStream(Stream: TStream); override;
  289. class function GetFileFormat: TImageFileFormat; override;
  290. { You can choose compression type used when saving DDS file.
  291. dcNone means that file will be saved in the current bitmaps pixel format.}
  292. property Compression: TDDSCompresion read FCompression write FCompression;
  293. end;
  294. {$ENDIF}
  295. {$IFNDEF DONT_LINK_MNG}
  296. { TImagingGraphic descendant for loading/saving MNG images.}
  297. TImagingMNG = class(TImagingGraphicForSave)
  298. protected
  299. FLossyCompression: Boolean;
  300. FLossyAlpha: Boolean;
  301. FPreFilter: LongInt;
  302. FCompressLevel: LongInt;
  303. FQuality: LongInt;
  304. FProgressive: Boolean;
  305. public
  306. constructor Create; override;
  307. procedure SaveToStream(Stream: TStream); override;
  308. class function GetFileFormat: TImageFileFormat; override;
  309. {$IFDEF COMPONENT_SET_LCL}
  310. function GetMimeType: string; override;
  311. {$ENDIF}
  312. { See ImagingMNGLossyCompression option for details.}
  313. property LossyCompression: Boolean read FLossyCompression write FLossyCompression;
  314. { See ImagingMNGLossyAlpha option for details.}
  315. property LossyAlpha: Boolean read FLossyAlpha write FLossyAlpha;
  316. { See ImagingMNGPreFilter option for details.}
  317. property PreFilter: LongInt read FPreFilter write FPreFilter;
  318. { See ImagingMNGCompressLevel option for details.}
  319. property CompressLevel: LongInt read FCompressLevel write FCompressLevel;
  320. { See ImagingMNGQuality option for details.}
  321. property Quality: LongInt read FQuality write FQuality;
  322. { See ImagingMNGProgressive option for details.}
  323. property Progressive: Boolean read FProgressive write FProgressive;
  324. end;
  325. {$ENDIF}
  326. {$IFNDEF DONT_LINK_JNG}
  327. { TImagingGraphic descendant for loading/saving JNG images.}
  328. TImagingJNG = class(TImagingGraphicForSave)
  329. protected
  330. FLossyAlpha: Boolean;
  331. FAlphaPreFilter: LongInt;
  332. FAlphaCompressLevel: LongInt;
  333. FQuality: LongInt;
  334. FProgressive: Boolean;
  335. public
  336. constructor Create; override;
  337. procedure SaveToStream(Stream: TStream); override;
  338. class function GetFileFormat: TImageFileFormat; override;
  339. { See ImagingJNGLossyAlpha option for details.}
  340. property LossyAlpha: Boolean read FLossyAlpha write FLossyAlpha;
  341. { See ImagingJNGPreFilter option for details.}
  342. property AlphaPreFilter: LongInt read FAlphaPreFilter write FAlphaPreFilter;
  343. { See ImagingJNGCompressLevel option for details.}
  344. property AlphaCompressLevel: LongInt read FAlphaCompressLevel write FAlphaCompressLevel;
  345. { See ImagingJNGQuality option for details.}
  346. property Quality: LongInt read FQuality write FQuality;
  347. { See ImagingJNGProgressive option for details.}
  348. property Progressive: Boolean read FProgressive write FProgressive;
  349. end;
  350. {$ENDIF}
  351. { Returns bitmap pixel format with the closest match with given data format.}
  352. function DataFormatToPixelFormat(Format: TImageFormat): TPixelFormat;
  353. { Returns data format with closest match with given bitmap pixel format.}
  354. function PixelFormatToDataFormat(Format: TPixelFormat): TImageFormat;
  355. { Converts TImageData structure to VCL/CLX/LCL bitmap.}
  356. procedure ConvertDataToBitmap(const Data: TImageData; Bitmap: TBitmap);
  357. { Converts VCL/CLX/LCL bitmap to TImageData structure.}
  358. procedure ConvertBitmapToData(Bitmap: TBitmap; var Data: TImageData);
  359. { Converts TBaseImage instance to VCL/CLX/LCL bitmap.}
  360. procedure ConvertImageToBitmap(Image: TBaseImage; Bitmap: TBitmap);
  361. { Converts VCL/CLX/LCL bitmap to TBaseImage. Image must exist before
  362. procedure is called. It overwrites its current image data.
  363. When Image is TMultiImage only the current image level is overwritten.}
  364. procedure ConvertBitmapToImage(Bitmap: TBitmap; Image: TBaseImage);
  365. { Displays image stored in TImageData structure onto TCanvas. This procedure
  366. draws image without converting from Imaging format to TBitmap.
  367. Only [ifA8R8G8B8, ifX8R8G8B8] image formats are supported. Use this
  368. when you want displaying images that change frequently (because converting to
  369. TBitmap by ConvertImageDataToBitmap is generally slow). Dest and Src
  370. rectangles represent coordinates in the form (X1, Y1, X2, Y2).}
  371. procedure DisplayImageData(DstCanvas: TCanvas; const DstRect: TRect; const ImageData: TImageData; const SrcRect: TRect);
  372. { Displays image onto TCanvas at position [DstX, DstY]. This procedure
  373. draws image without converting from Imaging format to TBitmap.
  374. Only [ifA8R8G8B8, ifX8R8G8B8] image formats are supported. Use this
  375. when you want displaying images that change frequently (because converting to
  376. TBitmap by ConvertImageDataToBitmap is generally slow).}
  377. procedure DisplayImage(DstCanvas: TCanvas; DstX, DstY: LongInt; Image: TBaseImage); overload;
  378. { Displays image onto TCanvas to rectangle DstRect. This procedure
  379. draws image without converting from Imaging format to TBitmap.
  380. Only [ifA8R8G8B8, ifX8R8G8B8] image formats are supported. Use this
  381. when you want displaying images that change frequently (because converting to
  382. TBitmap by ConvertImageDataToBitmap is generally slow).}
  383. procedure DisplayImage(DstCanvas: TCanvas; const DstRect: TRect; Image: TBaseImage); overload;
  384. { Displays part of the image specified by SrcRect onto TCanvas to rectangle DstRect.
  385. This procedure draws image without converting from Imaging format to TBitmap.
  386. Only [ifA8R8G8B8, ifX8R8G8B8] image formats are supported. Use this
  387. when you want displaying images that change frequently (because converting to
  388. TBitmap by ConvertImageDataToBitmap is generally slow).}
  389. procedure DisplayImage(DstCanvas: TCanvas; const DstRect: TRect; Image: TBaseImage; const SrcRect: TRect); overload;
  390. {$IFDEF MSWINDOWS}
  391. { Displays image stored in TImageData structure onto Windows device context.
  392. Behaviour is the same as of DisplayImageData.}
  393. procedure DisplayImageDataOnDC(DC: HDC; const DstRect: TRect; const ImageData: TImageData; const SrcRect: TRect);
  394. {$ENDIF}
  395. implementation
  396. uses
  397. {$IF Defined(LCL)}
  398. {$IF Defined(LCLGTK2)}
  399. GLib2, GDK2, GTK2, GTKDef, GTKProc,
  400. {$ELSEIF Defined(LCLGTK)}
  401. GDK, GTK, GTKDef, GTKProc,
  402. {$IFEND}
  403. {$IFEND}
  404. {$IFNDEF DONT_LINK_BITMAP}
  405. ImagingBitmap,
  406. {$ENDIF}
  407. {$IFNDEF DONT_LINK_JPEG}
  408. ImagingJpeg,
  409. {$ENDIF}
  410. {$IFNDEF DONT_LINK_TARGA}
  411. ImagingTarga,
  412. {$ENDIF}
  413. {$IFNDEF DONT_LINK_DDS}
  414. ImagingDds,
  415. {$ENDIF}
  416. {$IF not Defined(DONT_LINK_PNG) or not Defined(DONT_LINK_MNG) or not Defined(DONT_LINK_JNG)}
  417. ImagingNetworkGraphics,
  418. {$IFEND}
  419. ImagingUtility, Contnrs, OverbyteICSMD5, Messages;
  420. var
  421. HashedPicList: TStringList;
  422. resourcestring
  423. SBadFormatDataToBitmap = 'Cannot find compatible bitmap format for image %s';
  424. SBadFormatBitmapToData = 'Cannot find compatible data format for bitmap %p';
  425. SBadFormatDisplay = 'Unsupported image format passed';
  426. SUnsupportedLCLWidgetSet = 'This function is not implemented for current LCL widget set';
  427. SImagingGraphicName = 'Imaging Graphic AllInOne';
  428. const
  429. WM_SynchronizeMe = WM_USER + 1; //custom message to make thread synchronizing inside DLLs
  430. //WParam is a method pointer, LParam is not used
  431. type
  432. TDllSynchroClass = class
  433. private
  434. FSynchronizeWindow: HWND;
  435. procedure SynchronizeMe(var Message: TMessage); message WM_SynchronizeMe;
  436. protected
  437. procedure WndProc(var Message: TMessage);
  438. public
  439. constructor Create;
  440. destructor Destroy; override;
  441. procedure DefaultHandler(var Message); override;
  442. property Handle: HWND read FSynchronizeWindow;
  443. end;
  444. type
  445. //internal threaded class that performs self-animation in containers like TImage
  446. TPainterThread = class(TThread)
  447. private
  448. FGraphicList: TObjectList;
  449. FPause: Boolean;
  450. FCurIndex: Integer;
  451. FSyncWnd: TDllSynchroClass;
  452. procedure DoOnTerminate(Sender: TObject);
  453. protected
  454. procedure DoChange;
  455. procedure Execute; override;
  456. procedure Synchronize(AMethod: TThreadMethod); reintroduce;
  457. public
  458. constructor Create(CreateSuspended: Boolean = False);
  459. destructor Destroy; override;
  460. //appends graphic to animation list
  461. procedure AddNotifyObject(const AObject: TImagingGraphic);
  462. //removes graphic to animation list
  463. procedure RemoveNotifyObject(const AObject: TImagingGraphic);
  464. end;
  465. var
  466. PainterThread: TPainterThread;
  467. { Registers types to VCL/CLX/LCL.}
  468. procedure RegisterTypes;
  469. var
  470. I: LongInt;
  471. procedure RegisterFileFormatAllInOne(Format: TImageFileFormat);
  472. var
  473. I: LongInt;
  474. begin
  475. for I := 0 to Format.Extensions.Count - 1 do
  476. TPicture.RegisterFileFormat(Format.Extensions[I], SImagingGraphicName,
  477. TImagingGraphic);
  478. end;
  479. procedure RegisterFileFormat(AClass: TImagingGraphicClass);
  480. var
  481. I: LongInt;
  482. begin
  483. for I := 0 to AClass.GetFileFormat.Extensions.Count - 1 do
  484. TPicture.RegisterFileFormat(AClass.GetFileFormat.Extensions[I],
  485. AClass.GetFileFormat.Name, AClass);
  486. end;
  487. begin
  488. for I := Imaging.GetFileFormatCount - 1 downto 0 do
  489. RegisterFileFormatAllInOne(Imaging.GetFileFormatAtIndex(I));
  490. Classes.RegisterClass(TImagingGraphic);
  491. {$IFNDEF DONT_LINK_TARGA}
  492. RegisterFileFormat(TImagingTarga);
  493. Classes.RegisterClass(TImagingTarga);
  494. {$ENDIF}
  495. {$IFNDEF DONT_LINK_DDS}
  496. RegisterFileFormat(TImagingDDS);
  497. Classes.RegisterClass(TImagingDDS);
  498. {$ENDIF}
  499. {$IFNDEF DONT_LINK_JNG}
  500. RegisterFileFormat(TImagingJNG);
  501. Classes.RegisterClass(TImagingJNG);
  502. {$ENDIF}
  503. {$IFNDEF DONT_LINK_MNG}
  504. RegisterFileFormat(TImagingMNG);
  505. Classes.RegisterClass(TImagingMNG);
  506. {$ENDIF}
  507. {$IFNDEF DONT_LINK_GIF}
  508. RegisterFileFormat(TImagingGifGraphic);
  509. Classes.RegisterClass(TImagingGifGraphic);
  510. {$ENDIF}
  511. {$IFNDEF DONT_LINK_PNG}
  512. {$IFDEF COMPONENT_SET_LCL}
  513. // Unregister Lazarus´ default PNG loader which crashes on some PNG files
  514. TPicture.UnregisterGraphicClass(TPortableNetworkGraphic);
  515. {$ENDIF}
  516. RegisterFileFormat(TImagingPNG);
  517. Classes.RegisterClass(TImagingPNG);
  518. {$ENDIF}
  519. {$IFNDEF DONT_LINK_JPEG}
  520. RegisterFileFormat(TImagingJpeg);
  521. Classes.RegisterClass(TImagingJpeg);
  522. {$ENDIF}
  523. {$IFNDEF DONT_LINK_BITMAP}
  524. RegisterFileFormat(TImagingBitmap);
  525. Classes.RegisterClass(TImagingBitmap);
  526. {$ENDIF}
  527. end;
  528. { Unregisters types from VCL/LCL.}
  529. procedure UnRegisterTypes;
  530. begin
  531. {$IFNDEF DONT_LINK_BITMAP}
  532. TPicture.UnregisterGraphicClass(TImagingBitmap);
  533. Classes.UnRegisterClass(TImagingBitmap);
  534. {$ENDIF}
  535. {$IFNDEF DONT_LINK_JPEG}
  536. TPicture.UnregisterGraphicClass(TImagingJpeg);
  537. Classes.UnRegisterClass(TImagingJpeg);
  538. {$ENDIF}
  539. {$IFNDEF DONT_LINK_PNG}
  540. TPicture.UnregisterGraphicClass(TImagingPNG);
  541. Classes.UnRegisterClass(TImagingPNG);
  542. {$ENDIF}
  543. {$IFNDEF DONT_LINK_GIF}
  544. TPicture.UnregisterGraphicClass(TImagingGifGraphic);
  545. Classes.UnRegisterClass(TImagingGifGraphic);
  546. {$ENDIF}
  547. {$IFNDEF DONT_LINK_TARGA}
  548. TPicture.UnregisterGraphicClass(TImagingTarga);
  549. Classes.UnRegisterClass(TImagingTarga);
  550. {$ENDIF}
  551. {$IFNDEF DONT_LINK_DDS}
  552. TPicture.UnregisterGraphicClass(TImagingDDS);
  553. Classes.UnRegisterClass(TImagingDDS);
  554. {$ENDIF}
  555. TPicture.UnregisterGraphicClass(TImagingGraphic);
  556. Classes.UnRegisterClass(TImagingGraphic);
  557. end;
  558. function DataFormatToPixelFormat(Format: TImageFormat): TPixelFormat;
  559. begin
  560. case Format of
  561. {$IFDEF COMPONENT_SET_VCL}
  562. ifIndex8: Result := pf8bit;
  563. ifR5G6B5: Result := pf16bit;
  564. ifR8G8B8: Result := pf24bit;
  565. {$ENDIF}
  566. ifA8R8G8B8,
  567. ifX8R8G8B8: Result := pf32bit;
  568. else
  569. Result := pfCustom;
  570. end;
  571. end;
  572. function PixelFormatToDataFormat(Format: TPixelFormat): TImageFormat;
  573. begin
  574. case Format of
  575. pf8bit: Result := ifIndex8;
  576. pf15bit: Result := ifA1R5G5B5;
  577. pf16bit: Result := ifR5G6B5;
  578. pf24bit: Result := ifR8G8B8;
  579. pf32bit: Result := ifA8R8G8B8;
  580. else
  581. Result := ifUnknown;
  582. end;
  583. end;
  584. procedure ConvertDataToBitmap(const Data: TImageData; Bitmap: TBitmap);
  585. var
  586. I, LineBytes: LongInt;
  587. PF: TPixelFormat;
  588. Info: TImageFormatInfo;
  589. WorkData: TImageData;
  590. {$IFDEF COMPONENT_SET_VCL}
  591. LogPalette: TMaxLogPalette;
  592. {$ENDIF}
  593. {$IFDEF COMPONENT_SET_LCL}
  594. RawImage: TRawImage;
  595. ImgHandle, ImgMaskHandle: HBitmap;
  596. {$ENDIF}
  597. begin
  598. PF := DataFormatToPixelFormat(Data.Format);
  599. GetImageFormatInfo(Data.Format, Info);
  600. if PF = pfCustom then
  601. begin
  602. // Convert from formats not supported by Graphics unit
  603. Imaging.InitImage(WorkData);
  604. Imaging.CloneImage(Data, WorkData);
  605. if Info.IsFloatingPoint or Info.HasAlphaChannel or Info.IsSpecial then
  606. Imaging.ConvertImage(WorkData, ifA8R8G8B8)
  607. else
  608. {$IFDEF COMPONENT_SET_VCL}
  609. if Info.IsIndexed or Info.HasGrayChannel then
  610. Imaging.ConvertImage(WorkData, ifIndex8)
  611. else if Info.UsePixelFormat then
  612. Imaging.ConvertImage(WorkData, ifR5G6B5)
  613. else
  614. Imaging.ConvertImage(WorkData, ifR8G8B8);
  615. {$ELSE}
  616. Imaging.ConvertImage(WorkData, ifA8R8G8B8);
  617. {$ENDIF}
  618. PF := DataFormatToPixelFormat(WorkData.Format);
  619. GetImageFormatInfo(WorkData.Format, Info);
  620. end
  621. else
  622. WorkData := Data;
  623. if PF = pfCustom then
  624. RaiseImaging(SBadFormatDataToBitmap, [ImageToStr(WorkData)]);
  625. LineBytes := WorkData.Width * Info.BytesPerPixel;
  626. {$IFDEF COMPONENT_SET_VCL}
  627. Bitmap.Width := WorkData.Width;
  628. Bitmap.Height := WorkData.Height;
  629. Bitmap.PixelFormat := PF;
  630. if (PF = pf8bit) and (WorkData.Palette <> nil) then
  631. begin
  632. // Copy palette, this must be done before copying bits
  633. FillChar(LogPalette, SizeOf(LogPalette), 0);
  634. LogPalette.palVersion := $300;
  635. LogPalette.palNumEntries := Info.PaletteEntries;
  636. for I := 0 to Info.PaletteEntries - 1 do
  637. with LogPalette do
  638. begin
  639. palPalEntry[I].peRed := WorkData.Palette[I].R;
  640. palPalEntry[I].peGreen := WorkData.Palette[I].G;
  641. palPalEntry[I].peBlue := WorkData.Palette[I].B;
  642. end;
  643. Bitmap.Palette := CreatePalette(PLogPalette(@LogPalette)^);
  644. end;
  645. // Copy scanlines
  646. for I := 0 to WorkData.Height - 1 do
  647. Move(PByteArray(WorkData.Bits)[I * LineBytes], Bitmap.Scanline[I]^, LineBytes);
  648. {$ENDIF}
  649. {$IFDEF COMPONENT_SET_LCL}
  650. // Create 32bit raw image from image data
  651. FillChar(RawImage, SizeOf(RawImage), 0);
  652. with RawImage.Description do
  653. begin
  654. Width := WorkData.Width;
  655. Height := WorkData.Height;
  656. BitsPerPixel := Info.BytesPerPixel * 8;
  657. Format := ricfRGBA;
  658. LineEnd := rileByteBoundary;
  659. BitOrder := riboBitsInOrder;
  660. ByteOrder := riboLSBFirst;
  661. LineOrder := riloTopToBottom;
  662. AlphaPrec := 8;
  663. RedPrec := 8;
  664. GreenPrec := 8;
  665. BluePrec := 8;
  666. AlphaShift := 24;
  667. RedShift := 16;
  668. GreenShift := 8;
  669. BlueShift := 0;
  670. Depth := 24;
  671. end;
  672. RawImage.Data := WorkData.Bits;
  673. RawImage.DataSize := WorkData.Size;
  674. // Create bitmap from raw image
  675. { If you get complitation error here upgrade to Lazarus 0.9.24+ }
  676. if RawImage_CreateBitmaps(RawImage, ImgHandle, ImgMaskHandle, False) then
  677. begin
  678. Bitmap.Handle := ImgHandle;
  679. Bitmap.MaskHandle := ImgMaskHandle;
  680. end;
  681. {$ENDIF}
  682. if WorkData.Bits <> Data.Bits then
  683. Imaging.FreeImage(WorkData);
  684. end;
  685. procedure ConvertBitmapToData(Bitmap: TBitmap; var Data: TImageData);
  686. var
  687. I, LineBytes: LongInt;
  688. Format: TImageFormat;
  689. Info: TImageFormatInfo;
  690. {$IFDEF COMPONENT_SET_VCL}
  691. Colors: Word;
  692. LogPalette: TMaxLogPalette;
  693. {$ENDIF}
  694. {$IFDEF COMPONENT_SET_LCL}
  695. RawImage: TRawImage;
  696. LineLazBytes: LongInt;
  697. {$ENDIF}
  698. begin
  699. {$IFDEF COMPONENT_SET_LCL}
  700. // In the current Lazarus 0.9.10 Bitmap.PixelFormat property is useless.
  701. // We cannot change bitmap's format by changing it (it will just release
  702. // old image but not convert it to new format) nor we can determine bitmaps's
  703. // current format (it is usually set to pfDevice). So bitmap's format is obtained
  704. // trough RawImage api and cannot be changed to mirror some Imaging format
  705. // (so formats with no coresponding Imaging format cannot be saved now).
  706. if RawImage_DescriptionFromBitmap(Bitmap.Handle, RawImage.Description) then
  707. case RawImage.Description.BitsPerPixel of
  708. 8: Format := ifIndex8;
  709. 16:
  710. if RawImage.Description.Depth = 15 then
  711. Format := ifA1R5G5B5
  712. else
  713. Format := ifR5G6B5;
  714. 24: Format := ifR8G8B8;
  715. 32: Format := ifA8R8G8B8;
  716. 48: Format := ifR16G16B16;
  717. 64: Format := ifA16R16G16B16;
  718. else
  719. Format := ifUnknown;
  720. end;
  721. {$ELSE}
  722. Format := PixelFormatToDataFormat(Bitmap.PixelFormat);
  723. if Format = ifUnknown then
  724. begin
  725. // Convert from formats not supported by Imaging (1/4 bit)
  726. if Bitmap.PixelFormat < pf8bit then
  727. Bitmap.PixelFormat := pf8bit
  728. else
  729. Bitmap.PixelFormat := pf32bit;
  730. Format := PixelFormatToDataFormat(Bitmap.PixelFormat);
  731. end;
  732. {$ENDIF}
  733. if Format = ifUnknown then
  734. RaiseImaging(SBadFormatBitmapToData, []);
  735. Imaging.NewImage(Bitmap.Width, Bitmap.Height, Format, Data);
  736. GetImageFormatInfo(Data.Format, Info);
  737. LineBytes := Data.Width * Info.BytesPerPixel;
  738. {$IFDEF COMPONENT_SET_VCL}
  739. if (Format = ifIndex8) and (GetObject(Bitmap.Palette, SizeOf(Colors),
  740. @Colors) <> 0) then
  741. begin
  742. // Copy palette
  743. GetPaletteEntries(Bitmap.Palette, 0, Colors, LogPalette.palPalEntry);
  744. if Colors > Info.PaletteEntries then
  745. Colors := Info.PaletteEntries;
  746. for I := 0 to Colors - 1 do
  747. with LogPalette do
  748. begin
  749. Data.Palette[I].A := $FF;
  750. Data.Palette[I].R := palPalEntry[I].peRed;
  751. Data.Palette[I].G := palPalEntry[I].peGreen;
  752. Data.Palette[I].B := palPalEntry[I].peBlue;
  753. end;
  754. end;
  755. // Copy scanlines
  756. for I := 0 to Data.Height - 1 do
  757. Move(Bitmap.ScanLine[I]^, PByteArray(Data.Bits)[I * LineBytes], LineBytes);
  758. {$ENDIF}
  759. {$IFDEF COMPONENT_SET_LCL}
  760. // Get raw image from bitmap (mask handle must be 0 or expect violations)
  761. if RawImage_FromBitmap(RawImage, Bitmap.Handle, 0, nil) then
  762. begin
  763. LineLazBytes := GetBytesPerLine(Data.Width, RawImage.Description.BitsPerPixel,
  764. RawImage.Description.LineEnd);
  765. // Copy scanlines
  766. for I := 0 to Data.Height - 1 do
  767. Move(PByteArray(RawImage.Data)[I * LineLazBytes],
  768. PByteArray(Data.Bits)[I * LineBytes], LineBytes);
  769. { If you get complitation error here upgrade to Lazarus 0.9.24+ }
  770. RawImage.FreeData;
  771. end;
  772. {$ENDIF}
  773. end;
  774. procedure ConvertImageToBitmap(Image: TBaseImage; Bitmap: TBitmap);
  775. begin
  776. ConvertDataToBitmap(Image.ImageDataPointer^, Bitmap);
  777. end;
  778. procedure ConvertBitmapToImage(Bitmap: TBitmap; Image: TBaseImage);
  779. begin
  780. ConvertBitmapToData(Bitmap, Image.ImageDataPointer^);
  781. end;
  782. {$IFDEF MSWINDOWS}
  783. procedure DisplayImageDataOnDC(DC: HDC; const DstRect: TRect; const ImageData: TImageData; const SrcRect: TRect);
  784. var
  785. OldMode: Integer;
  786. BitmapInfo: Windows.TBitmapInfo;
  787. Bmp: TBitmap;
  788. begin
  789. if TestImage(ImageData) then
  790. begin
  791. Assert(ImageData.Format in [ifA8R8G8B8, ifX8R8G8B8], SBadFormatDisplay);
  792. OldMode := Windows.SetStretchBltMode(DC, COLORONCOLOR);
  793. FillChar(BitmapInfo, SizeOf(BitmapInfo), 0);
  794. with BitmapInfo.bmiHeader do
  795. begin
  796. biSize := SizeOf(TBitmapInfoHeader);
  797. biPlanes := 1;
  798. biBitCount := 32;
  799. biCompression := BI_RGB;
  800. biWidth := ImageData.Width;
  801. biHeight := -ImageData.Height;
  802. biSizeImage := ImageData.Size;
  803. biXPelsPerMeter := 0;
  804. biYPelsPerMeter := 0;
  805. biClrUsed := 0;
  806. biClrImportant := 0;
  807. end;
  808. try
  809. with SrcRect, ImageData do
  810. if Windows.StretchDIBits(DC, DstRect.Left, DstRect.Top,
  811. DstRect.Right - DstRect.Left, DstRect.Bottom - DstRect.Top, Left,
  812. Top, Right - Left, Bottom - Top, Bits, BitmapInfo, DIB_RGB_COLORS, SRCCOPY) <> Height then
  813. begin
  814. // StretchDIBits may fail on some ocassions (error 487, http://support.microsoft.com/kb/269585).
  815. // This fallback is slow but works every time. Thanks to Sergey Galezdinov for the fix.
  816. Bmp := TBitmap.Create;
  817. try
  818. ConvertDataToBitmap(ImageData, Bmp);
  819. StretchBlt(DC, DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left, DstRect.Bottom - DstRect.Top,
  820. Bmp.Canvas.Handle, 0, 0, Width, Height, SRCCOPY);
  821. finally
  822. Bmp.Free;
  823. end;
  824. end;
  825. finally
  826. Windows.SetStretchBltMode(DC, OldMode);
  827. end;
  828. end;
  829. end;
  830. {$ENDIF}
  831. procedure DisplayImageData(DstCanvas: TCanvas; const DstRect: TRect; const ImageData: TImageData; const SrcRect: TRect);
  832. {$IF Defined(DCC) or Defined(LCLWIN32)} // Delphi or LCL Win32
  833. begin
  834. DisplayImageDataOnDC(DstCanvas.Handle, DstRect, ImageData, SrcRect);
  835. end;
  836. {$ELSEIF Defined(LCLGTK) or Defined(LCLGTK2)}
  837. procedure GDKDrawBitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY,
  838. SrcWidth, SrcHeight: Integer; ImageData: TImageData);
  839. var
  840. P: TPoint;
  841. begin
  842. P := TGtkDeviceContext(Dest).Offset;
  843. Inc(DstX, P.X);
  844. Inc(DstY, P.Y);
  845. gdk_draw_rgb_32_image(TGtkDeviceContext(Dest).Drawable, TGtkDeviceContext(Dest).GC,
  846. DstX, DstY, SrcWidth, SrcHeight, GDK_RGB_DITHER_NONE,
  847. @PLongWordArray(ImageData.Bits)[SrcY * ImageData.Width + SrcX], ImageData.Width * 4);
  848. end;
  849. var
  850. DisplayImage: TImageData;
  851. NewWidth, NewHeight: Integer;
  852. SrcBounds, DstBounds, DstClip: TRect;
  853. begin
  854. if TestImage(ImageData) then
  855. begin
  856. Assert(ImageData.Format in [ifA8R8G8B8, ifX8R8G8B8], SBadFormatDisplay);
  857. InitImage(DisplayImage);
  858. SrcBounds := RectToBounds(SrcRect);
  859. DstBounds := RectToBounds(DstRect);
  860. WidgetSet.GetClipBox(DstCanvas.Handle, @DstClip);
  861. ClipStretchBounds(SrcBounds.Left, SrcBounds.Top, SrcBounds.Right, SrcBounds.Bottom,
  862. DstBounds.Left, DstBounds.Top, DstBounds.Right, DstBounds.Bottom, ImageData.Width,
  863. ImageData.Height, DstClip);
  864. NewWidth := DstBounds.Right;
  865. NewHeight := DstBounds.Bottom;
  866. if (NewWidth > 0) and (NewHeight > 0) then
  867. begin
  868. if (SrcBounds.Right = NewWidth) and (SrcBounds.Bottom = NewHeight) then
  869. try
  870. CloneImage(ImageData, DisplayImage);
  871. // Swap R-B channels for GTK display compatability!
  872. SwapChannels(DisplayImage, ChannelRed, ChannelBlue);
  873. GDKDrawBitmap(DstCanvas.Handle, DstBounds.Left, DstBounds.Top,
  874. SrcBounds.Left, SrcBounds.Top, NewWidth, NewHeight, DisplayImage);
  875. finally
  876. FreeImage(DisplayImage);
  877. end
  878. else
  879. try
  880. // Create new image with desired dimensions
  881. NewImage(NewWidth, NewHeight, ImageData.Format, DisplayImage);
  882. // Stretch pixels from old image to new one TResizeFilter = (rfNearest, rfBilinear, rfBicubic);
  883. StretchRect(ImageData, SrcBounds.Left, SrcBounds.Top, SrcBounds.Right,
  884. SrcBounds.Bottom, DisplayImage, 0, 0, NewWidth, NewHeight, rfNearest);
  885. // Swap R-B channels for GTK display compatability!
  886. SwapChannels(DisplayImage, ChannelRed, ChannelBlue);
  887. GDKDrawBitmap(DstCanvas.Handle, DstBounds.Left, DstBounds.Top, 0, 0,
  888. NewWidth, NewHeight, DisplayImage);
  889. finally
  890. FreeImage(DisplayImage);
  891. end
  892. end;
  893. end;
  894. end;
  895. {$ELSE}
  896. begin
  897. raise Exception.Create(SUnsupportedLCLWidgetSet);
  898. end;
  899. {$IFEND}
  900. procedure DisplayImage(DstCanvas: TCanvas; DstX, DstY: LongInt; Image: TBaseImage);
  901. begin
  902. DisplayImageData(DstCanvas, BoundsToRect(DstX, DstY, Image.Width, Image.Height),
  903. Image.ImageDataPointer^, Image.BoundsRect);
  904. end;
  905. procedure DisplayImage(DstCanvas: TCanvas; const DstRect: TRect; Image: TBaseImage);
  906. begin
  907. DisplayImageData(DstCanvas, DstRect, Image.ImageDataPointer^, Image.BoundsRect);
  908. end;
  909. procedure DisplayImage(DstCanvas: TCanvas; const DstRect: TRect; Image: TBaseImage; const SrcRect: TRect);
  910. begin
  911. DisplayImageData(DstCanvas, DstRect, Image.ImageDataPointer^, SrcRect);
  912. end;
  913. { TImagingGraphic class implementation }
  914. constructor TImagingGraphic.Create;
  915. begin
  916. inherited Create;
  917. FBgColor := clNone;
  918. FSelfAnimated := True;
  919. FReAnimate := True;
  920. FAddedToList := False;
  921. FLoadState := lsEmpty;
  922. FMultImage := nil;
  923. FLastCanvas := nil;
  924. FBGShare := False;
  925. FActiveImage := 0;
  926. FIsReferenced := True;
  927. end;
  928. {$WARNINGS OFF}
  929. constructor TImagingGraphic.Create(const Referenced: Boolean);
  930. begin
  931. Create;
  932. FIsReferenced := Referenced;
  933. end;
  934. {$WARNINGS ON}
  935. destructor TImagingGraphic.Destroy;
  936. begin
  937. FLastCanvas := nil;
  938. SelfAnimated := False;
  939. if FMultImage <> nil then
  940. FMultImage.ReferredFree(FIsReferenced);
  941. FMultImage := nil;
  942. if not FBGShare then
  943. FreeAndNil(FBackGroundBitmap);
  944. inherited;
  945. end;
  946. procedure TImagingGraphic.DoPaintTriggered;
  947. begin
  948. if (Self = nil) or Empty or (FMultImage = nil) then Exit;
  949. if FActiveImage < FMultImage.ImageCount - 1 then
  950. FActiveImage := FActiveImage + 1
  951. else
  952. FActiveImage := 0;
  953. try
  954. if GetCurrentObject(FLastCanvas.Handle, OBJ_BITMAP) <> 0 then
  955. Draw(FLastCanvas, FLastRect)
  956. else
  957. begin
  958. FLastCanvas := nil;
  959. FreeAndNil(FBackGroundBitmap);
  960. Changed(Self);
  961. end;
  962. except
  963. //if AV happens while accessing FLastCanvas
  964. FLastCanvas := nil;
  965. Changed(Self);
  966. end;
  967. end;
  968. procedure TImagingGraphic.Draw(ACanvas: TCanvas; const ARect: TRect);
  969. var
  970. b: TBitmap;
  971. TransCol: TColor32Rec;
  972. BackData, StretchBackData, Data: TImageData;
  973. sRect: TRect;
  974. ShouldAdd: Boolean;
  975. function RectToSize(const szRect: TRect): TSize;
  976. begin
  977. Result.cx := Abs(szRect.Right - szRect.Left);
  978. Result.cy := Abs(szRect.Bottom - szRect.Top);
  979. end;
  980. begin
  981. if (FMultImage = nil) or not (lsLoaded = FLoadState) then Exit;
  982. //need to add to animation thread only if animation contains more then 1 frame, should be animated/re-animated and HDC's window is not 0
  983. ShouldAdd := (FMultImage.ImageCount > 1) and (FSelfAnimated or (not FAddedToList and FReAnimate)) and
  984. (WindowFromDC(ACanvas.Handle) <> 0);
  985. try
  986. { TODO -oSega-Zero : do correct drawing when something has overlapped the part of canvas }
  987. { if FSelfAnimated and FAddedToList and (FLastCanvas <> nil) then
  988. with ACanvas.ClipRect do
  989. if not EqualRect(ACanvas.ClipRect, ARect) then
  990. try
  991. FLastCanvas := nil;
  992. if not BackgroundSharing then
  993. FreeAndNil(FBackGroundBitmap);
  994. Exit;
  995. finally
  996. Changed(Self);
  997. end; // }
  998. InitImage(BackData);
  999. NewImage(Width, Height, ifA8R8G8B8, BackData);
  1000. with RectToSize(ARect) do
  1001. if (cx <> Width) or (cy <> Height) then
  1002. begin
  1003. SetAlpha(BackData, 0);
  1004. InitImage(StretchBackData);
  1005. NewImage(cx, cy, ifA8R8G8B8, StretchBackData);
  1006. end;
  1007. FMultImage.ActiveImage := FActiveImage;
  1008. with RectToSize(ARect) do
  1009. if BackGroundBitmap <> nil then
  1010. begin
  1011. if (cx <> Width) or (cy <> Height) then
  1012. begin
  1013. ConvertBitmapToData(BackGroundBitmap, StretchBackData);
  1014. //Set alpha channel to 255 - we don't need any transparency here
  1015. SetAlpha(StretchBackData, 255);
  1016. end
  1017. else
  1018. begin
  1019. ConvertBitmapToData(BackGroundBitmap, BackData);
  1020. //Set alpha channel to 255 - we don't need any transparency here
  1021. SetAlpha(BackData, 255);
  1022. end;
  1023. end
  1024. else
  1025. if FBgColor <> clNone then
  1026. begin
  1027. if (cx <> Width) or (cy <> Height) then
  1028. ConvertImage(StretchBackData, ifA8R8G8B8)
  1029. else
  1030. ConvertImage(BackData, ifA8R8G8B8);
  1031. with TransCol do
  1032. begin
  1033. A := 255;
  1034. R := GetRValue(ColorToRGB(FBgColor));
  1035. G := GetGValue(ColorToRGB(FBgColor));
  1036. B := GetBValue(ColorToRGB(FBgColor));
  1037. end;
  1038. if (cx <> Width) or (cy <> Height) then
  1039. FillRect(StretchBackData, 0, 0, cx, cy, @TransCol)
  1040. else
  1041. FillRect(BackData, 0, 0, Width, Height, @TransCol);
  1042. end
  1043. else
  1044. begin
  1045. b := TBitmap.Create;
  1046. b.Width := cx;
  1047. b.Height := cy;
  1048. b.PixelFormat := pf32bit;
  1049. b.Canvas.CopyRect(Rect(0, 0, b.Width, b.Height), ACanvas, ARect);
  1050. if (cx <> Width) or (cy <> Height) then
  1051. begin
  1052. ConvertBitmapToData(b, StretchBackData);
  1053. SetAlpha(StretchBackData, 255);
  1054. end
  1055. else
  1056. begin
  1057. ConvertBitmapToData(b, BackData);
  1058. SetAlpha(BackData, 255);
  1059. end;
  1060. with RectToSize(ARect) do
  1061. if not EqualRect(ACanvas.ClipRect, ARect) and ((cx <> Width) and (cy <> Height)) then
  1062. b.Free
  1063. else
  1064. begin
  1065. FBackGroundBitmap := b;
  1066. BackgroundSharing := False;
  1067. end;
  1068. end;
  1069. PrepareFrame(FMultImage.ActiveImage, Data, @BackData);
  1070. with RectToSize(ARect) do
  1071. if (cx <> Width) or (cy <> Height) then
  1072. DoPrepareFrame(FMultImage.ActiveImage, Data, @StretchBackData);
  1073. if Data.Format <> ifA8R8G8B8 then
  1074. ConvertImage(Data, ifA8R8G8B8);
  1075. sRect := Rect(0, 0, Data.Width, Data.Height);
  1076. DisplayImageData(ACanvas, ARect, Data, sRect);
  1077. if TestImage(StretchBackData) then
  1078. FreeImage(StretchBackData);
  1079. FreeImage(BackData);
  1080. FreeImage(Data);
  1081. if ShouldAdd and (FLastCanvas <> ACanvas) then
  1082. FLastCanvas := ACanvas;
  1083. FLastRect := ARect;
  1084. except
  1085. on E: Exception do
  1086. begin
  1087. //SendDebug('error painting info: ' + E.Message);
  1088. raise;
  1089. end;
  1090. end;
  1091. if ShouldAdd then SelfAnimated := True;
  1092. end;
  1093. function TImagingGraphic.GetCurrentDelay: LongInt;
  1094. begin
  1095. Result := -1;
  1096. if (Self <> nil) and not Empty then
  1097. with FMultImage do
  1098. begin
  1099. if not Valid then Exit;
  1100. Result := 10;
  1101. if Images[ActiveImage].Extra <> nil then
  1102. if Images[ActiveImage].Extra.Delay > 0 then
  1103. begin
  1104. Result := Images[ActiveImage].Extra.Delay;
  1105. if (Result < 3) then
  1106. Result := 3;
  1107. if (Result > 1000) then
  1108. Result := 1000;
  1109. end;
  1110. Result := Result * 10;
  1111. end;
  1112. end;
  1113. function TImagingGraphic.GetEmpty: Boolean;
  1114. begin
  1115. Result := (FMultImage = nil) or ((FMultImage.ImageCount = 0) or not FMultImage.AllImagesValid);
  1116. end;
  1117. class function TImagingGraphic.GetFileFormat: TImageFileFormat;
  1118. begin
  1119. Result := nil;
  1120. end;
  1121. function TImagingGraphic.GetHeight: Integer;
  1122. begin
  1123. if not Empty then
  1124. Result := FMultImage.Height
  1125. else
  1126. Result := 0;
  1127. end;
  1128. function TImagingGraphic.GetWidth: Integer;
  1129. begin
  1130. if not Empty then
  1131. Result := FMultImage.Width
  1132. else
  1133. Result := 0;
  1134. end;
  1135. procedure TImagingGraphic.SaveToStream(Stream: TStream);
  1136. begin
  1137. if (FMultImage <> nil) and (GetFileFormat <> nil) then
  1138. GetFileFormat.SaveToStream(Stream, FMultImage.DataArray);
  1139. end;
  1140. procedure TImagingGraphic.SetActiveImgIndex(const Value: Integer);
  1141. begin
  1142. FActiveImage := Value;
  1143. // if FMultImage.ActiveImage <> Value then
  1144. // FMultImage.ActiveImage := Value;
  1145. end;
  1146. procedure TImagingGraphic.SetBackGroundBitmap(const Value: TBitmap);
  1147. begin
  1148. if (BackGroundBitmap <> nil) and not FBGShare then
  1149. FreeAndNil(FBackGroundBitmap);
  1150. FBackGroundBitmap := Value;
  1151. end;
  1152. procedure TImagingGraphic.SetHeight(Value: Integer);
  1153. begin
  1154. if (Value > 0) and (Width > 0) then
  1155. begin
  1156. UnRefImage;
  1157. FMultImage.ResizeImages(Width, Value, rfBicubic);
  1158. Changed(Self);
  1159. end;
  1160. end;
  1161. procedure TImagingGraphic.SetSelfAnimated(const Value: Boolean);
  1162. begin
  1163. FSelfAnimated := Value;
  1164. if FSelfAnimated then
  1165. begin
  1166. if not FAddedToList then
  1167. PainterThread.AddNotifyObject(Self);
  1168. FAddedToList := True;
  1169. end
  1170. else
  1171. if FAddedToList then
  1172. begin
  1173. PainterThread.RemoveNotifyObject(Self);
  1174. FAddedToList := False;
  1175. end;
  1176. end;
  1177. procedure TImagingGraphic.SetSize(AWidth, AHeight: Integer);
  1178. begin
  1179. if (AWidth > 0) and (AHeight > 0) then
  1180. begin
  1181. UnRefImage;
  1182. FMultImage.ResizeImages(AWidth, AHeight, rfBicubic);
  1183. Changed(Self);
  1184. end;
  1185. end;
  1186. procedure TImagingGraphic.SetWidth(Value: Integer);
  1187. begin
  1188. if (Height > 0) and (Value > 0) then
  1189. begin
  1190. UnRefImage;
  1191. FMultImage.ResizeImages(Value, Height, rfBicubic);
  1192. Changed(Self);
  1193. end;
  1194. end;
  1195. procedure TImagingGraphic.UnRefImage;
  1196. var
  1197. TempStream: TMemoryStream;
  1198. begin
  1199. if (FMultImage = nil) or not FIsReferenced then Exit;
  1200. TempStream := TMemoryStream.Create;
  1201. try
  1202. SaveToStream(TempStream);
  1203. TempStream.Position := 0;
  1204. FMultImage.ReferredFree;
  1205. FMultImage := nil;
  1206. FIsReferenced := False;
  1207. LoadFromStream(TempStream);
  1208. finally
  1209. TempStream.Free;
  1210. end;
  1211. end;
  1212. procedure TImagingGraphic.LoadFromStream(Stream: TStream);
  1213. begin
  1214. if Stream <> nil then
  1215. begin
  1216. ReadDataFromStream(Stream);
  1217. Changed(Self);
  1218. end;
  1219. end;
  1220. procedure TImagingGraphic.PaintTriggered;
  1221. begin
  1222. if not ParentControlVisible then
  1223. begin
  1224. SelfAnimated := False;
  1225. if not FBGShare then
  1226. FreeAndNil(FBackGroundBitmap);
  1227. FLastRect := Rect(0, 0, 0, 0);
  1228. end
  1229. else
  1230. begin
  1231. DoPaintTriggered;
  1232. FWaitCounter := GetCurrentDelay;
  1233. end;
  1234. end;
  1235. procedure TImagingGraphic.PrepareFrame(const FrameIndex: Integer; var Frame: TImageData;
  1236. Back: PImageData);
  1237. begin
  1238. CloneImage(FMultImage.DataArray[FrameIndex], Frame);
  1239. DoPrepareFrame(FrameIndex, Frame, Back);
  1240. end;
  1241. procedure TImagingGraphic.DoPrepareFrame(const FrameIndex: Integer; var Frame: TImageData; Back: PImageData);
  1242. var
  1243. BackCanvas: TImagingCanvas;
  1244. FImageCanvas: TImagingCanvas;
  1245. sRect, ARect: TRect;
  1246. begin
  1247. if Frame.Format <> ifA8R8G8B8 then
  1248. ConvertImage(Frame, ifA8R8G8B8);
  1249. if Back <> nil then
  1250. begin
  1251. BackCanvas := TImagingCanvas.CreateForData(Back);
  1252. FImageCanvas:= TImagingCanvas.CreateForData(@Frame);
  1253. sRect := Rect(0, 0, Back^.Width, Back^.Height);
  1254. ARect := Rect(0, 0, Width, Height);
  1255. FImageCanvas.StretchDrawAlpha(ARect, BackCanvas, sRect, rfBicubic);
  1256. CloneImage(Back^, Frame);
  1257. FreeAndNil(FImageCanvas);
  1258. FreeAndNil(BackCanvas);
  1259. end;
  1260. end;
  1261. procedure TImagingGraphic.ReadDataFromStream(Stream: TStream);
  1262. var
  1263. StrHash: string;
  1264. HashPos: Integer;
  1265. buf: array of Byte;
  1266. BackupMulti: TRefMultiImage;
  1267. begin
  1268. //in case of data already loaded before but not freed
  1269. BackupMulti := FMultImage;
  1270. try
  1271. BeforeLoad(Stream);
  1272. if not FIsReferenced then
  1273. begin
  1274. FMultImage := TRefMultiImage.Create;
  1275. if not FMultImage.LoadMultiFromStream(Stream) then
  1276. begin
  1277. //couldnt load picture
  1278. FreeAndNil(FMultImage);
  1279. Exit;
  1280. end;
  1281. end
  1282. else
  1283. begin
  1284. StrHash := '';
  1285. Stream.Position := 0;
  1286. SetLength(buf, Stream.Size);
  1287. Stream.Read(buf[0], Stream.Size);
  1288. StrHash := Getmd5(Pointer(buf), Stream.Size);
  1289. SetLength(buf, 0);
  1290. //find hash in Internal RefCount hashed List
  1291. HashPos := HashedPicList.IndexOf(StrHash);
  1292. if HashPos < 0 then
  1293. begin
  1294. FMultImage := TRefMultiImage.Create;
  1295. Stream.Position := 0;
  1296. FLoadState := lsLoading;
  1297. if not FMultImage.LoadMultiFromStream(Stream) then
  1298. begin
  1299. //couldnt load picture
  1300. FMultImage.ReferredFree(False);
  1301. FMultImage := BackupMulti;
  1302. Exit;
  1303. end;
  1304. HashedPicList.AddObject(StrHash, FMultImage.GetCopy);
  1305. end
  1306. else
  1307. begin
  1308. //inc RefCount
  1309. if HashedPicList.Objects[HashPos] <> nil then
  1310. FMultImage := TRefMultiImage(HashedPicList.Objects[HashPos]).GetCopy;//}
  1311. end;
  1312. end;
  1313. if BackupMulti <> nil then
  1314. begin
  1315. BackupMulti.ReferredFree(FIsReferenced);
  1316. BackupMulti := nil;
  1317. end;
  1318. AfterLoad(Stream);
  1319. FLoadState := lsLoaded;
  1320. Transparent := True;
  1321. except
  1322. if FMultImage <> nil then
  1323. begin
  1324. FMultImage.ReferredFree(FIsReferenced);
  1325. FMultImage := nil;
  1326. end;
  1327. FMultImage := BackupMulti;
  1328. end;
  1329. end;
  1330. procedure TImagingGraphic.AssignTo(Dest: TPersistent);
  1331. var
  1332. FramesToAssign: TDynImageDataArray;
  1333. I: Integer;
  1334. begin
  1335. if FMultImage = nil then Exit;
  1336. begin
  1337. SetLength(FramesToAssign , FMultImage.ImageCount);
  1338. for I := 0 to FMultImage.ImageCount - 1 do
  1339. begin
  1340. InitImage(FramesToAssign[I]);
  1341. PrepareFrame(I, FramesToAssign[I], nil);
  1342. end;
  1343. if Dest is TSingleImage then
  1344. TSingleImage(Dest).CreateFromData(FramesToAssign[0])
  1345. else
  1346. if Dest is TMultiImage then
  1347. TMultiImage(Dest).CreateFromArray(FramesToAssign)
  1348. else
  1349. if Dest is TBitmap then
  1350. ConvertDataToBitmap(FramesToAssign[0], TBitmap(Dest))
  1351. else
  1352. inherited AssignTo(Dest);
  1353. FreeImagesInArray(FramesToAssign);
  1354. SetLength(FramesToAssign, 0);
  1355. end;
  1356. end;
  1357. procedure TImagingGraphic.AfterLoad(Stream: TStream);
  1358. begin
  1359. //nothing here
  1360. end;
  1361. procedure TImagingGraphic.Assign(Source: TPersistent);
  1362. var
  1363. ID: TImageData;
  1364. begin
  1365. if Source is TImagingGraphic then
  1366. begin
  1367. if (Source <> nil) and (TImagingGraphic(Source).FMultImage <> nil) then
  1368. begin
  1369. FMultImage := TImagingGraphic(Source).Frames.GetCopy;
  1370. FLoadState := lsLoaded;
  1371. end
  1372. else
  1373. begin
  1374. if FMultImage <> nil then FMultImage.ReferredFree(FIsReferenced);
  1375. FMultImage := TRefMultiImage.Create;
  1376. end;
  1377. end
  1378. else
  1379. if Source is TBaseImage then
  1380. AssignFromImage(TBaseImage(Source))
  1381. else
  1382. if Source is TBitmap then
  1383. begin
  1384. ID := FMultImage[0];
  1385. ConvertBitmapToData(TBitmap(Source), ID);
  1386. end
  1387. else
  1388. inherited Assign(Source);
  1389. end;
  1390. procedure TImagingGraphic.AssignFromImage(Image: TBaseImage);
  1391. begin
  1392. if (Image <> nil) and Image.Valid then
  1393. AssignFromImageData(Image.ImageDataPointer^);
  1394. end;
  1395. procedure TImagingGraphic.AssignToImage(Image: TBaseImage);
  1396. begin
  1397. if (Image <> nil) then
  1398. begin
  1399. if (Image is TSingleImage) and (Image.ImageDataPointer <> nil) then
  1400. AssignToImageData(Image.ImageDataPointer^);
  1401. end;
  1402. end;
  1403. procedure TImagingGraphic.AssignFromImageData(const ImageData: TImageData);
  1404. begin
  1405. if FMultImage = nil then
  1406. FMultImage := TRefMultiImage.Create
  1407. else
  1408. begin
  1409. UnRefImage;
  1410. FMultImage.SetImageCount(0);
  1411. end;
  1412. FMultImage.AddImage(ImageData);
  1413. end;
  1414. procedure TImagingGraphic.AssignToImageData(var ImageData: TImageData);
  1415. begin
  1416. if TestImage(ImageData) then
  1417. FreeImage(ImageData);
  1418. if FMultImage <> nil then
  1419. PrepareFrame(0, ImageData, nil);
  1420. end;
  1421. procedure TImagingGraphic.BeforeLoad(Stream: TStream);
  1422. begin
  1423. //nothing here
  1424. end;
  1425. { TImagingGraphicForSave class implementation }
  1426. constructor TImagingGraphicForSave.Create;
  1427. begin
  1428. inherited Create;
  1429. FDefaultFileExt := GetFileFormat.Extensions[0];
  1430. FSavingFormat := ifUnknown;
  1431. GetFileFormat.CheckOptionsValidity;
  1432. end;
  1433. procedure TImagingGraphicForSave.WriteDataToStream(Stream: TStream);
  1434. var
  1435. Image: TSingleImage;
  1436. begin
  1437. if FDefaultFileExt <> '' then
  1438. begin
  1439. Image := TSingleImage.Create;
  1440. try
  1441. Image.Assign(Self);
  1442. if FSavingFormat <> ifUnknown then
  1443. Image.Format := FSavingFormat;
  1444. Image.SaveToStream(FDefaultFileExt, Stream);
  1445. finally
  1446. Image.Free;
  1447. end;
  1448. end;
  1449. end;
  1450. procedure TImagingGraphicForSave.SaveToStream(Stream: TStream);
  1451. begin
  1452. WriteDataToStream(Stream);
  1453. end;
  1454. {$IFDEF COMPONENT_SET_LCL}
  1455. class function TImagingGraphicForSave.GetFileExtensions: string;
  1456. begin
  1457. Result := StringReplace(GetFileFormat.Extensions.CommaText, ',', ';', [rfReplaceAll]);
  1458. end;
  1459. function TImagingGraphicForSave.GetMimeType: string;
  1460. begin
  1461. Result := 'image/' + FDefaultFileExt;
  1462. end;
  1463. {$ENDIF}
  1464. {$IFNDEF DONT_LINK_BITMAP}
  1465. { TImagingBitmap class implementation }
  1466. constructor TImagingBitmap.Create;
  1467. begin
  1468. inherited Create;
  1469. FUseRLE := (GetFileFormat as TBitmapFileFormat).UseRLE;
  1470. end;
  1471. class function TImagingBitmap.GetFileFormat: TImageFileFormat;
  1472. begin
  1473. Result := FindImageFileFormatByClass(TBitmapFileFormat);
  1474. end;
  1475. procedure TImagingBitmap.SaveToStream(Stream: TStream);
  1476. begin
  1477. Imaging.PushOptions;
  1478. Imaging.SetOption(ImagingBitmapRLE, Ord(FUseRLE));
  1479. inherited SaveToStream(Stream);
  1480. Imaging.PopOptions;
  1481. end;
  1482. {$ENDIF}
  1483. {$IFNDEF DONT_LINK_JPEG}
  1484. { TImagingJpeg class implementation }
  1485. constructor TImagingJpeg.Create;
  1486. begin
  1487. inherited Create;
  1488. FQuality := (GetFileFormat as TJpegFileFormat).Quality;
  1489. FProgressive := (GetFileFormat as TJpegFileFormat).Progressive;
  1490. end;
  1491. class function TImagingJpeg.GetFileFormat: TImageFileFormat;
  1492. begin
  1493. Result := FindImageFileFormatByClass(TJpegFileFormat);
  1494. end;
  1495. {$IFDEF COMPONENT_SET_LCL}
  1496. function TImagingJpeg.GetMimeType: string;
  1497. begin
  1498. Result := 'image/jpeg';
  1499. end;
  1500. {$ENDIF}
  1501. procedure TImagingJpeg.SaveToStream(Stream: TStream);
  1502. begin
  1503. Imaging.PushOptions;
  1504. Imaging.SetOption(ImagingJpegQuality, FQuality);
  1505. Imaging.SetOption(ImagingJpegProgressive, Ord(FProgressive));
  1506. inherited SaveToStream(Stream);
  1507. Imaging.PopOptions;
  1508. end;
  1509. {$ENDIF}
  1510. {$IFNDEF DONT_LINK_PNG}
  1511. { TImagingPNG class implementation }
  1512. constructor TImagingPNG.Create;
  1513. begin
  1514. inherited Create;
  1515. FPreFilter := (GetFileFormat as TPNGFileFormat).PreFilter;
  1516. FCompressLevel := (GetFileFormat as TPNGFileFormat).CompressLevel;
  1517. end;
  1518. class function TImagingPNG.GetFileFormat: TImageFileFormat;
  1519. begin
  1520. Result := FindImageFileFormatByClass(TPNGFileFormat);
  1521. end;
  1522. procedure TImagingPNG.SaveToStream(Stream: TStream);
  1523. begin
  1524. Imaging.PushOptions;
  1525. Imaging.SetOption(ImagingPNGPreFilter, FPreFilter);
  1526. Imaging.SetOption(ImagingPNGCompressLevel, FCompressLevel);
  1527. inherited SaveToStream(Stream);
  1528. Imaging.PopOptions;
  1529. end;
  1530. {$ENDIF}
  1531. {$IFNDEF DONT_LINK_TARGA}
  1532. { TImagingTarga class implementation }
  1533. constructor TImagingTarga.Create;
  1534. begin
  1535. inherited Create;
  1536. FUseRLE := (GetFileFormat as TTargaFileFormat).UseRLE;
  1537. end;
  1538. class function TImagingTarga.GetFileFormat: TImageFileFormat;
  1539. begin
  1540. Result := FindImageFileFormatByClass(TTargaFileFormat);
  1541. end;
  1542. procedure TImagingTarga.SaveToStream(Stream: TStream);
  1543. begin
  1544. Imaging.PushOptions;
  1545. Imaging.SetOption(ImagingTargaRLE, Ord(FUseRLE));
  1546. inherited SaveToStream(Stream);
  1547. Imaging.PopOptions;
  1548. end;
  1549. {$ENDIF}
  1550. {$IFNDEF DONT_LINK_DDS}
  1551. { TImagingDDS class implementation }
  1552. constructor TImagingDDS.Create;
  1553. begin
  1554. inherited Create;
  1555. FCompression := dcNone;
  1556. end;
  1557. class function TImagingDDS.GetFileFormat: TImageFileFormat;
  1558. begin
  1559. Result := FindImageFileFormatByClass(TDDSFileFormat);
  1560. end;
  1561. procedure TImagingDDS.SaveToStream(Stream: TStream);
  1562. begin
  1563. case FCompression of
  1564. dcNone: FSavingFormat := ifUnknown;
  1565. dcDXT1: FSavingFormat := ifDXT1;
  1566. dcDXT3: FSavingFormat := ifDXT3;
  1567. dcDXT5: FSavingFormat := ifDXT5;
  1568. end;
  1569. Imaging.PushOptions;
  1570. Imaging.SetOption(ImagingDDSSaveCubeMap, Ord(False));
  1571. Imaging.SetOption(ImagingDDSSaveVolume, Ord(False));
  1572. Imaging.SetOption(ImagingDDSSaveMipMapCount, 1);
  1573. Imaging.SetOption(ImagingDDSSaveDepth, 1);
  1574. inherited SaveToStream(Stream);
  1575. Imaging.PopOptions;
  1576. end;
  1577. {$ENDIF}
  1578. {$IFNDEF DONT_LINK_MNG}
  1579. { TImagingMNG class implementation }
  1580. constructor TImagingMNG.Create;
  1581. begin
  1582. inherited Create;
  1583. FLossyCompression := (GetFileFormat as TMNGFileFormat).LossyCompression;
  1584. FLossyAlpha := (GetFileFormat as TMNGFileFormat).LossyAlpha;
  1585. FPreFilter := (GetFileFormat as TMNGFileFormat).PreFilter;
  1586. FCompressLevel := (GetFileFormat as TMNGFileFormat).CompressLevel;
  1587. FQuality := (GetFileFormat as TMNGFileFormat).Quality;
  1588. FProgressive := (GetFileFormat as TMNGFileFormat).Progressive;
  1589. end;
  1590. class function TImagingMNG.GetFileFormat: TImageFileFormat;
  1591. begin
  1592. Result := FindImageFileFormatByClass(TMNGFileFormat);
  1593. end;
  1594. {$IFDEF COMPONENT_SET_LCL}
  1595. function TImagingMNG.GetMimeType: string;
  1596. begin
  1597. Result := 'video/mng';
  1598. end;
  1599. {$ENDIF}
  1600. procedure TImagingMNG.SaveToStream(Stream: TStream);
  1601. begin
  1602. Imaging.PushOptions;
  1603. Imaging.SetOption(ImagingMNGLossyCompression, Ord(FLossyCompression));
  1604. Imaging.SetOption(ImagingMNGLossyAlpha, Ord(FLossyAlpha));
  1605. Imaging.SetOption(ImagingMNGPreFilter, FPreFilter);
  1606. Imaging.SetOption(ImagingMNGCompressLevel, FCompressLevel);
  1607. Imaging.SetOption(ImagingMNGQuality, FQuality);
  1608. Imaging.SetOption(ImagingMNGProgressive, Ord(FProgressive));
  1609. inherited SaveToStream(Stream);
  1610. Imaging.PopOptions;
  1611. end;
  1612. {$ENDIF}
  1613. {$IFNDEF DONT_LINK_JNG}
  1614. { TImagingJNG class implementation }
  1615. constructor TImagingJNG.Create;
  1616. begin
  1617. inherited Create;
  1618. FLossyAlpha := (GetFileFormat as TJNGFileFormat).LossyAlpha;
  1619. FAlphaPreFilter := (GetFileFormat as TJNGFileFormat).PreFilter;
  1620. FAlphaCompressLevel := (GetFileFormat as TJNGFileFormat).CompressLevel;
  1621. FQuality := (GetFileFormat as TJNGFileFormat).Quality;
  1622. FProgressive := (GetFileFormat as TJNGFileFormat).Progressive;
  1623. end;
  1624. class function TImagingJNG.GetFileFormat: TImageFileFormat;
  1625. begin
  1626. Result := FindImageFileFormatByClass(TJNGFileFormat);
  1627. end;
  1628. procedure TImagingJNG.SaveToStream(Stream: TStream);
  1629. begin
  1630. Imaging.PushOptions;
  1631. Imaging.SetOption(ImagingJNGLossyALpha, Ord(FLossyAlpha));
  1632. Imaging.SetOption(ImagingJNGAlphaPreFilter, FAlphaPreFilter);
  1633. Imaging.SetOption(ImagingJNGAlphaCompressLevel, FAlphaCompressLevel);
  1634. Imaging.SetOption(ImagingJNGQuality, FQuality);
  1635. Imaging.SetOption(ImagingJNGProgressive, Ord(FProgressive));
  1636. inherited SaveToStream(Stream);
  1637. Imaging.PopOptions;
  1638. end;
  1639. {$ENDIF}
  1640. procedure TImagingGraphic.LoadFromClipboardFormat(AFormat: Word;
  1641. AData: Cardinal; APalette: HPALETTE);
  1642. begin
  1643. //not implemented yet
  1644. end;
  1645. procedure TImagingGraphic.SaveToClipboardFormat(var AFormat: Word;
  1646. var AData: Cardinal; var APalette: HPALETTE);
  1647. begin
  1648. //not implemented yet
  1649. end;
  1650. function TImagingGraphic.ParentControlVisible: Boolean;
  1651. begin
  1652. Result := FLastCanvas <> nil;
  1653. if Result then
  1654. try
  1655. FLastCanvas.Refresh;
  1656. Result := (FLastCanvas.Handle <> 0) and IsWindowVisible(WindowFromDC(FLastCanvas.Handle));
  1657. except
  1658. FLastCanvas := nil;
  1659. FLastRect := Rect(0, 0, 0, 0);
  1660. Result := False;
  1661. end;
  1662. end;
  1663. { TPainterThread }
  1664. var
  1665. AEvent: THandle;
  1666. procedure TPainterThread.AddNotifyObject(const AObject: TImagingGraphic);
  1667. begin
  1668. if FGraphicList.IndexOf(AObject) < 0 then
  1669. try
  1670. if not AObject.SelfAnimated then Exit;
  1671. //if this is the first object in list then start animaition cycle
  1672. if FGraphicList.Count = 0 then Resume;
  1673. FPause := True;
  1674. //if animation cycle waiting for signal then send the signal manually
  1675. if AEvent <> 0 then
  1676. SetEvent(AEvent);
  1677. Suspend;
  1678. FGraphicList.Add(AObject);
  1679. finally
  1680. FPause := False;
  1681. Resume;
  1682. end;
  1683. end;
  1684. constructor TPainterThread.Create(CreateSuspended: Boolean);
  1685. begin
  1686. FGraphicList := TObjectList.Create(False);
  1687. FPause := False;
  1688. inherited Create(CreateSuspended);
  1689. OnTerminate := Self.DoOnTerminate;
  1690. if HInstance <> MainInstance then
  1691. FSyncWnd := TDllSynchroClass.Create;
  1692. end;
  1693. destructor TPainterThread.Destroy;
  1694. begin
  1695. //terminate the animation cycle
  1696. FPause := True;
  1697. //if animation cycle waiting for signal then send the signal manually
  1698. if AEvent <> 0 then
  1699. SetEvent(AEvent);
  1700. if FGraphicList.Count > 0 then
  1701. FGraphicList.Clear;
  1702. FGraphicList.Free;
  1703. if HInstance <> MainInstance then
  1704. FSyncWnd.Free;
  1705. inherited;
  1706. end;
  1707. procedure TPainterThread.DoChange;
  1708. begin
  1709. //animated drawing should be done in the main thread
  1710. if (FGraphicList.Count > 0) and not FPause then
  1711. try
  1712. TImagingGraphic(FGraphicList[FCurIndex]).PaintTriggered;
  1713. except
  1714. end;
  1715. end;
  1716. procedure TPainterThread.Execute;
  1717. var
  1718. I, MinInterval: Integer;
  1719. begin
  1720. while not Terminated do
  1721. if not FPause and (FGraphicList.Count > 0) then
  1722. try
  1723. I := 0;
  1724. //calc the minimum interval for waiting
  1725. MinInterval := TImagingGraphic(FGraphicList[0]).FWaitCounter;
  1726. while I < FGraphicList.Count do
  1727. begin
  1728. if (TImagingGraphic(FGraphicList[I]).FWaitCounter > 0) and
  1729. (TImagingGraphic(FGraphicList[I]).FWaitCounter < MinInterval) then
  1730. MinInterval := TImagingGraphic(FGraphicList[I]).FWaitCounter;
  1731. Inc(I);
  1732. end;
  1733. //create the signal object
  1734. if (FGraphicList.Count > 0) and not FPause then
  1735. AEvent := CreateEvent(nil, True, False, '');
  1736. //wait for signal exactly MinInterval. That trick allow us not to use any kind of timer
  1737. if (FGraphicList.Count > 0) and not FPause then
  1738. WaitForSingleObject(AEvent, MinInterval);
  1739. if AEvent <> 0 then
  1740. CloseHandle(AEvent);
  1741. AEvent := 0;
  1742. if Terminated or FPause then Continue;
  1743. //decrement internal wait counters
  1744. I := 0;
  1745. while I < FGraphicList.Count do
  1746. begin
  1747. if (TImagingGraphic(FGraphicList[I]).FWaitCounter > 0) then
  1748. Dec(TImagingGraphic(FGraphicList[I]).FWaitCounter, MinInterval);
  1749. Inc(I);
  1750. end;
  1751. //if there are items with WiatCounter = 0 then do the animation paint
  1752. I := 0;
  1753. while not Suspended and not FPause and (I < FGraphicList.Count) do
  1754. begin
  1755. if TImagingGraphic(FGraphicList[I]).FWaitCounter < 0 then
  1756. begin
  1757. Inc(I);
  1758. Continue;
  1759. end;
  1760. if (FGraphicList.Count > 0) and (TImagingGraphic(FGraphicList[I]).FWaitCounter = 0) and
  1761. (I < FGraphicList.Count) then
  1762. try
  1763. FCurIndex := I;
  1764. Synchronize(DoChange);
  1765. except
  1766. end;
  1767. Inc(I);
  1768. end;
  1769. except
  1770. end;
  1771. end;
  1772. procedure TPainterThread.DoOnTerminate(Sender: TObject);
  1773. begin
  1774. FPause := True;
  1775. end;
  1776. procedure TPainterThread.RemoveNotifyObject(const AObject: TImagingGraphic);
  1777. begin
  1778. FPause := True;
  1779. //if animation cycle waiting for signal then send the signal manually
  1780. if AEvent <> 0 then
  1781. SetEvent(AEvent);
  1782. Suspend;
  1783. if FGraphicList.Count = 0 then Exit;
  1784. if FGraphicList.IndexOf(AObject) >= 0 then
  1785. FGraphicList.Remove(AObject);
  1786. if FGraphicList.Count <> 0 then
  1787. begin
  1788. FPause := False;
  1789. Resume;
  1790. end;
  1791. end;
  1792. procedure TPainterThread.Synchronize(AMethod: TThreadMethod);
  1793. var
  1794. SyncMsg: TMessage;
  1795. begin
  1796. //the code below is based on the fact that hInstance and MainInstance in dll are differs.
  1797. //There are some problems when calling the standard Synchronize method inside dlls.
  1798. //Here we use a window in the main thread and SendMessage functiona as a waitfor replacement
  1799. if HInstance <> MainInstance then
  1800. begin
  1801. SyncMsg.Msg := WM_SynchronizeMe;
  1802. SyncMsg.WParam := LongInt(@TMethod(AMethod));
  1803. with SyncMsg do
  1804. SendMessage(FSyncWnd.Handle, Msg, WParam, LParam);
  1805. end
  1806. else
  1807. inherited Synchronize(AMethod);
  1808. end;
  1809. { TRefMultiImage }
  1810. constructor TRefMultiImage.Create;
  1811. begin
  1812. inherited;
  1813. FRefCount := 0;
  1814. end;
  1815. function TRefMultiImage.GetCopy: TRefMultiImage;
  1816. begin
  1817. Result := nil;
  1818. if Self <> nil then
  1819. begin
  1820. Inc(FRefCount);
  1821. Result := Self;
  1822. end;
  1823. end;
  1824. procedure TRefMultiImage.ReferredFree(const DeleteFromList: Boolean);
  1825. var
  1826. I: Integer;
  1827. begin
  1828. if Self = nil then Exit;
  1829. if FRefCount > 0 then
  1830. Dec(FRefCount);
  1831. if (FRefCount = 0) and DeleteFromList then
  1832. with HashedPicList do
  1833. begin
  1834. I := IndexOfObject(Self);
  1835. if I >= 0 then
  1836. Delete(I);
  1837. end;
  1838. if FRefCount = 0 then
  1839. Free;
  1840. end;
  1841. {$IFNDEF DONT_LINK_GIF}
  1842. { TImagingGifGraphics }
  1843. destructor TImagingGifGraphic.Destroy;
  1844. begin
  1845. if TestImage(FLastFrame) then
  1846. FreeImage(FLastFrame);
  1847. inherited;
  1848. end;
  1849. procedure TImagingGifGraphic.AfterLoad(Stream: TStream);
  1850. var
  1851. GlobPal: Pointer;
  1852. I: Integer;
  1853. begin
  1854. if (FMultImage <> nil) then
  1855. begin
  1856. if (FMultImage.RefCount <= 1) then
  1857. begin
  1858. //to reduce memory usage, Free all palettes, that are referenced to global palette
  1859. GlobPal := nil;
  1860. for I := 0 to FMultImage.ImageCount - 1 do
  1861. begin
  1862. if not GifData(I).IsLocalPalette then
  1863. begin
  1864. if GlobPal = nil then
  1865. GlobPal := FMultImage.DataArray[I].Palette
  1866. else
  1867. FreeMemNil(FMultImage.DataArray[I].Palette);
  1868. GifData(I).Palette := GlobPal;
  1869. end
  1870. else
  1871. with GifData(I) do
  1872. if Transparent then
  1873. FMultImage.DataArray[I].Palette[TransparentIndex].A := 0;
  1874. end;
  1875. end;
  1876. //in case of self animated this will control frames from looping
  1877. FRepeatCount := 0;
  1878. if GifData(0) <> nil then
  1879. FRepeatCount := GifData(0).LoopCount;
  1880. end;
  1881. end;
  1882. procedure TImagingGifGraphic.DoOverlay(const FrameIndex: Integer; var Frame, BG: TImageData);
  1883. var
  1884. Last: Integer;
  1885. First: Integer;
  1886. iGIFData: TGifExtraData;
  1887. J: Integer;
  1888. FrameBufferImg, FrameCopy: TImageData;
  1889. UseCache: Boolean;
  1890. procedure CopyFrameTransparent32(const Image, Frame: TImageData; Left, Top: Integer);
  1891. var
  1892. X, Y: Integer;
  1893. Src, Dst: PColor32;
  1894. begin
  1895. Src := Frame.Bits;
  1896. // Copy all pixels from frame to log screen but ignore the transparent ones
  1897. for Y := 0 to Frame.Height - 1 do
  1898. begin
  1899. Dst := @PColor32RecArray(Image.Bits)[(Top + Y) * Image.Width + Left];
  1900. for X := 0 to Frame.Width - 1 do
  1901. begin
  1902. if (TColor32Rec(Src^).A <> 0) then
  1903. Dst^ := Src^;
  1904. Inc(Src);
  1905. Inc(Dst);
  1906. end;
  1907. end;
  1908. end;
  1909. begin
  1910. with FMultImage do
  1911. begin
  1912. //frames overlaying algorithm. Overworked from JEDI source (JvGIFCtrl.pas)
  1913. Last := FrameIndex;
  1914. First := Max(0, Last);
  1915. iGIFData := GifData(FrameIndex);
  1916. UseCache := (TestImage(FLastFrame)) and (FCacheIndex = FrameIndex - 1) and (FCacheIndex >= 0) and
  1917. (GifData(FCacheIndex).DisposalMethod <> dmRestorePrevious);
  1918. InitImage(FrameCopy);
  1919. if UseCache then
  1920. begin
  1921. CloneImage(FLastFrame, FrameCopy)
  1922. end
  1923. else
  1924. begin
  1925. FreeImage(FLastFrame);
  1926. NewImage(BG.Width, BG.Height, ifA8R8G8B8, FrameCopy);
  1927. end;
  1928. if not UseCache then
  1929. begin
  1930. while First > 0 do
  1931. begin
  1932. if (iGIFData.GlobalWidth = GifData(First).RealFrameWidth) and
  1933. (iGIFData.GlobalHeight = GifData(First).RealFrameHeight) then
  1934. begin
  1935. if ((GifData(First).DisposalMethod = dmRestoreBackground) and
  1936. (First < Last)) then
  1937. Break;
  1938. end;
  1939. // if TestImage(FLastFrame) and (First = FCacheIndex) then Break;
  1940. Dec(First);
  1941. end;
  1942. for J := First to Last - 1 do
  1943. begin
  1944. case GifData(J).DisposalMethod of
  1945. dmNoRemoval, dmLeave:
  1946. begin
  1947. //we copy just a meaning bytes, not all the frame
  1948. InitImage(FrameBufferImg);
  1949. PrepareFrame(J, FrameBufferImg, nil);
  1950. CopyFrameTransparent32(FrameCopy, FrameBufferImg, GifData(J).FrameLeft, GifData(J).FrameTop);
  1951. FreeImage(FrameBufferImg);
  1952. end;
  1953. dmRestoreBackground:
  1954. begin
  1955. if (J > First) then
  1956. begin
  1957. //filling the rect with background is equal to "clearing" it
  1958. CopyRect(BG, GifData(J).FrameLeft, GifData(J).FrameTop,
  1959. GifData(J).RealFrameWidth, GifData(J).RealFrameHeight,
  1960. FrameCopy, GifData(J).FrameLeft, GifData(J).FrameTop);
  1961. end;
  1962. end;
  1963. dmRestorePrevious:
  1964. begin { do nothing }
  1965. end;
  1966. end;//case
  1967. end;//for *)
  1968. end//not UseCache
  1969. else
  1970. with GifData(FCacheIndex) do
  1971. if DisposalMethod = dmRestoreBackground then
  1972. CopyRect(BG, FrameLeft, FrameTop, RealFrameWidth, RealFrameHeight,
  1973. FrameCopy, FrameLeft, FrameTop);
  1974. with iGifData do
  1975. CopyFrameTransparent32(FrameCopy, Frame, FrameLeft, FrameTop);
  1976. CloneImage(FrameCopy, FLastFrame);
  1977. FCacheIndex := FrameIndex;
  1978. CopyFrameTransparent32(BG, FrameCopy, 0, 0);
  1979. CloneImage(BG, Frame);
  1980. FreeImage(FrameCopy);
  1981. end;
  1982. end;
  1983. class function TImagingGifGraphic.GetFileFormat: TImageFileFormat;
  1984. begin
  1985. Result := FindImageFileFormatByClass(TGIFFileFormat);
  1986. end;
  1987. function TImagingGifGraphic.GetHeight: Integer;
  1988. begin
  1989. Result := 0;
  1990. if Empty then Exit;
  1991. if GifData(0) <> nil then
  1992. Result := GifData(0).GlobalHeight;
  1993. end;
  1994. function TImagingGifGraphic.GetWidth: Integer;
  1995. begin
  1996. Result := 0;
  1997. if Empty then Exit;
  1998. if GifData(0) <> nil then
  1999. Result := GifData(0).GlobalWidth;
  2000. end;
  2001. function TImagingGifGraphic.GifData(const Index: Integer): TGifExtraData;
  2002. begin
  2003. Result := nil;
  2004. if GetEmpty or (Index < 0) or (Index > FMultImage.ImageCount - 1) then Exit;
  2005. Result := TGifExtraData(FMultImage.DataArray[Index].Extra);
  2006. end;
  2007. procedure TImagingGifGraphic.DoPaintTriggered;
  2008. begin
  2009. if Empty then Exit;
  2010. if (GifData(0) <> nil) and (GifData(0).LoopCount <> 0) then
  2011. begin
  2012. if FRepeatCount <= 0 then Exit;
  2013. //if gif animation is not coninued looping, then image should be stopped after RepeatCount is 0
  2014. if (FActiveImage = FMultImage.ImageCount - 1) and (FRepeatCount > 0) then
  2015. Dec(FRepeatCount);
  2016. //when reached to the end of repeat, set activeframe to the last - 1, so the PaintTriggered
  2017. //could set it to last frame
  2018. if FRepeatCount <= 0 then
  2019. FActiveImage := Max(FMultImage.ImageCount - 2, 0)
  2020. end;
  2021. inherited DoPaintTriggered;
  2022. end;
  2023. procedure TImagingGifGraphic.PrepareFrame(const FrameIndex: Integer; var Frame: TImageData; Back: PImageData);
  2024. begin
  2025. //if frame referenced to global palette, then we should copy it to the Frame.Palette
  2026. if (GifData(FrameIndex) <> nil) and not GifData(FrameIndex).IsLocalPalette then
  2027. begin
  2028. InitImage(Frame);
  2029. with GifData(FrameIndex) do
  2030. NewImage(RealFrameWidth, RealFrameHeight, ifIndex8, Frame);
  2031. Move(GifData(FrameIndex).Palette^, Frame.Palette^, SizeOf(TPalette32Size256));
  2032. Move(FMultImage.DataArray[FrameIndex].Bits^, Frame.Bits^, FMultImage.Images[FrameIndex].Size);
  2033. Frame.Format := ifIndex8;
  2034. Frame.Size := FMultImage.Images[FrameIndex].Size;
  2035. Frame.Width := FMultImage.Images[FrameIndex].Width;
  2036. Frame.Height := FMultImage.Images[FrameIndex].Height;
  2037. with GifData(FrameIndex) do
  2038. if Transparent then
  2039. Frame.Palette[TransparentIndex].A := 0;
  2040. // if (Back <> nil) or ((Back = nil) and not GifData(FrameIndex).AllGlobal) then
  2041. ConvertImage(Frame, ifA8R8G8B8);
  2042. end
  2043. else
  2044. begin
  2045. //else if local then just convert to ifA8R8G8B8
  2046. if (GifData(FrameIndex) <> nil) then
  2047. inherited PrepareFrame(FrameIndex, Frame, nil)
  2048. else
  2049. inherited;
  2050. end;
  2051. //last step: overlay previous frames to current, according to DisposalMethod
  2052. if (Back <> nil) and (GifData(FrameIndex) <> nil) then
  2053. DoOverlay(FrameIndex, Frame, Back^);
  2054. end;
  2055. {$ENDIF}
  2056. { TDllSynchroClass }
  2057. constructor TDllSynchroClass.Create;
  2058. begin
  2059. FSynchronizeWindow := AllocateHWnd(WndProc);
  2060. end;
  2061. procedure TDllSynchroClass.DefaultHandler(var Message);
  2062. begin
  2063. with TMessage(Message) do
  2064. Result := DefWindowProc(FSynchronizeWindow, Msg, WParam, LParam);
  2065. end;
  2066. destructor TDllSynchroClass.Destroy;
  2067. begin
  2068. DestroyWindow(FSynchronizeWindow);
  2069. inherited;
  2070. end;
  2071. type
  2072. PMethod = ^TMethod;
  2073. procedure TDllSynchroClass.SynchronizeMe(var Message: TMessage);
  2074. begin
  2075. try
  2076. TThreadMethod(PMethod(Message.WParam)^)();
  2077. except
  2078. end;
  2079. end;
  2080. procedure TDllSynchroClass.WndProc(var Message: TMessage);
  2081. begin
  2082. Dispatch(Message);
  2083. end;
  2084. initialization
  2085. RegisterTypes;
  2086. HashedPicList := TStringList.Create;
  2087. HashedPicList.Sorted := True;
  2088. PainterThread := TPainterThread.Create(True);
  2089. PainterThread.Priority := tpNormal;
  2090. finalization
  2091. UnRegisterTypes;
  2092. HashedPicList.Free;
  2093. PainterThread.FPause := True;
  2094. PainterThread.Terminate;
  2095. PainterThread.Free;
  2096. {$IFEND} // {$IF not Defined(COMPONENT_SET_LCL) and not Defined(COMPONENT_SET_VCL)}
  2097. {
  2098. File Notes:
  2099. -- TODOS ----------------------------------------------------
  2100. - nothing now
  2101. -- 0.26.1 Changes/Bug Fixes ---------------------------------
  2102. - Added some more IFDEFs for Lazarus widget sets.
  2103. - Removed CLX code.
  2104. - GTK version of Unix DisplayImageData only used with LCL GTK so the
  2105. the rest of the unit can be used with Qt or other LCL interfaces.
  2106. - Fallback mechanism for DisplayImageDataOnDC, it may fail on occasions.
  2107. - Changed file format conditional compilation to reflect changes
  2108. in LINK symbols.
  2109. - Lazarus 0.9.26 compatibility changes.
  2110. -- 0.24.1 Changes/Bug Fixes ---------------------------------
  2111. - Fixed wrong IFDEF causing that Imaging wouldn't compile in Lazarus
  2112. with GTK2 target.
  2113. - Added commnets with code for Lazarus rev. 11861+ regarding
  2114. RawImage interface. Replace current code with that in comments
  2115. if you use Lazarus from SVN. New RawImage interface will be used by
  2116. default after next Lazarus release.
  2117. -- 0.23 Changes/Bug Fixes -----------------------------------
  2118. - Added TImagingGIF.
  2119. -- 0.21 Changes/Bug Fixes -----------------------------------
  2120. - Uses only high level interface now (except for saving options).
  2121. - Slightly changed class hierarchy. TImagingGraphic is now only for loading
  2122. and base class for savers is new TImagingGraphicForSave. Also
  2123. TImagingGraphic is now registered with all supported file formats
  2124. by TPicture's format support.
  2125. -- 0.19 Changes/Bug Fixes -----------------------------------
  2126. - added DisplayImage procedures (thanks to Paul Michell, modified)
  2127. - removed RegisterTypes and UnRegisterTypes from interface section,
  2128. they are called automatically
  2129. - added procedures: ConvertImageToBitmap and ConvertBitmapToImage
  2130. -- 0.17 Changes/Bug Fixes -----------------------------------
  2131. - LCL data to bitmap conversion didn´t work in Linux, fixed
  2132. - added MNG file format
  2133. - added JNG file format
  2134. -- 0.15 Changes/Bug Fixes -----------------------------------
  2135. - made it LCL compatible
  2136. - made it CLX compatible
  2137. - added all initial stuff
  2138. }
  2139. end.