ImagingFormats.pas 136 KB

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