ImagingFormats.pas 121 KB

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