ImagingFormats.pas 140 KB

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