ImagingFormats.pas 125 KB

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