2
0

GR32_Png.pas 71 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611
  1. unit GR32_Png;
  2. (* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1 or LGPL 2.1 with linking exception
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * Alternatively, the contents of this file may be used under the terms of the
  16. * Free Pascal modified version of the GNU Lesser General Public License
  17. * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
  18. * of this license are applicable instead of those above.
  19. * Please see the file LICENSE.txt for additional information concerning this
  20. * license.
  21. *
  22. * The Original Code is GR32PNG for Graphics32
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Christian-W. Budde
  26. *
  27. * Portions created by the Initial Developer are Copyright (C) 2000-2009
  28. * the Initial Developer. All Rights Reserved.
  29. *
  30. * Contributor(s):
  31. *
  32. * ***** END LICENSE BLOCK ***** *)
  33. interface
  34. {$include GR32.inc}
  35. {$include GR32_PngCompilerSwitches.inc}
  36. uses
  37. Classes, Graphics, SysUtils, GR32, GR32_PortableNetworkGraphic;
  38. type
  39. TProgressEvent = procedure(Sender: TObject; Percent: Single) of object;
  40. TPortableNetworkGraphic32 = class(TPortableNetworkGraphic)
  41. private
  42. FProgressEvent: TProgressEvent;
  43. procedure AssignPropertiesFromBitmap32(Bitmap32: TCustomBitmap32);
  44. function GetBackgroundColor: TColor32;
  45. protected
  46. procedure AssignTo(Dest: TPersistent); override;
  47. function GR32Scanline(Bitmap: TObject; Y: Integer): Pointer; virtual;
  48. function GR32ScanlineProgress(Bitmap: TObject; Y: Integer): Pointer; virtual;
  49. public
  50. procedure Assign(Source: TPersistent); override;
  51. procedure MakeIndexColored(MaxColorCount: Integer);
  52. function IsPremultiplied: Boolean;
  53. procedure DrawToBitmap32(Bitmap32: TCustomBitmap32); virtual;
  54. property Background: TColor32 read GetBackgroundColor;
  55. property Progress: TProgressEvent read FProgressEvent write FProgressEvent;
  56. end;
  57. function IsValidPNG(Stream: TStream): Boolean; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
  58. function IsValidPNG(const Filename: string): Boolean; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
  59. procedure LoadBitmap32FromPNG(Bitmap: TBitmap32; const Filename: string); overload; {$IFDEF USEINLINING} inline; {$ENDIF}
  60. procedure LoadBitmap32FromPNG(Bitmap: TBitmap32; Stream: TStream); overload; {$IFDEF USEINLINING} inline; {$ENDIF}
  61. procedure SaveBitmap32ToPNG(Bitmap: TBitmap32; const FileName: string); overload; {$IFDEF USEINLINING} inline; {$ENDIF}
  62. procedure SaveBitmap32ToPNG(Bitmap: TBitmap32; Stream: TStream); overload; {$IFDEF USEINLINING} inline; {$ENDIF}
  63. implementation
  64. uses
  65. Math;
  66. resourcestring
  67. RCStrUnsupportedFormat = 'Unsupported Format';
  68. RCStrDataIncomplete = 'Data not complete';
  69. type
  70. TCustomPngNonInterlacedDecoder = class(TCustomPngDecoder)
  71. protected
  72. FBytesPerRow: Integer;
  73. FRowByteSize: Integer;
  74. procedure TransferData(Source: Pointer; Destination: PColor32); virtual; abstract;
  75. public
  76. constructor Create(Stream: TStream; Header: TChunkPngImageHeader;
  77. Gamma: TChunkPngGamma = nil; Palette: TChunkPngPalette = nil;
  78. Transparency: TCustomPngTransparency = nil); override;
  79. destructor Destroy; override;
  80. procedure DecodeToScanline(Bitmap: TObject; ScanLineCallback: TScanLineCallback); override;
  81. end;
  82. TPngNonInterlacedGrayscale1bitDecoder = class(TCustomPngNonInterlacedDecoder)
  83. protected
  84. procedure TransferData(Source: Pointer; Destination: PColor32); override;
  85. end;
  86. TPngNonInterlacedGrayscale2bitDecoder = class(TCustomPngNonInterlacedDecoder)
  87. protected
  88. procedure TransferData(Source: Pointer; Destination: PColor32); override;
  89. end;
  90. TPngNonInterlacedGrayscale4bitDecoder = class(TCustomPngNonInterlacedDecoder)
  91. protected
  92. procedure TransferData(Source: Pointer; Destination: PColor32); override;
  93. end;
  94. TPngNonInterlacedGrayscale8bitDecoder = class(TCustomPngNonInterlacedDecoder)
  95. protected
  96. procedure TransferData(Source: Pointer; Destination: PColor32); override;
  97. end;
  98. TPngNonInterlacedGrayscale16bitDecoder = class(TCustomPngNonInterlacedDecoder)
  99. protected
  100. procedure TransferData(Source: Pointer; Destination: PColor32); override;
  101. end;
  102. TPngNonInterlacedTrueColor8bitDecoder = class(TCustomPngNonInterlacedDecoder)
  103. protected
  104. procedure TransferData(Source: Pointer; Destination: PColor32); override;
  105. end;
  106. TPngNonInterlacedTrueColor16bitDecoder = class(TCustomPngNonInterlacedDecoder)
  107. protected
  108. procedure TransferData(Source: Pointer; Destination: PColor32); override;
  109. end;
  110. TPngNonInterlacedPaletteDecoder = class(TCustomPngNonInterlacedDecoder)
  111. protected
  112. procedure TransferData(Source: Pointer; Destination: PColor32); override;
  113. end;
  114. TPngNonInterlacedPalette8bitDecoder = class(TCustomPngNonInterlacedDecoder)
  115. protected
  116. procedure TransferData(Source: Pointer; Destination: PColor32); override;
  117. end;
  118. TPngNonInterlacedGrayscaleAlpha8bitDecoder = class(TCustomPngNonInterlacedDecoder)
  119. protected
  120. procedure TransferData(Source: Pointer; Destination: PColor32); override;
  121. end;
  122. TPngNonInterlacedGrayscaleAlpha16bitDecoder = class(TCustomPngNonInterlacedDecoder)
  123. protected
  124. procedure TransferData(Source: Pointer; Destination: PColor32); override;
  125. end;
  126. TPngNonInterlacedTrueColorAlpha8bitDecoder = class(TCustomPngNonInterlacedDecoder)
  127. protected
  128. procedure TransferData(Source: Pointer; Destination: PColor32); override;
  129. end;
  130. TPngNonInterlacedTrueColorAlpha16bitDecoder = class(TCustomPngNonInterlacedDecoder)
  131. protected
  132. procedure TransferData(Source: Pointer; Destination: PColor32); override;
  133. end;
  134. TCustomPngAdam7Decoder = class(TCustomPngDecoder)
  135. protected
  136. procedure TransferData(const Pass: Byte; Source: Pointer; Destination: PColor32); virtual; abstract;
  137. public
  138. constructor Create(Stream: TStream; Header: TChunkPngImageHeader;
  139. Gamma: TChunkPngGamma = nil; Palette: TChunkPngPalette = nil;
  140. Transparency: TCustomPngTransparency = nil); override;
  141. destructor Destroy; override;
  142. procedure DecodeToScanline(Bitmap: TObject; ScanLineCallback: TScanLineCallback); override;
  143. end;
  144. TPngAdam7Grayscale1bitDecoder = class(TCustomPngAdam7Decoder)
  145. protected
  146. procedure TransferData(const Pass: Byte; Source: Pointer; Destination: PColor32); override;
  147. end;
  148. TPngAdam7Grayscale2bitDecoder = class(TCustomPngAdam7Decoder)
  149. protected
  150. procedure TransferData(const Pass: Byte; Source: Pointer; Destination: PColor32); override;
  151. end;
  152. TPngAdam7Grayscale4bitDecoder = class(TCustomPngAdam7Decoder)
  153. protected
  154. procedure TransferData(const Pass: Byte; Source: Pointer; Destination: PColor32); override;
  155. end;
  156. TPngAdam7Grayscale8bitDecoder = class(TCustomPngAdam7Decoder)
  157. protected
  158. procedure TransferData(const Pass: Byte; Source: Pointer; Destination: PColor32); override;
  159. end;
  160. TPngAdam7Grayscale16bitDecoder = class(TCustomPngAdam7Decoder)
  161. protected
  162. procedure TransferData(const Pass: Byte; Source: Pointer; Destination: PColor32); override;
  163. end;
  164. TPngAdam7TrueColor8bitDecoder = class(TCustomPngAdam7Decoder)
  165. protected
  166. procedure TransferData(const Pass: Byte; Source: Pointer; Destination: PColor32); override;
  167. end;
  168. TPngAdam7TrueColor16bitDecoder = class(TCustomPngAdam7Decoder)
  169. protected
  170. procedure TransferData(const Pass: Byte; Source: Pointer; Destination: PColor32); override;
  171. end;
  172. TPngAdam7Palette1bitDecoder = class(TCustomPngAdam7Decoder)
  173. protected
  174. procedure TransferData(const Pass: Byte; Source: Pointer; Destination: PColor32); override;
  175. end;
  176. TPngAdam7Palette2bitDecoder = class(TCustomPngAdam7Decoder)
  177. protected
  178. procedure TransferData(const Pass: Byte; Source: Pointer; Destination: PColor32); override;
  179. end;
  180. TPngAdam7Palette4bitDecoder = class(TCustomPngAdam7Decoder)
  181. protected
  182. procedure TransferData(const Pass: Byte; Source: Pointer; Destination: PColor32); override;
  183. end;
  184. TPngAdam7Palette8bitDecoder = class(TCustomPngAdam7Decoder)
  185. protected
  186. procedure TransferData(const Pass: Byte; Source: Pointer; Destination: PColor32); override;
  187. end;
  188. TPngAdam7GrayscaleAlpha8bitDecoder = class(TCustomPngAdam7Decoder)
  189. protected
  190. procedure TransferData(const Pass: Byte; Source: Pointer; Destination: PColor32); override;
  191. end;
  192. TPngAdam7GrayscaleAlpha16bitDecoder = class(TCustomPngAdam7Decoder)
  193. protected
  194. procedure TransferData(const Pass: Byte; Source: Pointer; Destination: PColor32); override;
  195. end;
  196. TPngAdam7TrueColorAlpha8bitDecoder = class(TCustomPngAdam7Decoder)
  197. protected
  198. procedure TransferData(const Pass: Byte; Source: Pointer; Destination: PColor32); override;
  199. end;
  200. TPngAdam7TrueColorAlpha16bitDecoder = class(TCustomPngAdam7Decoder)
  201. protected
  202. procedure TransferData(const Pass: Byte; Source: Pointer; Destination: PColor32); override;
  203. end;
  204. TCustomPngNonInterlacedEncoder = class(TCustomPngEncoder)
  205. protected
  206. FBytesPerRow: Integer;
  207. FRowByteSize: Integer;
  208. function ColorInPalette(Color: TColor32): Integer; virtual;
  209. procedure TransferData(Source: PColor32; Destination: Pointer); virtual; abstract;
  210. public
  211. constructor Create(Stream: TStream; Header: TChunkPngImageHeader;
  212. Gamma: TChunkPngGamma = nil; Palette: TChunkPngPalette = nil;
  213. Transparency: TCustomPngTransparency = nil); override;
  214. destructor Destroy; override;
  215. procedure EncodeFromScanline(Bitmap: TObject; ScanLineCallback: TScanLineCallback); override;
  216. end;
  217. TPngNonInterlacedGrayscale1bitEncoder = class(TCustomPngNonInterlacedEncoder)
  218. protected
  219. procedure TransferData(Source: PColor32; Destination: Pointer); override;
  220. end;
  221. TPngNonInterlacedGrayscale2bitEncoder = class(TCustomPngNonInterlacedEncoder)
  222. protected
  223. procedure TransferData(Source: PColor32; Destination: Pointer); override;
  224. end;
  225. TPngNonInterlacedGrayscale4bitEncoder = class(TCustomPngNonInterlacedEncoder)
  226. protected
  227. procedure TransferData(Source: PColor32; Destination: Pointer); override;
  228. end;
  229. TPngNonInterlacedGrayscale8bitEncoder = class(TCustomPngNonInterlacedEncoder)
  230. protected
  231. procedure TransferData(Source: PColor32; Destination: Pointer); override;
  232. end;
  233. TPngNonInterlacedTrueColor8bitEncoder = class(TCustomPngNonInterlacedEncoder)
  234. protected
  235. procedure TransferData(Source: PColor32; Destination: Pointer); override;
  236. end;
  237. TPngNonInterlacedPalette1bitEncoder = class(TCustomPngNonInterlacedEncoder)
  238. protected
  239. procedure TransferData(Source: PColor32; Destination: Pointer); override;
  240. end;
  241. TPngNonInterlacedPalette2bitEncoder = class(TCustomPngNonInterlacedEncoder)
  242. protected
  243. procedure TransferData(Source: PColor32; Destination: Pointer); override;
  244. end;
  245. TPngNonInterlacedPalette4bitEncoder = class(TCustomPngNonInterlacedEncoder)
  246. protected
  247. procedure TransferData(Source: PColor32; Destination: Pointer); override;
  248. end;
  249. TPngNonInterlacedPalette8bitEncoder = class(TCustomPngNonInterlacedEncoder)
  250. protected
  251. procedure TransferData(Source: PColor32; Destination: Pointer); override;
  252. end;
  253. TPngNonInterlacedGrayscaleAlpha8bitEncoder = class(TCustomPngNonInterlacedEncoder)
  254. protected
  255. procedure TransferData(Source: PColor32; Destination: Pointer); override;
  256. end;
  257. TPngNonInterlacedTrueColorAlpha8bitEncoder = class(TCustomPngNonInterlacedEncoder)
  258. protected
  259. procedure TransferData(Source: PColor32; Destination: Pointer); override;
  260. end;
  261. TPalette24 = array of TRGB24;
  262. TPngHistogramEntry = class
  263. private
  264. FColor: TColor32;
  265. FCount: Integer;
  266. public
  267. constructor Create(Key: TColor32);
  268. procedure Advance;
  269. property Count: Integer read FCount write FCount;
  270. property Color: TColor32 read FColor;
  271. end;
  272. TPngPalette = class
  273. private
  274. FItems: array of TColor32;
  275. FCount: Integer;
  276. protected
  277. procedure Remove(Index: Integer);
  278. function GetItem(index: Integer): TColor32;
  279. function Find(const item: TColor32; var index: Integer): Boolean;
  280. function Compare(const item1, item2: TColor32): Integer;
  281. procedure InsertItem(index: Integer; const anItem: TColor32);
  282. public
  283. function Add(const Item: TColor32): Integer; overload;
  284. function IndexOf(const Value: TColor32): Integer;
  285. procedure GetNearest(var Value: TColor32);
  286. procedure Clear;
  287. procedure LimitTo(Count: Integer);
  288. property Items[index: Integer]: TColor32 read GetItem; default;
  289. property Count: Integer read FCount;
  290. end;
  291. TPngHistogram = class
  292. private
  293. FItems: array of TPngHistogramEntry;
  294. FCount: Integer;
  295. procedure Remove(Index: Integer);
  296. protected
  297. function GetItem(index: Integer): TPngHistogramEntry;
  298. function Find(const item: TColor32; var index: Integer): Boolean;
  299. function Compare(const item1, item2: TColor32): Integer;
  300. procedure InsertItem(index: Integer; const anItem: TPngHistogramEntry);
  301. public
  302. function Add(const anItem: TPngHistogramEntry): Integer; overload;
  303. function IndexOf(const Value: TColor32): Integer;
  304. function Add(Value: TColor32): Integer; overload;
  305. procedure Advance(Value: TColor32); overload;
  306. procedure Clear;
  307. procedure Clean;
  308. function GetPalette(MaxColors: Integer = 256): TPngPalette;
  309. property Items[index: Integer]: TPngHistogramEntry read GetItem; default;
  310. property Count: Integer read FCount;
  311. end;
  312. function IsValidPNG(Stream: TStream): Boolean;
  313. begin
  314. Result := TPortableNetworkGraphic32.CanLoad(Stream);
  315. end;
  316. function IsValidPNG(const Filename: string): Boolean;
  317. begin
  318. Result := TPortableNetworkGraphic32.CanLoad(Filename);
  319. end;
  320. procedure LoadBitmap32FromPNG(Bitmap: TBitmap32; const Filename: string);
  321. var
  322. PNG: TPortableNetworkGraphic32;
  323. begin
  324. PNG := TPortableNetworkGraphic32.Create;
  325. try
  326. PNG.LoadFromFile(Filename);
  327. PNG.AssignTo(Bitmap);
  328. finally
  329. PNG.Free;
  330. end;
  331. end;
  332. procedure LoadBitmap32FromPNG(Bitmap: TBitmap32; Stream: TStream);
  333. var
  334. PNG: TPortableNetworkGraphic32;
  335. begin
  336. PNG := TPortableNetworkGraphic32.Create;
  337. try
  338. PNG.LoadFromStream(Stream);
  339. PNG.AssignTo(Bitmap);
  340. finally
  341. PNG.Free;
  342. end;
  343. end;
  344. procedure SaveBitmap32ToPNG(Bitmap: TBitmap32; const FileName: string);
  345. var
  346. PNG: TPortableNetworkGraphic32;
  347. begin
  348. PNG := TPortableNetworkGraphic32.Create;
  349. try
  350. PNG.Assign(Bitmap);
  351. PNG.SaveToFile(Filename);
  352. finally
  353. PNG.Free;
  354. end;
  355. end;
  356. procedure SaveBitmap32ToPNG(Bitmap: TBitmap32; Stream: TStream);
  357. var
  358. PNG: TPortableNetworkGraphic32;
  359. begin
  360. PNG := TPortableNetworkGraphic32.Create;
  361. try
  362. PNG.Assign(Bitmap);
  363. PNG.SaveToStream(Stream);
  364. finally
  365. PNG.Free;
  366. end;
  367. end;
  368. { TPortableNetworkGraphic32 }
  369. function TPortableNetworkGraphic32.GetBackgroundColor: TColor32;
  370. var
  371. ResultColor32: TColor32Entry absolute Result;
  372. begin
  373. if (FBackgroundChunk <> nil) then
  374. begin
  375. if FBackgroundChunk.Background is TPngBackgroundColorFormat04 then
  376. with TPngBackgroundColorFormat04(FBackgroundChunk.Background) do
  377. begin
  378. ResultColor32.R := GraySampleValue;
  379. ResultColor32.G := GraySampleValue;
  380. ResultColor32.B := GraySampleValue;
  381. ResultColor32.A := $FF;
  382. end
  383. else
  384. if FBackgroundChunk.Background is TPngBackgroundColorFormat26 then
  385. with TPngBackgroundColorFormat26(FBackgroundChunk.Background) do
  386. begin
  387. ResultColor32.R := RedSampleValue;
  388. ResultColor32.G := GreenSampleValue;
  389. ResultColor32.B := BlueSampleValue;
  390. ResultColor32.A := $FF;
  391. end
  392. else
  393. if FBackgroundChunk.Background is TPngBackgroundColorFormat3 then
  394. with TPngBackgroundColorFormat3(FBackgroundChunk.Background) do
  395. begin
  396. ResultColor32.R := PaletteEntry[PaletteIndex].R;
  397. ResultColor32.G := PaletteEntry[PaletteIndex].R;
  398. ResultColor32.B := PaletteEntry[PaletteIndex].R;
  399. ResultColor32.A := $FF;
  400. end;
  401. end else
  402. Result := $0;
  403. end;
  404. function TPortableNetworkGraphic32.GR32Scanline(Bitmap: TObject; Y: Integer): Pointer;
  405. begin
  406. if Bitmap is TCustomBitmap32 then
  407. Result := TCustomBitmap32(Bitmap).ScanLine[Y]
  408. else
  409. Result := nil;
  410. end;
  411. function TPortableNetworkGraphic32.GR32ScanlineProgress(Bitmap: TObject;
  412. Y: Integer): Pointer;
  413. begin
  414. Result := GR32Scanline(Bitmap, Y);
  415. if FImageHeader.Height > 0 then
  416. FProgressEvent(Self, 100 * Y / FImageHeader.Height)
  417. else
  418. FProgressEvent(Self, 100);
  419. end;
  420. function TPortableNetworkGraphic32.IsPremultiplied: Boolean;
  421. var
  422. TempBitmap: TBitmap32;
  423. Pointer: PColor32EntryArray;
  424. Value: TColor32Entry;
  425. Index: Integer;
  426. begin
  427. // this code checks whether the bitmap is *NOT* premultiplied
  428. // unfortunately this is just a weak check and might fail
  429. Result := True;
  430. TempBitmap := TBitmap32.Create;
  431. try
  432. AssignTo(TempBitmap);
  433. Pointer := PColor32EntryArray(TempBitmap.Bits);
  434. for Index := 0 to TempBitmap.Width * TempBitmap.Height - 1 do
  435. begin
  436. Value := Pointer^[Index];
  437. if (Value.R > Value.A) or (Value.G > Value.A) or (Value.B > Value.A) then
  438. begin
  439. Result := False;
  440. Exit;
  441. end;
  442. end;
  443. finally
  444. TempBitmap.Free;
  445. end;
  446. end;
  447. procedure TPortableNetworkGraphic32.MakeIndexColored(MaxColorCount: Integer);
  448. var
  449. Index: Integer;
  450. Histogram: TPngHistogram;
  451. Palette: TPngPalette;
  452. Bitmap: TBitmap32;
  453. Bits: PColor32;
  454. PixelCount: Integer;
  455. InvPixelCount: TFloat;
  456. RGB24: TRGB24;
  457. EncoderClass: TCustomPngEncoderClass;
  458. DataStream: TMemoryStream;
  459. begin
  460. if ColorType in [ctIndexedColor, ctGrayscale, ctGrayscaleAlpha] then
  461. raise Exception.Create('Color type not suitable');
  462. Bitmap := TBitmap32.Create;
  463. try
  464. AssignTo(Bitmap);
  465. Histogram := TPngHistogram.Create;
  466. try
  467. Bits := PColor32(Bitmap.Bits);
  468. PixelCount := Bitmap.Height * Bitmap.Width;
  469. InvPixelCount := 100 / (PixelCount - 1);
  470. if (Assigned(FProgressEvent)) then
  471. for Index := 0 to PixelCount - 1 do
  472. begin
  473. Histogram.Advance(Bits^);
  474. Inc(Bits);
  475. FProgressEvent(Self, 0.5 * Index * InvPixelCount);
  476. end
  477. else
  478. for Index := 0 to PixelCount - 1 do
  479. begin
  480. Histogram.Advance(Bits^);
  481. Inc(Bits);
  482. end;
  483. Palette := Histogram.GetPalette(MaxColorCount);
  484. finally
  485. Histogram.Free;
  486. end;
  487. Bits := PColor32(Bitmap.Bits);
  488. if (Assigned(FProgressEvent)) then
  489. for Index := 0 to PixelCount - 1 do
  490. begin
  491. Palette.GetNearest(Bits^);
  492. Inc(Bits);
  493. FProgressEvent(Self, 50 + 0.5 * Index * InvPixelCount);
  494. end
  495. else
  496. for Index := 0 to PixelCount - 1 do
  497. begin
  498. Palette.GetNearest(Bits^);
  499. Inc(Bits);
  500. end;
  501. // basic properties
  502. ImageHeader.Width := Width;
  503. ImageHeader.Height := Height;
  504. ImageHeader.CompressionMethod := 0;
  505. ImageHeader.InterlaceMethod := imNone;
  506. ImageHeader.ColorType := ctIndexedColor;
  507. if Palette.Count <= 2 then
  508. ImageHeader.BitDepth := 1
  509. else
  510. if Palette.Count <= 4 then
  511. ImageHeader.BitDepth := 2
  512. else
  513. if Palette.Count <= 16 then
  514. ImageHeader.BitDepth := 4
  515. else
  516. ImageHeader.BitDepth := 8;
  517. if not (FPaletteChunk <> nil) then
  518. FPaletteChunk := TChunkPngPalette.Create(ImageHeader);
  519. FPaletteChunk.Count := Palette.Count;
  520. for Index := 0 to Palette.Count - 1 do
  521. begin
  522. RGB24.R := TColor32Entry(Palette.Items[Index]).R;
  523. RGB24.G := TColor32Entry(Palette.Items[Index]).G;
  524. RGB24.B := TColor32Entry(Palette.Items[Index]).B;
  525. FPaletteChunk.PaletteEntry[Index] := RGB24;
  526. end;
  527. {$IFDEF StoreGamma}
  528. // add linear gamma chunk
  529. if not (FGammaChunk <> nil) then
  530. FGammaChunk := TChunkPngGamma.Create(ImageHeader);
  531. FGammaChunk.GammaAsSingle := 1;
  532. {$ELSE}
  533. // delete any gama correction table
  534. FreeAndNil(FGammaChunk);
  535. {$ENDIF}
  536. case ImageHeader.ColorType of
  537. ctIndexedColor:
  538. case ImageHeader.BitDepth of
  539. 1 : EncoderClass := TPngNonInterlacedPalette1bitEncoder;
  540. 2 : EncoderClass := TPngNonInterlacedPalette2bitEncoder;
  541. 4 : EncoderClass := TPngNonInterlacedPalette4bitEncoder;
  542. 8 : EncoderClass := TPngNonInterlacedPalette8bitEncoder;
  543. else
  544. raise EPngError.Create(RCStrUnsupportedFormat);
  545. end;
  546. else
  547. raise EPngError.Create(RCStrUnsupportedFormat);
  548. end;
  549. DataStream := TMemoryStream.Create;
  550. try
  551. with EncoderClass.Create(DataStream, FImageHeader, FGammaChunk, FPaletteChunk) do
  552. try
  553. if (Assigned(FProgressEvent)) then
  554. EncodeFromScanline(Bitmap, GR32ScanlineProgress)
  555. else
  556. EncodeFromScanline(Bitmap, GR32Scanline);
  557. finally
  558. Free;
  559. end;
  560. // reset data stream position
  561. DataStream.Seek(0, soFromBeginning);
  562. // compress image data from data stream
  563. CompressImageDataFromStream(DataStream);
  564. finally
  565. DataStream.Free;
  566. end;
  567. finally
  568. Bitmap.Free;
  569. end;
  570. end;
  571. procedure TPortableNetworkGraphic32.DrawToBitmap32(Bitmap32: TCustomBitmap32);
  572. var
  573. DecoderClass: TCustomPngDecoderClass;
  574. DataStream: TMemoryStream;
  575. Transparency: TCustomPngTransparency;
  576. begin
  577. DataStream := TMemoryStream.Create;
  578. try
  579. // decompress image data to data stream
  580. DecompressImageDataToStream(DataStream);
  581. // reset data stream position
  582. DataStream.Seek(0, soFromBeginning);
  583. case ImageHeader.InterlaceMethod of
  584. imNone:
  585. case ImageHeader.ColorType of
  586. ctGrayscale:
  587. case ImageHeader.BitDepth of
  588. 1: DecoderClass := TPngNonInterlacedGrayscale1bitDecoder;
  589. 2: DecoderClass := TPngNonInterlacedGrayscale2bitDecoder;
  590. 4: DecoderClass := TPngNonInterlacedGrayscale4bitDecoder;
  591. 8: DecoderClass := TPngNonInterlacedGrayscale8bitDecoder;
  592. 16:DecoderClass := TPngNonInterlacedGrayscale16bitDecoder;
  593. else
  594. raise EPngError.Create(RCStrUnsupportedFormat);
  595. end;
  596. ctTrueColor :
  597. case ImageHeader.BitDepth of
  598. 8: DecoderClass := TPngNonInterlacedTrueColor8bitDecoder;
  599. 16:DecoderClass := TPngNonInterlacedTrueColor16bitDecoder;
  600. else
  601. raise EPngError.Create(RCStrUnsupportedFormat);
  602. end;
  603. ctIndexedColor :
  604. case ImageHeader.BitDepth of
  605. 1,
  606. 2,
  607. 4: DecoderClass := TPngNonInterlacedPaletteDecoder;
  608. 8: DecoderClass := TPngNonInterlacedPalette8bitDecoder;
  609. else
  610. raise EPngError.Create(RCStrUnsupportedFormat);
  611. end;
  612. ctGrayscaleAlpha :
  613. case ImageHeader.BitDepth of
  614. 8: DecoderClass := TPngNonInterlacedGrayscaleAlpha8bitDecoder;
  615. 16:DecoderClass := TPngNonInterlacedGrayscaleAlpha16bitDecoder;
  616. else
  617. raise EPngError.Create(RCStrUnsupportedFormat);
  618. end;
  619. ctTrueColorAlpha :
  620. case ImageHeader.BitDepth of
  621. 8: DecoderClass := TPngNonInterlacedTrueColorAlpha8bitDecoder;
  622. 16:DecoderClass := TPngNonInterlacedTrueColorAlpha16bitDecoder;
  623. else
  624. raise EPngError.Create(RCStrUnsupportedFormat);
  625. end;
  626. else
  627. raise EPngError.Create(RCStrUnsupportedFormat);
  628. end;
  629. imAdam7 :
  630. case ImageHeader.ColorType of
  631. ctGrayscale :
  632. case ImageHeader.BitDepth of
  633. 1: DecoderClass := TPngAdam7Grayscale1bitDecoder;
  634. 2: DecoderClass := TPngAdam7Grayscale2bitDecoder;
  635. 4: DecoderClass := TPngAdam7Grayscale4bitDecoder;
  636. 8: DecoderClass := TPngAdam7Grayscale8bitDecoder;
  637. 16:DecoderClass := TPngAdam7Grayscale16bitDecoder;
  638. else
  639. raise EPngError.Create(RCStrUnsupportedFormat);
  640. end;
  641. ctTrueColor :
  642. case ImageHeader.BitDepth of
  643. 8: DecoderClass := TPngAdam7TrueColor8bitDecoder;
  644. 16:DecoderClass := TPngAdam7TrueColor16bitDecoder;
  645. else
  646. raise EPngError.Create(RCStrUnsupportedFormat);
  647. end;
  648. ctIndexedColor :
  649. case ImageHeader.BitDepth of
  650. 1: DecoderClass := TPngAdam7Palette1bitDecoder;
  651. 2: DecoderClass := TPngAdam7Palette2bitDecoder;
  652. 4: DecoderClass := TPngAdam7Palette4bitDecoder;
  653. 8: DecoderClass := TPngAdam7Palette8bitDecoder;
  654. else
  655. raise EPngError.Create(RCStrUnsupportedFormat);
  656. end;
  657. ctGrayscaleAlpha :
  658. case ImageHeader.BitDepth of
  659. 8: DecoderClass := TPngAdam7GrayscaleAlpha8bitDecoder;
  660. 16:DecoderClass := TPngAdam7GrayscaleAlpha16bitDecoder;
  661. else
  662. raise EPngError.Create(RCStrUnsupportedFormat);
  663. end;
  664. ctTrueColorAlpha :
  665. case ImageHeader.BitDepth of
  666. 8: DecoderClass := TPngAdam7TrueColorAlpha8bitDecoder;
  667. 16:DecoderClass := TPngAdam7TrueColorAlpha16bitDecoder;
  668. else
  669. raise EPngError.Create(RCStrUnsupportedFormat);
  670. end;
  671. else
  672. raise EPngError.Create(RCStrUnsupportedFormat);
  673. end;
  674. else
  675. raise EPngError.Create(RCStrUnsupportedFormat);
  676. end;
  677. if (FTransparencyChunk <> nil) then
  678. Transparency := FTransparencyChunk.Transparency
  679. else
  680. Transparency := nil;
  681. with DecoderClass.Create(DataStream, FImageHeader, FGammaChunk,
  682. FPaletteChunk, Transparency) do
  683. try
  684. if (Assigned(FProgressEvent)) then
  685. DecodeToScanline(Bitmap32, GR32ScanlineProgress)
  686. else
  687. DecodeToScanline(Bitmap32, GR32Scanline);
  688. finally
  689. Free;
  690. end;
  691. finally
  692. DataStream.Free;
  693. end;
  694. end;
  695. function ColorIndexInPalette(Color: TColor32; Palette: TPalette24): Integer;
  696. begin
  697. for Result := 0 to Length(Palette) - 1 do
  698. if (TColor32Entry(Color).R = Palette[Result].R) and
  699. (TColor32Entry(Color).G = Palette[Result].G) and
  700. (TColor32Entry(Color).B = Palette[Result].B) then
  701. Exit;
  702. Result := -1;
  703. end;
  704. procedure TPortableNetworkGraphic32.AssignPropertiesFromBitmap32(
  705. Bitmap32: TCustomBitmap32);
  706. var
  707. Index, PalIndex: Integer;
  708. IsAlpha: Boolean;
  709. IsGrayScale: Boolean;
  710. IsPalette: Boolean;
  711. Color: TColor32;
  712. TempPalette: TPalette24;
  713. TempAlpha: Byte;
  714. begin
  715. // basic properties
  716. ImageHeader.Width := Bitmap32.Width;
  717. ImageHeader.Height := Bitmap32.Height;
  718. ImageHeader.CompressionMethod := 0;
  719. ImageHeader.InterlaceMethod := imNone;
  720. // initialize
  721. SetLength(TempPalette, 0);
  722. IsGrayScale := True;
  723. IsPalette := True;
  724. IsAlpha := False;
  725. TempAlpha := 0;
  726. // check every pixel in the bitmap for the use of the alpha channel,
  727. // whether the image is grayscale or whether the colors can be stored
  728. // as a palette (and build the palette at the same time)
  729. for Index := 0 to Bitmap32.Width * Bitmap32.Height - 1 do
  730. begin
  731. Color := Bitmap32.Bits[Index];
  732. // check whether the palette is empty
  733. if Length(TempPalette) = 0 then
  734. begin
  735. IsAlpha := TColor32Entry(Color).A < 255 ;
  736. // eventually store first alpha component
  737. if IsAlpha then
  738. TempAlpha := TColor32Entry(Color).A;
  739. SetLength(TempPalette, 1);
  740. TempPalette[0].R := TColor32Entry(Color).R;
  741. TempPalette[0].G := TColor32Entry(Color).G;
  742. TempPalette[0].B := TColor32Entry(Color).B;
  743. IsGrayScale := (TColor32Entry(Color).R = TColor32Entry(Color).G) and
  744. (TColor32Entry(Color).B = TColor32Entry(Color).G);
  745. end else
  746. begin
  747. // check alpha channel
  748. if (TColor32Entry(Color).A < 255) then
  749. begin
  750. if IsAlpha then
  751. begin
  752. if IsPalette and (TempAlpha <> TColor32Entry(Color).A) then
  753. IsPalette := False;
  754. end else
  755. TempAlpha := TColor32Entry(Color).A;
  756. IsAlpha := True;
  757. end;
  758. if ColorIndexInPalette(Color, TempPalette) < 0 then
  759. begin
  760. if IsPalette then
  761. begin
  762. if (Length(TempPalette) < 256) then
  763. begin
  764. PalIndex := Length(TempPalette);
  765. SetLength(TempPalette, Length(TempPalette) + 1);
  766. TempPalette[PalIndex].R := TColor32Entry(Color).R;
  767. TempPalette[PalIndex].G := TColor32Entry(Color).G;
  768. TempPalette[PalIndex].B := TColor32Entry(Color).B;
  769. if IsGrayScale and not
  770. ((TColor32Entry(Color).R = TColor32Entry(Color).G) and
  771. (TColor32Entry(Color).B = TColor32Entry(Color).G)) then
  772. IsGrayScale := False;
  773. end else
  774. IsPalette := False;
  775. end else
  776. if not ((TColor32Entry(Color).R = TColor32Entry(Color).G) and
  777. (TColor32Entry(Color).B = TColor32Entry(Color).G)) then
  778. IsGrayScale := False;
  779. end;
  780. end;
  781. if IsAlpha and (not IsPalette) and (not IsGrayScale) then
  782. Break;
  783. end;
  784. // temporary fix for the case that a palette and an alpha channel has been detected
  785. if IsPalette and IsAlpha then
  786. IsPalette := False;
  787. // set image header
  788. if IsGrayScale then
  789. begin
  790. if IsAlpha then
  791. begin
  792. ImageHeader.ColorType := ctGrayscaleAlpha;
  793. ImageHeader.BitDepth := 8;
  794. end else
  795. begin
  796. ImageHeader.ColorType := ctIndexedColor; // ctGrayscale
  797. if Length(TempPalette) <= 2 then
  798. ImageHeader.BitDepth := 1
  799. else
  800. if Length(TempPalette) <= 4 then
  801. ImageHeader.BitDepth := 2
  802. else
  803. if Length(TempPalette) <= 16 then
  804. ImageHeader.BitDepth := 4
  805. else
  806. ImageHeader.BitDepth := 8;
  807. end;
  808. end else
  809. if IsPalette then
  810. begin
  811. ImageHeader.ColorType := ctIndexedColor;
  812. if Length(TempPalette) <= 2 then
  813. ImageHeader.BitDepth := 1
  814. else
  815. if Length(TempPalette) <= 4 then
  816. ImageHeader.BitDepth := 2
  817. else
  818. if Length(TempPalette) <= 16 then
  819. ImageHeader.BitDepth := 4
  820. else
  821. ImageHeader.BitDepth := 8;
  822. end else
  823. if IsAlpha then
  824. begin
  825. ImageHeader.ColorType := ctTrueColorAlpha;
  826. ImageHeader.BitDepth := 8;
  827. end else
  828. begin
  829. ImageHeader.ColorType := ctTrueColor;
  830. ImageHeader.BitDepth := 8;
  831. end;
  832. // eventually prepare palette
  833. if ImageHeader.HasPalette then
  834. begin
  835. Assert(Length(TempPalette) <= 256);
  836. if not (FPaletteChunk <> nil) then
  837. FPaletteChunk := TChunkPngPalette.Create(ImageHeader);
  838. FPaletteChunk.Count := Length(TempPalette);
  839. for Index := 0 to Length(TempPalette) - 1 do
  840. FPaletteChunk.PaletteEntry[Index] := TempPalette[Index];
  841. end;
  842. {$IFDEF StoreGamma}
  843. // add linear gamma chunk
  844. if not (FGammaChunk <> nil) then
  845. FGammaChunk := TChunkPngGamma.Create(ImageHeader);
  846. FGammaChunk.GammaAsSingle := 1;
  847. {$ELSE}
  848. // delete any gama correction table
  849. FreeAndNil(FGammaChunk);
  850. {$ENDIF}
  851. end;
  852. procedure TPortableNetworkGraphic32.Assign(Source: TPersistent);
  853. var
  854. EncoderClass: TCustomPngEncoderClass;
  855. DataStream: TMemoryStream;
  856. begin
  857. if Source is TCustomBitmap32 then
  858. begin
  859. // Assign
  860. AssignPropertiesFromBitmap32(TCustomBitmap32(Source));
  861. case ImageHeader.ColorType of
  862. ctGrayscale:
  863. case ImageHeader.BitDepth of
  864. 1: EncoderClass := TPngNonInterlacedGrayscale1bitEncoder;
  865. 2: EncoderClass := TPngNonInterlacedGrayscale2bitEncoder;
  866. 4: EncoderClass := TPngNonInterlacedGrayscale4bitEncoder;
  867. 8: EncoderClass := TPngNonInterlacedGrayscale8bitEncoder;
  868. else
  869. raise EPngError.Create(RCStrUnsupportedFormat);
  870. end;
  871. ctTrueColor:
  872. EncoderClass := TPngNonInterlacedTrueColor8bitEncoder;
  873. ctIndexedColor:
  874. case ImageHeader.BitDepth of
  875. 1 : EncoderClass := TPngNonInterlacedPalette1bitEncoder;
  876. 2 : EncoderClass := TPngNonInterlacedPalette2bitEncoder;
  877. 4 : EncoderClass := TPngNonInterlacedPalette4bitEncoder;
  878. 8 : EncoderClass := TPngNonInterlacedPalette8bitEncoder;
  879. else
  880. raise EPngError.Create(RCStrUnsupportedFormat);
  881. end;
  882. ctGrayscaleAlpha:
  883. EncoderClass := TPngNonInterlacedGrayscaleAlpha8bitEncoder;
  884. ctTrueColorAlpha:
  885. EncoderClass := TPngNonInterlacedTrueColorAlpha8bitEncoder;
  886. else
  887. raise EPngError.Create(RCStrUnsupportedFormat);
  888. end;
  889. DataStream := TMemoryStream.Create;
  890. try
  891. with EncoderClass.Create(DataStream, FImageHeader, FGammaChunk, FPaletteChunk) do
  892. try
  893. if (Assigned(FProgressEvent)) then
  894. EncodeFromScanline(TCustomBitmap32(Source), GR32ScanlineProgress)
  895. else
  896. EncodeFromScanline(TCustomBitmap32(Source), GR32Scanline);
  897. finally
  898. Free;
  899. end;
  900. // reset data stream position
  901. DataStream.Seek(0, soFromBeginning);
  902. // compress image data from data stream
  903. CompressImageDataFromStream(DataStream);
  904. finally
  905. DataStream.Free;
  906. end;
  907. end
  908. else
  909. inherited;
  910. end;
  911. procedure TPortableNetworkGraphic32.AssignTo(Dest: TPersistent);
  912. begin
  913. if Dest is TCustomBitmap32 then
  914. begin
  915. TCustomBitmap32(Dest).SetSize(ImageHeader.Width, ImageHeader.Height);
  916. DrawToBitmap32(TCustomBitmap32(Dest));
  917. end
  918. else
  919. inherited;
  920. end;
  921. const
  922. CRowStart: array [0..6] of Integer = (0, 0, 4, 0, 2, 0, 1);
  923. CColumnStart: array [0..6] of Integer = (0, 4, 0, 2, 0, 1, 0);
  924. CRowIncrement: array [0..6] of Integer = (8, 8, 8, 4, 4, 2, 2);
  925. CColumnIncrement: array [0..6] of Integer = (8, 8, 4, 4, 2, 2, 1);
  926. CGrayScaleTable1Bit: array [0..1] of Byte = (0, $FF);
  927. CGrayScaleTable2Bit: array [0..3] of Byte = (0, $55, $AA, $FF);
  928. CGrayScaleTable4Bit: array [0..15] of Byte = (0, $11, $22, $33, $44, $55,
  929. $66, $77, $88, $99, $AA, $BB, $CC, $DD, $EE, $FF);
  930. { TCustomPngNonInterlacedDecoder }
  931. constructor TCustomPngNonInterlacedDecoder.Create(Stream: TStream;
  932. Header: TChunkPngImageHeader; Gamma: TChunkPngGamma;
  933. Palette: TChunkPngPalette; Transparency: TCustomPngTransparency);
  934. begin
  935. inherited;
  936. FBytesPerRow := FHeader.BytesPerRow;
  937. FRowByteSize := FBytesPerRow + 1;
  938. GetMem(FRowBuffer[0], FRowByteSize);
  939. GetMem(FRowBuffer[1], FRowByteSize);
  940. end;
  941. destructor TCustomPngNonInterlacedDecoder.Destroy;
  942. begin
  943. Dispose(FRowBuffer[0]);
  944. Dispose(FRowBuffer[1]);
  945. inherited;
  946. end;
  947. procedure TCustomPngNonInterlacedDecoder.DecodeToScanline(
  948. Bitmap: TObject; ScanLineCallback: TScanLineCallback);
  949. var
  950. Index: Integer;
  951. CurrentRow: Integer;
  952. PixelByteSize: Integer;
  953. AdaptiveFilterMethod: TAdaptiveFilterMethod;
  954. UsedFilters: TAvailableAdaptiveFilterMethods;
  955. begin
  956. // initialize variables
  957. CurrentRow := 0;
  958. UsedFilters := [];
  959. PixelByteSize := FHeader.PixelByteSize;
  960. FillChar(FRowBuffer[1 - CurrentRow]^[0], FRowByteSize, 0);
  961. for Index := 0 to FHeader.Height - 1 do
  962. begin
  963. // read data from stream
  964. if FStream.Read(FRowBuffer[CurrentRow][0], FRowByteSize) <> FRowByteSize then
  965. raise EPngError.Create(RCStrDataIncomplete);
  966. // get active filter method
  967. AdaptiveFilterMethod := TAdaptiveFilterMethod(FRowBuffer[CurrentRow]^[0]);
  968. // filter current row
  969. DecodeFilterRow(AdaptiveFilterMethod, FRowBuffer[CurrentRow],
  970. FRowBuffer[1 - CurrentRow], FBytesPerRow, PixelByteSize);
  971. // log used row pre filters
  972. case AdaptiveFilterMethod of
  973. afmSub:
  974. UsedFilters := UsedFilters + [aafmSub];
  975. afmUp:
  976. UsedFilters := UsedFilters + [aafmUp];
  977. afmAverage:
  978. UsedFilters := UsedFilters + [aafmAverage];
  979. afmPaeth:
  980. UsedFilters := UsedFilters + [aafmPaeth];
  981. end;
  982. // transfer data from row to image
  983. TransferData(@FRowBuffer[CurrentRow][1], ScanLineCallback(Bitmap, Index));
  984. // flip current row
  985. CurrentRow := 1 - CurrentRow;
  986. end;
  987. FHeader.AdaptiveFilterMethods := UsedFilters;
  988. end;
  989. { TPngNonInterlacedGrayscale1bitDecoder }
  990. procedure TPngNonInterlacedGrayscale1bitDecoder.TransferData(Source: Pointer;
  991. Destination: PColor32);
  992. var
  993. Index: Integer;
  994. Src: PByte absolute Source;
  995. BitIndex: Byte;
  996. begin
  997. BitIndex := 8;
  998. for Index := 0 to FHeader.Width - 1 do
  999. begin
  1000. Dec(BitIndex);
  1001. PColor32Entry(Destination)^.R := FMappingTable[CGrayScaleTable1Bit[(Src^ shr BitIndex) and $1]];
  1002. PColor32Entry(Destination)^.G := PColor32Entry(Destination)^.R;
  1003. PColor32Entry(Destination)^.B := PColor32Entry(Destination)^.R;
  1004. PColor32Entry(Destination)^.A := 255;
  1005. if BitIndex = 0 then
  1006. begin
  1007. BitIndex := 8;
  1008. Inc(Src);
  1009. end;
  1010. Inc(Destination);
  1011. end;
  1012. end;
  1013. { TPngNonInterlacedGrayscale2bitDecoder }
  1014. procedure TPngNonInterlacedGrayscale2bitDecoder.TransferData(Source: Pointer;
  1015. Destination: PColor32);
  1016. var
  1017. Index: Integer;
  1018. Src: PByte absolute Source;
  1019. BitIndex: Byte;
  1020. begin
  1021. BitIndex := 8;
  1022. for Index := 0 to FHeader.Width - 1 do
  1023. begin
  1024. Dec(BitIndex, 2);
  1025. PColor32Entry(Destination)^.R := FMappingTable[CGrayScaleTable2Bit[(Src^ shr BitIndex) and $3]];
  1026. PColor32Entry(Destination)^.G := PColor32Entry(Destination)^.R;
  1027. PColor32Entry(Destination)^.B := PColor32Entry(Destination)^.R;
  1028. PColor32Entry(Destination)^.A := 255;
  1029. if BitIndex = 0 then
  1030. begin
  1031. BitIndex := 8;
  1032. Inc(Src);
  1033. end;
  1034. Inc(Destination);
  1035. end;
  1036. end;
  1037. { TPngNonInterlacedGrayscale4bitDecoder }
  1038. procedure TPngNonInterlacedGrayscale4bitDecoder.TransferData(Source: Pointer;
  1039. Destination: PColor32);
  1040. var
  1041. Index: Integer;
  1042. Src: PByte absolute Source;
  1043. BitIndex: Byte;
  1044. begin
  1045. BitIndex := 8;
  1046. for Index := 0 to FHeader.Width - 1 do
  1047. begin
  1048. Dec(BitIndex, 4);
  1049. PColor32Entry(Destination)^.R := FMappingTable[CGrayScaleTable4Bit[(Src^ shr BitIndex) and $F]];
  1050. PColor32Entry(Destination)^.G := PColor32Entry(Destination)^.R;
  1051. PColor32Entry(Destination)^.B := PColor32Entry(Destination)^.R;
  1052. PColor32Entry(Destination)^.A := 255;
  1053. if BitIndex = 0 then
  1054. begin
  1055. BitIndex := 8;
  1056. Inc(Src);
  1057. end;
  1058. Inc(Destination);
  1059. end;
  1060. end;
  1061. { TPngNonInterlacedGrayscale8bitDecoder }
  1062. procedure TPngNonInterlacedGrayscale8bitDecoder.TransferData(Source: Pointer;
  1063. Destination: PColor32);
  1064. var
  1065. Index: Integer;
  1066. Src: PByte absolute Source;
  1067. begin
  1068. for Index := 0 to FHeader.Width - 1 do
  1069. begin
  1070. PColor32Entry(Destination)^.R := FMappingTable[Src^];
  1071. PColor32Entry(Destination)^.G := PColor32Entry(Destination)^.R;
  1072. PColor32Entry(Destination)^.B := PColor32Entry(Destination)^.R;
  1073. PColor32Entry(Destination)^.A := 255;
  1074. Inc(Src);
  1075. Inc(Destination);
  1076. end;
  1077. end;
  1078. { TPngNonInterlacedGrayscale16bitDecoder }
  1079. procedure TPngNonInterlacedGrayscale16bitDecoder.TransferData(
  1080. Source: Pointer; Destination: PColor32);
  1081. var
  1082. Index: Integer;
  1083. Src: PWord absolute Source;
  1084. begin
  1085. for Index := 0 to FHeader.Width - 1 do
  1086. begin
  1087. PColor32Entry(Destination)^.R := FMappingTable[Src^ and $FF];
  1088. PColor32Entry(Destination)^.G := PColor32Entry(Destination)^.R;
  1089. PColor32Entry(Destination)^.B := PColor32Entry(Destination)^.R;
  1090. PColor32Entry(Destination)^.A := 255;
  1091. Inc(Src);
  1092. Inc(Destination);
  1093. end;
  1094. end;
  1095. { TPngNonInterlacedTrueColor8bitDecoder }
  1096. procedure TPngNonInterlacedTrueColor8bitDecoder.TransferData(Source: Pointer;
  1097. Destination: PColor32);
  1098. var
  1099. Index: Integer;
  1100. Src: PRGB24 absolute Source;
  1101. begin
  1102. for Index := 0 to FHeader.Width - 1 do
  1103. begin
  1104. PColor32Entry(Destination)^.R := FMappingTable[Src^.R];
  1105. PColor32Entry(Destination)^.G := FMappingTable[Src^.G];
  1106. PColor32Entry(Destination)^.B := FMappingTable[Src^.B];
  1107. PColor32Entry(Destination)^.A := 255;
  1108. Inc(Src);
  1109. Inc(Destination);
  1110. end;
  1111. end;
  1112. { TPngNonInterlacedTrueColor16bitDecoder }
  1113. procedure TPngNonInterlacedTrueColor16bitDecoder.TransferData(
  1114. Source: Pointer; Destination: PColor32);
  1115. var
  1116. Index: Integer;
  1117. Src: PRGB24Word absolute Source;
  1118. begin
  1119. for Index := 0 to FHeader.Width - 1 do
  1120. begin
  1121. PColor32Entry(Destination)^.R := FMappingTable[Src^.R and $FF];
  1122. PColor32Entry(Destination)^.G := FMappingTable[Src^.G and $FF];
  1123. PColor32Entry(Destination)^.B := FMappingTable[Src^.B and $FF];
  1124. PColor32Entry(Destination)^.A := 255;
  1125. Inc(Src);
  1126. Inc(Destination);
  1127. end;
  1128. end;
  1129. { TPngNonInterlacedPaletteDecoder }
  1130. procedure TPngNonInterlacedPaletteDecoder.TransferData(Source: Pointer;
  1131. Destination: PColor32);
  1132. var
  1133. Index: Integer;
  1134. Src: PByte absolute Source;
  1135. Palette: PRGB24Array;
  1136. Color: TRGB24;
  1137. BitIndex: Byte;
  1138. BitMask: Byte;
  1139. BitDepth: Byte;
  1140. begin
  1141. BitIndex := 8;
  1142. BitDepth := FHeader.BitDepth;
  1143. BitMask := (1 shl BitDepth) - 1;
  1144. Palette := PRGB24Array(FMappingTable);
  1145. for Index := 0 to FHeader.Width - 1 do
  1146. begin
  1147. Dec(BitIndex, BitDepth);
  1148. Color := Palette[(Src^ shr BitIndex) and BitMask];
  1149. PColor32Entry(Destination)^.R := Color.R;
  1150. PColor32Entry(Destination)^.G := Color.G;
  1151. PColor32Entry(Destination)^.B := Color.B;
  1152. PColor32Entry(Destination)^.A := FAlphaTable[(Src^ shr BitIndex) and BitMask];
  1153. if BitIndex = 0 then
  1154. begin
  1155. BitIndex := 8;
  1156. Inc(Src);
  1157. end;
  1158. Inc(Destination);
  1159. end;
  1160. end;
  1161. { TPngNonInterlacedPalette8bitDecoder }
  1162. procedure TPngNonInterlacedPalette8bitDecoder.TransferData(Source: Pointer;
  1163. Destination: PColor32);
  1164. var
  1165. Index: Integer;
  1166. Src: PByte absolute Source;
  1167. Palette: PRGB24Array;
  1168. begin
  1169. Palette := PRGB24Array(FMappingTable);
  1170. for Index := 0 to FHeader.Width - 1 do
  1171. begin
  1172. PColor32Entry(Destination)^.R := Palette[Src^].R;
  1173. PColor32Entry(Destination)^.G := Palette[Src^].G;
  1174. PColor32Entry(Destination)^.B := Palette[Src^].B;
  1175. PColor32Entry(Destination)^.A := FAlphaTable[Src^];
  1176. Inc(Src);
  1177. Inc(Destination);
  1178. end;
  1179. end;
  1180. { TPngNonInterlacedGrayscaleAlpha8bitDecoder }
  1181. procedure TPngNonInterlacedGrayscaleAlpha8bitDecoder.TransferData(
  1182. Source: Pointer; Destination: PColor32);
  1183. var
  1184. Index: Integer;
  1185. Src: PByte absolute Source;
  1186. begin
  1187. for Index := 0 to FHeader.Width - 1 do
  1188. begin
  1189. PColor32Entry(Destination)^.R := FMappingTable[Src^]; Inc(Src);
  1190. PColor32Entry(Destination)^.G := PColor32Entry(Destination)^.R;
  1191. PColor32Entry(Destination)^.B := PColor32Entry(Destination)^.R;
  1192. PColor32Entry(Destination)^.A := Src^; Inc(Src);
  1193. Inc(Destination);
  1194. end;
  1195. end;
  1196. { TPngNonInterlacedGrayscaleAlpha16bitDecoder }
  1197. procedure TPngNonInterlacedGrayscaleAlpha16bitDecoder.TransferData(
  1198. Source: Pointer; Destination: PColor32);
  1199. var
  1200. Index: Integer;
  1201. Src: PWord absolute Source;
  1202. begin
  1203. for Index := 0 to FHeader.Width - 1 do
  1204. begin
  1205. PColor32Entry(Destination)^.R := FMappingTable[Src^ and $FF]; Inc(Src);
  1206. PColor32Entry(Destination)^.G := PColor32Entry(Destination)^.R;
  1207. PColor32Entry(Destination)^.B := PColor32Entry(Destination)^.R;
  1208. PColor32Entry(Destination)^.A := Src^ and $FF; Inc(Src);
  1209. Inc(Destination);
  1210. end;
  1211. end;
  1212. { TPngNonInterlacedTrueColorAlpha8bitDecoder }
  1213. procedure ConvertColorNonInterlacedTrueColorAlpha8bit(Src: PRGB32;
  1214. Dst: PColor32Entry; Count: Integer; MappingTable: PByteArray);
  1215. {$IFDEF PUREPASCAL} inline;
  1216. var
  1217. Index: Integer;
  1218. begin
  1219. for Index := 0 to Count - 1 do
  1220. begin
  1221. Dst^.R := MappingTable[Src^.R];
  1222. Dst^.G := MappingTable[Src^.G];
  1223. Dst^.B := MappingTable[Src^.B];
  1224. Dst^.A := Src^.A;
  1225. Inc(Src);
  1226. Inc(Dst);
  1227. end;
  1228. {$ELSE}
  1229. asm
  1230. {$IFDEF Target_x64}
  1231. LEA RCX, [RCX + 4 * R8]
  1232. LEA RDX, [RDX + 4 * R8]
  1233. NEG R8
  1234. JNL @Done
  1235. @Start:
  1236. MOVZX R10, [RCX + 4 * R8].BYTE
  1237. MOVZX R10, [R9 + R10].BYTE
  1238. MOV [RDX + 4 * R8 + $02], R10B
  1239. MOVZX R10, [RCX + 4 * R8 + $01].BYTE
  1240. MOVZX R10, [R9 + R10].BYTE
  1241. MOV [RDX + 4 * R8 + $01], R10B
  1242. MOVZX R10,[RCX + 4 * R8 + $02].BYTE
  1243. MOVZX R10,[R9 + R10].BYTE
  1244. MOV [RDX + 4 * R8], R10B
  1245. MOVZX R10, [RCX + 4 * R8 + $03].BYTE
  1246. MOV [RDX + 4 * R8 + $03], R10B
  1247. ADD R8, 1
  1248. JS @Start
  1249. @Done:
  1250. {$ENDIF}
  1251. {$IFDEF Target_x86}
  1252. LEA EAX, [EAX + 4 * ECX]
  1253. LEA EDX, [EDX + 4 * ECX]
  1254. NEG ECX
  1255. JNL @Done
  1256. PUSH EBX
  1257. PUSH EDI
  1258. MOV EDI, MappingTable;
  1259. @Start:
  1260. MOVZX EBX, [EAX + 4 * ECX].BYTE
  1261. MOVZX EBX, [EDI + EBX].BYTE
  1262. MOV [EDX + 4 * ECX + $02], BL
  1263. MOVZX EBX, [EAX + 4 * ECX + $01].BYTE
  1264. MOVZX EBX, [EDI + EBX].BYTE
  1265. MOV [EDX + 4 * ECX + $01], BL
  1266. MOVZX EBX, [EAX + 4 * ECX + $02].BYTE
  1267. MOVZX EBX, [EDI + EBX].BYTE
  1268. MOV [EDX + 4 * ECX], BL
  1269. MOVZX EBX, [EAX + 4 * ECX + $03].BYTE
  1270. MOV [EDX + 4 * ECX + $03], BL
  1271. ADD ECX, 1
  1272. JS @Start
  1273. POP EDI
  1274. POP EBX
  1275. @Done:
  1276. {$ENDIF}
  1277. {$ENDIF}
  1278. end;
  1279. procedure TPngNonInterlacedTrueColorAlpha8bitDecoder.TransferData(
  1280. Source: Pointer; Destination: PColor32);
  1281. begin
  1282. ConvertColorNonInterlacedTrueColorAlpha8bit(PRGB32(Source),
  1283. PColor32Entry(Destination), FHeader.Width, FMappingTable);
  1284. end;
  1285. { TPngNonInterlacedTrueColorAlpha16bitDecoder }
  1286. procedure TPngNonInterlacedTrueColorAlpha16bitDecoder.TransferData(
  1287. Source: Pointer; Destination: PColor32);
  1288. var
  1289. Index: Integer;
  1290. Src: PRGB32Word absolute Source;
  1291. begin
  1292. for Index := 0 to FHeader.Width - 1 do
  1293. begin
  1294. PColor32Entry(Destination)^.R := FMappingTable[Src^.R and $FF];
  1295. PColor32Entry(Destination)^.G := FMappingTable[Src^.G and $FF];
  1296. PColor32Entry(Destination)^.B := FMappingTable[Src^.B and $FF];
  1297. PColor32Entry(Destination)^.A := Src^.A and $FF;
  1298. Inc(Src);
  1299. Inc(Destination);
  1300. end;
  1301. end;
  1302. { TCustomPngAdam7Decoder }
  1303. constructor TCustomPngAdam7Decoder.Create(Stream: TStream;
  1304. Header: TChunkPngImageHeader; Gamma: TChunkPngGamma;
  1305. Palette: TChunkPngPalette; Transparency: TCustomPngTransparency);
  1306. begin
  1307. inherited;
  1308. // allocate row buffer memory
  1309. GetMem(FRowBuffer[0], FHeader.BytesPerRow + 1);
  1310. GetMem(FRowBuffer[1], FHeader.BytesPerRow + 1);
  1311. end;
  1312. destructor TCustomPngAdam7Decoder.Destroy;
  1313. begin
  1314. Dispose(FRowBuffer[0]);
  1315. Dispose(FRowBuffer[1]);
  1316. inherited;
  1317. end;
  1318. procedure TCustomPngAdam7Decoder.DecodeToScanline(
  1319. Bitmap: TObject; ScanLineCallback: TScanLineCallback);
  1320. var
  1321. CurrentRow: Integer;
  1322. RowByteSize: Integer;
  1323. PixelPerRow: Integer;
  1324. PixelByteSize: Integer;
  1325. CurrentPass: Integer;
  1326. PassRow: Integer;
  1327. UsedFilters: TAvailableAdaptiveFilterMethods;
  1328. begin
  1329. // initialize variables
  1330. CurrentRow := 0;
  1331. UsedFilters := [];
  1332. PixelByteSize := FHeader.PixelByteSize;
  1333. // The Adam7 interlacer uses 7 passes to create the complete image
  1334. for CurrentPass := 0 to 6 do
  1335. begin
  1336. // calculate some intermediate variables
  1337. PixelPerRow := (FHeader.Width - CColumnStart[CurrentPass] + CColumnIncrement[CurrentPass] - 1) div CColumnIncrement[CurrentPass];
  1338. case FHeader.ColorType of
  1339. ctGrayscale, ctIndexedColor:
  1340. RowByteSize := (PixelPerRow * FHeader.BitDepth + 7) div 8;
  1341. ctTrueColor:
  1342. RowByteSize := (PixelPerRow * FHeader.BitDepth * 3) div 8;
  1343. ctGrayscaleAlpha:
  1344. RowByteSize := (PixelPerRow * FHeader.BitDepth * 2) div 8;
  1345. ctTrueColorAlpha:
  1346. RowByteSize := (PixelPerRow * FHeader.BitDepth * 4) div 8;
  1347. else
  1348. Continue;
  1349. end;
  1350. if RowByteSize = 0 then
  1351. Continue;
  1352. PassRow := CRowStart[CurrentPass];
  1353. // clear previous row
  1354. FillChar(FRowBuffer[1 - CurrentRow]^[0], RowByteSize, 0);
  1355. // process pixel
  1356. while PassRow < FHeader.Height do
  1357. begin
  1358. // get interlaced row data
  1359. if FStream.Read(FRowBuffer[CurrentRow][0], RowByteSize + 1) <> (RowByteSize + 1) then
  1360. raise EPngError.Create(RCStrDataIncomplete);
  1361. DecodeFilterRow(TAdaptiveFilterMethod(FRowBuffer[CurrentRow]^[0]), FRowBuffer[CurrentRow], FRowBuffer[1 - CurrentRow], RowByteSize, PixelByteSize);
  1362. // log used row pre filters
  1363. case TAdaptiveFilterMethod(FRowBuffer[CurrentRow]) of
  1364. afmSub:
  1365. UsedFilters := UsedFilters + [aafmSub];
  1366. afmUp:
  1367. UsedFilters := UsedFilters + [aafmUp];
  1368. afmAverage:
  1369. UsedFilters := UsedFilters + [aafmAverage];
  1370. afmPaeth:
  1371. UsedFilters := UsedFilters + [aafmPaeth];
  1372. end;
  1373. // transfer and deinterlace image data
  1374. TransferData(CurrentPass, @FRowBuffer[CurrentRow][1], ScanLineCallback(Bitmap, PassRow));
  1375. // prepare for the next pass
  1376. Inc(PassRow, CRowIncrement[CurrentPass]);
  1377. CurrentRow := 1 - CurrentRow;
  1378. end;
  1379. end;
  1380. FHeader.AdaptiveFilterMethods := UsedFilters;
  1381. end;
  1382. { TPngAdam7Grayscale1bitDecoder }
  1383. procedure TPngAdam7Grayscale1bitDecoder.TransferData(const Pass: Byte;
  1384. Source: Pointer; Destination: PColor32);
  1385. var
  1386. Index: Integer;
  1387. BitIndex: Integer;
  1388. Src: PByte absolute Source;
  1389. begin
  1390. Index := CColumnStart[Pass];
  1391. Inc(Destination, Index);
  1392. BitIndex := 8;
  1393. repeat
  1394. Dec(BitIndex);
  1395. PColor32Entry(Destination)^.R := FMappingTable[CGrayScaleTable1Bit[(Src^ shr BitIndex) and $1]];
  1396. PColor32Entry(Destination)^.G := PColor32Entry(Destination)^.R;
  1397. PColor32Entry(Destination)^.B := PColor32Entry(Destination)^.R;
  1398. PColor32Entry(Destination)^.A := 255;
  1399. if BitIndex = 0 then
  1400. begin
  1401. BitIndex := 8;
  1402. Inc(Src);
  1403. end;
  1404. Inc(Destination, CColumnIncrement[Pass]);
  1405. Inc(Index, CColumnIncrement[Pass]);
  1406. until Index >= FHeader.Width;
  1407. end;
  1408. { TPngAdam7Grayscale2bitDecoder }
  1409. procedure TPngAdam7Grayscale2bitDecoder.TransferData(const Pass: Byte;
  1410. Source: Pointer; Destination: PColor32);
  1411. var
  1412. Index: Integer;
  1413. BitIndex: Integer;
  1414. Src: PByte absolute Source;
  1415. begin
  1416. Index := CColumnStart[Pass];
  1417. Inc(Destination, Index);
  1418. BitIndex := 8;
  1419. repeat
  1420. Dec(BitIndex, 2);
  1421. PColor32Entry(Destination)^.R := FMappingTable[CGrayScaleTable2Bit[((Src^ shr BitIndex) and $3)]];
  1422. PColor32Entry(Destination)^.G := PColor32Entry(Destination)^.R;
  1423. PColor32Entry(Destination)^.B := PColor32Entry(Destination)^.R;
  1424. PColor32Entry(Destination)^.A := 255;
  1425. if BitIndex = 0 then
  1426. begin
  1427. BitIndex := 8;
  1428. Inc(Src);
  1429. end;
  1430. Inc(Destination, CColumnIncrement[Pass]);
  1431. Inc(Index, CColumnIncrement[Pass]);
  1432. until Index >= FHeader.Width;
  1433. end;
  1434. { TPngAdam7Grayscale4bitDecoder }
  1435. procedure TPngAdam7Grayscale4bitDecoder.TransferData(const Pass: Byte;
  1436. Source: Pointer; Destination: PColor32);
  1437. var
  1438. Index: Integer;
  1439. BitIndex: Integer;
  1440. Src: PByte absolute Source;
  1441. begin
  1442. Index := CColumnStart[Pass];
  1443. Inc(Destination, Index);
  1444. BitIndex := 8;
  1445. repeat
  1446. Dec(BitIndex, 4);
  1447. PColor32Entry(Destination)^.R := FMappingTable[CGrayScaleTable4Bit[((Src^ shr BitIndex) and $F)]];
  1448. PColor32Entry(Destination)^.G := PColor32Entry(Destination)^.R;
  1449. PColor32Entry(Destination)^.B := PColor32Entry(Destination)^.R;
  1450. PColor32Entry(Destination)^.A := 255;
  1451. if BitIndex = 0 then
  1452. begin
  1453. BitIndex := 8;
  1454. Inc(Src);
  1455. end;
  1456. Inc(Destination, CColumnIncrement[Pass]);
  1457. Inc(Index, CColumnIncrement[Pass]);
  1458. until Index >= FHeader.Width;
  1459. end;
  1460. { TPngAdam7Grayscale8bitDecoder }
  1461. procedure TPngAdam7Grayscale8bitDecoder.TransferData(const Pass: Byte;
  1462. Source: Pointer; Destination: PColor32);
  1463. var
  1464. Index: Integer;
  1465. Src: PByte absolute Source;
  1466. begin
  1467. Index := CColumnStart[Pass];
  1468. Inc(Destination, Index);
  1469. repeat
  1470. PColor32Entry(Destination)^.R := FMappingTable[Src^]; Inc(Src);
  1471. PColor32Entry(Destination)^.G := PColor32Entry(Destination)^.R;
  1472. PColor32Entry(Destination)^.B := PColor32Entry(Destination)^.R;
  1473. PColor32Entry(Destination)^.A := 255;
  1474. Inc(Destination, CColumnIncrement[Pass]);
  1475. Inc(Index, CColumnIncrement[Pass]);
  1476. until Index >= FHeader.Width;
  1477. end;
  1478. { TPngAdam7Grayscale16bitDecoder }
  1479. procedure TPngAdam7Grayscale16bitDecoder.TransferData(const Pass: Byte;
  1480. Source: Pointer; Destination: PColor32);
  1481. var
  1482. Index: Integer;
  1483. Src: PWord absolute Source;
  1484. begin
  1485. Index := CColumnStart[Pass];
  1486. Inc(Destination, Index);
  1487. repeat
  1488. PColor32Entry(Destination)^.R := FMappingTable[Src^ and $FF]; Inc(Src);
  1489. PColor32Entry(Destination)^.G := PColor32Entry(Destination)^.R;
  1490. PColor32Entry(Destination)^.B := PColor32Entry(Destination)^.R;
  1491. PColor32Entry(Destination)^.A := 255;
  1492. Inc(Destination, CColumnIncrement[Pass]);
  1493. Inc(Index, CColumnIncrement[Pass]);
  1494. until Index >= FHeader.Width;
  1495. end;
  1496. { TPngAdam7TrueColor8bitDecoder }
  1497. procedure TPngAdam7TrueColor8bitDecoder.TransferData(const Pass: Byte;
  1498. Source: Pointer; Destination: PColor32);
  1499. var
  1500. Index: Integer;
  1501. Src: PRGB24 absolute Source;
  1502. begin
  1503. Index := CColumnStart[Pass];
  1504. Inc(Destination, Index);
  1505. repeat
  1506. PColor32Entry(Destination)^.R := FMappingTable[Src^.R];
  1507. PColor32Entry(Destination)^.G := FMappingTable[Src^.G];
  1508. PColor32Entry(Destination)^.B := FMappingTable[Src^.B];
  1509. PColor32Entry(Destination)^.A := 255;
  1510. Inc(Src);
  1511. Inc(Destination, CColumnIncrement[Pass]);
  1512. Inc(Index, CColumnIncrement[Pass]);
  1513. until Index >= FHeader.Width;
  1514. end;
  1515. { TPngAdam7TrueColor16bitDecoder }
  1516. procedure TPngAdam7TrueColor16bitDecoder.TransferData(const Pass: Byte;
  1517. Source: Pointer; Destination: PColor32);
  1518. var
  1519. Index: Integer;
  1520. Src: PRGB24Word absolute Source;
  1521. begin
  1522. Index := CColumnStart[Pass];
  1523. Inc(Destination, Index);
  1524. repeat
  1525. PColor32Entry(Destination)^.R := FMappingTable[Src^.R and $FF];
  1526. PColor32Entry(Destination)^.G := FMappingTable[Src^.G and $FF];
  1527. PColor32Entry(Destination)^.B := FMappingTable[Src^.B and $FF];
  1528. PColor32Entry(Destination)^.A := 255;
  1529. Inc(Src);
  1530. Inc(Destination, CColumnIncrement[Pass]);
  1531. Inc(Index, CColumnIncrement[Pass]);
  1532. until Index >= FHeader.Width;
  1533. end;
  1534. { TPngAdam7Palette1bitDecoder }
  1535. procedure TPngAdam7Palette1bitDecoder.TransferData(const Pass: Byte;
  1536. Source: Pointer; Destination: PColor32);
  1537. var
  1538. Index: Integer;
  1539. BitIndex: Integer;
  1540. Src: PByte absolute Source;
  1541. Palette: PRGB24Array;
  1542. Color: TRGB24;
  1543. begin
  1544. BitIndex := 8;
  1545. Palette := PRGB24Array(FMappingTable);
  1546. Index := CColumnStart[Pass];
  1547. Inc(Destination, Index);
  1548. repeat
  1549. Dec(BitIndex);
  1550. Color := Palette[(Src^ shr BitIndex) and $1];
  1551. PColor32Entry(Destination)^.R := Color.R;
  1552. PColor32Entry(Destination)^.G := Color.G;
  1553. PColor32Entry(Destination)^.B := Color.B;
  1554. PColor32Entry(Destination)^.A := FAlphaTable[(Src^ shr BitIndex) and $1];
  1555. if BitIndex = 0 then
  1556. begin
  1557. BitIndex := 8;
  1558. Inc(Src);
  1559. end;
  1560. Inc(Destination, CColumnIncrement[Pass]);
  1561. Inc(Index, CColumnIncrement[Pass]);
  1562. until Index >= FHeader.Width;
  1563. end;
  1564. { TPngAdam7Palette2bitDecoder }
  1565. procedure TPngAdam7Palette2bitDecoder.TransferData(const Pass: Byte;
  1566. Source: Pointer; Destination: PColor32);
  1567. var
  1568. Index: Integer;
  1569. BitIndex: Integer;
  1570. Src: PByte absolute Source;
  1571. Palette: PRGB24Array;
  1572. Color: TRGB24;
  1573. begin
  1574. BitIndex := 8;
  1575. Palette := PRGB24Array(FMappingTable);
  1576. Index := CColumnStart[Pass];
  1577. Inc(Destination, Index);
  1578. repeat
  1579. Dec(BitIndex, 2);
  1580. Color := Palette[(Src^ shr BitIndex) and $3];
  1581. PColor32Entry(Destination)^.R := Color.R;
  1582. PColor32Entry(Destination)^.G := Color.G;
  1583. PColor32Entry(Destination)^.B := Color.B;
  1584. PColor32Entry(Destination)^.A := FAlphaTable[(Src^ shr BitIndex) and $3];
  1585. if BitIndex = 0 then
  1586. begin
  1587. BitIndex := 8;
  1588. Inc(Src);
  1589. end;
  1590. Inc(Destination, CColumnIncrement[Pass]);
  1591. Inc(Index, CColumnIncrement[Pass]);
  1592. until Index >= FHeader.Width;
  1593. end;
  1594. { TPngAdam7Palette4bitDecoder }
  1595. procedure TPngAdam7Palette4bitDecoder.TransferData(const Pass: Byte;
  1596. Source: Pointer; Destination: PColor32);
  1597. var
  1598. Index: Integer;
  1599. BitIndex: Integer;
  1600. Src: PByte absolute Source;
  1601. Palette: PRGB24Array;
  1602. Color: TRGB24;
  1603. begin
  1604. BitIndex := 8;
  1605. Palette := PRGB24Array(FMappingTable);
  1606. Index := CColumnStart[Pass];
  1607. Inc(Destination, Index);
  1608. repeat
  1609. Dec(BitIndex, 4);
  1610. Color := Palette[(Src^ shr BitIndex) and $F];
  1611. PColor32Entry(Destination)^.R := Color.R;
  1612. PColor32Entry(Destination)^.G := Color.G;
  1613. PColor32Entry(Destination)^.B := Color.B;
  1614. PColor32Entry(Destination)^.A := FAlphaTable[(Src^ shr BitIndex) and $F];
  1615. if BitIndex = 0 then
  1616. begin
  1617. BitIndex := 8;
  1618. Inc(Src);
  1619. end;
  1620. Inc(Destination, CColumnIncrement[Pass]);
  1621. Inc(Index, CColumnIncrement[Pass]);
  1622. until Index >= FHeader.Width;
  1623. end;
  1624. { TPngAdam7Palette8bitDecoder }
  1625. procedure TPngAdam7Palette8bitDecoder.TransferData(const Pass: Byte;
  1626. Source: Pointer; Destination: PColor32);
  1627. var
  1628. Index: Integer;
  1629. Src: PByte absolute Source;
  1630. Palette: PRGB24Array;
  1631. begin
  1632. Palette := PRGB24Array(FMappingTable);
  1633. Index := CColumnStart[Pass];
  1634. Inc(Destination, Index);
  1635. repeat
  1636. PColor32Entry(Destination)^.R := Palette[Src^].R;
  1637. PColor32Entry(Destination)^.G := Palette[Src^].G;
  1638. PColor32Entry(Destination)^.B := Palette[Src^].B;
  1639. PColor32Entry(Destination)^.A := FAlphaTable[Src^];
  1640. Inc(Src);
  1641. Inc(Destination, CColumnIncrement[Pass]);
  1642. Inc(Index, CColumnIncrement[Pass]);
  1643. until Index >= FHeader.Width;
  1644. end;
  1645. { TPngAdam7GrayscaleAlpha8bitDecoder }
  1646. procedure TPngAdam7GrayscaleAlpha8bitDecoder.TransferData(const Pass: Byte;
  1647. Source: Pointer; Destination: PColor32);
  1648. var
  1649. Index: Integer;
  1650. Src: PByte absolute Source;
  1651. begin
  1652. Index := CColumnStart[Pass];
  1653. Inc(Destination, Index);
  1654. repeat
  1655. PColor32Entry(Destination)^.R := FMappingTable[Src^]; Inc(Src);
  1656. PColor32Entry(Destination)^.G := PColor32Entry(Destination)^.R;
  1657. PColor32Entry(Destination)^.B := PColor32Entry(Destination)^.R;
  1658. PColor32Entry(Destination)^.A := Src^; Inc(Src);
  1659. Inc(Destination, CColumnIncrement[Pass]);
  1660. Inc(Index, CColumnIncrement[Pass]);
  1661. until Index >= FHeader.Width;
  1662. end;
  1663. { TPngAdam7GrayscaleAlpha16bitDecoder }
  1664. procedure TPngAdam7GrayscaleAlpha16bitDecoder.TransferData(const Pass: Byte;
  1665. Source: Pointer; Destination: PColor32);
  1666. var
  1667. Index: Integer;
  1668. Src: PWord absolute Source;
  1669. begin
  1670. Index := CColumnStart[Pass];
  1671. Inc(Destination, Index);
  1672. repeat
  1673. PColor32Entry(Destination)^.R := FMappingTable[Src^ and $FF]; Inc(Src);
  1674. PColor32Entry(Destination)^.G := PColor32Entry(Destination)^.R;
  1675. PColor32Entry(Destination)^.B := PColor32Entry(Destination)^.R;
  1676. PColor32Entry(Destination)^.A := Src^ and $FF; Inc(Src);
  1677. Inc(Destination, CColumnIncrement[Pass]);
  1678. Inc(Index, CColumnIncrement[Pass]);
  1679. until Index >= FHeader.Width;
  1680. end;
  1681. { TPngAdam7TrueColorAlpha8bitDecoder }
  1682. procedure TPngAdam7TrueColorAlpha8bitDecoder.TransferData(const Pass: Byte;
  1683. Source: Pointer; Destination: PColor32);
  1684. var
  1685. Index: Integer;
  1686. SrcPtr: PRGB32 absolute Source;
  1687. begin
  1688. Index := CColumnStart[Pass];
  1689. Inc(Destination, Index);
  1690. repeat
  1691. PColor32Entry(Destination)^.R := FMappingTable[SrcPtr^.R];
  1692. PColor32Entry(Destination)^.G := FMappingTable[SrcPtr^.G];
  1693. PColor32Entry(Destination)^.B := FMappingTable[SrcPtr^.B];
  1694. PColor32Entry(Destination)^.A := SrcPtr^.A;
  1695. Inc(SrcPtr);
  1696. Inc(Destination, CColumnIncrement[Pass]);
  1697. Inc(Index, CColumnIncrement[Pass]);
  1698. until Index >= FHeader.Width;
  1699. end;
  1700. { TPngAdam7TrueColorAlpha16bitDecoder }
  1701. procedure TPngAdam7TrueColorAlpha16bitDecoder.TransferData(const Pass: Byte;
  1702. Source: Pointer; Destination: PColor32);
  1703. var
  1704. Index: Integer;
  1705. SrcPtr: PRGB32Word absolute Source;
  1706. begin
  1707. Index := CColumnStart[Pass];
  1708. Inc(Destination, Index);
  1709. repeat
  1710. PColor32Entry(Destination)^.R := FMappingTable[SrcPtr^.R and $FF];
  1711. PColor32Entry(Destination)^.G := FMappingTable[SrcPtr^.G and $FF];
  1712. PColor32Entry(Destination)^.B := FMappingTable[SrcPtr^.B and $FF];
  1713. PColor32Entry(Destination)^.A := SrcPtr^.A and $FF;
  1714. Inc(SrcPtr);
  1715. Inc(Destination, CColumnIncrement[Pass]);
  1716. Inc(Index, CColumnIncrement[Pass]);
  1717. until Index >= FHeader.Width;
  1718. end;
  1719. { TCustomPngNonInterlacedEncoder }
  1720. constructor TCustomPngNonInterlacedEncoder.Create(Stream: TStream;
  1721. Header: TChunkPngImageHeader; Gamma: TChunkPngGamma;
  1722. Palette: TChunkPngPalette; Transparency: TCustomPngTransparency);
  1723. begin
  1724. inherited;
  1725. FBytesPerRow := FHeader.BytesPerRow;
  1726. FRowByteSize := FBytesPerRow + 1;
  1727. GetMem(FRowBuffer[0], FRowByteSize);
  1728. GetMem(FRowBuffer[1], FRowByteSize);
  1729. end;
  1730. destructor TCustomPngNonInterlacedEncoder.Destroy;
  1731. begin
  1732. Dispose(FRowBuffer[0]);
  1733. Dispose(FRowBuffer[1]);
  1734. inherited;
  1735. end;
  1736. function TCustomPngNonInterlacedEncoder.ColorInPalette(
  1737. Color: TColor32): Integer;
  1738. var
  1739. Color24: TRGB24;
  1740. begin
  1741. for Result := 0 to FPalette.Count - 1 do
  1742. begin
  1743. Color24 := FPalette.PaletteEntry[Result];
  1744. if (TColor32Entry(Color).R = Color24.R) and
  1745. (TColor32Entry(Color).G = Color24.G) and
  1746. (TColor32Entry(Color).B = Color24.B) then
  1747. Exit;
  1748. end;
  1749. Result := -1;
  1750. end;
  1751. procedure TCustomPngNonInterlacedEncoder.EncodeFromScanline(Bitmap: TObject;
  1752. ScanLineCallback: TScanLineCallback);
  1753. var
  1754. Index: Integer;
  1755. CurrentRow: Integer;
  1756. OutputRow: PByteArray;
  1757. TempBuffer: PByteArray;
  1758. begin
  1759. // initialize variables
  1760. CurrentRow := 0;
  1761. FillChar(FRowBuffer[1 - CurrentRow]^[0], FRowByteSize, 0);
  1762. // check if pre filter is used and eventually calculate pre filter
  1763. if FHeader.ColorType <> ctIndexedColor then
  1764. begin
  1765. Assert(FRowByteSize = FBytesPerRow + 1);
  1766. GetMem(OutputRow, FRowByteSize);
  1767. GetMem(TempBuffer, FRowByteSize);
  1768. try
  1769. for Index := 0 to FHeader.Height - 1 do
  1770. begin
  1771. // transfer data from image to current row
  1772. TransferData(ScanLineCallback(Bitmap, Index), @FRowBuffer[CurrentRow][1]);
  1773. // filter current row
  1774. EncodeFilterRow(FRowBuffer[CurrentRow], FRowBuffer[1 - CurrentRow],
  1775. OutputRow, TempBuffer, FBytesPerRow, FHeader.PixelByteSize);
  1776. Assert(OutputRow[0] in [0..4]);
  1777. // write data to data stream
  1778. FStream.Write(OutputRow[0], FRowByteSize);
  1779. // flip current row used
  1780. CurrentRow := 1 - CurrentRow;
  1781. end;
  1782. finally
  1783. Dispose(OutputRow);
  1784. Dispose(TempBuffer);
  1785. end;
  1786. end
  1787. else
  1788. for Index := 0 to FHeader.Height - 1 do
  1789. begin
  1790. // transfer data from image to current row
  1791. TransferData(ScanLineCallback(Bitmap, Index), @FRowBuffer[CurrentRow][1]);
  1792. // set filter method to none
  1793. FRowBuffer[CurrentRow][0] := 0;
  1794. // write data to data stream
  1795. FStream.Write(FRowBuffer[CurrentRow][0], FRowByteSize);
  1796. // flip current row used
  1797. CurrentRow := 1 - CurrentRow;
  1798. end;
  1799. end;
  1800. { TPngNonInterlacedGrayscale1bitEncoder }
  1801. procedure TPngNonInterlacedGrayscale1bitEncoder.TransferData(Source: PColor32;
  1802. Destination: Pointer);
  1803. var
  1804. Index: Integer;
  1805. Dest: PByte absolute Destination;
  1806. BitIndex: Byte;
  1807. begin
  1808. BitIndex := 8;
  1809. for Index := 0 to FHeader.Width - 1 do
  1810. begin
  1811. Dec(BitIndex);
  1812. Dest^ := (Dest^ and not ($1 shl BitIndex)) or
  1813. (((PColor32Entry(Source)^.R shr 7) and $1) shl BitIndex);
  1814. if BitIndex = 0 then
  1815. begin
  1816. BitIndex := 8;
  1817. Inc(Dest);
  1818. end;
  1819. Inc(Source);
  1820. end;
  1821. end;
  1822. { TPngNonInterlacedGrayscale2bitEncoder }
  1823. procedure TPngNonInterlacedGrayscale2bitEncoder.TransferData(Source: PColor32;
  1824. Destination: Pointer);
  1825. var
  1826. Index: Integer;
  1827. Dest: PByte absolute Destination;
  1828. BitIndex: Byte;
  1829. begin
  1830. BitIndex := 8;
  1831. for Index := 0 to FHeader.Width - 1 do
  1832. begin
  1833. Dec(BitIndex, 2);
  1834. Dest^ := (Dest^ and not ($3 shl BitIndex)) or
  1835. (((PColor32Entry(Source)^.R shr 6) and $3) shl BitIndex);
  1836. if BitIndex = 0 then
  1837. begin
  1838. BitIndex := 8;
  1839. Inc(Dest);
  1840. end;
  1841. Inc(Source);
  1842. end;
  1843. end;
  1844. { TPngNonInterlacedGrayscale4bitEncoder }
  1845. procedure TPngNonInterlacedGrayscale4bitEncoder.TransferData(Source: PColor32;
  1846. Destination: Pointer);
  1847. var
  1848. Index: Integer;
  1849. Dest: PByte absolute Destination;
  1850. BitIndex: Byte;
  1851. begin
  1852. BitIndex := 8;
  1853. for Index := 0 to FHeader.Width - 1 do
  1854. begin
  1855. Dec(BitIndex, 4);
  1856. Dest^ := (Dest^ and not ($F shl BitIndex)) or
  1857. (((PColor32Entry(Source)^.R shr 4) and $F) shl BitIndex);
  1858. if BitIndex = 0 then
  1859. begin
  1860. BitIndex := 8;
  1861. Inc(Dest);
  1862. end;
  1863. Inc(Source);
  1864. end;
  1865. end;
  1866. { TPngNonInterlacedGrayscale8bitEncoder }
  1867. procedure TPngNonInterlacedGrayscale8bitEncoder.TransferData(Source: PColor32;
  1868. Destination: Pointer);
  1869. var
  1870. Index: Integer;
  1871. Dest: PByte absolute Destination;
  1872. begin
  1873. for Index := 0 to FHeader.Width - 1 do
  1874. begin
  1875. Dest^ := PColor32Entry(Source)^.R;
  1876. Inc(Source);
  1877. Inc(Dest);
  1878. end;
  1879. end;
  1880. { TPngNonInterlacedTrueColor8bitEncoder }
  1881. procedure TPngNonInterlacedTrueColor8bitEncoder.TransferData(Source: PColor32;
  1882. Destination: Pointer);
  1883. var
  1884. Index: Integer;
  1885. Dest: PRGB24 absolute Destination;
  1886. begin
  1887. for Index := 0 to FHeader.Width - 1 do
  1888. begin
  1889. Dest^.R := PColor32Entry(Source)^.R;
  1890. Dest^.G := PColor32Entry(Source)^.G ;
  1891. Dest^.B := PColor32Entry(Source)^.B;
  1892. Inc(Source);
  1893. Inc(Dest);
  1894. end;
  1895. end;
  1896. { TPngNonInterlacedPalette1bitEncoder }
  1897. procedure TPngNonInterlacedPalette1bitEncoder.TransferData(Source: PColor32;
  1898. Destination: Pointer);
  1899. var
  1900. Index: Integer;
  1901. Dest: PByte absolute Destination;
  1902. BitIndex: Byte;
  1903. begin
  1904. BitIndex := 8;
  1905. for Index := 0 to FHeader.Width - 1 do
  1906. begin
  1907. Dec(BitIndex);
  1908. Dest^ := (Dest^ and not ($1 shl BitIndex)) or
  1909. ((ColorInPalette(Source^) and $1) shl BitIndex);
  1910. if BitIndex = 0 then
  1911. begin
  1912. BitIndex := 8;
  1913. Inc(Dest);
  1914. end;
  1915. Inc(Source);
  1916. end;
  1917. end;
  1918. { TPngNonInterlacedPalette2bitEncoder }
  1919. procedure TPngNonInterlacedPalette2bitEncoder.TransferData(Source: PColor32;
  1920. Destination: Pointer);
  1921. var
  1922. Index: Integer;
  1923. Dest: PByte absolute Destination;
  1924. BitIndex: Byte;
  1925. begin
  1926. BitIndex := 8;
  1927. for Index := 0 to FHeader.Width - 1 do
  1928. begin
  1929. Dec(BitIndex, 2);
  1930. Dest^ := (Dest^ and not ($3 shl BitIndex)) or
  1931. ((ColorInPalette(Source^) and $3) shl BitIndex);
  1932. if BitIndex = 0 then
  1933. begin
  1934. BitIndex := 8;
  1935. Inc(Dest);
  1936. end;
  1937. Inc(Source);
  1938. end;
  1939. end;
  1940. { TPngNonInterlacedPalette4bitEncoder }
  1941. procedure TPngNonInterlacedPalette4bitEncoder.TransferData(Source: PColor32;
  1942. Destination: Pointer);
  1943. var
  1944. Index: Integer;
  1945. Dest: PByte absolute Destination;
  1946. BitIndex: Byte;
  1947. begin
  1948. BitIndex := 8;
  1949. for Index := 0 to FHeader.Width - 1 do
  1950. begin
  1951. Dec(BitIndex, 4);
  1952. Dest^ := (Dest^ and not ($F shl BitIndex)) or
  1953. ((ColorInPalette(Source^) and $F) shl BitIndex);
  1954. if BitIndex = 0 then
  1955. begin
  1956. BitIndex := 8;
  1957. Inc(Dest);
  1958. end;
  1959. Inc(Source);
  1960. end;
  1961. end;
  1962. { TPngNonInterlacedPalette8bitEncoder }
  1963. procedure TPngNonInterlacedPalette8bitEncoder.TransferData(Source: PColor32;
  1964. Destination: Pointer);
  1965. var
  1966. Index: Integer;
  1967. Dest: PByte absolute Destination;
  1968. begin
  1969. for Index := 0 to FHeader.Width - 1 do
  1970. begin
  1971. Dest^ := ColorInPalette(Source^);
  1972. Inc(Source);
  1973. Inc(Dest);
  1974. end;
  1975. end;
  1976. { TPngNonInterlacedGrayscaleAlpha8bitEncoder }
  1977. procedure TPngNonInterlacedGrayscaleAlpha8bitEncoder.TransferData(Source: PColor32;
  1978. Destination: Pointer);
  1979. var
  1980. Index: Integer;
  1981. Dest: PByte absolute Destination;
  1982. begin
  1983. for Index := 0 to FHeader.Width - 1 do
  1984. begin
  1985. Dest^ := PColor32Entry(Source)^.R; Inc(Dest);
  1986. Dest^ := PColor32Entry(Source)^.A; Inc(Dest);
  1987. Inc(Source);
  1988. end;
  1989. end;
  1990. { TPngNonInterlacedTrueColorAlpha8bitEncoder }
  1991. procedure TPngNonInterlacedTrueColorAlpha8bitEncoder.TransferData(Source: PColor32;
  1992. Destination: Pointer);
  1993. var
  1994. Index: Integer;
  1995. Dest: PRGB32 absolute Destination;
  1996. begin
  1997. for Index := 0 to FHeader.Width - 1 do
  1998. begin
  1999. Dest^.R := PColor32Entry(Source)^.R;
  2000. Dest^.G := PColor32Entry(Source)^.G;
  2001. Dest^.B := PColor32Entry(Source)^.B;
  2002. Dest^.A := PColor32Entry(Source)^.A;
  2003. Inc(Dest);
  2004. Inc(Source);
  2005. end;
  2006. end;
  2007. { TPngPalette }
  2008. function TPngPalette.Add(const Item: TColor32): Integer;
  2009. begin
  2010. Find(Item, Result{%H-});
  2011. InsertItem(Result, Item);
  2012. end;
  2013. procedure TPngPalette.Clear;
  2014. begin
  2015. SetLength(FItems, 0);
  2016. FCount := 0;
  2017. end;
  2018. function TPngPalette.Compare(const item1, item2: TColor32): Integer;
  2019. begin
  2020. Result := item1 - item2;
  2021. end;
  2022. function TPngPalette.Find(const item: TColor32; var index: Integer): Boolean;
  2023. var
  2024. lo, hi, mid, compResult: Integer;
  2025. begin
  2026. Result := False;
  2027. lo := 0;
  2028. hi := FCount - 1;
  2029. while lo <= hi do
  2030. begin
  2031. mid := (lo + hi) shr 1;
  2032. compResult := Compare(FItems[mid], item);
  2033. if compResult < 0 then
  2034. lo := mid + 1
  2035. else
  2036. begin
  2037. hi := mid - 1;
  2038. if compResult = 0 then
  2039. Result:=True;
  2040. end;
  2041. end;
  2042. index := lo;
  2043. end;
  2044. function TPngPalette.GetItem(index: Integer): TColor32;
  2045. begin
  2046. Result := FItems[index];
  2047. end;
  2048. procedure TPngPalette.GetNearest(var Value: TColor32);
  2049. var
  2050. Index, MinIndex: Integer;
  2051. Distance, MinDistance: Integer;
  2052. begin
  2053. if IndexOf(Value) < 0 then
  2054. begin
  2055. MinDistance :=
  2056. Sqr(TColor32Entry(Value).R - TColor32Entry(FItems[0]).R) +
  2057. Sqr(TColor32Entry(Value).G - TColor32Entry(FItems[0]).G) +
  2058. Sqr(TColor32Entry(Value).B - TColor32Entry(FItems[0]).B);
  2059. MinIndex := 0;
  2060. for Index := 1 to Count - 1 do
  2061. begin
  2062. Distance :=
  2063. Sqr(TColor32Entry(Value).R - TColor32Entry(FItems[Index]).R) +
  2064. Sqr(TColor32Entry(Value).G - TColor32Entry(FItems[Index]).G) +
  2065. Sqr(TColor32Entry(Value).B - TColor32Entry(FItems[Index]).B);
  2066. if Distance < MinDistance then
  2067. begin
  2068. MinDistance := Distance;
  2069. MinIndex := Index;
  2070. end;
  2071. end;
  2072. Value := FItems[MinIndex];
  2073. end;
  2074. end;
  2075. function TPngPalette.IndexOf(const Value: TColor32): Integer;
  2076. begin
  2077. if not Find(Value, Result{%H-}) then
  2078. Result := -1;
  2079. end;
  2080. procedure TPngPalette.InsertItem(index: Integer; const anItem: TColor32);
  2081. begin
  2082. if Count = Length(FItems) then
  2083. SetLength(FItems, Count + 8 + (Count shr 4));
  2084. if index < Count then
  2085. System.Move(FItems[Index], FItems[Index + 1], (Count - Index) * SizeOf(TColor32));
  2086. Inc(FCount);
  2087. FItems[index] := anItem;
  2088. end;
  2089. procedure TPngPalette.LimitTo(Count: Integer);
  2090. begin
  2091. SetLength(FItems, Count);
  2092. FCount := Count;
  2093. end;
  2094. procedure TPngPalette.Remove(Index: Integer);
  2095. var
  2096. n: Integer;
  2097. begin
  2098. Dec(FCount);
  2099. n := FCount - index;
  2100. if n > 0 then
  2101. System.Move(FItems[Index + 1], FItems[Index], n * SizeOf(TColor32));
  2102. SetLength(FItems, FCount);
  2103. end;
  2104. { TPngHistogramEntry }
  2105. constructor TPngHistogramEntry.Create(Key: TColor32);
  2106. begin
  2107. FColor := Key;
  2108. end;
  2109. procedure TPngHistogramEntry.Advance;
  2110. begin
  2111. Inc(FCount);
  2112. end;
  2113. { TPngHistogram }
  2114. function TPngHistogram.GetItem(index: Integer): TPngHistogramEntry;
  2115. begin
  2116. Result := FItems[index];
  2117. end;
  2118. function TPngHistogram.Find(const item: TColor32; var index: Integer): Boolean;
  2119. var
  2120. lo, hi, mid, compResult: Integer;
  2121. begin
  2122. Result := False;
  2123. lo := 0;
  2124. hi := FCount - 1;
  2125. while lo <= hi do
  2126. begin
  2127. mid := (lo + hi) shr 1;
  2128. compResult := Compare(FItems[mid].Color, item);
  2129. if compResult < 0 then
  2130. lo := mid + 1
  2131. else
  2132. begin
  2133. hi := mid - 1;
  2134. if compResult = 0 then
  2135. Result:=True;
  2136. end;
  2137. end;
  2138. index := lo;
  2139. end;
  2140. procedure TPngHistogram.InsertItem(index: Integer; const anItem: TPngHistogramEntry);
  2141. begin
  2142. if Count = Length(FItems) then
  2143. SetLength(FItems, Count + 8 + (Count shr 4));
  2144. if index < Count then
  2145. System.Move(FItems[index], FItems[index+1], (Count-index)*SizeOf(Pointer));
  2146. Inc(FCount);
  2147. FItems[index] := anItem;
  2148. end;
  2149. function TPngHistogram.Add(Value: TColor32): Integer;
  2150. begin
  2151. Result := Add(TPngHistogramEntry.Create(Value));
  2152. end;
  2153. function TPngHistogram.Add(const anItem: TPngHistogramEntry): Integer;
  2154. begin
  2155. Find(anItem.Color, Result{%H-});
  2156. InsertItem(Result, anItem);
  2157. end;
  2158. procedure TPngHistogram.Advance(Value: TColor32);
  2159. var
  2160. Index: Integer;
  2161. begin
  2162. Index := IndexOf(Value);
  2163. if Index < 0 then
  2164. Add(Value)
  2165. else
  2166. FItems[Index].Advance;
  2167. end;
  2168. function TPngHistogram.IndexOf(const Value: TColor32): Integer;
  2169. begin
  2170. if not Find(Value, Result{%H-}) then
  2171. Result := -1;
  2172. end;
  2173. procedure TPngHistogram.Remove(Index: Integer);
  2174. var
  2175. n: Integer;
  2176. begin
  2177. Dec(FCount);
  2178. n := FCount - index;
  2179. if n > 0 then
  2180. System.Move(FItems[Index + 1], FItems[Index], n * SizeOf(TPngHistogramEntry));
  2181. SetLength(FItems, FCount);
  2182. end;
  2183. function TPngHistogram.GetPalette(MaxColors: Integer = 256): TPngPalette;
  2184. var
  2185. PaletteIndex, Index, LastIndex: Integer;
  2186. ColorCount: Integer;
  2187. begin
  2188. Result := TPngPalette.Create;
  2189. for PaletteIndex := 0 to Min(Count, MaxColors) - 1 do
  2190. begin
  2191. ColorCount := FItems[0].Count;
  2192. LastIndex := 0;
  2193. for Index := 1 to FCount - 1 do
  2194. begin
  2195. if (FItems[Index].Count > ColorCount) then
  2196. begin
  2197. LastIndex := Index;
  2198. ColorCount := FItems[Index].Count;
  2199. end;
  2200. end;
  2201. Result.Add(FItems[LastIndex].FColor);
  2202. Remove(LastIndex);
  2203. end;
  2204. end;
  2205. procedure TPngHistogram.Clear;
  2206. begin
  2207. SetLength(FItems, 0);
  2208. FCount := 0;
  2209. end;
  2210. function TPngHistogram.Compare(const item1, item2: TColor32): Integer;
  2211. begin
  2212. Result := item1 - item2;
  2213. end;
  2214. procedure TPngHistogram.Clean;
  2215. var
  2216. i: Integer;
  2217. begin
  2218. for i := 0 to FCount - 1 do
  2219. FItems[i].Free;
  2220. Clear;
  2221. end;
  2222. end.