ImagingFormats.pas 141 KB

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