GR32_Png.pas 72 KB

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