GR32_Resamplers.pas 148 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990
  1. unit GR32_Resamplers;
  2. (* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1 or LGPL 2.1 with linking exception
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * Alternatively, the contents of this file may be used under the terms of the
  16. * Free Pascal modified version of the GNU Lesser General Public License
  17. * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
  18. * of this license are applicable instead of those above.
  19. * Please see the file LICENSE.txt for additional information concerning this
  20. * license.
  21. *
  22. * The Original Code is Graphics32
  23. *
  24. * The Initial Developers of the Original Code is
  25. * Mattias Andersson <[email protected]>
  26. * (parts of this unit were taken from GR32_Transforms.pas by Alex A. Denisov)
  27. *
  28. * Many of the filters here were adapted from:
  29. * - "Interpolated Bitmap Resampling using filters"
  30. * Anders Melander, 1997
  31. * which in turn was based on:
  32. * - "General Filtered Image Rescaling"
  33. * Dale Schumacher
  34. * Graphics Gems III, Academic Press, Inc.
  35. * 1 July 1992
  36. *
  37. * Portions created by the Initial Developer are Copyright (C) 2000-2009
  38. * the Initial Developer. All Rights Reserved.
  39. *
  40. * ***** END LICENSE BLOCK ***** *)
  41. interface
  42. {$include GR32.inc}
  43. // Define PREMULTIPLY to have TKernelResampler handle alpha correctly.
  44. // The downside of the alpha handling is that the performance and
  45. // precision of the resampler suffers slightly.
  46. {$define PREMULTIPLY}
  47. uses
  48. Classes,
  49. SysUtils, // Exception
  50. GR32,
  51. GR32_Transforms,
  52. GR32_Containers,
  53. GR32_OrdinalMaps,
  54. GR32_Blend;
  55. //------------------------------------------------------------------------------
  56. //
  57. // BlockTransfer
  58. //
  59. //------------------------------------------------------------------------------
  60. // Unscaled block transfer
  61. //------------------------------------------------------------------------------
  62. procedure BlockTransfer(
  63. Dst: TCustomBitmap32; DstX: Integer; DstY: Integer; DstClip: TRect;
  64. Src: TCustomBitmap32; SrcRect: TRect;
  65. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent = nil);
  66. procedure BlockTransferX(
  67. Dst: TCustomBitmap32; DstX, DstY: TFixed;
  68. Src: TCustomBitmap32; SrcRect: TRect;
  69. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent = nil);
  70. //------------------------------------------------------------------------------
  71. //
  72. // StretchTransfer
  73. //
  74. //------------------------------------------------------------------------------
  75. // Scaled block transfer using resampler
  76. //------------------------------------------------------------------------------
  77. procedure StretchTransfer(
  78. Dst: TCustomBitmap32; DstRect: TRect; DstClip: TRect;
  79. Src: TCustomBitmap32; SrcRect: TRect;
  80. Resampler: TCustomResampler;
  81. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent = nil);
  82. //------------------------------------------------------------------------------
  83. //
  84. // BlendTransfer
  85. //
  86. //------------------------------------------------------------------------------
  87. // Unscaled block blend
  88. //------------------------------------------------------------------------------
  89. procedure BlendTransfer(
  90. Dst: TCustomBitmap32; DstX, DstY: Integer; DstClip: TRect;
  91. SrcF: TCustomBitmap32; SrcRectF: TRect;
  92. SrcB: TCustomBitmap32; SrcRectB: TRect;
  93. BlendCallback: TBlendReg); overload;
  94. procedure BlendTransfer(
  95. Dst: TCustomBitmap32; DstX, DstY: Integer; DstClip: TRect;
  96. SrcF: TCustomBitmap32; SrcRectF: TRect;
  97. SrcB: TCustomBitmap32; SrcRectB: TRect;
  98. BlendCallback: TBlendRegEx; MasterAlpha: Integer); overload;
  99. //------------------------------------------------------------------------------
  100. //
  101. // Resampling
  102. //
  103. //------------------------------------------------------------------------------
  104. const
  105. MAX_KERNEL_WIDTH = 16;
  106. type
  107. PKernelEntry = ^TKernelEntry;
  108. TKernelEntry = array [-MAX_KERNEL_WIDTH..MAX_KERNEL_WIDTH] of Integer;
  109. TArrayOfKernelEntry = array of TArrayOfInteger;
  110. PKernelEntryArray = ^TKernelEntryArray;
  111. TKernelEntryArray = array [0..0] of TArrayOfInteger;
  112. TFilterMethod = function(Value: TFloat): TFloat of object;
  113. EBitmapException = class(Exception);
  114. ESrcInvalidException = class(Exception);
  115. ENestedException = class(Exception);
  116. ETransformerException = class(Exception);
  117. TGetSampleInt = function(X, Y: Integer): TColor32 of object;
  118. TGetSampleFloat = function(X, Y: TFloat): TColor32 of object;
  119. TGetSampleFixed = function(X, Y: TFixed): TColor32 of object;
  120. //------------------------------------------------------------------------------
  121. //
  122. // TCustomKernel
  123. //
  124. //------------------------------------------------------------------------------
  125. // Abstract base class for resampler kernels.
  126. //------------------------------------------------------------------------------
  127. type
  128. TCustomKernel = class(TPersistent)
  129. protected
  130. FObserver: TNotifiablePersistent;
  131. protected
  132. procedure AssignTo(Dst: TPersistent); override;
  133. function RangeCheck: Boolean; virtual;
  134. public
  135. constructor Create; virtual;
  136. procedure Changed;
  137. function Filter(Value: TFloat): TFloat; virtual; abstract;
  138. function GetWidth: TFloat; virtual; abstract;
  139. property Observer: TNotifiablePersistent read FObserver;
  140. end;
  141. TCustomKernelClass = class of TCustomKernel;
  142. //------------------------------------------------------------------------------
  143. //
  144. // TBoxKernel
  145. //
  146. //------------------------------------------------------------------------------
  147. // Nearest neighbor interpolation filter.
  148. // Also known as box filter, top-hat function or a Fourier window.
  149. //------------------------------------------------------------------------------
  150. type
  151. TBoxKernel = class(TCustomKernel)
  152. public
  153. function Filter(Value: TFloat): TFloat; override;
  154. function GetWidth: TFloat; override;
  155. end;
  156. //------------------------------------------------------------------------------
  157. //
  158. // TLinearKernel
  159. //
  160. //------------------------------------------------------------------------------
  161. // Linear reconstruction filter.
  162. // Also known as triangle filter, tent filter, roof function, Chateau function
  163. // or a Bartlett window.
  164. //------------------------------------------------------------------------------
  165. type
  166. TLinearKernel = class(TCustomKernel)
  167. public
  168. function Filter(Value: TFloat): TFloat; override;
  169. function GetWidth: TFloat; override;
  170. end;
  171. //------------------------------------------------------------------------------
  172. //
  173. // TCosineKernel
  174. //
  175. //------------------------------------------------------------------------------
  176. // Cosine reconstruction filter.
  177. //------------------------------------------------------------------------------
  178. type
  179. TCosineKernel = class(TCustomKernel)
  180. public
  181. function Filter(Value: TFloat): TFloat; override;
  182. function GetWidth: TFloat; override;
  183. end;
  184. //------------------------------------------------------------------------------
  185. //
  186. // TSplineKernel
  187. //
  188. //------------------------------------------------------------------------------
  189. // B-Spline interpolation filter.
  190. // Not the same as the Spline windowed Sinc kernel.
  191. //------------------------------------------------------------------------------
  192. type
  193. TSplineKernel = class(TCustomKernel)
  194. protected
  195. function RangeCheck: Boolean; override;
  196. public
  197. function Filter(Value: TFloat): TFloat; override;
  198. function GetWidth: TFloat; override;
  199. end;
  200. //------------------------------------------------------------------------------
  201. //
  202. // TMitchellKernel
  203. //
  204. //------------------------------------------------------------------------------
  205. // An implementation of a special case of the cubic filter described by Mitchell
  206. // and Netravali using the parameters (B: 1/3, C: 1/3).
  207. //
  208. // References:
  209. //
  210. // - Don P. Mitchell & Arun N. Netravali
  211. // AT&T Bell Laboratories
  212. // "Reconstruction Filters in Computer Graphics"
  213. // Computer Graphics, Volume 22, Number 4, August 1988.
  214. //
  215. // Also known as Mitchell-Netravali.
  216. // Many other variants of this filter, with various other values for B&C, exist.
  217. // Often people come up with some variation of B&C and then put their own name
  218. // on the filter. For example Robidoux (B:0.3782, C:0.3109), etc.
  219. //
  220. //------------------------------------------------------------------------------
  221. type
  222. TMitchellKernel = class(TCustomKernel)
  223. protected
  224. function RangeCheck: Boolean; override;
  225. public
  226. function Filter(Value: TFloat): TFloat; override;
  227. function GetWidth: TFloat; override;
  228. end;
  229. //------------------------------------------------------------------------------
  230. //
  231. // TCubicKernel
  232. //
  233. //------------------------------------------------------------------------------
  234. // A reconstruction filter described by a cubic polynomial.
  235. //
  236. // References:
  237. //
  238. // - Robert G. Keys
  239. // "Cubic convolution interpolation for digital image processing"
  240. // IEEE Transactions on Acoustics, Speech, and Signal Processing
  241. // Volume: 29, Issue: 6, December 1981
  242. //
  243. //------------------------------------------------------------------------------
  244. type
  245. TCubicKernel = class(TCustomKernel)
  246. private
  247. FCoeff: TFloat;
  248. procedure SetCoeff(const Value: TFloat);
  249. protected
  250. function RangeCheck: Boolean; override;
  251. public
  252. constructor Create; override;
  253. function Filter(Value: TFloat): TFloat; override;
  254. function GetWidth: TFloat; override;
  255. published
  256. property Coeff: TFloat read FCoeff write SetCoeff;
  257. end;
  258. //------------------------------------------------------------------------------
  259. //
  260. // THermiteKernel
  261. //
  262. //------------------------------------------------------------------------------
  263. // An implementation of the hermite kernel.
  264. //------------------------------------------------------------------------------
  265. type
  266. THermiteKernel = class(TCustomKernel)
  267. private
  268. FBias: TFloat;
  269. FTension: TFloat;
  270. procedure SetBias(const Value: TFloat);
  271. procedure SetTension(const Value: TFloat);
  272. protected
  273. function RangeCheck: Boolean; override;
  274. public
  275. constructor Create; override;
  276. function Filter(Value: TFloat): TFloat; override;
  277. function GetWidth: TFloat; override;
  278. published
  279. property Bias: TFloat read FBias write SetBias;
  280. property Tension: TFloat read FTension write SetTension;
  281. end;
  282. //------------------------------------------------------------------------------
  283. //
  284. // TSinshKernel
  285. //
  286. //------------------------------------------------------------------------------
  287. // A filter described by a hyperbolic sine, something, something.
  288. //------------------------------------------------------------------------------
  289. type
  290. TSinshKernel = class(TCustomKernel)
  291. private
  292. FWidth: TFloat;
  293. FCoeff: TFloat;
  294. procedure SetCoeff(const Value: TFloat);
  295. protected
  296. function RangeCheck: Boolean; override;
  297. public
  298. constructor Create; override;
  299. procedure SetWidth(Value: TFloat);
  300. function GetWidth: TFloat; override;
  301. function Filter(Value: TFloat): TFloat; override;
  302. published
  303. property Coeff: TFloat read FCoeff write SetCoeff;
  304. property Width: TFloat read GetWidth write SetWidth;
  305. end;
  306. //------------------------------------------------------------------------------
  307. //
  308. // TWindowedKernel
  309. //
  310. //------------------------------------------------------------------------------
  311. // Abstract base class for windowed kernels.
  312. // Returns the value of the filter function constrained by a window function.
  313. // Descendant classes must override the Window method in order to implement a
  314. // custom window function.
  315. //------------------------------------------------------------------------------
  316. type
  317. TWindowedKernel = class(TCustomKernel)
  318. strict protected
  319. FWidth : TFloat;
  320. FWidthReciprocal : TFloat;
  321. protected
  322. function RangeCheck: Boolean; override;
  323. function Window(Value: TFloat): TFloat; virtual; abstract;
  324. procedure DoSetWidth(Value: TFloat);
  325. public
  326. function Filter(Value: TFloat): TFloat; override;
  327. procedure SetWidth(Value: TFloat);
  328. function GetWidth: TFloat; override;
  329. property WidthReciprocal : TFloat read FWidthReciprocal;
  330. published
  331. property Width: TFloat read FWidth write SetWidth;
  332. end;
  333. //------------------------------------------------------------------------------
  334. //
  335. // TGaussianKernel
  336. //
  337. //------------------------------------------------------------------------------
  338. // A kernel constrained by a Gaussian window function.
  339. //------------------------------------------------------------------------------
  340. type
  341. TGaussianKernel = class(TWindowedKernel)
  342. private
  343. FSigma: TFloat;
  344. FSigmaReciprocal: TFloat;
  345. FNormalizationFactor: Single;
  346. procedure DoSetSigma(const Value: TFloat);
  347. procedure SetSigma(const Value: TFloat);
  348. protected
  349. function Window(Value: TFloat): TFloat; override;
  350. public
  351. constructor Create; override;
  352. published
  353. property Sigma: TFloat read FSigma write SetSigma;
  354. end;
  355. //------------------------------------------------------------------------------
  356. //
  357. // TWindowedSincKernel
  358. //
  359. //------------------------------------------------------------------------------
  360. // Abstract base class for windowed Sinc kernels.
  361. // Returns the value of the Sinc function constrained by a window function.
  362. // Descendant classes must override the Window method in order to implement a
  363. // custom window function.
  364. //------------------------------------------------------------------------------
  365. type
  366. TWindowedSincKernel = class(TWindowedKernel)
  367. protected
  368. class function Sinc(Value: TFloat): TFloat; static;
  369. public
  370. constructor Create; override;
  371. function Filter(Value: TFloat): TFloat; override;
  372. published
  373. property Width: TFloat read FWidth write SetWidth;
  374. end;
  375. //------------------------------------------------------------------------------
  376. //
  377. // TAlbrecht-Kernel
  378. //
  379. //------------------------------------------------------------------------------
  380. // A Sinc kernel constrained by Albrecht window functions.
  381. //
  382. // References:
  383. //
  384. // - Hans-Helge Albrecht
  385. // Physikalisch-Technische Bundesanstalt, Berlin, Germany
  386. // "A family of cosine-sum windows for high resolution measurements"
  387. // IEEE International Conference on Acoustics, Speech, and Signal Processing,
  388. // Salt Lake City, May 2001.
  389. //
  390. //------------------------------------------------------------------------------
  391. type
  392. TAlbrechtKernel = class(TWindowedSincKernel)
  393. private
  394. FTerms: Integer;
  395. FCoefPointer : Array [0..11] of Double;
  396. procedure SetTerms(Value : Integer);
  397. protected
  398. function Window(Value: TFloat): TFloat; override;
  399. public
  400. constructor Create; override;
  401. published
  402. property Terms: Integer read FTerms write SetTerms;
  403. end;
  404. //------------------------------------------------------------------------------
  405. //
  406. // TLanczosKernel
  407. //
  408. //------------------------------------------------------------------------------
  409. // A Sinc kernel constrained by a Lanczos window function.
  410. // It uses three lobes of the Sinc filter as a window.
  411. //
  412. // References:
  413. //
  414. // - Claude E. Duchon
  415. // School of Meteorology, University of Oklahoma, USA
  416. // "Lanczos Filtering in One and Two Dimensions"
  417. // Journal of Applied Meteorology and Climatology, volume 18, pp. 1016-1022
  418. // 1 Aug 1979
  419. //
  420. // Also known as Lanczo3.
  421. //------------------------------------------------------------------------------
  422. type
  423. TLanczosKernel = class(TWindowedSincKernel)
  424. protected
  425. function Window(Value: TFloat): TFloat; override;
  426. end;
  427. //------------------------------------------------------------------------------
  428. //
  429. // TBlackmanKernel
  430. //
  431. //------------------------------------------------------------------------------
  432. // A Sinc kernel constrained by a Blackman window function.
  433. //
  434. // References:
  435. //
  436. // - Ralph Beebe Blackman & John Wilder Tukey
  437. // "Particular Pairs of Windows"
  438. // The measurement of power spectra from the point of view of communications
  439. // engineering.
  440. // New York: Dover, pp. 98-99, 1959.
  441. //
  442. //------------------------------------------------------------------------------
  443. type
  444. TBlackmanKernel = class(TWindowedSincKernel)
  445. protected
  446. function Window(Value: TFloat): TFloat; override;
  447. end;
  448. //------------------------------------------------------------------------------
  449. //
  450. // THannKernel
  451. //
  452. //------------------------------------------------------------------------------
  453. // A Sinc kernel constrained by a Hann window function.
  454. // Also known as raised cosine.
  455. //
  456. // References:
  457. //
  458. // - Ralph Beebe Blackman & John Wilder Tukey
  459. // The measurement of power spectra from the point of view of communications
  460. // engineering — Part I.
  461. // The Bell System Technical Journal. 37 (1), pp. 273, 1958.
  462. //
  463. // Supposedly based on work done by Julius von Hann, 1839-1921
  464. //
  465. //------------------------------------------------------------------------------
  466. type
  467. THannKernel = class(TWindowedSincKernel)
  468. protected
  469. function Window(Value: TFloat): TFloat; override;
  470. end;
  471. //------------------------------------------------------------------------------
  472. //
  473. // THammingKernel
  474. //
  475. //------------------------------------------------------------------------------
  476. // A Sinc kernel constrained by a Hamming window function.
  477. //
  478. // References:
  479. //
  480. // - Richard W. Hamming
  481. // "Digital Filters"
  482. // Prentice-Hall, 1977 pp. 226; 2nd ed. 1983; 3rd ed. 1989
  483. //
  484. //------------------------------------------------------------------------------
  485. type
  486. THammingKernel = class(TWindowedSincKernel)
  487. protected
  488. function Window(Value: TFloat): TFloat; override;
  489. end;
  490. //------------------------------------------------------------------------------
  491. //
  492. // TNearestResampler
  493. //
  494. //------------------------------------------------------------------------------
  495. // A fast resampler based on the nearest-neighbor interpolation algorithm.
  496. //------------------------------------------------------------------------------
  497. type
  498. TNearestResampler = class(TCustomResampler)
  499. private
  500. FGetSampleInt: TGetSampleInt;
  501. protected
  502. function GetPixelTransparentEdge(X, Y: Integer): TColor32;
  503. function GetWidth: TFloat; override;
  504. procedure Resample(
  505. Dst: TCustomBitmap32; DstRect: TRect; DstClip: TRect;
  506. Src: TCustomBitmap32; SrcRect: TRect;
  507. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent); override;
  508. public
  509. function GetSampleInt(X, Y: Integer): TColor32; override;
  510. function GetSampleFixed(X, Y: TFixed): TColor32; override;
  511. function GetSampleFloat(X, Y: TFloat): TColor32; override;
  512. procedure PrepareSampling; override;
  513. end;
  514. //------------------------------------------------------------------------------
  515. //
  516. // TLinearResampler
  517. //
  518. //------------------------------------------------------------------------------
  519. // Performance-optimized linear upsampler.
  520. // Falls back to using TLinearKernel for downsampling.
  521. //------------------------------------------------------------------------------
  522. type
  523. TLinearResampler = class(TCustomResampler)
  524. private
  525. FLinearKernel: TLinearKernel;
  526. FGetSampleFixed: TGetSampleFixed;
  527. protected
  528. function GetWidth: TFloat; override;
  529. function GetPixelTransparentEdge(X, Y: TFixed): TColor32;
  530. procedure Resample(
  531. Dst: TCustomBitmap32; DstRect: TRect; DstClip: TRect;
  532. Src: TCustomBitmap32; SrcRect: TRect;
  533. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent); override;
  534. public
  535. constructor Create; override;
  536. destructor Destroy; override;
  537. function GetSampleFixed(X, Y: TFixed): TColor32; override;
  538. function GetSampleFloat(X, Y: TFloat): TColor32; override;
  539. procedure PrepareSampling; override;
  540. end;
  541. //------------------------------------------------------------------------------
  542. //
  543. // TDraftResampler
  544. //
  545. //------------------------------------------------------------------------------
  546. // Performance-optimized downsampler.
  547. // Falls back to using TLinearResampler for upsampling.
  548. //------------------------------------------------------------------------------
  549. type
  550. TDraftResampler = class(TLinearResampler)
  551. protected
  552. procedure Resample(
  553. Dst: TCustomBitmap32; DstRect: TRect; DstClip: TRect;
  554. Src: TCustomBitmap32; SrcRect: TRect;
  555. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent); override;
  556. end;
  557. //------------------------------------------------------------------------------
  558. //
  559. // TKernelResampler
  560. //
  561. //------------------------------------------------------------------------------
  562. // This resampler class will perform resampling by using an arbitrary
  563. // reconstruction kernel.
  564. // By using the kmTableNearest and kmTableLinear kernel modes, kernel values are
  565. // precomputed in a look-up table. This allows GetSample to execute faster for
  566. // complex kernels.
  567. //------------------------------------------------------------------------------
  568. type
  569. TKernelMode = (kmDynamic, kmTableNearest, kmTableLinear);
  570. TKernelResampler = class(TCustomResampler)
  571. private
  572. FKernel: TCustomKernel;
  573. FKernelMode: TKernelMode;
  574. FWeightTable: TIntegerMap;
  575. FTableSize: Integer;
  576. FOuterColor: TColor32;
  577. procedure SetKernel(const Value: TCustomKernel);
  578. function GetKernelClassName: string;
  579. procedure SetKernelClassName(const Value: string);
  580. procedure SetKernelMode(const Value: TKernelMode);
  581. procedure SetTableSize(Value: Integer);
  582. protected
  583. function GetWidth: TFloat; override;
  584. public
  585. constructor Create; override;
  586. destructor Destroy; override;
  587. function GetSampleFloat(X, Y: TFloat): TColor32; override;
  588. procedure Resample(
  589. Dst: TCustomBitmap32; DstRect: TRect; DstClip: TRect;
  590. Src: TCustomBitmap32; SrcRect: TRect;
  591. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent); override;
  592. procedure PrepareSampling; override;
  593. procedure FinalizeSampling; override;
  594. published
  595. property KernelClassName: string read GetKernelClassName write SetKernelClassName;
  596. property Kernel: TCustomKernel read FKernel write SetKernel;
  597. property KernelMode: TKernelMode read FKernelMode write SetKernelMode;
  598. property TableSize: Integer read FTableSize write SetTableSize;
  599. end;
  600. //------------------------------------------------------------------------------
  601. //
  602. // TNestedSampler
  603. //
  604. //------------------------------------------------------------------------------
  605. // TNestedSampler is a base class for chained or nested samplers.
  606. //------------------------------------------------------------------------------
  607. type
  608. TNestedSampler = class(TCustomSampler)
  609. private
  610. FSampler: TCustomSampler;
  611. FGetSampleInt: TGetSampleInt;
  612. FGetSampleFixed: TGetSampleFixed;
  613. FGetSampleFloat: TGetSampleFloat;
  614. procedure SetSampler(const Value: TCustomSampler);
  615. protected
  616. procedure AssignTo(Dst: TPersistent); override;
  617. public
  618. constructor Create(ASampler: TCustomSampler); reintroduce; virtual;
  619. procedure PrepareSampling; override;
  620. procedure FinalizeSampling; override;
  621. function HasBounds: Boolean; override;
  622. function GetSampleBounds: TFloatRect; override;
  623. published
  624. property Sampler: TCustomSampler read FSampler write SetSampler;
  625. end;
  626. //------------------------------------------------------------------------------
  627. //
  628. // TTransformer
  629. //
  630. //------------------------------------------------------------------------------
  631. // TTransformer is a nested sampler that will transform the sampling coordinates
  632. // using a transformation defined by a TTransformation descendant.
  633. //------------------------------------------------------------------------------
  634. type
  635. TTransformInt = procedure(DstX, DstY: Integer; out SrcX, SrcY: Integer) of object;
  636. TTransformFixed = procedure(DstX, DstY: TFixed; out SrcX, SrcY: TFixed) of object;
  637. TTransformFloat = procedure(DstX, DstY: TFloat; out SrcX, SrcY: TFloat) of object;
  638. TTransformer = class(TNestedSampler)
  639. private
  640. FTransformation: TTransformation;
  641. FTransformInt: TTransformInt; // Unused
  642. FTransformFixed: TTransformFixed;
  643. FTransformFloat: TTransformFloat;
  644. FReverse: boolean;
  645. public
  646. constructor Create(ASampler: TCustomSampler; ATransformation: TTransformation; AReverse: boolean = True); reintroduce;
  647. procedure PrepareSampling; override;
  648. function GetSampleInt(X, Y: Integer): TColor32; override;
  649. function GetSampleFixed(X, Y: TFixed): TColor32; override;
  650. function GetSampleFloat(X, Y: TFloat): TColor32; override;
  651. function HasBounds: Boolean; override;
  652. function GetSampleBounds: TFloatRect; override;
  653. published
  654. property Transformation: TTransformation read FTransformation write FTransformation;
  655. property ReverseTransform: boolean read FReverse write FReverse;
  656. end;
  657. //------------------------------------------------------------------------------
  658. //
  659. // TSuperSampler
  660. //
  661. //------------------------------------------------------------------------------
  662. // TSuperSampler is a nested sampler that adds a mechanism for performing super
  663. // sampling.
  664. //------------------------------------------------------------------------------
  665. type
  666. TSamplingRange = 1..MaxInt;
  667. TSuperSampler = class(TNestedSampler)
  668. private
  669. FSamplingY: TSamplingRange;
  670. FSamplingX: TSamplingRange;
  671. FDistanceX: TFixed;
  672. FDistanceY: TFixed;
  673. FOffsetX: TFixed;
  674. FOffsetY: TFixed;
  675. FScale: TFixed;
  676. procedure SetSamplingX(const Value: TSamplingRange);
  677. procedure SetSamplingY(const Value: TSamplingRange);
  678. public
  679. constructor Create(Sampler: TCustomSampler); override;
  680. function GetSampleFixed(X, Y: TFixed): TColor32; override;
  681. published
  682. property SamplingX: TSamplingRange read FSamplingX write SetSamplingX;
  683. property SamplingY: TSamplingRange read FSamplingY write SetSamplingY;
  684. end;
  685. //------------------------------------------------------------------------------
  686. //
  687. // TAdaptiveSuperSampler
  688. //
  689. //------------------------------------------------------------------------------
  690. // Adaptive supersampling is different from ordinary supersampling in the sense
  691. // that samples are choosen adaptively; It is a recursive method that collects
  692. // more samples at areas with rapid transitions.
  693. //------------------------------------------------------------------------------
  694. type
  695. TRecurseProc = function(X, Y, W: TFixed; const C1, C2: TColor32): TColor32 of object;
  696. TAdaptiveSuperSampler = class(TNestedSampler)
  697. private
  698. FMinOffset: TFixed;
  699. FLevel: Integer;
  700. FTolerance: Integer;
  701. procedure SetLevel(const Value: Integer);
  702. function DoRecurse(X, Y, Offset: TFixed; const A, B, C, D, E: TColor32): TColor32;
  703. function QuadrantColor(const C1, C2: TColor32; X, Y, Offset: TFixed;
  704. Proc: TRecurseProc): TColor32;
  705. function RecurseAC(X, Y, Offset: TFixed; const A, C: TColor32): TColor32;
  706. function RecurseBD(X, Y, Offset: TFixed; const B, D: TColor32): TColor32;
  707. protected
  708. function CompareColors(C1, C2: TColor32): Boolean; virtual;
  709. public
  710. constructor Create(Sampler: TCustomSampler); override;
  711. function GetSampleFixed(X, Y: TFixed): TColor32; override;
  712. published
  713. property Level: Integer read FLevel write SetLevel;
  714. property Tolerance: Integer read FTolerance write FTolerance;
  715. end;
  716. //------------------------------------------------------------------------------
  717. //
  718. // TPatternSampler
  719. //
  720. //------------------------------------------------------------------------------
  721. // TPatternSampler provides a mechanism for performing sampling according to a
  722. // supplied sample pattern.
  723. //------------------------------------------------------------------------------
  724. type
  725. TFloatSamplePattern = array of array of TArrayOfFloatPoint;
  726. TFixedSamplePattern = array of array of TArrayOfFixedPoint;
  727. TPatternSampler = class(TNestedSampler)
  728. private
  729. FPattern: TFixedSamplePattern;
  730. procedure SetPattern(const Value: TFixedSamplePattern);
  731. protected
  732. WrapProcVert: TWrapProc;
  733. public
  734. destructor Destroy; override;
  735. function GetSampleFixed(X, Y: TFixed): TColor32; override;
  736. property Pattern: TFixedSamplePattern read FPattern write SetPattern;
  737. end;
  738. { Auxiliary record used in accumulation routines }
  739. PBufferEntry = ^TBufferEntry;
  740. TBufferEntry = record
  741. B, G, R, A: Integer;
  742. end;
  743. //------------------------------------------------------------------------------
  744. //
  745. // TKernelSampler
  746. //
  747. //------------------------------------------------------------------------------
  748. // TKernelSampler is an abstract base class for samplers that compute an output
  749. // sample by collecting a number of samples in a local region of the actual
  750. // sample coordinate.
  751. //------------------------------------------------------------------------------
  752. type
  753. TKernelSampler = class(TNestedSampler)
  754. private
  755. FKernel: TIntegerMap;
  756. FStartEntry: TBufferEntry;
  757. FCenterX: Integer;
  758. FCenterY: Integer;
  759. protected
  760. procedure SetKernel(const Value: TIntegerMap);
  761. procedure UpdateBuffer(var Buffer: TBufferEntry; Color: TColor32;
  762. Weight: Integer); virtual; abstract;
  763. function ConvertBuffer(var Buffer: TBufferEntry): TColor32; virtual;
  764. public
  765. constructor Create(ASampler: TCustomSampler); override;
  766. destructor Destroy; override;
  767. function GetSampleInt(X, Y: Integer): TColor32; override;
  768. function GetSampleFixed(X, Y: TFixed): TColor32; override;
  769. published
  770. property Kernel: TIntegerMap read FKernel write SetKernel;
  771. property CenterX: Integer read FCenterX write FCenterX;
  772. property CenterY: Integer read FCenterY write FCenterY;
  773. end;
  774. //------------------------------------------------------------------------------
  775. //
  776. // TConvolver
  777. //
  778. //------------------------------------------------------------------------------
  779. // The TConvolver kernel sampler provides functionality for performing discrete
  780. // convolution within a chain of nested samplers.
  781. //------------------------------------------------------------------------------
  782. type
  783. TConvolver = class(TKernelSampler)
  784. protected
  785. procedure UpdateBuffer(var Buffer: TBufferEntry; Color: TColor32;
  786. Weight: Integer); override;
  787. end;
  788. //------------------------------------------------------------------------------
  789. //
  790. // TSelectiveConvolver
  791. //
  792. //------------------------------------------------------------------------------
  793. // TSelectiveConvolver works similarly to TConvolver, but it will exclude color
  794. // samples from the convolution depending on a the difference from a local
  795. // reference sample value.
  796. //------------------------------------------------------------------------------
  797. type
  798. TSelectiveConvolver = class(TConvolver)
  799. private
  800. FRefColor: TColor32;
  801. FDelta: Integer;
  802. FWeightSum: TBufferEntry;
  803. protected
  804. procedure UpdateBuffer(var Buffer: TBufferEntry; Color: TColor32;
  805. Weight: Integer); override;
  806. function ConvertBuffer(var Buffer: TBufferEntry): TColor32; override;
  807. public
  808. constructor Create(ASampler: TCustomSampler); override;
  809. function GetSampleInt(X, Y: Integer): TColor32; override;
  810. function GetSampleFixed(X, Y: TFixed): TColor32; override;
  811. published
  812. property Delta: Integer read FDelta write FDelta;
  813. end;
  814. //------------------------------------------------------------------------------
  815. //
  816. // TMorphologicalSampler
  817. //
  818. //------------------------------------------------------------------------------
  819. // Abstract base class for TDilater and TEroder.
  820. //------------------------------------------------------------------------------
  821. type
  822. TMorphologicalSampler = class(TKernelSampler)
  823. protected
  824. function ConvertBuffer(var Buffer: TBufferEntry): TColor32; override;
  825. end;
  826. //------------------------------------------------------------------------------
  827. //
  828. // TDilater
  829. //
  830. //------------------------------------------------------------------------------
  831. // TDilater is a nested sampler for performing morphological dilation.
  832. //------------------------------------------------------------------------------
  833. type
  834. TDilater = class(TMorphologicalSampler)
  835. protected
  836. procedure UpdateBuffer(var Buffer: TBufferEntry; Color: TColor32;
  837. Weight: Integer); override;
  838. end;
  839. //------------------------------------------------------------------------------
  840. //
  841. // TEroder
  842. //
  843. //------------------------------------------------------------------------------
  844. // TEroder is a nested sampler for performing morphological erosion
  845. //------------------------------------------------------------------------------
  846. type
  847. TEroder = class(TMorphologicalSampler)
  848. protected
  849. procedure UpdateBuffer(var Buffer: TBufferEntry; Color: TColor32;
  850. Weight: Integer); override;
  851. public
  852. constructor Create(ASampler: TCustomSampler); override;
  853. end;
  854. //------------------------------------------------------------------------------
  855. //
  856. // TExpander
  857. //
  858. //------------------------------------------------------------------------------
  859. // TExpander implements a neighborhood operation similar to morphological
  860. // dilation.
  861. //------------------------------------------------------------------------------
  862. type
  863. TExpander = class(TKernelSampler)
  864. protected
  865. procedure UpdateBuffer(var Buffer: TBufferEntry; Color: TColor32;
  866. Weight: Integer); override;
  867. end;
  868. //------------------------------------------------------------------------------
  869. //
  870. // TContracter
  871. //
  872. //------------------------------------------------------------------------------
  873. // Similar to TExpander, but contracts instead of exanding.
  874. //------------------------------------------------------------------------------
  875. type
  876. TContracter = class(TExpander)
  877. private
  878. FMaxWeight: TColor32;
  879. protected
  880. procedure UpdateBuffer(var Buffer: TBufferEntry; Color: TColor32;
  881. Weight: Integer); override;
  882. public
  883. procedure PrepareSampling; override;
  884. function GetSampleInt(X, Y: Integer): TColor32; override;
  885. function GetSampleFixed(X, Y: TFixed): TColor32; override;
  886. end;
  887. //------------------------------------------------------------------------------
  888. //
  889. // CreateJitteredPattern
  890. //
  891. //------------------------------------------------------------------------------
  892. // Create a random jitter pattern for use with TPatternSampler.
  893. //------------------------------------------------------------------------------
  894. function CreateJitteredPattern(TileWidth, TileHeight, SamplesX, SamplesY: Integer): TFixedSamplePattern;
  895. //------------------------------------------------------------------------------
  896. //
  897. // Convolution and morphological routines
  898. //
  899. //------------------------------------------------------------------------------
  900. // Kernel sampler wrapper functions.
  901. //------------------------------------------------------------------------------
  902. procedure Convolve(Src, Dst: TCustomBitmap32; Kernel: TIntegerMap; CenterX, CenterY: Integer);
  903. procedure Dilate(Src, Dst: TCustomBitmap32; Kernel: TIntegerMap; CenterX, CenterY: Integer);
  904. procedure Erode(Src, Dst: TCustomBitmap32; Kernel: TIntegerMap; CenterX, CenterY: Integer);
  905. procedure Expand(Src, Dst: TCustomBitmap32; Kernel: TIntegerMap; CenterX, CenterY: Integer);
  906. procedure Contract(Src, Dst: TCustomBitmap32; Kernel: TIntegerMap; CenterX, CenterY: Integer);
  907. //------------------------------------------------------------------------------
  908. //
  909. // Auxiliary routines for accumulating colors in a buffer
  910. //
  911. //------------------------------------------------------------------------------
  912. procedure IncBuffer(var Buffer: TBufferEntry; Color: TColor32); {$IFDEF USEINLINING} inline; {$ENDIF}
  913. procedure MultiplyBuffer(var Buffer: TBufferEntry; W: Integer); {$IFDEF USEINLINING} inline; {$ENDIF}
  914. function BufferToColor32(const Buffer: TBufferEntry; Shift: Integer): TColor32; {$IFDEF USEINLINING} inline; {$ENDIF}
  915. procedure ShrBuffer(var Buffer: TBufferEntry; Shift: Integer); {$IFDEF USEINLINING} inline; {$ENDIF}
  916. //------------------------------------------------------------------------------
  917. //
  918. // Downsample byte map
  919. //
  920. //------------------------------------------------------------------------------
  921. procedure DownsampleByteMap2x(Source, Dest: TByteMap);
  922. procedure DownsampleByteMap3x(Source, Dest: TByteMap);
  923. procedure DownsampleByteMap4x(Source, Dest: TByteMap);
  924. //------------------------------------------------------------------------------
  925. //
  926. // Registration routines
  927. //
  928. //------------------------------------------------------------------------------
  929. procedure RegisterResampler(ResamplerClass: TCustomResamplerClass);
  930. procedure RegisterKernel(KernelClass: TCustomKernelClass);
  931. var
  932. KernelList: TCustomClassList<TCustomKernelClass>;
  933. ResamplerList: TCustomClassList<TCustomResamplerClass>;
  934. const
  935. EMPTY_ENTRY: TBufferEntry = (B: 0; G: 0; R: 0; A: 0) deprecated 'Use Default(TBufferEntry)';
  936. //------------------------------------------------------------------------------
  937. //
  938. // Bindings
  939. //
  940. //------------------------------------------------------------------------------
  941. var
  942. BlockAverage: function(Dlx, Dly: Cardinal; RowSrc: PColor32; OffSrc: Cardinal): TColor32;
  943. Interpolator: function(WX_256, WY_256: Cardinal; C11, C21: PColor32): TColor32;
  944. //------------------------------------------------------------------------------
  945. resourcestring
  946. SDstNil = 'Destination bitmap is nil';
  947. SSrcNil = 'Source bitmap is nil';
  948. SSrcInvalid = 'Source rectangle is invalid';
  949. SSamplerNil = 'Nested sampler is nil';
  950. STransformationNil = 'Transformation is nil';
  951. //------------------------------------------------------------------------------
  952. //------------------------------------------------------------------------------
  953. //------------------------------------------------------------------------------
  954. implementation
  955. uses
  956. Math,
  957. Types,
  958. GR32_Bindings,
  959. GR32_LowLevel,
  960. GR32_Rasterizers,
  961. GR32_Math,
  962. GR32_Gamma;
  963. resourcestring
  964. RCStrInvalidSrcRect = 'Invalid SrcRect';
  965. const
  966. CAlbrecht2 : array [0..1] of Double = (5.383553946707251E-1,
  967. 4.616446053292749E-1);
  968. CAlbrecht3 : array [0..2] of Double = (3.46100822018625E-1,
  969. 4.97340635096738E-1, 1.56558542884637E-1);
  970. CAlbrecht4 : array [0..3] of Double = (2.26982412792069E-1,
  971. 4.57254070828427E-1, 2.73199027957384E-1, 4.25644884221201E-2);
  972. CAlbrecht5 : array [0..4] of Double = (1.48942606015830E-1,
  973. 3.86001173639176E-1, 3.40977403214053E-1, 1.139879604246E-1,
  974. 1.00908567063414E-2);
  975. CAlbrecht6 : array [0..5] of Double = (9.71676200107429E-2,
  976. 3.08845222524055E-1, 3.62623371437917E-1, 1.88953325525116E-1,
  977. 4.02095714148751E-2, 2.20088908729420E-3);
  978. CAlbrecht7 : array [0..6] of Double = (6.39644241143904E-2,
  979. 2.39938645993528E-1, 3.50159563238205E-1, 2.47741118970808E-1,
  980. 8.54382560558580E-2, 1.23202033692932E-2, 4.37788257917735E-4);
  981. CAlbrecht8 : array [0..7] of Double = (4.21072107042137E-2,
  982. 1.82076226633776E-1, 3.17713781059942E-1, 2.84438001373442E-1,
  983. 1.36762237777383E-1, 3.34038053504025E-2, 3.41677216705768E-3,
  984. 8.19649337831348E-5);
  985. CAlbrecht9 : array [0..8] of Double = (2.76143731612611E-2,
  986. 1.35382228758844E-1, 2.75287234472237E-1, 2.98843335317801E-1,
  987. 1.85319330279284E-1, 6.48884482549063E-2, 1.17641910285655E-2,
  988. 8.85987580106899E-4, 1.48711469943406E-5);
  989. CAlbrecht10: array [0..9] of Double = (1.79908225352538E-2,
  990. 9.87959586065210E-2, 2.29883817001211E-1, 2.94113019095183E-1,
  991. 2.24338977814325E-1, 1.03248806248099E-1, 2.75674109448523E-2,
  992. 3.83958622947123E-3, 2.18971708430106E-4, 2.62981665347889E-6);
  993. CAlbrecht11: array [0..10] of Double = (1.18717127796602E-2,
  994. 7.19533651951142E-2, 1.87887160922585E-1, 2.75808174097291E-1,
  995. 2.48904243244464E-1, 1.41729867200712E-1, 5.02002976228256E-2,
  996. 1.04589649084984E-2, 1.13615112741660E-3, 4.96285981703436E-5,
  997. 4.34303262685720E-7);
  998. type
  999. TTransformationAccess = class(TTransformation);
  1000. TCustomBitmap32Access = class(TCustomBitmap32);
  1001. TCustomResamplerAccess = class(TCustomResampler);
  1002. TCustomKernelAccess = class(TCustomKernel);
  1003. TPointRec = record
  1004. Pos: Integer;
  1005. Weight: Integer;
  1006. end;
  1007. TCluster = array of TPointRec;
  1008. TMappingTable = array of TCluster;
  1009. TKernelSamplerClass = class of TKernelSampler;
  1010. { Auxiliary rasterization routine for kernel-based samplers }
  1011. procedure RasterizeKernelSampler(Src, Dst: TCustomBitmap32; Kernel: TIntegerMap;
  1012. CenterX, CenterY: Integer; SamplerClass: TKernelSamplerClass);
  1013. var
  1014. Sampler: TKernelSampler;
  1015. Rasterizer: TRasterizer;
  1016. begin
  1017. Rasterizer := DefaultRasterizerClass.Create;
  1018. try
  1019. Dst.SetSizeFrom(Src);
  1020. Sampler := SamplerClass.Create(Src.Resampler);
  1021. try
  1022. Sampler.Kernel := Kernel;
  1023. Sampler.CenterX := CenterX;
  1024. Sampler.CenterY := CenterY;
  1025. Rasterizer.Sampler := Sampler;
  1026. Rasterizer.Rasterize(Dst);
  1027. finally
  1028. Sampler.Free;
  1029. end;
  1030. finally
  1031. Rasterizer.Free;
  1032. end;
  1033. end;
  1034. procedure Convolve(Src, Dst: TCustomBitmap32; Kernel: TIntegerMap; CenterX, CenterY: Integer);
  1035. begin
  1036. RasterizeKernelSampler(Src, Dst, Kernel, CenterX, CenterY, TConvolver);
  1037. end;
  1038. procedure Dilate(Src, Dst: TCustomBitmap32; Kernel: TIntegerMap; CenterX, CenterY: Integer);
  1039. begin
  1040. RasterizeKernelSampler(Src, Dst, Kernel, CenterX, CenterY, TDilater);
  1041. end;
  1042. procedure Erode(Src, Dst: TCustomBitmap32; Kernel: TIntegerMap; CenterX, CenterY: Integer);
  1043. begin
  1044. RasterizeKernelSampler(Src, Dst, Kernel, CenterX, CenterY, TEroder);
  1045. end;
  1046. procedure Expand(Src, Dst: TCustomBitmap32; Kernel: TIntegerMap; CenterX, CenterY: Integer);
  1047. begin
  1048. RasterizeKernelSampler(Src, Dst, Kernel, CenterX, CenterY, TExpander);
  1049. end;
  1050. procedure Contract(Src, Dst: TCustomBitmap32; Kernel: TIntegerMap; CenterX, CenterY: Integer);
  1051. begin
  1052. RasterizeKernelSampler(Src, Dst, Kernel, CenterX, CenterY, TContracter);
  1053. end;
  1054. { Auxiliary routines }
  1055. procedure IncBuffer(var Buffer: TBufferEntry; Color: TColor32);
  1056. begin
  1057. with TColor32Entry(Color) do
  1058. begin
  1059. Inc(Buffer.B, B);
  1060. Inc(Buffer.G, G);
  1061. Inc(Buffer.R, R);
  1062. Inc(Buffer.A, A);
  1063. end;
  1064. end;
  1065. procedure MultiplyBuffer(var Buffer: TBufferEntry; W: Integer);
  1066. begin
  1067. Buffer.B := Buffer.B * W;
  1068. Buffer.G := Buffer.G * W;
  1069. Buffer.R := Buffer.R * W;
  1070. Buffer.A := Buffer.A * W;
  1071. end;
  1072. procedure ShrBuffer(var Buffer: TBufferEntry; Shift: Integer);
  1073. begin
  1074. Buffer.B := Buffer.B shr Shift;
  1075. Buffer.G := Buffer.G shr Shift;
  1076. Buffer.R := Buffer.R shr Shift;
  1077. Buffer.A := Buffer.A shr Shift;
  1078. end;
  1079. function BufferToColor32(const Buffer: TBufferEntry; Shift: Integer): TColor32;
  1080. begin
  1081. with TColor32Entry(Result) do
  1082. begin
  1083. B := Buffer.B shr Shift;
  1084. G := Buffer.G shr Shift;
  1085. R := Buffer.R shr Shift;
  1086. A := Buffer.A shr Shift;
  1087. end;
  1088. end;
  1089. procedure CheckBitmaps(Dst, Src: TCustomBitmap32); {$IFDEF USEINLINING}inline;{$ENDIF}
  1090. begin
  1091. if not Assigned(Dst) then raise EBitmapException.Create(SDstNil);
  1092. if not Assigned(Src) then raise EBitmapException.Create(SSrcNil);
  1093. end;
  1094. procedure BlendBlock(
  1095. Dst: TCustomBitmap32; DstRect: TRect;
  1096. Src: TCustomBitmap32; SrcX, SrcY: Integer;
  1097. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
  1098. var
  1099. SrcP, DstP: PColor32;
  1100. SP, DP: PColor32;
  1101. MC: TColor32;
  1102. W, I, DstY: Integer;
  1103. BlendLine: TBlendLine;
  1104. BlendLineEx: TBlendLineEx;
  1105. begin
  1106. { Internal routine }
  1107. W := DstRect.Right - DstRect.Left;
  1108. SrcP := Src.PixelPtr[SrcX, SrcY];
  1109. DstP := Dst.PixelPtr[DstRect.Left, DstRect.Top];
  1110. case CombineOp of
  1111. dmOpaque:
  1112. begin
  1113. for DstY := DstRect.Top to DstRect.Bottom - 1 do
  1114. begin
  1115. //Move(SrcP^, DstP^, W shl 2); // for FastCode
  1116. MoveLongWord(SrcP^, DstP^, W);
  1117. Inc(SrcP, Src.Width);
  1118. Inc(DstP, Dst.Width);
  1119. end;
  1120. end;
  1121. dmBlend:
  1122. if Src.MasterAlpha >= 255 then
  1123. begin
  1124. BlendLine := BLEND_LINE[Src.CombineMode]^;
  1125. for DstY := DstRect.Top to DstRect.Bottom - 1 do
  1126. begin
  1127. BlendLine(SrcP, DstP, W);
  1128. Inc(SrcP, Src.Width);
  1129. Inc(DstP, Dst.Width);
  1130. end
  1131. end
  1132. else
  1133. begin
  1134. BlendLineEx := BLEND_LINE_EX[Src.CombineMode]^;
  1135. for DstY := DstRect.Top to DstRect.Bottom - 1 do
  1136. begin
  1137. BlendLineEx(SrcP, DstP, W, Src.MasterAlpha);
  1138. Inc(SrcP, Src.Width);
  1139. Inc(DstP, Dst.Width);
  1140. end
  1141. end;
  1142. dmTransparent:
  1143. begin
  1144. MC := Src.OuterColor;
  1145. for DstY := DstRect.Top to DstRect.Bottom - 1 do
  1146. begin
  1147. SP := SrcP;
  1148. DP := DstP;
  1149. { TODO: Write an optimized routine for fast masked transfers. }
  1150. for I := 0 to W - 1 do
  1151. begin
  1152. if MC <> SP^ then DP^ := SP^;
  1153. Inc(SP); Inc(DP);
  1154. end;
  1155. Inc(SrcP, Src.Width);
  1156. Inc(DstP, Dst.Width);
  1157. end;
  1158. end;
  1159. else // dmCustom:
  1160. begin
  1161. for DstY := DstRect.Top to DstRect.Bottom - 1 do
  1162. begin
  1163. SP := SrcP;
  1164. DP := DstP;
  1165. for I := 0 to W - 1 do
  1166. begin
  1167. CombineCallBack(SP^, DP^, Src.MasterAlpha);
  1168. Inc(SP); Inc(DP);
  1169. end;
  1170. Inc(SrcP, Src.Width);
  1171. Inc(DstP, Dst.Width);
  1172. end;
  1173. end;
  1174. end;
  1175. end;
  1176. //------------------------------------------------------------------------------
  1177. //
  1178. // BlockTransfer
  1179. //
  1180. //------------------------------------------------------------------------------
  1181. procedure BlockTransfer(
  1182. Dst: TCustomBitmap32; DstX: Integer; DstY: Integer; DstClip: TRect;
  1183. Src: TCustomBitmap32; SrcRect: TRect;
  1184. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
  1185. var
  1186. SrcX, SrcY: Integer;
  1187. begin
  1188. CheckBitmaps(Dst, Src);
  1189. if Dst.Empty or Src.Empty or ((CombineOp = dmBlend) and (Src.MasterAlpha = 0)) then Exit;
  1190. SrcX := SrcRect.Left;
  1191. SrcY := SrcRect.Top;
  1192. GR32.IntersectRect(DstClip, DstClip, Dst.BoundsRect);
  1193. GR32.IntersectRect(SrcRect, SrcRect, Src.BoundsRect);
  1194. GR32.OffsetRect(SrcRect, DstX - SrcX, DstY - SrcY);
  1195. GR32.IntersectRect(SrcRect, DstClip, SrcRect);
  1196. if GR32.IsRectEmpty(SrcRect) then
  1197. exit;
  1198. DstClip := SrcRect;
  1199. GR32.OffsetRect(SrcRect, SrcX - DstX, SrcY - DstY);
  1200. if not Dst.MeasuringMode then
  1201. begin
  1202. if (CombineOp = dmCustom) and not Assigned(CombineCallBack) then
  1203. CombineOp := dmOpaque;
  1204. BlendBlock(Dst, DstClip, Src, SrcRect.Left, SrcRect.Top, CombineOp, CombineCallBack);
  1205. end;
  1206. Dst.Changed(DstClip);
  1207. end;
  1208. //------------------------------------------------------------------------------
  1209. {$WARNINGS OFF}
  1210. procedure BlockTransferX(
  1211. Dst: TCustomBitmap32; DstX, DstY: TFixed;
  1212. Src: TCustomBitmap32; SrcRect: TRect;
  1213. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent = nil);
  1214. type
  1215. TColor32Array = array [0..1] of TColor32;
  1216. PColor32Array = ^TColor32Array;
  1217. var
  1218. I, Index, SrcW, SrcRectW, SrcRectH, DstW, DstH: Integer;
  1219. FracX, FracY: Integer;
  1220. Buffer: array [0..1] of TArrayOfColor32;
  1221. SrcP, Buf1, Buf2: PColor32Array;
  1222. DstP: PColor32;
  1223. C1, C2, C3, C4: TColor32;
  1224. LW, RW, TW, BW, MA: Integer;
  1225. DstBounds: TRect;
  1226. BlendLineEx: TBlendLineEx;
  1227. BlendMemEx: TBlendMemEx;
  1228. begin
  1229. CheckBitmaps(Dst, Src);
  1230. if Dst.Empty or Src.Empty or ((CombineOp = dmBlend) and (Src.MasterAlpha = 0)) then Exit;
  1231. SrcRectW := SrcRect.Right - SrcRect.Left - 1;
  1232. SrcRectH := SrcRect.Bottom - SrcRect.Top - 1;
  1233. FracX := (DstX and $FFFF) shr 8;
  1234. FracY := (DstY and $FFFF) shr 8;
  1235. DstX := DstX div $10000;
  1236. DstY := DstY div $10000;
  1237. DstW := Dst.Width;
  1238. DstH := Dst.Height;
  1239. MA := Src.MasterAlpha;
  1240. if (DstX >= DstW) or (DstY >= DstH) or (MA = 0) then Exit;
  1241. if (DstX + SrcRectW <= 0) or (Dsty + SrcRectH <= 0) then Exit;
  1242. if DstX < 0 then LW := $FF else LW := FracX xor $FF;
  1243. if DstY < 0 then TW := $FF else TW := FracY xor $FF;
  1244. if DstX + SrcRectW >= DstW then RW := $FF else RW := FracX;
  1245. if DstY + SrcRectH >= DstH then BW := $FF else BW := FracY;
  1246. DstBounds := Dst.BoundsRect;
  1247. Dec(DstBounds.Right);
  1248. Dec(DstBounds.Bottom);
  1249. GR32.OffsetRect(DstBounds, SrcRect.Left - DstX, SrcRect.Top - DstY);
  1250. GR32.IntersectRect(SrcRect, SrcRect, DstBounds);
  1251. if GR32.IsRectEmpty(SrcRect) then Exit;
  1252. SrcW := Src.Width;
  1253. SrcRectW := SrcRect.Right - SrcRect.Left;
  1254. SrcRectH := SrcRect.Bottom - SrcRect.Top;
  1255. if DstX < 0 then DstX := 0;
  1256. if DstY < 0 then DstY := 0;
  1257. if not Dst.MeasuringMode then
  1258. begin
  1259. SetLength(Buffer[0], SrcRectW + 1);
  1260. SetLength(Buffer[1], SrcRectW + 1);
  1261. BlendLineEx := BLEND_LINE_EX[Src.CombineMode]^;
  1262. BlendMemEx := BLEND_MEM_EX[Src.CombineMode]^;
  1263. try
  1264. SrcP := PColor32Array(Src.PixelPtr[SrcRect.Left, SrcRect.Top - 1]);
  1265. DstP := Dst.PixelPtr[DstX, DstY];
  1266. Buf1 := @Buffer[0][0];
  1267. Buf2 := @Buffer[1][0];
  1268. if SrcRect.Top > 0 then
  1269. begin
  1270. MoveLongWord(SrcP[0], Buf1[0], SrcRectW);
  1271. CombineLine(@Buf1[1], @Buf1[0], SrcRectW, FracX);
  1272. if SrcRect.Left > 0 then
  1273. C2 := CombineReg(PColor32(NativeUInt(SrcP) - 4)^, SrcP[0], FracX xor $FF)
  1274. else
  1275. C2 := SrcP[0];
  1276. if SrcRect.Right < SrcW then
  1277. C4 := CombineReg(SrcP[SrcRectW - 1], SrcP[SrcRectW], FracX)
  1278. else
  1279. C4 := SrcP[SrcRectW - 1];
  1280. end;
  1281. Inc(PColor32(SrcP), SrcW);
  1282. MoveLongWord(SrcP^, Buf2^, SrcRectW);
  1283. CombineLine(@Buf2[1], @Buf2[0], SrcRectW, FracX xor $FF);
  1284. if SrcRect.Left > 0 then
  1285. C1 := CombineReg(PColor32(NativeUInt(SrcP) - 4)^, SrcP[0], FracX)
  1286. else
  1287. C1 := SrcP[0];
  1288. if SrcRect.Right < SrcW then
  1289. C3 := CombineReg(SrcP[SrcRectW - 1], SrcP[SrcRectW], FracX)
  1290. else
  1291. C3 := SrcP[SrcRectW - 1];
  1292. if SrcRect.Top > 0 then
  1293. begin
  1294. BlendMemEx(CombineReg(C1, C2, FracY), DstP^, LW * TW * MA shr 16);
  1295. CombineLine(@Buf2[0], @Buf1[0], SrcRectW, FracY xor $FF);
  1296. end
  1297. else
  1298. begin
  1299. BlendMemEx(C1, DstP^, LW * TW * MA shr 16);
  1300. MoveLongWord(Buf2^, Buf1^, SrcRectW);
  1301. end;
  1302. Inc(DstP, 1);
  1303. BlendLineEx(@Buf1[0], DstP, SrcRectW - 1, TW * MA shr 8);
  1304. Inc(DstP, SrcRectW - 1);
  1305. if SrcRect.Top > 0 then
  1306. BlendMemEx(CombineReg(C3, C4, FracY), DstP^, RW * TW * MA shr 16)
  1307. else
  1308. BlendMemEx(C3, DstP^, RW * TW * MA shr 16);
  1309. Inc(DstP, DstW - SrcRectW);
  1310. Index := 1;
  1311. for I := SrcRect.Top to SrcRect.Bottom - 2 do
  1312. begin
  1313. Buf1 := @Buffer[Index][0];
  1314. Buf2 := @Buffer[Index xor 1][0];
  1315. Inc(PColor32(SrcP), SrcW);
  1316. MoveLongWord(SrcP[0], Buf2^, SrcRectW);
  1317. // Horizontal translation
  1318. CombineLine(@Buf2[1], @Buf2[0], SrcRectW, FracX xor $FF);
  1319. if SrcRect.Left > 0 then
  1320. C2 := CombineReg(PColor32(NativeUInt(SrcP) - 4)^, SrcP[0], FracX xor $FF)
  1321. else
  1322. C2 := SrcP[0];
  1323. BlendMemEx(CombineReg(C1, C2, FracY), DstP^, LW * MA shr 8);
  1324. Inc(DstP);
  1325. C1 := C2;
  1326. // Vertical translation
  1327. CombineLine(@Buf2[0], @Buf1[0], SrcRectW, FracY xor $FF);
  1328. // Blend horizontal line to Dst
  1329. BlendLineEx(@Buf1[0], DstP, SrcRectW - 1, MA);
  1330. Inc(DstP, SrcRectW - 1);
  1331. if SrcRect.Right < SrcW then
  1332. C4 := CombineReg(SrcP[SrcRectW - 1], SrcP[SrcRectW], FracX)
  1333. else
  1334. C4 := SrcP[SrcRectW - 1];
  1335. BlendMemEx(CombineReg(C3, C4, FracY), DstP^, RW * MA shr 8);
  1336. Inc(DstP, DstW - SrcRectW);
  1337. C3 := C4;
  1338. Index := Index xor 1;
  1339. end;
  1340. Buf1 := @Buffer[Index][0];
  1341. Buf2 := @Buffer[Index xor 1][0];
  1342. Inc(PColor32(SrcP), SrcW);
  1343. if SrcRect.Bottom < Src.Height then
  1344. begin
  1345. MoveLongWord(SrcP[0], Buf2^, SrcRectW);
  1346. CombineLine(@Buf2[1], @Buf2[0], SrcRectW, FracY xor $FF);
  1347. CombineLine(@Buf2[0], @Buf1[0], SrcRectW, FracY xor $FF);
  1348. if SrcRect.Left > 0 then
  1349. C2 := CombineReg(PColor32(NativeUInt(SrcP) - 4)^, SrcP[0], FracX xor $FF)
  1350. else
  1351. C2 := SrcP[0];
  1352. BlendMemEx(CombineReg(C1, C2, FracY), DstP^, LW * BW * MA shr 16)
  1353. end
  1354. else
  1355. BlendMemEx(C1, DstP^, LW * BW * MA shr 16);
  1356. Inc(DstP);
  1357. BlendLineEx(@Buf1[0], DstP, SrcRectW - 1, BW * MA shr 8);
  1358. Inc(DstP, SrcRectW - 1);
  1359. if SrcRect.Bottom < Src.Height then
  1360. begin
  1361. if SrcRect.Right < SrcW then
  1362. C4 := CombineReg(SrcP[SrcRectW - 1], SrcP[SrcRectW], FracX)
  1363. else
  1364. C4 := SrcP[SrcRectW - 1];
  1365. BlendMemEx(CombineReg(C3, C4, FracY), DstP^, RW * BW * MA shr 16);
  1366. end
  1367. else
  1368. BlendMemEx(C3, DstP^, RW * BW * MA shr 16);
  1369. finally
  1370. Buffer[0] := nil;
  1371. Buffer[1] := nil;
  1372. end;
  1373. end;
  1374. Dst.Changed(MakeRect(DstX, DstY, DstX + SrcRectW + 1, DstY + SrcRectH + 1));
  1375. end;
  1376. {$WARNINGS ON}
  1377. //------------------------------------------------------------------------------
  1378. //
  1379. // BlendTransfer
  1380. //
  1381. //------------------------------------------------------------------------------
  1382. procedure BlendTransfer(
  1383. Dst: TCustomBitmap32; DstX, DstY: Integer; DstClip: TRect;
  1384. SrcF: TCustomBitmap32; SrcRectF: TRect;
  1385. SrcB: TCustomBitmap32; SrcRectB: TRect;
  1386. BlendCallback: TBlendReg);
  1387. var
  1388. I, J, SrcFX, SrcFY, SrcBX, SrcBY: Integer;
  1389. PSrcF, PSrcB, PDst: PColor32Array;
  1390. begin
  1391. if not Assigned(Dst) then raise EBitmapException.Create(SDstNil);
  1392. if not Assigned(SrcF) then raise EBitmapException.Create(SSrcNil);
  1393. if not Assigned(SrcB) then raise EBitmapException.Create(SSrcNil);
  1394. if Dst.Empty or SrcF.Empty or SrcB.Empty or not Assigned(BlendCallback) then Exit;
  1395. if not Dst.MeasuringMode then
  1396. begin
  1397. SrcFX := SrcRectF.Left - DstX;
  1398. SrcFY := SrcRectF.Top - DstY;
  1399. SrcBX := SrcRectB.Left - DstX;
  1400. SrcBY := SrcRectB.Top - DstY;
  1401. GR32.IntersectRect(DstClip, DstClip, Dst.BoundsRect);
  1402. GR32.IntersectRect(SrcRectF, SrcRectF, SrcF.BoundsRect);
  1403. GR32.IntersectRect(SrcRectB, SrcRectB, SrcB.BoundsRect);
  1404. GR32.OffsetRect(SrcRectF, -SrcFX, -SrcFY);
  1405. GR32.OffsetRect(SrcRectB, -SrcBX, -SrcBY);
  1406. GR32.IntersectRect(DstClip, DstClip, SrcRectF);
  1407. GR32.IntersectRect(DstClip, DstClip, SrcRectB);
  1408. if not GR32.IsRectEmpty(DstClip) then
  1409. for I := DstClip.Top to DstClip.Bottom - 1 do
  1410. begin
  1411. PSrcF := PColor32Array(SrcF.PixelPtr[SrcFX, SrcFY + I]);
  1412. PSrcB := PColor32Array(SrcB.PixelPtr[SrcBX, SrcBY + I]);
  1413. PDst := Dst.ScanLine[I];
  1414. for J := DstClip.Left to DstClip.Right - 1 do
  1415. PDst[J] := BlendCallback(PSrcF[J], PSrcB[J]);
  1416. end;
  1417. end;
  1418. Dst.Changed(DstClip);
  1419. end;
  1420. //------------------------------------------------------------------------------
  1421. procedure BlendTransfer(
  1422. Dst: TCustomBitmap32; DstX, DstY: Integer; DstClip: TRect;
  1423. SrcF: TCustomBitmap32; SrcRectF: TRect;
  1424. SrcB: TCustomBitmap32; SrcRectB: TRect;
  1425. BlendCallback: TBlendRegEx; MasterAlpha: Integer);
  1426. var
  1427. I, J, SrcFX, SrcFY, SrcBX, SrcBY: Integer;
  1428. PSrcF, PSrcB, PDst: PColor32Array;
  1429. begin
  1430. if not Assigned(Dst) then raise EBitmapException.Create(SDstNil);
  1431. if not Assigned(SrcF) then raise EBitmapException.Create(SSrcNil);
  1432. if not Assigned(SrcB) then raise EBitmapException.Create(SSrcNil);
  1433. if Dst.Empty or SrcF.Empty or SrcB.Empty or not Assigned(BlendCallback) then Exit;
  1434. if not Dst.MeasuringMode then
  1435. begin
  1436. SrcFX := SrcRectF.Left - DstX;
  1437. SrcFY := SrcRectF.Top - DstY;
  1438. SrcBX := SrcRectB.Left - DstX;
  1439. SrcBY := SrcRectB.Top - DstY;
  1440. GR32.IntersectRect(DstClip, DstClip, Dst.BoundsRect);
  1441. GR32.IntersectRect(SrcRectF, SrcRectF, SrcF.BoundsRect);
  1442. GR32.IntersectRect(SrcRectB, SrcRectB, SrcB.BoundsRect);
  1443. GR32.OffsetRect(SrcRectF, -SrcFX, -SrcFY);
  1444. GR32.OffsetRect(SrcRectB, -SrcBX, -SrcBY);
  1445. GR32.IntersectRect(DstClip, DstClip, SrcRectF);
  1446. GR32.IntersectRect(DstClip, DstClip, SrcRectB);
  1447. if not GR32.IsRectEmpty(DstClip) then
  1448. for I := DstClip.Top to DstClip.Bottom - 1 do
  1449. begin
  1450. PSrcF := PColor32Array(SrcF.PixelPtr[SrcFX, SrcFY + I]);
  1451. PSrcB := PColor32Array(SrcB.PixelPtr[SrcBX, SrcBY + I]);
  1452. PDst := Dst.ScanLine[I];
  1453. for J := DstClip.Left to DstClip.Right - 1 do
  1454. PDst[J] := BlendCallback(PSrcF[J], PSrcB[J], MasterAlpha);
  1455. end;
  1456. end;
  1457. Dst.Changed(DstClip);
  1458. end;
  1459. //------------------------------------------------------------------------------
  1460. //
  1461. // StretchNearest
  1462. //
  1463. //------------------------------------------------------------------------------
  1464. // Used by TNearestResampler.Resample
  1465. //------------------------------------------------------------------------------
  1466. procedure StretchNearest(
  1467. Dst: TCustomBitmap32; DstRect, DstClip: TRect;
  1468. Src: TCustomBitmap32; SrcRect: TRect;
  1469. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
  1470. var
  1471. R: TRect;
  1472. SrcW, SrcH, DstW, DstH, DstClipW, DstClipH: Integer;
  1473. SrcY, OldSrcY: Integer;
  1474. I, J: Integer;
  1475. MapHorz: PIntegerArray;
  1476. SrcLine, DstLine: PColor32Array;
  1477. Buffer: TArrayOfColor32;
  1478. Scale: TFloat;
  1479. BlendLine: TBlendLine;
  1480. BlendLineEx: TBlendLineEx;
  1481. DstLinePtr, MapPtr: PColor32;
  1482. begin
  1483. GR32.IntersectRect(DstClip, DstClip, MakeRect(0, 0, Dst.Width, Dst.Height));
  1484. GR32.IntersectRect(DstClip, DstClip, DstRect);
  1485. if GR32.IsRectEmpty(DstClip) then Exit;
  1486. GR32.IntersectRect(R, DstClip, DstRect);
  1487. if GR32.IsRectEmpty(R) then Exit;
  1488. if (SrcRect.Left < 0) or (SrcRect.Top < 0) or (SrcRect.Right > Src.Width) or
  1489. (SrcRect.Bottom > Src.Height) then
  1490. raise Exception.Create(RCStrInvalidSrcRect);
  1491. SrcW := SrcRect.Right - SrcRect.Left;
  1492. SrcH := SrcRect.Bottom - SrcRect.Top;
  1493. DstW := DstRect.Right - DstRect.Left;
  1494. DstH := DstRect.Bottom - DstRect.Top;
  1495. DstClipW := DstClip.Right - DstClip.Left;
  1496. DstClipH := DstClip.Bottom - DstClip.Top;
  1497. if (SrcW = DstW) and (SrcH = DstH) then
  1498. begin
  1499. { Copy without resampling }
  1500. BlendBlock(Dst, DstClip, Src, SrcRect.Left + DstClip.Left - DstRect.Left,
  1501. SrcRect.Top + DstClip.Top - DstRect.Top, CombineOp, CombineCallBack);
  1502. end
  1503. else
  1504. begin
  1505. GetMem(MapHorz, DstClipW * SizeOf(Integer));
  1506. try
  1507. if DstW > 1 then
  1508. begin
  1509. if FullEdge then
  1510. begin
  1511. Scale := SrcW / DstW;
  1512. for I := 0 to DstClipW - 1 do
  1513. MapHorz^[I] := Trunc(SrcRect.Left + (I + DstClip.Left - DstRect.Left) * Scale);
  1514. end
  1515. else
  1516. begin
  1517. Scale := (SrcW - 1) / (DstW - 1);
  1518. for I := 0 to DstClipW - 1 do
  1519. MapHorz^[I] := Round(SrcRect.Left + (I + DstClip.Left - DstRect.Left) * Scale);
  1520. end;
  1521. Assert(MapHorz^[0] >= SrcRect.Left);
  1522. Assert(MapHorz^[DstClipW - 1] < SrcRect.Right);
  1523. end
  1524. else
  1525. MapHorz^[0] := (SrcRect.Left + SrcRect.Right - 1) div 2;
  1526. if DstH <= 1 then Scale := 0
  1527. else if FullEdge then Scale := SrcH / DstH
  1528. else Scale := (SrcH - 1) / (DstH - 1);
  1529. if CombineOp = dmOpaque then
  1530. begin
  1531. DstLine := PColor32Array(Dst.PixelPtr[DstClip.Left, DstClip.Top]);
  1532. OldSrcY := -1;
  1533. for J := 0 to DstClipH - 1 do
  1534. begin
  1535. if DstH <= 1 then
  1536. SrcY := (SrcRect.Top + SrcRect.Bottom - 1) div 2
  1537. else if FullEdge then
  1538. SrcY := Trunc(SrcRect.Top + (J + DstClip.Top - DstRect.Top) * Scale)
  1539. else
  1540. SrcY := Round(SrcRect.Top + (J + DstClip.Top - DstRect.Top) * Scale);
  1541. if SrcY <> OldSrcY then
  1542. begin
  1543. SrcLine := Src.ScanLine[SrcY];
  1544. DstLinePtr := @DstLine[0];
  1545. MapPtr := @MapHorz^[0];
  1546. for I := 0 to DstClipW - 1 do
  1547. begin
  1548. DstLinePtr^ := SrcLine[MapPtr^];
  1549. Inc(DstLinePtr);
  1550. Inc(MapPtr);
  1551. end;
  1552. OldSrcY := SrcY;
  1553. end
  1554. else
  1555. MoveLongWord(DstLine[-Dst.Width], DstLine[0], DstClipW);
  1556. Inc(DstLine, Dst.Width);
  1557. end;
  1558. end
  1559. else
  1560. begin
  1561. SetLength(Buffer, DstClipW);
  1562. DstLine := PColor32Array(Dst.PixelPtr[DstClip.Left, DstClip.Top]);
  1563. OldSrcY := -1;
  1564. if Src.MasterAlpha >= 255 then
  1565. begin
  1566. BlendLine := BLEND_LINE[Src.CombineMode]^;
  1567. BlendLineEx := nil; // stop compiler warnings...
  1568. end
  1569. else
  1570. begin
  1571. BlendLineEx := BLEND_LINE_EX[Src.CombineMode]^;
  1572. BlendLine := nil; // stop compiler warnings...
  1573. end;
  1574. for J := 0 to DstClipH - 1 do
  1575. begin
  1576. if DstH > 1 then
  1577. begin
  1578. if FullEdge then
  1579. SrcY := Trunc(SrcRect.Top + (J + DstClip.Top - DstRect.Top) * Scale)
  1580. else
  1581. SrcY := Round(SrcRect.Top + (J + DstClip.Top - DstRect.Top) * Scale);
  1582. end
  1583. else
  1584. SrcY := (SrcRect.Top + SrcRect.Bottom - 1) div 2;
  1585. if SrcY <> OldSrcY then
  1586. begin
  1587. SrcLine := Src.ScanLine[SrcY];
  1588. DstLinePtr := @Buffer[0];
  1589. MapPtr := @MapHorz^[0];
  1590. for I := 0 to DstClipW - 1 do
  1591. begin
  1592. DstLinePtr^ := SrcLine[MapPtr^];
  1593. Inc(DstLinePtr);
  1594. Inc(MapPtr);
  1595. end;
  1596. OldSrcY := SrcY;
  1597. end;
  1598. case CombineOp of
  1599. dmBlend:
  1600. if Src.MasterAlpha >= 255 then
  1601. BlendLine(@Buffer[0], @DstLine[0], DstClipW)
  1602. else
  1603. BlendLineEx(@Buffer[0], @DstLine[0], DstClipW, Src.MasterAlpha);
  1604. dmTransparent:
  1605. for I := 0 to DstClipW - 1 do
  1606. if Buffer[I] <> Src.OuterColor then DstLine[I] := Buffer[I];
  1607. dmCustom:
  1608. for I := 0 to DstClipW - 1 do
  1609. CombineCallBack(Buffer[I], DstLine[I], Src.MasterAlpha);
  1610. end;
  1611. Inc(DstLine, Dst.Width);
  1612. end;
  1613. end;
  1614. finally
  1615. FreeMem(MapHorz);
  1616. end;
  1617. end;
  1618. end;
  1619. //------------------------------------------------------------------------------
  1620. //
  1621. // StretchNearest
  1622. //
  1623. //------------------------------------------------------------------------------
  1624. // Used by TDraftResampler.Resample (via DraftResample) and TLinearResampler.Resample
  1625. //------------------------------------------------------------------------------
  1626. procedure StretchHorzStretchVertLinear(
  1627. Dst: TCustomBitmap32; DstRect, DstClip: TRect;
  1628. Src: TCustomBitmap32; SrcRect: TRect;
  1629. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
  1630. //Assure DstRect is >= SrcRect, otherwise quality loss will occur
  1631. var
  1632. SrcW, SrcH, DstW, DstH, DstClipW, DstClipH: Integer;
  1633. MapHorz, MapVert: array of TPointRec;
  1634. t2, Scale: TFloat;
  1635. SrcLine, DstLine: PColor32Array;
  1636. SrcIndex: Integer;
  1637. SrcPtr1, SrcPtr2: PColor32;
  1638. I, J: Integer;
  1639. WY: Cardinal;
  1640. C: TColor32;
  1641. BlendMemEx: TBlendMemEx;
  1642. begin
  1643. SrcW := SrcRect.Right - SrcRect.Left;
  1644. SrcH := SrcRect.Bottom - SrcRect.Top;
  1645. DstW := DstRect.Right - DstRect.Left;
  1646. DstH := DstRect.Bottom - DstRect.Top;
  1647. DstClipW := DstClip.Right - DstClip.Left;
  1648. DstClipH := DstClip.Bottom - DstClip.Top;
  1649. SetLength(MapHorz, DstClipW);
  1650. if FullEdge then Scale := SrcW / DstW
  1651. else Scale := (SrcW - 1) / (DstW - 1);
  1652. for I := 0 to DstClipW - 1 do
  1653. begin
  1654. if FullEdge then t2 := SrcRect.Left - 0.5 + (I + DstClip.Left - DstRect.Left + 0.5) * Scale
  1655. else t2 := SrcRect.Left + (I + DstClip.Left - DstRect.Left) * Scale;
  1656. if t2 < 0 then t2 := 0
  1657. else if t2 > Src.Width - 1 then t2 := Src.Width - 1;
  1658. MapHorz[I].Pos := Floor(t2);
  1659. MapHorz[I].Weight := 256 - Round(Frac(t2) * 256);
  1660. //Pre-pack weights to reduce MMX Reg. setups per pixel:
  1661. //MapHorz[I].Weight:= MapHorz[I].Weight shl 16 + MapHorz[I].Weight;
  1662. end;
  1663. I := DstClipW - 1;
  1664. while MapHorz[I].Pos = SrcRect.Right - 1 do
  1665. begin
  1666. Dec(MapHorz[I].Pos);
  1667. MapHorz[I].Weight := 0;
  1668. Dec(I);
  1669. end;
  1670. SetLength(MapVert, DstClipH);
  1671. if FullEdge then Scale := SrcH / DstH
  1672. else Scale := (SrcH - 1) / (DstH - 1);
  1673. for I := 0 to DstClipH - 1 do
  1674. begin
  1675. if FullEdge then t2 := SrcRect.Top - 0.5 + (I + DstClip.Top - DstRect.Top + 0.5) * Scale
  1676. else t2 := SrcRect.Top + (I + DstClip.Top - DstRect.Top) * Scale;
  1677. if t2 < 0 then t2 := 0
  1678. else if t2 > Src.Height - 1 then t2 := Src.Height - 1;
  1679. MapVert[I].Pos := Floor(t2);
  1680. MapVert[I].Weight := 256 - Round(Frac(t2) * 256);
  1681. //Pre-pack weights to reduce MMX Reg. setups per pixel:
  1682. //MapVert[I].Weight := MapVert[I].Weight shl 16 + MapVert[I].Weight;
  1683. end;
  1684. I := DstClipH - 1;
  1685. while MapVert[I].Pos = SrcRect.Bottom - 1 do
  1686. begin
  1687. Dec(MapVert[I].Pos);
  1688. MapVert[I].Weight := 0;
  1689. Dec(I);
  1690. end;
  1691. DstLine := PColor32Array(Dst.PixelPtr[DstClip.Left, DstClip.Top]);
  1692. SrcW := Src.Width;
  1693. DstW := Dst.Width;
  1694. case CombineOp of
  1695. dmOpaque:
  1696. for J := 0 to DstClipH - 1 do
  1697. begin
  1698. SrcLine := Src.ScanLine[MapVert[J].Pos];
  1699. WY := MapVert[J].Weight;
  1700. SrcIndex := MapHorz[0].Pos;
  1701. SrcPtr1 := @SrcLine[SrcIndex];
  1702. SrcPtr2 := @SrcLine[SrcIndex + SrcW];
  1703. for I := 0 to DstClipW - 1 do
  1704. begin
  1705. if SrcIndex <> MapHorz[I].Pos then
  1706. begin
  1707. SrcIndex := MapHorz[I].Pos;
  1708. SrcPtr1 := @SrcLine[SrcIndex];
  1709. SrcPtr2 := @SrcLine[SrcIndex + SrcW];
  1710. end;
  1711. DstLine[I] := Interpolator(MapHorz[I].Weight, WY, SrcPtr1, SrcPtr2);
  1712. end;
  1713. Inc(DstLine, DstW);
  1714. end;
  1715. dmBlend:
  1716. begin
  1717. BlendMemEx := BLEND_MEM_EX[Src.CombineMode]^;
  1718. for J := 0 to DstClipH - 1 do
  1719. begin
  1720. SrcLine := Src.ScanLine[MapVert[J].Pos];
  1721. WY := MapVert[J].Weight;
  1722. SrcIndex := MapHorz[0].Pos;
  1723. SrcPtr1 := @SrcLine[SrcIndex];
  1724. SrcPtr2 := @SrcLine[SrcIndex + SrcW];
  1725. for I := 0 to DstClipW - 1 do
  1726. begin
  1727. if SrcIndex <> MapHorz[I].Pos then
  1728. begin
  1729. SrcIndex := MapHorz[I].Pos;
  1730. SrcPtr1 := @SrcLine[SrcIndex];
  1731. SrcPtr2 := @SrcLine[SrcIndex + SrcW];
  1732. end;
  1733. C := Interpolator(MapHorz[I].Weight, WY, SrcPtr1, SrcPtr2);
  1734. BlendMemEx(C, DstLine[I], Src.MasterAlpha)
  1735. end;
  1736. Inc(DstLine, Dst.Width);
  1737. end
  1738. end;
  1739. dmTransparent:
  1740. begin
  1741. for J := 0 to DstClipH - 1 do
  1742. begin
  1743. SrcLine := Src.ScanLine[MapVert[J].Pos];
  1744. WY := MapVert[J].Weight;
  1745. SrcIndex := MapHorz[0].Pos;
  1746. SrcPtr1 := @SrcLine[SrcIndex];
  1747. SrcPtr2 := @SrcLine[SrcIndex + SrcW];
  1748. for I := 0 to DstClipW - 1 do
  1749. begin
  1750. if SrcIndex <> MapHorz[I].Pos then
  1751. begin
  1752. SrcIndex := MapHorz[I].Pos;
  1753. SrcPtr1 := @SrcLine[SrcIndex];
  1754. SrcPtr2 := @SrcLine[SrcIndex + SrcW];
  1755. end;
  1756. C := Interpolator(MapHorz[I].Weight, WY, SrcPtr1, SrcPtr2);
  1757. if C <> Src.OuterColor then DstLine[I] := C;
  1758. end;
  1759. Inc(DstLine, Dst.Width);
  1760. end
  1761. end;
  1762. else // cmCustom
  1763. for J := 0 to DstClipH - 1 do
  1764. begin
  1765. SrcLine := Src.ScanLine[MapVert[J].Pos];
  1766. WY := MapVert[J].Weight;
  1767. SrcIndex := MapHorz[0].Pos;
  1768. SrcPtr1 := @SrcLine[SrcIndex];
  1769. SrcPtr2 := @SrcLine[SrcIndex + SrcW];
  1770. for I := 0 to DstClipW - 1 do
  1771. begin
  1772. if SrcIndex <> MapHorz[I].Pos then
  1773. begin
  1774. SrcIndex := MapHorz[I].Pos;
  1775. SrcPtr1 := @SrcLine[SrcIndex];
  1776. SrcPtr2 := @SrcLine[SrcIndex + SrcW];
  1777. end;
  1778. C := Interpolator(MapHorz[I].Weight, WY, SrcPtr1, SrcPtr2);
  1779. CombineCallBack(C, DstLine[I], Src.MasterAlpha);
  1780. end;
  1781. Inc(DstLine, Dst.Width);
  1782. end;
  1783. end;
  1784. end;
  1785. //------------------------------------------------------------------------------
  1786. //
  1787. // Resample
  1788. //
  1789. //------------------------------------------------------------------------------
  1790. // Primarily used by TKernelResampler.Resample
  1791. //------------------------------------------------------------------------------
  1792. // Precision of TMappingTable[][].Weight.
  1793. // Totals Cb,Cg,Cr,Ca in Resample need to be unscaled by (1 shl MappingTablePrecicionShift2).
  1794. const
  1795. // Weight precision
  1796. {$ifdef PREMULTIPLY}
  1797. MappingTablePrecicionShift = 8; // Fixed precision [24:8]
  1798. {$else PREMULTIPLY}
  1799. MappingTablePrecicionShift = 11; // Fixed precision [21:11]
  1800. {$endif PREMULTIPLY}
  1801. MappingTablePrecicionShift2 = 2 * MappingTablePrecicionShift;
  1802. MappingTablePrecicion = 1 shl MappingTablePrecicionShift;
  1803. MappingTablePrecicion2 = 1 shl MappingTablePrecicionShift2;
  1804. MappingTablePrecicionRound = (1 shl MappingTablePrecicionShift2) div 2 - 1;
  1805. MappingTablePrecicionMax2 = 255 shl MappingTablePrecicionShift2;
  1806. {$ifdef PREMULTIPLY}
  1807. const
  1808. // Premultiplication
  1809. // Max error across all value[0..255]/alpha[1..255] combinations:
  1810. // Shift=1: +/-1
  1811. // Shift=2: +/-3
  1812. // Shift=3: +/-7 in other words: error = +/- 2^(shift-1)
  1813. // Shift=4: +/-15
  1814. // Shift=5: +/-31
  1815. MappingTablePremultPrecicionShift = 2; // [0..7]
  1816. MappingTablePremultPrecicion = 1 shl MappingTablePremultPrecicionShift;
  1817. {$endif PREMULTIPLY}
  1818. //------------------------------------------------------------------------------
  1819. // BuildMappingTable
  1820. //------------------------------------------------------------------------------
  1821. function BuildMappingTable(DstLo, DstHi: Integer; ClipLo, ClipHi: Integer;
  1822. SrcLo, SrcHi: Integer; Kernel: TCustomKernel): TMappingTable;
  1823. var
  1824. SrcWidth, DstWidth, ClipWidth: Integer;
  1825. Filter: TFilterMethod;
  1826. FilterWidth: TFloat;
  1827. Scale, InvScale: TFloat;
  1828. Center: TFloat;
  1829. Count: Integer;
  1830. Left, Right: Integer;
  1831. I, J, K: Integer;
  1832. Weight: Integer;
  1833. x0, x1, x2, x3: TFloat;
  1834. begin
  1835. SrcWidth := SrcHi - SrcLo;
  1836. DstWidth := DstHi - DstLo;
  1837. ClipWidth := ClipHi - ClipLo;
  1838. if SrcWidth = 0 then
  1839. begin
  1840. Result := nil;
  1841. Exit;
  1842. end;
  1843. if SrcWidth = 1 then
  1844. begin
  1845. SetLength(Result, ClipWidth);
  1846. for I := 0 to ClipWidth - 1 do
  1847. begin
  1848. SetLength(Result[I], 1);
  1849. Result[I][0].Pos := SrcLo;
  1850. Result[I][0].Weight := MappingTablePrecicion; // Weight=1
  1851. end;
  1852. Exit;
  1853. end;
  1854. SetLength(Result, ClipWidth);
  1855. if ClipWidth = 0 then
  1856. Exit;
  1857. if FullEdge then
  1858. Scale := DstWidth / SrcWidth
  1859. else
  1860. Scale := (DstWidth - 1) / (SrcWidth - 1);
  1861. Filter := Kernel.Filter;
  1862. FilterWidth := Kernel.GetWidth;
  1863. K := 0;
  1864. if Scale = 0 then
  1865. begin
  1866. Assert(Length(Result) = 1);
  1867. SetLength(Result[0], 1);
  1868. Result[0][0].Pos := (SrcLo + SrcHi) div 2;
  1869. Result[0][0].Weight := MappingTablePrecicion; // Weight=1
  1870. end else
  1871. if Scale < 1 then
  1872. begin
  1873. InvScale := Scale;
  1874. Scale := 1 / Scale;
  1875. FilterWidth := FilterWidth * Scale;
  1876. for I := 0 to ClipWidth - 1 do
  1877. begin
  1878. if FullEdge then
  1879. Center := SrcLo - 0.5 + (I - DstLo + ClipLo + 0.5) * Scale
  1880. else
  1881. Center := SrcLo + (I - DstLo + ClipLo) * Scale;
  1882. Left := Floor(Center - FilterWidth);
  1883. Right := Ceil(Center + FilterWidth);
  1884. Count := -MappingTablePrecicion;
  1885. for J := Left to Right do
  1886. begin
  1887. //
  1888. // Compute the intergral for the convolution with the filter using the midpoint-rule:
  1889. //
  1890. // Assume that f(x) is continuous on [a, b], n is a positive integer and
  1891. //
  1892. // b - a
  1893. // ∆x = -------
  1894. // n
  1895. //
  1896. // If [a,b] is divided into n subintervals, each of length ∆x, and m{i} is the midpoint
  1897. // of the i'th subinterval, set
  1898. //
  1899. // M{n} = ∑ f(m{i}) ∆x
  1900. //
  1901. // then
  1902. //
  1903. // M{n} ≈ ∫ f(x)dx
  1904. //
  1905. // In other words, the integral from x1 to x2 of f(x) dx is approximately:
  1906. //
  1907. // f((x1+x2)/2)*(x2-x1). 
  1908. //
  1909. x0 := J - Center;
  1910. x1 := Max(x0 - 0.5, -FilterWidth);
  1911. x2 := Min(x0 + 0.5, FilterWidth);
  1912. x3 := (x2 + x1) * 0.5; // Center of [x1, x2]
  1913. Weight := Round(MappingTablePrecicion * Filter(x3 * InvScale) * (x2 - x1) * InvScale);
  1914. if Weight <> 0 then
  1915. begin
  1916. Inc(Count, Weight);
  1917. K := Length(Result[I]);
  1918. SetLength(Result[I], K + 1);
  1919. Result[I][K].Pos := Constrain(J, SrcLo, SrcHi - 1);
  1920. Result[I][K].Weight := Weight;
  1921. end;
  1922. end;
  1923. if Length(Result[I]) = 0 then
  1924. begin
  1925. SetLength(Result[I], 1);
  1926. Result[I][0].Pos := Floor(Center);
  1927. Result[I][0].Weight := MappingTablePrecicion;
  1928. end else
  1929. if Count <> 0 then
  1930. Dec(Result[I][K div 2].Weight, Count);
  1931. end;
  1932. end
  1933. else // scale > 1
  1934. begin
  1935. Scale := 1 / Scale;
  1936. for I := 0 to ClipWidth - 1 do
  1937. begin
  1938. if FullEdge then
  1939. Center := SrcLo - 0.5 + (I - DstLo + ClipLo + 0.5) * Scale
  1940. else
  1941. Center := SrcLo + (I - DstLo + ClipLo) * Scale;
  1942. Left := Floor(Center - FilterWidth);
  1943. Right := Ceil(Center + FilterWidth);
  1944. Count := -MappingTablePrecicion;
  1945. for J := Left to Right do
  1946. begin
  1947. x0 := J - Center;
  1948. x1 := Max(x0 - 0.5, -FilterWidth);
  1949. x2 := Min(x0 + 0.5, FilterWidth);
  1950. x3 := (x1 + x2) * 0.5;
  1951. Weight := Round(MappingTablePrecicion * Filter(x3) * (x2 - x1));
  1952. if Weight <> 0 then
  1953. begin
  1954. Inc(Count, Weight);
  1955. K := Length(Result[I]);
  1956. SetLength(Result[I], K + 1);
  1957. Result[I][K].Pos := Constrain(J, SrcLo, SrcHi - 1);
  1958. Result[I][K].Weight := Weight;
  1959. end;
  1960. end;
  1961. if Count <> 0 then
  1962. Dec(Result[I][K div 2].Weight, Count);
  1963. end;
  1964. end;
  1965. end;
  1966. //------------------------------------------------------------------------------
  1967. // Premultiply
  1968. //------------------------------------------------------------------------------
  1969. {$ifdef PREMULTIPLY}
  1970. function Premultiply(Value, Alpha: integer): integer; {$IFDEF USEINLINING} inline; {$ENDIF}
  1971. begin
  1972. // Instead of performing a full traditional premultiplication:
  1973. //
  1974. // RGBp = RGB * Alpha / 255
  1975. //
  1976. // we try to lessen the rounding error, which is normally
  1977. // introduced when this is done in integer precision, by
  1978. // using a smaller divisor. Additionally we use a power of 2
  1979. // divisor so the division can be done with a simple shift:
  1980. //
  1981. // RGBp = RGB * Alpha >> X
  1982. //
  1983. // We need to use "div" for division instead of a direct "shr" as
  1984. // "shr" performs a logical shift and not an arithmetic shift.
  1985. // The compiler will optimize a "div" with a power of 2 constant
  1986. // divisor to an arithmetic shift, so it's a very cheap operation.
  1987. Result := (Value * Alpha) div MappingTablePremultPrecicion;
  1988. end;
  1989. //------------------------------------------------------------------------------
  1990. // Unpremultiply
  1991. //------------------------------------------------------------------------------
  1992. function Unpremultiply(Value, Alpha: integer): integer; {$IFDEF USEINLINING} inline; {$ENDIF}
  1993. begin
  1994. // It would be best if we could do the multiplication before the division
  1995. // but unfortunately that overflows the fixed precision.
  1996. Result := (Value div Alpha) * MappingTablePremultPrecicion;
  1997. end;
  1998. {$endif PREMULTIPLY}
  1999. //------------------------------------------------------------------------------
  2000. // Resample
  2001. //------------------------------------------------------------------------------
  2002. procedure Resample(
  2003. Dst: TCustomBitmap32; DstRect: TRect; DstClip: TRect;
  2004. Src: TCustomBitmap32; SrcRect: TRect;
  2005. Kernel: TCustomKernel;
  2006. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
  2007. var
  2008. DstClipW: Integer;
  2009. MapX, MapY: TMappingTable;
  2010. I, J, X, Y: Integer;
  2011. MapXLoPos, MapXHiPos: Integer;
  2012. HorzBuffer: array of TBufferEntry;
  2013. ClusterX, ClusterY: TCluster;
  2014. Cb, Cg, Cr, Ca: Integer;
  2015. C: TColor32Entry;
  2016. ClusterWeight: Integer;
  2017. DstLine: PColor32Array;
  2018. RangeCheck: Boolean;
  2019. BlendMemEx: TBlendMemEx;
  2020. SourceColor: PColor32Entry;
  2021. BufferEntry: PBufferEntry;
  2022. {$ifdef PREMULTIPLY}
  2023. Alpha: integer;
  2024. DoPremultiply: boolean;
  2025. {$endif PREMULTIPLY}
  2026. begin
  2027. if (CombineOp = dmCustom) and not Assigned(CombineCallBack) then
  2028. CombineOp := dmOpaque;
  2029. { check source and destination }
  2030. if (CombineOp = dmBlend) and (Src.MasterAlpha = 0) then
  2031. Exit;
  2032. BlendMemEx := BLEND_MEM_EX[Src.CombineMode]^; // store in local variable
  2033. DstClipW := DstClip.Right - DstClip.Left;
  2034. // Mapping tables
  2035. MapX := BuildMappingTable(DstRect.Left, DstRect.Right, DstClip.Left, DstClip.Right, SrcRect.Left, SrcRect.Right, Kernel);
  2036. MapY := BuildMappingTable(DstRect.Top, DstRect.Bottom, DstClip.Top, DstClip.Bottom, SrcRect.Top, SrcRect.Bottom, Kernel);
  2037. if (MapX = nil) or (MapY = nil) then
  2038. Exit;
  2039. {$ifdef PREMULTIPLY}
  2040. // Scan bitmap for alpha
  2041. DoPremultiply := False;
  2042. SourceColor := PColor32Entry(Src.Bits);
  2043. I := Src.Height*Src.Width;
  2044. while (I > 0) do
  2045. begin
  2046. if (SourceColor.A <> 255) and (SourceColor.A <> 0) then
  2047. begin
  2048. // We only need to do alpha-premultiplication if Alpha exist in range [1..254]
  2049. DoPremultiply := True;
  2050. break;
  2051. end;
  2052. Inc(SourceColor);
  2053. Dec(I);
  2054. end;
  2055. {$endif PREMULTIPLY}
  2056. ClusterX := nil;
  2057. ClusterY := nil;
  2058. {$ifdef PREMULTIPLY}
  2059. // If we're doing premultiplication then we always need to clamp the unpremultiplied
  2060. // values. Why? Well, premult/unpremult normally goes like this:
  2061. //
  2062. // RGBp = RGB * Alpha / 255
  2063. // RGB = RGBp * 255 / Alpha
  2064. //
  2065. // or in this particular case:
  2066. //
  2067. // RGBp = RGB * Alpha / 255
  2068. // RGB = ∑RGBp * 255 / ∑Alpha
  2069. //
  2070. // Now in case the rounding of the RGB or Alpha values leads to (∑RGBp > RGBp) or
  2071. // (Alpha > ∑Alpha) then we will get RGB values out of bounds (i.e. > 255).
  2072. RangeCheck := DoPremultiply or Kernel.RangeCheck;
  2073. {$else PREMULTIPLY}
  2074. RangeCheck := Kernel.RangeCheck;
  2075. {$endif PREMULTIPLY}
  2076. MapXLoPos := MapX[0][0].Pos;
  2077. MapXHiPos := MapX[DstClipW - 1][High(MapX[DstClipW - 1])].Pos;
  2078. SetLength(HorzBuffer, MapXHiPos - MapXLoPos + 1);
  2079. { transfer pixels }
  2080. for J := DstClip.Top to DstClip.Bottom - 1 do
  2081. begin
  2082. ClusterY := MapY[J - DstClip.Top];
  2083. ClusterWeight := ClusterY[0].Weight;
  2084. SourceColor := @Src.Bits[ClusterY[0].Pos * Src.Width + MapXLoPos];
  2085. BufferEntry := @HorzBuffer[0];
  2086. X := MapXHiPos - MapXLoPos;
  2087. while (X >= 0) do // for X := MapXLoPos to MapXHiPos do
  2088. begin
  2089. {$ifdef PREMULTIPLY}
  2090. // Alpha=0 should not contribute to sample.
  2091. Alpha := SourceColor.A;
  2092. if (Alpha <> 0) then
  2093. begin
  2094. Alpha := Alpha * ClusterWeight;
  2095. if (DoPremultiply) then
  2096. begin
  2097. // Sample premultiplied values
  2098. // RGB is multiplied with Alpha during premultiplication so instead of
  2099. // BufferEntry.RGB := Premultiply(SourceColor.RGB * ClusterWeight, Alpha);
  2100. // we're doing
  2101. // Alpha := Alpha * ClusterWeight;
  2102. // BufferEntry.RGB := Premultiply(SourceColor.RGB, Alpha);
  2103. // and saving 3 multiplications.
  2104. BufferEntry.B := Premultiply(SourceColor.B, Alpha);
  2105. BufferEntry.G := Premultiply(SourceColor.G, Alpha);
  2106. BufferEntry.R := Premultiply(SourceColor.R, Alpha);
  2107. end else
  2108. begin
  2109. BufferEntry.B := SourceColor.B * ClusterWeight;
  2110. BufferEntry.G := SourceColor.G * ClusterWeight;
  2111. BufferEntry.R := SourceColor.R * ClusterWeight;
  2112. end;
  2113. BufferEntry.A := Alpha;
  2114. end else
  2115. BufferEntry^ := Default(TBufferEntry);
  2116. {$else PREMULTIPLY}
  2117. // Alpha=0 should not contribute to sample.
  2118. if (SourceColor.A <> 0) then
  2119. begin
  2120. BufferEntry.B := SourceColor.B * ClusterWeight;
  2121. BufferEntry.G := SourceColor.G * ClusterWeight;
  2122. BufferEntry.R := SourceColor.R * ClusterWeight;
  2123. BufferEntry.A := SourceColor.A * ClusterWeight;
  2124. end else
  2125. BufferEntry^ := Default(TBufferEntry);
  2126. {$endif PREMULTIPLY}
  2127. Inc(SourceColor);
  2128. Inc(BufferEntry);
  2129. Dec(X);
  2130. end;
  2131. Y := Length(ClusterY) - 1;
  2132. while (Y > 0) do // for Y := 1 to Length(ClusterY) - 1 do
  2133. begin
  2134. ClusterWeight := ClusterY[Y].Weight;
  2135. SourceColor := @Src.Bits[ClusterY[Y].Pos * Src.Width + MapXLoPos];
  2136. BufferEntry := @HorzBuffer[0];
  2137. X := MapXHiPos - MapXLoPos;
  2138. while (X >= 0) do // for X := MapXLoPos to MapXHiPos do
  2139. begin
  2140. {$ifdef PREMULTIPLY}
  2141. // Alpha=0 should not contribute to sample.
  2142. Alpha := SourceColor.A;
  2143. if (Alpha <> 0) then
  2144. begin
  2145. Alpha := Alpha * ClusterWeight;
  2146. if (DoPremultiply) then
  2147. begin
  2148. // Sample premultiplied values
  2149. Inc(BufferEntry.B, Premultiply(SourceColor.B, Alpha));
  2150. Inc(BufferEntry.G, Premultiply(SourceColor.G, Alpha));
  2151. Inc(BufferEntry.R, Premultiply(SourceColor.R, Alpha));
  2152. end else
  2153. begin
  2154. Inc(BufferEntry.B, SourceColor.B * ClusterWeight);
  2155. Inc(BufferEntry.G, SourceColor.G * ClusterWeight);
  2156. Inc(BufferEntry.R, SourceColor.R * ClusterWeight);
  2157. end;
  2158. Inc(BufferEntry.A, Alpha);
  2159. end;
  2160. {$else PREMULTIPLY}
  2161. // Alpha=0 should not contribute to sample.
  2162. if (SourceColor.A <> 0) then
  2163. begin
  2164. Inc(BufferEntry.B, SourceColor.B * ClusterWeight);
  2165. Inc(BufferEntry.G, SourceColor.G * ClusterWeight);
  2166. Inc(BufferEntry.R, SourceColor.R * ClusterWeight);
  2167. Inc(BufferEntry.A, SourceColor.A * ClusterWeight);
  2168. end;
  2169. {$endif PREMULTIPLY}
  2170. Inc(SourceColor);
  2171. Inc(BufferEntry);
  2172. Dec(X);
  2173. end;
  2174. Dec(Y);
  2175. end;
  2176. DstLine := Dst.ScanLine[J];
  2177. for I := DstClip.Left to DstClip.Right - 1 do
  2178. begin
  2179. Cb := 0; Cg := Cb; Cr := Cb; Ca := Cb;
  2180. ClusterX := MapX[I - DstClip.Left];
  2181. X := Length(ClusterX) - 1;
  2182. while (X >= 0) do // for X := 0 to Length(ClusterX) - 1 do
  2183. begin
  2184. with HorzBuffer[ClusterX[X].Pos - MapXLoPos] do
  2185. if (A <> 0) then // If Alpha=0 then RGB=0
  2186. begin
  2187. ClusterWeight := ClusterX[X].Weight;
  2188. Inc(Cb, B * ClusterWeight); // Note: Fixed precision multiplication done here
  2189. Inc(Cg, G * ClusterWeight);
  2190. Inc(Cr, R * ClusterWeight);
  2191. Inc(Ca, A * ClusterWeight);
  2192. end;
  2193. Dec(X);
  2194. end;
  2195. // Unpremultiply, unscale and round
  2196. if RangeCheck then
  2197. begin
  2198. {$ifdef PREMULTIPLY}
  2199. Alpha:= (Clamp(Ca, 0, MappingTablePrecicionMax2) + MappingTablePrecicionRound) shr MappingTablePrecicionShift2;
  2200. if (Alpha <> 0) then
  2201. begin
  2202. if (DoPremultiply) then
  2203. begin
  2204. C.B := (Clamp(Unpremultiply(Cb, Alpha), 0, MappingTablePrecicionMax2) + MappingTablePrecicionRound) shr MappingTablePrecicionShift2;
  2205. C.G := (Clamp(Unpremultiply(Cg, Alpha), 0, MappingTablePrecicionMax2) + MappingTablePrecicionRound) shr MappingTablePrecicionShift2;
  2206. C.R := (Clamp(Unpremultiply(Cr, Alpha), 0, MappingTablePrecicionMax2) + MappingTablePrecicionRound) shr MappingTablePrecicionShift2;
  2207. C.A := Alpha;
  2208. end else
  2209. begin
  2210. C.B := (Clamp(Cb, 0, MappingTablePrecicionMax2) + MappingTablePrecicionRound) shr MappingTablePrecicionShift2;
  2211. C.G := (Clamp(Cg, 0, MappingTablePrecicionMax2) + MappingTablePrecicionRound) shr MappingTablePrecicionShift2;
  2212. C.R := (Clamp(Cr, 0, MappingTablePrecicionMax2) + MappingTablePrecicionRound) shr MappingTablePrecicionShift2;
  2213. C.A := 255; // We know Alpha=255 because RangeCheck is True otherwise
  2214. end;
  2215. end else
  2216. C.ARGB := 0;
  2217. {$else PREMULTIPLY}
  2218. if (Ca <> 0) then
  2219. begin
  2220. C.B := (Clamp(Cb, 0, MappingTablePrecicionMax2) + MappingTablePrecicionRound) shr MappingTablePrecicionShift2;
  2221. C.G := (Clamp(Cg, 0, MappingTablePrecicionMax2) + MappingTablePrecicionRound) shr MappingTablePrecicionShift2;
  2222. C.R := (Clamp(Cr, 0, MappingTablePrecicionMax2) + MappingTablePrecicionRound) shr MappingTablePrecicionShift2;
  2223. C.A := (Clamp(Ca, 0, MappingTablePrecicionMax2) + MappingTablePrecicionRound) shr MappingTablePrecicionShift2;
  2224. end else
  2225. C.ARGB := 0;
  2226. {$endif PREMULTIPLY}
  2227. end else
  2228. begin
  2229. {$ifdef PREMULTIPLY}
  2230. Alpha:= (Ca + MappingTablePrecicionRound) shr MappingTablePrecicionShift2;
  2231. if (Alpha <> 0) then
  2232. begin
  2233. C.B := (Cb + MappingTablePrecicionRound) shr MappingTablePrecicionShift2;
  2234. C.G := (Cg + MappingTablePrecicionRound) shr MappingTablePrecicionShift2;
  2235. C.R := (Cr + MappingTablePrecicionRound) shr MappingTablePrecicionShift2;
  2236. C.A := 255; // We know Alpha=255 because RangeCheck is True otherwise
  2237. end else
  2238. C.ARGB := 0;
  2239. {$else PREMULTIPLY}
  2240. if (Ca <> 0) then
  2241. begin
  2242. C.B := (Cb + MappingTablePrecicionRound) shr MappingTablePrecicionShift2;
  2243. C.G := (Cg + MappingTablePrecicionRound) shr MappingTablePrecicionShift2;
  2244. C.R := (Cr + MappingTablePrecicionRound) shr MappingTablePrecicionShift2;
  2245. C.A := (Ca + MappingTablePrecicionRound) shr MappingTablePrecicionShift2;
  2246. end else
  2247. C.ARGB := 0;
  2248. {$endif PREMULTIPLY}
  2249. end;
  2250. // Combine it with the background
  2251. case CombineOp of
  2252. dmOpaque:
  2253. DstLine[I] := C.ARGB;
  2254. dmBlend:
  2255. BlendMemEx(C.ARGB, DstLine[I], Src.MasterAlpha);
  2256. dmTransparent:
  2257. if C.ARGB <> Src.OuterColor then
  2258. DstLine[I] := C.ARGB;
  2259. dmCustom:
  2260. CombineCallBack(C.ARGB, DstLine[I], Src.MasterAlpha);
  2261. end;
  2262. end;
  2263. end;
  2264. end;
  2265. //------------------------------------------------------------------------------
  2266. //
  2267. // DraftResample
  2268. //
  2269. //------------------------------------------------------------------------------
  2270. // Used by TDraftResampler.Resample
  2271. //------------------------------------------------------------------------------
  2272. //------------------------------------------------------------------------------
  2273. // BlockAverage_Pas
  2274. //------------------------------------------------------------------------------
  2275. function BlockAverage_Pas(Dlx, Dly: Cardinal; RowSrc: PColor32; OffSrc: Cardinal): TColor32;
  2276. var
  2277. C: PColor32Entry;
  2278. ix, iy, iA, iR, iG, iB, Area: Cardinal;
  2279. begin
  2280. iR := 0; iB := iR; iG := iR; iA := iR;
  2281. for iy := 1 to Dly do
  2282. begin
  2283. C := PColor32Entry(RowSrc);
  2284. for ix := 1 to Dlx do
  2285. begin
  2286. Inc(iB, C.B);
  2287. Inc(iG, C.G);
  2288. Inc(iR, C.R);
  2289. Inc(iA, C.A);
  2290. Inc(C);
  2291. end;
  2292. Inc(PByte(RowSrc), OffSrc);
  2293. end;
  2294. Area := Dlx * Dly;
  2295. Area := $1000000 div Area;
  2296. Result := iA * Area and $FF000000 or
  2297. iR * Area shr 8 and $FF0000 or
  2298. iG * Area shr 16 and $FF00 or
  2299. iB * Area shr 24 and $FF;
  2300. end;
  2301. //------------------------------------------------------------------------------
  2302. // BlockAverage_SSE2
  2303. //------------------------------------------------------------------------------
  2304. {$if (not defined(PUREPASCAL)) and (not defined(OMIT_SSE2))}
  2305. function BlockAverage_SSE2(Dlx, Dly: Cardinal; RowSrc: PColor32; OffSrc: Cardinal): TColor32;
  2306. asm
  2307. {$IFDEF TARGET_X64}
  2308. MOV EAX,ECX
  2309. MOV R10D,EDX
  2310. SHL EAX,$02
  2311. SUB R9D,EAX
  2312. PXOR XMM1,XMM1
  2313. PXOR XMM2,XMM2
  2314. PXOR XMM7,XMM7
  2315. @@LoopY:
  2316. MOV EAX,ECX
  2317. PXOR XMM0,XMM0
  2318. LEA R8,[R8+RAX*4]
  2319. NEG RAX
  2320. @@LoopX:
  2321. MOVD XMM6,[R8+RAX*4]
  2322. PUNPCKLBW XMM6,XMM7
  2323. PADDW XMM0,XMM6
  2324. INC RAX
  2325. JNZ @@LoopX
  2326. MOVQ XMM6,XMM0
  2327. PUNPCKLWD XMM6,XMM7
  2328. PADDD XMM1,XMM6
  2329. ADD R8,R9
  2330. DEC EDX
  2331. JNZ @@LoopY
  2332. MOV EAX, ECX
  2333. MUL R10D
  2334. MOV ECX,EAX
  2335. MOV EAX,$01000000
  2336. DIV ECX
  2337. MOV ECX,EAX
  2338. MOVD EAX,XMM1
  2339. MUL ECX
  2340. SHR EAX,$18
  2341. MOV R10D,EAX
  2342. SHUFPS XMM1,XMM1,$39
  2343. MOVD EAX,XMM1
  2344. MUL ECX
  2345. SHR EAX,$10
  2346. AND EAX,$0000FF00
  2347. ADD R10D,EAX
  2348. PSHUFD XMM1,XMM1,$39
  2349. MOVD EAX,XMM1
  2350. MUL ECX
  2351. SHR EAX,$08
  2352. AND EAX,$00FF0000
  2353. ADD R10D,EAX
  2354. PSHUFD XMM1,XMM1,$39
  2355. MOVD EAX,XMM1
  2356. MUL ECX
  2357. AND EAX,$FF000000
  2358. ADD EAX,R10D
  2359. {$ELSE}
  2360. PUSH EBX
  2361. PUSH ESI
  2362. PUSH EDI
  2363. MOV EBX,OffSrc
  2364. MOV ESI,EAX
  2365. MOV EDI,EDX
  2366. SHL ESI,$02
  2367. SUB EBX,ESI
  2368. PXOR XMM1,XMM1
  2369. PXOR XMM2,XMM2
  2370. PXOR XMM7,XMM7
  2371. @@LoopY:
  2372. MOV ESI,EAX
  2373. PXOR XMM0,XMM0
  2374. LEA ECX,[ECX+ESI*4]
  2375. NEG ESI
  2376. @@LoopX:
  2377. MOVD XMM6,[ECX+ESI*4]
  2378. PUNPCKLBW XMM6,XMM7
  2379. PADDW XMM0,XMM6
  2380. INC ESI
  2381. JNZ @@LoopX
  2382. MOVQ XMM6,XMM0
  2383. PUNPCKLWD XMM6,XMM7
  2384. PADDD XMM1,XMM6
  2385. ADD ECX,EBX
  2386. DEC EDX
  2387. JNZ @@LoopY
  2388. MUL EDI
  2389. MOV ECX,EAX
  2390. MOV EAX,$01000000
  2391. DIV ECX
  2392. MOV ECX,EAX
  2393. MOVD EAX,XMM1
  2394. MUL ECX
  2395. SHR EAX,$18
  2396. MOV EDI,EAX
  2397. SHUFPS XMM1,XMM1,$39
  2398. MOVD EAX,XMM1
  2399. MUL ECX
  2400. SHR EAX,$10
  2401. AND EAX,$0000FF00
  2402. ADD EDI,EAX
  2403. PSHUFD XMM1,XMM1,$39
  2404. MOVD EAX,XMM1
  2405. MUL ECX
  2406. SHR EAX,$08
  2407. AND EAX,$00FF0000
  2408. ADD EDI,EAX
  2409. PSHUFD XMM1,XMM1,$39
  2410. MOVD EAX,XMM1
  2411. MUL ECX
  2412. AND EAX,$FF000000
  2413. ADD EAX,EDI
  2414. POP EDI
  2415. POP ESI
  2416. POP EBX
  2417. {$ENDIF}
  2418. end;
  2419. {$ifend}
  2420. //------------------------------------------------------------------------------
  2421. // DraftResample
  2422. //------------------------------------------------------------------------------
  2423. procedure DraftResample(Dst: TCustomBitmap32; DstRect: TRect; DstClip: TRect;
  2424. Src: TCustomBitmap32; SrcRect: TRect; Kernel: TCustomKernel;
  2425. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
  2426. var
  2427. SrcW, SrcH,
  2428. DstW, DstH,
  2429. DstClipW, DstClipH: Cardinal;
  2430. RowSrc: PColor32;
  2431. xsrc: PColor32;
  2432. OffSrc,
  2433. dy, dx,
  2434. c1, c2, r1, r2,
  2435. xs: Cardinal;
  2436. C: TColor32;
  2437. DstLine: PColor32Array;
  2438. ScaleFactor: TFloat;
  2439. I,J, sc, sr, cx, cy: Integer;
  2440. BlendMemEx: TBlendMemEx;
  2441. begin
  2442. { rangechecking and rect intersection done by caller }
  2443. SrcW := SrcRect.Right - SrcRect.Left;
  2444. SrcH := SrcRect.Bottom - SrcRect.Top;
  2445. DstW := DstRect.Right - DstRect.Left;
  2446. DstH := DstRect.Bottom - DstRect.Top;
  2447. DstClipW := DstClip.Right - DstClip.Left;
  2448. DstClipH := DstClip.Bottom - DstClip.Top;
  2449. BlendMemEx := BLEND_MEM_EX[Src.CombineMode]^;
  2450. if (DstW > SrcW)or(DstH > SrcH) then
  2451. begin
  2452. if (SrcW < 2) or (SrcH < 2) then
  2453. Resample(Dst, DstRect, DstClip, Src, SrcRect, Kernel, CombineOp, CombineCallBack)
  2454. else
  2455. StretchHorzStretchVertLinear(Dst, DstRect, DstClip, Src, SrcRect, CombineOp, CombineCallBack);
  2456. end else
  2457. begin //Full Scaledown, ignores Fulledge - cannot be integrated into this resampling method
  2458. OffSrc := Src.Width * 4;
  2459. ScaleFactor:= SrcW / DstW;
  2460. cx := Trunc( (DstClip.Left - DstRect.Left) * ScaleFactor);
  2461. r2 := Trunc(ScaleFactor);
  2462. sr := Trunc( $10000 * ScaleFactor );
  2463. ScaleFactor:= SrcH / DstH;
  2464. cy := Trunc( (DstClip.Top - DstRect.Top) * ScaleFactor);
  2465. c2 := Trunc(ScaleFactor);
  2466. sc := Trunc( $10000 * ScaleFactor );
  2467. DstLine := PColor32Array(Dst.PixelPtr[0, DstClip.Top]);
  2468. RowSrc := Src.PixelPtr[SrcRect.Left + cx, SrcRect.Top + cy ];
  2469. xs := r2;
  2470. c1 := 0;
  2471. Dec(DstClip.Left, 2);
  2472. Inc(DstClipW);
  2473. Inc(DstClipH);
  2474. for J := 2 to DstClipH do
  2475. begin
  2476. dy := c2 - c1;
  2477. c1 := c2;
  2478. c2 := FixedMul(J, sc);
  2479. r1 := 0;
  2480. r2 := xs;
  2481. xsrc := RowSrc;
  2482. case CombineOp of
  2483. dmOpaque:
  2484. for I := 2 to DstClipW do
  2485. begin
  2486. dx := r2 - r1; r1 := r2;
  2487. r2 := FixedMul(I, sr);
  2488. DstLine[DstClip.Left + I] := BlockAverage(dx, dy, xsrc, OffSrc);
  2489. Inc(xsrc, dx);
  2490. end;
  2491. dmBlend:
  2492. for I := 2 to DstClipW do
  2493. begin
  2494. dx := r2 - r1; r1 := r2;
  2495. r2 := FixedMul(I, sr);
  2496. BlendMemEx(BlockAverage(dx, dy, xsrc, OffSrc),
  2497. DstLine[DstClip.Left + I], Src.MasterAlpha);
  2498. Inc(xsrc, dx);
  2499. end;
  2500. dmTransparent:
  2501. for I := 2 to DstClipW do
  2502. begin
  2503. dx := r2 - r1; r1 := r2;
  2504. r2 := FixedMul(I, sr);
  2505. C := BlockAverage(dx, dy, xsrc, OffSrc);
  2506. if C <> Src.OuterColor then DstLine[DstClip.Left + I] := C;
  2507. Inc(xsrc, dx);
  2508. end;
  2509. dmCustom:
  2510. for I := 2 to DstClipW do
  2511. begin
  2512. dx := r2 - r1; r1 := r2;
  2513. r2 := FixedMul(I, sr);
  2514. CombineCallBack(BlockAverage(dx, dy, xsrc, OffSrc),
  2515. DstLine[DstClip.Left + I], Src.MasterAlpha);
  2516. Inc(xsrc, dx);
  2517. end;
  2518. end;
  2519. Inc(DstLine, Dst.Width);
  2520. Inc(PByte(RowSrc), OffSrc * dy);
  2521. end;
  2522. end;
  2523. end;
  2524. //------------------------------------------------------------------------------
  2525. //
  2526. // Special interpolators (for sfLinear and sfDraft)
  2527. //
  2528. //------------------------------------------------------------------------------
  2529. //------------------------------------------------------------------------------
  2530. // Interpolator_Pas
  2531. //------------------------------------------------------------------------------
  2532. function Interpolator_Pas(WX_256, WY_256: Cardinal; C11, C21: PColor32): TColor32;
  2533. var
  2534. C1, C3: TColor32;
  2535. begin
  2536. if WX_256 > $FF then WX_256:= $FF;
  2537. if WY_256 > $FF then WY_256:= $FF;
  2538. C1 := C11^; Inc(C11);
  2539. C3 := C21^; Inc(C21);
  2540. Result := CombineReg(CombineReg(C1, C11^, WX_256),
  2541. CombineReg(C3, C21^, WX_256), WY_256);
  2542. end;
  2543. //------------------------------------------------------------------------------
  2544. // Interpolator_SSE2
  2545. //------------------------------------------------------------------------------
  2546. {$if (not defined(PUREPASCAL)) and (not defined(OMIT_SSE2))}
  2547. function Interpolator_SSE2(WX_256, WY_256: Cardinal; C11, C21: PColor32): TColor32;
  2548. asm
  2549. {$IFDEF TARGET_X64}
  2550. MOV RAX, RCX
  2551. MOVQ XMM1,QWORD PTR [R8]
  2552. MOVQ XMM2,XMM1
  2553. MOVQ XMM3,QWORD PTR [R9]
  2554. {$ELSE}
  2555. MOVQ XMM1,[ECX]
  2556. MOVQ XMM2,XMM1
  2557. MOV ECX,C21
  2558. MOVQ XMM3,[ECX]
  2559. {$ENDIF}
  2560. PSRLQ XMM1,32
  2561. MOVQ XMM4,XMM3
  2562. PSRLQ XMM3,32
  2563. MOVD XMM5,EAX
  2564. PSHUFLW XMM5,XMM5,0
  2565. PXOR XMM0,XMM0
  2566. PUNPCKLBW XMM1,XMM0
  2567. PUNPCKLBW XMM2,XMM0
  2568. PSUBW XMM2,XMM1
  2569. PMULLW XMM2,XMM5
  2570. PSLLW XMM1,8
  2571. PADDW XMM2,XMM1
  2572. PSRLW XMM2,8
  2573. PUNPCKLBW XMM3,XMM0
  2574. PUNPCKLBW XMM4,XMM0
  2575. PSUBW XMM4,XMM3
  2576. PSLLW XMM3,8
  2577. PMULLW XMM4,XMM5
  2578. PADDW XMM4,XMM3
  2579. PSRLW XMM4,8
  2580. MOVD XMM5,EDX
  2581. PSHUFLW XMM5,XMM5,0
  2582. PSUBW XMM2,XMM4
  2583. PMULLW XMM2,XMM5
  2584. PSLLW XMM4,8
  2585. PADDW XMM2,XMM4
  2586. PSRLW XMM2,8
  2587. PACKUSWB XMM2,XMM0
  2588. MOVD EAX,XMM2
  2589. end;
  2590. {$ifend}
  2591. //------------------------------------------------------------------------------
  2592. //
  2593. // StretchTransfer
  2594. //
  2595. //------------------------------------------------------------------------------
  2596. {$WARNINGS OFF}
  2597. procedure StretchTransfer(
  2598. Dst: TCustomBitmap32; DstRect: TRect; DstClip: TRect;
  2599. Src: TCustomBitmap32; SrcRect: TRect;
  2600. Resampler: TCustomResampler;
  2601. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
  2602. var
  2603. SrcW, SrcH: Integer;
  2604. DstW, DstH: Integer;
  2605. R: TRect;
  2606. RatioX, RatioY: Single;
  2607. begin
  2608. CheckBitmaps(Dst, Src);
  2609. // transform dest rect when the src rect is out of the src bitmap's bounds
  2610. if (SrcRect.Left < 0) or (SrcRect.Right > Src.Width) or
  2611. (SrcRect.Top < 0) or (SrcRect.Bottom > Src.Height) then
  2612. begin
  2613. RatioX := (DstRect.Right - DstRect.Left) / (SrcRect.Right - SrcRect.Left);
  2614. RatioY := (DstRect.Bottom - DstRect.Top) / (SrcRect.Bottom - SrcRect.Top);
  2615. if SrcRect.Left < 0 then
  2616. begin
  2617. DstRect.Left := DstRect.Left + Ceil(-SrcRect.Left * RatioX);
  2618. SrcRect.Left := 0;
  2619. end;
  2620. if SrcRect.Top < 0 then
  2621. begin
  2622. DstRect.Top := DstRect.Top + Ceil(-SrcRect.Top * RatioY);
  2623. SrcRect.Top := 0;
  2624. end;
  2625. if SrcRect.Right > Src.Width then
  2626. begin
  2627. DstRect.Right := DstRect.Right - Floor((SrcRect.Right - Src.Width) * RatioX);
  2628. SrcRect.Right := Src.Width;
  2629. end;
  2630. if SrcRect.Bottom > Src.Height then
  2631. begin
  2632. DstRect.Bottom := DstRect.Bottom - Floor((SrcRect.Bottom - Src.Height) * RatioY);
  2633. SrcRect.Bottom := Src.Height;
  2634. end;
  2635. end;
  2636. if Src.Empty or Dst.Empty or
  2637. ((CombineOp = dmBlend) and (Src.MasterAlpha = 0)) or
  2638. GR32.IsRectEmpty(SrcRect) then
  2639. Exit;
  2640. if not Dst.MeasuringMode then
  2641. begin
  2642. GR32.IntersectRect(DstClip, DstClip, Dst.BoundsRect);
  2643. GR32.IntersectRect(DstClip, DstClip, DstRect);
  2644. if GR32.IsRectEmpty(DstClip) then Exit;
  2645. GR32.IntersectRect(R, DstClip, DstRect);
  2646. if GR32.IsRectEmpty(R) then Exit;
  2647. if (CombineOp = dmCustom) and not Assigned(CombineCallBack) then
  2648. CombineOp := dmOpaque;
  2649. SrcW := SrcRect.Right - SrcRect.Left;
  2650. SrcH := SrcRect.Bottom - SrcRect.Top;
  2651. DstW := DstRect.Right - DstRect.Left;
  2652. DstH := DstRect.Bottom - DstRect.Top;
  2653. if (SrcW = DstW) and (SrcH = DstH) then
  2654. BlendBlock(Dst, DstClip, Src, SrcRect.Left + DstClip.Left - DstRect.Left, SrcRect.Top + DstClip.Top - DstRect.Top, CombineOp, CombineCallBack)
  2655. else
  2656. TCustomResamplerAccess(Resampler).Resample(Dst, DstRect, DstClip, Src, SrcRect, CombineOp, CombineCallBack);
  2657. end;
  2658. Dst.Changed(DstRect);
  2659. end;
  2660. {$WARNINGS ON}
  2661. //------------------------------------------------------------------------------
  2662. //
  2663. // TByteMap downsample functions
  2664. //
  2665. //------------------------------------------------------------------------------
  2666. procedure DownsampleByteMap2x(Source, Dest: TByteMap);
  2667. var
  2668. X, Y: Integer;
  2669. ScnLn: array [0 .. 2] of PByteArray;
  2670. begin
  2671. for Y := 0 to (Source.Height div 2) - 1 do
  2672. begin
  2673. ScnLn[0] := Dest.ScanLine[Y];
  2674. ScnLn[1] := Source.ScanLine[Y * 2];
  2675. ScnLn[2] := Source.ScanLine[Y * 2 + 1];
  2676. for X := 0 to (Source.Width div 2) - 1 do
  2677. ScnLn[0, X] := (
  2678. ScnLn[1, 2 * X] + ScnLn[1, 2 * X + 1] +
  2679. ScnLn[2, 2 * X] + ScnLn[2, 2 * X + 1]) div 4;
  2680. end;
  2681. end;
  2682. //------------------------------------------------------------------------------
  2683. procedure DownsampleByteMap3x(Source, Dest: TByteMap);
  2684. var
  2685. X, Y: Integer;
  2686. x3: Integer;
  2687. ScnLn: array [0 .. 3] of PByteArray;
  2688. begin
  2689. for Y := 0 to (Source.Height div 3) - 1 do
  2690. begin
  2691. ScnLn[0] := Dest.ScanLine[Y];
  2692. ScnLn[1] := Source.ScanLine[3 * Y];
  2693. ScnLn[2] := Source.ScanLine[3 * Y + 1];
  2694. ScnLn[3] := Source.ScanLine[3 * Y + 2];
  2695. for X := 0 to (Source.Width div 3) - 1 do
  2696. begin
  2697. x3 := 3 * X;
  2698. ScnLn[0, X] := (
  2699. ScnLn[1, x3] + ScnLn[1, x3 + 1] + ScnLn[1, x3 + 2] +
  2700. ScnLn[2, x3] + ScnLn[2, x3 + 1] + ScnLn[2, x3 + 2] +
  2701. ScnLn[3, x3] + ScnLn[3, x3 + 1] + ScnLn[3, x3 + 2]) div 9;
  2702. end;
  2703. end;
  2704. end;
  2705. //------------------------------------------------------------------------------
  2706. procedure DownsampleByteMap4x(Source, Dest: TByteMap);
  2707. var
  2708. X, Y: Integer;
  2709. x4: Integer;
  2710. ScnLn: array [0 .. 4] of PByteArray;
  2711. begin
  2712. for Y := 0 to (Source.Height div 4) - 1 do
  2713. begin
  2714. ScnLn[0] := Dest.ScanLine[Y];
  2715. ScnLn[1] := Source.ScanLine[Y * 4];
  2716. ScnLn[2] := Source.ScanLine[Y * 4 + 1];
  2717. ScnLn[3] := Source.ScanLine[Y * 4 + 2];
  2718. ScnLn[4] := Source.ScanLine[Y * 4 + 3];
  2719. for X := 0 to (Source.Width div 4) - 1 do
  2720. begin
  2721. x4 := 4 * X;
  2722. ScnLn[0, X] := (
  2723. ScnLn[1, x4] + ScnLn[1, x4 + 1] + ScnLn[1, x4 + 2] + ScnLn[1, x4 + 3] +
  2724. ScnLn[2, x4] + ScnLn[2, x4 + 1] + ScnLn[2, x4 + 2] + ScnLn[2, x4 + 3] +
  2725. ScnLn[3, x4] + ScnLn[3, x4 + 1] + ScnLn[3, x4 + 2] + ScnLn[3, x4 + 3] +
  2726. ScnLn[4, x4] + ScnLn[4, x4 + 1] + ScnLn[4, x4 + 2] + ScnLn[4, x4 + 3]) div 16;
  2727. end;
  2728. end;
  2729. end;
  2730. //------------------------------------------------------------------------------
  2731. //
  2732. // TCustomKernel
  2733. //
  2734. //------------------------------------------------------------------------------
  2735. procedure TCustomKernel.AssignTo(Dst: TPersistent);
  2736. begin
  2737. if Dst is TCustomKernel then
  2738. SmartAssign(Self, Dst)
  2739. else
  2740. inherited;
  2741. end;
  2742. procedure TCustomKernel.Changed;
  2743. begin
  2744. if Assigned(FObserver) then FObserver.Changed;
  2745. end;
  2746. constructor TCustomKernel.Create;
  2747. begin
  2748. end;
  2749. function TCustomKernel.RangeCheck: Boolean;
  2750. begin
  2751. Result := False;
  2752. end;
  2753. //------------------------------------------------------------------------------
  2754. //
  2755. // TBoxKernel
  2756. //
  2757. //------------------------------------------------------------------------------
  2758. function TBoxKernel.Filter(Value: TFloat): TFloat;
  2759. begin
  2760. if (Value >= -0.5) and (Value <= 0.5) then
  2761. Result := 1.0
  2762. else
  2763. Result := 0;
  2764. end;
  2765. function TBoxKernel.GetWidth: TFloat;
  2766. begin
  2767. Result := 1;
  2768. end;
  2769. //------------------------------------------------------------------------------
  2770. //
  2771. // TLinearKernel
  2772. //
  2773. //------------------------------------------------------------------------------
  2774. function TLinearKernel.Filter(Value: TFloat): TFloat;
  2775. begin
  2776. if Value < -1 then
  2777. Result := 0
  2778. else
  2779. if Value < 0 then
  2780. Result := 1 + Value
  2781. else
  2782. if Value < 1 then
  2783. Result := 1 - Value
  2784. else
  2785. Result := 0;
  2786. end;
  2787. function TLinearKernel.GetWidth: TFloat;
  2788. begin
  2789. Result := 1;
  2790. end;
  2791. //------------------------------------------------------------------------------
  2792. //
  2793. // TCosineKernel
  2794. //
  2795. //------------------------------------------------------------------------------
  2796. function TCosineKernel.Filter(Value: TFloat): TFloat;
  2797. begin
  2798. Result := 0;
  2799. if Abs(Value) < 1 then
  2800. Result := (Cos(Value * Pi) + 1) * 0.5;
  2801. end;
  2802. function TCosineKernel.GetWidth: TFloat;
  2803. begin
  2804. Result := 1;
  2805. end;
  2806. //------------------------------------------------------------------------------
  2807. //
  2808. // TSplineKernel
  2809. //
  2810. //------------------------------------------------------------------------------
  2811. function TSplineKernel.Filter(Value: TFloat): TFloat;
  2812. var
  2813. tt: TFloat;
  2814. const
  2815. TwoThirds = 2 / 3;
  2816. OneSixth = 1 / 6;
  2817. begin
  2818. Value := Abs(Value);
  2819. if Value < 1 then
  2820. begin
  2821. tt := Sqr(Value);
  2822. Result := 0.5 * tt * Value - tt + TwoThirds;
  2823. end
  2824. else if Value < 2 then
  2825. begin
  2826. Value := 2 - Value;
  2827. Result := OneSixth * Sqr(Value) * Value;
  2828. end
  2829. else Result := 0;
  2830. end;
  2831. function TSplineKernel.RangeCheck: Boolean;
  2832. begin
  2833. Result := True;
  2834. end;
  2835. function TSplineKernel.GetWidth: TFloat;
  2836. begin
  2837. Result := 2;
  2838. end;
  2839. //------------------------------------------------------------------------------
  2840. //
  2841. // TMitchellKernel
  2842. //
  2843. //------------------------------------------------------------------------------
  2844. function TMitchellKernel.Filter(Value: TFloat): TFloat;
  2845. var
  2846. tt, ttt: TFloat;
  2847. const
  2848. OneEighteenth = 1 / 18;
  2849. begin
  2850. Value := Abs(Value);
  2851. tt := Sqr(Value);
  2852. ttt := tt * Value;
  2853. // Given B = C = 1/3
  2854. if Value < 1 then
  2855. // ((((12 - 9 * B - 6 * C) * ttt) + ((-18 + 12 * B + 6 * C) * tt) + (6 - 2 * B))) / 6
  2856. Result := (21 * ttt - 36 * tt + 16 ) * OneEighteenth
  2857. else
  2858. if Value < 2 then
  2859. // ((((-1 * B - 6 * C) * ttt) + ((6 * B + 30 * C) * tt) + ((-12 * B - 48 * C) * Value) + (8 * B + 24 * C))) / 6
  2860. Result := (- 7 * ttt + 36 * tt - 60 * Value + 32) * OneEighteenth
  2861. else
  2862. Result := 0;
  2863. end;
  2864. function TMitchellKernel.RangeCheck: Boolean;
  2865. begin
  2866. Result := True;
  2867. end;
  2868. function TMitchellKernel.GetWidth: TFloat;
  2869. begin
  2870. Result := 2;
  2871. end;
  2872. //------------------------------------------------------------------------------
  2873. //
  2874. // TCubicKernel
  2875. //
  2876. //------------------------------------------------------------------------------
  2877. constructor TCubicKernel.Create;
  2878. begin
  2879. FCoeff := -0.5;
  2880. end;
  2881. function TCubicKernel.Filter(Value: TFloat): TFloat;
  2882. var
  2883. tt, ttt: TFloat;
  2884. begin
  2885. Value := Abs(Value);
  2886. tt := Sqr(Value);
  2887. ttt := tt * Value;
  2888. if Value <= 1 then
  2889. Result := (FCoeff + 2) * ttt - (FCoeff + 3) * tt + 1
  2890. else
  2891. if Value < 2 then
  2892. Result := FCoeff * (ttt - 5 * tt + 8 * Value - 4)
  2893. else
  2894. Result := 0;
  2895. end;
  2896. function TCubicKernel.RangeCheck: Boolean;
  2897. begin
  2898. Result := True;
  2899. end;
  2900. function TCubicKernel.GetWidth: TFloat;
  2901. begin
  2902. Result := 2;
  2903. end;
  2904. procedure TCubicKernel.SetCoeff(const Value: TFloat);
  2905. begin
  2906. if Value <> FCoeff then
  2907. begin
  2908. FCoeff := Value;
  2909. Changed;
  2910. end
  2911. end;
  2912. //------------------------------------------------------------------------------
  2913. //
  2914. // THermiteKernel
  2915. //
  2916. //------------------------------------------------------------------------------
  2917. constructor THermiteKernel.Create;
  2918. begin
  2919. FBias := 0;
  2920. FTension := 0;
  2921. end;
  2922. function THermiteKernel.Filter(Value: TFloat): TFloat;
  2923. var
  2924. Z: Integer;
  2925. t, t2, t3, m0, m1, a0, a1, a2, a3: TFloat;
  2926. begin
  2927. t := (1 - FTension) * 0.5;
  2928. m0 := (1 + FBias) * t;
  2929. m1 := (1 - FBias) * t;
  2930. Z := Floor(Value);
  2931. t := Abs(Z - Value);
  2932. t2 := t * t;
  2933. t3 := t2 * t;
  2934. a1 := t3 - 2 * t2 + t;
  2935. a2 := t3 - t2;
  2936. a3 := -2 * t3 + 3 * t2;
  2937. a0 := -a3 + 1;
  2938. case Z of
  2939. -2: Result := a2 * m1;
  2940. -1: Result := a3 + a1 * m1 + a2 * (m0 - m1);
  2941. 0: Result := a0 + a1 * (m0 - m1) - a2 * m0;
  2942. 1: Result := -a1 * m0;
  2943. else
  2944. Result := 0;
  2945. end;
  2946. end;
  2947. function THermiteKernel.GetWidth: TFloat;
  2948. begin
  2949. Result := 2;
  2950. end;
  2951. function THermiteKernel.RangeCheck: Boolean;
  2952. begin
  2953. Result := True;
  2954. end;
  2955. procedure THermiteKernel.SetBias(const Value: TFloat);
  2956. begin
  2957. if FBias <> Value then
  2958. begin
  2959. FBias := Value;
  2960. Changed;
  2961. end;
  2962. end;
  2963. procedure THermiteKernel.SetTension(const Value: TFloat);
  2964. begin
  2965. if FTension <> Value then
  2966. begin
  2967. FTension := Value;
  2968. Changed;
  2969. end;
  2970. end;
  2971. //------------------------------------------------------------------------------
  2972. //
  2973. // TSinshKernel
  2974. //
  2975. //------------------------------------------------------------------------------
  2976. constructor TSinshKernel.Create;
  2977. begin
  2978. FWidth := 3;
  2979. FCoeff := 0.5;
  2980. end;
  2981. function TSinshKernel.Filter(Value: TFloat): TFloat;
  2982. begin
  2983. if Value = 0 then
  2984. Result := 1
  2985. else
  2986. Result := FCoeff * Sin(Pi * Value) / Sinh(Pi * FCoeff * Value);
  2987. end;
  2988. function TSinshKernel.RangeCheck: Boolean;
  2989. begin
  2990. Result := True;
  2991. end;
  2992. procedure TSinshKernel.SetWidth(Value: TFloat);
  2993. begin
  2994. if FWidth <> Value then
  2995. begin
  2996. FWidth := Value;
  2997. Changed;
  2998. end;
  2999. end;
  3000. function TSinshKernel.GetWidth: TFloat;
  3001. begin
  3002. Result := FWidth;
  3003. end;
  3004. procedure TSinshKernel.SetCoeff(const Value: TFloat);
  3005. begin
  3006. if (FCoeff <> Value) and (FCoeff <> 0) then
  3007. begin
  3008. FCoeff := Value;
  3009. Changed;
  3010. end;
  3011. end;
  3012. //------------------------------------------------------------------------------
  3013. //
  3014. // TWindowedKernel
  3015. //
  3016. //------------------------------------------------------------------------------
  3017. procedure TWindowedKernel.DoSetWidth(Value: TFloat);
  3018. begin
  3019. FWidth := Value;
  3020. FWidthReciprocal := 1 / FWidth;
  3021. end;
  3022. function TWindowedKernel.Filter(Value: TFloat): TFloat;
  3023. begin
  3024. Value := Abs(Value);
  3025. if Value < FWidth then
  3026. Result := Window(Value)
  3027. else
  3028. Result := 0;
  3029. end;
  3030. function TWindowedKernel.RangeCheck: Boolean;
  3031. begin
  3032. Result := True;
  3033. end;
  3034. procedure TWindowedKernel.SetWidth(Value: TFloat);
  3035. begin
  3036. Value := Min(MAX_KERNEL_WIDTH, Value);
  3037. if Value <> FWidth then
  3038. begin
  3039. DoSetWidth(Value);
  3040. Changed;
  3041. end;
  3042. end;
  3043. function TWindowedKernel.GetWidth: TFloat;
  3044. begin
  3045. Result := FWidth;
  3046. end;
  3047. //------------------------------------------------------------------------------
  3048. //
  3049. // TGaussianKernel
  3050. //
  3051. //------------------------------------------------------------------------------
  3052. const
  3053. // Because the gaussian function has inifinite extent we need to limit the
  3054. // width of the window to something reasonable.
  3055. // Often the limit (width) is set to "Full Width at Half Maximum" (FWHM) by
  3056. // calculing the ratio between Radius and Sigma as
  3057. //
  3058. // Ratio = 1 / FWHM
  3059. // = 1 / (2 * Sqrt(2 * Ln(2)))
  3060. // = 0.424660891294479
  3061. //
  3062. // however, for resampling we need the area of the curve covered by the window
  3063. // to be as close to 1 as possible so instead we calculate the ratio so that
  3064. //
  3065. // Ceil(Sigma / Ratio)
  3066. //
  3067. // gives us the smallest size of a kernel containing values >= 1/255:
  3068. //
  3069. // Ratio = 1 / Sqrt(-2 * Ln(1/255))
  3070. // = 0.300386630413846
  3071. //
  3072. GaussianRadiusToSigma = 0.300386630413846;
  3073. GaussianSigmaToRadius = 1 / GaussianRadiusToSigma;
  3074. GaussianMinSigma = 0.4; // Sigma smaller than this causes overflow; Window(0) > 1
  3075. constructor TGaussianKernel.Create;
  3076. begin
  3077. inherited;
  3078. DoSetSigma(1 / Sqrt(2 * Pi));
  3079. end;
  3080. procedure TGaussianKernel.DoSetSigma(const Value: TFloat);
  3081. begin
  3082. FSigma := Value;
  3083. FSigmaReciprocal := -0.5 / Sqr(FSigma);
  3084. FNormalizationFactor := 1 / (FSigma * Sqrt(2 * Pi));
  3085. DoSetWidth(FSigma * GaussianSigmaToRadius);
  3086. end;
  3087. procedure TGaussianKernel.SetSigma(const Value: TFloat);
  3088. begin
  3089. if (FSigma <> Value) and (FSigma <> 0) then
  3090. begin
  3091. DoSetSigma(Value);
  3092. Changed;
  3093. end;
  3094. end;
  3095. function TGaussianKernel.Window(Value: TFloat): TFloat;
  3096. begin
  3097. (*
  3098. ** Gauss(x, σ) = 1/(σ √ 2π) * e^( - x^2 / (2 * σ^2))
  3099. **
  3100. ** FNormalizationFactor = 1/(σ √ 2π)
  3101. **
  3102. ** FSigmaReciprocal = - 1 / (2 * σ^2)
  3103. *)
  3104. Result := FNormalizationFactor * Exp(Sqr(Value) * FSigmaReciprocal);
  3105. end;
  3106. //------------------------------------------------------------------------------
  3107. //
  3108. // TWindowedSincKernel
  3109. //
  3110. //------------------------------------------------------------------------------
  3111. class function TWindowedSincKernel.Sinc(Value: TFloat): TFloat;
  3112. begin
  3113. if Value <> 0 then
  3114. begin
  3115. Value := Value * Pi;
  3116. Result := Sin(Value) / Value;
  3117. end
  3118. else Result := 1;
  3119. end;
  3120. constructor TWindowedSincKernel.Create;
  3121. begin
  3122. inherited;
  3123. FWidth := 3;
  3124. FWidthReciprocal := 1 / FWidth;
  3125. end;
  3126. function TWindowedSincKernel.Filter(Value: TFloat): TFloat;
  3127. begin
  3128. Value := Abs(Value);
  3129. if Value < FWidth then
  3130. Result := Sinc(Value) * Window(Value)
  3131. else
  3132. Result := 0;
  3133. end;
  3134. //------------------------------------------------------------------------------
  3135. //
  3136. // TAlbrechtKernel
  3137. //
  3138. //------------------------------------------------------------------------------
  3139. constructor TAlbrechtKernel.Create;
  3140. begin
  3141. inherited;
  3142. Terms := 7;
  3143. end;
  3144. procedure TAlbrechtKernel.SetTerms(Value: Integer);
  3145. begin
  3146. Value := Constrain(Value, 2, 11);
  3147. if FTerms <> Value then
  3148. begin
  3149. FTerms := Value;
  3150. case Value of
  3151. 2 : Move(CAlbrecht2 [0], FCoefPointer[0], Value * SizeOf(Double));
  3152. 3 : Move(CAlbrecht3 [0], FCoefPointer[0], Value * SizeOf(Double));
  3153. 4 : Move(CAlbrecht4 [0], FCoefPointer[0], Value * SizeOf(Double));
  3154. 5 : Move(CAlbrecht5 [0], FCoefPointer[0], Value * SizeOf(Double));
  3155. 6 : Move(CAlbrecht6 [0], FCoefPointer[0], Value * SizeOf(Double));
  3156. 7 : Move(CAlbrecht7 [0], FCoefPointer[0], Value * SizeOf(Double));
  3157. 8 : Move(CAlbrecht8 [0], FCoefPointer[0], Value * SizeOf(Double));
  3158. 9 : Move(CAlbrecht9 [0], FCoefPointer[0], Value * SizeOf(Double));
  3159. 10 : Move(CAlbrecht10[0], FCoefPointer[0], Value * SizeOf(Double));
  3160. 11 : Move(CAlbrecht11[0], FCoefPointer[0], Value * SizeOf(Double));
  3161. end;
  3162. Changed;
  3163. end;
  3164. end;
  3165. function TAlbrechtKernel.Window(Value: TFloat): TFloat;
  3166. var
  3167. cs : Double;
  3168. i : Integer;
  3169. begin
  3170. cs := Cos(Pi * Value * FWidthReciprocal);
  3171. i := FTerms - 1;
  3172. Result := FCoefPointer[i];
  3173. while i > 0 do
  3174. begin
  3175. Dec(i);
  3176. Result := Result * cs + FCoefPointer[i];
  3177. end;
  3178. end;
  3179. //------------------------------------------------------------------------------
  3180. //
  3181. // TLanczosKernel
  3182. //
  3183. //------------------------------------------------------------------------------
  3184. function TLanczosKernel.Window(Value: TFloat): TFloat;
  3185. begin
  3186. Result := Sinc(Value * FWidthReciprocal); // Get rid of division
  3187. end;
  3188. //------------------------------------------------------------------------------
  3189. //
  3190. // TBlackmanKernel
  3191. //
  3192. //------------------------------------------------------------------------------
  3193. function TBlackmanKernel.Window(Value: TFloat): TFloat;
  3194. begin
  3195. Value := Cos(Pi * Value * FWidthReciprocal); // get rid of division
  3196. Result := 0.34 + 0.5 * Value + 0.16 * sqr(Value);
  3197. end;
  3198. //------------------------------------------------------------------------------
  3199. //
  3200. // THannKernel
  3201. //
  3202. //------------------------------------------------------------------------------
  3203. function THannKernel.Window(Value: TFloat): TFloat;
  3204. begin
  3205. Result := 0.5 + 0.5 * Cos(Pi * Value * FWidthReciprocal); // get rid of division
  3206. end;
  3207. //------------------------------------------------------------------------------
  3208. //
  3209. // THammingKernel
  3210. //
  3211. //------------------------------------------------------------------------------
  3212. function THammingKernel.Window(Value: TFloat): TFloat;
  3213. begin
  3214. Result := 0.54 + 0.46 * Cos(Pi * Value * FWidthReciprocal); // get rid of division
  3215. end;
  3216. //------------------------------------------------------------------------------
  3217. //
  3218. // TKernelResampler
  3219. //
  3220. //------------------------------------------------------------------------------
  3221. constructor TKernelResampler.Create;
  3222. begin
  3223. inherited;
  3224. Kernel := TBoxKernel.Create;
  3225. FTableSize := 32;
  3226. end;
  3227. destructor TKernelResampler.Destroy;
  3228. begin
  3229. FKernel.Free;
  3230. inherited;
  3231. end;
  3232. function TKernelResampler.GetKernelClassName: string;
  3233. begin
  3234. Result := FKernel.ClassName;
  3235. end;
  3236. procedure TKernelResampler.SetKernelClassName(const Value: string);
  3237. var
  3238. KernelClass: TCustomKernelClass;
  3239. NewKernel: TCustomKernel;
  3240. begin
  3241. if (Value <> '') and (FKernel.ClassName <> Value) and (KernelList <> nil) then
  3242. begin
  3243. KernelClass := KernelList.Find(Value);
  3244. if (KernelClass <> nil) then
  3245. begin
  3246. NewKernel := KernelClass.Create;
  3247. try
  3248. SetKernel(NewKernel);
  3249. except
  3250. if (FKernel <> NewKernel) then
  3251. NewKernel.Free;
  3252. raise;
  3253. end;
  3254. end;
  3255. end;
  3256. end;
  3257. procedure TKernelResampler.SetKernel(const Value: TCustomKernel);
  3258. begin
  3259. if (Value <> nil) and (FKernel <> Value) then
  3260. begin
  3261. FreeAndNil(FKernel);
  3262. FKernel := Value;
  3263. TCustomKernelAccess(FKernel).FObserver := Self;
  3264. Changed;
  3265. end;
  3266. end;
  3267. procedure TKernelResampler.Resample(Dst: TCustomBitmap32; DstRect,
  3268. DstClip: TRect; Src: TCustomBitmap32; SrcRect: TRect; CombineOp: TDrawMode;
  3269. CombineCallBack: TPixelCombineEvent);
  3270. begin
  3271. GR32_Resamplers.Resample(Dst, DstRect, DstClip, Src, SrcRect, FKernel, CombineOp, CombineCallBack);
  3272. end;
  3273. {$WARNINGS OFF}
  3274. function TKernelResampler.GetSampleFloat(X, Y: TFloat): TColor32;
  3275. var
  3276. clX, clY: Integer;
  3277. fracX, fracY: Integer;
  3278. fracXS: TFloat absolute fracX;
  3279. fracYS: TFloat absolute fracY;
  3280. Filter: TFilterMethod;
  3281. WrapProcVert: TWrapProcEx absolute Filter;
  3282. WrapProcHorz: TWrapProcEx;
  3283. Colors: PColor32EntryArray;
  3284. KWidth, W, Wv, I, J, Incr, Dev: Integer;
  3285. SrcP: PColor32Entry;
  3286. C: TColor32Entry absolute SrcP;
  3287. LoX, HiX, LoY, HiY, MappingY: Integer;
  3288. HorzKernel, VertKernel: TKernelEntry;
  3289. PHorzKernel, PVertKernel, FloorKernel, CeilKernel: PKernelEntry;
  3290. HorzEntry, VertEntry: TBufferEntry;
  3291. MappingX: TKernelEntry;
  3292. Edge: Boolean;
  3293. Alpha: integer;
  3294. OuterPremultColorR, OuterPremultColorG, OuterPremultColorB: Byte;
  3295. begin
  3296. KWidth := Ceil(FKernel.GetWidth);
  3297. clX := Ceil(X);
  3298. clY := Ceil(Y);
  3299. case PixelAccessMode of
  3300. pamUnsafe, pamWrap:
  3301. begin
  3302. LoX := -KWidth; HiX := KWidth;
  3303. LoY := -KWidth; HiY := KWidth;
  3304. end;
  3305. pamSafe, pamTransparentEdge:
  3306. begin
  3307. with ClipRect do
  3308. begin
  3309. if not ((clX < Left) or (clX > Right) or (clY < Top) or (clY > Bottom)) then
  3310. begin
  3311. Edge := False;
  3312. if clX - KWidth < Left then
  3313. begin
  3314. LoX := Left - clX;
  3315. Edge := True;
  3316. end
  3317. else
  3318. LoX := -KWidth;
  3319. if clX + KWidth >= Right then
  3320. begin
  3321. HiX := Right - clX - 1;
  3322. Edge := True;
  3323. end
  3324. else
  3325. HiX := KWidth;
  3326. if clY - KWidth < Top then
  3327. begin
  3328. LoY := Top - clY;
  3329. Edge := True;
  3330. end
  3331. else
  3332. LoY := -KWidth;
  3333. if clY + KWidth >= Bottom then
  3334. begin
  3335. HiY := Bottom - clY - 1;
  3336. Edge := True;
  3337. end
  3338. else
  3339. HiY := KWidth;
  3340. end
  3341. else
  3342. begin
  3343. if PixelAccessMode = pamTransparentEdge then
  3344. Result := 0
  3345. else
  3346. Result := FOuterColor;
  3347. Exit;
  3348. end;
  3349. end;
  3350. end;
  3351. end;
  3352. case FKernelMode of
  3353. kmDynamic:
  3354. begin
  3355. Filter := FKernel.Filter;
  3356. fracXS := clX - X;
  3357. fracYS := clY - Y;
  3358. PHorzKernel := @HorzKernel;
  3359. PVertKernel := @VertKernel;
  3360. Dev := -256;
  3361. for I := -KWidth to KWidth do
  3362. begin
  3363. W := Round(Filter(I + fracXS) * 256);
  3364. HorzKernel[I] := W;
  3365. Inc(Dev, W);
  3366. end;
  3367. Dec(HorzKernel[0], Dev);
  3368. Dev := -256;
  3369. for I := -KWidth to KWidth do
  3370. begin
  3371. W := Round(Filter(I + fracYS) * 256);
  3372. VertKernel[I] := W;
  3373. Inc(Dev, W);
  3374. end;
  3375. Dec(VertKernel[0], Dev);
  3376. end;
  3377. kmTableNearest:
  3378. begin
  3379. W := FWeightTable.Height - 2;
  3380. PHorzKernel := @FWeightTable.ValPtr[KWidth - MAX_KERNEL_WIDTH, Round((clX - X) * W)]^;
  3381. PVertKernel := @FWeightTable.ValPtr[KWidth - MAX_KERNEL_WIDTH, Round((clY - Y) * W)]^;
  3382. end;
  3383. kmTableLinear:
  3384. begin
  3385. W := (FWeightTable.Height - 2) * $10000;
  3386. J := FWeightTable.Width * 4;
  3387. with TFixedRec(FracX) do
  3388. begin
  3389. Fixed := Round((clX - X) * W);
  3390. PHorzKernel := @HorzKernel;
  3391. FloorKernel := @FWeightTable.ValPtr[KWidth - MAX_KERNEL_WIDTH, Int]^;
  3392. CeilKernel := PKernelEntry(NativeUInt(FloorKernel) + J);
  3393. Dev := -256;
  3394. for I := -KWidth to KWidth do
  3395. begin
  3396. Wv := FloorKernel[I] + ((CeilKernel[I] - FloorKernel[I]) * Frac + $7FFF) div FixedOne;
  3397. HorzKernel[I] := Wv;
  3398. Inc(Dev, Wv);
  3399. end;
  3400. Dec(HorzKernel[0], Dev);
  3401. end;
  3402. with TFixedRec(FracY) do
  3403. begin
  3404. Fixed := Round((clY - Y) * W);
  3405. PVertKernel := @VertKernel;
  3406. FloorKernel := @FWeightTable.ValPtr[KWidth - MAX_KERNEL_WIDTH, Int]^;
  3407. CeilKernel := PKernelEntry(NativeUInt(FloorKernel) + J);
  3408. Dev := -256;
  3409. for I := -KWidth to KWidth do
  3410. begin
  3411. Wv := FloorKernel[I] + ((CeilKernel[I] - FloorKernel[I]) * Frac + $7FFF) div FixedOne;
  3412. VertKernel[I] := Wv;
  3413. Inc(Dev, Wv);
  3414. end;
  3415. Dec(VertKernel[0], Dev);
  3416. end;
  3417. end;
  3418. end;
  3419. VertEntry := Default(TBufferEntry);
  3420. case PixelAccessMode of
  3421. pamUnsafe, pamSafe, pamTransparentEdge:
  3422. begin
  3423. SrcP := PColor32Entry(Bitmap.PixelPtr[LoX + clX, LoY + clY]);
  3424. Incr := Bitmap.Width - (HiX - LoX) - 1;
  3425. for I := LoY to HiY do
  3426. begin
  3427. Wv := PVertKernel[I];
  3428. if Wv <> 0 then
  3429. begin
  3430. HorzEntry := Default(TBufferEntry);
  3431. for J := LoX to HiX do
  3432. begin
  3433. // Alpha=0 should not contribute to sample.
  3434. Alpha := SrcP.A;
  3435. if (Alpha <> 0) then
  3436. begin
  3437. W := PHorzKernel[J];
  3438. Inc(HorzEntry.A, Alpha * W);
  3439. // Sample premultiplied values
  3440. if (Alpha = 255) then
  3441. begin
  3442. Inc(HorzEntry.R, SrcP.R * W);
  3443. Inc(HorzEntry.G, SrcP.G * W);
  3444. Inc(HorzEntry.B, SrcP.B * W);
  3445. end else
  3446. begin
  3447. Inc(HorzEntry.R, Integer(Div255(Alpha * SrcP.R)) * W);
  3448. Inc(HorzEntry.G, Integer(Div255(Alpha * SrcP.G)) * W);
  3449. Inc(HorzEntry.B, Integer(Div255(Alpha * SrcP.B)) * W);
  3450. end;
  3451. end;
  3452. Inc(SrcP);
  3453. end;
  3454. Inc(VertEntry.A, HorzEntry.A * Wv);
  3455. Inc(VertEntry.R, HorzEntry.R * Wv);
  3456. Inc(VertEntry.G, HorzEntry.G * Wv);
  3457. Inc(VertEntry.B, HorzEntry.B * Wv);
  3458. end else Inc(SrcP, HiX - LoX + 1);
  3459. Inc(SrcP, Incr);
  3460. end;
  3461. if (PixelAccessMode = pamSafe) and Edge then
  3462. begin
  3463. Alpha := TColor32Entry(FOuterColor).A;
  3464. // Alpha=0 should not contribute to sample.
  3465. if (Alpha <> 0) then
  3466. begin
  3467. // Sample premultiplied values
  3468. OuterPremultColorR := Integer(Div255(Alpha * TColor32Entry(FOuterColor).R));
  3469. OuterPremultColorG := Integer(Div255(Alpha * TColor32Entry(FOuterColor).G));
  3470. OuterPremultColorB := Integer(Div255(Alpha * TColor32Entry(FOuterColor).B));
  3471. for I := -KWidth to KWidth do
  3472. begin
  3473. Wv := PVertKernel[I];
  3474. if Wv <> 0 then
  3475. begin
  3476. HorzEntry := Default(TBufferEntry);
  3477. for J := -KWidth to KWidth do
  3478. if (J < LoX) or (J > HiX) or (I < LoY) or (I > HiY) then
  3479. begin
  3480. W := PHorzKernel[J];
  3481. Inc(HorzEntry.A, Alpha * W);
  3482. Inc(HorzEntry.R, OuterPremultColorR * W);
  3483. Inc(HorzEntry.G, OuterPremultColorG * W);
  3484. Inc(HorzEntry.B, OuterPremultColorB * W);
  3485. end;
  3486. Inc(VertEntry.A, HorzEntry.A * Wv);
  3487. Inc(VertEntry.R, HorzEntry.R * Wv);
  3488. Inc(VertEntry.G, HorzEntry.G * Wv);
  3489. Inc(VertEntry.B, HorzEntry.B * Wv);
  3490. end;
  3491. end
  3492. end;
  3493. end;
  3494. end;
  3495. pamWrap:
  3496. begin
  3497. WrapProcHorz := GetWrapProcEx(Bitmap.WrapMode, ClipRect.Left, ClipRect.Right - 1);
  3498. WrapProcVert := GetWrapProcEx(Bitmap.WrapMode, ClipRect.Top, ClipRect.Bottom - 1);
  3499. for I := -KWidth to KWidth do
  3500. MappingX[I] := WrapProcHorz(clX + I, ClipRect.Left, ClipRect.Right - 1);
  3501. for I := -KWidth to KWidth do
  3502. begin
  3503. Wv := PVertKernel[I];
  3504. if Wv <> 0 then
  3505. begin
  3506. MappingY := WrapProcVert(clY + I, ClipRect.Top, ClipRect.Bottom - 1);
  3507. Colors := PColor32EntryArray(Bitmap.ScanLine[MappingY]);
  3508. HorzEntry := Default(TBufferEntry);
  3509. for J := -KWidth to KWidth do
  3510. begin
  3511. C := Colors[MappingX[J]];
  3512. Alpha := C.A;
  3513. // Alpha=0 should not contribute to sample.
  3514. if (Alpha <> 0) then
  3515. begin
  3516. W := PHorzKernel[J];
  3517. Inc(HorzEntry.A, Alpha * W);
  3518. // Sample premultiplied values
  3519. if (Alpha = 255) then
  3520. begin
  3521. Inc(HorzEntry.R, C.R * W);
  3522. Inc(HorzEntry.G, C.G * W);
  3523. Inc(HorzEntry.B, C.B * W);
  3524. end else
  3525. begin
  3526. Inc(HorzEntry.R, Div255(Alpha * C.R) * W);
  3527. Inc(HorzEntry.G, Div255(Alpha * C.G) * W);
  3528. Inc(HorzEntry.B, Div255(Alpha * C.B) * W);
  3529. end;
  3530. end;
  3531. end;
  3532. Inc(VertEntry.A, HorzEntry.A * Wv);
  3533. Inc(VertEntry.R, HorzEntry.R * Wv);
  3534. Inc(VertEntry.G, HorzEntry.G * Wv);
  3535. Inc(VertEntry.B, HorzEntry.B * Wv);
  3536. end;
  3537. end;
  3538. end;
  3539. end;
  3540. // Round and unpremultiply result
  3541. with TColor32Entry(Result) do
  3542. begin
  3543. if FKernel.RangeCheck then
  3544. begin
  3545. A := Clamp(TFixedRec(Integer(VertEntry.A + FixedHalf)).Int);
  3546. if (A = 255) then
  3547. begin
  3548. R := Clamp(TFixedRec(Integer(VertEntry.R + FixedHalf)).Int);
  3549. G := Clamp(TFixedRec(Integer(VertEntry.G + FixedHalf)).Int);
  3550. B := Clamp(TFixedRec(Integer(VertEntry.B + FixedHalf)).Int);
  3551. end else
  3552. if (A <> 0) then
  3553. begin
  3554. R := Clamp(TFixedRec(Integer(VertEntry.R + FixedHalf)).Int * 255 div A);
  3555. G := Clamp(TFixedRec(Integer(VertEntry.G + FixedHalf)).Int * 255 div A);
  3556. B := Clamp(TFixedRec(Integer(VertEntry.B + FixedHalf)).Int * 255 div A);
  3557. end else
  3558. begin
  3559. R := 0;
  3560. G := 0;
  3561. B := 0;
  3562. end;
  3563. end
  3564. else
  3565. begin
  3566. A := TFixedRec(Integer(VertEntry.A + FixedHalf)).Int;
  3567. if (A = 255) then
  3568. begin
  3569. R := TFixedRec(Integer(VertEntry.R + FixedHalf)).Int;
  3570. G := TFixedRec(Integer(VertEntry.G + FixedHalf)).Int;
  3571. B := TFixedRec(Integer(VertEntry.B + FixedHalf)).Int;
  3572. end else
  3573. if (A <> 0) then
  3574. begin
  3575. R := TFixedRec(Integer(VertEntry.R + FixedHalf)).Int * 255 div A;
  3576. G := TFixedRec(Integer(VertEntry.G + FixedHalf)).Int * 255 div A;
  3577. B := TFixedRec(Integer(VertEntry.B + FixedHalf)).Int * 255 div A;
  3578. end else
  3579. begin
  3580. R := 0;
  3581. G := 0;
  3582. B := 0;
  3583. end;
  3584. end;
  3585. end;
  3586. end;
  3587. {$WARNINGS ON}
  3588. function TKernelResampler.GetWidth: TFloat;
  3589. begin
  3590. Result := Kernel.GetWidth;
  3591. end;
  3592. procedure TKernelResampler.SetKernelMode(const Value: TKernelMode);
  3593. begin
  3594. if FKernelMode <> Value then
  3595. begin
  3596. FKernelMode := Value;
  3597. Changed;
  3598. end;
  3599. end;
  3600. procedure TKernelResampler.SetTableSize(Value: Integer);
  3601. begin
  3602. if Value < 2 then Value := 2;
  3603. if FTableSize <> Value then
  3604. begin
  3605. FTableSize := Value;
  3606. Changed;
  3607. end;
  3608. end;
  3609. procedure TKernelResampler.FinalizeSampling;
  3610. begin
  3611. if FKernelMode in [kmTableNearest, kmTableLinear] then
  3612. FWeightTable.Free;
  3613. inherited;
  3614. end;
  3615. procedure TKernelResampler.PrepareSampling;
  3616. var
  3617. I, J, W, Weight, Dev: Integer;
  3618. Fraction: TFloat;
  3619. KernelPtr: PKernelEntry;
  3620. begin
  3621. inherited;
  3622. FOuterColor := Bitmap.OuterColor;
  3623. W := Ceil(FKernel.GetWidth);
  3624. if FKernelMode in [kmTableNearest, kmTableLinear] then
  3625. begin
  3626. FWeightTable := TIntegerMap.Create(W * 2 + 1, FTableSize + 1);
  3627. for I := 0 to FTableSize do
  3628. begin
  3629. Fraction := I / (FTableSize - 1);
  3630. KernelPtr := @FWeightTable.ValPtr[W - MAX_KERNEL_WIDTH, I]^;
  3631. Dev := - 256;
  3632. for J := -W to W do
  3633. begin
  3634. Weight := Round(FKernel.Filter(J + Fraction) * 256);
  3635. KernelPtr[J] := Weight;
  3636. Inc(Dev, Weight);
  3637. end;
  3638. Dec(KernelPtr[0], Dev);
  3639. end;
  3640. end;
  3641. end;
  3642. //------------------------------------------------------------------------------
  3643. //
  3644. // TNearestResampler
  3645. //
  3646. //------------------------------------------------------------------------------
  3647. function TNearestResampler.GetSampleInt(X, Y: Integer): TColor32;
  3648. begin
  3649. Result := FGetSampleInt(X, Y);
  3650. end;
  3651. function TNearestResampler.GetSampleFixed(X, Y: TFixed): TColor32;
  3652. begin
  3653. Result := FGetSampleInt(FixedRound(X), FixedRound(Y));
  3654. end;
  3655. function TNearestResampler.GetSampleFloat(X, Y: TFloat): TColor32;
  3656. begin
  3657. Result := FGetSampleInt(Round(X), Round(Y));
  3658. end;
  3659. function TNearestResampler.GetWidth: TFloat;
  3660. begin
  3661. Result := 1;
  3662. end;
  3663. function TNearestResampler.GetPixelTransparentEdge(X,Y: Integer): TColor32;
  3664. var
  3665. I, J: Integer;
  3666. begin
  3667. with Bitmap, Bitmap.ClipRect do
  3668. begin
  3669. I := Clamp(X, Left, Right - 1);
  3670. J := Clamp(Y, Top, Bottom - 1);
  3671. Result := Pixel[I, J];
  3672. if (I <> X) or (J <> Y) then
  3673. Result := Result and $00FFFFFF;
  3674. end;
  3675. end;
  3676. procedure TNearestResampler.PrepareSampling;
  3677. begin
  3678. inherited;
  3679. case PixelAccessMode of
  3680. pamUnsafe: FGetSampleInt := TCustomBitmap32Access(Bitmap).GetPixel;
  3681. pamSafe: FGetSampleInt := TCustomBitmap32Access(Bitmap).GetPixelS;
  3682. pamWrap: FGetSampleInt := TCustomBitmap32Access(Bitmap).GetPixelW;
  3683. pamTransparentEdge: FGetSampleInt := GetPixelTransparentEdge;
  3684. end;
  3685. end;
  3686. procedure TNearestResampler.Resample(
  3687. Dst: TCustomBitmap32; DstRect: TRect; DstClip: TRect;
  3688. Src: TCustomBitmap32; SrcRect: TRect;
  3689. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
  3690. begin
  3691. StretchNearest(Dst, DstRect, DstClip, Src, SrcRect, CombineOp, CombineCallBack)
  3692. end;
  3693. //------------------------------------------------------------------------------
  3694. //
  3695. // TLinearResampler
  3696. //
  3697. //------------------------------------------------------------------------------
  3698. constructor TLinearResampler.Create;
  3699. begin
  3700. inherited;
  3701. FLinearKernel := TLinearKernel.Create;
  3702. end;
  3703. destructor TLinearResampler.Destroy;
  3704. begin
  3705. FLinearKernel.Free;
  3706. inherited Destroy;
  3707. end;
  3708. function TLinearResampler.GetSampleFixed(X, Y: TFixed): TColor32;
  3709. begin
  3710. Result := FGetSampleFixed(X, Y);
  3711. end;
  3712. function TLinearResampler.GetSampleFloat(X, Y: TFloat): TColor32;
  3713. begin
  3714. Result := FGetSampleFixed(Round(X * FixedOne), Round(Y * FixedOne));
  3715. end;
  3716. function TLinearResampler.GetPixelTransparentEdge(X, Y: TFixed): TColor32;
  3717. var
  3718. PixelX, PixelY, X1, X2, Y1, Y2, WeightX, EdgeX, EdgeY: TFixed;
  3719. C1, C2, C3, C4: TColor32;
  3720. PSrc: PColor32Array;
  3721. begin
  3722. EdgeX := Bitmap.ClipRect.Right - 1;
  3723. EdgeY := Bitmap.ClipRect.Bottom - 1;
  3724. PixelX := TFixedRec(X).Int;
  3725. PixelY := TFixedRec(Y).Int;
  3726. if (PixelX >= Bitmap.ClipRect.Left) and (PixelY >= Bitmap.ClipRect.Top) and (PixelX < EdgeX) and (PixelY < EdgeY) then
  3727. begin //Safe
  3728. Result := TCustomBitmap32Access(Bitmap).GET_T256(X shr 8, Y shr 8);
  3729. end
  3730. else
  3731. if (PixelX >= Bitmap.ClipRect.Left - 1) and (PixelY >= Bitmap.ClipRect.Top - 1) and (PixelX <= EdgeX) and (PixelY <= EdgeY) then
  3732. begin //Near edge, on edge or outside
  3733. X1 := Clamp(PixelX, EdgeX);
  3734. X2 := Clamp(PixelX + Sign(X), EdgeX);
  3735. Y1 := Clamp(PixelY, EdgeY) * Bitmap.Width;
  3736. Y2 := Clamp(PixelY + Sign(Y), EdgeY) * Bitmap.Width;
  3737. PSrc := @Bitmap.Bits[0];
  3738. C1 := PSrc[X1 + Y1];
  3739. C2 := PSrc[X2 + Y1];
  3740. C3 := PSrc[X1 + Y2];
  3741. C4 := PSrc[X2 + Y2];
  3742. if X <= Fixed(Bitmap.ClipRect.Left) then
  3743. begin
  3744. C1 := C1 and $00FFFFFF;
  3745. C3 := C3 and $00FFFFFF;
  3746. end else
  3747. if PixelX = EdgeX then
  3748. begin
  3749. C2 := C2 and $00FFFFFF;
  3750. C4 := C4 and $00FFFFFF;
  3751. end;
  3752. if Y <= Fixed(Bitmap.ClipRect.Top) then
  3753. begin
  3754. C1 := C1 and $00FFFFFF;
  3755. C2 := C2 and $00FFFFFF;
  3756. end else
  3757. if PixelY = EdgeY then
  3758. begin
  3759. C3 := C3 and $00FFFFFF;
  3760. C4 := C4 and $00FFFFFF;
  3761. end;
  3762. WeightX := ((X shr 8) and $FF) xor $FF;
  3763. Result := CombineReg(CombineReg(C1, C2, WeightX),
  3764. CombineReg(C3, C4, WeightX),
  3765. ((Y shr 8) and $FF) xor $FF);
  3766. end
  3767. else
  3768. Result := 0; //Nothing really makes sense here, return zero
  3769. end;
  3770. procedure TLinearResampler.PrepareSampling;
  3771. begin
  3772. inherited;
  3773. case PixelAccessMode of
  3774. pamUnsafe: FGetSampleFixed := TCustomBitmap32Access(Bitmap).GetPixelX;
  3775. pamSafe: FGetSampleFixed := TCustomBitmap32Access(Bitmap).GetPixelXS;
  3776. pamWrap: FGetSampleFixed := TCustomBitmap32Access(Bitmap).GetPixelXW;
  3777. pamTransparentEdge: FGetSampleFixed := GetPixelTransparentEdge;
  3778. end;
  3779. end;
  3780. function TLinearResampler.GetWidth: TFloat;
  3781. begin
  3782. Result := 1;
  3783. end;
  3784. procedure TLinearResampler.Resample(
  3785. Dst: TCustomBitmap32; DstRect: TRect; DstClip: TRect;
  3786. Src: TCustomBitmap32; SrcRect: TRect;
  3787. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
  3788. var
  3789. SrcW, SrcH: TFloat;
  3790. DstW, DstH: Integer;
  3791. begin
  3792. SrcW := SrcRect.Right - SrcRect.Left;
  3793. SrcH := SrcRect.Bottom - SrcRect.Top;
  3794. DstW := DstRect.Right - DstRect.Left;
  3795. DstH := DstRect.Bottom - DstRect.Top;
  3796. if (DstW > SrcW) and (DstH > SrcH) and (SrcW > 1) and (SrcH > 1) then
  3797. StretchHorzStretchVertLinear(Dst, DstRect, DstClip, Src, SrcRect, CombineOp,
  3798. CombineCallBack)
  3799. else
  3800. GR32_Resamplers.Resample(Dst, DstRect, DstClip, Src, SrcRect, FLinearKernel,
  3801. CombineOp, CombineCallBack);
  3802. end;
  3803. procedure TDraftResampler.Resample(
  3804. Dst: TCustomBitmap32; DstRect: TRect; DstClip: TRect;
  3805. Src: TCustomBitmap32; SrcRect: TRect;
  3806. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
  3807. begin
  3808. DraftResample(Dst, DstRect, DstClip, Src, SrcRect, FLinearKernel, CombineOp,
  3809. CombineCallBack)
  3810. end;
  3811. //------------------------------------------------------------------------------
  3812. //
  3813. // TTransformer
  3814. //
  3815. //------------------------------------------------------------------------------
  3816. function TTransformer.GetSampleInt(X, Y: Integer): TColor32;
  3817. var
  3818. U, V: TFixed;
  3819. begin
  3820. FTransformFixed(X * FixedOne + FixedHalf, Y * FixedOne + FixedHalf, U, V);
  3821. Result := FGetSampleFixed(U - FixedHalf, V - FixedHalf);
  3822. end;
  3823. function TTransformer.GetSampleFixed(X, Y: TFixed): TColor32;
  3824. var
  3825. U, V: TFixed;
  3826. begin
  3827. FTransformFixed(X + FixedHalf, Y + FixedHalf, U, V);
  3828. Result := FGetSampleFixed(U - FixedHalf, V - FixedHalf);
  3829. end;
  3830. function TTransformer.GetSampleFloat(X, Y: TFloat): TColor32;
  3831. var
  3832. U, V: TFloat;
  3833. begin
  3834. FTransformFloat(X + 0.5, Y + 0.5, U, V);
  3835. Result := FGetSampleFloat(U - 0.5, V - 0.5);
  3836. end;
  3837. constructor TTransformer.Create(ASampler: TCustomSampler; ATransformation: TTransformation; AReverse: boolean);
  3838. begin
  3839. inherited Create(ASampler);
  3840. FTransformation := ATransformation;
  3841. FReverse := AReverse;
  3842. end;
  3843. procedure TTransformer.PrepareSampling;
  3844. begin
  3845. inherited;
  3846. if (FTransformation = nil) then
  3847. raise ETransformerException.Create(STransformationNil);
  3848. if (FReverse) then
  3849. begin
  3850. FTransformInt := TTransformationAccess(FTransformation).ReverseTransformInt;
  3851. FTransformFixed := TTransformationAccess(FTransformation).ReverseTransformFixed;
  3852. FTransformFloat := TTransformationAccess(FTransformation).ReverseTransformFloat;
  3853. end else
  3854. begin
  3855. FTransformInt := TTransformationAccess(FTransformation).TransformInt;
  3856. FTransformFixed := TTransformationAccess(FTransformation).TransformFixed;
  3857. FTransformFloat := TTransformationAccess(FTransformation).TransformFloat;
  3858. end;
  3859. if not TTransformationAccess(FTransformation).TransformValid then
  3860. TTransformationAccess(FTransformation).PrepareTransform;
  3861. end;
  3862. function TTransformer.GetSampleBounds: TFloatRect;
  3863. begin
  3864. GR32.IntersectRect(Result, inherited GetSampleBounds, FTransformation.SrcRect);
  3865. Result := FTransformation.GetTransformedBounds(Result);
  3866. end;
  3867. function TTransformer.HasBounds: Boolean;
  3868. begin
  3869. Result := FTransformation.HasTransformedBounds and inherited HasBounds;
  3870. end;
  3871. //------------------------------------------------------------------------------
  3872. //
  3873. // TSuperSampler
  3874. //
  3875. //------------------------------------------------------------------------------
  3876. constructor TSuperSampler.Create(Sampler: TCustomSampler);
  3877. begin
  3878. inherited Create(Sampler);
  3879. FSamplingX := 4;
  3880. FSamplingY := 4;
  3881. SamplingX := 4;
  3882. SamplingY := 4;
  3883. end;
  3884. function TSuperSampler.GetSampleFixed(X, Y: TFixed): TColor32;
  3885. var
  3886. I, J: Integer;
  3887. dX, dY, tX: TFixed;
  3888. Buffer: TBufferEntry;
  3889. begin
  3890. Buffer := Default(TBufferEntry);
  3891. tX := X + FOffsetX;
  3892. Inc(Y, FOffsetY);
  3893. dX := FDistanceX;
  3894. dY := FDistanceY;
  3895. for J := 1 to FSamplingY do
  3896. begin
  3897. X := tX;
  3898. for I := 1 to FSamplingX do
  3899. begin
  3900. IncBuffer(Buffer, FGetSampleFixed(X, Y));
  3901. Inc(X, dX);
  3902. end;
  3903. Inc(Y, dY);
  3904. end;
  3905. MultiplyBuffer(Buffer, FScale);
  3906. Result := BufferToColor32(Buffer, 16);
  3907. end;
  3908. procedure TSuperSampler.SetSamplingX(const Value: TSamplingRange);
  3909. begin
  3910. FSamplingX := Value;
  3911. FDistanceX := Fixed(1 / Value);
  3912. FOffsetX := Fixed(((1 / Value) - 1) * 0.5); // replaced "/2" by "*0.5"
  3913. FScale := Fixed(1 / (FSamplingX * FSamplingY));
  3914. end;
  3915. procedure TSuperSampler.SetSamplingY(const Value: TSamplingRange);
  3916. begin
  3917. FSamplingY := Value;
  3918. FDistanceY := Fixed(1 / Value);
  3919. FOffsetY := Fixed(((1 / Value) - 1) * 0.5); // replaced "/2" by "*0.5"
  3920. FScale := Fixed(1 / (FSamplingX * FSamplingY));
  3921. end;
  3922. //------------------------------------------------------------------------------
  3923. //
  3924. // TAdaptiveSuperSampler
  3925. //
  3926. //------------------------------------------------------------------------------
  3927. function TAdaptiveSuperSampler.CompareColors(C1, C2: TColor32): Boolean;
  3928. var
  3929. Diff: TColor32Entry;
  3930. begin
  3931. Diff.ARGB := ColorDifference(C1, C2);
  3932. Result := FTolerance < Diff.R + Diff.G + Diff.B;
  3933. end;
  3934. constructor TAdaptiveSuperSampler.Create(Sampler: TCustomSampler);
  3935. begin
  3936. inherited Create(Sampler);
  3937. Level := 4;
  3938. Tolerance := 256;
  3939. end;
  3940. function TAdaptiveSuperSampler.DoRecurse(X, Y, Offset: TFixed; const A, B,
  3941. C, D, E: TColor32): TColor32;
  3942. var
  3943. C1, C2, C3, C4: TColor32;
  3944. begin
  3945. C1 := QuadrantColor(A, E, X - Offset, Y - Offset, Offset, RecurseAC);
  3946. C2 := QuadrantColor(B, E, X + Offset, Y - Offset, Offset, RecurseBD);
  3947. C3 := QuadrantColor(E, C, X + Offset, Y + Offset, Offset, RecurseAC);
  3948. C4 := QuadrantColor(E, D, X - Offset, Y + Offset, Offset, RecurseBD);
  3949. Result := ColorAverage(ColorAverage(C1, C2), ColorAverage(C3, C4));
  3950. end;
  3951. function TAdaptiveSuperSampler.GetSampleFixed(X, Y: TFixed): TColor32;
  3952. var
  3953. A, B, C, D, E: TColor32;
  3954. const
  3955. FIXED_HALF = 32768;
  3956. begin
  3957. A := FGetSampleFixed(X - FIXED_HALF, Y - FIXED_HALF);
  3958. B := FGetSampleFixed(X + FIXED_HALF, Y - FIXED_HALF);
  3959. C := FGetSampleFixed(X + FIXED_HALF, Y + FIXED_HALF);
  3960. D := FGetSampleFixed(X - FIXED_HALF, Y + FIXED_HALF);
  3961. E := FGetSampleFixed(X, Y);
  3962. Result := Self.DoRecurse(X, Y, 16384, A, B, C, D, E);
  3963. end;
  3964. function TAdaptiveSuperSampler.QuadrantColor(const C1, C2: TColor32; X, Y,
  3965. Offset: TFixed; Proc: TRecurseProc): TColor32;
  3966. begin
  3967. if CompareColors(C1, C2) and (Offset >= FMinOffset) then
  3968. Result := Proc(X, Y, Offset, C1, C2)
  3969. else
  3970. Result := ColorAverage(C1, C2);
  3971. end;
  3972. function TAdaptiveSuperSampler.RecurseAC(X, Y, Offset: TFixed; const A,
  3973. C: TColor32): TColor32;
  3974. var
  3975. B, D, E: TColor32;
  3976. begin
  3977. B := FGetSampleFixed(X + Offset, Y - Offset);
  3978. D := FGetSampleFixed(X - Offset, Y + Offset);
  3979. E := FGetSampleFixed(X, Y);
  3980. Result := DoRecurse(X, Y, Offset shr 1, A, B, C, D, E);
  3981. end;
  3982. function TAdaptiveSuperSampler.RecurseBD(X, Y, Offset: TFixed; const B,
  3983. D: TColor32): TColor32;
  3984. var
  3985. A, C, E: TColor32;
  3986. begin
  3987. A := FGetSampleFixed(X - Offset, Y - Offset);
  3988. C := FGetSampleFixed(X + Offset, Y + Offset);
  3989. E := FGetSampleFixed(X, Y);
  3990. Result := DoRecurse(X, Y, Offset shr 1, A, B, C, D, E);
  3991. end;
  3992. procedure TAdaptiveSuperSampler.SetLevel(const Value: Integer);
  3993. begin
  3994. FLevel := Value;
  3995. FMinOffset := Fixed(1 / (1 shl Value));
  3996. end;
  3997. //------------------------------------------------------------------------------
  3998. //
  3999. // TPatternSampler
  4000. //
  4001. //------------------------------------------------------------------------------
  4002. destructor TPatternSampler.Destroy;
  4003. begin
  4004. FPattern := nil;
  4005. inherited;
  4006. end;
  4007. function TPatternSampler.GetSampleFixed(X, Y: TFixed): TColor32;
  4008. var
  4009. Points: TArrayOfFixedPoint;
  4010. P: PFixedPoint;
  4011. I, PY: Integer;
  4012. Buffer: TBufferEntry;
  4013. GetSample: TGetSampleFixed;
  4014. WrapProcHorz: TWrapProc;
  4015. begin
  4016. GetSample := FSampler.GetSampleFixed;
  4017. PY := WrapProcVert(TFixedRec(Y).Int, High(FPattern));
  4018. I := High(FPattern[PY]);
  4019. WrapProcHorz := GetOptimalWrap(I);
  4020. Points := FPattern[PY][WrapProcHorz(TFixedRec(X).Int, I)];
  4021. Buffer := Default(TBufferEntry);
  4022. P := @Points[0];
  4023. for I := 0 to High(Points) do
  4024. begin
  4025. IncBuffer(Buffer, GetSample(P.X + X, P.Y + Y));
  4026. Inc(P);
  4027. end;
  4028. MultiplyBuffer(Buffer, FixedOne div Length(Points));
  4029. Result := BufferToColor32(Buffer, 16);
  4030. end;
  4031. procedure TPatternSampler.SetPattern(const Value: TFixedSamplePattern);
  4032. begin
  4033. if (Value <> nil) then
  4034. begin
  4035. FPattern := Value;
  4036. WrapProcVert := GetOptimalWrap(High(FPattern));
  4037. end;
  4038. end;
  4039. //------------------------------------------------------------------------------
  4040. //
  4041. // CreateJitteredPattern
  4042. //
  4043. //------------------------------------------------------------------------------
  4044. function JitteredPattern(XRes, YRes: Integer): TArrayOfFixedPoint;
  4045. var
  4046. I, J: Integer;
  4047. begin
  4048. SetLength(Result, XRes * YRes);
  4049. for I := 0 to XRes - 1 do
  4050. for J := 0 to YRes - 1 do
  4051. with Result[I + J * XRes] do
  4052. begin
  4053. X := (Random(65536) + I * 65536) div XRes - 32768;
  4054. Y := (Random(65536) + J * 65536) div YRes - 32768;
  4055. end;
  4056. end;
  4057. function CreateJitteredPattern(TileWidth, TileHeight, SamplesX, SamplesY: Integer): TFixedSamplePattern;
  4058. var
  4059. I, J: Integer;
  4060. begin
  4061. SetLength(Result, TileHeight, TileWidth);
  4062. for I := 0 to TileWidth - 1 do
  4063. for J := 0 to TileHeight - 1 do
  4064. Result[J][I] := JitteredPattern(SamplesX, SamplesY);
  4065. end;
  4066. //------------------------------------------------------------------------------
  4067. //
  4068. // TNestedSampler
  4069. //
  4070. //------------------------------------------------------------------------------
  4071. procedure TNestedSampler.AssignTo(Dst: TPersistent);
  4072. begin
  4073. if Dst is TNestedSampler then
  4074. SmartAssign(Self, Dst)
  4075. else
  4076. inherited;
  4077. end;
  4078. constructor TNestedSampler.Create(ASampler: TCustomSampler);
  4079. begin
  4080. inherited Create;
  4081. Sampler := ASampler;
  4082. end;
  4083. procedure TNestedSampler.FinalizeSampling;
  4084. begin
  4085. if (FSampler = nil) then
  4086. raise ENestedException.Create(SSamplerNil);
  4087. FSampler.FinalizeSampling;
  4088. end;
  4089. {$WARNINGS OFF}
  4090. function TNestedSampler.GetSampleBounds: TFloatRect;
  4091. begin
  4092. if (FSampler = nil) then
  4093. raise ENestedException.Create(SSamplerNil);
  4094. Result := FSampler.GetSampleBounds;
  4095. end;
  4096. function TNestedSampler.HasBounds: Boolean;
  4097. begin
  4098. if (FSampler = nil) then
  4099. raise ENestedException.Create(SSamplerNil);
  4100. Result := FSampler.HasBounds;
  4101. end;
  4102. {$WARNINGS ON}
  4103. procedure TNestedSampler.PrepareSampling;
  4104. begin
  4105. if (FSampler = nil) then
  4106. raise ENestedException.Create(SSamplerNil);
  4107. FSampler.PrepareSampling;
  4108. end;
  4109. procedure TNestedSampler.SetSampler(const Value: TCustomSampler);
  4110. begin
  4111. FSampler := Value;
  4112. if (Value <> nil) then
  4113. begin
  4114. FGetSampleInt := FSampler.GetSampleInt;
  4115. FGetSampleFixed := FSampler.GetSampleFixed;
  4116. FGetSampleFloat := FSampler.GetSampleFloat;
  4117. end;
  4118. end;
  4119. //------------------------------------------------------------------------------
  4120. //
  4121. // TKernelSampler
  4122. //
  4123. //------------------------------------------------------------------------------
  4124. function TKernelSampler.ConvertBuffer(var Buffer: TBufferEntry): TColor32;
  4125. begin
  4126. Buffer.A := Constrain(Buffer.A, 0, $FFFF);
  4127. Buffer.R := Constrain(Buffer.R, 0, $FFFF);
  4128. Buffer.G := Constrain(Buffer.G, 0, $FFFF);
  4129. Buffer.B := Constrain(Buffer.B, 0, $FFFF);
  4130. Result := BufferToColor32(Buffer, 8);
  4131. end;
  4132. constructor TKernelSampler.Create(ASampler: TCustomSampler);
  4133. begin
  4134. inherited;
  4135. FKernel := TIntegerMap.Create;
  4136. FStartEntry := Default(TBufferEntry);
  4137. end;
  4138. destructor TKernelSampler.Destroy;
  4139. begin
  4140. FKernel.Free;
  4141. inherited;
  4142. end;
  4143. function TKernelSampler.GetSampleFixed(X, Y: TFixed): TColor32;
  4144. var
  4145. I, J: Integer;
  4146. Buffer: TBufferEntry;
  4147. begin
  4148. X := X + FCenterX shl 16;
  4149. Y := Y + FCenterY shl 16;
  4150. Buffer := FStartEntry;
  4151. for I := 0 to FKernel.Width - 1 do
  4152. for J := 0 to FKernel.Height - 1 do
  4153. UpdateBuffer(Buffer, FGetSampleFixed(X - I shl 16, Y - J shl 16), FKernel[I, J]);
  4154. Result := ConvertBuffer(Buffer);
  4155. end;
  4156. function TKernelSampler.GetSampleInt(X, Y: Integer): TColor32;
  4157. var
  4158. I, J: Integer;
  4159. Buffer: TBufferEntry;
  4160. begin
  4161. X := X + FCenterX;
  4162. Y := Y + FCenterY;
  4163. Buffer := FStartEntry;
  4164. for I := 0 to FKernel.Width - 1 do
  4165. for J := 0 to FKernel.Height - 1 do
  4166. UpdateBuffer(Buffer, FGetSampleInt(X - I, Y - J), FKernel[I, J]);
  4167. Result := ConvertBuffer(Buffer);
  4168. end;
  4169. procedure TKernelSampler.SetKernel(const Value: TIntegerMap);
  4170. begin
  4171. FKernel.Assign(Value);
  4172. end;
  4173. //------------------------------------------------------------------------------
  4174. //
  4175. // TConvolver
  4176. //
  4177. //------------------------------------------------------------------------------
  4178. procedure TConvolver.UpdateBuffer(var Buffer: TBufferEntry; Color: TColor32;
  4179. Weight: Integer);
  4180. begin
  4181. with TColor32Entry(Color) do
  4182. begin
  4183. Inc(Buffer.A, A * Weight);
  4184. Inc(Buffer.R, R * Weight);
  4185. Inc(Buffer.G, G * Weight);
  4186. Inc(Buffer.B, B * Weight);
  4187. end;
  4188. end;
  4189. //------------------------------------------------------------------------------
  4190. //
  4191. // TDilater
  4192. //
  4193. //------------------------------------------------------------------------------
  4194. procedure TDilater.UpdateBuffer(var Buffer: TBufferEntry; Color: TColor32;
  4195. Weight: Integer);
  4196. begin
  4197. with TColor32Entry(Color) do
  4198. begin
  4199. Buffer.A := Max(Buffer.A, A + Weight);
  4200. Buffer.R := Max(Buffer.R, R + Weight);
  4201. Buffer.G := Max(Buffer.G, G + Weight);
  4202. Buffer.B := Max(Buffer.B, B + Weight);
  4203. end;
  4204. end;
  4205. //------------------------------------------------------------------------------
  4206. //
  4207. // TEroder
  4208. //
  4209. //------------------------------------------------------------------------------
  4210. constructor TEroder.Create(ASampler: TCustomSampler);
  4211. const
  4212. START_ENTRY: TBufferEntry = (B: $FFFF; G: $FFFF; R: $FFFF; A: $FFFF);
  4213. begin
  4214. inherited;
  4215. FStartEntry := START_ENTRY;
  4216. end;
  4217. procedure TEroder.UpdateBuffer(var Buffer: TBufferEntry; Color: TColor32;
  4218. Weight: Integer);
  4219. begin
  4220. with TColor32Entry(Color) do
  4221. begin
  4222. Buffer.A := Min(Buffer.A, A - Weight);
  4223. Buffer.R := Min(Buffer.R, R - Weight);
  4224. Buffer.G := Min(Buffer.G, G - Weight);
  4225. Buffer.B := Min(Buffer.B, B - Weight);
  4226. end;
  4227. end;
  4228. //------------------------------------------------------------------------------
  4229. //
  4230. // TExpander
  4231. //
  4232. //------------------------------------------------------------------------------
  4233. procedure TExpander.UpdateBuffer(var Buffer: TBufferEntry; Color: TColor32;
  4234. Weight: Integer);
  4235. begin
  4236. with TColor32Entry(Color) do
  4237. begin
  4238. Buffer.A := Max(Buffer.A, A * Weight);
  4239. Buffer.R := Max(Buffer.R, R * Weight);
  4240. Buffer.G := Max(Buffer.G, G * Weight);
  4241. Buffer.B := Max(Buffer.B, B * Weight);
  4242. end;
  4243. end;
  4244. //------------------------------------------------------------------------------
  4245. //
  4246. // TContracter
  4247. //
  4248. //------------------------------------------------------------------------------
  4249. function TContracter.GetSampleFixed(X, Y: TFixed): TColor32;
  4250. begin
  4251. Result := ColorSub(FMaxWeight, inherited GetSampleFixed(X, Y));
  4252. end;
  4253. function TContracter.GetSampleInt(X, Y: Integer): TColor32;
  4254. begin
  4255. Result := ColorSub(FMaxWeight, inherited GetSampleInt(X, Y));
  4256. end;
  4257. procedure TContracter.PrepareSampling;
  4258. var
  4259. I, J, W: Integer;
  4260. begin
  4261. W := Low(Integer);
  4262. for I := 0 to FKernel.Width - 1 do
  4263. for J := 0 to FKernel.Height - 1 do
  4264. W := Max(W, FKernel[I, J]);
  4265. if W > 255 then
  4266. W := 255;
  4267. FMaxWeight := Gray32(W, W);
  4268. end;
  4269. procedure TContracter.UpdateBuffer(var Buffer: TBufferEntry; Color: TColor32;
  4270. Weight: Integer);
  4271. begin
  4272. inherited UpdateBuffer(Buffer, Color xor $FFFFFFFF, Weight);
  4273. end;
  4274. //------------------------------------------------------------------------------
  4275. //
  4276. // TMorphologicalSampler
  4277. //
  4278. //------------------------------------------------------------------------------
  4279. function TMorphologicalSampler.ConvertBuffer(
  4280. var Buffer: TBufferEntry): TColor32;
  4281. begin
  4282. Buffer.A := Constrain(Buffer.A, 0, $FF);
  4283. Buffer.R := Constrain(Buffer.R, 0, $FF);
  4284. Buffer.G := Constrain(Buffer.G, 0, $FF);
  4285. Buffer.B := Constrain(Buffer.B, 0, $FF);
  4286. with TColor32Entry(Result) do
  4287. begin
  4288. A := Buffer.A;
  4289. R := Buffer.R;
  4290. G := Buffer.G;
  4291. B := Buffer.B;
  4292. end;
  4293. end;
  4294. //------------------------------------------------------------------------------
  4295. //
  4296. // TSelectiveConvolver
  4297. //
  4298. //------------------------------------------------------------------------------
  4299. function TSelectiveConvolver.ConvertBuffer(var Buffer: TBufferEntry): TColor32;
  4300. begin
  4301. with TColor32Entry(Result) do
  4302. begin
  4303. A := Buffer.A div FWeightSum.A;
  4304. R := Buffer.R div FWeightSum.R;
  4305. G := Buffer.G div FWeightSum.G;
  4306. B := Buffer.B div FWeightSum.B;
  4307. end;
  4308. end;
  4309. constructor TSelectiveConvolver.Create(ASampler: TCustomSampler);
  4310. begin
  4311. inherited;
  4312. FDelta := 30;
  4313. end;
  4314. function TSelectiveConvolver.GetSampleFixed(X, Y: TFixed): TColor32;
  4315. begin
  4316. FRefColor := FGetSampleFixed(X, Y);
  4317. FWeightSum := Default(TBufferEntry);
  4318. Result := inherited GetSampleFixed(X, Y);
  4319. end;
  4320. function TSelectiveConvolver.GetSampleInt(X, Y: Integer): TColor32;
  4321. begin
  4322. FRefColor := FGetSampleInt(X, Y);
  4323. FWeightSum := Default(TBufferEntry);
  4324. Result := inherited GetSampleInt(X, Y);
  4325. end;
  4326. procedure TSelectiveConvolver.UpdateBuffer(var Buffer: TBufferEntry;
  4327. Color: TColor32; Weight: Integer);
  4328. begin
  4329. with TColor32Entry(Color) do
  4330. begin
  4331. if Abs(TColor32Entry(FRefColor).A - A) <= FDelta then
  4332. begin
  4333. Inc(Buffer.A, A * Weight);
  4334. Inc(FWeightSum.A, Weight);
  4335. end;
  4336. if Abs(TColor32Entry(FRefColor).R - R) <= FDelta then
  4337. begin
  4338. Inc(Buffer.R, R * Weight);
  4339. Inc(FWeightSum.R, Weight);
  4340. end;
  4341. if Abs(TColor32Entry(FRefColor).G - G) <= FDelta then
  4342. begin
  4343. Inc(Buffer.G, G * Weight);
  4344. Inc(FWeightSum.G, Weight);
  4345. end;
  4346. if Abs(TColor32Entry(FRefColor).B - B) <= FDelta then
  4347. begin
  4348. Inc(Buffer.B, B * Weight);
  4349. Inc(FWeightSum.B, Weight);
  4350. end;
  4351. end;
  4352. end;
  4353. //------------------------------------------------------------------------------
  4354. //
  4355. // Registration routines
  4356. //
  4357. //------------------------------------------------------------------------------
  4358. procedure RegisterResampler(ResamplerClass: TCustomResamplerClass);
  4359. begin
  4360. if (ResamplerList = nil) then
  4361. ResamplerList := TCustomClassList<TCustomResamplerClass>.Create;
  4362. ResamplerList.Add(ResamplerClass);
  4363. end;
  4364. procedure RegisterKernel(KernelClass: TCustomKernelClass);
  4365. begin
  4366. if (KernelList = nil) then
  4367. KernelList := TCustomClassList<TCustomKernelClass>.Create;
  4368. KernelList.Add(KernelClass);
  4369. end;
  4370. //------------------------------------------------------------------------------
  4371. //
  4372. // Bindings
  4373. //
  4374. //------------------------------------------------------------------------------
  4375. var
  4376. ResamplersRegistry: TFunctionRegistry;
  4377. procedure RegisterBindings;
  4378. begin
  4379. ResamplersRegistry := NewRegistry('GR32_Resamplers bindings');
  4380. ResamplersRegistry.RegisterBinding(@@BlockAverage, 'BlockAverage');
  4381. ResamplersRegistry.RegisterBinding(@@Interpolator, 'Interpolator');
  4382. ResamplersRegistry[@@BlockAverage].ADD(@BlockAverage_Pas, [isPascal]).Name := 'BlockAverage_Pas';
  4383. ResamplersRegistry[@@Interpolator].ADD(@Interpolator_Pas, [isPascal]).Name := 'Interpolator_Pas';
  4384. {$if (not defined(PUREPASCAL)) and (not defined(OMIT_SSE2))}
  4385. ResamplersRegistry[@@BlockAverage].ADD(@BlockAverage_SSE2, [isSSE2]).Name := 'BlockAverage_SSE2';
  4386. ResamplersRegistry[@@Interpolator].ADD(@Interpolator_SSE2, [isSSE2]).Name := 'Interpolator_SSE2';
  4387. {$ifend}
  4388. ResamplersRegistry.RebindAll;
  4389. end;
  4390. //------------------------------------------------------------------------------
  4391. initialization
  4392. RegisterBindings;
  4393. { Register resamplers }
  4394. RegisterResampler(TNearestResampler);
  4395. RegisterResampler(TLinearResampler);
  4396. RegisterResampler(TDraftResampler);
  4397. RegisterResampler(TKernelResampler);
  4398. { Register kernels }
  4399. RegisterKernel(TBoxKernel);
  4400. RegisterKernel(TLinearKernel);
  4401. RegisterKernel(TCosineKernel);
  4402. RegisterKernel(TSplineKernel);
  4403. RegisterKernel(TCubicKernel);
  4404. RegisterKernel(TMitchellKernel);
  4405. RegisterKernel(TAlbrechtKernel);
  4406. RegisterKernel(TLanczosKernel);
  4407. RegisterKernel(TGaussianKernel);
  4408. RegisterKernel(TBlackmanKernel);
  4409. RegisterKernel(THannKernel);
  4410. RegisterKernel(THammingKernel);
  4411. RegisterKernel(TSinshKernel);
  4412. RegisterKernel(THermiteKernel);
  4413. finalization
  4414. ResamplerList.Free;
  4415. KernelList.Free;
  4416. end.