ImagingFormats.pas 118 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726
  1. {
  2. $Id: ImagingFormats.pas,v 1.22 2006/10/26 13:29:28 galfar Exp $
  3. Vampyre Imaging Library
  4. by Marek Mauder ([email protected])
  5. http://imaginglib.sourceforge.net
  6. The contents of this file are used with permission, subject to the Mozilla
  7. Public License Version 1.1 (the "License"); you may not use this file except
  8. in compliance with the License. You may obtain a copy of the License at
  9. http://www.mozilla.org/MPL/MPL-1.1.html
  10. Software distributed under the License is distributed on an "AS IS" basis,
  11. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
  12. the specific language governing rights and limitations under the License.
  13. Alternatively, the contents of this file may be used under the terms of the
  14. GNU Lesser General Public License (the "LGPL License"), in which case the
  15. provisions of the LGPL License are applicable instead of those above.
  16. If you wish to allow use of your version of this file only under the terms
  17. of the LGPL License and not to allow others to use your version of this file
  18. under the MPL, indicate your decision by deleting the provisions above and
  19. replace them with the notice and other provisions required by the LGPL
  20. License. If you do not delete the provisions above, a recipient may use
  21. your version of this file under either the MPL or the LGPL License.
  22. For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
  23. }
  24. { This unit manages information about all image data formats and contains
  25. low level format conversion, manipulation, and other related functions.}
  26. unit ImagingFormats;
  27. {$I ImagingOptions.inc}
  28. interface
  29. uses
  30. ImagingTypes, Imaging, ImagingUtility;
  31. type
  32. TImageFormatInfoArray = array[TImageFormat] of PImageFormatInfo;
  33. PImageFormatInfoArray = ^TImageFormatInfoArray;
  34. { Additional image manipulation functions (usually used internally by Imaging unit) }
  35. type
  36. { Color reduction operations.}
  37. TReduceColorsAction = (raCreateHistogram, raUpdateHistogram, raMakeColorMap,
  38. raMapImage);
  39. TReduceColorsActions = set of TReduceColorsAction;
  40. const
  41. AllReduceColorsActions = [raCreateHistogram, raUpdateHistogram,
  42. raMakeColorMap, raMapImage];
  43. { Reduces the number of colors of source. Src is bits of source image
  44. (ARGB or floating point) and Dst is in some indexed format. MaxColors
  45. is the number of colors to which reduce and DstPal is palette to which
  46. the resulting colors are written and it must be allocated to at least
  47. MaxColors entries. ChannelMask is 'anded' with every pixel's channel value
  48. when creating color histogram. If $FF is used all 8bits of color channels
  49. are used which can be slow for large images with many colors so you can
  50. use lower masks to speed it up.}
  51. procedure ReduceColorsMedianCut(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  52. DstInfo: PImageFormatInfo; MaxColors: LongInt; ChannelMask: Byte;
  53. DstPal: PPalette32; Actions: TReduceColorsActions = AllReduceColorsActions);
  54. { Stretches rectangle in source image to rectangle in destination image
  55. using nearest neighbor filtering. It is fast but results look blocky
  56. because there is no interpolation used. SrcImage and DstImage must be
  57. in the same data format. Works for all data formats except special formats.}
  58. procedure StretchNearest(const SrcImage: TImageData; SrcX, SrcY, SrcWidth,
  59. SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth,
  60. DstHeight: LongInt);
  61. type
  62. { Built-in sampling filters.}
  63. TSamplingFilter = (sfNearest, sfLinear, sfCosine, sfHermite, sfQuadratic,
  64. sfGaussian, sfSpline, sfLanczos, sfMitchell, sfCatmullRom);
  65. { Type of custom sampling function}
  66. TFilterFunction = function(Value: Single): Single;
  67. { Stretches rectangle in source image to rectangle in destination image
  68. with resampling. One of built-in resampling filters defined by
  69. Filter is used. Set WrapEdges to True for seamlessly tileable images.
  70. SrcImage and DstImage must be in the same data format.
  71. Works for all data formats except special and indexed formats.}
  72. procedure StretchResample(const SrcImage: TImageData; SrcX, SrcY, SrcWidth,
  73. SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth,
  74. DstHeight: LongInt; Filter: TSamplingFilter; WrapEdges: Boolean = False); overload;
  75. { Stretches rectangle in source image to rectangle in destination image
  76. with resampling. You can use custom sampling function and filter radius.
  77. Set WrapEdges to True for seamlessly tileable images. SrcImage and DstImage
  78. must be in the same data format.
  79. Works for all data formats except special and indexed formats.}
  80. procedure StretchResample(const SrcImage: TImageData; SrcX, SrcY, SrcWidth,
  81. SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth,
  82. DstHeight: LongInt; Filter: TFilterFunction; Radius: Single;
  83. WrapEdges: Boolean = False); overload;
  84. { Helper for functions that create mipmap levels. BiggerLevel is
  85. valid image and SmallerLevel is empty zeroed image. SmallerLevel is created
  86. with Width and Height dimensions and it is filled with pixels of BiggerLevel
  87. using resampling filter specified by ImagingMipMapFilter option.
  88. Uses StretchNearest and StretchResample internally so the same image data format
  89. limitations apply.}
  90. procedure FillMipMapLevel(const BiggerLevel: TImageData; Width, Height: LongInt;
  91. var SmallerLevel: TImageData);
  92. { Various helper format support functions }
  93. { Copies Src pixel to Dest pixel. It is faster than System.Move procedure.}
  94. procedure CopyPixel(Src, Dest: Pointer; BytesPerPixel: LongInt); {$IFDEF USE_INLINE}inline;{$ENDIF}
  95. { Compares Src pixel and Dest pixel. It is faster than SysUtils.CompareMem function.}
  96. function ComparePixels(PixelA, PixelB: Pointer; BytesPerPixel: LongInt): Boolean; {$IFDEF USE_INLINE}inline;{$ENDIF}
  97. { Translates pixel color in SrcFormat to DstFormat.}
  98. procedure TranslatePixel(SrcPixel, DstPixel: Pointer; SrcFormat,
  99. DstFormat: TImageFormat; SrcPalette, DstPalette: PPalette32);
  100. { Clamps floating point pixel channel values to [0.0, 1.0] range.}
  101. procedure ClampFloatPixel(var PixF: TColorFPRec); {$IFDEF USE_INLINE}inline;{$ENDIF}
  102. { Adds padding bytes at the ends of scanlines. Bpp is the number of bytes per
  103. pixel of source and WidthBytes is the number of bytes per scanlines of dest.}
  104. procedure AddPadBytes(DataIn: Pointer; DataOut: Pointer; Width, Height,
  105. Bpp, WidthBytes: LongInt);
  106. { Removes padding from image with scanlines that have aligned sizes. Bpp is
  107. the number of bytes per pixel of dest and WidthBytes is the number of bytes
  108. per scanlines of source.}
  109. procedure RemovePadBytes(DataIn: Pointer; DataOut: Pointer; Width, Height,
  110. Bpp, WidthBytes: LongInt);
  111. { Helper function for image file loaders. Some 15 bit images (targas, bitmaps)
  112. may contain 1 bit alpha but there is no indication of it. This function checks
  113. all 16 bit(shoul be X1R5G5B5 or A1R5G5B5 format) pixels and some of them have
  114. alpha bit set it returns True, otherwise False.}
  115. function Has16BitImageAlpha(NumPixels: LongInt; Data: PWord): Boolean;
  116. { Provides indexed access to each line of pixels. Does not work with special
  117. format images.}
  118. function GetScanLine(ImageBits: Pointer; const FormatInfo: TImageFormatInfo;
  119. LineWidth, Index: LongInt): Pointer; {$IFDEF USE_INLINE}inline;{$ENDIF}
  120. { Returns True if Format is valid image data format identifier.}
  121. function IsImageFormatValid(Format: TImageFormat): Boolean;
  122. { Converts 16bit half floating point value to 32bit Single.}
  123. function HalfToFloat(Half: THalfFloat): Single;
  124. { Converts 32bit Single to 16bit half floating point.}
  125. function FloatToHalf(Float: Single): THalfFloat;
  126. { Converts half float color value to single-precision floating point color.}
  127. function ColorHalfToFloat(ColorHF: TColorHFRec): TColorFPRec; {$IFDEF USE_INLINE}inline;{$ENDIF}
  128. { Converts single-precision floating point color to half float color.}
  129. function ColorFloatToHalf(ColorFP: TColorFPRec): TColorHFRec; {$IFDEF USE_INLINE}inline;{$ENDIF}
  130. { Pixel readers/writers for different image formats }
  131. { Returns pixel of image in any ARGB format. Channel values are scaled to 16 bits.}
  132. procedure ChannelGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo;
  133. var Pix: TColor64Rec);
  134. { Sets pixel of image in any ARGB format. Channel values must be scaled to 16 bits.}
  135. procedure ChannelSetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo;
  136. const Pix: TColor64Rec);
  137. { Returns pixel of image in any grayscale format. Gray value is scaled to 64 bits
  138. and alpha to 16 bits.}
  139. procedure GrayGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo;
  140. var Gray: TColor64Rec; var Alpha: Word);
  141. { Sets pixel of image in any grayscale format. Gray value must be scaled to 64 bits
  142. and alpha to 16 bits.}
  143. procedure GraySetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo;
  144. const Gray: TColor64Rec; Alpha: Word);
  145. { Returns pixel of image in any floating point format. Channel values are
  146. in range <0.0, 1.0>.}
  147. procedure FloatGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo;
  148. var Pix: TColorFPRec);
  149. { Sets pixel of image in any floating point format. Channel values must be
  150. in range <0.0, 1.0>.}
  151. procedure FloatSetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo;
  152. const Pix: TColorFPRec);
  153. { Returns pixel of image in any indexed format. Returned value is index to
  154. the palette.}
  155. procedure IndexGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo;
  156. var Index: LongWord);
  157. { Sets pixel of image in any indexed format. Index is index to the palette.}
  158. procedure IndexSetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo;
  159. Index: LongWord);
  160. { Pixel readers/writers for 32bit and FP colors}
  161. { Function for getting pixel colors. Native pixel is read from Image and
  162. then translated to 32 bit ARGB.}
  163. function GetPixel32Generic(Bits: Pointer; Info: PImageFormatInfo;
  164. Palette: PPalette32): TColor32Rec;
  165. { Procedure for setting pixel colors. Input 32 bit ARGB color is translated to
  166. native format and then written to Image.}
  167. procedure SetPixel32Generic(Bits: Pointer; Info: PImageFormatInfo;
  168. Palette: PPalette32; const Color: TColor32Rec);
  169. { Function for getting pixel colors. Native pixel is read from Image and
  170. then translated to FP ARGB.}
  171. function GetPixelFPGeneric(Bits: Pointer; Info: PImageFormatInfo;
  172. Palette: PPalette32): TColorFPRec;
  173. { Procedure for setting pixel colors. Input FP ARGB color is translated to
  174. native format and then written to Image.}
  175. procedure SetPixelFPGeneric(Bits: Pointer; Info: PImageFormatInfo;
  176. Palette: PPalette32; const Color: TColorFPRec);
  177. { Image format conversion functions }
  178. { Converts any ARGB format to any ARGB format.}
  179. procedure ChannelToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  180. DstInfo: PImageFormatInfo);
  181. { Converts any ARGB format to any grayscale format.}
  182. procedure ChannelToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  183. DstInfo: PImageFormatInfo);
  184. { Converts any ARGB format to any floating point format.}
  185. procedure ChannelToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  186. DstInfo: PImageFormatInfo);
  187. { Converts any ARGB format to any indexed format.}
  188. procedure ChannelToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  189. DstInfo: PImageFormatInfo; DstPal: PPalette32);
  190. { Converts any grayscale format to any grayscale format.}
  191. procedure GrayToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  192. DstInfo: PImageFormatInfo);
  193. { Converts any grayscale format to any ARGB format.}
  194. procedure GrayToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  195. DstInfo: PImageFormatInfo);
  196. { Converts any grayscale format to any floating point format.}
  197. procedure GrayToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  198. DstInfo: PImageFormatInfo);
  199. { Converts any grayscale format to any indexed format.}
  200. procedure GrayToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  201. DstInfo: PImageFormatInfo; DstPal: PPalette32);
  202. { Converts any floating point format to any floating point format.}
  203. procedure FloatToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  204. DstInfo: PImageFormatInfo);
  205. { Converts any floating point format to any ARGB format.}
  206. procedure FloatToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  207. DstInfo: PImageFormatInfo);
  208. { Converts any floating point format to any grayscale format.}
  209. procedure FloatToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  210. DstInfo: PImageFormatInfo);
  211. { Converts any floating point format to any indexed format.}
  212. procedure FloatToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  213. DstInfo: PImageFormatInfo; DstPal: PPalette32);
  214. { Converts any indexed format to any indexed format.}
  215. procedure IndexToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  216. DstInfo: PImageFormatInfo; SrcPal, DstPal: PPalette32);
  217. { Converts any indexed format to any ARGB format.}
  218. procedure IndexToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  219. DstInfo: PImageFormatInfo; SrcPal: PPalette32);
  220. { Converts any indexed format to any grayscale format.}
  221. procedure IndexToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  222. DstInfo: PImageFormatInfo; SrcPal: PPalette32);
  223. { Converts any indexed format to any floating point format.}
  224. procedure IndexToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  225. DstInfo: PImageFormatInfo; SrcPal: PPalette32);
  226. { Special formats conversion functions }
  227. { Converts image to/from/between special image formats (dxtc, ...).}
  228. procedure ConvertSpecial(var Image: TImageData; SrcInfo,
  229. DstInfo: PImageFormatInfo);
  230. { Inits all image format information. Called internally on startup.}
  231. procedure InitImageFormats(var Infos: TImageFormatInfoArray);
  232. implementation
  233. { TImageFormatInfo member functions }
  234. { Returns size in bytes of image in given standard format where
  235. Size = Width * Height * Bpp.}
  236. function GetStdPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; forward;
  237. { Checks if Width and Height are valid for given standard format.}
  238. procedure CheckStdDimensions(Format: TImageFormat; var Width, Height: LongInt); forward;
  239. { Returns size in bytes of image in given DXT format.}
  240. function GetDXTPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; forward;
  241. { Checks if Width and Height are valid for given DXT format. If they are
  242. not valid, they are changed to pass the check.}
  243. procedure CheckDXTDimensions(Format: TImageFormat; var Width, Height: LongInt); forward;
  244. { Optimized pixel readers/writers for 32bit and FP colors to be stored in TImageFormatInfo }
  245. function GetPixel32ifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColor32Rec; forward;
  246. procedure SetPixel32ifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColor32Rec); forward;
  247. function GetPixelFPifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec; forward;
  248. procedure SetPixelFPifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec); forward;
  249. function GetPixel32Channel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColor32Rec; forward;
  250. procedure SetPixel32Channel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColor32Rec); forward;
  251. function GetPixelFPChannel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec; forward;
  252. procedure SetPixelFPChannel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec); forward;
  253. function GetPixelFPFloat32(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec; forward;
  254. procedure SetPixelFPFloat32(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec); forward;
  255. const
  256. // grayscale conversion channel weights
  257. GrayConv: TColorFPRec = (B: 0.114; G: 0.587; R: 0.299; A: 0.0);
  258. // contants for converting integer colors to floating point
  259. OneDiv8Bit: Single = 1.0 / 255.0;
  260. OneDiv16Bit: Single = 1.0 / 65535.0;
  261. var
  262. PFR3G3B2: TPixelFormatInfo;
  263. PFX5R1G1B1: TPixelFormatInfo;
  264. PFR5G6B5: TPixelFormatInfo;
  265. PFA1R5G5B5: TPixelFormatInfo;
  266. PFA4R4G4B4: TPixelFormatInfo;
  267. PFX1R5G5B5: TPixelFormatInfo;
  268. PFX4R4G4B4: TPixelFormatInfo;
  269. FInfos: PImageFormatInfoArray;
  270. var
  271. // Free Pascal generates hundreds of warnings here
  272. {$WARNINGS OFF}
  273. // indexed formats
  274. Index8Info: TImageFormatInfo = (
  275. Format: ifIndex8;
  276. Name: 'Index8';
  277. BytesPerPixel: 1;
  278. ChannelCount: 1;
  279. PaletteEntries: 256;
  280. IsIndexed: True;
  281. GetPixelsSize: GetStdPixelsSize;
  282. CheckDimensions: CheckStdDimensions;
  283. GetPixel32: GetPixel32Generic;
  284. GetPixelFP: GetPixelFPGeneric;
  285. SetPixel32: SetPixel32Generic;
  286. SetPixelFP: SetPixelFPGeneric);
  287. // grayscale formats
  288. Gray8Info: TImageFormatInfo = (
  289. Format: ifGray8;
  290. Name: 'Gray8';
  291. BytesPerPixel: 1;
  292. ChannelCount: 1;
  293. HasGrayChannel: True;
  294. GetPixelsSize: GetStdPixelsSize;
  295. CheckDimensions: CheckStdDimensions;
  296. GetPixel32: GetPixel32Channel8Bit;
  297. GetPixelFP: GetPixelFPChannel8Bit;
  298. SetPixel32: SetPixel32Channel8Bit;
  299. SetPixelFP: SetPixelFPChannel8Bit);
  300. A8Gray8Info: TImageFormatInfo = (
  301. Format: ifA8Gray8;
  302. Name: 'A8Gray8';
  303. BytesPerPixel: 2;
  304. ChannelCount: 2;
  305. HasGrayChannel: True;
  306. HasAlphaChannel: True;
  307. GetPixelsSize: GetStdPixelsSize;
  308. CheckDimensions: CheckStdDimensions;
  309. GetPixel32: GetPixel32Channel8Bit;
  310. GetPixelFP: GetPixelFPChannel8Bit;
  311. SetPixel32: SetPixel32Channel8Bit;
  312. SetPixelFP: SetPixelFPChannel8Bit);
  313. Gray16Info: TImageFormatInfo = (
  314. Format: ifGray16;
  315. Name: 'Gray16';
  316. BytesPerPixel: 2;
  317. ChannelCount: 1;
  318. HasGrayChannel: True;
  319. GetPixelsSize: GetStdPixelsSize;
  320. CheckDimensions: CheckStdDimensions;
  321. GetPixel32: GetPixel32Generic;
  322. GetPixelFP: GetPixelFPGeneric;
  323. SetPixel32: SetPixel32Generic;
  324. SetPixelFP: SetPixelFPGeneric);
  325. Gray32Info: TImageFormatInfo = (
  326. Format: ifGray32;
  327. Name: 'Gray32';
  328. BytesPerPixel: 4;
  329. ChannelCount: 1;
  330. HasGrayChannel: True;
  331. GetPixelsSize: GetStdPixelsSize;
  332. CheckDimensions: CheckStdDimensions;
  333. GetPixel32: GetPixel32Generic;
  334. GetPixelFP: GetPixelFPGeneric;
  335. SetPixel32: SetPixel32Generic;
  336. SetPixelFP: SetPixelFPGeneric);
  337. Gray64Info: TImageFormatInfo = (
  338. Format: ifGray64;
  339. Name: 'Gray64';
  340. BytesPerPixel: 8;
  341. ChannelCount: 1;
  342. HasGrayChannel: True;
  343. GetPixelsSize: GetStdPixelsSize;
  344. CheckDimensions: CheckStdDimensions;
  345. GetPixel32: GetPixel32Generic;
  346. GetPixelFP: GetPixelFPGeneric;
  347. SetPixel32: SetPixel32Generic;
  348. SetPixelFP: SetPixelFPGeneric);
  349. A16Gray16Info: TImageFormatInfo = (
  350. Format: ifA16Gray16;
  351. Name: 'A16Gray16';
  352. BytesPerPixel: 4;
  353. ChannelCount: 2;
  354. HasGrayChannel: True;
  355. HasAlphaChannel: True;
  356. GetPixelsSize: GetStdPixelsSize;
  357. CheckDimensions: CheckStdDimensions;
  358. GetPixel32: GetPixel32Generic;
  359. GetPixelFP: GetPixelFPGeneric;
  360. SetPixel32: SetPixel32Generic;
  361. SetPixelFP: SetPixelFPGeneric);
  362. // ARGB formats
  363. X5R1G1B1Info: TImageFormatInfo = (
  364. Format: ifX5R1G1B1;
  365. Name: 'X5R1G1B1';
  366. BytesPerPixel: 1;
  367. ChannelCount: 3;
  368. UsePixelFormat: True;
  369. PixelFormat: @PFX5R1G1B1;
  370. GetPixelsSize: GetStdPixelsSize;
  371. CheckDimensions: CheckStdDimensions;
  372. GetPixel32: GetPixel32Generic;
  373. GetPixelFP: GetPixelFPGeneric;
  374. SetPixel32: SetPixel32Generic;
  375. SetPixelFP: SetPixelFPGeneric);
  376. R3G3B2Info: TImageFormatInfo = (
  377. Format: ifR3G3B2;
  378. Name: 'R3G3B2';
  379. BytesPerPixel: 1;
  380. ChannelCount: 3;
  381. UsePixelFormat: True;
  382. PixelFormat: @PFR3G3B2;
  383. GetPixelsSize: GetStdPixelsSize;
  384. CheckDimensions: CheckStdDimensions;
  385. GetPixel32: GetPixel32Generic;
  386. GetPixelFP: GetPixelFPGeneric;
  387. SetPixel32: SetPixel32Generic;
  388. SetPixelFP: SetPixelFPGeneric);
  389. R5G6B5Info: TImageFormatInfo = (
  390. Format: ifR5G6B5;
  391. Name: 'R5G6B5';
  392. BytesPerPixel: 2;
  393. ChannelCount: 3;
  394. UsePixelFormat: True;
  395. PixelFormat: @PFR5G6B5;
  396. GetPixelsSize: GetStdPixelsSize;
  397. CheckDimensions: CheckStdDimensions;
  398. GetPixel32: GetPixel32Generic;
  399. GetPixelFP: GetPixelFPGeneric;
  400. SetPixel32: SetPixel32Generic;
  401. SetPixelFP: SetPixelFPGeneric);
  402. A1R5G5B5Info: TImageFormatInfo = (
  403. Format: ifA1R5G5B5;
  404. Name: 'A1R5G5B5';
  405. BytesPerPixel: 2;
  406. ChannelCount: 4;
  407. HasAlphaChannel: True;
  408. UsePixelFormat: True;
  409. PixelFormat: @PFA1R5G5B5;
  410. GetPixelsSize: GetStdPixelsSize;
  411. CheckDimensions: CheckStdDimensions;
  412. GetPixel32: GetPixel32Generic;
  413. GetPixelFP: GetPixelFPGeneric;
  414. SetPixel32: SetPixel32Generic;
  415. SetPixelFP: SetPixelFPGeneric);
  416. A4R4G4B4Info: TImageFormatInfo = (
  417. Format: ifA4R4G4B4;
  418. Name: 'A4R4G4B4';
  419. BytesPerPixel: 2;
  420. ChannelCount: 4;
  421. HasAlphaChannel: True;
  422. UsePixelFormat: True;
  423. PixelFormat: @PFA4R4G4B4;
  424. GetPixelsSize: GetStdPixelsSize;
  425. CheckDimensions: CheckStdDimensions;
  426. GetPixel32: GetPixel32Generic;
  427. GetPixelFP: GetPixelFPGeneric;
  428. SetPixel32: SetPixel32Generic;
  429. SetPixelFP: SetPixelFPGeneric);
  430. X1R5G5B5Info: TImageFormatInfo = (
  431. Format: ifX1R5G5B5;
  432. Name: 'X1R5G5B5';
  433. BytesPerPixel: 2;
  434. ChannelCount: 3;
  435. UsePixelFormat: True;
  436. PixelFormat: @PFX1R5G5B5;
  437. GetPixelsSize: GetStdPixelsSize;
  438. CheckDimensions: CheckStdDimensions;
  439. GetPixel32: GetPixel32Generic;
  440. GetPixelFP: GetPixelFPGeneric;
  441. SetPixel32: SetPixel32Generic;
  442. SetPixelFP: SetPixelFPGeneric);
  443. X4R4G4B4Info: TImageFormatInfo = (
  444. Format: ifX4R4G4B4;
  445. Name: 'X4R4G4B4';
  446. BytesPerPixel: 2;
  447. ChannelCount: 3;
  448. UsePixelFormat: True;
  449. PixelFormat: @PFX4R4G4B4;
  450. GetPixelsSize: GetStdPixelsSize;
  451. CheckDimensions: CheckStdDimensions;
  452. GetPixel32: GetPixel32Generic;
  453. GetPixelFP: GetPixelFPGeneric;
  454. SetPixel32: SetPixel32Generic;
  455. SetPixelFP: SetPixelFPGeneric);
  456. R8G8B8Info: TImageFormatInfo = (
  457. Format: ifR8G8B8;
  458. Name: 'R8G8B8';
  459. BytesPerPixel: 3;
  460. ChannelCount: 3;
  461. GetPixelsSize: GetStdPixelsSize;
  462. CheckDimensions: CheckStdDimensions;
  463. GetPixel32: GetPixel32Channel8Bit;
  464. GetPixelFP: GetPixelFPChannel8Bit;
  465. SetPixel32: SetPixel32Channel8Bit;
  466. SetPixelFP: SetPixelFPChannel8Bit);
  467. A8R8G8B8Info: TImageFormatInfo = (
  468. Format: ifA8R8G8B8;
  469. Name: 'A8R8G8B8';
  470. BytesPerPixel: 4;
  471. ChannelCount: 4;
  472. HasAlphaChannel: True;
  473. GetPixelsSize: GetStdPixelsSize;
  474. CheckDimensions: CheckStdDimensions;
  475. GetPixel32: GetPixel32ifA8R8G8B8;
  476. GetPixelFP: GetPixelFPifA8R8G8B8;
  477. SetPixel32: SetPixel32ifA8R8G8B8;
  478. SetPixelFP: SetPixelFPifA8R8G8B8);
  479. X8R8G8B8Info: TImageFormatInfo = (
  480. Format: ifX8R8G8B8;
  481. Name: 'X8R8G8B8';
  482. BytesPerPixel: 4;
  483. ChannelCount: 3;
  484. GetPixelsSize: GetStdPixelsSize;
  485. CheckDimensions: CheckStdDimensions;
  486. GetPixel32: GetPixel32Channel8Bit;
  487. GetPixelFP: GetPixelFPChannel8Bit;
  488. SetPixel32: SetPixel32Channel8Bit;
  489. SetPixelFP: SetPixelFPChannel8Bit);
  490. R16G16B16Info: TImageFormatInfo = (
  491. Format: ifR16G16B16;
  492. Name: 'R16G16B16';
  493. BytesPerPixel: 6;
  494. ChannelCount: 3;
  495. RBSwapFormat: ifB16G16R16;
  496. GetPixelsSize: GetStdPixelsSize;
  497. CheckDimensions: CheckStdDimensions;
  498. GetPixel32: GetPixel32Generic;
  499. GetPixelFP: GetPixelFPGeneric;
  500. SetPixel32: SetPixel32Generic;
  501. SetPixelFP: SetPixelFPGeneric);
  502. A16R16G16B16Info: TImageFormatInfo = (
  503. Format: ifA16R16G16B16;
  504. Name: 'A16R16G16B16';
  505. BytesPerPixel: 8;
  506. ChannelCount: 4;
  507. HasAlphaChannel: True;
  508. RBSwapFormat: ifA16B16G16R16;
  509. GetPixelsSize: GetStdPixelsSize;
  510. CheckDimensions: CheckStdDimensions;
  511. GetPixel32: GetPixel32Generic;
  512. GetPixelFP: GetPixelFPGeneric;
  513. SetPixel32: SetPixel32Generic;
  514. SetPixelFP: SetPixelFPGeneric);
  515. B16G16R16Info: TImageFormatInfo = (
  516. Format: ifB16G16R16;
  517. Name: 'B16G16R16';
  518. BytesPerPixel: 6;
  519. ChannelCount: 3;
  520. IsRBSwapped: True;
  521. RBSwapFormat: ifR16G16B16;
  522. GetPixelsSize: GetStdPixelsSize;
  523. CheckDimensions: CheckStdDimensions;
  524. GetPixel32: GetPixel32Generic;
  525. GetPixelFP: GetPixelFPGeneric;
  526. SetPixel32: SetPixel32Generic;
  527. SetPixelFP: SetPixelFPGeneric);
  528. A16B16G16R16Info: TImageFormatInfo = (
  529. Format: ifA16B16G16R16;
  530. Name: 'A16B16G16R16';
  531. BytesPerPixel: 8;
  532. ChannelCount: 4;
  533. HasAlphaChannel: True;
  534. IsRBSwapped: True;
  535. RBSwapFormat: ifA16R16G16B16;
  536. GetPixelsSize: GetStdPixelsSize;
  537. CheckDimensions: CheckStdDimensions;
  538. GetPixel32: GetPixel32Generic;
  539. GetPixelFP: GetPixelFPGeneric;
  540. SetPixel32: SetPixel32Generic;
  541. SetPixelFP: SetPixelFPGeneric);
  542. // floating point formats
  543. R32FInfo: TImageFormatInfo = (
  544. Format: ifR32F;
  545. Name: 'R32F';
  546. BytesPerPixel: 4;
  547. ChannelCount: 1;
  548. IsFloatingPoint: True;
  549. GetPixelsSize: GetStdPixelsSize;
  550. CheckDimensions: CheckStdDimensions;
  551. GetPixel32: GetPixel32Generic;
  552. GetPixelFP: GetPixelFPFloat32;
  553. SetPixel32: SetPixel32Generic;
  554. SetPixelFP: SetPixelFPFloat32);
  555. A32R32G32B32FInfo: TImageFormatInfo = (
  556. Format: ifA32R32G32B32F;
  557. Name: 'A32R32G32B32F';
  558. BytesPerPixel: 16;
  559. ChannelCount: 4;
  560. HasAlphaChannel: True;
  561. IsFloatingPoint: True;
  562. RBSwapFormat: ifA32B32G32R32F;
  563. GetPixelsSize: GetStdPixelsSize;
  564. CheckDimensions: CheckStdDimensions;
  565. GetPixel32: GetPixel32Generic;
  566. GetPixelFP: GetPixelFPFloat32;
  567. SetPixel32: SetPixel32Generic;
  568. SetPixelFP: SetPixelFPFloat32);
  569. A32B32G32R32FInfo: TImageFormatInfo = (
  570. Format: ifA32B32G32R32F;
  571. Name: 'A32B32G32R32F';
  572. BytesPerPixel: 16;
  573. ChannelCount: 4;
  574. HasAlphaChannel: True;
  575. IsFloatingPoint: True;
  576. IsRBSwapped: True;
  577. RBSwapFormat: ifA32R32G32B32F;
  578. GetPixelsSize: GetStdPixelsSize;
  579. CheckDimensions: CheckStdDimensions;
  580. GetPixel32: GetPixel32Generic;
  581. GetPixelFP: GetPixelFPFloat32;
  582. SetPixel32: SetPixel32Generic;
  583. SetPixelFP: SetPixelFPFloat32);
  584. R16FInfo: TImageFormatInfo = (
  585. Format: ifR16F;
  586. Name: 'R16F';
  587. BytesPerPixel: 2;
  588. ChannelCount: 1;
  589. IsFloatingPoint: True;
  590. GetPixelsSize: GetStdPixelsSize;
  591. CheckDimensions: CheckStdDimensions;
  592. GetPixel32: GetPixel32Generic;
  593. GetPixelFP: GetPixelFPGeneric;
  594. SetPixel32: SetPixel32Generic;
  595. SetPixelFP: SetPixelFPGeneric);
  596. A16R16G16B16FInfo: TImageFormatInfo = (
  597. Format: ifA16R16G16B16F;
  598. Name: 'A16R16G16B16F';
  599. BytesPerPixel: 8;
  600. ChannelCount: 4;
  601. HasAlphaChannel: True;
  602. IsFloatingPoint: True;
  603. RBSwapFormat: ifA16B16G16R16F;
  604. GetPixelsSize: GetStdPixelsSize;
  605. CheckDimensions: CheckStdDimensions;
  606. GetPixel32: GetPixel32Generic;
  607. GetPixelFP: GetPixelFPGeneric;
  608. SetPixel32: SetPixel32Generic;
  609. SetPixelFP: SetPixelFPGeneric);
  610. A16B16G16R16FInfo: TImageFormatInfo = (
  611. Format: ifA16B16G16R16F;
  612. Name: 'A16B16G16R16F';
  613. BytesPerPixel: 8;
  614. ChannelCount: 4;
  615. HasAlphaChannel: True;
  616. IsFloatingPoint: True;
  617. IsRBSwapped: True;
  618. RBSwapFormat: ifA16R16G16B16F;
  619. GetPixelsSize: GetStdPixelsSize;
  620. CheckDimensions: CheckStdDimensions;
  621. GetPixel32: GetPixel32Generic;
  622. GetPixelFP: GetPixelFPGeneric;
  623. SetPixel32: SetPixel32Generic;
  624. SetPixelFP: SetPixelFPGeneric);
  625. // special formats
  626. DXT1Info: TImageFormatInfo = (
  627. Format: ifDXT1;
  628. Name: 'DXT1';
  629. ChannelCount: 4;
  630. HasAlphaChannel: True;
  631. IsSpecial: True;
  632. GetPixelsSize: GetDXTPixelsSize;
  633. CheckDimensions: CheckDXTDimensions);
  634. DXT3Info: TImageFormatInfo = (
  635. Format: ifDXT3;
  636. Name: 'DXT3';
  637. ChannelCount: 4;
  638. HasAlphaChannel: True;
  639. IsSpecial: True;
  640. GetPixelsSize: GetDXTPixelsSize;
  641. CheckDimensions: CheckDXTDimensions);
  642. DXT5Info: TImageFormatInfo = (
  643. Format: ifDXT5;
  644. Name: 'DXT5';
  645. ChannelCount: 4;
  646. HasAlphaChannel: True;
  647. IsSpecial: True;
  648. GetPixelsSize: GetDXTPixelsSize;
  649. CheckDimensions: CheckDXTDimensions);
  650. {$WARNINGS ON}
  651. function PixelFormat(ABitCount, RBitCount, GBitCount, BBitCount: Byte): TPixelFormatInfo; forward;
  652. procedure InitImageFormats(var Infos: TImageFormatInfoArray);
  653. begin
  654. FInfos := @Infos;
  655. Infos[ifDefault] := @A8R8G8B8Info;
  656. // indexed formats
  657. Infos[ifIndex8] := @Index8Info;
  658. // grayscale formats
  659. Infos[ifGray8] := @Gray8Info;
  660. Infos[ifA8Gray8] := @A8Gray8Info;
  661. Infos[ifGray16] := @Gray16Info;
  662. Infos[ifGray32] := @Gray32Info;
  663. Infos[ifGray64] := @Gray64Info;
  664. Infos[ifA16Gray16] := @A16Gray16Info;
  665. // ARGB formats
  666. Infos[ifX5R1G1B1] := @X5R1G1B1Info;
  667. Infos[ifR3G3B2] := @R3G3B2Info;
  668. Infos[ifR5G6B5] := @R5G6B5Info;
  669. Infos[ifA1R5G5B5] := @A1R5G5B5Info;
  670. Infos[ifA4R4G4B4] := @A4R4G4B4Info;
  671. Infos[ifX1R5G5B5] := @X1R5G5B5Info;
  672. Infos[ifX4R4G4B4] := @X4R4G4B4Info;
  673. Infos[ifR8G8B8] := @R8G8B8Info;
  674. Infos[ifA8R8G8B8] := @A8R8G8B8Info;
  675. Infos[ifX8R8G8B8] := @X8R8G8B8Info;
  676. Infos[ifR16G16B16] := @R16G16B16Info;
  677. Infos[ifA16R16G16B16] := @A16R16G16B16Info;
  678. Infos[ifB16G16R16] := @B16G16R16Info;
  679. Infos[ifA16B16G16R16] := @A16B16G16R16Info;
  680. // floating point formats
  681. Infos[ifR32F] := @R32FInfo;
  682. Infos[ifA32R32G32B32F] := @A32R32G32B32FInfo;
  683. Infos[ifA32B32G32R32F] := @A32B32G32R32FInfo;
  684. Infos[ifR16F] := @R16FInfo;
  685. Infos[ifA16R16G16B16F] := @A16R16G16B16FInfo;
  686. Infos[ifA16B16G16R16F] := @A16B16G16R16FInfo;
  687. // special formats
  688. Infos[ifDXT1] := @DXT1Info;
  689. Infos[ifDXT3] := @DXT3Info;
  690. Infos[ifDXT5] := @DXT5Info;
  691. PFR3G3B2 := PixelFormat(0, 3, 3, 2);
  692. PFX5R1G1B1 := PixelFormat(0, 1, 1, 1);
  693. PFR5G6B5 := PixelFormat(0, 5, 6, 5);
  694. PFA1R5G5B5 := PixelFormat(1, 5, 5, 5);
  695. PFA4R4G4B4 := PixelFormat(4, 4, 4, 4);
  696. PFX1R5G5B5 := PixelFormat(0, 5, 5, 5);
  697. PFX4R4G4B4 := PixelFormat(0, 4, 4, 4);
  698. end;
  699. { Internal unit helper functions }
  700. function PixelFormat(ABitCount, RBitCount, GBitCount, BBitCount: Byte): TPixelFormatInfo;
  701. begin
  702. Result.ABitMask := ((1 shl ABitCount) - 1) shl (RBitCount + GBitCount +
  703. BBitCount);
  704. Result.RBitMask := ((1 shl RBitCount) - 1) shl (GBitCount + BBitCount);
  705. Result.GBitMask := ((1 shl GBitCount) - 1) shl (BBitCount);
  706. Result.BBitMask := (1 shl BBitCount) - 1;
  707. Result.ABitCount := ABitCount;
  708. Result.RBitCount := RBitCount;
  709. Result.GBitCount := GBitCount;
  710. Result.BBitCount := BBitCount;
  711. Result.AShift := RBitCount + GBitCount + BBitCount;
  712. Result.RShift := GBitCount + BBitCount;
  713. Result.GShift := BBitCount;
  714. Result.BShift := 0;
  715. Result.ARecDiv := Max(1, Pow2Int(Result.ABitCount) - 1);
  716. Result.RRecDiv := Max(1, Pow2Int(Result.RBitCount) - 1);
  717. Result.GRecDiv := Max(1, Pow2Int(Result.GBitCount) - 1);
  718. Result.BRecDiv := Max(1, Pow2Int(Result.BBitCount) - 1);
  719. end;
  720. function PixelFormatMask(ABitMask, RBitMask, GBitMask, BBitMask: LongWord): TPixelFormatInfo;
  721. function GetBitCount(B: LongWord): LongWord;
  722. var
  723. I: LongWord;
  724. begin
  725. I := 0;
  726. while (I < 31) and (((1 shl I) and B) = 0) do
  727. Inc(I);
  728. Result := 0;
  729. while ((1 shl I) and B) <> 0 do
  730. begin
  731. Inc(I);
  732. Inc(Result);
  733. end;
  734. end;
  735. begin
  736. Result := PixelFormat(GetBitCount(ABitMask), GetBitCount(RBitMask),
  737. GetBitCount(GBitMask), GetBitCount(BBitMask));
  738. end;
  739. function PFSetARGB(const PF: TPixelFormatInfo; A, R, G, B: Byte): TColor32;
  740. {$IFDEF USE_INLINE}inline;{$ENDIF}
  741. begin
  742. with PF do
  743. Result :=
  744. (A shl ABitCount shr 8 shl AShift) or
  745. (R shl RBitCount shr 8 shl RShift) or
  746. (G shl GBitCount shr 8 shl GShift) or
  747. (B shl BBitCount shr 8 shl BShift);
  748. end;
  749. procedure PFGetARGB(const PF: TPixelFormatInfo; Color: LongWord;
  750. var A, R, G, B: Byte); {$IFDEF USE_INLINE}inline;{$ENDIF}
  751. begin
  752. with PF do
  753. begin
  754. A := (Color and ABitMask shr AShift) * 255 div ARecDiv;
  755. R := (Color and RBitMask shr RShift) * 255 div RRecDiv;
  756. G := (Color and GBitMask shr GShift) * 255 div GRecDiv;
  757. B := (Color and BBitMask shl BShift) * 255 div BRecDiv;
  758. end;
  759. end;
  760. function PFSetColor(const PF: TPixelFormatInfo; ARGB: TColor32): LongWord;
  761. {$IFDEF USE_INLINE}inline;{$ENDIF}
  762. begin
  763. with PF do
  764. Result :=
  765. (Byte(ARGB shr 24) shl ABitCount shr 8 shl AShift) or
  766. (Byte(ARGB shr 16) shl RBitCount shr 8 shl RShift) or
  767. (Byte(ARGB shr 8) shl GBitCount shr 8 shl GShift) or
  768. (Byte(ARGB) shl BBitCount shr 8 shl BShift);
  769. end;
  770. function PFGetColor(const PF: TPixelFormatInfo; Color: LongWord): TColor32;
  771. {$IFDEF USE_INLINE}inline;{$ENDIF}
  772. begin
  773. with PF, TColor32Rec(Result) do
  774. begin
  775. A := (Color and ABitMask shr AShift) * 255 div ARecDiv;
  776. R := (Color and RBitMask shr RShift) * 255 div RRecDiv;
  777. G := (Color and GBitMask shr GShift) * 255 div GRecDiv;
  778. B := (Color and BBitMask shl BShift) * 255 div BRecDiv;
  779. end;
  780. end;
  781. { Additional image manipulation functions (usually used internally by Imaging unit) }
  782. const
  783. MaxPossibleColors = 4096;
  784. HashSize = 32768;
  785. AlphaWeight = 1024;
  786. RedWeight = 612;
  787. GreenWeight = 1202;
  788. BlueWeight = 234;
  789. type
  790. PColorBin = ^TColorBin;
  791. TColorBin = record
  792. Color: TColor32Rec;
  793. Number: LongInt;
  794. Next: PColorBin;
  795. end;
  796. THashTable = array[0..HashSize - 1] of PColorBin;
  797. TColorBox = record
  798. AMin, AMax,
  799. RMin, RMax,
  800. GMin, GMax,
  801. BMin, BMax: LongInt;
  802. Total: LongInt;
  803. Represented: TColor32Rec;
  804. List: PColorBin;
  805. end;
  806. var
  807. Table: THashTable;
  808. Box: array[0..MaxPossibleColors - 1] of TColorBox;
  809. Boxes: LongInt;
  810. BoxesCreated: Boolean = False;
  811. procedure ReduceColorsMedianCut(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  812. DstInfo: PImageFormatInfo; MaxColors: LongInt; ChannelMask: Byte;
  813. DstPal: PPalette32; Actions: TReduceColorsActions);
  814. procedure CreateHistogram (Src: PByte; SrcInfo: PImageFormatInfo;
  815. ChannelMask: Byte);
  816. var
  817. A, R, G, B: Byte;
  818. I, Addr: LongInt;
  819. PC: PColorBin;
  820. Col: TColor32Rec;
  821. begin
  822. for I := 0 to NumPixels - 1 do
  823. begin
  824. Col := GetPixel32Generic(Src, SrcInfo, nil);
  825. A := Col.A and ChannelMask;
  826. R := Col.R and ChannelMask;
  827. G := Col.G and ChannelMask;
  828. B := Col.B and ChannelMask;
  829. Addr := (A + 11 * B + 59 * R + 119 * G) mod HashSize;
  830. PC := Table[Addr];
  831. while (PC <> nil) and ((PC.Color.R <> R) or (PC.Color.G <> G) or
  832. (PC.Color.B <> B) or (PC.Color.A <> A)) do
  833. PC := PC.Next;
  834. if PC = nil then
  835. begin
  836. New(PC);
  837. PC.Color.R := R;
  838. PC.Color.G := G;
  839. PC.Color.B := B;
  840. PC.Color.A := A;
  841. PC.Number := 1;
  842. PC.Next := Table[Addr];
  843. Table[Addr] := PC;
  844. end
  845. else
  846. Inc(PC^.Number);
  847. Inc(Src, SrcInfo.BytesPerPixel);
  848. end;
  849. end;
  850. procedure InitBox (var Box : TColorBox);
  851. begin
  852. Box.AMin := 256;
  853. Box.RMin := 256;
  854. Box.GMin := 256;
  855. Box.BMin := 256;
  856. Box.AMax := -1;
  857. Box.RMax := -1;
  858. Box.GMax := -1;
  859. Box.BMax := -1;
  860. Box.Total := 0;
  861. Box.List := nil;
  862. end;
  863. procedure ChangeBox (var Box: TColorBox; const C: TColorBin);
  864. begin
  865. with C.Color do
  866. begin
  867. if A < Box.AMin then Box.AMin := A;
  868. if A > Box.AMax then Box.AMax := A;
  869. if B < Box.BMin then Box.BMin := B;
  870. if B > Box.BMax then Box.BMax := B;
  871. if G < Box.GMin then Box.GMin := G;
  872. if G > Box.GMax then Box.GMax := G;
  873. if R < Box.RMin then Box.RMin := R;
  874. if R > Box.RMax then Box.RMax := R;
  875. end;
  876. Inc(Box.Total, C.Number);
  877. end;
  878. procedure MakeColormap;
  879. var
  880. I, J: LongInt;
  881. CP, Pom: PColorBin;
  882. Cut, LargestIdx, Largest, Size, S: LongInt;
  883. CutA, CutR, CutG, CutB: Boolean;
  884. SumA, SumR, SumG, SumB: LongInt;
  885. Temp: TColorBox;
  886. begin
  887. I := 0;
  888. Boxes := 1;
  889. LargestIdx := 0;
  890. while (I < HashSize) and (Table[I] = nil) do
  891. Inc(i);
  892. if I < HashSize then
  893. begin
  894. // put all colors into Box[0]
  895. InitBox(Box[0]);
  896. repeat
  897. CP := Table[I];
  898. while CP.Next <> nil do
  899. begin
  900. ChangeBox(Box[0], CP^);
  901. CP := CP.Next;
  902. end;
  903. ChangeBox(Box[0], CP^);
  904. CP.Next := Box[0].List;
  905. Box[0].List := Table[I];
  906. Table[I] := nil;
  907. repeat
  908. Inc(I)
  909. until (I = HashSize) or (Table[I] <> nil);
  910. until I = HashSize;
  911. // now all colors are in Box[0]
  912. repeat
  913. // cut one color box
  914. Largest := 0;
  915. for I := 0 to Boxes - 1 do
  916. with Box[I] do
  917. begin
  918. Size := (AMax - AMin) * AlphaWeight;
  919. S := (RMax - RMin) * RedWeight;
  920. if S > Size then
  921. Size := S;
  922. S := (GMax - GMin) * GreenWeight;
  923. if S > Size then
  924. Size := S;
  925. S := (BMax - BMin) * BlueWeight;
  926. if S > Size then
  927. Size := S;
  928. if Size > Largest then
  929. begin
  930. Largest := Size;
  931. LargestIdx := I;
  932. end;
  933. end;
  934. if Largest > 0 then
  935. begin
  936. // cutting Box[LargestIdx] into Box[LargestIdx] and Box[Boxes]
  937. CutR := False;
  938. CutG := False;
  939. CutB := False;
  940. CutA := False;
  941. with Box[LargestIdx] do
  942. begin
  943. if (AMax - AMin) * AlphaWeight = Largest then
  944. begin
  945. Cut := (AMax + AMin) shr 1;
  946. CutA := True;
  947. end
  948. else
  949. if (RMax - RMin) * RedWeight = Largest then
  950. begin
  951. Cut := (RMax + RMin) shr 1;
  952. CutR := True;
  953. end
  954. else
  955. if (GMax - GMin) * GreenWeight = Largest then
  956. begin
  957. Cut := (GMax + GMin) shr 1;
  958. CutG := True;
  959. end
  960. else
  961. begin
  962. Cut := (BMax + BMin) shr 1;
  963. CutB := True;
  964. end;
  965. CP := List;
  966. end;
  967. InitBox(Box[LargestIdx]);
  968. InitBox(Box[Boxes]);
  969. repeat
  970. // distribute one color
  971. Pom := CP.Next;
  972. with CP.Color do
  973. begin
  974. if (CutA and (A <= Cut)) or (CutR and (R <= Cut)) or
  975. (CutG and (G <= Cut)) or (CutB and (B <= Cut)) then
  976. I := LargestIdx
  977. else
  978. I := Boxes;
  979. end;
  980. CP.Next := Box[i].List;
  981. Box[i].List := CP;
  982. ChangeBox(Box[i], CP^);
  983. CP := Pom;
  984. until CP = nil;
  985. Inc(Boxes);
  986. end;
  987. until (Boxes = MaxColors) or (Largest = 0);
  988. // compute box representation
  989. for I := 0 to Boxes - 1 do
  990. begin
  991. SumR := 0;
  992. SumG := 0;
  993. SumB := 0;
  994. SumA := 0;
  995. repeat
  996. CP := Box[I].List;
  997. Inc(SumR, CP.Color.R * CP.Number);
  998. Inc(SumG, CP.Color.G * CP.Number);
  999. Inc(SumB, CP.Color.B * CP.Number);
  1000. Inc(SumA, CP.Color.A * CP.Number);
  1001. Box[I].List := CP.Next;
  1002. Dispose(CP);
  1003. until Box[I].List = nil;
  1004. with Box[I] do
  1005. begin
  1006. Represented.A := SumA div Total;
  1007. Represented.R := SumR div Total;
  1008. Represented.G := SumG div Total;
  1009. Represented.B := SumB div Total;
  1010. AMin := AMin and ChannelMask;
  1011. RMin := RMin and ChannelMask;
  1012. GMin := GMin and ChannelMask;
  1013. BMin := BMin and ChannelMask;
  1014. AMax := (AMax and ChannelMask) + (not ChannelMask);
  1015. RMax := (RMax and ChannelMask) + (not ChannelMask);
  1016. GMax := (GMax and ChannelMask) + (not ChannelMask);
  1017. BMax := (BMax and ChannelMask) + (not ChannelMask);
  1018. end;
  1019. end;
  1020. // sort color boxes
  1021. for I := 0 to Boxes - 2 do
  1022. begin
  1023. Largest := 0;
  1024. for J := I to Boxes - 1 do
  1025. if Box[J].Total > Largest then
  1026. begin
  1027. Largest := Box[J].Total;
  1028. LargestIdx := J;
  1029. end;
  1030. if LargestIdx <> I then
  1031. begin
  1032. Temp := Box[I];
  1033. Box[I] := Box[LargestIdx];
  1034. Box[LargestIdx] := Temp;
  1035. end;
  1036. end;
  1037. end;
  1038. end;
  1039. procedure FillOutputPalette;
  1040. var
  1041. I: LongInt;
  1042. begin
  1043. FillChar(DstPal^, SizeOf(TColor32Rec) * MaxColors, $FF);
  1044. for I := 0 to MaxColors - 1 do
  1045. with Box[I].Represented do
  1046. begin
  1047. DstPal[I].A := A;
  1048. DstPal[I].R := R;
  1049. DstPal[I].G := G;
  1050. DstPal[I].B := B;
  1051. end;
  1052. end;
  1053. function MapColor(const Col: TColor32Rec) : LongInt;
  1054. var
  1055. I: LongInt;
  1056. begin
  1057. I := 0;
  1058. with Col do
  1059. while (I < Boxes) and ((Box[I].AMin > A) or (Box[I].AMax < A) or
  1060. (Box[I].RMin > R) or (Box[I].RMax < R) or (Box[I].GMin > G) or
  1061. (Box[I].GMax < G) or (Box[I].BMin > B) or (Box[I].BMax < B)) do
  1062. Inc(I);
  1063. if I = Boxes then
  1064. MapColor := 0
  1065. else
  1066. MapColor := I;
  1067. end;
  1068. procedure MapImage(Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo);
  1069. var
  1070. I: LongInt;
  1071. Col: TColor32Rec;
  1072. begin
  1073. for I := 0 to NumPixels - 1 do
  1074. begin
  1075. Col := GetPixel32Generic(Src, SrcInfo, nil);
  1076. IndexSetDstPixel(Dst, DstInfo, MapColor(Col));
  1077. Inc(Src, SrcInfo.BytesPerPixel);
  1078. Inc(Dst, DstInfo.BytesPerPixel);
  1079. end;
  1080. end;
  1081. begin
  1082. MaxColors := ClampInt(MaxColors, 2, MaxPossibleColors);
  1083. if raCreateHistogram in Actions then
  1084. FillChar(Table, SizeOf(Table), 0);
  1085. if raUpdateHistogram in Actions then
  1086. CreateHistogram(Src, SrcInfo, ChannelMask);
  1087. if raMakeColorMap in Actions then
  1088. begin
  1089. MakeColorMap;
  1090. FillOutputPalette;
  1091. end;
  1092. if raMapImage in Actions then
  1093. MapImage(Src, Dst, SrcInfo, DstInfo);
  1094. end;
  1095. procedure StretchNearest(const SrcImage: TImageData; SrcX, SrcY, SrcWidth,
  1096. SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth,
  1097. DstHeight: LongInt);
  1098. var
  1099. Info: TImageFormatInfo;
  1100. ScaleX, ScaleY, X, Y, Xp, Yp: LongInt;
  1101. DstPixel, SrcLine: PByte;
  1102. begin
  1103. GetImageFormatInfo(SrcImage.Format, Info);
  1104. Assert(SrcImage.Format = DstImage.Format);
  1105. Assert(not Info.IsSpecial);
  1106. // Use integers instead of floats for source image pixel coords
  1107. // Xp and Yp coords must be shifted right to get read source image coords
  1108. ScaleX := (SrcWidth shl 16) div DstWidth;
  1109. ScaleY := (SrcHeight shl 16) div DstHeight;
  1110. Yp := 0;
  1111. for Y := 0 to DstHeight - 1 do
  1112. begin
  1113. Xp := 0;
  1114. SrcLine := @PByteArray(SrcImage.Bits)[((SrcY + Yp shr 16) * SrcImage.Width + SrcX) * Info.BytesPerPixel];
  1115. DstPixel := @PByteArray(DstImage.Bits)[((DstY + Y) * DstImage.Width + DstX) * Info.BytesPerPixel];
  1116. for X := 0 to DstWidth - 1 do
  1117. begin
  1118. case Info.BytesPerPixel of
  1119. 1: PByte(DstPixel)^ := PByteArray(SrcLine)[Xp shr 16];
  1120. 2: PWord(DstPixel)^ := PWordArray(SrcLine)[Xp shr 16];
  1121. 3: PColor24Rec(DstPixel)^ := PPalette24(SrcLine)[Xp shr 16];
  1122. 4: PColor32(DstPixel)^ := PLongWordArray(SrcLine)[Xp shr 16];
  1123. 6: PColor48Rec(DstPixel)^ := PColor48RecArray(SrcLine)[Xp shr 16];
  1124. 8: PColor64(DstPixel)^ := PInt64Array(SrcLine)[Xp shr 16];
  1125. 16: PColorFPRec(DstPixel)^ := PColorFPRecArray(SrcLine)[Xp shr 16];
  1126. end;
  1127. Inc(DstPixel, Info.BytesPerPixel);
  1128. Inc(Xp, ScaleX);
  1129. end;
  1130. Inc(Yp, ScaleY);
  1131. end;
  1132. end;
  1133. { Filter function for nearest filtering. Also known as box filter.}
  1134. function FilterNearest(Value: Single): Single;
  1135. begin
  1136. if (Value > -0.5) and (Value <= 0.5) then
  1137. Result := 1
  1138. else
  1139. Result := 0;
  1140. end;
  1141. { Filter function for linear filtering. Also known as triangle or Bartlett filter.}
  1142. function FilterLinear(Value: Single): Single;
  1143. begin
  1144. if Value < 0.0 then
  1145. Value := -Value;
  1146. if Value < 1.0 then
  1147. Result := 1.0 - Value
  1148. else
  1149. Result := 0.0;
  1150. end;
  1151. { Cosine filter.}
  1152. function FilterCosine(Value: Single): Single;
  1153. begin
  1154. Result := 0;
  1155. if Abs(Value) < 1 then
  1156. Result := (Cos(Value * Pi) + 1) / 2;
  1157. end;
  1158. { f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 }
  1159. function FilterHermite(Value: Single): Single;
  1160. begin
  1161. if Value < 0.0 then
  1162. Value := -Value;
  1163. if Value < 1 then
  1164. Result := (2 * Value - 3) * Sqr(Value) + 1
  1165. else
  1166. Result := 0;
  1167. end;
  1168. { Quadratic filter. Also known as Bell.}
  1169. function FilterQuadratic(Value: Single): Single;
  1170. begin
  1171. if Value < 0.0 then
  1172. Value := -Value;
  1173. if Value < 0.5 then
  1174. Result := 0.75 - Sqr(Value)
  1175. else
  1176. if Value < 1.5 then
  1177. begin
  1178. Value := Value - 1.5;
  1179. Result := 0.5 * Sqr(Value);
  1180. end
  1181. else
  1182. Result := 0.0;
  1183. end;
  1184. { Gaussian filter.}
  1185. function FilterGaussian(Value: Single): Single;
  1186. begin
  1187. Result := Exp(-2.0 * Sqr(Value)) * Sqrt(2.0 / Pi);
  1188. end;
  1189. { 4th order (cubic) b-spline filter.}
  1190. function FilterSpline(Value: Single): Single;
  1191. var
  1192. Temp: Single;
  1193. begin
  1194. if Value < 0.0 then
  1195. Value := -Value;
  1196. if Value < 1.0 then
  1197. begin
  1198. Temp := Sqr(Value);
  1199. Result := 0.5 * Temp * Value - Temp + 2.0 / 3.0;
  1200. end
  1201. else
  1202. if Value < 2.0 then
  1203. begin
  1204. Value := 2.0 - Value;
  1205. Result := Sqr(Value) * Value / 6.0;
  1206. end
  1207. else
  1208. Result := 0.0;
  1209. end;
  1210. { Lanczos-windowed sinc filter.}
  1211. function FilterLanczos(Value: Single): Single;
  1212. function SinC(Value: Single): Single;
  1213. begin
  1214. if Value <> 0.0 then
  1215. begin
  1216. Value := Value * Pi;
  1217. Result := Sin(Value) / Value;
  1218. end
  1219. else
  1220. Result := 1.0;
  1221. end;
  1222. begin
  1223. if Value < 0.0 then
  1224. Value := -Value;
  1225. if Value < 3.0 then
  1226. Result := SinC(Value) * SinC(Value / 3.0)
  1227. else
  1228. Result := 0.0;
  1229. end;
  1230. { Micthell cubic filter.}
  1231. function FilterMitchell(Value: Single): Single;
  1232. const
  1233. B = 1.0 / 3.0;
  1234. C = 1.0 / 3.0;
  1235. var
  1236. Temp: Single;
  1237. begin
  1238. if Value < 0.0 then
  1239. Value := -Value;
  1240. Temp := Sqr(Value);
  1241. if Value < 1.0 then
  1242. begin
  1243. Value := (((12.0 - 9.0 * B - 6.0 * C) * (Value * Temp)) +
  1244. ((-18.0 + 12.0 * B + 6.0 * C) * Temp) +
  1245. (6.0 - 2.0 * B));
  1246. Result := Value / 6.0;
  1247. end
  1248. else
  1249. if Value < 2.0 then
  1250. begin
  1251. Value := (((-B - 6.0 * C) * (Value * Temp)) +
  1252. ((6.0 * B + 30.0 * C) * Temp) +
  1253. ((-12.0 * B - 48.0 * C) * Value) +
  1254. (8.0 * B + 24.0 * C));
  1255. Result := Value / 6.0;
  1256. end
  1257. else
  1258. Result := 0.0;
  1259. end;
  1260. { CatmullRom spline filter.}
  1261. function FilterCatmullRom(Value: Single): Single;
  1262. begin
  1263. if Value < 0.0 then
  1264. Value := -Value;
  1265. if Value < 1.0 then
  1266. Result := 0.5 * (2.0 + Sqr(Value) * (-5.0 + 3.0 * Value))
  1267. else
  1268. if Value < 2.0 then
  1269. Result := 0.5 * (4.0 + Value * (-8.0 + Value * (5.0 - Value)))
  1270. else
  1271. Result := 0.0;
  1272. end;
  1273. const
  1274. // Some built-in filter functions adn their default radii
  1275. FilterFunctions: array[TSamplingFilter] of TFilterFunction = (
  1276. FilterNearest, FilterLinear, FilterCosine, FilterHermite, FilterQuadratic,
  1277. FilterGaussian, FilterSpline, FilterLanczos, FilterMitchell, FilterCatmullRom);
  1278. FilterRadii: array[TSamplingFilter] of Single = (
  1279. 1.0, 1.0, 1.0, 1.0, 1.5,
  1280. 1.25, 2.0, 3.0, 2.0, 2.0);
  1281. procedure StretchResample(const SrcImage: TImageData; SrcX, SrcY, SrcWidth,
  1282. SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth,
  1283. DstHeight: LongInt; Filter: TSamplingFilter; WrapEdges: Boolean);
  1284. begin
  1285. // Calls the other function with filter function and radius defined by Filter
  1286. StretchResample(SrcImage, SrcX, SrcY, SrcWidth, SrcHeight, DstImage, DstX, DstY,
  1287. DstWidth, DstHeight, FilterFunctions[Filter], FilterRadii[Filter]);
  1288. end;
  1289. { The following resampling code is modified and extended code from Graphics32
  1290. library by Alex A. Denisov.}
  1291. type
  1292. TPointRec = record
  1293. Pos: LongInt;
  1294. Weight: Single;
  1295. end;
  1296. TCluster = array of TPointRec;
  1297. TMappingTable = array of TCluster;
  1298. var
  1299. FullEdge: Boolean = True;
  1300. function BuildMappingTable(DstLow, DstHigh, SrcLow, SrcHigh, SrcImageWidth: LongInt;
  1301. Filter: TFilterFunction; Radius: Single; WrapEdges: Boolean): TMappingTable;
  1302. var
  1303. I, J, K, N: LongInt;
  1304. Left, Right, SrcWidth, DstWidth: LongInt;
  1305. Weight, Scale, Center, Count: Single;
  1306. begin
  1307. Result := nil;
  1308. K := 0;
  1309. SrcWidth := SrcHigh - SrcLow;
  1310. DstWidth := DstHigh - DstLow;
  1311. // Check some special cases
  1312. if SrcWidth = 1 then
  1313. begin
  1314. SetLength(Result, DstWidth);
  1315. for I := 0 to DstWidth - 1 do
  1316. begin
  1317. SetLength(Result[I], 1);
  1318. Result[I][0].Pos := 0;
  1319. Result[I][0].Weight := 1.0;
  1320. end;
  1321. Exit;
  1322. end
  1323. else
  1324. if (SrcWidth = 0) or (DstWidth = 0) then
  1325. Exit;
  1326. if FullEdge then
  1327. Scale := DstWidth / SrcWidth
  1328. else
  1329. Scale := (DstWidth - 1) / (SrcWidth - 1);
  1330. SetLength(Result, DstWidth);
  1331. // Pre-calculate filter contributions for a row or column
  1332. if Scale = 0.0 then
  1333. begin
  1334. Assert(Length(Result) = 1);
  1335. SetLength(Result[0], 1);
  1336. Result[0][0].Pos := (SrcLow + SrcHigh) div 2;
  1337. Result[0][0].Weight := 1.0;
  1338. end
  1339. else
  1340. if Scale < 1.0 then
  1341. begin
  1342. // Sub-sampling - scales from bigger to smaller
  1343. Radius := Radius / Scale;
  1344. for I := 0 to DstWidth - 1 do
  1345. begin
  1346. if FullEdge then
  1347. Center := SrcLow - 0.5 + (I + 0.5) / Scale
  1348. else
  1349. Center := SrcLow + I / Scale;
  1350. Left := Floor(Center - Radius);
  1351. Right := Ceil(Center + Radius);
  1352. Count := -1.0;
  1353. for J := Left to Right do
  1354. begin
  1355. Weight := Filter((Center - J) * Scale) * Scale;
  1356. if Weight <> 0.0 then
  1357. begin
  1358. Count := Count + Weight;
  1359. K := Length(Result[I]);
  1360. SetLength(Result[I], K + 1);
  1361. Result[I][K].Pos := ClampInt(J, SrcLow, SrcHigh - 1);
  1362. Result[I][K].Weight := Weight;
  1363. end;
  1364. end;
  1365. if Length(Result[I]) = 0 then
  1366. begin
  1367. SetLength(Result[I], 1);
  1368. Result[I][0].Pos := Floor(Center);
  1369. Result[I][0].Weight := 1.0;
  1370. end
  1371. else
  1372. if Count <> 0.0 then
  1373. Result[I][K div 2].Weight := Result[I][K div 2].Weight - Count;
  1374. end;
  1375. end
  1376. else // if Scale > 1.0 then
  1377. begin
  1378. // Super-sampling - scales from smaller to bigger
  1379. Scale := 1.0 / Scale;
  1380. for I := 0 to DstWidth - 1 do
  1381. begin
  1382. if FullEdge then
  1383. Center := SrcLow - 0.5 + (I + 0.5) * Scale
  1384. else
  1385. Center := SrcLow + I * Scale;
  1386. Left := Floor(Center - Radius);
  1387. Right := Ceil(Center + Radius);
  1388. Count := -1.0;
  1389. for J := Left to Right do
  1390. begin
  1391. Weight := Filter(Center - J);
  1392. if Weight <> 0.0 then
  1393. begin
  1394. Count := Count + Weight;
  1395. K := Length(Result[I]);
  1396. SetLength(Result[I], K + 1);
  1397. if WrapEdges then
  1398. begin
  1399. if J < 0 then
  1400. N := SrcImageWidth + J
  1401. else
  1402. if J >= SrcImageWidth then
  1403. N := J - SrcImageWidth
  1404. else
  1405. N := ClampInt(J, SrcLow, SrcHigh - 1);
  1406. end
  1407. else
  1408. N := ClampInt(J, SrcLow, SrcHigh - 1);
  1409. Result[I][K].Pos := N;
  1410. Result[I][K].Weight := Weight;
  1411. end;
  1412. end;
  1413. if Count <> 0.0 then
  1414. Result[I][K div 2].Weight := Result[I][K div 2].Weight - Count;
  1415. end;
  1416. end;
  1417. end;
  1418. procedure StretchResample(const SrcImage: TImageData; SrcX, SrcY, SrcWidth,
  1419. SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth,
  1420. DstHeight: LongInt; Filter: TFilterFunction; Radius: Single; WrapEdges: Boolean);
  1421. const
  1422. Channel8BitMax: Single = 255.0;
  1423. var
  1424. MapX, MapY: TMappingTable;
  1425. I, J, X, Y: LongInt;
  1426. XMinimum, XMaximum: LongInt;
  1427. LineBuffer: array of TColorFPRec;
  1428. ClusterX, ClusterY: TCluster;
  1429. Weight, AccumA, AccumR, AccumG, AccumB: Single;
  1430. DstLine: PByte;
  1431. SrcColor: TColor32Rec;
  1432. SrcFloat: TColorFPRec;
  1433. Info: TImageFormatInfo;
  1434. BytesPerChannel: LongInt;
  1435. ChannelValueMax, InvChannelValueMax: Single;
  1436. UseOptimizedVersion: Boolean;
  1437. procedure FindExtremes(const Map: TMappingTable; var MinPos, MaxPos: LongInt);
  1438. var
  1439. I, J: LongInt;
  1440. begin
  1441. if Length(Map) > 0 then
  1442. begin
  1443. MinPos := Map[0][0].Pos;
  1444. MaxPos := MinPos;
  1445. for I := 0 to Length(Map) - 1 do
  1446. for J := 0 to Length(Map[I]) - 1 do
  1447. begin
  1448. if MinPos > Map[I][J].Pos then
  1449. MinPos := Map[I][J].Pos;
  1450. if MaxPos < Map[I][J].Pos then
  1451. MaxPos := Map[I][J].Pos;
  1452. end;
  1453. end;
  1454. end;
  1455. begin
  1456. GetImageFormatInfo(SrcImage.Format, Info);
  1457. Assert(SrcImage.Format = DstImage.Format);
  1458. Assert(not Info.IsSpecial and not Info.IsIndexed);
  1459. BytesPerChannel := Info.BytesPerPixel div Info.ChannelCount;
  1460. UseOptimizedVersion := (BytesPerChannel = 1) and not Info.UsePixelFormat;
  1461. // Create horizontal and vertical mapping tables
  1462. MapX := BuildMappingTable(DstX, DstX + DstWidth, SrcX, SrcX + SrcWidth,
  1463. SrcImage.Width, Filter, Radius, WrapEdges);
  1464. MapY := BuildMappingTable(DstY, DstY + DstHeight, SrcY, SrcY + SrcHeight,
  1465. SrcImage.Height, Filter, Radius, WrapEdges);
  1466. if (MapX = nil) or (MapY = nil) then
  1467. Exit;
  1468. ClusterX := nil;
  1469. ClusterY := nil;
  1470. try
  1471. // Find min and max X coords of pixels that will contribute to target image
  1472. FindExtremes(MapX, XMinimum, XMaximum);
  1473. SetLength(LineBuffer, XMaximum - XMinimum + 1);
  1474. if not UseOptimizedVersion then
  1475. begin
  1476. // Following code works for the rest of data formats
  1477. for J := 0 to DstHeight - 1 do
  1478. begin
  1479. // First for each pixel in the current line sample vertically
  1480. // and store results in LineBuffer. Then sample horizontally
  1481. // using values in LineBuffer.
  1482. ClusterY := MapY[J];
  1483. for X := XMinimum to XMaximum do
  1484. begin
  1485. // Clear accumulators
  1486. AccumA := 0.0;
  1487. AccumR := 0.0;
  1488. AccumG := 0.0;
  1489. AccumB := 0.0;
  1490. // For each pixel in line compute weighted sum of pixels
  1491. // in source column that will contribute to this pixel
  1492. for Y := 0 to Length(ClusterY) - 1 do
  1493. begin
  1494. // Accumulate this pixel's weighted value
  1495. Weight := ClusterY[Y].Weight;
  1496. SrcFloat := Info.GetPixelFP(@PByteArray(SrcImage.Bits)[(ClusterY[Y].Pos * SrcImage.Width + X) * Info.BytesPerPixel], @Info, nil);
  1497. AccumB := AccumB + SrcFloat.B * Weight;
  1498. AccumG := AccumG + SrcFloat.G * Weight;
  1499. AccumR := AccumR + SrcFloat.R * Weight;
  1500. AccumA := AccumA + SrcFloat.A * Weight;
  1501. end;
  1502. // Store accumulated value for this pixel in buffer
  1503. with LineBuffer[X - XMinimum] do
  1504. begin
  1505. A := AccumA;
  1506. R := AccumR;
  1507. G := AccumG;
  1508. B := AccumB;
  1509. end;
  1510. end;
  1511. DstLine := @PByteArray(DstImage.Bits)[((J + DstY) * DstImage.Width + DstX) * Info.BytesPerPixel];
  1512. // Now compute final colors for targte pixels in the current row
  1513. // by sampling horizontally
  1514. for I := 0 to DstWidth - 1 do
  1515. begin
  1516. ClusterX := MapX[I];
  1517. // Clear accumulator
  1518. AccumA := 0.0;
  1519. AccumR := 0.0;
  1520. AccumG := 0.0;
  1521. AccumB := 0.0;
  1522. // Compute weighted sum of values (which are already
  1523. // computed weighted sums of pixels in source columns stored in LineBuffer)
  1524. // that will contribute to the current target pixel
  1525. for X := 0 to Length(ClusterX) - 1 do
  1526. begin
  1527. Weight := ClusterX[X].Weight;
  1528. with LineBuffer[ClusterX[X].Pos - XMinimum] do
  1529. begin
  1530. AccumB := AccumB + B * Weight;
  1531. AccumG := AccumG + G * Weight;
  1532. AccumR := AccumR + R * Weight;
  1533. AccumA := AccumA + A * Weight;
  1534. end;
  1535. end;
  1536. // Now compute final color to be written to dest image
  1537. SrcFloat.A := AccumA;
  1538. SrcFloat.R := AccumR;
  1539. SrcFloat.G := AccumG;
  1540. SrcFloat.B := AccumB;
  1541. Info.SetPixelFP(DstLine, @Info, nil, SrcFloat);
  1542. Inc(DstLine, Info.BytesPerPixel);
  1543. end;
  1544. end;
  1545. end
  1546. else
  1547. begin
  1548. // Following code is optimized for images with 8 bit channels
  1549. for J := 0 to DstHeight - 1 do
  1550. begin
  1551. ClusterY := MapY[J];
  1552. for X := XMinimum to XMaximum do
  1553. begin
  1554. AccumA := 0.0;
  1555. AccumR := 0.0;
  1556. AccumG := 0.0;
  1557. AccumB := 0.0;
  1558. for Y := 0 to Length(ClusterY) - 1 do
  1559. begin
  1560. Weight := ClusterY[Y].Weight;
  1561. CopyPixel(
  1562. @PByteArray(SrcImage.Bits)[(ClusterY[Y].Pos * SrcImage.Width + X) * Info.BytesPerPixel],
  1563. @SrcColor, Info.BytesPerPixel);
  1564. AccumB := AccumB + SrcColor.B * Weight;
  1565. if Info.ChannelCount > 1 then
  1566. AccumG := AccumG + SrcColor.G * Weight;
  1567. if Info.ChannelCount > 2 then
  1568. AccumR := AccumR + SrcColor.R * Weight;
  1569. if Info.ChannelCount > 3 then
  1570. AccumA := AccumA + SrcColor.A * Weight;
  1571. end;
  1572. with LineBuffer[X - XMinimum] do
  1573. begin
  1574. A := AccumA;
  1575. R := AccumR;
  1576. G := AccumG;
  1577. B := AccumB;
  1578. end;
  1579. end;
  1580. DstLine := @PByteArray(DstImage.Bits)[((J + DstY) * DstImage.Width + DstX)* Info.BytesPerPixel];
  1581. for I := 0 to DstWidth - 1 do
  1582. begin
  1583. ClusterX := MapX[I];
  1584. AccumA := 0.0;
  1585. AccumR := 0.0;
  1586. AccumG := 0.0;
  1587. AccumB := 0.0;
  1588. for X := 0 to Length(ClusterX) - 1 do
  1589. begin
  1590. Weight := ClusterX[X].Weight;
  1591. with LineBuffer[ClusterX[X].Pos - XMinimum] do
  1592. begin
  1593. AccumB := AccumB + B * Weight;
  1594. if Info.ChannelCount > 1 then
  1595. AccumG := AccumG + G * Weight;
  1596. if Info.ChannelCount > 2 then
  1597. AccumR := AccumR + R * Weight;
  1598. if Info.ChannelCount > 3 then
  1599. AccumA := AccumA + A * Weight;
  1600. end;
  1601. end;
  1602. SrcColor.B := ClampToByte(Round(AccumB));
  1603. if Info.ChannelCount > 1 then
  1604. SrcColor.G := ClampToByte(Round(AccumG));
  1605. if Info.ChannelCount > 2 then
  1606. SrcColor.R := ClampToByte(Round(AccumR));
  1607. if Info.ChannelCount > 3 then
  1608. SrcColor.A := ClampToByte(Round(AccumA));
  1609. CopyPixel(@SrcColor, DstLine, Info.BytesPerPixel);
  1610. Inc(DstLine, Info.BytesPerPixel);
  1611. end;
  1612. end;
  1613. end;
  1614. finally
  1615. MapX := nil;
  1616. MapY := nil;
  1617. end;
  1618. end;
  1619. procedure FillMipMapLevel(const BiggerLevel: TImageData; Width, Height: LongInt;
  1620. var SmallerLevel: TImageData);
  1621. var
  1622. Filter: TSamplingFilter;
  1623. Info: TImageFormatInfo;
  1624. begin
  1625. Assert(TestImage(BiggerLevel));
  1626. Filter := TSamplingFilter(GetOption(ImagingMipMapFilter));
  1627. NewImage(Width, Height, BiggerLevel.Format, SmallerLevel);
  1628. GetImageFormatInfo(BiggerLevel.Format, Info);
  1629. if Filter = sfNearest then
  1630. begin
  1631. StretchNearest(BiggerLevel, 0, 0, BiggerLevel.Width, BiggerLevel.Height,
  1632. SmallerLevel, 0, 0, Width, Height);
  1633. end
  1634. else
  1635. begin
  1636. StretchResample(BiggerLevel, 0, 0, BiggerLevel.Width, BiggerLevel.Height,
  1637. SmallerLevel, 0, 0, Width, Height, Filter);
  1638. end;
  1639. end;
  1640. { Various format support functions }
  1641. procedure CopyPixel(Src, Dest: Pointer; BytesPerPixel: LongInt);
  1642. begin
  1643. case BytesPerPixel of
  1644. 1: PByte(Dest)^ := PByte(Src)^;
  1645. 2: PWord(Dest)^ := PWord(Src)^;
  1646. 3: PColor24Rec(Dest)^ := PColor24Rec(Src)^;
  1647. 4: PLongWord(Dest)^ := PLongWord(Src)^;
  1648. 6: PColor48Rec(Dest)^ := PColor48Rec(Src)^;
  1649. 8: PInt64(Dest)^ := PInt64(Src)^;
  1650. 16: PColorFPRec(Dest)^ := PColorFPRec(Src)^;
  1651. end;
  1652. end;
  1653. function ComparePixels(PixelA, PixelB: Pointer; BytesPerPixel: LongInt): Boolean;
  1654. begin
  1655. case BytesPerPixel of
  1656. 1: Result := PByte(PixelA)^ = PByte(PixelB)^;
  1657. 2: Result := PWord(PixelA)^ = PWord(PixelB)^;
  1658. 3: Result := (PWord(PixelA)^ = PWord(PixelB)^) and
  1659. (PColor24Rec(PixelA).R = PColor24Rec(PixelB).R);
  1660. 4: Result := PLongWord(PixelA)^ = PLongWord(PixelB)^;
  1661. 6: Result := (PLongWord(PixelA)^ = PLongWord(PixelB)^) and
  1662. (PColor48Rec(PixelA).R = PColor48Rec(PixelB).R);
  1663. 8: Result := PInt64(PixelA)^ = PInt64(PixelB)^;
  1664. 16: Result := (PFloatHelper(PixelA).Data2 = PFloatHelper(PixelB).Data2) and
  1665. (PFloatHelper(PixelA).Data1 = PFloatHelper(PixelB).Data1);
  1666. else
  1667. Result := False;
  1668. end;
  1669. end;
  1670. procedure TranslatePixel(SrcPixel, DstPixel: Pointer; SrcFormat,
  1671. DstFormat: TImageFormat; SrcPalette, DstPalette: PPalette32);
  1672. var
  1673. SrcInfo, DstInfo: PImageFormatInfo;
  1674. PixFP: TColorFPRec;
  1675. begin
  1676. SrcInfo := FInfos[SrcFormat];
  1677. DstInfo := FInfos[DstFormat];
  1678. PixFP := GetPixelFPGeneric(SrcPixel, SrcInfo, SrcPalette);
  1679. SetPixelFPGeneric(DstPixel, DstInfo, DstPalette, PixFP);
  1680. end;
  1681. procedure ClampFloatPixel(var PixF: TColorFPRec);
  1682. begin
  1683. if PixF.A > 1.0 then
  1684. PixF.A := 1.0;
  1685. if PixF.R > 1.0 then
  1686. PixF.R := 1.0;
  1687. if PixF.G > 1.0 then
  1688. PixF.G := 1.0;
  1689. if PixF.B > 1.0 then
  1690. PixF.B := 1.0;
  1691. if PixF.A < 0.0 then
  1692. PixF.A := 0.0;
  1693. if PixF.R < 0.0 then
  1694. PixF.R := 0.0;
  1695. if PixF.G < 0.0 then
  1696. PixF.G := 0.0;
  1697. if PixF.B < 0.0 then
  1698. PixF.B := 0.0;
  1699. end;
  1700. procedure AddPadBytes(DataIn: Pointer; DataOut: Pointer; Width, Height,
  1701. Bpp, WidthBytes: LongInt);
  1702. var
  1703. I, W: LongInt;
  1704. begin
  1705. W := Width * Bpp;
  1706. for I := 0 to Height - 1 do
  1707. Move(PByteArray(DataIn)[I * W], PByteArray(DataOut)[I * WidthBytes], W);
  1708. end;
  1709. procedure RemovePadBytes(DataIn: Pointer; DataOut: Pointer; Width, Height,
  1710. Bpp, WidthBytes: LongInt);
  1711. var
  1712. I, W: LongInt;
  1713. begin
  1714. W := Width * Bpp;
  1715. for I := 0 to Height - 1 do
  1716. Move(PByteArray(DataIn)[I * WidthBytes], PByteArray(DataOut)[I * W], W);
  1717. end;
  1718. function Has16BitImageAlpha(NumPixels: LongInt; Data: PWord): Boolean;
  1719. var
  1720. I: LongInt;
  1721. begin
  1722. Result := False;
  1723. for I := 0 to NumPixels - 1 do
  1724. begin
  1725. if Data^ >= 1 shl 15 then
  1726. begin
  1727. Result := True;
  1728. Exit;
  1729. end;
  1730. Inc(Data);
  1731. end;
  1732. end;
  1733. function GetScanLine(ImageBits: Pointer; const FormatInfo: TImageFormatInfo;
  1734. LineWidth, Index: LongInt): Pointer;
  1735. var
  1736. LineBytes: LongInt;
  1737. begin
  1738. Assert(not FormatInfo.IsSpecial);
  1739. LineBytes := FormatInfo.GetPixelsSize(FormatInfo.Format, LineWidth, 1);
  1740. Result := @PByteArray(ImageBits)[Index * LineBytes];
  1741. end;
  1742. function IsImageFormatValid(Format: TImageFormat): Boolean;
  1743. begin
  1744. Result := FInfos[Format] <> nil;
  1745. end;
  1746. const
  1747. HalfMin: Single = 5.96046448e-08; // Smallest positive half
  1748. HalfMinNorm: Single = 6.10351562e-05; // Smallest positive normalized half
  1749. HalfMax: Single = 65504.0; // Largest positive half
  1750. HalfEpsilon: Single = 0.00097656; // Smallest positive e for which half (1.0 + e) != half (1.0)
  1751. HalfNaN: THalfFloat = 65535;
  1752. HalfPosInf: THalfFloat = 31744;
  1753. HalfNegInf: THalfFloat = 64512;
  1754. {
  1755. Half/Float conversions inspired by half class from OpenEXR library.
  1756. Float (Pascal Single type) is an IEEE 754 single-precision
  1757. floating point number.
  1758. Bit layout of Single:
  1759. 31 (msb)
  1760. |
  1761. | 30 23
  1762. | | |
  1763. | | | 22 0 (lsb)
  1764. | | | | |
  1765. X XXXXXXXX XXXXXXXXXXXXXXXXXXXXXXX
  1766. s e m
  1767. Bit layout of half:
  1768. 15 (msb)
  1769. |
  1770. | 14 10
  1771. | | |
  1772. | | | 9 0 (lsb)
  1773. | | | | |
  1774. X XXXXX XXXXXXXXXX
  1775. s e m
  1776. S is the sign-bit, e is the exponent and m is the significand (mantissa).
  1777. }
  1778. function HalfToFloat(Half: THalfFloat): Single;
  1779. var
  1780. Dst, Sign, Mantissa: LongWord;
  1781. Exp: LongInt;
  1782. begin
  1783. // extract sign, exponent, and mantissa from half number
  1784. Sign := Half shr 15;
  1785. Exp := (Half and $7C00) shr 10;
  1786. Mantissa := Half and 1023;
  1787. if (Exp > 0) and (Exp < 31) then
  1788. begin
  1789. // common normalized number
  1790. Exp := Exp + (127 - 15);
  1791. Mantissa := Mantissa shl 13;
  1792. Dst := (Sign shl 31) or (LongWord(Exp) shl 23) or Mantissa;
  1793. // Result := Power(-1, Sign) * Power(2, Exp - 15) * (1 + Mantissa / 1024);
  1794. end
  1795. else if (Exp = 0) and (Mantissa = 0) then
  1796. begin
  1797. // zero - preserve sign
  1798. Dst := Sign shl 31;
  1799. end
  1800. else if (Exp = 0) and (Mantissa <> 0) then
  1801. begin
  1802. // denormalized number - renormalize it
  1803. while (Mantissa and $00000400) = 0 do
  1804. begin
  1805. Mantissa := Mantissa shl 1;
  1806. Dec(Exp);
  1807. end;
  1808. Inc(Exp);
  1809. Mantissa := Mantissa and not $00000400;
  1810. // now assemble normalized number
  1811. Exp := Exp + (127 - 15);
  1812. Mantissa := Mantissa shl 13;
  1813. Dst := (Sign shl 31) or (LongWord(Exp) shl 23) or Mantissa;
  1814. // Result := Power(-1, Sign) * Power(2, -14) * (Mantissa / 1024);
  1815. end
  1816. else if (Exp = 31) and (Mantissa = 0) then
  1817. begin
  1818. // +/- infinity
  1819. Dst := (Sign shl 31) or $7F800000;
  1820. end
  1821. else //if (Exp = 31) and (Mantisa <> 0) then
  1822. begin
  1823. // not a number - preserve sign and mantissa
  1824. Dst := (Sign shl 31) or $7F800000 or (Mantissa shl 13);
  1825. end;
  1826. // reinterpret LongWord as Single
  1827. Result := PSingle(@Dst)^;
  1828. end;
  1829. function FloatToHalf(Float: Single): THalfFloat;
  1830. var
  1831. Src: LongWord;
  1832. Sign, Exp, Mantissa: LongInt;
  1833. begin
  1834. Src := PLongWord(@Float)^;
  1835. // extract sign, exponent, and mantissa from Single number
  1836. Sign := Src shr 31;
  1837. Exp := LongInt((Src and $7F800000) shr 23) - 127 + 15;
  1838. Mantissa := Src and $007FFFFF;
  1839. if (Exp > 0) and (Exp < 30) then
  1840. begin
  1841. // simple case - round the significand and combine it with the sign and exponent
  1842. Result := (Sign shl 15) or (Exp shl 10) or ((Mantissa + $00001000) shr 13);
  1843. end
  1844. else if Src = 0 then
  1845. begin
  1846. // input float is zero - return zero
  1847. Result := 0;
  1848. end
  1849. else
  1850. begin
  1851. // difficult case - lengthy conversion
  1852. if Exp <= 0 then
  1853. begin
  1854. if Exp < -10 then
  1855. begin
  1856. // input float's value is less than HalfMin, return zero
  1857. Result := 0;
  1858. end
  1859. else
  1860. begin
  1861. // Float is a normalized Single whose magnitude is less than HalfNormMin.
  1862. // We convert it to denormalized half.
  1863. Mantissa := (Mantissa or $00800000) shr (1 - Exp);
  1864. // round to nearest
  1865. if (Mantissa and $00001000) > 0 then
  1866. Mantissa := Mantissa + $00002000;
  1867. // assemble Sign and Mantissa (Exp is zero to get denotmalized number)
  1868. Result := (Sign shl 15) or (Mantissa shr 13);
  1869. end;
  1870. end
  1871. else if Exp = 255 - 127 + 15 then
  1872. begin
  1873. if Mantissa = 0 then
  1874. begin
  1875. // input float is infinity, create infinity half with original sign
  1876. Result := (Sign shl 15) or $7C00;
  1877. end
  1878. else
  1879. begin
  1880. // input float is NaN, create half NaN with original sign and mantissa
  1881. Result := (Sign shl 15) or $7C00 or (Mantissa shr 13);
  1882. end;
  1883. end
  1884. else
  1885. begin
  1886. // Exp is > 0 so input float is normalized Single
  1887. // round to nearest
  1888. if (Mantissa and $00001000) > 0 then
  1889. begin
  1890. Mantissa := Mantissa + $00002000;
  1891. if (Mantissa and $00800000) > 0 then
  1892. begin
  1893. Mantissa := 0;
  1894. Exp := Exp + 1;
  1895. end;
  1896. end;
  1897. if Exp > 30 then
  1898. begin
  1899. // exponent overflow - return infinity half
  1900. Result := (Sign shl 15) or $7C00;
  1901. end
  1902. else
  1903. // assemble normalized half
  1904. Result := (Sign shl 15) or (Exp shl 10) or (Mantissa shr 13);
  1905. end;
  1906. end;
  1907. end;
  1908. function ColorHalfToFloat(ColorHF: TColorHFRec): TColorFPRec;
  1909. begin
  1910. Result.A := HalfToFloat(ColorHF.A);
  1911. Result.R := HalfToFloat(ColorHF.R);
  1912. Result.G := HalfToFloat(ColorHF.G);
  1913. Result.B := HalfToFloat(ColorHF.B);
  1914. end;
  1915. function ColorFloatToHalf(ColorFP: TColorFPRec): TColorHFRec;
  1916. begin
  1917. Result.A := FloatToHalf(ColorFP.A);
  1918. Result.R := FloatToHalf(ColorFP.R);
  1919. Result.G := FloatToHalf(ColorFP.G);
  1920. Result.B := FloatToHalf(ColorFP.B);
  1921. end;
  1922. { Pixel readers/writers for different image formats }
  1923. procedure ChannelGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo; var Pix:
  1924. TColor64Rec);
  1925. var
  1926. A, R, G, B: Byte;
  1927. begin
  1928. FillChar(Pix, SizeOf(Pix), 0);
  1929. // returns 64 bit color value with 16 bits for each channel
  1930. case SrcInfo.BytesPerPixel of
  1931. 1:
  1932. begin
  1933. PFGetARGB(SrcInfo.PixelFormat^, Src^, A, R, G, B);
  1934. Pix.A := A shl 8;
  1935. Pix.R := R shl 8;
  1936. Pix.G := G shl 8;
  1937. Pix.B := B shl 8;
  1938. end;
  1939. 2:
  1940. begin
  1941. PFGetARGB(SrcInfo.PixelFormat^, PWord(Src)^, A, R, G, B);
  1942. Pix.A := A shl 8;
  1943. Pix.R := R shl 8;
  1944. Pix.G := G shl 8;
  1945. Pix.B := B shl 8;
  1946. end;
  1947. 3:
  1948. with Pix do
  1949. begin
  1950. R := MulDiv(PColor24Rec(Src).R, 65535, 255);
  1951. G := MulDiv(PColor24Rec(Src).G, 65535, 255);
  1952. B := MulDiv(PColor24Rec(Src).B, 65535, 255);
  1953. end;
  1954. 4:
  1955. with Pix do
  1956. begin
  1957. A := MulDiv(PColor32Rec(Src).A, 65535, 255);
  1958. R := MulDiv(PColor32Rec(Src).R, 65535, 255);
  1959. G := MulDiv(PColor32Rec(Src).G, 65535, 255);
  1960. B := MulDiv(PColor32Rec(Src).B, 65535, 255);
  1961. end;
  1962. 6:
  1963. with Pix do
  1964. begin
  1965. R := PColor48Rec(Src).R;
  1966. G := PColor48Rec(Src).G;
  1967. B := PColor48Rec(Src).B;
  1968. end;
  1969. 8: Pix.Color := PColor64(Src)^;
  1970. end;
  1971. // if src has no alpha, we set it to max (otherwise we would have to
  1972. // test if dest has alpha or not in each ChannelToXXX function)
  1973. if not SrcInfo.HasAlphaChannel then
  1974. Pix.A := 65535;
  1975. if SrcInfo.IsRBSwapped then
  1976. SwapValues(Pix.R, Pix.B);
  1977. end;
  1978. procedure ChannelSetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo;
  1979. const Pix: TColor64Rec);
  1980. var
  1981. PixW: TColor64Rec;
  1982. begin
  1983. PixW := Pix;
  1984. if DstInfo.IsRBSwapped then
  1985. SwapValues(PixW.R, PixW.B);
  1986. // Pix contains 64 bit color value with 16 bit for each channel
  1987. case DstInfo.BytesPerPixel of
  1988. 1: Dst^ := PFSetARGB(DstInfo.PixelFormat^, PixW.A shr 8,
  1989. PixW.R shr 8, PixW.G shr 8, PixW.B shr 8);
  1990. 2: PWord(Dst)^ := PFSetARGB(DstInfo.PixelFormat^, PixW.A shr 8,
  1991. PixW.R shr 8, PixW.G shr 8, PixW.B shr 8);
  1992. 3:
  1993. with PColor24Rec(Dst)^ do
  1994. begin
  1995. R := MulDiv(PixW.R, 255, 65535);
  1996. G := MulDiv(PixW.G, 255, 65535);
  1997. B := MulDiv(PixW.B, 255, 65535);
  1998. end;
  1999. 4:
  2000. with PColor32Rec(Dst)^ do
  2001. begin
  2002. A := MulDiv(PixW.A, 255, 65535);
  2003. R := MulDiv(PixW.R, 255, 65535);
  2004. G := MulDiv(PixW.G, 255, 65535);
  2005. B := MulDiv(PixW.B, 255, 65535);
  2006. end;
  2007. 6:
  2008. with PColor48Rec(Dst)^ do
  2009. begin
  2010. R := PixW.R;
  2011. G := PixW.G;
  2012. B := PixW.B;
  2013. end;
  2014. 8: PColor64(Dst)^ := PixW.Color;
  2015. end;
  2016. end;
  2017. procedure GrayGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo;
  2018. var Gray: TColor64Rec; var Alpha: Word);
  2019. begin
  2020. FillChar(Gray, SizeOf(Gray), 0);
  2021. // Source alpha is scaled to 16 bits and stored in Alpha,
  2022. // grayscale value is scaled to 64 bits and stored in Gray
  2023. case SrcInfo.BytesPerPixel of
  2024. 1: Gray.A := MulDiv(Src^, 65535, 255);
  2025. 2:
  2026. if SrcInfo.HasAlphaChannel then
  2027. with PWordRec(Src)^ do
  2028. begin
  2029. Alpha := MulDiv(High, 65535, 255);
  2030. Gray.A := MulDiv(Low, 65535, 255);
  2031. end
  2032. else
  2033. Gray.A := PWord(Src)^;
  2034. 4:
  2035. if SrcInfo.HasAlphaChannel then
  2036. with PLongWordRec(Src)^ do
  2037. begin
  2038. Alpha := High;
  2039. Gray.A := Low;
  2040. end
  2041. else
  2042. with PLongWordRec(Src)^ do
  2043. begin
  2044. Gray.A := High;
  2045. Gray.R := Low;
  2046. end;
  2047. 8: Gray.Color := PColor64(Src)^;
  2048. end;
  2049. // if src has no alpha, we set it to max (otherwise we would have to
  2050. // test if dest has alpha or not in each GrayToXXX function)
  2051. if not SrcInfo.HasAlphaChannel then
  2052. Alpha := 65535;
  2053. end;
  2054. procedure GraySetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo;
  2055. const Gray: TColor64Rec; Alpha: Word);
  2056. begin
  2057. // Gray contains grayscale value scaled to 64 bits, Alpha contains
  2058. // alpha value scaled to 16 bits
  2059. case DstInfo.BytesPerPixel of
  2060. 1: Dst^ := MulDiv(Gray.A, 255, 65535);
  2061. 2:
  2062. if DstInfo.HasAlphaChannel then
  2063. with PWordRec(Dst)^ do
  2064. begin
  2065. High := MulDiv(Alpha, 255, 65535);
  2066. Low := MulDiv(Gray.A, 255, 65535);
  2067. end
  2068. else
  2069. PWord(Dst)^ := Gray.A;
  2070. 4:
  2071. if DstInfo.HasAlphaChannel then
  2072. with PLongWordRec(Dst)^ do
  2073. begin
  2074. High := Alpha;
  2075. Low := Gray.A;
  2076. end
  2077. else
  2078. with PLongWordRec(Dst)^ do
  2079. begin
  2080. High := Gray.A;
  2081. Low := Gray.R;
  2082. end;
  2083. 8: PColor64(Dst)^ := Gray.Color;
  2084. end;
  2085. end;
  2086. procedure FloatGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo;
  2087. var Pix: TColorFPRec);
  2088. var
  2089. PixHF: TColorHFRec;
  2090. begin
  2091. if SrcInfo.BytesPerPixel in [4, 16] then
  2092. begin
  2093. // IEEE 754 single-precision channels
  2094. FillChar(Pix, SizeOf(Pix), 0);
  2095. case SrcInfo.BytesPerPixel of
  2096. 4: Pix.R := PSingle(Src)^;
  2097. 16: Pix := PColorFPRec(Src)^;
  2098. end;
  2099. end
  2100. else
  2101. begin
  2102. // half float channels
  2103. FillChar(PixHF, SizeOf(PixHF), 0);
  2104. case SrcInfo.BytesPerPixel of
  2105. 2: PixHF.R := PHalfFloat(Src)^;
  2106. 8: PixHF := PColorHFRec(Src)^;
  2107. end;
  2108. Pix := ColorHalfToFloat(PixHF);
  2109. end;
  2110. // if src has no alpha, we set it to max (otherwise we would have to
  2111. // test if dest has alpha or not in each FloatToXXX function)
  2112. if not SrcInfo.HasAlphaChannel then
  2113. Pix.A := 1.0;
  2114. if SrcInfo.IsRBSwapped then
  2115. SwapValues(Pix.R, Pix.B);
  2116. end;
  2117. procedure FloatSetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo;
  2118. const Pix: TColorFPRec);
  2119. var
  2120. PixW: TColorFPRec;
  2121. PixHF: TColorHFRec;
  2122. begin
  2123. PixW := Pix;
  2124. if DstInfo.IsRBSwapped then
  2125. SwapValues(PixW.R, PixW.B);
  2126. if DstInfo.BytesPerPixel in [4, 16] then
  2127. begin
  2128. case DstInfo.BytesPerPixel of
  2129. 4: PSingle(Dst)^ := PixW.R;
  2130. 16: PColorFPRec(Dst)^ := PixW;
  2131. end;
  2132. end
  2133. else
  2134. begin
  2135. PixHF := ColorFloatToHalf(PixW);
  2136. case DstInfo.BytesPerPixel of
  2137. 2: PHalfFloat(Dst)^ := PixHF.R;
  2138. 8: PColorHFRec(Dst)^ := PixHF;
  2139. end;
  2140. end;
  2141. end;
  2142. procedure IndexGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo;
  2143. var Index: LongWord);
  2144. begin
  2145. case SrcInfo.BytesPerPixel of
  2146. 1: Index := Src^;
  2147. end;
  2148. end;
  2149. procedure IndexSetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo;
  2150. Index: LongWord);
  2151. begin
  2152. case DstInfo.BytesPerPixel of
  2153. 1: Dst^ := Byte(Index);
  2154. 2: PWord(Dst)^ := Word(Index);
  2155. 4: PLongWord(Dst)^ := Index;
  2156. end;
  2157. end;
  2158. { Pixel readers/writers for 32bit and FP colors}
  2159. function GetPixel32Generic(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColor32Rec;
  2160. var
  2161. Pix64: TColor64Rec;
  2162. PixF: TColorFPRec;
  2163. Alpha: Word;
  2164. Index: LongWord;
  2165. begin
  2166. if Info.Format = ifA8R8G8B8 then
  2167. begin
  2168. Result := PColor32Rec(Bits)^
  2169. end
  2170. else if Info.Format = ifR8G8B8 then
  2171. begin
  2172. PColor24Rec(@Result)^ := PColor24Rec(Bits)^;
  2173. Result.A := $FF;
  2174. end
  2175. else if Info.IsFloatingPoint then
  2176. begin
  2177. FloatGetSrcPixel(Bits, Info, PixF);
  2178. Result.A := ClampToByte(Round(PixF.A * 255.0));
  2179. Result.R := ClampToByte(Round(PixF.R * 255.0));
  2180. Result.G := ClampToByte(Round(PixF.G * 255.0));
  2181. Result.B := ClampToByte(Round(PixF.B * 255.0));
  2182. end
  2183. else if Info.HasGrayChannel then
  2184. begin
  2185. GrayGetSrcPixel(Bits, Info, Pix64, Alpha);
  2186. Result.A := MulDiv(Alpha, 255, 65535);
  2187. Result.R := MulDiv(Pix64.A, 255, 65535);
  2188. Result.G := MulDiv(Pix64.A, 255, 65535);
  2189. Result.B := MulDiv(Pix64.A, 255, 65535);
  2190. end
  2191. else if Info.IsIndexed then
  2192. begin
  2193. IndexGetSrcPixel(Bits, Info, Index);
  2194. Result := Palette[Index];
  2195. end
  2196. else
  2197. begin
  2198. ChannelGetSrcPixel(Bits, Info, Pix64);
  2199. Result.A := MulDiv(Pix64.A, 255, 65535);
  2200. Result.R := MulDiv(Pix64.R, 255, 65535);
  2201. Result.G := MulDiv(Pix64.G, 255, 65535);
  2202. Result.B := MulDiv(Pix64.B, 255, 65535);
  2203. end;
  2204. end;
  2205. procedure SetPixel32Generic(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColor32Rec);
  2206. var
  2207. Pix64: TColor64Rec;
  2208. PixF: TColorFPRec;
  2209. Alpha: Word;
  2210. Index: LongWord;
  2211. begin
  2212. if Info.Format = ifA8R8G8B8 then
  2213. begin
  2214. PColor32Rec(Bits)^ := Color
  2215. end
  2216. else if Info.Format = ifR8G8B8 then
  2217. begin
  2218. PColor24Rec(Bits)^ := Color.Color24Rec;
  2219. end
  2220. else if Info.IsFloatingPoint then
  2221. begin
  2222. PixF.A := Color.A * OneDiv8Bit;
  2223. PixF.R := Color.R * OneDiv8Bit;
  2224. PixF.G := Color.G * OneDiv8Bit;
  2225. PixF.B := Color.B * OneDiv8Bit;
  2226. FloatSetDstPixel(Bits, Info, PixF);
  2227. end
  2228. else if Info.HasGrayChannel then
  2229. begin
  2230. Alpha := MulDiv(Color.A, 65535, 255);
  2231. Pix64.Color := 0;
  2232. Pix64.A := MulDiv(Round(GrayConv.R * Color.R + GrayConv.G * Color.G +
  2233. GrayConv.B * Color.B), 65535, 255);
  2234. GraySetDstPixel(Bits, Info, Pix64, Alpha);
  2235. end
  2236. else if Info.IsIndexed then
  2237. begin
  2238. Index := FindColor(Palette, Info.PaletteEntries, Color.Color);
  2239. IndexSetDstPixel(Bits, Info, Index);
  2240. end
  2241. else
  2242. begin
  2243. Pix64.A := MulDiv(Color.A, 65535, 255);
  2244. Pix64.R := MulDiv(Color.R, 65535, 255);
  2245. Pix64.G := MulDiv(Color.G, 65535, 255);
  2246. Pix64.B := MulDiv(Color.B, 65535, 255);
  2247. ChannelSetDstPixel(Bits, Info, Pix64);
  2248. end;
  2249. end;
  2250. function GetPixelFPGeneric(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec;
  2251. var
  2252. Pix32: TColor32Rec;
  2253. Pix64: TColor64Rec;
  2254. Alpha: Word;
  2255. Index: LongWord;
  2256. begin
  2257. if Info.IsFloatingPoint then
  2258. begin
  2259. FloatGetSrcPixel(Bits, Info, Result);
  2260. end
  2261. else if Info.HasGrayChannel then
  2262. begin
  2263. GrayGetSrcPixel(Bits, Info, Pix64, Alpha);
  2264. Result.A := Alpha * OneDiv16Bit;
  2265. Result.R := Pix64.A * OneDiv16Bit;
  2266. Result.G := Pix64.A * OneDiv16Bit;
  2267. Result.B := Pix64.A * OneDiv16Bit;
  2268. end
  2269. else if Info.IsIndexed then
  2270. begin
  2271. IndexGetSrcPixel(Bits, Info, Index);
  2272. Pix32 := Palette[Index];
  2273. Result.A := Pix32.A * OneDiv8Bit;
  2274. Result.R := Pix32.R * OneDiv8Bit;
  2275. Result.G := Pix32.G * OneDiv8Bit;
  2276. Result.B := Pix32.B * OneDiv8Bit;
  2277. end
  2278. else
  2279. begin
  2280. ChannelGetSrcPixel(Bits, Info, Pix64);
  2281. Result.A := Pix64.A * OneDiv16Bit;
  2282. Result.R := Pix64.R * OneDiv16Bit;
  2283. Result.G := Pix64.G * OneDiv16Bit;
  2284. Result.B := Pix64.B * OneDiv16Bit;
  2285. end;
  2286. end;
  2287. procedure SetPixelFPGeneric(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec);
  2288. var
  2289. Pix32: TColor32Rec;
  2290. Pix64: TColor64Rec;
  2291. Alpha: Word;
  2292. Index: LongWord;
  2293. begin
  2294. if Info.IsFloatingPoint then
  2295. begin
  2296. FloatSetDstPixel(Bits, Info, Color);
  2297. end
  2298. else if Info.HasGrayChannel then
  2299. begin
  2300. Alpha := ClampToWord(Round(Color.A * 65535.0));
  2301. Pix64.Color := 0;
  2302. Pix64.A := ClampToWord(Round((GrayConv.R * Color.R + GrayConv.G * Color.G +
  2303. GrayConv.B * Color.B) * 65535.0));
  2304. GraySetDstPixel(Bits, Info, Pix64, Alpha);
  2305. end
  2306. else if Info.IsIndexed then
  2307. begin
  2308. Pix32.A := ClampToByte(Round(Color.A * 255.0));
  2309. Pix32.R := ClampToByte(Round(Color.R * 255.0));
  2310. Pix32.G := ClampToByte(Round(Color.G * 255.0));
  2311. Pix32.B := ClampToByte(Round(Color.B * 255.0));
  2312. Index := FindColor(Palette, Info.PaletteEntries, Pix32.Color);
  2313. IndexSetDstPixel(Bits, Info, Index);
  2314. end
  2315. else
  2316. begin
  2317. Pix64.A := ClampToWord(Round(Color.A * 65535.0));
  2318. Pix64.R := ClampToWord(Round(Color.R * 65535.0));
  2319. Pix64.G := ClampToWord(Round(Color.G * 65535.0));
  2320. Pix64.B := ClampToWord(Round(Color.B * 65535.0));
  2321. ChannelSetDstPixel(Bits, Info, Pix64);
  2322. end;
  2323. end;
  2324. { Image format conversion functions }
  2325. procedure ChannelToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  2326. DstInfo: PImageFormatInfo);
  2327. var
  2328. I: LongInt;
  2329. Pix64: TColor64Rec;
  2330. begin
  2331. // two most common conversions (RGB->ARGB and ARGB->RGB for 24/32 bit
  2332. // images) are made separately from general ARGB conversion to
  2333. // make them faster
  2334. if (SrcInfo.BytesPerPixel = 3) and (DstInfo.BytesPerPixel = 4) then
  2335. for I := 0 to NumPixels - 1 do
  2336. begin
  2337. PColor24Rec(Dst)^ := PColor24Rec(Src)^;
  2338. PColor32Rec(Dst).A := 255;
  2339. Inc(Src, SrcInfo.BytesPerPixel);
  2340. Inc(Dst, DstInfo.BytesPerPixel);
  2341. end
  2342. else
  2343. if (SrcInfo.BytesPerPixel = 4) and (DstInfo.BytesPerPixel = 3) then
  2344. for I := 0 to NumPixels - 1 do
  2345. begin
  2346. PColor24Rec(Dst)^ := PColor24Rec(Src)^;
  2347. Inc(Src, SrcInfo.BytesPerPixel);
  2348. Inc(Dst, DstInfo.BytesPerPixel);
  2349. end
  2350. else
  2351. for I := 0 to NumPixels - 1 do
  2352. begin
  2353. // general ARGB conversion
  2354. ChannelGetSrcPixel(Src, SrcInfo, Pix64);
  2355. ChannelSetDstPixel(Dst, DstInfo, Pix64);
  2356. Inc(Src, SrcInfo.BytesPerPixel);
  2357. Inc(Dst, DstInfo.BytesPerPixel);
  2358. end;
  2359. end;
  2360. procedure ChannelToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  2361. DstInfo: PImageFormatInfo);
  2362. var
  2363. I: LongInt;
  2364. Pix64: TColor64Rec;
  2365. Alpha: Word;
  2366. begin
  2367. // two most common conversions (R8G8B8->Gray8 nad A8R8G8B8->Gray8)
  2368. // are made separately from general conversions to make them faster
  2369. if (SrcInfo.BytesPerPixel in [3, 4]) and (DstInfo.Format = ifGray8) then
  2370. for I := 0 to NumPixels - 1 do
  2371. begin
  2372. Dst^ := Round(GrayConv.R * PColor24Rec(Src).R + GrayConv.G * PColor24Rec(Src).G +
  2373. GrayConv.B * PColor24Rec(Src).B);
  2374. Inc(Src, SrcInfo.BytesPerPixel);
  2375. Inc(Dst, DstInfo.BytesPerPixel);
  2376. end
  2377. else
  2378. for I := 0 to NumPixels - 1 do
  2379. begin
  2380. ChannelGetSrcPixel(Src, SrcInfo, Pix64);
  2381. // alpha is saved from source pixel to Alpha,
  2382. // Gray value is computed and set to highest word of Pix64 so
  2383. // Pix64.Color contains grayscale value scaled to 64 bits
  2384. Alpha := Pix64.A;
  2385. with GrayConv do
  2386. Pix64.A := Round(R * Pix64.R + G * Pix64.G + B * Pix64.B);
  2387. GraySetDstPixel(Dst, DstInfo, Pix64, Alpha);
  2388. Inc(Src, SrcInfo.BytesPerPixel);
  2389. Inc(Dst, DstInfo.BytesPerPixel);
  2390. end;
  2391. end;
  2392. procedure ChannelToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  2393. DstInfo: PImageFormatInfo);
  2394. var
  2395. I: LongInt;
  2396. Pix64: TColor64Rec;
  2397. PixF: TColorFPRec;
  2398. begin
  2399. for I := 0 to NumPixels - 1 do
  2400. begin
  2401. ChannelGetSrcPixel(Src, SrcInfo, Pix64);
  2402. // floating point channel values are scaled to 1.0
  2403. PixF.A := Pix64.A * OneDiv16Bit;
  2404. PixF.R := Pix64.R * OneDiv16Bit;
  2405. PixF.G := Pix64.G * OneDiv16Bit;
  2406. PixF.B := Pix64.B * OneDiv16Bit;
  2407. FloatSetDstPixel(Dst, DstInfo, PixF);
  2408. Inc(Src, SrcInfo.BytesPerPixel);
  2409. Inc(Dst, DstInfo.BytesPerPixel);
  2410. end;
  2411. end;
  2412. procedure ChannelToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  2413. DstInfo: PImageFormatInfo; DstPal: PPalette32);
  2414. begin
  2415. ReduceColorsMedianCut(NumPixels, Src, Dst, SrcInfo, DstInfo, DstInfo.PaletteEntries,
  2416. GetOption(ImagingColorReductionMask), DstPal);
  2417. end;
  2418. procedure GrayToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  2419. DstInfo: PImageFormatInfo);
  2420. var
  2421. I: LongInt;
  2422. Gray: TColor64Rec;
  2423. Alpha: Word;
  2424. begin
  2425. // two most common conversions (Gray8->Gray16 nad Gray16->Gray8)
  2426. // are made separately from general conversions to make them faster
  2427. if (SrcInfo.Format = ifGray8) and (DstInfo.Format = ifGray16) then
  2428. begin
  2429. for I := 0 to NumPixels - 1 do
  2430. PWordArray(Dst)[I] := PByteArray(Src)[I] shl 8;
  2431. end
  2432. else
  2433. if (DstInfo.Format = ifGray8) and (SrcInfo.Format = ifGray16) then
  2434. begin
  2435. for I := 0 to NumPixels - 1 do
  2436. PByteArray(Dst)[I] := PWordArray(Src)[I] shr 8;
  2437. end
  2438. else
  2439. for I := 0 to NumPixels - 1 do
  2440. begin
  2441. // general grayscale conversion
  2442. GrayGetSrcPixel(Src, SrcInfo, Gray, Alpha);
  2443. GraySetDstPixel(Dst, DstInfo, Gray, Alpha);
  2444. Inc(Src, SrcInfo.BytesPerPixel);
  2445. Inc(Dst, DstInfo.BytesPerPixel);
  2446. end;
  2447. end;
  2448. procedure GrayToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  2449. DstInfo: PImageFormatInfo);
  2450. var
  2451. I: LongInt;
  2452. Pix64: TColor64Rec;
  2453. Alpha: Word;
  2454. begin
  2455. // two most common conversions (Gray8->R8G8B8 nad Gray8->A8R8G8B8)
  2456. // are made separately from general conversions to make them faster
  2457. if (DstInfo.BytesPerPixel in [3, 4]) and (SrcInfo.Format = ifGray8) then
  2458. for I := 0 to NumPixels - 1 do
  2459. begin
  2460. PColor24Rec(Dst).R := Src^;
  2461. PColor24Rec(Dst).G := Src^;
  2462. PColor24Rec(Dst).B := Src^;
  2463. if DstInfo.HasAlphaChannel then
  2464. PColor32Rec(Dst).A := $FF;
  2465. Inc(Src, SrcInfo.BytesPerPixel);
  2466. Inc(Dst, DstInfo.BytesPerPixel);
  2467. end
  2468. else
  2469. for I := 0 to NumPixels - 1 do
  2470. begin
  2471. GrayGetSrcPixel(Src, SrcInfo, Pix64, Alpha);
  2472. // most significant word of grayscale value is used for
  2473. // each channel and alpha channel is set to Alpha
  2474. Pix64.R := Pix64.A;
  2475. Pix64.G := Pix64.A;
  2476. Pix64.B := Pix64.A;
  2477. Pix64.A := Alpha;
  2478. ChannelSetDstPixel(Dst, DstInfo, Pix64);
  2479. Inc(Src, SrcInfo.BytesPerPixel);
  2480. Inc(Dst, DstInfo.BytesPerPixel);
  2481. end;
  2482. end;
  2483. procedure GrayToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  2484. DstInfo: PImageFormatInfo);
  2485. var
  2486. I: LongInt;
  2487. Gray: TColor64Rec;
  2488. PixF: TColorFPRec;
  2489. Alpha: Word;
  2490. begin
  2491. for I := 0 to NumPixels - 1 do
  2492. begin
  2493. GrayGetSrcPixel(Src, SrcInfo, Gray, Alpha);
  2494. // most significant word of grayscale value is used for
  2495. // each channel and alpha channel is set to Alpha
  2496. // then all is scaled to 0..1
  2497. PixF.R := Gray.A * OneDiv16Bit;
  2498. PixF.G := Gray.A * OneDiv16Bit;
  2499. PixF.B := Gray.A * OneDiv16Bit;
  2500. PixF.A := Alpha * OneDiv16Bit;
  2501. FloatSetDstPixel(Dst, DstInfo, PixF);
  2502. Inc(Src, SrcInfo.BytesPerPixel);
  2503. Inc(Dst, DstInfo.BytesPerPixel);
  2504. end;
  2505. end;
  2506. procedure GrayToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  2507. DstInfo: PImageFormatInfo; DstPal: PPalette32);
  2508. var
  2509. I: LongInt;
  2510. Idx: LongWord;
  2511. Gray: TColor64Rec;
  2512. Alpha, Shift: Word;
  2513. begin
  2514. FillGrayscalePalette(DstPal, DstInfo.PaletteEntries);
  2515. Shift := Log2Int(DstInfo.PaletteEntries);
  2516. // most common conversion (Gray8->Index8)
  2517. // is made separately from general conversions to make it faster
  2518. if (SrcInfo.Format = ifGray8) and (DstInfo.Format = ifIndex8) then
  2519. for I := 0 to NumPixels - 1 do
  2520. begin
  2521. Dst^ := Src^;
  2522. Inc(Src, SrcInfo.BytesPerPixel);
  2523. Inc(Dst, DstInfo.BytesPerPixel);
  2524. end
  2525. else
  2526. for I := 0 to NumPixels - 1 do
  2527. begin
  2528. // gray value is read from src and index to precomputed
  2529. // grayscale palette is computed and written to dst
  2530. // (we assume here that there will be no more than 65536 palette
  2531. // entries in dst format, gray value is shifted so the highest
  2532. // gray value match the highest possible index in palette)
  2533. GrayGetSrcPixel(Src, SrcInfo, Gray, Alpha);
  2534. Idx := Gray.A shr (16 - Shift);
  2535. IndexSetDstPixel(Dst, DstInfo, Idx);
  2536. Inc(Src, SrcInfo.BytesPerPixel);
  2537. Inc(Dst, DstInfo.BytesPerPixel);
  2538. end;
  2539. end;
  2540. procedure FloatToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  2541. DstInfo: PImageFormatInfo);
  2542. var
  2543. I: LongInt;
  2544. PixF: TColorFPRec;
  2545. begin
  2546. for I := 0 to NumPixels - 1 do
  2547. begin
  2548. // general floating point conversion
  2549. FloatGetSrcPixel(Src, SrcInfo, PixF);
  2550. FloatSetDstPixel(Dst, DstInfo, PixF);
  2551. Inc(Src, SrcInfo.BytesPerPixel);
  2552. Inc(Dst, DstInfo.BytesPerPixel);
  2553. end;
  2554. end;
  2555. procedure FloatToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  2556. DstInfo: PImageFormatInfo);
  2557. var
  2558. I: LongInt;
  2559. Pix64: TColor64Rec;
  2560. PixF: TColorFPRec;
  2561. begin
  2562. for I := 0 to NumPixels - 1 do
  2563. begin
  2564. FloatGetSrcPixel(Src, SrcInfo, PixF);
  2565. ClampFloatPixel(PixF);
  2566. // floating point channel values are scaled to 1.0
  2567. Pix64.A := ClampToWord(Round(PixF.A * 65535));
  2568. Pix64.R := ClampToWord(Round(PixF.R * 65535));
  2569. Pix64.G := ClampToWord(Round(PixF.G * 65535));
  2570. Pix64.B := ClampToWord(Round(PixF.B * 65535));
  2571. ChannelSetDstPixel(Dst, DstInfo, Pix64);
  2572. Inc(Src, SrcInfo.BytesPerPixel);
  2573. Inc(Dst, DstInfo.BytesPerPixel);
  2574. end;
  2575. end;
  2576. procedure FloatToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  2577. DstInfo: PImageFormatInfo);
  2578. var
  2579. I: LongInt;
  2580. PixF: TColorFPRec;
  2581. Gray: TColor64Rec;
  2582. Alpha: Word;
  2583. begin
  2584. for I := 0 to NumPixels - 1 do
  2585. begin
  2586. FloatGetSrcPixel(Src, SrcInfo, PixF);
  2587. ClampFloatPixel(PixF);
  2588. // alpha is saved from source pixel to Alpha,
  2589. // Gray value is computed and set to highest word of Pix64 so
  2590. // Pix64.Color contains grayscale value scaled to 64 bits
  2591. Alpha := ClampToWord(Round(PixF.A * 65535.0));
  2592. Gray.A := ClampToWord(Round((GrayConv.R * PixF.R + GrayConv.G * PixF.G +
  2593. GrayConv.B * PixF.B) * 65535.0));
  2594. GraySetDstPixel(Dst, DstInfo, Gray, Alpha);
  2595. Inc(Src, SrcInfo.BytesPerPixel);
  2596. Inc(Dst, DstInfo.BytesPerPixel);
  2597. end;
  2598. end;
  2599. procedure FloatToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  2600. DstInfo: PImageFormatInfo; DstPal: PPalette32);
  2601. begin
  2602. ReduceColorsMedianCut(NumPixels, Src, Dst, SrcInfo, DstInfo, DstInfo.PaletteEntries,
  2603. GetOption(ImagingColorReductionMask), DstPal);
  2604. end;
  2605. procedure IndexToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  2606. DstInfo: PImageFormatInfo; SrcPal, DstPal: PPalette32);
  2607. var
  2608. I: LongInt;
  2609. begin
  2610. // there is only one indexed format now, so it is just a copy
  2611. for I := 0 to NumPixels - 1 do
  2612. begin
  2613. Dst^ := Src^;
  2614. Inc(Src, SrcInfo.BytesPerPixel);
  2615. Inc(Dst, DstInfo.BytesPerPixel);
  2616. end;
  2617. for I := 0 to SrcInfo.PaletteEntries - 1 do
  2618. DstPal[I] := SrcPal[I];
  2619. end;
  2620. procedure IndexToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  2621. DstInfo: PImageFormatInfo; SrcPal: PPalette32);
  2622. var
  2623. I: LongInt;
  2624. Pix64: TColor64Rec;
  2625. Idx: LongWord;
  2626. begin
  2627. // two most common conversions (Index8->R8G8B8 nad Index8->A8R8G8B8)
  2628. // are made separately from general conversions to make them faster
  2629. if (SrcInfo.Format = ifIndex8) and (DstInfo.Format in [ifR8G8B8, ifA8R8G8B8]) then
  2630. for I := 0 to NumPixels - 1 do
  2631. begin
  2632. with PColor24Rec(Dst)^ do
  2633. begin
  2634. R := SrcPal[Src^].R;
  2635. G := SrcPal[Src^].G;
  2636. B := SrcPal[Src^].B;
  2637. end;
  2638. if DstInfo.Format = ifA8R8G8B8 then
  2639. PColor32Rec(Dst).A := SrcPal[Src^].A;
  2640. Inc(Src, SrcInfo.BytesPerPixel);
  2641. Inc(Dst, DstInfo.BytesPerPixel);
  2642. end
  2643. else
  2644. for I := 0 to NumPixels - 1 do
  2645. begin
  2646. // index to palette is read from source and color
  2647. // is retrieved from palette entry. Color is then
  2648. // scaled to 16bits and written to dest
  2649. IndexGetSrcPixel(Src, SrcInfo, Idx);
  2650. with Pix64 do
  2651. begin
  2652. A := SrcPal[Idx].A shl 8;
  2653. R := SrcPal[Idx].R shl 8;
  2654. G := SrcPal[Idx].G shl 8;
  2655. B := SrcPal[Idx].B shl 8;
  2656. end;
  2657. ChannelSetDstPixel(Dst, DstInfo, Pix64);
  2658. Inc(Src, SrcInfo.BytesPerPixel);
  2659. Inc(Dst, DstInfo.BytesPerPixel);
  2660. end;
  2661. end;
  2662. procedure IndexToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  2663. DstInfo: PImageFormatInfo; SrcPal: PPalette32);
  2664. var
  2665. I: LongInt;
  2666. Gray: TColor64Rec;
  2667. Alpha: Word;
  2668. Idx: LongWord;
  2669. begin
  2670. // most common conversion (Index8->Gray8)
  2671. // is made separately from general conversions to make it faster
  2672. if (SrcInfo.Format = ifIndex8) and (DstInfo.Format = ifGray8) then
  2673. begin
  2674. for I := 0 to NumPixels - 1 do
  2675. begin
  2676. Dst^ := Round(GrayConv.R * SrcPal[Src^].R + GrayConv.G * SrcPal[Src^].G +
  2677. GrayConv.B * SrcPal[Src^].B);
  2678. Inc(Src, SrcInfo.BytesPerPixel);
  2679. Inc(Dst, DstInfo.BytesPerPixel);
  2680. end
  2681. end
  2682. else
  2683. for I := 0 to NumPixels - 1 do
  2684. begin
  2685. // index to palette is read from source and color
  2686. // is retrieved from palette entry. Color is then
  2687. // transformed to grayscale and assigned to the highest
  2688. // byte of Gray value
  2689. IndexGetSrcPixel(Src, SrcInfo, Idx);
  2690. Alpha := SrcPal[Idx].A shl 8;
  2691. Gray.A := MulDiv(Round(GrayConv.R * SrcPal[Idx].R + GrayConv.G * SrcPal[Idx].G +
  2692. GrayConv.B * SrcPal[Idx].B), 65535, 255);
  2693. GraySetDstPixel(Dst, DstInfo, Gray, Alpha);
  2694. Inc(Src, SrcInfo.BytesPerPixel);
  2695. Inc(Dst, DstInfo.BytesPerPixel);
  2696. end;
  2697. end;
  2698. procedure IndexToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  2699. DstInfo: PImageFormatInfo; SrcPal: PPalette32);
  2700. var
  2701. I: LongInt;
  2702. Idx: LongWord;
  2703. PixF: TColorFPRec;
  2704. begin
  2705. for I := 0 to NumPixels - 1 do
  2706. begin
  2707. // index to palette is read from source and color
  2708. // is retrieved from palette entry. Color is then
  2709. // scaled to 0..1 and written to dest
  2710. IndexGetSrcPixel(Src, SrcInfo, Idx);
  2711. with PixF do
  2712. begin
  2713. A := SrcPal[Idx].A * OneDiv8Bit;
  2714. R := SrcPal[Idx].R * OneDiv8Bit;
  2715. G := SrcPal[Idx].G * OneDiv8Bit;
  2716. B := SrcPal[Idx].B * OneDiv8Bit;
  2717. end;
  2718. FloatSetDstPixel(Dst, DstInfo, PixF);
  2719. Inc(Src, SrcInfo.BytesPerPixel);
  2720. Inc(Dst, DstInfo.BytesPerPixel);
  2721. end;
  2722. end;
  2723. { Special formats conversion functions }
  2724. var
  2725. UnSpecialFormat: TImageFormat = ifA8R8G8B8;
  2726. type
  2727. // DXT RGB color block
  2728. TDXTColorBlock = packed record
  2729. Color0, Color1: Word;
  2730. Mask: LongWord;
  2731. end;
  2732. PDXTColorBlock = ^TDXTColorBlock;
  2733. // DXT explicit alpha for a block
  2734. TDXTAlphaBlockExp = packed record
  2735. Alphas: array[0..3] of Word;
  2736. end;
  2737. PDXTAlphaBlockExp = ^TDXTAlphaBlockExp;
  2738. // DXT interpolated alpha for a block
  2739. TDXTAlphaBlockInt = packed record
  2740. Alphas: array[0..7] of Byte;
  2741. end;
  2742. PDXTAlphaBlockInt = ^TDXTAlphaBlockInt;
  2743. TPixelInfo = record
  2744. Color: Word;
  2745. Alpha: Byte;
  2746. Orig: TColor32Rec;
  2747. end;
  2748. TPixelBlock = array[0..15] of TPixelInfo;
  2749. function DecodeCol(Color : Word): TColor32Rec;
  2750. {$IFDEF USE_INLINE} inline; {$ENDIF}
  2751. begin
  2752. Result.A := $FF;
  2753. {Result.R := ((Color and $F800) shr 11) shl 3;
  2754. Result.G := ((Color and $07E0) shr 5) shl 2;
  2755. Result.B := (Color and $001F) shl 3;}
  2756. // this color expansion is slower but gives better results
  2757. Result.R := (Color shr 11) * 255 div 31;
  2758. Result.G := ((Color shr 5) and $3F) * 255 div 63;
  2759. Result.B := (Color and $1F) * 255 div 31;
  2760. end;
  2761. procedure DecodeDXT1(SrcBits, DestBits: PByte; Width, Height: LongInt);
  2762. var
  2763. Sel, X, Y, I, J, K: LongInt;
  2764. Block: TDXTColorBlock;
  2765. Colors: array[0..3] of TColor32Rec;
  2766. begin
  2767. for Y := 0 to Height div 4 - 1 do
  2768. for X := 0 to Width div 4 - 1 do
  2769. begin
  2770. Block := PDXTColorBlock(SrcBits)^;
  2771. Inc(SrcBits, SizeOf(Block));
  2772. // we read and decode endpoint colors
  2773. Colors[0] := DecodeCol(Block.Color0);
  2774. Colors[1] := DecodeCol(Block.Color1);
  2775. // and interpolate between them
  2776. if Block.Color0 > Block.Color1 then
  2777. begin
  2778. // interpolation for block without alpha
  2779. Colors[2].A := $FF;
  2780. Colors[2].R := (Colors[0].R shl 1 + Colors[1].R + 1) div 3;
  2781. Colors[2].G := (Colors[0].G shl 1 + Colors[1].G + 1) div 3;
  2782. Colors[2].B := (Colors[0].B shl 1 + Colors[1].B + 1) div 3;
  2783. Colors[3].A := $FF;
  2784. Colors[3].R := (Colors[0].R + Colors[1].R shl 1 + 1) div 3;
  2785. Colors[3].G := (Colors[0].G + Colors[1].G shl 1 + 1) div 3;
  2786. Colors[3].B := (Colors[0].B + Colors[1].B shl 1 + 1) div 3;
  2787. end
  2788. else
  2789. begin
  2790. // interpolation for block with alpha
  2791. Colors[2].A := $FF;
  2792. Colors[2].R := (Colors[0].R + Colors[1].R) shr 1;
  2793. Colors[2].G := (Colors[0].G + Colors[1].G) shr 1;
  2794. Colors[2].B := (Colors[0].B + Colors[1].B) shr 1;
  2795. Colors[3].A := 0;
  2796. Colors[3].R := (Colors[0].R + Colors[1].R shl 1 + 1) div 3;
  2797. Colors[3].G := (Colors[0].G + Colors[1].G shl 1 + 1) div 3;
  2798. Colors[3].B := (Colors[0].B + Colors[1].B shl 1 + 1) div 3;
  2799. end;
  2800. // we distribute the dxt block colors across the 4x4 block of the
  2801. // destination image accroding to the dxt block mask
  2802. K := 0;
  2803. for J := 0 to 3 do
  2804. for I := 0 to 3 do
  2805. begin
  2806. Sel := (Block.Mask and (3 shl (K shl 1))) shr (K shl 1);
  2807. if ((X shl 2 + I) < Width) and ((Y shl 2 + J) < Height) then
  2808. PPalette32(DestBits)[(Y shl 2 + J) * Width + X shl 2 + I] :=
  2809. Colors[Sel];
  2810. Inc(K);
  2811. end;
  2812. end;
  2813. end;
  2814. procedure DecodeDXT3(SrcBits, DestBits: PByte; Width, Height: LongInt);
  2815. var
  2816. Sel, X, Y, I, J, K: LongInt;
  2817. Block: TDXTColorBlock;
  2818. AlphaBlock: TDXTAlphaBlockExp;
  2819. Colors: array[0..3] of TColor32Rec;
  2820. AWord: Word;
  2821. begin
  2822. for Y := 0 to Height div 4 - 1 do
  2823. for X := 0 to Width div 4 - 1 do
  2824. begin
  2825. AlphaBlock := PDXTAlphaBlockExp(SrcBits)^;
  2826. Inc(SrcBits, SizeOf(AlphaBlock));
  2827. Block := PDXTColorBlock(SrcBits)^;
  2828. Inc(SrcBits, SizeOf(Block));
  2829. // we read and decode endpoint colors
  2830. Colors[0] := DecodeCol(Block.Color0);
  2831. Colors[1] := DecodeCol(Block.Color1);
  2832. // and interpolate between them
  2833. Colors[2].R := (Colors[0].R shl 1 + Colors[1].R + 1) div 3;
  2834. Colors[2].G := (Colors[0].G shl 1 + Colors[1].G + 1) div 3;
  2835. Colors[2].B := (Colors[0].B shl 1 + Colors[1].B + 1) div 3;
  2836. Colors[3].R := (Colors[0].R + Colors[1].R shl 1 + 1) div 3;
  2837. Colors[3].G := (Colors[0].G + Colors[1].G shl 1 + 1) div 3;
  2838. Colors[3].B := (Colors[0].B + Colors[1].B shl 1 + 1) div 3;
  2839. // we distribute the dxt block colors and alphas
  2840. // across the 4x4 block of the destination image
  2841. // accroding to the dxt block mask and alpha block
  2842. K := 0;
  2843. for J := 0 to 3 do
  2844. begin
  2845. AWord := AlphaBlock.Alphas[J];
  2846. for I := 0 to 3 do
  2847. begin
  2848. Sel := (Block.Mask and (3 shl (K shl 1))) shr (K shl 1);
  2849. if (X shl 2 + I < Width) and (Y shl 2 + J < Height) then
  2850. begin
  2851. Colors[Sel].A := AWord and $0F;
  2852. Colors[Sel].A := Colors[Sel].A or (Colors[Sel].A shl 4);
  2853. PPalette32(DestBits)[(Y shl 2 + J) * Width + X shl 2 + I] :=
  2854. Colors[Sel];
  2855. end;
  2856. Inc(K);
  2857. AWord := AWord shr 4;
  2858. end;
  2859. end;
  2860. end;
  2861. end;
  2862. procedure DecodeDXT5(SrcBits, DestBits: PByte; Width, Height: LongInt);
  2863. var
  2864. Sel, X, Y, I, J, K: LongInt;
  2865. Block: TDXTColorBlock;
  2866. AlphaBlock: TDXTAlphaBlockInt;
  2867. Colors: array[0..3] of TColor32Rec;
  2868. AMask: array[0..1] of LongWord;
  2869. begin
  2870. for Y := 0 to Height div 4 - 1 do
  2871. for X := 0 to Width div 4 - 1 do
  2872. begin
  2873. AlphaBlock := PDXTAlphaBlockInt(SrcBits)^;
  2874. Inc(SrcBits, SizeOf(AlphaBlock));
  2875. Block := PDXTColorBlock(SrcBits)^;
  2876. Inc(SrcBits, SizeOf(Block));
  2877. // we read and decode endpoint colors
  2878. Colors[0] := DecodeCol(Block.Color0);
  2879. Colors[1] := DecodeCol(Block.Color1);
  2880. // and interpolate between them
  2881. Colors[2].R := (Colors[0].R shl 1 + Colors[1].R + 1) div 3;
  2882. Colors[2].G := (Colors[0].G shl 1 + Colors[1].G + 1) div 3;
  2883. Colors[2].B := (Colors[0].B shl 1 + Colors[1].B + 1) div 3;
  2884. Colors[3].R := (Colors[0].R + Colors[1].R shl 1 + 1) div 3;
  2885. Colors[3].G := (Colors[0].G + Colors[1].G shl 1 + 1) div 3;
  2886. Colors[3].B := (Colors[0].B + Colors[1].B shl 1 + 1) div 3;
  2887. // 6 bit alpha mask is copied into two long words for
  2888. // easier usage
  2889. AMask[0] := PLongWord(@AlphaBlock.Alphas[2])^ and $00FFFFFF;
  2890. AMask[1] := PLongWord(@AlphaBlock.Alphas[5])^ and $00FFFFFF;
  2891. // alpha interpolation between two endpoint alphas
  2892. with AlphaBlock do
  2893. if Alphas[0] > Alphas[1] then
  2894. begin
  2895. // interpolation of six alphas
  2896. Alphas[2] := (6 * Alphas[0] + 1 * Alphas[1] + 3) div 7;
  2897. Alphas[3] := (5 * Alphas[0] + 2 * Alphas[1] + 3) div 7;
  2898. Alphas[4] := (4 * Alphas[0] + 3 * Alphas[1] + 3) div 7;
  2899. Alphas[5] := (3 * Alphas[0] + 4 * Alphas[1] + 3) div 7;
  2900. Alphas[6] := (2 * Alphas[0] + 5 * Alphas[1] + 3) div 7;
  2901. Alphas[7] := (1 * Alphas[0] + 6 * Alphas[1] + 3) div 7;
  2902. end
  2903. else
  2904. begin
  2905. // interpolation of four alphas, two alphas are set directly
  2906. Alphas[2] := (4 * Alphas[0] + 1 * Alphas[1] + 2) div 5;
  2907. Alphas[3] := (3 * Alphas[0] + 2 * Alphas[1] + 2) div 5;
  2908. Alphas[4] := (2 * Alphas[0] + 3 * Alphas[1] + 2) div 5;
  2909. Alphas[5] := (1 * Alphas[0] + 4 * Alphas[1] + 2) div 5;
  2910. Alphas[6] := 0;
  2911. Alphas[7] := $FF;
  2912. end;
  2913. // we distribute the dxt block colors and alphas
  2914. // across the 4x4 block of the destination image
  2915. // accroding to the dxt block mask and alpha block mask
  2916. K := 0;
  2917. for J := 0 to 3 do
  2918. for I := 0 to 3 do
  2919. begin
  2920. Sel := (Block.Mask and (3 shl (K shl 1))) shr (K shl 1);
  2921. if ((X shl 2 + I) < Width) and ((Y shl 2 + J) < Height) then
  2922. begin
  2923. Colors[Sel].A := AlphaBlock.Alphas[AMask[J shr 1] and 7];
  2924. PPalette32(DestBits)[(Y shl 2 + J) * Width + (X shl 2 + I)] :=
  2925. Colors[Sel];
  2926. end;
  2927. Inc(K);
  2928. AMask[J shr 1] := AMask[J shr 1] shr 3;
  2929. end;
  2930. end;
  2931. end;
  2932. procedure GetBlock(var Block: TPixelBlock; SrcBits: Pointer; XPos, YPos,
  2933. Width, Height: LongInt);
  2934. var
  2935. X, Y, I: LongInt;
  2936. Src: PColor32Rec;
  2937. begin
  2938. I := 0;
  2939. // 4x4 pixel block is filled with information about every
  2940. // pixel in the block: alpha, original color, 565 color
  2941. for Y := 0 to 3 do
  2942. for X := 0 to 3 do
  2943. begin
  2944. Src := @PPalette32(SrcBits)[(YPos shl 2 + Y) * Width + XPos shl 2 + X];
  2945. Block[I].Color := ((Src.R shr 3) shl 11) or ((Src.G shr 2) shl 5) or
  2946. (Src.B shr 3);
  2947. Block[I].Alpha := Src.A;
  2948. Block[I].Orig := Src^;
  2949. Inc(I);
  2950. end;
  2951. end;
  2952. function ColorDistance(const C1, C2: TColor32Rec): LongInt;
  2953. {$IFDEF USE_INLINE} inline;{$ENDIF}
  2954. begin
  2955. Result := (C1.R - C2.R) * (C1.R - C2.R) +
  2956. (C1.G - C2.G) * (C1.G - C2.G) + (C1.B - C2.B) * (C1.B - C2.B);
  2957. end;
  2958. procedure GetEndpoints(const Block: TPixelBlock; var Ep0, Ep1: Word);
  2959. var
  2960. I, J, Farthest, Dist: LongInt;
  2961. Colors: array[0..15] of TColor32Rec;
  2962. begin
  2963. // we choose two colors from the pixel block which has the
  2964. // largest distance between them
  2965. for I := 0 to 15 do
  2966. Colors[I] := Block[I].Orig;
  2967. Farthest := -1;
  2968. for I := 0 to 15 do
  2969. for J := I + 1 to 15 do
  2970. begin
  2971. Dist := ColorDistance(Colors[I], Colors[J]);
  2972. if Dist > Farthest then
  2973. begin
  2974. Farthest := Dist;
  2975. Ep0 := Block[I].Color;
  2976. Ep1 := Block[J].Color;
  2977. end;
  2978. end;
  2979. end;
  2980. procedure GetAlphaEndpoints(const Block: TPixelBlock; var Min, Max: Byte);
  2981. var
  2982. I: LongInt;
  2983. begin
  2984. Min := 255;
  2985. Max := 0;
  2986. // we choose the lowest and the highest alpha values
  2987. for I := 0 to 15 do
  2988. begin
  2989. if Block[I].Alpha < Min then
  2990. Min := Block[I].Alpha;
  2991. if Block[I].Alpha > Max then
  2992. Max := Block[I].Alpha;
  2993. end;
  2994. end;
  2995. procedure FixEndpoints(var Ep0, Ep1: Word; HasAlpha: Boolean);
  2996. var
  2997. Temp: Word;
  2998. begin
  2999. // if dxt block has alpha information, Ep0 must be smaller
  3000. // than Ep1, if the block has no alpha Ep1 must be smaller
  3001. if HasAlpha then
  3002. begin
  3003. if Ep0 > Ep1 then
  3004. begin
  3005. Temp := Ep0;
  3006. Ep0 := Ep1;
  3007. Ep1 := Temp;
  3008. end;
  3009. end
  3010. else
  3011. if Ep0 < Ep1 then
  3012. begin
  3013. Temp := Ep0;
  3014. Ep0 := Ep1;
  3015. Ep1 := Temp;
  3016. end;
  3017. end;
  3018. function GetColorMask(Ep0, Ep1: Word; NumCols: LongInt;
  3019. const Block: TPixelBlock): LongWord;
  3020. var
  3021. I, J, Closest, Dist: LongInt;
  3022. Colors: array[0..3] of TColor32Rec;
  3023. Mask: array[0..15] of Byte;
  3024. begin
  3025. // we decode endpoint colors
  3026. Colors[0] := DecodeCol(Ep0);
  3027. Colors[1] := DecodeCol(Ep1);
  3028. // and interpolate colors between (3 for DXT1 with alpha, 4 for the others)
  3029. if NumCols = 3 then
  3030. begin
  3031. Colors[2].R := (Colors[0].R + Colors[1].R) shr 1;
  3032. Colors[2].G := (Colors[0].G + Colors[1].G) shr 1;
  3033. Colors[2].B := (Colors[0].B + Colors[1].B) shr 1;
  3034. Colors[3].R := (Colors[0].R + Colors[1].R) shr 1;
  3035. Colors[3].G := (Colors[0].G + Colors[1].G) shr 1;
  3036. Colors[3].B := (Colors[0].B + Colors[1].B) shr 1;
  3037. end
  3038. else
  3039. begin
  3040. Colors[2].R := (Colors[0].R shl 1 + Colors[1].R + 1) div 3;
  3041. Colors[2].G := (Colors[0].G shl 1 + Colors[1].G + 1) div 3;
  3042. Colors[2].B := (Colors[0].B shl 1 + Colors[1].B + 1) div 3;
  3043. Colors[3].R := (Colors[0].R + Colors[1].R shl 1 + 1) div 3;
  3044. Colors[3].G := (Colors[0].G + Colors[1].G shl 1 + 1) div 3;
  3045. Colors[3].B := (Colors[0].B + Colors[1].B shl 1 + 1) div 3;
  3046. end;
  3047. for I := 0 to 15 do
  3048. begin
  3049. // this is only for DXT1 with alpha
  3050. if (Block[I].Alpha < 128) and (NumCols = 3) then
  3051. begin
  3052. Mask[I] := 3;
  3053. Continue;
  3054. end;
  3055. // for each of the 16 input pixels the nearest color in the
  3056. // 4 dxt colors is found
  3057. Closest := MaxInt;
  3058. for J := 0 to NumCols - 1 do
  3059. begin
  3060. Dist := ColorDistance(Block[I].Orig, Colors[J]);
  3061. if Dist < Closest then
  3062. begin
  3063. Closest := Dist;
  3064. Mask[I] := J;
  3065. end;
  3066. end;
  3067. end;
  3068. Result := 0;
  3069. for I := 0 to 15 do
  3070. Result := Result or (Mask[I] shl (I shl 1));
  3071. end;
  3072. procedure GetAlphaMask(Ep0, Ep1: Byte; var Block: TPixelBlock; Mask: PByteArray);
  3073. var
  3074. Alphas: array[0..7] of Byte;
  3075. M: array[0..15] of Byte;
  3076. I, J, Closest, Dist: LongInt;
  3077. begin
  3078. Alphas[0] := Ep0;
  3079. Alphas[1] := Ep1;
  3080. // interpolation between two given alpha endpoints
  3081. // (I use 6 interpolated values mode)
  3082. Alphas[2] := (6 * Alphas[0] + 1 * Alphas[1] + 3) div 7;
  3083. Alphas[3] := (5 * Alphas[0] + 2 * Alphas[1] + 3) div 7;
  3084. Alphas[4] := (4 * Alphas[0] + 3 * Alphas[1] + 3) div 7;
  3085. Alphas[5] := (3 * Alphas[0] + 4 * Alphas[1] + 3) div 7;
  3086. Alphas[6] := (2 * Alphas[0] + 5 * Alphas[1] + 3) div 7;
  3087. Alphas[7] := (1 * Alphas[0] + 6 * Alphas[1] + 3) div 7;
  3088. // the closest interpolated values for each of the input alpha
  3089. // is found
  3090. for I := 0 to 15 do
  3091. begin
  3092. Closest := MaxInt;
  3093. for J := 0 to 7 do
  3094. begin
  3095. Dist := Abs(Alphas[J] - Block[I].Alpha);
  3096. if Dist < Closest then
  3097. begin
  3098. Closest := Dist;
  3099. M[I] := J;
  3100. end;
  3101. end;
  3102. end;
  3103. Mask[0] := M[0] or (M[1] shl 3) or ((M[2] and 3) shl 6);
  3104. Mask[1] := ((M[2] and 4) shr 2) or (M[3] shl 1) or (M[4] shl 4) or
  3105. ((M[5] and 1) shl 7);
  3106. Mask[2] := ((M[5] and 6) shr 1) or (M[6] shl 2) or (M[7] shl 5);
  3107. Mask[3] := M[8] or (M[9] shl 3) or ((M[10] and 3) shl 6);
  3108. Mask[4] := ((M[10] and 4) shr 2) or (M[11] shl 1) or (M[12] shl 4) or
  3109. ((M[13] and 1) shl 7);
  3110. Mask[5] := ((M[13] and 6) shr 1) or (M[14] shl 2) or (M[15] shl 5);
  3111. end;
  3112. procedure EncodeDXT1(SrcBits: PByte; DestBits: PByte; Width, Height: LongInt);
  3113. var
  3114. X, Y, I: LongInt;
  3115. HasAlpha: Boolean;
  3116. Block: TDXTColorBlock;
  3117. Pixels: TPixelBlock;
  3118. begin
  3119. for Y := 0 to Height div 4 - 1 do
  3120. for X := 0 to Width div 4 - 1 do
  3121. begin
  3122. GetBlock(Pixels, SrcBits, X, Y, Width, Height);
  3123. HasAlpha := False;
  3124. for I := 0 to 15 do
  3125. if Pixels[I].Alpha < 128 then
  3126. begin
  3127. HasAlpha := True;
  3128. Break;
  3129. end;
  3130. GetEndpoints(Pixels, Block.Color0, Block.Color1);
  3131. FixEndpoints(Block.Color0, Block.Color1, HasAlpha);
  3132. if HasAlpha then
  3133. Block.Mask := GetColorMask(Block.Color0, Block.Color1, 3, Pixels)
  3134. else
  3135. Block.Mask := GetColorMask(Block.Color0, Block.Color1, 4, Pixels);
  3136. PDXTColorBlock(DestBits)^ := Block;
  3137. Inc(DestBits, SizeOf(Block));
  3138. end;
  3139. end;
  3140. procedure EncodeDXT3(SrcBits: Pointer; DestBits: PByte; Width, Height: LongInt);
  3141. var
  3142. X, Y, I: LongInt;
  3143. Block: TDXTColorBlock;
  3144. AlphaBlock: TDXTAlphaBlockExp;
  3145. Pixels: TPixelBlock;
  3146. begin
  3147. for Y := 0 to Height div 4 - 1 do
  3148. for X := 0 to Width div 4 - 1 do
  3149. begin
  3150. GetBlock(Pixels, SrcBits, X, Y, Width, Height);
  3151. for I := 0 to 7 do
  3152. PByteArray(@AlphaBlock.Alphas)[I] :=
  3153. ((Pixels[I shl 1].Alpha shr 4) shl 4) or (Pixels[I shl 1 + 1].Alpha shr 4);
  3154. GetEndpoints(Pixels, Block.Color0, Block.Color1);
  3155. FixEndpoints(Block.Color0, Block.Color1, False);
  3156. Block.Mask := GetColorMask(Block.Color0, Block.Color1, 4, Pixels);
  3157. PDXTAlphaBlockExp(DestBits)^ := AlphaBlock;
  3158. Inc(DestBits, SizeOf(AlphaBlock));
  3159. PDXTColorBlock(DestBits)^ := Block;
  3160. Inc(DestBits, SizeOf(Block));
  3161. end;
  3162. end;
  3163. procedure EncodeDXT5(SrcBits: Pointer; DestBits: PByte; Width, Height: LongInt);
  3164. var
  3165. X, Y: LongInt;
  3166. Block: TDXTColorBlock;
  3167. AlphaBlock: TDXTAlphaBlockInt;
  3168. Pixels: TPixelBlock;
  3169. begin
  3170. for Y := 0 to Height div 4 - 1 do
  3171. for X := 0 to Width div 4 - 1 do
  3172. begin
  3173. GetBlock(Pixels, SrcBits, X, Y, Width, Height);
  3174. GetEndpoints(Pixels, Block.Color0, Block.Color1);
  3175. FixEndpoints(Block.Color0, Block.Color1, False);
  3176. Block.Mask := GetColorMask(Block.Color0, Block.Color1, 4, Pixels);
  3177. GetAlphaEndPoints(Pixels, AlphaBlock.Alphas[1], AlphaBlock.Alphas[0]);
  3178. GetAlphaMask(AlphaBlock.Alphas[0], AlphaBlock.Alphas[1], Pixels,
  3179. PByteArray(@AlphaBlock.Alphas[2]));
  3180. PDXTAlphaBlockInt(DestBits)^ := AlphaBlock;
  3181. Inc(DestBits, SizeOf(AlphaBlock));
  3182. PDXTColorBlock(DestBits)^ := Block;
  3183. Inc(DestBits, SizeOf(Block));
  3184. end;
  3185. end;
  3186. procedure SpecialToUnSpecial(const SrcImage: TImageData; DestBits: Pointer;
  3187. SrcInfo, DstInfo: PImageFormatInfo);
  3188. begin
  3189. case SrcInfo.Format of
  3190. ifDXT1: DecodeDXT1(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height);
  3191. ifDXT3: DecodeDXT3(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height);
  3192. ifDXT5: DecodeDXT5(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height);
  3193. end;
  3194. end;
  3195. procedure UnSpecialToSpecial(const DestImage: TImageData; SrcBits: Pointer;
  3196. SrcInfo, DstInfo: PImageFormatInfo);
  3197. begin
  3198. case DstInfo.Format of
  3199. ifDXT1: EncodeDXT1(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height);
  3200. ifDXT3: EncodeDXT3(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height);
  3201. ifDXT5: EncodeDXT5(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height);
  3202. end;
  3203. end;
  3204. procedure ConvertSpecial(var Image: TImageData;
  3205. SrcInfo, DstInfo: PImageFormatInfo);
  3206. var
  3207. WorkImage: TImageData;
  3208. Width, Height: LongInt;
  3209. begin
  3210. // first convert image to default non-special format
  3211. if SrcInfo.IsSpecial then
  3212. begin
  3213. InitImage(WorkImage);
  3214. NewImage(Image.Width, Image.Height, UnSpecialFormat, WorkImage);
  3215. SpecialToUnSpecial(Image, WorkImage.Bits, SrcInfo, DstInfo);
  3216. FreeImage(Image);
  3217. Image := WorkImage;
  3218. end
  3219. else
  3220. ConvertImage(Image, UnSpecialFormat);
  3221. // we have now image in default non-special format and
  3222. // if dest format is special we will convert to this special format
  3223. if DstInfo.IsSpecial then
  3224. begin
  3225. Width := Image.Width;
  3226. Height := Image.Height;
  3227. DstInfo.CheckDimensions(DstInfo.Format, Width, Height);
  3228. InitImage(WorkImage);
  3229. NewImage(Width, Height, DstInfo.Format, WorkImage);
  3230. ResizeImage(Image, Width, Height, rfNearest);
  3231. UnSpecialToSpecial(WorkImage, Image.Bits, SrcInfo, DstInfo);
  3232. FreeImage(Image);
  3233. Image := WorkImage;
  3234. end
  3235. else
  3236. ConvertImage(Image, DstInfo.Format);
  3237. end;
  3238. function GetStdPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt;
  3239. begin
  3240. if FInfos[Format] <> nil then
  3241. Result := Width * Height * FInfos[Format].BytesPerPixel
  3242. else
  3243. Result := 0;
  3244. end;
  3245. procedure CheckStdDimensions(Format: TImageFormat; var Width, Height: LongInt);
  3246. begin
  3247. end;
  3248. function GetDXTPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt;
  3249. begin
  3250. // DXT can be used only for images with dimensions that are
  3251. // multiples of four
  3252. CheckDXTDimensions(Format, Width, Height);
  3253. Result := Width * Height;
  3254. if Format = ifDXT1 then
  3255. Result := Result div 2;
  3256. end;
  3257. procedure CheckDXTDimensions(Format: TImageFormat; var Width, Height: LongInt);
  3258. begin
  3259. // DXT image dimensions must be multiples of four
  3260. Width := (Width + 3) and not 3;
  3261. Height := (Height + 3) and not 3;
  3262. end;
  3263. { Optimized pixel readers/writers for 32bit and FP colors to be stored in TImageFormatInfo }
  3264. function GetPixel32ifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColor32Rec;
  3265. begin
  3266. Result.Color := PLongWord(Bits)^;
  3267. end;
  3268. procedure SetPixel32ifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColor32Rec);
  3269. begin
  3270. PLongWord(Bits)^ := Color.Color;
  3271. end;
  3272. function GetPixelFPifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec;
  3273. begin
  3274. Result.A := PColor32Rec(Bits).A * OneDiv8Bit;
  3275. Result.R := PColor32Rec(Bits).R * OneDiv8Bit;
  3276. Result.G := PColor32Rec(Bits).G * OneDiv8Bit;
  3277. Result.B := PColor32Rec(Bits).B * OneDiv8Bit;
  3278. end;
  3279. procedure SetPixelFPifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec);
  3280. begin
  3281. PColor32Rec(Bits).A := ClampToByte(Round(Color.A * 255.0));
  3282. PColor32Rec(Bits).R := ClampToByte(Round(Color.R * 255.0));
  3283. PColor32Rec(Bits).G := ClampToByte(Round(Color.G * 255.0));
  3284. PColor32Rec(Bits).B := ClampToByte(Round(Color.B * 255.0));
  3285. end;
  3286. function GetPixel32Channel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColor32Rec;
  3287. begin
  3288. case Info.Format of
  3289. ifR8G8B8, ifX8R8G8B8:
  3290. begin
  3291. Result.A := $FF;
  3292. PColor24Rec(@Result)^ := PColor24Rec(Bits)^;
  3293. end;
  3294. ifGray8, ifA8Gray8:
  3295. begin
  3296. if Info.HasAlphaChannel then
  3297. Result.A := PWordRec(Bits).High
  3298. else
  3299. Result.A := $FF;
  3300. Result.R := PWordRec(Bits).Low;
  3301. Result.G := PWordRec(Bits).Low;
  3302. Result.B := PWordRec(Bits).Low;
  3303. end;
  3304. end;
  3305. end;
  3306. procedure SetPixel32Channel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColor32Rec);
  3307. begin
  3308. case Info.Format of
  3309. ifR8G8B8, ifX8R8G8B8:
  3310. begin
  3311. PColor24Rec(Bits)^ := PColor24Rec(@Color)^;
  3312. end;
  3313. ifGray8, ifA8Gray8:
  3314. begin
  3315. if Info.HasAlphaChannel then
  3316. PWordRec(Bits).High := Color.A;
  3317. PWordRec(Bits).Low := Round(GrayConv.R * Color.R + GrayConv.G * Color.G +
  3318. GrayConv.B * Color.B);
  3319. end;
  3320. end;
  3321. end;
  3322. function GetPixelFPChannel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec;
  3323. begin
  3324. case Info.Format of
  3325. ifR8G8B8, ifX8R8G8B8:
  3326. begin
  3327. Result.A := 1.0;
  3328. Result.R := PColor24Rec(Bits).R * OneDiv8Bit;
  3329. Result.G := PColor24Rec(Bits).G * OneDiv8Bit;
  3330. Result.B := PColor24Rec(Bits).B * OneDiv8Bit;
  3331. end;
  3332. ifGray8, ifA8Gray8:
  3333. begin
  3334. if Info.HasAlphaChannel then
  3335. Result.A := PWordRec(Bits).High * OneDiv8Bit
  3336. else
  3337. Result.A := 1.0;
  3338. Result.R := PWordRec(Bits).Low * OneDiv8Bit;
  3339. Result.G := PWordRec(Bits).Low * OneDiv8Bit;
  3340. Result.B := PWordRec(Bits).Low * OneDiv8Bit;
  3341. end;
  3342. end;
  3343. end;
  3344. procedure SetPixelFPChannel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec);
  3345. begin
  3346. case Info.Format of
  3347. ifR8G8B8, ifX8R8G8B8:
  3348. begin
  3349. PColor24Rec(Bits).R := ClampToByte(Round(Color.R * 255.0));
  3350. PColor24Rec(Bits).G := ClampToByte(Round(Color.G * 255.0));
  3351. PColor24Rec(Bits).B := ClampToByte(Round(Color.B * 255.0));
  3352. end;
  3353. ifGray8, ifA8Gray8:
  3354. begin
  3355. if Info.HasAlphaChannel then
  3356. PWordRec(Bits).High := ClampToByte(Round(Color.A * 255.0));
  3357. PWordRec(Bits).Low := ClampToByte(Round((GrayConv.R * Color.R + GrayConv.G * Color.G +
  3358. GrayConv.B * Color.B) * 255.0));
  3359. end;
  3360. end;
  3361. end;
  3362. function GetPixelFPFloat32(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec;
  3363. begin
  3364. case Info.Format of
  3365. ifA32R32G32B32F:
  3366. begin
  3367. Result := PColorFPRec(Bits)^;
  3368. end;
  3369. ifA32B32G32R32F:
  3370. begin
  3371. Result := PColorFPRec(Bits)^;
  3372. SwapValues(Result.R, Result.B);
  3373. end;
  3374. ifR32F:
  3375. begin
  3376. Result.A := 1.0;
  3377. Result.R := PSingle(Bits)^;
  3378. Result.G := 0.0;
  3379. Result.B := 0.0;
  3380. end;
  3381. end;
  3382. end;
  3383. procedure SetPixelFPFloat32(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec);
  3384. begin
  3385. case Info.Format of
  3386. ifA32R32G32B32F:
  3387. begin
  3388. PColorFPRec(Bits)^ := Color;
  3389. end;
  3390. ifA32B32G32R32F:
  3391. begin
  3392. PColorFPRec(Bits)^ := Color;
  3393. SwapValues(PColorFPRec(Bits).R, PColorFPRec(Bits).B);
  3394. end;
  3395. ifR32F:
  3396. begin
  3397. PSingle(Bits)^ := Color.R;
  3398. end;
  3399. end;
  3400. end;
  3401. {
  3402. File Notes:
  3403. -- TODOS ----------------------------------------------------
  3404. - rewrite StretchRect for 8bit channels to use integer math
  3405. -- 0.19 Changes/Bug Fixes -----------------------------------
  3406. - StretchResample now uses pixel get/set functions stored in
  3407. TImageFormatInfo so it is much faster for formats that override
  3408. them with optimized ones
  3409. - added pixel set/get functions optimized for various image formats
  3410. (to be stored in TImageFormatInfo)
  3411. - bug in ConvertSpecial caused problems when converting DXTC images
  3412. to bitmaps in ImagingCoponents
  3413. - bug in StretchRect caused that it didn't work with ifR32F and
  3414. ifR16F formats
  3415. - removed leftover code in FillMipMapLevel which disabled
  3416. filtered resizing of images witch ChannelSize <> 8bits
  3417. - added half float converting functions and support for half based
  3418. image formats where needed
  3419. - added TranslatePixel and IsImageFormatValid functions
  3420. - fixed possible range overflows when converting from FP to integer images
  3421. - added pixel set/get functions: GetPixel32Generic, GetPixelFPGeneric,
  3422. SetPixel32Generic, SetPixelFPGeneric
  3423. - fixed occasional range overflows in StretchResample
  3424. -- 0.17 Changes/Bug Fixes -----------------------------------
  3425. - added StretchNearest, StretchResample and some sampling functions
  3426. - added ChannelCount values to TImageFormatInfo constants
  3427. - added resolution validity check to GetDXTPixelsSize
  3428. -- 0.15 Changes/Bug Fixes -----------------------------------
  3429. - added RBSwapFormat values to some TImageFromatInfo definitions
  3430. - fixed bug in ConvertSpecial (causing DXT images to convert only to 32bit)
  3431. - added CopyPixel, ComparePixels helper functions
  3432. -- 0.13 Changes/Bug Fixes -----------------------------------
  3433. - replaced pixel format conversions for colors not to be
  3434. darkened when converting from low bit counts
  3435. - ReduceColorsMedianCut was updated to support creating one
  3436. optimal palette for more images and it is somewhat faster
  3437. now too
  3438. - there was ugly bug in DXTC dimensions checking
  3439. }
  3440. end.