2
0

ImagingFormats.pas 136 KB

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