GR32_Resamplers.pas 114 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195
  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. * Portions created by the Initial Developer are Copyright (C) 2000-2009
  29. * the Initial Developer. All Rights Reserved.
  30. *
  31. * Contributor(s):
  32. * Michael Hansen <[email protected]>
  33. *
  34. * ***** END LICENSE BLOCK ***** *)
  35. interface
  36. {$I GR32.inc}
  37. {$IFNDEF FPC}
  38. {-$IFDEF USE_3DNOW}
  39. {$ENDIF}
  40. uses
  41. Types,
  42. Classes, SysUtils, GR32, GR32_Transforms, GR32_Containers,
  43. GR32_OrdinalMaps, GR32_Blend;
  44. procedure BlockTransfer(
  45. Dst: TCustomBitmap32; DstX: Integer; DstY: Integer; DstClip: TRect;
  46. Src: TCustomBitmap32; SrcRect: TRect;
  47. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent = nil);
  48. procedure BlockTransferX(
  49. Dst: TCustomBitmap32; DstX, DstY: TFixed;
  50. Src: TCustomBitmap32; SrcRect: TRect;
  51. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent = nil);
  52. procedure StretchTransfer(
  53. Dst: TCustomBitmap32; DstRect: TRect; DstClip: TRect;
  54. Src: TCustomBitmap32; SrcRect: TRect;
  55. Resampler: TCustomResampler;
  56. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent = nil);
  57. procedure BlendTransfer(
  58. Dst: TCustomBitmap32; DstX, DstY: Integer; DstClip: TRect;
  59. SrcF: TCustomBitmap32; SrcRectF: TRect;
  60. SrcB: TCustomBitmap32; SrcRectB: TRect;
  61. BlendCallback: TBlendReg); overload;
  62. procedure BlendTransfer(
  63. Dst: TCustomBitmap32; DstX, DstY: Integer; DstClip: TRect;
  64. SrcF: TCustomBitmap32; SrcRectF: TRect;
  65. SrcB: TCustomBitmap32; SrcRectB: TRect;
  66. BlendCallback: TBlendRegEx; MasterAlpha: Integer); overload;
  67. const
  68. MAX_KERNEL_WIDTH = 16;
  69. type
  70. PKernelEntry = ^TKernelEntry;
  71. TKernelEntry = array [-MAX_KERNEL_WIDTH..MAX_KERNEL_WIDTH] of Integer;
  72. TArrayOfKernelEntry = array of TArrayOfInteger;
  73. PKernelEntryArray = ^TKernelEntryArray;
  74. TKernelEntryArray = array [0..0] of TArrayOfInteger;
  75. TFilterMethod = function(Value: TFloat): TFloat of object;
  76. EBitmapException = class(Exception);
  77. ESrcInvalidException = class(Exception);
  78. ENestedException = class(Exception);
  79. TGetSampleInt = function(X, Y: Integer): TColor32 of object;
  80. TGetSampleFloat = function(X, Y: TFloat): TColor32 of object;
  81. TGetSampleFixed = function(X, Y: TFixed): TColor32 of object;
  82. { TCustomKernel }
  83. TCustomKernel = class(TPersistent)
  84. protected
  85. FObserver: TNotifiablePersistent;
  86. protected
  87. procedure AssignTo(Dst: TPersistent); override;
  88. function RangeCheck: Boolean; virtual;
  89. public
  90. constructor Create; virtual;
  91. procedure Changed;
  92. function Filter(Value: TFloat): TFloat; virtual; abstract;
  93. function GetWidth: TFloat; virtual; abstract;
  94. property Observer: TNotifiablePersistent read FObserver;
  95. end;
  96. TCustomKernelClass = class of TCustomKernel;
  97. { TBoxKernel }
  98. TBoxKernel = class(TCustomKernel)
  99. public
  100. function Filter(Value: TFloat): TFloat; override;
  101. function GetWidth: TFloat; override;
  102. end;
  103. { TLinearKernel }
  104. TLinearKernel = class(TCustomKernel)
  105. public
  106. function Filter(Value: TFloat): TFloat; override;
  107. function GetWidth: TFloat; override;
  108. end;
  109. { TCosineKernel }
  110. TCosineKernel = class(TCustomKernel)
  111. public
  112. function Filter(Value: TFloat): TFloat; override;
  113. function GetWidth: TFloat; override;
  114. end;
  115. { TSplineKernel }
  116. TSplineKernel = class(TCustomKernel)
  117. protected
  118. function RangeCheck: Boolean; override;
  119. public
  120. function Filter(Value: TFloat): TFloat; override;
  121. function GetWidth: TFloat; override;
  122. end;
  123. { TMitchellKernel }
  124. TMitchellKernel = class(TCustomKernel)
  125. protected
  126. function RangeCheck: Boolean; override;
  127. public
  128. function Filter(Value: TFloat): TFloat; override;
  129. function GetWidth: TFloat; override;
  130. end;
  131. { TCubicKernel }
  132. TCubicKernel = class(TCustomKernel)
  133. private
  134. FCoeff: TFloat;
  135. procedure SetCoeff(const Value: TFloat);
  136. protected
  137. function RangeCheck: Boolean; override;
  138. public
  139. constructor Create; override;
  140. function Filter(Value: TFloat): TFloat; override;
  141. function GetWidth: TFloat; override;
  142. published
  143. property Coeff: TFloat read FCoeff write SetCoeff;
  144. end;
  145. { THermiteKernel }
  146. THermiteKernel = class(TCustomKernel)
  147. private
  148. FBias: TFloat;
  149. FTension: TFloat;
  150. procedure SetBias(const Value: TFloat);
  151. procedure SetTension(const Value: TFloat);
  152. protected
  153. function RangeCheck: Boolean; override;
  154. public
  155. constructor Create; override;
  156. function Filter(Value: TFloat): TFloat; override;
  157. function GetWidth: TFloat; override;
  158. published
  159. property Bias: TFloat read FBias write SetBias;
  160. property Tension: TFloat read FTension write SetTension;
  161. end;
  162. { TWindowedSincKernel }
  163. TWindowedSincKernel = class(TCustomKernel)
  164. private
  165. FWidth : TFloat;
  166. FWidthReciprocal : TFloat;
  167. protected
  168. function RangeCheck: Boolean; override;
  169. function Window(Value: TFloat): TFloat; virtual; abstract;
  170. public
  171. constructor Create; override;
  172. function Filter(Value: TFloat): TFloat; override;
  173. procedure SetWidth(Value: TFloat);
  174. function GetWidth: TFloat; override;
  175. property WidthReciprocal : TFloat read FWidthReciprocal;
  176. published
  177. property Width: TFloat read FWidth write SetWidth;
  178. end;
  179. { TAlbrecht-Kernel }
  180. TAlbrechtKernel = class(TWindowedSincKernel)
  181. private
  182. FTerms: Integer;
  183. FCoefPointer : Array [0..11] of Double;
  184. procedure SetTerms(Value : Integer);
  185. protected
  186. function Window(Value: TFloat): TFloat; override;
  187. public
  188. constructor Create; override;
  189. published
  190. property Terms: Integer read FTerms write SetTerms;
  191. end;
  192. { TLanczosKernel }
  193. TLanczosKernel = class(TWindowedSincKernel)
  194. protected
  195. function Window(Value: TFloat): TFloat; override;
  196. public
  197. end;
  198. { TGaussianKernel }
  199. TGaussianKernel = class(TWindowedSincKernel)
  200. private
  201. FSigma: TFloat;
  202. FSigmaReciprocalLn2: TFloat;
  203. procedure SetSigma(const Value: TFloat);
  204. protected
  205. function Window(Value: TFloat): TFloat; override;
  206. public
  207. constructor Create; override;
  208. published
  209. property Sigma: TFloat read FSigma write SetSigma;
  210. end;
  211. { TBlackmanKernel }
  212. TBlackmanKernel = class(TWindowedSincKernel)
  213. protected
  214. function Window(Value: TFloat): TFloat; override;
  215. end;
  216. { THannKernel }
  217. THannKernel = class(TWindowedSincKernel)
  218. protected
  219. function Window(Value: TFloat): TFloat; override;
  220. end;
  221. { THammingKernel }
  222. THammingKernel = class(TWindowedSincKernel)
  223. protected
  224. function Window(Value: TFloat): TFloat; override;
  225. end;
  226. { TSinshKernel }
  227. TSinshKernel = class(TCustomKernel)
  228. private
  229. FWidth: TFloat;
  230. FCoeff: TFloat;
  231. procedure SetCoeff(const Value: TFloat);
  232. protected
  233. function RangeCheck: Boolean; override;
  234. public
  235. constructor Create; override;
  236. procedure SetWidth(Value: TFloat);
  237. function GetWidth: TFloat; override;
  238. function Filter(Value: TFloat): TFloat; override;
  239. published
  240. property Coeff: TFloat read FCoeff write SetCoeff;
  241. property Width: TFloat read GetWidth write SetWidth;
  242. end;
  243. { TNearestResampler }
  244. TNearestResampler = class(TCustomResampler)
  245. private
  246. FGetSampleInt: TGetSampleInt;
  247. protected
  248. function GetPixelTransparentEdge(X, Y: Integer): TColor32;
  249. function GetWidth: TFloat; override;
  250. procedure Resample(
  251. Dst: TCustomBitmap32; DstRect: TRect; DstClip: TRect;
  252. Src: TCustomBitmap32; SrcRect: TRect;
  253. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent); override;
  254. public
  255. function GetSampleInt(X, Y: Integer): TColor32; override;
  256. function GetSampleFixed(X, Y: TFixed): TColor32; override;
  257. function GetSampleFloat(X, Y: TFloat): TColor32; override;
  258. procedure PrepareSampling; override;
  259. end;
  260. { TLinearResampler }
  261. TLinearResampler = class(TCustomResampler)
  262. private
  263. FLinearKernel: TLinearKernel;
  264. FGetSampleFixed: TGetSampleFixed;
  265. protected
  266. function GetWidth: TFloat; override;
  267. function GetPixelTransparentEdge(X, Y: TFixed): TColor32;
  268. procedure Resample(
  269. Dst: TCustomBitmap32; DstRect: TRect; DstClip: TRect;
  270. Src: TCustomBitmap32; SrcRect: TRect;
  271. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent); override;
  272. public
  273. constructor Create; override;
  274. destructor Destroy; override;
  275. function GetSampleFixed(X, Y: TFixed): TColor32; override;
  276. function GetSampleFloat(X, Y: TFloat): TColor32; override;
  277. procedure PrepareSampling; override;
  278. end;
  279. { TDraftResampler }
  280. TDraftResampler = class(TLinearResampler)
  281. protected
  282. procedure Resample(
  283. Dst: TCustomBitmap32; DstRect: TRect; DstClip: TRect;
  284. Src: TCustomBitmap32; SrcRect: TRect;
  285. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent); override;
  286. end;
  287. { TKernelResampler }
  288. { This resampler class will perform resampling by using an arbitrary
  289. reconstruction kernel. By using the kmTableNearest and kmTableLinear
  290. kernel modes, kernel values are precomputed in a look-up table. This
  291. allows GetSample to execute faster for complex kernels. }
  292. TKernelMode = (kmDynamic, kmTableNearest, kmTableLinear);
  293. TKernelResampler = class(TCustomResampler)
  294. private
  295. FKernel: TCustomKernel;
  296. FKernelMode: TKernelMode;
  297. FWeightTable: TIntegerMap;
  298. FTableSize: Integer;
  299. FOuterColor: TColor32;
  300. procedure SetKernel(const Value: TCustomKernel);
  301. function GetKernelClassName: string;
  302. procedure SetKernelClassName(const Value: string);
  303. procedure SetKernelMode(const Value: TKernelMode);
  304. procedure SetTableSize(Value: Integer);
  305. protected
  306. function GetWidth: TFloat; override;
  307. public
  308. constructor Create; override;
  309. destructor Destroy; override;
  310. function GetSampleFloat(X, Y: TFloat): TColor32; override;
  311. procedure Resample(
  312. Dst: TCustomBitmap32; DstRect: TRect; DstClip: TRect;
  313. Src: TCustomBitmap32; SrcRect: TRect;
  314. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent); override;
  315. procedure PrepareSampling; override;
  316. procedure FinalizeSampling; override;
  317. published
  318. property KernelClassName: string read GetKernelClassName write SetKernelClassName;
  319. property Kernel: TCustomKernel read FKernel write SetKernel;
  320. property KernelMode: TKernelMode read FKernelMode write SetKernelMode;
  321. property TableSize: Integer read FTableSize write SetTableSize;
  322. end;
  323. { TNestedSampler }
  324. TNestedSampler = class(TCustomSampler)
  325. private
  326. FSampler: TCustomSampler;
  327. FGetSampleInt: TGetSampleInt;
  328. FGetSampleFixed: TGetSampleFixed;
  329. FGetSampleFloat: TGetSampleFloat;
  330. procedure SetSampler(const Value: TCustomSampler);
  331. protected
  332. procedure AssignTo(Dst: TPersistent); override;
  333. public
  334. constructor Create(ASampler: TCustomSampler); reintroduce; virtual;
  335. procedure PrepareSampling; override;
  336. procedure FinalizeSampling; override;
  337. function HasBounds: Boolean; override;
  338. function GetSampleBounds: TFloatRect; override;
  339. published
  340. property Sampler: TCustomSampler read FSampler write SetSampler;
  341. end;
  342. { TTransformer }
  343. TReverseTransformInt = procedure(DstX, DstY: Integer; out SrcX, SrcY: Integer) of object;
  344. TReverseTransformFixed = procedure(DstX, DstY: TFixed; out SrcX, SrcY: TFixed) of object;
  345. TReverseTransformFloat = procedure(DstX, DstY: TFloat; out SrcX, SrcY: TFloat) of object;
  346. TTransformer = class(TNestedSampler)
  347. private
  348. FTransformation: TTransformation;
  349. FTransformationReverseTransformInt: TReverseTransformInt;
  350. FTransformationReverseTransformFixed: TReverseTransformFixed;
  351. FTransformationReverseTransformFloat: TReverseTransformFloat;
  352. procedure SetTransformation(const Value: TTransformation);
  353. public
  354. constructor Create(ASampler: TCustomSampler; ATransformation: TTransformation); reintroduce;
  355. procedure PrepareSampling; override;
  356. function GetSampleInt(X, Y: Integer): TColor32; override;
  357. function GetSampleFixed(X, Y: TFixed): TColor32; override;
  358. function GetSampleFloat(X, Y: TFloat): TColor32; override;
  359. function HasBounds: Boolean; override;
  360. function GetSampleBounds: TFloatRect; override;
  361. published
  362. property Transformation: TTransformation read FTransformation write SetTransformation;
  363. end;
  364. { TSuperSampler }
  365. TSamplingRange = 1..MaxInt;
  366. TSuperSampler = class(TNestedSampler)
  367. private
  368. FSamplingY: TSamplingRange;
  369. FSamplingX: TSamplingRange;
  370. FDistanceX: TFixed;
  371. FDistanceY: TFixed;
  372. FOffsetX: TFixed;
  373. FOffsetY: TFixed;
  374. FScale: TFixed;
  375. procedure SetSamplingX(const Value: TSamplingRange);
  376. procedure SetSamplingY(const Value: TSamplingRange);
  377. public
  378. constructor Create(Sampler: TCustomSampler); override;
  379. function GetSampleFixed(X, Y: TFixed): TColor32; override;
  380. published
  381. property SamplingX: TSamplingRange read FSamplingX write SetSamplingX;
  382. property SamplingY: TSamplingRange read FSamplingY write SetSamplingY;
  383. end;
  384. { TAdaptiveSuperSampler }
  385. TRecurseProc = function(X, Y, W: TFixed; const C1, C2: TColor32): TColor32 of object;
  386. TAdaptiveSuperSampler = class(TNestedSampler)
  387. private
  388. FMinOffset: TFixed;
  389. FLevel: Integer;
  390. FTolerance: Integer;
  391. procedure SetLevel(const Value: Integer);
  392. function DoRecurse(X, Y, Offset: TFixed; const A, B, C, D, E: TColor32): TColor32;
  393. function QuadrantColor(const C1, C2: TColor32; X, Y, Offset: TFixed;
  394. Proc: TRecurseProc): TColor32;
  395. function RecurseAC(X, Y, Offset: TFixed; const A, C: TColor32): TColor32;
  396. function RecurseBD(X, Y, Offset: TFixed; const B, D: TColor32): TColor32;
  397. protected
  398. function CompareColors(C1, C2: TColor32): Boolean; virtual;
  399. public
  400. constructor Create(Sampler: TCustomSampler); override;
  401. function GetSampleFixed(X, Y: TFixed): TColor32; override;
  402. published
  403. property Level: Integer read FLevel write SetLevel;
  404. property Tolerance: Integer read FTolerance write FTolerance;
  405. end;
  406. { TPatternSampler }
  407. TFloatSamplePattern = array of array of TArrayOfFloatPoint;
  408. TFixedSamplePattern = array of array of TArrayOfFixedPoint;
  409. TPatternSampler = class(TNestedSampler)
  410. private
  411. FPattern: TFixedSamplePattern;
  412. procedure SetPattern(const Value: TFixedSamplePattern);
  413. protected
  414. WrapProcVert: TWrapProc;
  415. public
  416. destructor Destroy; override;
  417. function GetSampleFixed(X, Y: TFixed): TColor32; override;
  418. property Pattern: TFixedSamplePattern read FPattern write SetPattern;
  419. end;
  420. { Auxiliary record used in accumulation routines }
  421. PBufferEntry = ^TBufferEntry;
  422. TBufferEntry = record
  423. B, G, R, A: Integer;
  424. end;
  425. { TKernelSampler }
  426. TKernelSampler = class(TNestedSampler)
  427. private
  428. FKernel: TIntegerMap;
  429. FStartEntry: TBufferEntry;
  430. FCenterX: Integer;
  431. FCenterY: Integer;
  432. protected
  433. procedure UpdateBuffer(var Buffer: TBufferEntry; Color: TColor32;
  434. Weight: Integer); virtual; abstract;
  435. function ConvertBuffer(var Buffer: TBufferEntry): TColor32; virtual;
  436. public
  437. constructor Create(ASampler: TCustomSampler); override;
  438. destructor Destroy; override;
  439. function GetSampleInt(X, Y: Integer): TColor32; override;
  440. function GetSampleFixed(X, Y: TFixed): TColor32; override;
  441. published
  442. property Kernel: TIntegerMap read FKernel write FKernel;
  443. property CenterX: Integer read FCenterX write FCenterX;
  444. property CenterY: Integer read FCenterY write FCenterY;
  445. end;
  446. { TConvolver }
  447. TConvolver = class(TKernelSampler)
  448. protected
  449. procedure UpdateBuffer(var Buffer: TBufferEntry; Color: TColor32;
  450. Weight: Integer); override;
  451. end;
  452. { TSelectiveConvolver }
  453. TSelectiveConvolver = class(TConvolver)
  454. private
  455. FRefColor: TColor32;
  456. FDelta: Integer;
  457. FWeightSum: TBufferEntry;
  458. protected
  459. procedure UpdateBuffer(var Buffer: TBufferEntry; Color: TColor32;
  460. Weight: Integer); override;
  461. function ConvertBuffer(var Buffer: TBufferEntry): TColor32; override;
  462. public
  463. constructor Create(ASampler: TCustomSampler); override;
  464. function GetSampleInt(X, Y: Integer): TColor32; override;
  465. function GetSampleFixed(X, Y: TFixed): TColor32; override;
  466. published
  467. property Delta: Integer read FDelta write FDelta;
  468. end;
  469. { TMorphologicalSampler }
  470. TMorphologicalSampler = class(TKernelSampler)
  471. protected
  472. function ConvertBuffer(var Buffer: TBufferEntry): TColor32; override;
  473. end;
  474. { TDilater }
  475. TDilater = class(TMorphologicalSampler)
  476. protected
  477. procedure UpdateBuffer(var Buffer: TBufferEntry; Color: TColor32;
  478. Weight: Integer); override;
  479. end;
  480. { TEroder }
  481. TEroder = class(TMorphologicalSampler)
  482. protected
  483. procedure UpdateBuffer(var Buffer: TBufferEntry; Color: TColor32;
  484. Weight: Integer); override;
  485. public
  486. constructor Create(ASampler: TCustomSampler); override;
  487. end;
  488. { TExpander }
  489. TExpander = class(TKernelSampler)
  490. protected
  491. procedure UpdateBuffer(var Buffer: TBufferEntry; Color: TColor32;
  492. Weight: Integer); override;
  493. end;
  494. { TContracter }
  495. TContracter = class(TExpander)
  496. private
  497. FMaxWeight: TColor32;
  498. protected
  499. procedure UpdateBuffer(var Buffer: TBufferEntry; Color: TColor32;
  500. Weight: Integer); override;
  501. public
  502. procedure PrepareSampling; override;
  503. function GetSampleInt(X, Y: Integer): TColor32; override;
  504. function GetSampleFixed(X, Y: TFixed): TColor32; override;
  505. end;
  506. function CreateJitteredPattern(TileWidth, TileHeight, SamplesX, SamplesY: Integer): TFixedSamplePattern;
  507. { Convolution and morphological routines }
  508. procedure Convolve(Src, Dst: TCustomBitmap32; Kernel: TIntegerMap; CenterX, CenterY: Integer);
  509. procedure Dilate(Src, Dst: TCustomBitmap32; Kernel: TIntegerMap; CenterX, CenterY: Integer);
  510. procedure Erode(Src, Dst: TCustomBitmap32; Kernel: TIntegerMap; CenterX, CenterY: Integer);
  511. procedure Expand(Src, Dst: TCustomBitmap32; Kernel: TIntegerMap; CenterX, CenterY: Integer);
  512. procedure Contract(Src, Dst: TCustomBitmap32; Kernel: TIntegerMap; CenterX, CenterY: Integer);
  513. { Auxiliary routines for accumulating colors in a buffer }
  514. procedure IncBuffer(var Buffer: TBufferEntry; Color: TColor32); {$IFDEF USEINLINING} inline; {$ENDIF}
  515. procedure MultiplyBuffer(var Buffer: TBufferEntry; W: Integer); {$IFDEF USEINLINING} inline; {$ENDIF}
  516. function BufferToColor32(const Buffer: TBufferEntry; Shift: Integer): TColor32; {$IFDEF USEINLINING} inline; {$ENDIF}
  517. procedure ShrBuffer(var Buffer: TBufferEntry; Shift: Integer); {$IFDEF USEINLINING} inline; {$ENDIF}
  518. { Registration routines }
  519. procedure RegisterResampler(ResamplerClass: TCustomResamplerClass);
  520. procedure RegisterKernel(KernelClass: TCustomKernelClass);
  521. var
  522. KernelList: TClassList;
  523. ResamplerList: TClassList;
  524. const
  525. EMPTY_ENTRY: TBufferEntry = (B: 0; G: 0; R: 0; A: 0);
  526. var
  527. BlockAverage: function(Dlx, Dly: Cardinal; RowSrc: PColor32; OffSrc: Cardinal): TColor32;
  528. Interpolator: function(WX_256, WY_256: Cardinal; C11, C21: PColor32): TColor32;
  529. resourcestring
  530. SDstNil = 'Destination bitmap is nil';
  531. SSrcNil = 'Source bitmap is nil';
  532. SSrcInvalid = 'Source rectangle is invalid';
  533. SSamplerNil = 'Nested sampler is nil';
  534. implementation
  535. uses
  536. GR32_System, GR32_Bindings, GR32_LowLevel, GR32_Rasterizers, GR32_Math, Math;
  537. resourcestring
  538. RCStrInvalidSrcRect = 'Invalid SrcRect';
  539. const
  540. CAlbrecht2 : array [0..1] of Double = (5.383553946707251E-1,
  541. 4.616446053292749E-1);
  542. CAlbrecht3 : array [0..2] of Double = (3.46100822018625E-1,
  543. 4.97340635096738E-1, 1.56558542884637E-1);
  544. CAlbrecht4 : array [0..3] of Double = (2.26982412792069E-1,
  545. 4.57254070828427E-1, 2.73199027957384E-1, 4.25644884221201E-2);
  546. CAlbrecht5 : array [0..4] of Double = (1.48942606015830E-1,
  547. 3.86001173639176E-1, 3.40977403214053E-1, 1.139879604246E-1,
  548. 1.00908567063414E-2);
  549. CAlbrecht6 : array [0..5] of Double = (9.71676200107429E-2,
  550. 3.08845222524055E-1, 3.62623371437917E-1, 1.88953325525116E-1,
  551. 4.02095714148751E-2, 2.20088908729420E-3);
  552. CAlbrecht7 : array [0..6] of Double = (6.39644241143904E-2,
  553. 2.39938645993528E-1, 3.50159563238205E-1, 2.47741118970808E-1,
  554. 8.54382560558580E-2, 1.23202033692932E-2, 4.37788257917735E-4);
  555. CAlbrecht8 : array [0..7] of Double = (4.21072107042137E-2,
  556. 1.82076226633776E-1, 3.17713781059942E-1, 2.84438001373442E-1,
  557. 1.36762237777383E-1, 3.34038053504025E-2, 3.41677216705768E-3,
  558. 8.19649337831348E-5);
  559. CAlbrecht9 : array [0..8] of Double = (2.76143731612611E-2,
  560. 1.35382228758844E-1, 2.75287234472237E-1, 2.98843335317801E-1,
  561. 1.85319330279284E-1, 6.48884482549063E-2, 1.17641910285655E-2,
  562. 8.85987580106899E-4, 1.48711469943406E-5);
  563. CAlbrecht10: array [0..9] of Double = (1.79908225352538E-2,
  564. 9.87959586065210E-2, 2.29883817001211E-1, 2.94113019095183E-1,
  565. 2.24338977814325E-1, 1.03248806248099E-1, 2.75674109448523E-2,
  566. 3.83958622947123E-3, 2.18971708430106E-4, 2.62981665347889E-6);
  567. CAlbrecht11: array [0..10] of Double = (1.18717127796602E-2,
  568. 7.19533651951142E-2, 1.87887160922585E-1, 2.75808174097291E-1,
  569. 2.48904243244464E-1, 1.41729867200712E-1, 5.02002976228256E-2,
  570. 1.04589649084984E-2, 1.13615112741660E-3, 4.96285981703436E-5,
  571. 4.34303262685720E-7);
  572. type
  573. TTransformationAccess = class(TTransformation);
  574. TCustomBitmap32Access = class(TCustomBitmap32);
  575. TCustomResamplerAccess = class(TCustomResampler);
  576. PPointRec = ^TPointRec;
  577. TPointRec = record
  578. Pos: Integer;
  579. Weight: Cardinal;
  580. end;
  581. TCluster = array of TPointRec;
  582. TMappingTable = array of TCluster;
  583. TKernelSamplerClass = class of TKernelSampler;
  584. { Auxiliary rasterization routine for kernel-based samplers }
  585. procedure RasterizeKernelSampler(Src, Dst: TCustomBitmap32; Kernel: TIntegerMap;
  586. CenterX, CenterY: Integer; SamplerClass: TKernelSamplerClass);
  587. var
  588. Sampler: TKernelSampler;
  589. Rasterizer: TRasterizer;
  590. begin
  591. Rasterizer := DefaultRasterizerClass.Create;
  592. try
  593. Dst.SetSizeFrom(Src);
  594. Sampler := SamplerClass.Create(Src.Resampler);
  595. Sampler.Kernel := Kernel;
  596. try
  597. Rasterizer.Sampler := Sampler;
  598. Rasterizer.Rasterize(Dst);
  599. finally
  600. Sampler.Free;
  601. end;
  602. finally
  603. Rasterizer.Free;
  604. end;
  605. end;
  606. procedure Convolve(Src, Dst: TCustomBitmap32; Kernel: TIntegerMap; CenterX, CenterY: Integer);
  607. begin
  608. RasterizeKernelSampler(Src, Dst, Kernel, CenterX, CenterY, TConvolver);
  609. end;
  610. procedure Dilate(Src, Dst: TCustomBitmap32; Kernel: TIntegerMap; CenterX, CenterY: Integer);
  611. begin
  612. RasterizeKernelSampler(Src, Dst, Kernel, CenterX, CenterY, TDilater);
  613. end;
  614. procedure Erode(Src, Dst: TCustomBitmap32; Kernel: TIntegerMap; CenterX, CenterY: Integer);
  615. begin
  616. RasterizeKernelSampler(Src, Dst, Kernel, CenterX, CenterY, TEroder);
  617. end;
  618. procedure Expand(Src, Dst: TCustomBitmap32; Kernel: TIntegerMap; CenterX, CenterY: Integer);
  619. begin
  620. RasterizeKernelSampler(Src, Dst, Kernel, CenterX, CenterY, TExpander);
  621. end;
  622. procedure Contract(Src, Dst: TCustomBitmap32; Kernel: TIntegerMap; CenterX, CenterY: Integer);
  623. begin
  624. RasterizeKernelSampler(Src, Dst, Kernel, CenterX, CenterY, TContracter);
  625. end;
  626. { Auxiliary routines }
  627. procedure IncBuffer(var Buffer: TBufferEntry; Color: TColor32);
  628. begin
  629. with TColor32Entry(Color) do
  630. begin
  631. Inc(Buffer.B, B);
  632. Inc(Buffer.G, G);
  633. Inc(Buffer.R, R);
  634. Inc(Buffer.A, A);
  635. end;
  636. end;
  637. procedure MultiplyBuffer(var Buffer: TBufferEntry; W: Integer);
  638. begin
  639. Buffer.B := Buffer.B * W;
  640. Buffer.G := Buffer.G * W;
  641. Buffer.R := Buffer.R * W;
  642. Buffer.A := Buffer.A * W;
  643. end;
  644. procedure ShrBuffer(var Buffer: TBufferEntry; Shift: Integer);
  645. begin
  646. Buffer.B := Buffer.B shr Shift;
  647. Buffer.G := Buffer.G shr Shift;
  648. Buffer.R := Buffer.R shr Shift;
  649. Buffer.A := Buffer.A shr Shift;
  650. end;
  651. function BufferToColor32(const Buffer: TBufferEntry; Shift: Integer): TColor32;
  652. begin
  653. with TColor32Entry(Result) do
  654. begin
  655. B := Buffer.B shr Shift;
  656. G := Buffer.G shr Shift;
  657. R := Buffer.R shr Shift;
  658. A := Buffer.A shr Shift;
  659. end;
  660. end;
  661. procedure CheckBitmaps(Dst, Src: TCustomBitmap32); {$IFDEF USEINLINING}inline;{$ENDIF}
  662. begin
  663. if not Assigned(Dst) then raise EBitmapException.Create(SDstNil);
  664. if not Assigned(Src) then raise EBitmapException.Create(SSrcNil);
  665. end;
  666. procedure BlendBlock(
  667. Dst: TCustomBitmap32; DstRect: TRect;
  668. Src: TCustomBitmap32; SrcX, SrcY: Integer;
  669. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
  670. var
  671. SrcP, DstP: PColor32;
  672. SP, DP: PColor32;
  673. MC: TColor32;
  674. W, I, DstY: Integer;
  675. BlendLine: TBlendLine;
  676. BlendLineEx: TBlendLineEx;
  677. begin
  678. { Internal routine }
  679. W := DstRect.Right - DstRect.Left;
  680. SrcP := Src.PixelPtr[SrcX, SrcY];
  681. DstP := Dst.PixelPtr[DstRect.Left, DstRect.Top];
  682. case CombineOp of
  683. dmOpaque:
  684. begin
  685. for DstY := DstRect.Top to DstRect.Bottom - 1 do
  686. begin
  687. //Move(SrcP^, DstP^, W shl 2); // for FastCode
  688. MoveLongWord(SrcP^, DstP^, W);
  689. Inc(SrcP, Src.Width);
  690. Inc(DstP, Dst.Width);
  691. end;
  692. end;
  693. dmBlend:
  694. if Src.MasterAlpha >= 255 then
  695. begin
  696. BlendLine := BLEND_LINE[Src.CombineMode]^;
  697. for DstY := DstRect.Top to DstRect.Bottom - 1 do
  698. begin
  699. BlendLine(SrcP, DstP, W);
  700. Inc(SrcP, Src.Width);
  701. Inc(DstP, Dst.Width);
  702. end
  703. end
  704. else
  705. begin
  706. BlendLineEx := BLEND_LINE_EX[Src.CombineMode]^;
  707. for DstY := DstRect.Top to DstRect.Bottom - 1 do
  708. begin
  709. BlendLineEx(SrcP, DstP, W, Src.MasterAlpha);
  710. Inc(SrcP, Src.Width);
  711. Inc(DstP, Dst.Width);
  712. end
  713. end;
  714. dmTransparent:
  715. begin
  716. MC := Src.OuterColor;
  717. for DstY := DstRect.Top to DstRect.Bottom - 1 do
  718. begin
  719. SP := SrcP;
  720. DP := DstP;
  721. { TODO: Write an optimized routine for fast masked transfers. }
  722. for I := 0 to W - 1 do
  723. begin
  724. if MC <> SP^ then DP^ := SP^;
  725. Inc(SP); Inc(DP);
  726. end;
  727. Inc(SrcP, Src.Width);
  728. Inc(DstP, Dst.Width);
  729. end;
  730. end;
  731. else // dmCustom:
  732. begin
  733. for DstY := DstRect.Top to DstRect.Bottom - 1 do
  734. begin
  735. SP := SrcP;
  736. DP := DstP;
  737. for I := 0 to W - 1 do
  738. begin
  739. CombineCallBack(SP^, DP^, Src.MasterAlpha);
  740. Inc(SP); Inc(DP);
  741. end;
  742. Inc(SrcP, Src.Width);
  743. Inc(DstP, Dst.Width);
  744. end;
  745. end;
  746. end;
  747. end;
  748. procedure BlockTransfer(
  749. Dst: TCustomBitmap32; DstX: Integer; DstY: Integer; DstClip: TRect;
  750. Src: TCustomBitmap32; SrcRect: TRect;
  751. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
  752. var
  753. SrcX, SrcY: Integer;
  754. begin
  755. CheckBitmaps(Dst, Src);
  756. if Dst.Empty or Src.Empty or ((CombineOp = dmBlend) and (Src.MasterAlpha = 0)) then Exit;
  757. SrcX := SrcRect.Left;
  758. SrcY := SrcRect.Top;
  759. GR32.IntersectRect(DstClip, DstClip, Dst.BoundsRect);
  760. GR32.IntersectRect(SrcRect, SrcRect, Src.BoundsRect);
  761. GR32.OffsetRect(SrcRect, DstX - SrcX, DstY - SrcY);
  762. GR32.IntersectRect(SrcRect, DstClip, SrcRect);
  763. if GR32.IsRectEmpty(SrcRect) then
  764. exit;
  765. DstClip := SrcRect;
  766. GR32.OffsetRect(SrcRect, SrcX - DstX, SrcY - DstY);
  767. if not Dst.MeasuringMode then
  768. begin
  769. try
  770. if (CombineOp = dmCustom) and not Assigned(CombineCallBack) then
  771. CombineOp := dmOpaque;
  772. BlendBlock(Dst, DstClip, Src, SrcRect.Left, SrcRect.Top, CombineOp, CombineCallBack);
  773. finally
  774. EMMS;
  775. end;
  776. end;
  777. Dst.Changed(DstClip);
  778. end;
  779. {$WARNINGS OFF}
  780. procedure BlockTransferX(
  781. Dst: TCustomBitmap32; DstX, DstY: TFixed;
  782. Src: TCustomBitmap32; SrcRect: TRect;
  783. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent = nil);
  784. type
  785. TColor32Array = array [0..1] of TColor32;
  786. PColor32Array = ^TColor32Array;
  787. var
  788. I, Index, SrcW, SrcRectW, SrcRectH, DstW, DstH: Integer;
  789. FracX, FracY: Integer;
  790. Buffer: array [0..1] of TArrayOfColor32;
  791. SrcP, Buf1, Buf2: PColor32Array;
  792. DstP: PColor32;
  793. C1, C2, C3, C4: TColor32;
  794. LW, RW, TW, BW, MA: Integer;
  795. DstBounds: TRect;
  796. BlendLineEx: TBlendLineEx;
  797. BlendMemEx: TBlendMemEx;
  798. begin
  799. CheckBitmaps(Dst, Src);
  800. if Dst.Empty or Src.Empty or ((CombineOp = dmBlend) and (Src.MasterAlpha = 0)) then Exit;
  801. SrcRectW := SrcRect.Right - SrcRect.Left - 1;
  802. SrcRectH := SrcRect.Bottom - SrcRect.Top - 1;
  803. FracX := (DstX and $FFFF) shr 8;
  804. FracY := (DstY and $FFFF) shr 8;
  805. DstX := DstX div $10000;
  806. DstY := DstY div $10000;
  807. DstW := Dst.Width;
  808. DstH := Dst.Height;
  809. MA := Src.MasterAlpha;
  810. if (DstX >= DstW) or (DstY >= DstH) or (MA = 0) then Exit;
  811. if (DstX + SrcRectW <= 0) or (Dsty + SrcRectH <= 0) then Exit;
  812. if DstX < 0 then LW := $FF else LW := FracX xor $FF;
  813. if DstY < 0 then TW := $FF else TW := FracY xor $FF;
  814. if DstX + SrcRectW >= DstW then RW := $FF else RW := FracX;
  815. if DstY + SrcRectH >= DstH then BW := $FF else BW := FracY;
  816. DstBounds := Dst.BoundsRect;
  817. Dec(DstBounds.Right);
  818. Dec(DstBounds.Bottom);
  819. GR32.OffsetRect(DstBounds, SrcRect.Left - DstX, SrcRect.Top - DstY);
  820. GR32.IntersectRect(SrcRect, SrcRect, DstBounds);
  821. if GR32.IsRectEmpty(SrcRect) then Exit;
  822. SrcW := Src.Width;
  823. SrcRectW := SrcRect.Right - SrcRect.Left;
  824. SrcRectH := SrcRect.Bottom - SrcRect.Top;
  825. if DstX < 0 then DstX := 0;
  826. if DstY < 0 then DstY := 0;
  827. if not Dst.MeasuringMode then
  828. begin
  829. SetLength(Buffer[0], SrcRectW + 1);
  830. SetLength(Buffer[1], SrcRectW + 1);
  831. BlendLineEx := BLEND_LINE_EX[Src.CombineMode]^;
  832. BlendMemEx := BLEND_MEM_EX[Src.CombineMode]^;
  833. try
  834. SrcP := PColor32Array(Src.PixelPtr[SrcRect.Left, SrcRect.Top - 1]);
  835. DstP := Dst.PixelPtr[DstX, DstY];
  836. Buf1 := @Buffer[0][0];
  837. Buf2 := @Buffer[1][0];
  838. if SrcRect.Top > 0 then
  839. begin
  840. MoveLongWord(SrcP[0], Buf1[0], SrcRectW);
  841. CombineLine(@Buf1[1], @Buf1[0], SrcRectW, FracX);
  842. if SrcRect.Left > 0 then
  843. {$IFDEF HAS_NATIVEINT}
  844. C2 := CombineReg(PColor32(NativeUInt(SrcP) - 4)^, SrcP[0], FracX xor $FF)
  845. {$ELSE}
  846. C2 := CombineReg(PColor32(Integer(SrcP) - 4)^, SrcP[0], FracX xor $FF)
  847. {$ENDIF}
  848. else
  849. C2 := SrcP[0];
  850. if SrcRect.Right < SrcW then
  851. C4 := CombineReg(SrcP[SrcRectW - 1], SrcP[SrcRectW], FracX)
  852. else
  853. C4 := SrcP[SrcRectW - 1];
  854. end;
  855. Inc(PColor32(SrcP), SrcW);
  856. MoveLongWord(SrcP^, Buf2^, SrcRectW);
  857. CombineLine(@Buf2[1], @Buf2[0], SrcRectW, FracX xor $FF);
  858. if SrcRect.Left > 0 then
  859. {$IFDEF HAS_NATIVEINT}
  860. C1 := CombineReg(PColor32(NativeUInt(SrcP) - 4)^, SrcP[0], FracX)
  861. {$ELSE}
  862. C1 := CombineReg(PColor32(Integer(SrcP) - 4)^, SrcP[0], FracX)
  863. {$ENDIF}
  864. else
  865. C1 := SrcP[0];
  866. if SrcRect.Right < SrcW then
  867. C3 := CombineReg(SrcP[SrcRectW - 1], SrcP[SrcRectW], FracX)
  868. else
  869. C3 := SrcP[SrcRectW - 1];
  870. if SrcRect.Top > 0 then
  871. begin
  872. BlendMemEx(CombineReg(C1, C2, FracY), DstP^, LW * TW * MA shr 16);
  873. CombineLine(@Buf2[0], @Buf1[0], SrcRectW, FracY xor $FF);
  874. end
  875. else
  876. begin
  877. BlendMemEx(C1, DstP^, LW * TW * MA shr 16);
  878. MoveLongWord(Buf2^, Buf1^, SrcRectW);
  879. end;
  880. Inc(DstP, 1);
  881. BlendLineEx(@Buf1[0], DstP, SrcRectW - 1, TW * MA shr 8);
  882. Inc(DstP, SrcRectW - 1);
  883. if SrcRect.Top > 0 then
  884. BlendMemEx(CombineReg(C3, C4, FracY), DstP^, RW * TW * MA shr 16)
  885. else
  886. BlendMemEx(C3, DstP^, RW * TW * MA shr 16);
  887. Inc(DstP, DstW - SrcRectW);
  888. Index := 1;
  889. for I := SrcRect.Top to SrcRect.Bottom - 2 do
  890. begin
  891. Buf1 := @Buffer[Index][0];
  892. Buf2 := @Buffer[Index xor 1][0];
  893. Inc(PColor32(SrcP), SrcW);
  894. MoveLongWord(SrcP[0], Buf2^, SrcRectW);
  895. // Horizontal translation
  896. CombineLine(@Buf2[1], @Buf2[0], SrcRectW, FracX xor $FF);
  897. if SrcRect.Left > 0 then
  898. {$IFDEF HAS_NATIVEINT}
  899. C2 := CombineReg(PColor32(NativeUInt(SrcP) - 4)^, SrcP[0], FracX xor $FF)
  900. {$ELSE}
  901. C2 := CombineReg(PColor32(Integer(SrcP) - 4)^, SrcP[0], FracX xor $FF)
  902. {$ENDIF}
  903. else
  904. C2 := SrcP[0];
  905. BlendMemEx(CombineReg(C1, C2, FracY), DstP^, LW * MA shr 8);
  906. Inc(DstP);
  907. C1 := C2;
  908. // Vertical translation
  909. CombineLine(@Buf2[0], @Buf1[0], SrcRectW, FracY xor $FF);
  910. // Blend horizontal line to Dst
  911. BlendLineEx(@Buf1[0], DstP, SrcRectW - 1, MA);
  912. Inc(DstP, SrcRectW - 1);
  913. if SrcRect.Right < SrcW then
  914. C4 := CombineReg(SrcP[SrcRectW - 1], SrcP[SrcRectW], FracX)
  915. else
  916. C4 := SrcP[SrcRectW - 1];
  917. BlendMemEx(CombineReg(C3, C4, FracY), DstP^, RW * MA shr 8);
  918. Inc(DstP, DstW - SrcRectW);
  919. C3 := C4;
  920. Index := Index xor 1;
  921. end;
  922. Buf1 := @Buffer[Index][0];
  923. Buf2 := @Buffer[Index xor 1][0];
  924. Inc(PColor32(SrcP), SrcW);
  925. if SrcRect.Bottom < Src.Height then
  926. begin
  927. MoveLongWord(SrcP[0], Buf2^, SrcRectW);
  928. CombineLine(@Buf2[1], @Buf2[0], SrcRectW, FracY xor $FF);
  929. CombineLine(@Buf2[0], @Buf1[0], SrcRectW, FracY xor $FF);
  930. if SrcRect.Left > 0 then
  931. {$IFDEF HAS_NATIVEINT}
  932. C2 := CombineReg(PColor32(NativeUInt(SrcP) - 4)^, SrcP[0], FracX xor $FF)
  933. {$ELSE}
  934. C2 := CombineReg(PColor32(Integer(SrcP) - 4)^, SrcP[0], FracX xor $FF)
  935. {$ENDIF}
  936. else
  937. C2 := SrcP[0];
  938. BlendMemEx(CombineReg(C1, C2, FracY), DstP^, LW * BW * MA shr 16)
  939. end
  940. else
  941. BlendMemEx(C1, DstP^, LW * BW * MA shr 16);
  942. Inc(DstP);
  943. BlendLineEx(@Buf1[0], DstP, SrcRectW - 1, BW * MA shr 8);
  944. Inc(DstP, SrcRectW - 1);
  945. if SrcRect.Bottom < Src.Height then
  946. begin
  947. if SrcRect.Right < SrcW then
  948. C4 := CombineReg(SrcP[SrcRectW - 1], SrcP[SrcRectW], FracX)
  949. else
  950. C4 := SrcP[SrcRectW - 1];
  951. BlendMemEx(CombineReg(C3, C4, FracY), DstP^, RW * BW * MA shr 16);
  952. end
  953. else
  954. BlendMemEx(C3, DstP^, RW * BW * MA shr 16);
  955. finally
  956. EMMS;
  957. Buffer[0] := nil;
  958. Buffer[1] := nil;
  959. end;
  960. end;
  961. Dst.Changed(MakeRect(DstX, DstY, DstX + SrcRectW + 1, DstY + SrcRectH + 1));
  962. end;
  963. {$WARNINGS ON}
  964. procedure BlendTransfer(
  965. Dst: TCustomBitmap32; DstX, DstY: Integer; DstClip: TRect;
  966. SrcF: TCustomBitmap32; SrcRectF: TRect;
  967. SrcB: TCustomBitmap32; SrcRectB: TRect;
  968. BlendCallback: TBlendReg);
  969. var
  970. I, J, SrcFX, SrcFY, SrcBX, SrcBY: Integer;
  971. PSrcF, PSrcB, PDst: PColor32Array;
  972. begin
  973. if not Assigned(Dst) then raise EBitmapException.Create(SDstNil);
  974. if not Assigned(SrcF) then raise EBitmapException.Create(SSrcNil);
  975. if not Assigned(SrcB) then raise EBitmapException.Create(SSrcNil);
  976. if Dst.Empty or SrcF.Empty or SrcB.Empty or not Assigned(BlendCallback) then Exit;
  977. if not Dst.MeasuringMode then
  978. begin
  979. SrcFX := SrcRectF.Left - DstX;
  980. SrcFY := SrcRectF.Top - DstY;
  981. SrcBX := SrcRectB.Left - DstX;
  982. SrcBY := SrcRectB.Top - DstY;
  983. GR32.IntersectRect(DstClip, DstClip, Dst.BoundsRect);
  984. GR32.IntersectRect(SrcRectF, SrcRectF, SrcF.BoundsRect);
  985. GR32.IntersectRect(SrcRectB, SrcRectB, SrcB.BoundsRect);
  986. GR32.OffsetRect(SrcRectF, -SrcFX, -SrcFY);
  987. GR32.OffsetRect(SrcRectB, -SrcBX, -SrcFY);
  988. GR32.IntersectRect(DstClip, DstClip, SrcRectF);
  989. GR32.IntersectRect(DstClip, DstClip, SrcRectB);
  990. if not GR32.IsRectEmpty(DstClip) then
  991. try
  992. for I := DstClip.Top to DstClip.Bottom - 1 do
  993. begin
  994. PSrcF := PColor32Array(SrcF.PixelPtr[SrcFX, SrcFY + I]);
  995. PSrcB := PColor32Array(SrcB.PixelPtr[SrcBX, SrcBY + I]);
  996. PDst := Dst.ScanLine[I];
  997. for J := DstClip.Left to DstClip.Right - 1 do
  998. PDst[J] := BlendCallback(PSrcF[J], PSrcB[J]);
  999. end;
  1000. finally
  1001. EMMS;
  1002. end;
  1003. end;
  1004. Dst.Changed(DstClip);
  1005. end;
  1006. procedure BlendTransfer(
  1007. Dst: TCustomBitmap32; DstX, DstY: Integer; DstClip: TRect;
  1008. SrcF: TCustomBitmap32; SrcRectF: TRect;
  1009. SrcB: TCustomBitmap32; SrcRectB: TRect;
  1010. BlendCallback: TBlendRegEx; MasterAlpha: Integer);
  1011. var
  1012. I, J, SrcFX, SrcFY, SrcBX, SrcBY: Integer;
  1013. PSrcF, PSrcB, PDst: PColor32Array;
  1014. begin
  1015. if not Assigned(Dst) then raise EBitmapException.Create(SDstNil);
  1016. if not Assigned(SrcF) then raise EBitmapException.Create(SSrcNil);
  1017. if not Assigned(SrcB) then raise EBitmapException.Create(SSrcNil);
  1018. if Dst.Empty or SrcF.Empty or SrcB.Empty or not Assigned(BlendCallback) then Exit;
  1019. if not Dst.MeasuringMode then
  1020. begin
  1021. SrcFX := SrcRectF.Left - DstX;
  1022. SrcFY := SrcRectF.Top - DstY;
  1023. SrcBX := SrcRectB.Left - DstX;
  1024. SrcBY := SrcRectB.Top - DstY;
  1025. GR32.IntersectRect(DstClip, DstClip, Dst.BoundsRect);
  1026. GR32.IntersectRect(SrcRectF, SrcRectF, SrcF.BoundsRect);
  1027. GR32.IntersectRect(SrcRectB, SrcRectB, SrcB.BoundsRect);
  1028. GR32.OffsetRect(SrcRectF, -SrcFX, -SrcFY);
  1029. GR32.OffsetRect(SrcRectB, -SrcBX, -SrcFY);
  1030. GR32.IntersectRect(DstClip, DstClip, SrcRectF);
  1031. GR32.IntersectRect(DstClip, DstClip, SrcRectB);
  1032. if not GR32.IsRectEmpty(DstClip) then
  1033. try
  1034. for I := DstClip.Top to DstClip.Bottom - 1 do
  1035. begin
  1036. PSrcF := PColor32Array(SrcF.PixelPtr[SrcFX, SrcFY + I]);
  1037. PSrcB := PColor32Array(SrcB.PixelPtr[SrcBX, SrcBY + I]);
  1038. PDst := Dst.ScanLine[I];
  1039. for J := DstClip.Left to DstClip.Right - 1 do
  1040. PDst[J] := BlendCallback(PSrcF[J], PSrcB[J], MasterAlpha);
  1041. end;
  1042. finally
  1043. EMMS;
  1044. end;
  1045. end;
  1046. Dst.Changed(DstClip);
  1047. end;
  1048. procedure StretchNearest(
  1049. Dst: TCustomBitmap32; DstRect, DstClip: TRect;
  1050. Src: TCustomBitmap32; SrcRect: TRect;
  1051. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
  1052. var
  1053. R: TRect;
  1054. SrcW, SrcH, DstW, DstH, DstClipW, DstClipH: Integer;
  1055. SrcY, OldSrcY: Integer;
  1056. I, J: Integer;
  1057. MapHorz: PIntegerArray;
  1058. SrcLine, DstLine: PColor32Array;
  1059. Buffer: TArrayOfColor32;
  1060. Scale: TFloat;
  1061. BlendLine: TBlendLine;
  1062. BlendLineEx: TBlendLineEx;
  1063. DstLinePtr, MapPtr: PColor32;
  1064. begin
  1065. GR32.IntersectRect(DstClip, DstClip, MakeRect(0, 0, Dst.Width, Dst.Height));
  1066. GR32.IntersectRect(DstClip, DstClip, DstRect);
  1067. if GR32.IsRectEmpty(DstClip) then Exit;
  1068. GR32.IntersectRect(R, DstClip, DstRect);
  1069. if GR32.IsRectEmpty(R) then Exit;
  1070. if (SrcRect.Left < 0) or (SrcRect.Top < 0) or (SrcRect.Right > Src.Width) or
  1071. (SrcRect.Bottom > Src.Height) then
  1072. raise Exception.Create(RCStrInvalidSrcRect);
  1073. SrcW := SrcRect.Right - SrcRect.Left;
  1074. SrcH := SrcRect.Bottom - SrcRect.Top;
  1075. DstW := DstRect.Right - DstRect.Left;
  1076. DstH := DstRect.Bottom - DstRect.Top;
  1077. DstClipW := DstClip.Right - DstClip.Left;
  1078. DstClipH := DstClip.Bottom - DstClip.Top;
  1079. try
  1080. if (SrcW = DstW) and (SrcH = DstH) then
  1081. begin
  1082. { Copy without resampling }
  1083. BlendBlock(Dst, DstClip, Src, SrcRect.Left + DstClip.Left - DstRect.Left,
  1084. SrcRect.Top + DstClip.Top - DstRect.Top, CombineOp, CombineCallBack);
  1085. end
  1086. else
  1087. begin
  1088. GetMem(MapHorz, DstClipW * SizeOf(Integer));
  1089. try
  1090. if DstW > 1 then
  1091. begin
  1092. if FullEdge then
  1093. begin
  1094. Scale := SrcW / DstW;
  1095. for I := 0 to DstClipW - 1 do
  1096. MapHorz^[I] := Trunc(SrcRect.Left + (I + DstClip.Left - DstRect.Left) * Scale);
  1097. end
  1098. else
  1099. begin
  1100. Scale := (SrcW - 1) / (DstW - 1);
  1101. for I := 0 to DstClipW - 1 do
  1102. MapHorz^[I] := Round(SrcRect.Left + (I + DstClip.Left - DstRect.Left) * Scale);
  1103. end;
  1104. Assert(MapHorz^[0] >= SrcRect.Left);
  1105. Assert(MapHorz^[DstClipW - 1] < SrcRect.Right);
  1106. end
  1107. else
  1108. MapHorz^[0] := (SrcRect.Left + SrcRect.Right - 1) div 2;
  1109. if DstH <= 1 then Scale := 0
  1110. else if FullEdge then Scale := SrcH / DstH
  1111. else Scale := (SrcH - 1) / (DstH - 1);
  1112. if CombineOp = dmOpaque then
  1113. begin
  1114. DstLine := PColor32Array(Dst.PixelPtr[DstClip.Left, DstClip.Top]);
  1115. OldSrcY := -1;
  1116. for J := 0 to DstClipH - 1 do
  1117. begin
  1118. if DstH <= 1 then
  1119. SrcY := (SrcRect.Top + SrcRect.Bottom - 1) div 2
  1120. else if FullEdge then
  1121. SrcY := Trunc(SrcRect.Top + (J + DstClip.Top - DstRect.Top) * Scale)
  1122. else
  1123. SrcY := Round(SrcRect.Top + (J + DstClip.Top - DstRect.Top) * Scale);
  1124. if SrcY <> OldSrcY then
  1125. begin
  1126. SrcLine := Src.ScanLine[SrcY];
  1127. DstLinePtr := @DstLine[0];
  1128. MapPtr := @MapHorz^[0];
  1129. for I := 0 to DstClipW - 1 do
  1130. begin
  1131. DstLinePtr^ := SrcLine[MapPtr^];
  1132. Inc(DstLinePtr);
  1133. Inc(MapPtr);
  1134. end;
  1135. OldSrcY := SrcY;
  1136. end
  1137. else
  1138. MoveLongWord(DstLine[-Dst.Width], DstLine[0], DstClipW);
  1139. Inc(DstLine, Dst.Width);
  1140. end;
  1141. end
  1142. else
  1143. begin
  1144. SetLength(Buffer, DstClipW);
  1145. DstLine := PColor32Array(Dst.PixelPtr[DstClip.Left, DstClip.Top]);
  1146. OldSrcY := -1;
  1147. if Src.MasterAlpha >= 255 then
  1148. begin
  1149. BlendLine := BLEND_LINE[Src.CombineMode]^;
  1150. BlendLineEx := nil; // stop compiler warnings...
  1151. end
  1152. else
  1153. begin
  1154. BlendLineEx := BLEND_LINE_EX[Src.CombineMode]^;
  1155. BlendLine := nil; // stop compiler warnings...
  1156. end;
  1157. for J := 0 to DstClipH - 1 do
  1158. begin
  1159. if DstH > 1 then
  1160. begin
  1161. EMMS;
  1162. if FullEdge then
  1163. SrcY := Trunc(SrcRect.Top + (J + DstClip.Top - DstRect.Top) * Scale)
  1164. else
  1165. SrcY := Round(SrcRect.Top + (J + DstClip.Top - DstRect.Top) * Scale);
  1166. end
  1167. else
  1168. SrcY := (SrcRect.Top + SrcRect.Bottom - 1) div 2;
  1169. if SrcY <> OldSrcY then
  1170. begin
  1171. SrcLine := Src.ScanLine[SrcY];
  1172. DstLinePtr := @Buffer[0];
  1173. MapPtr := @MapHorz^[0];
  1174. for I := 0 to DstClipW - 1 do
  1175. begin
  1176. DstLinePtr^ := SrcLine[MapPtr^];
  1177. Inc(DstLinePtr);
  1178. Inc(MapPtr);
  1179. end;
  1180. OldSrcY := SrcY;
  1181. end;
  1182. case CombineOp of
  1183. dmBlend:
  1184. if Src.MasterAlpha >= 255 then
  1185. BlendLine(@Buffer[0], @DstLine[0], DstClipW)
  1186. else
  1187. BlendLineEx(@Buffer[0], @DstLine[0], DstClipW, Src.MasterAlpha);
  1188. dmTransparent:
  1189. for I := 0 to DstClipW - 1 do
  1190. if Buffer[I] <> Src.OuterColor then DstLine[I] := Buffer[I];
  1191. dmCustom:
  1192. for I := 0 to DstClipW - 1 do
  1193. CombineCallBack(Buffer[I], DstLine[I], Src.MasterAlpha);
  1194. end;
  1195. Inc(DstLine, Dst.Width);
  1196. end;
  1197. end;
  1198. finally
  1199. FreeMem(MapHorz);
  1200. end;
  1201. end;
  1202. finally
  1203. EMMS;
  1204. end;
  1205. end;
  1206. procedure StretchHorzStretchVertLinear(
  1207. Dst: TCustomBitmap32; DstRect, DstClip: TRect;
  1208. Src: TCustomBitmap32; SrcRect: TRect;
  1209. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
  1210. //Assure DstRect is >= SrcRect, otherwise quality loss will occur
  1211. var
  1212. SrcW, SrcH, DstW, DstH, DstClipW, DstClipH: Integer;
  1213. MapHorz, MapVert: array of TPointRec;
  1214. t2, Scale: TFloat;
  1215. SrcLine, DstLine: PColor32Array;
  1216. SrcIndex: Integer;
  1217. SrcPtr1, SrcPtr2: PColor32;
  1218. I, J: Integer;
  1219. WY: Cardinal;
  1220. C: TColor32;
  1221. BlendMemEx: TBlendMemEx;
  1222. begin
  1223. SrcW := SrcRect.Right - SrcRect.Left;
  1224. SrcH := SrcRect.Bottom - SrcRect.Top;
  1225. DstW := DstRect.Right - DstRect.Left;
  1226. DstH := DstRect.Bottom - DstRect.Top;
  1227. DstClipW := DstClip.Right - DstClip.Left;
  1228. DstClipH := DstClip.Bottom - DstClip.Top;
  1229. SetLength(MapHorz, DstClipW);
  1230. if FullEdge then Scale := SrcW / DstW
  1231. else Scale := (SrcW - 1) / (DstW - 1);
  1232. for I := 0 to DstClipW - 1 do
  1233. begin
  1234. if FullEdge then t2 := SrcRect.Left - 0.5 + (I + DstClip.Left - DstRect.Left + 0.5) * Scale
  1235. else t2 := SrcRect.Left + (I + DstClip.Left - DstRect.Left) * Scale;
  1236. if t2 < 0 then t2 := 0
  1237. else if t2 > Src.Width - 1 then t2 := Src.Width - 1;
  1238. MapHorz[I].Pos := Floor(t2);
  1239. MapHorz[I].Weight := 256 - Round(Frac(t2) * 256);
  1240. //Pre-pack weights to reduce MMX Reg. setups per pixel:
  1241. //MapHorz[I].Weight:= MapHorz[I].Weight shl 16 + MapHorz[I].Weight;
  1242. end;
  1243. I := DstClipW - 1;
  1244. while MapHorz[I].Pos = SrcRect.Right - 1 do
  1245. begin
  1246. Dec(MapHorz[I].Pos);
  1247. MapHorz[I].Weight := 0;
  1248. Dec(I);
  1249. end;
  1250. SetLength(MapVert, DstClipH);
  1251. if FullEdge then Scale := SrcH / DstH
  1252. else Scale := (SrcH - 1) / (DstH - 1);
  1253. for I := 0 to DstClipH - 1 do
  1254. begin
  1255. if FullEdge then t2 := SrcRect.Top - 0.5 + (I + DstClip.Top - DstRect.Top + 0.5) * Scale
  1256. else t2 := SrcRect.Top + (I + DstClip.Top - DstRect.Top) * Scale;
  1257. if t2 < 0 then t2 := 0
  1258. else if t2 > Src.Height - 1 then t2 := Src.Height - 1;
  1259. MapVert[I].Pos := Floor(t2);
  1260. MapVert[I].Weight := 256 - Round(Frac(t2) * 256);
  1261. //Pre-pack weights to reduce MMX Reg. setups per pixel:
  1262. //MapVert[I].Weight := MapVert[I].Weight shl 16 + MapVert[I].Weight;
  1263. end;
  1264. I := DstClipH - 1;
  1265. while MapVert[I].Pos = SrcRect.Bottom - 1 do
  1266. begin
  1267. Dec(MapVert[I].Pos);
  1268. MapVert[I].Weight := 0;
  1269. Dec(I);
  1270. end;
  1271. DstLine := PColor32Array(Dst.PixelPtr[DstClip.Left, DstClip.Top]);
  1272. SrcW := Src.Width;
  1273. DstW := Dst.Width;
  1274. case CombineOp of
  1275. dmOpaque:
  1276. for J := 0 to DstClipH - 1 do
  1277. begin
  1278. SrcLine := Src.ScanLine[MapVert[J].Pos];
  1279. WY := MapVert[J].Weight;
  1280. SrcIndex := MapHorz[0].Pos;
  1281. SrcPtr1 := @SrcLine[SrcIndex];
  1282. SrcPtr2 := @SrcLine[SrcIndex + SrcW];
  1283. for I := 0 to DstClipW - 1 do
  1284. begin
  1285. if SrcIndex <> MapHorz[I].Pos then
  1286. begin
  1287. SrcIndex := MapHorz[I].Pos;
  1288. SrcPtr1 := @SrcLine[SrcIndex];
  1289. SrcPtr2 := @SrcLine[SrcIndex + SrcW];
  1290. end;
  1291. DstLine[I] := Interpolator(MapHorz[I].Weight, WY, SrcPtr1, SrcPtr2);
  1292. end;
  1293. Inc(DstLine, DstW);
  1294. end;
  1295. dmBlend:
  1296. begin
  1297. BlendMemEx := BLEND_MEM_EX[Src.CombineMode]^;
  1298. for J := 0 to DstClipH - 1 do
  1299. begin
  1300. SrcLine := Src.ScanLine[MapVert[J].Pos];
  1301. WY := MapVert[J].Weight;
  1302. SrcIndex := MapHorz[0].Pos;
  1303. SrcPtr1 := @SrcLine[SrcIndex];
  1304. SrcPtr2 := @SrcLine[SrcIndex + SrcW];
  1305. for I := 0 to DstClipW - 1 do
  1306. begin
  1307. if SrcIndex <> MapHorz[I].Pos then
  1308. begin
  1309. SrcIndex := MapHorz[I].Pos;
  1310. SrcPtr1 := @SrcLine[SrcIndex];
  1311. SrcPtr2 := @SrcLine[SrcIndex + SrcW];
  1312. end;
  1313. C := Interpolator(MapHorz[I].Weight, WY, SrcPtr1, SrcPtr2);
  1314. BlendMemEx(C, DstLine[I], Src.MasterAlpha)
  1315. end;
  1316. Inc(DstLine, Dst.Width);
  1317. end
  1318. end;
  1319. dmTransparent:
  1320. begin
  1321. for J := 0 to DstClipH - 1 do
  1322. begin
  1323. SrcLine := Src.ScanLine[MapVert[J].Pos];
  1324. WY := MapVert[J].Weight;
  1325. SrcIndex := MapHorz[0].Pos;
  1326. SrcPtr1 := @SrcLine[SrcIndex];
  1327. SrcPtr2 := @SrcLine[SrcIndex + SrcW];
  1328. for I := 0 to DstClipW - 1 do
  1329. begin
  1330. if SrcIndex <> MapHorz[I].Pos then
  1331. begin
  1332. SrcIndex := MapHorz[I].Pos;
  1333. SrcPtr1 := @SrcLine[SrcIndex];
  1334. SrcPtr2 := @SrcLine[SrcIndex + SrcW];
  1335. end;
  1336. C := Interpolator(MapHorz[I].Weight, WY, SrcPtr1, SrcPtr2);
  1337. if C <> Src.OuterColor then DstLine[I] := C;
  1338. end;
  1339. Inc(DstLine, Dst.Width);
  1340. end
  1341. end;
  1342. else // cmCustom
  1343. for J := 0 to DstClipH - 1 do
  1344. begin
  1345. SrcLine := Src.ScanLine[MapVert[J].Pos];
  1346. WY := MapVert[J].Weight;
  1347. SrcIndex := MapHorz[0].Pos;
  1348. SrcPtr1 := @SrcLine[SrcIndex];
  1349. SrcPtr2 := @SrcLine[SrcIndex + SrcW];
  1350. for I := 0 to DstClipW - 1 do
  1351. begin
  1352. if SrcIndex <> MapHorz[I].Pos then
  1353. begin
  1354. SrcIndex := MapHorz[I].Pos;
  1355. SrcPtr1 := @SrcLine[SrcIndex];
  1356. SrcPtr2 := @SrcLine[SrcIndex + SrcW];
  1357. end;
  1358. C := Interpolator(MapHorz[I].Weight, WY, SrcPtr1, SrcPtr2);
  1359. CombineCallBack(C, DstLine[I], Src.MasterAlpha);
  1360. end;
  1361. Inc(DstLine, Dst.Width);
  1362. end;
  1363. end;
  1364. EMMS;
  1365. end;
  1366. function BuildMappingTable(
  1367. DstLo, DstHi: Integer;
  1368. ClipLo, ClipHi: Integer;
  1369. SrcLo, SrcHi: Integer;
  1370. Kernel: TCustomKernel): TMappingTable;
  1371. var
  1372. SrcW, DstW, ClipW: Integer;
  1373. Filter: TFilterMethod;
  1374. FilterWidth: TFloat;
  1375. Scale, OldScale: TFloat;
  1376. Center: TFloat;
  1377. Count: Integer;
  1378. Left, Right: Integer;
  1379. I, J, K: Integer;
  1380. Weight: Integer;
  1381. begin
  1382. SrcW := SrcHi - SrcLo;
  1383. DstW := DstHi - DstLo;
  1384. ClipW := ClipHi - ClipLo;
  1385. if SrcW = 0 then
  1386. begin
  1387. Result := nil;
  1388. Exit;
  1389. end
  1390. else if SrcW = 1 then
  1391. begin
  1392. SetLength(Result, ClipW);
  1393. for I := 0 to ClipW - 1 do
  1394. begin
  1395. SetLength(Result[I], 1);
  1396. Result[I][0].Pos := SrcLo;
  1397. Result[I][0].Weight := 256;
  1398. end;
  1399. Exit;
  1400. end;
  1401. SetLength(Result, ClipW);
  1402. if ClipW = 0 then Exit;
  1403. if FullEdge then Scale := DstW / SrcW
  1404. else Scale := (DstW - 1) / (SrcW - 1);
  1405. Filter := Kernel.Filter;
  1406. FilterWidth := Kernel.GetWidth;
  1407. K := 0;
  1408. if Scale = 0 then
  1409. begin
  1410. Assert(Length(Result) = 1);
  1411. SetLength(Result[0], 1);
  1412. Result[0][0].Pos := (SrcLo + SrcHi) div 2;
  1413. Result[0][0].Weight := 256;
  1414. end
  1415. else if Scale < 1 then
  1416. begin
  1417. OldScale := Scale;
  1418. Scale := 1 / Scale;
  1419. FilterWidth := FilterWidth * Scale;
  1420. for I := 0 to ClipW - 1 do
  1421. begin
  1422. if FullEdge then
  1423. Center := SrcLo - 0.5 + (I - DstLo + ClipLo + 0.5) * Scale
  1424. else
  1425. Center := SrcLo + (I - DstLo + ClipLo) * Scale;
  1426. Left := Floor(Center - FilterWidth);
  1427. Right := Ceil(Center + FilterWidth);
  1428. Count := -256;
  1429. for J := Left to Right do
  1430. begin
  1431. Weight := Round(256 * Filter((Center - J) * OldScale) * OldScale);
  1432. if Weight <> 0 then
  1433. begin
  1434. Inc(Count, Weight);
  1435. K := Length(Result[I]);
  1436. SetLength(Result[I], K + 1);
  1437. Result[I][K].Pos := Constrain(J, SrcLo, SrcHi - 1);
  1438. Result[I][K].Weight := Weight;
  1439. end;
  1440. end;
  1441. if Length(Result[I]) = 0 then
  1442. begin
  1443. SetLength(Result[I], 1);
  1444. Result[I][0].Pos := Floor(Center);
  1445. Result[I][0].Weight := 256;
  1446. end
  1447. else if Count <> 0 then
  1448. Dec(Result[I][K div 2].Weight, Count);
  1449. end;
  1450. end
  1451. else // scale > 1
  1452. begin
  1453. Scale := 1 / Scale;
  1454. for I := 0 to ClipW - 1 do
  1455. begin
  1456. if FullEdge then
  1457. Center := SrcLo - 0.5 + (I - DstLo + ClipLo + 0.5) * Scale
  1458. else
  1459. Center := SrcLo + (I - DstLo + ClipLo) * Scale;
  1460. Left := Floor(Center - FilterWidth);
  1461. Right := Ceil(Center + FilterWidth);
  1462. Count := -256;
  1463. for J := Left to Right do
  1464. begin
  1465. Weight := Round(256 * Filter(Center - j));
  1466. if Weight <> 0 then
  1467. begin
  1468. Inc(Count, Weight);
  1469. K := Length(Result[I]);
  1470. SetLength(Result[I], k + 1);
  1471. Result[I][K].Pos := Constrain(j, SrcLo, SrcHi - 1);
  1472. Result[I][K].Weight := Weight;
  1473. end;
  1474. end;
  1475. if Count <> 0 then
  1476. Dec(Result[I][K div 2].Weight, Count);
  1477. end;
  1478. end;
  1479. end;
  1480. {$WARNINGS OFF}
  1481. procedure Resample(
  1482. Dst: TCustomBitmap32; DstRect: TRect; DstClip: TRect;
  1483. Src: TCustomBitmap32; SrcRect: TRect;
  1484. Kernel: TCustomKernel;
  1485. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
  1486. var
  1487. DstClipW: Integer;
  1488. MapX, MapY: TMappingTable;
  1489. I, J, X, Y: Integer;
  1490. MapXLoPos, MapXHiPos: Integer;
  1491. HorzBuffer: array of TBufferEntry;
  1492. ClusterX, ClusterY: TCluster;
  1493. Wt, Cr, Cg, Cb, Ca: Integer;
  1494. C: Cardinal;
  1495. ClustYW: Integer;
  1496. DstLine: PColor32Array;
  1497. RangeCheck: Boolean;
  1498. BlendMemEx: TBlendMemEx;
  1499. begin
  1500. if (CombineOp = dmCustom) and not Assigned(CombineCallBack) then
  1501. CombineOp := dmOpaque;
  1502. { check source and destination }
  1503. if (CombineOp = dmBlend) and (Src.MasterAlpha = 0) then Exit;
  1504. BlendMemEx := BLEND_MEM_EX[Src.CombineMode]^; // store in local variable
  1505. DstClipW := DstClip.Right - DstClip.Left;
  1506. // mapping tables
  1507. MapX := BuildMappingTable(DstRect.Left, DstRect.Right, DstClip.Left, DstClip.Right, SrcRect.Left, SrcRect.Right, Kernel);
  1508. MapY := BuildMappingTable(DstRect.Top, DstRect.Bottom, DstClip.Top, DstClip.Bottom, SrcRect.Top, SrcRect.Bottom, Kernel);
  1509. ClusterX := nil;
  1510. ClusterY := nil;
  1511. try
  1512. RangeCheck := Kernel.RangeCheck; //StretchFilter in [sfLanczos, sfMitchell];
  1513. if (MapX = nil) or (MapY = nil) then Exit;
  1514. MapXLoPos := MapX[0][0].Pos;
  1515. MapXHiPos := MapX[DstClipW - 1][High(MapX[DstClipW - 1])].Pos;
  1516. SetLength(HorzBuffer, MapXHiPos - MapXLoPos + 1);
  1517. { transfer pixels }
  1518. for J := DstClip.Top to DstClip.Bottom - 1 do
  1519. begin
  1520. ClusterY := MapY[J - DstClip.Top];
  1521. for X := MapXLoPos to MapXHiPos do
  1522. begin
  1523. Ca := 0; Cr := 0; Cg := 0; Cb := 0;
  1524. for Y := 0 to Length(ClusterY) - 1 do
  1525. begin
  1526. C := Src.Bits[X + ClusterY[Y].Pos * Src.Width];
  1527. ClustYW := ClusterY[Y].Weight;
  1528. Inc(Ca, Integer(C shr 24) * ClustYW);
  1529. Inc(Cr, Integer(C and $00FF0000) shr 16 * ClustYW);
  1530. Inc(Cg, Integer(C and $0000FF00) shr 8 * ClustYW);
  1531. Inc(Cb, Integer(C and $000000FF) * ClustYW);
  1532. end;
  1533. with HorzBuffer[X - MapXLoPos] do
  1534. begin
  1535. R := Cr;
  1536. G := Cg;
  1537. B := Cb;
  1538. A := Ca;
  1539. end;
  1540. end;
  1541. DstLine := Dst.ScanLine[J];
  1542. for I := DstClip.Left to DstClip.Right - 1 do
  1543. begin
  1544. ClusterX := MapX[I - DstClip.Left];
  1545. Ca := 0; Cr := 0; Cg := 0; Cb := 0;
  1546. for X := 0 to Length(ClusterX) - 1 do
  1547. begin
  1548. Wt := ClusterX[X].Weight;
  1549. with HorzBuffer[ClusterX[X].Pos - MapXLoPos] do
  1550. begin
  1551. Inc(Ca, A * Wt);
  1552. Inc(Cr, R * Wt);
  1553. Inc(Cg, G * Wt);
  1554. Inc(Cb, B * Wt);
  1555. end;
  1556. end;
  1557. if RangeCheck then
  1558. begin
  1559. if Ca > $FF0000 then Ca := $FF0000
  1560. else if Ca < 0 then Ca := 0
  1561. else Ca := Ca and $00FF0000;
  1562. if Cr > $FF0000 then Cr := $FF0000
  1563. else if Cr < 0 then Cr := 0
  1564. else Cr := Cr and $00FF0000;
  1565. if Cg > $FF0000 then Cg := $FF0000
  1566. else if Cg < 0 then Cg := 0
  1567. else Cg := Cg and $00FF0000;
  1568. if Cb > $FF0000 then Cb := $FF0000
  1569. else if Cb < 0 then Cb := 0
  1570. else Cb := Cb and $00FF0000;
  1571. C := (Ca shl 8) or Cr or (Cg shr 8) or (Cb shr 16);
  1572. end
  1573. else
  1574. C := ((Ca and $00FF0000) shl 8) or (Cr and $00FF0000) or ((Cg and $00FF0000) shr 8) or ((Cb and $00FF0000) shr 16);
  1575. // combine it with the background
  1576. case CombineOp of
  1577. dmOpaque: DstLine[I] := C;
  1578. dmBlend: BlendMemEx(C, DstLine[I], Src.MasterAlpha);
  1579. dmTransparent: if C <> Src.OuterColor then DstLine[I] := C;
  1580. dmCustom: CombineCallBack(C, DstLine[I], Src.MasterAlpha);
  1581. end;
  1582. end;
  1583. end;
  1584. finally
  1585. EMMS;
  1586. MapX := nil;
  1587. MapY := nil;
  1588. end;
  1589. end;
  1590. {$WARNINGS ON}
  1591. { Draft Resample Routines }
  1592. function BlockAverage_Pas(Dlx, Dly: Cardinal; RowSrc: PColor32; OffSrc: Cardinal): TColor32;
  1593. var
  1594. C: PColor32Entry;
  1595. ix, iy, iA, iR, iG, iB, Area: Cardinal;
  1596. begin
  1597. iR := 0; iB := iR; iG := iR; iA := iR;
  1598. for iy := 1 to Dly do
  1599. begin
  1600. C := PColor32Entry(RowSrc);
  1601. for ix := 1 to Dlx do
  1602. begin
  1603. Inc(iB, C.B);
  1604. Inc(iG, C.G);
  1605. Inc(iR, C.R);
  1606. Inc(iA, C.A);
  1607. Inc(C);
  1608. end;
  1609. {$IFDEF HAS_NATIVEINT}
  1610. Inc(NativeUInt(RowSrc), OffSrc);
  1611. {$ELSE}
  1612. Inc(PByte(RowSrc), OffSrc);
  1613. {$ENDIF}
  1614. end;
  1615. Area := Dlx * Dly;
  1616. Area := $1000000 div Area;
  1617. Result := iA * Area and $FF000000 or
  1618. iR * Area shr 8 and $FF0000 or
  1619. iG * Area shr 16 and $FF00 or
  1620. iB * Area shr 24 and $FF;
  1621. end;
  1622. {$IFNDEF PUREPASCAL}
  1623. function BlockAverage_MMX(Dlx, Dly: Cardinal; RowSrc: PColor32; OffSrc: Cardinal): TColor32;
  1624. asm
  1625. {$IFDEF TARGET_X64}
  1626. MOV R10D,ECX
  1627. MOV R11D,EDX
  1628. SHL R10,$02
  1629. SUB R9,R10
  1630. PXOR MM1,MM1
  1631. PXOR MM2,MM2
  1632. PXOR MM7,MM7
  1633. @@LoopY:
  1634. MOV R10,RCX
  1635. PXOR MM0,MM0
  1636. LEA R8,[R8+R10*4]
  1637. NEG R10
  1638. @@LoopX:
  1639. MOVD MM6,[R8+R10*4]
  1640. PUNPCKLBW MM6,MM7
  1641. PADDW MM0,MM6
  1642. INC R10
  1643. JNZ @@LoopX
  1644. MOVQ MM6,MM0
  1645. PUNPCKLWD MM6,MM7
  1646. PADDD MM1,MM6
  1647. MOVQ MM6,MM0
  1648. PUNPCKHWD MM6,MM7
  1649. PADDD MM2,MM6
  1650. ADD R8,R9
  1651. DEC EDX
  1652. JNZ @@LoopY
  1653. MOV EAX, ECX
  1654. MUL R11D
  1655. MOV ECX,EAX
  1656. MOV EAX,$01000000
  1657. DIV ECX
  1658. MOV ECX,EAX
  1659. MOVD EAX,MM1
  1660. MUL ECX
  1661. SHR EAX,$18
  1662. MOV R11D,EAX
  1663. PSRLQ MM1,$20
  1664. MOVD EAX,MM1
  1665. MUL ECX
  1666. SHR EAX,$10
  1667. AND EAX,$0000FF00
  1668. ADD R11D,EAX
  1669. MOVD EAX,MM2
  1670. MUL ECX
  1671. SHR EAX,$08
  1672. AND EAX,$00FF0000
  1673. ADD R11D,EAX
  1674. PSRLQ MM2,$20
  1675. MOVD EAX,MM2
  1676. MUL ECX
  1677. AND EAX,$FF000000
  1678. ADD EAX,R11D
  1679. {$ELSE}
  1680. PUSH EBX
  1681. PUSH ESI
  1682. PUSH EDI
  1683. MOV EBX,OffSrc
  1684. MOV ESI,EAX
  1685. MOV EDI,EDX
  1686. SHL ESI,$02
  1687. SUB EBX,ESI
  1688. PXOR MM1,MM1
  1689. PXOR MM2,MM2
  1690. PXOR MM7,MM7
  1691. @@LoopY:
  1692. MOV ESI,EAX
  1693. PXOR MM0,MM0
  1694. LEA ECX,[ECX+ESI*4]
  1695. NEG ESI
  1696. @@LoopX:
  1697. MOVD MM6,[ECX+ESI*4]
  1698. PUNPCKLBW MM6,MM7
  1699. PADDW MM0,MM6
  1700. INC ESI
  1701. JNZ @@LoopX
  1702. MOVQ MM6,MM0
  1703. PUNPCKLWD MM6,MM7
  1704. PADDD MM1,MM6
  1705. MOVQ MM6,MM0
  1706. PUNPCKHWD MM6,MM7
  1707. PADDD MM2,MM6
  1708. ADD ECX,EBX
  1709. DEC EDX
  1710. JNZ @@LoopY
  1711. MUL EDI
  1712. MOV ECX,EAX
  1713. MOV EAX,$01000000
  1714. DIV ECX
  1715. MOV ECX,EAX
  1716. MOVD EAX,MM1
  1717. MUL ECX
  1718. SHR EAX,$18
  1719. MOV EDI,EAX
  1720. PSRLQ MM1,$20
  1721. MOVD EAX,MM1
  1722. MUL ECX
  1723. SHR EAX,$10
  1724. AND EAX,$0000FF00
  1725. ADD EDI,EAX
  1726. MOVD EAX,MM2
  1727. MUL ECX
  1728. SHR EAX,$08
  1729. AND EAX,$00FF0000
  1730. ADD EDI,EAX
  1731. PSRLQ MM2,$20
  1732. MOVD EAX,MM2
  1733. MUL ECX
  1734. AND EAX,$FF000000
  1735. ADD EAX,EDI
  1736. POP EDI
  1737. POP ESI
  1738. POP EBX
  1739. {$ENDIF}
  1740. end;
  1741. {$IFDEF USE_3DNOW}
  1742. function BlockAverage_3DNow(Dlx, Dly: Cardinal; RowSrc: PColor32; OffSrc: Cardinal): TColor32;
  1743. asm
  1744. PUSH EBX
  1745. PUSH ESI
  1746. PUSH EDI
  1747. MOV EBX,OffSrc
  1748. MOV ESI,EAX
  1749. MOV EDI,EDX
  1750. SHL ESI,$02
  1751. SUB EBX,ESI
  1752. PXOR MM1,MM1
  1753. PXOR MM2,MM2
  1754. PXOR MM7,MM7
  1755. @@LoopY:
  1756. MOV ESI,EAX
  1757. PXOR MM0,MM0
  1758. LEA ECX,[ECX+ESI*4]
  1759. NEG ESI
  1760. db $0F,$0D,$84,$B1,$00,$02,$00,$00 // PREFETCH [ECX + ESI * 4 + 512]
  1761. @@LoopX:
  1762. MOVD MM6,[ECX + ESI * 4]
  1763. PUNPCKLBW MM6,MM7
  1764. PADDW MM0,MM6
  1765. INC ESI
  1766. JNZ @@LoopX
  1767. MOVQ MM6,MM0
  1768. PUNPCKLWD MM6,MM7
  1769. PADDD MM1,MM6
  1770. MOVQ MM6,MM0
  1771. PUNPCKHWD MM6,MM7
  1772. PADDD MM2,MM6
  1773. ADD ECX,EBX
  1774. DEC EDX
  1775. JNZ @@LoopY
  1776. MUL EDI
  1777. MOV ECX,EAX
  1778. MOV EAX,$01000000
  1779. div ECX
  1780. MOV ECX,EAX
  1781. MOVD EAX,MM1
  1782. MUL ECX
  1783. SHR EAX,$18
  1784. MOV EDI,EAX
  1785. PSRLQ MM1,$20
  1786. MOVD EAX,MM1
  1787. MUL ECX
  1788. SHR EAX,$10
  1789. AND EAX,$0000FF00
  1790. ADD EDI,EAX
  1791. MOVD EAX,MM2
  1792. MUL ECX
  1793. SHR EAX,$08
  1794. AND EAX,$00FF0000
  1795. ADD EDI,EAX
  1796. PSRLQ MM2,$20
  1797. MOVD EAX,MM2
  1798. MUL ECX
  1799. AND EAX,$FF000000
  1800. ADD EAX,EDI
  1801. POP EDI
  1802. POP ESI
  1803. POP EBX
  1804. end;
  1805. {$ENDIF}
  1806. function BlockAverage_SSE2(Dlx, Dly: Cardinal; RowSrc: PColor32; OffSrc: Cardinal): TColor32;
  1807. asm
  1808. {$IFDEF TARGET_X64}
  1809. MOV EAX,ECX
  1810. MOV R10D,EDX
  1811. SHL EAX,$02
  1812. SUB R9D,EAX
  1813. PXOR XMM1,XMM1
  1814. PXOR XMM2,XMM2
  1815. PXOR XMM7,XMM7
  1816. @@LoopY:
  1817. MOV EAX,ECX
  1818. PXOR XMM0,XMM0
  1819. LEA R8,[R8+RAX*4]
  1820. NEG RAX
  1821. @@LoopX:
  1822. MOVD XMM6,[R8+RAX*4]
  1823. PUNPCKLBW XMM6,XMM7
  1824. PADDW XMM0,XMM6
  1825. INC RAX
  1826. JNZ @@LoopX
  1827. MOVQ XMM6,XMM0
  1828. PUNPCKLWD XMM6,XMM7
  1829. PADDD XMM1,XMM6
  1830. ADD R8,R9
  1831. DEC EDX
  1832. JNZ @@LoopY
  1833. MOV EAX, ECX
  1834. MUL R10D
  1835. MOV ECX,EAX
  1836. MOV EAX,$01000000
  1837. DIV ECX
  1838. MOV ECX,EAX
  1839. MOVD EAX,XMM1
  1840. MUL ECX
  1841. SHR EAX,$18
  1842. MOV R10D,EAX
  1843. SHUFPS XMM1,XMM1,$39
  1844. MOVD EAX,XMM1
  1845. MUL ECX
  1846. SHR EAX,$10
  1847. AND EAX,$0000FF00
  1848. ADD R10D,EAX
  1849. PSHUFD XMM1,XMM1,$39
  1850. MOVD EAX,XMM1
  1851. MUL ECX
  1852. SHR EAX,$08
  1853. AND EAX,$00FF0000
  1854. ADD R10D,EAX
  1855. PSHUFD XMM1,XMM1,$39
  1856. MOVD EAX,XMM1
  1857. MUL ECX
  1858. AND EAX,$FF000000
  1859. ADD EAX,R10D
  1860. {$ELSE}
  1861. PUSH EBX
  1862. PUSH ESI
  1863. PUSH EDI
  1864. MOV EBX,OffSrc
  1865. MOV ESI,EAX
  1866. MOV EDI,EDX
  1867. SHL ESI,$02
  1868. SUB EBX,ESI
  1869. PXOR XMM1,XMM1
  1870. PXOR XMM2,XMM2
  1871. PXOR XMM7,XMM7
  1872. @@LoopY:
  1873. MOV ESI,EAX
  1874. PXOR XMM0,XMM0
  1875. LEA ECX,[ECX+ESI*4]
  1876. NEG ESI
  1877. @@LoopX:
  1878. MOVD XMM6,[ECX+ESI*4]
  1879. PUNPCKLBW XMM6,XMM7
  1880. PADDW XMM0,XMM6
  1881. INC ESI
  1882. JNZ @@LoopX
  1883. MOVQ XMM6,XMM0
  1884. PUNPCKLWD XMM6,XMM7
  1885. PADDD XMM1,XMM6
  1886. ADD ECX,EBX
  1887. DEC EDX
  1888. JNZ @@LoopY
  1889. MUL EDI
  1890. MOV ECX,EAX
  1891. MOV EAX,$01000000
  1892. DIV ECX
  1893. MOV ECX,EAX
  1894. MOVD EAX,XMM1
  1895. MUL ECX
  1896. SHR EAX,$18
  1897. MOV EDI,EAX
  1898. SHUFPS XMM1,XMM1,$39
  1899. MOVD EAX,XMM1
  1900. MUL ECX
  1901. SHR EAX,$10
  1902. AND EAX,$0000FF00
  1903. ADD EDI,EAX
  1904. PSHUFD XMM1,XMM1,$39
  1905. MOVD EAX,XMM1
  1906. MUL ECX
  1907. SHR EAX,$08
  1908. AND EAX,$00FF0000
  1909. ADD EDI,EAX
  1910. PSHUFD XMM1,XMM1,$39
  1911. MOVD EAX,XMM1
  1912. MUL ECX
  1913. AND EAX,$FF000000
  1914. ADD EAX,EDI
  1915. POP EDI
  1916. POP ESI
  1917. POP EBX
  1918. {$ENDIF}
  1919. end;
  1920. {$ENDIF}
  1921. procedure DraftResample(Dst: TCustomBitmap32; DstRect: TRect; DstClip: TRect;
  1922. Src: TCustomBitmap32; SrcRect: TRect; Kernel: TCustomKernel;
  1923. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
  1924. var
  1925. SrcW, SrcH,
  1926. DstW, DstH,
  1927. DstClipW, DstClipH: Cardinal;
  1928. RowSrc: PColor32;
  1929. xsrc: PColor32;
  1930. OffSrc,
  1931. dy, dx,
  1932. c1, c2, r1, r2,
  1933. xs: Cardinal;
  1934. C: TColor32;
  1935. DstLine: PColor32Array;
  1936. ScaleFactor: TFloat;
  1937. I,J, sc, sr, cx, cy: Integer;
  1938. BlendMemEx: TBlendMemEx;
  1939. begin
  1940. { rangechecking and rect intersection done by caller }
  1941. SrcW := SrcRect.Right - SrcRect.Left;
  1942. SrcH := SrcRect.Bottom - SrcRect.Top;
  1943. DstW := DstRect.Right - DstRect.Left;
  1944. DstH := DstRect.Bottom - DstRect.Top;
  1945. DstClipW := DstClip.Right - DstClip.Left;
  1946. DstClipH := DstClip.Bottom - DstClip.Top;
  1947. BlendMemEx := BLEND_MEM_EX[Src.CombineMode]^;
  1948. if (DstW > SrcW)or(DstH > SrcH) then begin
  1949. if (SrcW < 2) or (SrcH < 2) then
  1950. Resample(Dst, DstRect, DstClip, Src, SrcRect, Kernel, CombineOp,
  1951. CombineCallBack)
  1952. else
  1953. StretchHorzStretchVertLinear(Dst, DstRect, DstClip, Src, SrcRect, CombineOp,
  1954. CombineCallBack);
  1955. end
  1956. else
  1957. begin //Full Scaledown, ignores Fulledge - cannot be integrated into this resampling method
  1958. OffSrc := Src.Width * 4;
  1959. ScaleFactor:= SrcW / DstW;
  1960. cx := Trunc( (DstClip.Left - DstRect.Left) * ScaleFactor);
  1961. r2 := Trunc(ScaleFactor);
  1962. sr := Trunc( $10000 * ScaleFactor );
  1963. ScaleFactor:= SrcH / DstH;
  1964. cy := Trunc( (DstClip.Top - DstRect.Top) * ScaleFactor);
  1965. c2 := Trunc(ScaleFactor);
  1966. sc := Trunc( $10000 * ScaleFactor );
  1967. DstLine := PColor32Array(Dst.PixelPtr[0, DstClip.Top]);
  1968. RowSrc := Src.PixelPtr[SrcRect.Left + cx, SrcRect.Top + cy ];
  1969. xs := r2;
  1970. c1 := 0;
  1971. Dec(DstClip.Left, 2);
  1972. Inc(DstClipW);
  1973. Inc(DstClipH);
  1974. for J := 2 to DstClipH do
  1975. begin
  1976. dy := c2 - c1;
  1977. c1 := c2;
  1978. c2 := FixedMul(J, sc);
  1979. r1 := 0;
  1980. r2 := xs;
  1981. xsrc := RowSrc;
  1982. case CombineOp of
  1983. dmOpaque:
  1984. for I := 2 to DstClipW do
  1985. begin
  1986. dx := r2 - r1; r1 := r2;
  1987. r2 := FixedMul(I, sr);
  1988. DstLine[DstClip.Left + I] := BlockAverage(dx, dy, xsrc, OffSrc);
  1989. Inc(xsrc, dx);
  1990. end;
  1991. dmBlend:
  1992. for I := 2 to DstClipW do
  1993. begin
  1994. dx := r2 - r1; r1 := r2;
  1995. r2 := FixedMul(I, sr);
  1996. BlendMemEx(BlockAverage(dx, dy, xsrc, OffSrc),
  1997. DstLine[DstClip.Left + I], Src.MasterAlpha);
  1998. Inc(xsrc, dx);
  1999. end;
  2000. dmTransparent:
  2001. for I := 2 to DstClipW do
  2002. begin
  2003. dx := r2 - r1; r1 := r2;
  2004. r2 := FixedMul(I, sr);
  2005. C := BlockAverage(dx, dy, xsrc, OffSrc);
  2006. if C <> Src.OuterColor then DstLine[DstClip.Left + I] := C;
  2007. Inc(xsrc, dx);
  2008. end;
  2009. dmCustom:
  2010. for I := 2 to DstClipW do
  2011. begin
  2012. dx := r2 - r1; r1 := r2;
  2013. r2 := FixedMul(I, sr);
  2014. CombineCallBack(BlockAverage(dx, dy, xsrc, OffSrc),
  2015. DstLine[DstClip.Left + I], Src.MasterAlpha);
  2016. Inc(xsrc, dx);
  2017. end;
  2018. end;
  2019. Inc(DstLine, Dst.Width);
  2020. {$IFDEF HAS_NATIVEINT}
  2021. Inc(NativeUInt(RowSrc), OffSrc * dy);
  2022. {$ELSE}
  2023. Inc(PByte(RowSrc), OffSrc * dy);
  2024. {$ENDIF}
  2025. end;
  2026. end;
  2027. EMMS;
  2028. end;
  2029. { Special interpolators (for sfLinear and sfDraft) }
  2030. function Interpolator_Pas(WX_256, WY_256: Cardinal; C11, C21: PColor32): TColor32;
  2031. var
  2032. C1, C3: TColor32;
  2033. begin
  2034. if WX_256 > $FF then WX_256:= $FF;
  2035. if WY_256 > $FF then WY_256:= $FF;
  2036. C1 := C11^; Inc(C11);
  2037. C3 := C21^; Inc(C21);
  2038. Result := CombineReg(CombineReg(C1, C11^, WX_256),
  2039. CombineReg(C3, C21^, WX_256), WY_256);
  2040. end;
  2041. {$IFNDEF PUREPASCAL}
  2042. function Interpolator_MMX(WX_256, WY_256: Cardinal; C11, C21: PColor32): TColor32;
  2043. asm
  2044. {$IFDEF TARGET_X64}
  2045. MOV RAX, RCX
  2046. MOVQ MM1,QWORD PTR [R8]
  2047. MOVQ MM2,MM1
  2048. MOVQ MM3,QWORD PTR [R9]
  2049. {$ELSE}
  2050. MOVQ MM1,[ECX]
  2051. MOVQ MM2,MM1
  2052. MOV ECX,C21
  2053. MOVQ MM3,[ECX]
  2054. {$ENDIF}
  2055. PSRLQ MM1,32
  2056. MOVQ MM4,MM3
  2057. PSRLQ MM3,32
  2058. MOVD MM5,EAX
  2059. PSHUFW MM5,MM5,0
  2060. PXOR MM0,MM0
  2061. PUNPCKLBW MM1,MM0
  2062. PUNPCKLBW MM2,MM0
  2063. PSUBW MM2,MM1
  2064. PMULLW MM2,MM5
  2065. PSLLW MM1,8
  2066. PADDW MM2,MM1
  2067. PSRLW MM2,8
  2068. PUNPCKLBW MM3,MM0
  2069. PUNPCKLBW MM4,MM0
  2070. PSUBW MM4,MM3
  2071. PSLLW MM3,8
  2072. PMULLW MM4,MM5
  2073. PADDW MM4,MM3
  2074. PSRLW MM4,8
  2075. MOVD MM5,EDX
  2076. PSHUFW MM5,MM5,0
  2077. PSUBW MM2,MM4
  2078. PMULLW MM2,MM5
  2079. PSLLW MM4,8
  2080. PADDW MM2,MM4
  2081. PSRLW MM2,8
  2082. PACKUSWB MM2,MM0
  2083. MOVD EAX,MM2
  2084. end;
  2085. function Interpolator_SSE2(WX_256, WY_256: Cardinal; C11, C21: PColor32): TColor32;
  2086. asm
  2087. {$IFDEF TARGET_X64}
  2088. MOV RAX, RCX
  2089. MOVQ XMM1,QWORD PTR [R8]
  2090. MOVQ XMM2,XMM1
  2091. MOVQ XMM3,QWORD PTR [R9]
  2092. {$ELSE}
  2093. MOVQ XMM1,[ECX]
  2094. MOVQ XMM2,XMM1
  2095. MOV ECX,C21
  2096. MOVQ XMM3,[ECX]
  2097. {$ENDIF}
  2098. PSRLQ XMM1,32
  2099. MOVQ XMM4,XMM3
  2100. PSRLQ XMM3,32
  2101. MOVD XMM5,EAX
  2102. PSHUFLW XMM5,XMM5,0
  2103. PXOR XMM0,XMM0
  2104. PUNPCKLBW XMM1,XMM0
  2105. PUNPCKLBW XMM2,XMM0
  2106. PSUBW XMM2,XMM1
  2107. PMULLW XMM2,XMM5
  2108. PSLLW XMM1,8
  2109. PADDW XMM2,XMM1
  2110. PSRLW XMM2,8
  2111. PUNPCKLBW XMM3,XMM0
  2112. PUNPCKLBW XMM4,XMM0
  2113. PSUBW XMM4,XMM3
  2114. PSLLW XMM3,8
  2115. PMULLW XMM4,XMM5
  2116. PADDW XMM4,XMM3
  2117. PSRLW XMM4,8
  2118. MOVD XMM5,EDX
  2119. PSHUFLW XMM5,XMM5,0
  2120. PSUBW XMM2,XMM4
  2121. PMULLW XMM2,XMM5
  2122. PSLLW XMM4,8
  2123. PADDW XMM2,XMM4
  2124. PSRLW XMM2,8
  2125. PACKUSWB XMM2,XMM0
  2126. MOVD EAX,XMM2
  2127. end;
  2128. {$ENDIF}
  2129. { Stretch Transfer }
  2130. {$WARNINGS OFF}
  2131. procedure StretchTransfer(
  2132. Dst: TCustomBitmap32; DstRect: TRect; DstClip: TRect;
  2133. Src: TCustomBitmap32; SrcRect: TRect;
  2134. Resampler: TCustomResampler;
  2135. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
  2136. var
  2137. SrcW, SrcH: Integer;
  2138. DstW, DstH: Integer;
  2139. R: TRect;
  2140. RatioX, RatioY: Single;
  2141. begin
  2142. CheckBitmaps(Dst, Src);
  2143. // transform dest rect when the src rect is out of the src bitmap's bounds
  2144. if (SrcRect.Left < 0) or (SrcRect.Right > Src.Width) or
  2145. (SrcRect.Top < 0) or (SrcRect.Bottom > Src.Height) then
  2146. begin
  2147. RatioX := (DstRect.Right - DstRect.Left) / (SrcRect.Right - SrcRect.Left);
  2148. RatioY := (DstRect.Bottom - DstRect.Top) / (SrcRect.Bottom - SrcRect.Top);
  2149. if SrcRect.Left < 0 then
  2150. begin
  2151. DstRect.Left := DstRect.Left + Ceil(-SrcRect.Left * RatioX);
  2152. SrcRect.Left := 0;
  2153. end;
  2154. if SrcRect.Top < 0 then
  2155. begin
  2156. DstRect.Top := DstRect.Top + Ceil(-SrcRect.Top * RatioY);
  2157. SrcRect.Top := 0;
  2158. end;
  2159. if SrcRect.Right > Src.Width then
  2160. begin
  2161. DstRect.Right := DstRect.Right - Floor((SrcRect.Right - Src.Width) * RatioX);
  2162. SrcRect.Right := Src.Width;
  2163. end;
  2164. if SrcRect.Bottom > Src.Height then
  2165. begin
  2166. DstRect.Bottom := DstRect.Bottom - Floor((SrcRect.Bottom - Src.Height) * RatioY);
  2167. SrcRect.Bottom := Src.Height;
  2168. end;
  2169. end;
  2170. if Src.Empty or Dst.Empty or
  2171. ((CombineOp = dmBlend) and (Src.MasterAlpha = 0)) or
  2172. GR32.IsRectEmpty(SrcRect) then
  2173. Exit;
  2174. if not Dst.MeasuringMode then
  2175. begin
  2176. GR32.IntersectRect(DstClip, DstClip, Dst.BoundsRect);
  2177. GR32.IntersectRect(DstClip, DstClip, DstRect);
  2178. if GR32.IsRectEmpty(DstClip) then Exit;
  2179. GR32.IntersectRect(R, DstClip, DstRect);
  2180. if GR32.IsRectEmpty(R) then Exit;
  2181. if (CombineOp = dmCustom) and not Assigned(CombineCallBack) then
  2182. CombineOp := dmOpaque;
  2183. SrcW := SrcRect.Right - SrcRect.Left;
  2184. SrcH := SrcRect.Bottom - SrcRect.Top;
  2185. DstW := DstRect.Right - DstRect.Left;
  2186. DstH := DstRect.Bottom - DstRect.Top;
  2187. try
  2188. if (SrcW = DstW) and (SrcH = DstH) then
  2189. BlendBlock(Dst, DstClip, Src, SrcRect.Left + DstClip.Left - DstRect.Left,
  2190. SrcRect.Top + DstClip.Top - DstRect.Top, CombineOp, CombineCallBack)
  2191. else
  2192. TCustomResamplerAccess(Resampler).Resample(
  2193. Dst, DstRect, DstClip, Src, SrcRect, CombineOp, CombineCallBack);
  2194. finally
  2195. EMMS;
  2196. end;
  2197. end;
  2198. Dst.Changed(DstRect);
  2199. end;
  2200. {$WARNINGS ON}
  2201. { TCustomKernel }
  2202. procedure TCustomKernel.AssignTo(Dst: TPersistent);
  2203. begin
  2204. if Dst is TCustomKernel then
  2205. SmartAssign(Self, Dst)
  2206. else
  2207. inherited;
  2208. end;
  2209. procedure TCustomKernel.Changed;
  2210. begin
  2211. if Assigned(FObserver) then FObserver.Changed;
  2212. end;
  2213. constructor TCustomKernel.Create;
  2214. begin
  2215. end;
  2216. function TCustomKernel.RangeCheck: Boolean;
  2217. begin
  2218. Result := False;
  2219. end;
  2220. { TBoxKernel }
  2221. function TBoxKernel.Filter(Value: TFloat): TFloat;
  2222. begin
  2223. if (Value >= -0.5) and (Value <= 0.5) then Result := 1.0
  2224. else Result := 0;
  2225. end;
  2226. function TBoxKernel.GetWidth: TFloat;
  2227. begin
  2228. Result := 1;
  2229. end;
  2230. { TLinearKernel }
  2231. function TLinearKernel.Filter(Value: TFloat): TFloat;
  2232. begin
  2233. if Value < -1 then Result := 0
  2234. else if Value < 0 then Result := 1 + Value
  2235. else if Value < 1 then Result := 1 - Value
  2236. else Result := 0;
  2237. end;
  2238. function TLinearKernel.GetWidth: TFloat;
  2239. begin
  2240. Result := 1;
  2241. end;
  2242. { TCosineKernel }
  2243. function TCosineKernel.Filter(Value: TFloat): TFloat;
  2244. begin
  2245. Result := 0;
  2246. if Abs(Value) < 1 then
  2247. Result := (Cos(Value * Pi) + 1) * 0.5;
  2248. end;
  2249. function TCosineKernel.GetWidth: TFloat;
  2250. begin
  2251. Result := 1;
  2252. end;
  2253. { TSplineKernel }
  2254. function TSplineKernel.Filter(Value: TFloat): TFloat;
  2255. var
  2256. tt: TFloat;
  2257. const
  2258. TwoThirds = 2 / 3;
  2259. OneSixth = 1 / 6;
  2260. begin
  2261. Value := Abs(Value);
  2262. if Value < 1 then
  2263. begin
  2264. tt := Sqr(Value);
  2265. Result := 0.5 * tt * Value - tt + TwoThirds;
  2266. end
  2267. else if Value < 2 then
  2268. begin
  2269. Value := 2 - Value;
  2270. Result := OneSixth * Sqr(Value) * Value;
  2271. end
  2272. else Result := 0;
  2273. end;
  2274. function TSplineKernel.RangeCheck: Boolean;
  2275. begin
  2276. Result := True;
  2277. end;
  2278. function TSplineKernel.GetWidth: TFloat;
  2279. begin
  2280. Result := 2;
  2281. end;
  2282. { TWindowedSincKernel }
  2283. function SInc(Value: TFloat): TFloat;
  2284. begin
  2285. if Value <> 0 then
  2286. begin
  2287. Value := Value * Pi;
  2288. Result := Sin(Value) / Value;
  2289. end
  2290. else Result := 1;
  2291. end;
  2292. constructor TWindowedSincKernel.Create;
  2293. begin
  2294. FWidth := 3;
  2295. FWidthReciprocal := 1 / FWidth;
  2296. end;
  2297. function TWindowedSincKernel.Filter(Value: TFloat): TFloat;
  2298. begin
  2299. Value := Abs(Value);
  2300. if Value < FWidth then
  2301. Result := SInc(Value) * Window(Value)
  2302. else
  2303. Result := 0;
  2304. end;
  2305. function TWindowedSincKernel.RangeCheck: Boolean;
  2306. begin
  2307. Result := True;
  2308. end;
  2309. procedure TWindowedSincKernel.SetWidth(Value: TFloat);
  2310. begin
  2311. Value := Min(MAX_KERNEL_WIDTH, Value);
  2312. if Value <> FWidth then
  2313. begin
  2314. FWidth := Value;
  2315. FWidthReciprocal := 1 / FWidth;
  2316. Changed;
  2317. end;
  2318. end;
  2319. function TWindowedSincKernel.GetWidth: TFloat;
  2320. begin
  2321. Result := FWidth;
  2322. end;
  2323. { TAlbrechtKernel }
  2324. constructor TAlbrechtKernel.Create;
  2325. begin
  2326. inherited;
  2327. Terms := 7;
  2328. end;
  2329. procedure TAlbrechtKernel.SetTerms(Value: Integer);
  2330. begin
  2331. if (Value < 2) then Value := 2;
  2332. if (Value > 11) then Value := 11;
  2333. if FTerms <> Value then
  2334. begin
  2335. FTerms := Value;
  2336. case Value of
  2337. 2 : Move(CAlbrecht2 [0], FCoefPointer[0], Value * SizeOf(Double));
  2338. 3 : Move(CAlbrecht3 [0], FCoefPointer[0], Value * SizeOf(Double));
  2339. 4 : Move(CAlbrecht4 [0], FCoefPointer[0], Value * SizeOf(Double));
  2340. 5 : Move(CAlbrecht5 [0], FCoefPointer[0], Value * SizeOf(Double));
  2341. 6 : Move(CAlbrecht6 [0], FCoefPointer[0], Value * SizeOf(Double));
  2342. 7 : Move(CAlbrecht7 [0], FCoefPointer[0], Value * SizeOf(Double));
  2343. 8 : Move(CAlbrecht8 [0], FCoefPointer[0], Value * SizeOf(Double));
  2344. 9 : Move(CAlbrecht9 [0], FCoefPointer[0], Value * SizeOf(Double));
  2345. 10 : Move(CAlbrecht10[0], FCoefPointer[0], Value * SizeOf(Double));
  2346. 11 : Move(CAlbrecht11[0], FCoefPointer[0], Value * SizeOf(Double));
  2347. end;
  2348. end;
  2349. end;
  2350. function TAlbrechtKernel.Window(Value: TFloat): TFloat;
  2351. var
  2352. cs : Double;
  2353. i : Integer;
  2354. begin
  2355. cs := Cos(Pi * Value * FWidthReciprocal);
  2356. i := FTerms - 1;
  2357. Result := FCoefPointer[i];
  2358. while i > 0 do
  2359. begin
  2360. Dec(i);
  2361. Result := Result * cs + FCoefPointer[i];
  2362. end;
  2363. end;
  2364. { TLanczosKernel }
  2365. function TLanczosKernel.Window(Value: TFloat): TFloat;
  2366. begin
  2367. Result := SInc(Value * FWidthReciprocal); // Get rid of division
  2368. end;
  2369. { TMitchellKernel }
  2370. function TMitchellKernel.Filter(Value: TFloat): TFloat;
  2371. var
  2372. tt, ttt: TFloat;
  2373. const OneEighteenth = 1 / 18;
  2374. begin
  2375. Value := Abs(Value);
  2376. tt := Sqr(Value);
  2377. ttt := tt * Value;
  2378. if Value < 1 then Result := (21 * ttt - 36 * tt + 16 ) * OneEighteenth // get rid of divisions
  2379. else if Value < 2 then Result := (- 7 * ttt + 36 * tt - 60 * Value + 32) * OneEighteenth // "
  2380. else Result := 0;
  2381. end;
  2382. function TMitchellKernel.RangeCheck: Boolean;
  2383. begin
  2384. Result := True;
  2385. end;
  2386. function TMitchellKernel.GetWidth: TFloat;
  2387. begin
  2388. Result := 2;
  2389. end;
  2390. { TCubicKernel }
  2391. constructor TCubicKernel.Create;
  2392. begin
  2393. FCoeff := -0.5;
  2394. end;
  2395. function TCubicKernel.Filter(Value: TFloat): TFloat;
  2396. var
  2397. tt, ttt: TFloat;
  2398. begin
  2399. Value := Abs(Value);
  2400. tt := Sqr(Value);
  2401. ttt := tt * Value;
  2402. if Value < 1 then
  2403. Result := (FCoeff + 2) * ttt - (FCoeff + 3) * tt + 1
  2404. else if Value < 2 then
  2405. Result := FCoeff * (ttt - 5 * tt + 8 * Value - 4)
  2406. else
  2407. Result := 0;
  2408. end;
  2409. function TCubicKernel.RangeCheck: Boolean;
  2410. begin
  2411. Result := True;
  2412. end;
  2413. function TCubicKernel.GetWidth: TFloat;
  2414. begin
  2415. Result := 2;
  2416. end;
  2417. { TGaussKernel }
  2418. constructor TGaussianKernel.Create;
  2419. begin
  2420. inherited;
  2421. FSigma := 1.33;
  2422. FSigmaReciprocalLn2 := -Ln(2) / FSigma;
  2423. end;
  2424. procedure TGaussianKernel.SetSigma(const Value: TFloat);
  2425. begin
  2426. if (FSigma <> Value) and (FSigma <> 0) then
  2427. begin
  2428. FSigma := Value;
  2429. FSigmaReciprocalLn2 := -Ln(2) / FSigma;
  2430. Changed;
  2431. end;
  2432. end;
  2433. function TGaussianKernel.Window(Value: TFloat): TFloat;
  2434. begin
  2435. Result := Exp(Sqr(Value) * FSigmaReciprocalLn2); // get rid of nasty LN2 and divition
  2436. end;
  2437. procedure TCubicKernel.SetCoeff(const Value: TFloat);
  2438. begin
  2439. if Value <> FCoeff then
  2440. begin
  2441. FCoeff := Value;
  2442. Changed;
  2443. end
  2444. end;
  2445. { TBlackmanKernel }
  2446. function TBlackmanKernel.Window(Value: TFloat): TFloat;
  2447. begin
  2448. Value := Cos(Pi * Value * FWidthReciprocal); // get rid of division
  2449. Result := 0.34 + 0.5 * Value + 0.16 * sqr(Value);
  2450. end;
  2451. { THannKernel }
  2452. function THannKernel.Window(Value: TFloat): TFloat;
  2453. begin
  2454. Result := 0.5 + 0.5 * Cos(Pi * Value * FWidthReciprocal); // get rid of division
  2455. end;
  2456. { THammingKernel }
  2457. function THammingKernel.Window(Value: TFloat): TFloat;
  2458. begin
  2459. Result := 0.54 + 0.46 * Cos(Pi * Value * FWidthReciprocal); // get rid of division
  2460. end;
  2461. { TSinshKernel }
  2462. constructor TSinshKernel.Create;
  2463. begin
  2464. FWidth := 3;
  2465. FCoeff := 0.5;
  2466. end;
  2467. function TSinshKernel.Filter(Value: TFloat): TFloat;
  2468. begin
  2469. if Value = 0 then
  2470. Result := 1
  2471. else
  2472. Result := FCoeff * Sin(Pi * Value) / Sinh(Pi * FCoeff * Value);
  2473. end;
  2474. function TSinshKernel.RangeCheck: Boolean;
  2475. begin
  2476. Result := True;
  2477. end;
  2478. procedure TSinshKernel.SetWidth(Value: TFloat);
  2479. begin
  2480. if FWidth <> Value then
  2481. begin
  2482. FWidth := Value;
  2483. Changed;
  2484. end;
  2485. end;
  2486. function TSinshKernel.GetWidth: TFloat;
  2487. begin
  2488. Result := FWidth;
  2489. end;
  2490. procedure TSinshKernel.SetCoeff(const Value: TFloat);
  2491. begin
  2492. if (FCoeff <> Value) and (FCoeff <> 0) then
  2493. begin
  2494. FCoeff := Value;
  2495. Changed;
  2496. end;
  2497. end;
  2498. { THermiteKernel }
  2499. constructor THermiteKernel.Create;
  2500. begin
  2501. FBias := 0;
  2502. FTension := 0;
  2503. end;
  2504. function THermiteKernel.Filter(Value: TFloat): TFloat;
  2505. var
  2506. Z: Integer;
  2507. t, t2, t3, m0, m1, a0, a1, a2, a3: TFloat;
  2508. begin
  2509. t := (1 - FTension) * 0.5;
  2510. m0 := (1 + FBias) * t;
  2511. m1 := (1 - FBias) * t;
  2512. Z := Floor(Value);
  2513. t := Abs(Z - Value);
  2514. t2 := t * t;
  2515. t3 := t2 * t;
  2516. a1 := t3 - 2 * t2 + t;
  2517. a2 := t3 - t2;
  2518. a3 := -2 * t3 + 3 * t2;
  2519. a0 := -a3 + 1;
  2520. case Z of
  2521. -2: Result := a2 * m1;
  2522. -1: Result := a3 + a1 * m1 + a2 * (m0 - m1);
  2523. 0: Result := a0 + a1 * (m0 - m1) - a2 * m0;
  2524. 1: Result := -a1 * m0;
  2525. else
  2526. Result := 0;
  2527. end;
  2528. end;
  2529. function THermiteKernel.GetWidth: TFloat;
  2530. begin
  2531. Result := 2;
  2532. end;
  2533. function THermiteKernel.RangeCheck: Boolean;
  2534. begin
  2535. Result := True;
  2536. end;
  2537. procedure THermiteKernel.SetBias(const Value: TFloat);
  2538. begin
  2539. if FBias <> Value then
  2540. begin
  2541. FBias := Value;
  2542. Changed;
  2543. end;
  2544. end;
  2545. procedure THermiteKernel.SetTension(const Value: TFloat);
  2546. begin
  2547. if FTension <> Value then
  2548. begin
  2549. FTension := Value;
  2550. Changed;
  2551. end;
  2552. end;
  2553. { TKernelResampler }
  2554. constructor TKernelResampler.Create;
  2555. begin
  2556. inherited;
  2557. Kernel := TBoxKernel.Create;
  2558. FTableSize := 32;
  2559. end;
  2560. destructor TKernelResampler.Destroy;
  2561. begin
  2562. FKernel.Free;
  2563. inherited;
  2564. end;
  2565. function TKernelResampler.GetKernelClassName: string;
  2566. begin
  2567. Result := FKernel.ClassName;
  2568. end;
  2569. procedure TKernelResampler.SetKernelClassName(const Value: string);
  2570. var
  2571. KernelClass: TCustomKernelClass;
  2572. begin
  2573. if (Value <> '') and (FKernel.ClassName <> Value) and Assigned(KernelList) then
  2574. begin
  2575. KernelClass := TCustomKernelClass(KernelList.Find(Value));
  2576. if Assigned(KernelClass) then
  2577. begin
  2578. FKernel.Free;
  2579. FKernel := KernelClass.Create;
  2580. Changed;
  2581. end;
  2582. end;
  2583. end;
  2584. procedure TKernelResampler.SetKernel(const Value: TCustomKernel);
  2585. begin
  2586. if Assigned(Value) and (FKernel <> Value) then
  2587. begin
  2588. FKernel.Free;
  2589. FKernel := Value;
  2590. Changed;
  2591. end;
  2592. end;
  2593. procedure TKernelResampler.Resample(Dst: TCustomBitmap32; DstRect,
  2594. DstClip: TRect; Src: TCustomBitmap32; SrcRect: TRect; CombineOp: TDrawMode;
  2595. CombineCallBack: TPixelCombineEvent);
  2596. begin
  2597. GR32_Resamplers.Resample(Dst, DstRect, DstClip, Src, SrcRect, FKernel, CombineOp, CombineCallBack);
  2598. end;
  2599. {$WARNINGS OFF}
  2600. function TKernelResampler.GetSampleFloat(X, Y: TFloat): TColor32;
  2601. var
  2602. clX, clY: Integer;
  2603. fracX, fracY: Integer;
  2604. fracXS: TFloat absolute fracX;
  2605. fracYS: TFloat absolute fracY;
  2606. Filter: TFilterMethod;
  2607. WrapProcVert: TWrapProcEx absolute Filter;
  2608. WrapProcHorz: TWrapProcEx;
  2609. Colors: PColor32EntryArray;
  2610. KWidth, W, Wv, I, J, Incr, Dev: Integer;
  2611. SrcP: PColor32Entry;
  2612. C: TColor32Entry absolute SrcP;
  2613. LoX, HiX, LoY, HiY, MappingY: Integer;
  2614. HorzKernel, VertKernel: TKernelEntry;
  2615. PHorzKernel, PVertKernel, FloorKernel, CeilKernel: PKernelEntry;
  2616. HorzEntry, VertEntry: TBufferEntry;
  2617. MappingX: TKernelEntry;
  2618. Edge: Boolean;
  2619. Alpha: integer;
  2620. OuterPremultColorR, OuterPremultColorG, OuterPremultColorB: Byte;
  2621. begin
  2622. KWidth := Ceil(FKernel.GetWidth);
  2623. clX := Ceil(X);
  2624. clY := Ceil(Y);
  2625. case PixelAccessMode of
  2626. pamUnsafe, pamWrap:
  2627. begin
  2628. LoX := -KWidth; HiX := KWidth;
  2629. LoY := -KWidth; HiY := KWidth;
  2630. end;
  2631. pamSafe, pamTransparentEdge:
  2632. begin
  2633. with ClipRect do
  2634. begin
  2635. if not ((clX < Left) or (clX > Right) or (clY < Top) or (clY > Bottom)) then
  2636. begin
  2637. Edge := False;
  2638. if clX - KWidth < Left then
  2639. begin
  2640. LoX := Left - clX;
  2641. Edge := True;
  2642. end
  2643. else
  2644. LoX := -KWidth;
  2645. if clX + KWidth >= Right then
  2646. begin
  2647. HiX := Right - clX - 1;
  2648. Edge := True;
  2649. end
  2650. else
  2651. HiX := KWidth;
  2652. if clY - KWidth < Top then
  2653. begin
  2654. LoY := Top - clY;
  2655. Edge := True;
  2656. end
  2657. else
  2658. LoY := -KWidth;
  2659. if clY + KWidth >= Bottom then
  2660. begin
  2661. HiY := Bottom - clY - 1;
  2662. Edge := True;
  2663. end
  2664. else
  2665. HiY := KWidth;
  2666. end
  2667. else
  2668. begin
  2669. if PixelAccessMode = pamTransparentEdge then
  2670. Result := 0
  2671. else
  2672. Result := FOuterColor;
  2673. Exit;
  2674. end;
  2675. end;
  2676. end;
  2677. end;
  2678. case FKernelMode of
  2679. kmDynamic:
  2680. begin
  2681. Filter := FKernel.Filter;
  2682. fracXS := clX - X;
  2683. fracYS := clY - Y;
  2684. PHorzKernel := @HorzKernel;
  2685. PVertKernel := @VertKernel;
  2686. Dev := -256;
  2687. for I := -KWidth to KWidth do
  2688. begin
  2689. W := Round(Filter(I + fracXS) * 256);
  2690. HorzKernel[I] := W;
  2691. Inc(Dev, W);
  2692. end;
  2693. Dec(HorzKernel[0], Dev);
  2694. Dev := -256;
  2695. for I := -KWidth to KWidth do
  2696. begin
  2697. W := Round(Filter(I + fracYS) * 256);
  2698. VertKernel[I] := W;
  2699. Inc(Dev, W);
  2700. end;
  2701. Dec(VertKernel[0], Dev);
  2702. end;
  2703. kmTableNearest:
  2704. begin
  2705. W := FWeightTable.Height - 2;
  2706. PHorzKernel := @FWeightTable.ValPtr[KWidth - MAX_KERNEL_WIDTH, Round((clX - X) * W)]^;
  2707. PVertKernel := @FWeightTable.ValPtr[KWidth - MAX_KERNEL_WIDTH, Round((clY - Y) * W)]^;
  2708. end;
  2709. kmTableLinear:
  2710. begin
  2711. W := (FWeightTable.Height - 2) * $10000;
  2712. J := FWeightTable.Width * 4;
  2713. with TFixedRec(FracX) do
  2714. begin
  2715. Fixed := Round((clX - X) * W);
  2716. PHorzKernel := @HorzKernel;
  2717. FloorKernel := @FWeightTable.ValPtr[KWidth - MAX_KERNEL_WIDTH, Int]^;
  2718. {$IFDEF HAS_NATIVEINT}
  2719. CeilKernel := PKernelEntry(NativeUInt(FloorKernel) + J);
  2720. {$ELSE}
  2721. CeilKernel := PKernelEntry(Cardinal(FloorKernel) + J);
  2722. {$ENDIF}
  2723. Dev := -256;
  2724. for I := -KWidth to KWidth do
  2725. begin
  2726. Wv := FloorKernel[I] + ((CeilKernel[I] - FloorKernel[I]) * Frac + $7FFF) div FixedOne;
  2727. HorzKernel[I] := Wv;
  2728. Inc(Dev, Wv);
  2729. end;
  2730. Dec(HorzKernel[0], Dev);
  2731. end;
  2732. with TFixedRec(FracY) do
  2733. begin
  2734. Fixed := Round((clY - Y) * W);
  2735. PVertKernel := @VertKernel;
  2736. FloorKernel := @FWeightTable.ValPtr[KWidth - MAX_KERNEL_WIDTH, Int]^;
  2737. {$IFDEF HAS_NATIVEINT}
  2738. CeilKernel := PKernelEntry(NativeUInt(FloorKernel) + J);
  2739. {$ELSE}
  2740. CeilKernel := PKernelEntry(Cardinal(FloorKernel) + J);
  2741. {$ENDIF}
  2742. Dev := -256;
  2743. for I := -KWidth to KWidth do
  2744. begin
  2745. Wv := FloorKernel[I] + ((CeilKernel[I] - FloorKernel[I]) * Frac + $7FFF) div FixedOne;
  2746. VertKernel[I] := Wv;
  2747. Inc(Dev, Wv);
  2748. end;
  2749. Dec(VertKernel[0], Dev);
  2750. end;
  2751. end;
  2752. end;
  2753. VertEntry := EMPTY_ENTRY;
  2754. case PixelAccessMode of
  2755. pamUnsafe, pamSafe, pamTransparentEdge:
  2756. begin
  2757. SrcP := PColor32Entry(Bitmap.PixelPtr[LoX + clX, LoY + clY]);
  2758. Incr := Bitmap.Width - (HiX - LoX) - 1;
  2759. for I := LoY to HiY do
  2760. begin
  2761. Wv := PVertKernel[I];
  2762. if Wv <> 0 then
  2763. begin
  2764. HorzEntry := EMPTY_ENTRY;
  2765. for J := LoX to HiX do
  2766. begin
  2767. // Alpha=0 should not contribute to sample.
  2768. Alpha := SrcP.A;
  2769. if (Alpha <> 0) then
  2770. begin
  2771. W := PHorzKernel[J];
  2772. Inc(HorzEntry.A, Alpha * W);
  2773. // Sample premultiplied values
  2774. if (Alpha = 255) then
  2775. begin
  2776. Inc(HorzEntry.R, SrcP.R * W);
  2777. Inc(HorzEntry.G, SrcP.G * W);
  2778. Inc(HorzEntry.B, SrcP.B * W);
  2779. end else
  2780. begin
  2781. Inc(HorzEntry.R, Integer(Div255(Alpha * SrcP.R)) * W);
  2782. Inc(HorzEntry.G, Integer(Div255(Alpha * SrcP.G)) * W);
  2783. Inc(HorzEntry.B, Integer(Div255(Alpha * SrcP.B)) * W);
  2784. end;
  2785. end;
  2786. Inc(SrcP);
  2787. end;
  2788. Inc(VertEntry.A, HorzEntry.A * Wv);
  2789. Inc(VertEntry.R, HorzEntry.R * Wv);
  2790. Inc(VertEntry.G, HorzEntry.G * Wv);
  2791. Inc(VertEntry.B, HorzEntry.B * Wv);
  2792. end else Inc(SrcP, HiX - LoX + 1);
  2793. Inc(SrcP, Incr);
  2794. end;
  2795. if (PixelAccessMode = pamSafe) and Edge then
  2796. begin
  2797. Alpha := TColor32Entry(FOuterColor).A;
  2798. // Alpha=0 should not contribute to sample.
  2799. if (Alpha <> 0) then
  2800. begin
  2801. // Sample premultiplied values
  2802. OuterPremultColorR := Integer(Div255(Alpha * TColor32Entry(FOuterColor).R));
  2803. OuterPremultColorG := Integer(Div255(Alpha * TColor32Entry(FOuterColor).G));
  2804. OuterPremultColorB := Integer(Div255(Alpha * TColor32Entry(FOuterColor).B));
  2805. for I := -KWidth to KWidth do
  2806. begin
  2807. Wv := PVertKernel[I];
  2808. if Wv <> 0 then
  2809. begin
  2810. HorzEntry := EMPTY_ENTRY;
  2811. for J := -KWidth to KWidth do
  2812. if (J < LoX) or (J > HiX) or (I < LoY) or (I > HiY) then
  2813. begin
  2814. W := PHorzKernel[J];
  2815. Inc(HorzEntry.A, Alpha * W);
  2816. Inc(HorzEntry.R, OuterPremultColorR * W);
  2817. Inc(HorzEntry.G, OuterPremultColorG * W);
  2818. Inc(HorzEntry.B, OuterPremultColorB * W);
  2819. end;
  2820. Inc(VertEntry.A, HorzEntry.A * Wv);
  2821. Inc(VertEntry.R, HorzEntry.R * Wv);
  2822. Inc(VertEntry.G, HorzEntry.G * Wv);
  2823. Inc(VertEntry.B, HorzEntry.B * Wv);
  2824. end;
  2825. end
  2826. end;
  2827. end;
  2828. end;
  2829. pamWrap:
  2830. begin
  2831. WrapProcHorz := GetWrapProcEx(Bitmap.WrapMode, ClipRect.Left, ClipRect.Right - 1);
  2832. WrapProcVert := GetWrapProcEx(Bitmap.WrapMode, ClipRect.Top, ClipRect.Bottom - 1);
  2833. for I := -KWidth to KWidth do
  2834. MappingX[I] := WrapProcHorz(clX + I, ClipRect.Left, ClipRect.Right - 1);
  2835. for I := -KWidth to KWidth do
  2836. begin
  2837. Wv := PVertKernel[I];
  2838. if Wv <> 0 then
  2839. begin
  2840. MappingY := WrapProcVert(clY + I, ClipRect.Top, ClipRect.Bottom - 1);
  2841. Colors := PColor32EntryArray(Bitmap.ScanLine[MappingY]);
  2842. HorzEntry := EMPTY_ENTRY;
  2843. for J := -KWidth to KWidth do
  2844. begin
  2845. C := Colors[MappingX[J]];
  2846. Alpha := C.A;
  2847. // Alpha=0 should not contribute to sample.
  2848. if (Alpha <> 0) then
  2849. begin
  2850. W := PHorzKernel[J];
  2851. Inc(HorzEntry.A, Alpha * W);
  2852. // Sample premultiplied values
  2853. if (Alpha = 255) then
  2854. begin
  2855. Inc(HorzEntry.R, C.R * W);
  2856. Inc(HorzEntry.G, C.G * W);
  2857. Inc(HorzEntry.B, C.B * W);
  2858. end else
  2859. begin
  2860. Inc(HorzEntry.R, Div255(Alpha * C.R) * W);
  2861. Inc(HorzEntry.G, Div255(Alpha * C.G) * W);
  2862. Inc(HorzEntry.B, Div255(Alpha * C.B) * W);
  2863. end;
  2864. end;
  2865. end;
  2866. Inc(VertEntry.A, HorzEntry.A * Wv);
  2867. Inc(VertEntry.R, HorzEntry.R * Wv);
  2868. Inc(VertEntry.G, HorzEntry.G * Wv);
  2869. Inc(VertEntry.B, HorzEntry.B * Wv);
  2870. end;
  2871. end;
  2872. end;
  2873. end;
  2874. // Round and unpremultiply result
  2875. with TColor32Entry(Result) do
  2876. begin
  2877. if FKernel.RangeCheck then
  2878. begin
  2879. A := Clamp(TFixedRec(Integer(VertEntry.A + FixedHalf)).Int);
  2880. if (A = 255) then
  2881. begin
  2882. R := Clamp(TFixedRec(Integer(VertEntry.R + FixedHalf)).Int);
  2883. G := Clamp(TFixedRec(Integer(VertEntry.G + FixedHalf)).Int);
  2884. B := Clamp(TFixedRec(Integer(VertEntry.B + FixedHalf)).Int);
  2885. end else
  2886. if (A <> 0) then
  2887. begin
  2888. R := Clamp(TFixedRec(Integer(VertEntry.R + FixedHalf)).Int * 255 div A);
  2889. G := Clamp(TFixedRec(Integer(VertEntry.G + FixedHalf)).Int * 255 div A);
  2890. B := Clamp(TFixedRec(Integer(VertEntry.B + FixedHalf)).Int * 255 div A);
  2891. end else
  2892. begin
  2893. R := 0;
  2894. G := 0;
  2895. B := 0;
  2896. end;
  2897. end
  2898. else
  2899. begin
  2900. A := TFixedRec(Integer(VertEntry.A + FixedHalf)).Int;
  2901. if (A = 255) then
  2902. begin
  2903. R := TFixedRec(Integer(VertEntry.R + FixedHalf)).Int;
  2904. G := TFixedRec(Integer(VertEntry.G + FixedHalf)).Int;
  2905. B := TFixedRec(Integer(VertEntry.B + FixedHalf)).Int;
  2906. end else
  2907. if (A <> 0) then
  2908. begin
  2909. R := TFixedRec(Integer(VertEntry.R + FixedHalf)).Int * 255 div A;
  2910. G := TFixedRec(Integer(VertEntry.G + FixedHalf)).Int * 255 div A;
  2911. B := TFixedRec(Integer(VertEntry.B + FixedHalf)).Int * 255 div A;
  2912. end else
  2913. begin
  2914. R := 0;
  2915. G := 0;
  2916. B := 0;
  2917. end;
  2918. end;
  2919. end;
  2920. end;
  2921. {$WARNINGS ON}
  2922. function TKernelResampler.GetWidth: TFloat;
  2923. begin
  2924. Result := Kernel.GetWidth;
  2925. end;
  2926. procedure TKernelResampler.SetKernelMode(const Value: TKernelMode);
  2927. begin
  2928. if FKernelMode <> Value then
  2929. begin
  2930. FKernelMode := Value;
  2931. Changed;
  2932. end;
  2933. end;
  2934. procedure TKernelResampler.SetTableSize(Value: Integer);
  2935. begin
  2936. if Value < 2 then Value := 2;
  2937. if FTableSize <> Value then
  2938. begin
  2939. FTableSize := Value;
  2940. Changed;
  2941. end;
  2942. end;
  2943. procedure TKernelResampler.FinalizeSampling;
  2944. begin
  2945. if FKernelMode in [kmTableNearest, kmTableLinear] then
  2946. FWeightTable.Free;
  2947. inherited;
  2948. end;
  2949. procedure TKernelResampler.PrepareSampling;
  2950. var
  2951. I, J, W, Weight, Dev: Integer;
  2952. Fraction: TFloat;
  2953. KernelPtr: PKernelEntry;
  2954. begin
  2955. inherited;
  2956. FOuterColor := Bitmap.OuterColor;
  2957. W := Ceil(FKernel.GetWidth);
  2958. if FKernelMode in [kmTableNearest, kmTableLinear] then
  2959. begin
  2960. FWeightTable := TIntegerMap.Create(W * 2 + 1, FTableSize + 1);
  2961. for I := 0 to FTableSize do
  2962. begin
  2963. Fraction := I / (FTableSize - 1);
  2964. KernelPtr := @FWeightTable.ValPtr[W - MAX_KERNEL_WIDTH, I]^;
  2965. Dev := - 256;
  2966. for J := -W to W do
  2967. begin
  2968. Weight := Round(FKernel.Filter(J + Fraction) * 256);
  2969. KernelPtr[J] := Weight;
  2970. Inc(Dev, Weight);
  2971. end;
  2972. Dec(KernelPtr[0], Dev);
  2973. end;
  2974. end;
  2975. end;
  2976. { TCustomBitmap32NearestResampler }
  2977. function TNearestResampler.GetSampleInt(X, Y: Integer): TColor32;
  2978. begin
  2979. Result := FGetSampleInt(X, Y);
  2980. end;
  2981. function TNearestResampler.GetSampleFixed(X, Y: TFixed): TColor32;
  2982. begin
  2983. Result := FGetSampleInt(FixedRound(X), FixedRound(Y));
  2984. end;
  2985. function TNearestResampler.GetSampleFloat(X, Y: TFloat): TColor32;
  2986. begin
  2987. Result := FGetSampleInt(Round(X), Round(Y));
  2988. end;
  2989. function TNearestResampler.GetWidth: TFloat;
  2990. begin
  2991. Result := 1;
  2992. end;
  2993. function TNearestResampler.GetPixelTransparentEdge(X,Y: Integer): TColor32;
  2994. var
  2995. I, J: Integer;
  2996. begin
  2997. with Bitmap, Bitmap.ClipRect do
  2998. begin
  2999. I := Clamp(X, Left, Right - 1);
  3000. J := Clamp(Y, Top, Bottom - 1);
  3001. Result := Pixel[I, J];
  3002. if (I <> X) or (J <> Y) then
  3003. Result := Result and $00FFFFFF;
  3004. end;
  3005. end;
  3006. procedure TNearestResampler.PrepareSampling;
  3007. begin
  3008. inherited;
  3009. case PixelAccessMode of
  3010. pamUnsafe: FGetSampleInt := TCustomBitmap32Access(Bitmap).GetPixel;
  3011. pamSafe: FGetSampleInt := TCustomBitmap32Access(Bitmap).GetPixelS;
  3012. pamWrap: FGetSampleInt := TCustomBitmap32Access(Bitmap).GetPixelW;
  3013. pamTransparentEdge: FGetSampleInt := GetPixelTransparentEdge;
  3014. end;
  3015. end;
  3016. procedure TNearestResampler.Resample(
  3017. Dst: TCustomBitmap32; DstRect: TRect; DstClip: TRect;
  3018. Src: TCustomBitmap32; SrcRect: TRect;
  3019. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
  3020. begin
  3021. StretchNearest(Dst, DstRect, DstClip, Src, SrcRect, CombineOp, CombineCallBack)
  3022. end;
  3023. { TCustomBitmap32LinearResampler }
  3024. constructor TLinearResampler.Create;
  3025. begin
  3026. inherited;
  3027. FLinearKernel := TLinearKernel.Create;
  3028. end;
  3029. destructor TLinearResampler.Destroy;
  3030. begin
  3031. FLinearKernel.Free;
  3032. inherited Destroy;
  3033. end;
  3034. function TLinearResampler.GetSampleFixed(X, Y: TFixed): TColor32;
  3035. begin
  3036. Result := FGetSampleFixed(X, Y);
  3037. end;
  3038. function TLinearResampler.GetSampleFloat(X, Y: TFloat): TColor32;
  3039. begin
  3040. Result := FGetSampleFixed(Round(X * FixedOne), Round(Y * FixedOne));
  3041. end;
  3042. function TLinearResampler.GetPixelTransparentEdge(X, Y: TFixed): TColor32;
  3043. var
  3044. I, J, X1, X2, Y1, Y2, WX, R, B: TFixed;
  3045. C1, C2, C3, C4: TColor32;
  3046. PSrc: PColor32Array;
  3047. begin
  3048. with TCustomBitmap32Access(Bitmap), Bitmap.ClipRect do
  3049. begin
  3050. R := Right - 1;
  3051. B := Bottom - 1;
  3052. I := TFixedRec(X).Int;
  3053. J := TFixedRec(Y).Int;
  3054. if (I >= Left) and (J >= Top) and (I < R) and (J < B) then
  3055. begin //Safe
  3056. Result := GET_T256(X shr 8, Y shr 8);
  3057. EMMS;
  3058. end
  3059. else
  3060. if (I >= Left - 1) and (J >= Top - 1) and (I <= R) and (J <= B) then
  3061. begin //Near edge, on edge or outside
  3062. X1 := Clamp(I, R);
  3063. X2 := Clamp(I + Sign(X), R);
  3064. Y1 := Clamp(J, B) * Width;
  3065. Y2 := Clamp(J + Sign(Y), B) * Width;
  3066. PSrc := @Bits[0];
  3067. C1 := PSrc[X1 + Y1];
  3068. C2 := PSrc[X2 + Y1];
  3069. C3 := PSrc[X1 + Y2];
  3070. C4 := PSrc[X2 + Y2];
  3071. if X <= Fixed(Left) then
  3072. begin
  3073. C1 := C1 and $00FFFFFF;
  3074. C3 := C3 and $00FFFFFF;
  3075. end
  3076. else if I = R then
  3077. begin
  3078. C2 := C2 and $00FFFFFF;
  3079. C4 := C4 and $00FFFFFF;
  3080. end;
  3081. if Y <= Fixed(Top) then
  3082. begin
  3083. C1 := C1 and $00FFFFFF;
  3084. C2 := C2 and $00FFFFFF;
  3085. end
  3086. else if J = B then
  3087. begin
  3088. C3 := C3 and $00FFFFFF;
  3089. C4 := C4 and $00FFFFFF;
  3090. end;
  3091. WX := GAMMA_TABLE[((X shr 8) and $FF) xor $FF];
  3092. Result := CombineReg(CombineReg(C1, C2, WX),
  3093. CombineReg(C3, C4, WX),
  3094. GAMMA_TABLE[((Y shr 8) and $FF) xor $FF]);
  3095. EMMS;
  3096. end
  3097. else
  3098. Result := 0; //Nothing really makes sense here, return zero
  3099. end;
  3100. end;
  3101. procedure TLinearResampler.PrepareSampling;
  3102. begin
  3103. inherited;
  3104. case PixelAccessMode of
  3105. pamUnsafe: FGetSampleFixed := TCustomBitmap32Access(Bitmap).GetPixelX;
  3106. pamSafe: FGetSampleFixed := TCustomBitmap32Access(Bitmap).GetPixelXS;
  3107. pamWrap: FGetSampleFixed := TCustomBitmap32Access(Bitmap).GetPixelXW;
  3108. pamTransparentEdge: FGetSampleFixed := GetPixelTransparentEdge;
  3109. end;
  3110. end;
  3111. function TLinearResampler.GetWidth: TFloat;
  3112. begin
  3113. Result := 1;
  3114. end;
  3115. procedure TLinearResampler.Resample(
  3116. Dst: TCustomBitmap32; DstRect: TRect; DstClip: TRect;
  3117. Src: TCustomBitmap32; SrcRect: TRect;
  3118. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
  3119. var
  3120. SrcW, SrcH: TFloat;
  3121. DstW, DstH: Integer;
  3122. begin
  3123. SrcW := SrcRect.Right - SrcRect.Left;
  3124. SrcH := SrcRect.Bottom - SrcRect.Top;
  3125. DstW := DstRect.Right - DstRect.Left;
  3126. DstH := DstRect.Bottom - DstRect.Top;
  3127. if (DstW > SrcW) and (DstH > SrcH) and (SrcW > 1) and (SrcH > 1) then
  3128. StretchHorzStretchVertLinear(Dst, DstRect, DstClip, Src, SrcRect, CombineOp,
  3129. CombineCallBack)
  3130. else
  3131. GR32_Resamplers.Resample(Dst, DstRect, DstClip, Src, SrcRect, FLinearKernel,
  3132. CombineOp, CombineCallBack);
  3133. end;
  3134. procedure TDraftResampler.Resample(
  3135. Dst: TCustomBitmap32; DstRect: TRect; DstClip: TRect;
  3136. Src: TCustomBitmap32; SrcRect: TRect;
  3137. CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
  3138. begin
  3139. DraftResample(Dst, DstRect, DstClip, Src, SrcRect, FLinearKernel, CombineOp,
  3140. CombineCallBack)
  3141. end;
  3142. { TTransformer }
  3143. function TTransformer.GetSampleInt(X, Y: Integer): TColor32;
  3144. var
  3145. U, V: TFixed;
  3146. begin
  3147. FTransformationReverseTransformFixed(X * FixedOne + FixedHalf,
  3148. Y * FixedOne + FixedHalf, U, V);
  3149. Result := FGetSampleFixed(U - FixedHalf, V - FixedHalf);
  3150. end;
  3151. function TTransformer.GetSampleFixed(X, Y: TFixed): TColor32;
  3152. var
  3153. U, V: TFixed;
  3154. begin
  3155. FTransformationReverseTransformFixed(X + FixedHalf, Y + FixedHalf, U, V);
  3156. Result := FGetSampleFixed(U - FixedHalf, V - FixedHalf);
  3157. end;
  3158. function TTransformer.GetSampleFloat(X, Y: TFloat): TColor32;
  3159. var
  3160. U, V: TFloat;
  3161. begin
  3162. FTransformationReverseTransformFloat(X + 0.5, Y + 0.5, U, V);
  3163. Result := FGetSampleFloat(U - 0.5, V - 0.5);
  3164. end;
  3165. procedure TTransformer.SetTransformation(const Value: TTransformation);
  3166. begin
  3167. FTransformation := Value;
  3168. if Assigned(Value) then
  3169. begin
  3170. FTransformationReverseTransformInt := TTransformationAccess(FTransformation).ReverseTransformInt;
  3171. FTransformationReverseTransformFixed := TTransformationAccess(FTransformation).ReverseTransformFixed;
  3172. FTransformationReverseTransformFloat := TTransformationAccess(FTransformation).ReverseTransformFloat;
  3173. end;
  3174. end;
  3175. constructor TTransformer.Create(ASampler: TCustomSampler; ATransformation: TTransformation);
  3176. begin
  3177. inherited Create(ASampler);
  3178. Transformation := ATransformation;
  3179. end;
  3180. procedure TTransformer.PrepareSampling;
  3181. begin
  3182. inherited;
  3183. with TTransformationAccess(FTransformation) do
  3184. if not TransformValid then
  3185. PrepareTransform;
  3186. end;
  3187. function TTransformer.GetSampleBounds: TFloatRect;
  3188. begin
  3189. IntersectRect(Result, inherited GetSampleBounds, FTransformation.SrcRect);
  3190. Result := FTransformation.GetTransformedBounds(Result);
  3191. end;
  3192. function TTransformer.HasBounds: Boolean;
  3193. begin
  3194. Result := FTransformation.HasTransformedBounds and inherited HasBounds;
  3195. end;
  3196. { TSuperSampler }
  3197. constructor TSuperSampler.Create(Sampler: TCustomSampler);
  3198. begin
  3199. inherited Create(Sampler);
  3200. FSamplingX := 4;
  3201. FSamplingY := 4;
  3202. SamplingX := 4;
  3203. SamplingY := 4;
  3204. end;
  3205. function TSuperSampler.GetSampleFixed(X, Y: TFixed): TColor32;
  3206. var
  3207. I, J: Integer;
  3208. dX, dY, tX: TFixed;
  3209. Buffer: TBufferEntry;
  3210. begin
  3211. Buffer := EMPTY_ENTRY;
  3212. tX := X + FOffsetX;
  3213. Inc(Y, FOffsetY);
  3214. dX := FDistanceX;
  3215. dY := FDistanceY;
  3216. for J := 1 to FSamplingY do
  3217. begin
  3218. X := tX;
  3219. for I := 1 to FSamplingX do
  3220. begin
  3221. IncBuffer(Buffer, FGetSampleFixed(X, Y));
  3222. Inc(X, dX);
  3223. end;
  3224. Inc(Y, dY);
  3225. end;
  3226. MultiplyBuffer(Buffer, FScale);
  3227. Result := BufferToColor32(Buffer, 16);
  3228. end;
  3229. procedure TSuperSampler.SetSamplingX(const Value: TSamplingRange);
  3230. begin
  3231. FSamplingX := Value;
  3232. FDistanceX := Fixed(1 / Value);
  3233. FOffsetX := Fixed(((1 / Value) - 1) * 0.5); // replaced "/2" by "*0.5"
  3234. FScale := Fixed(1 / (FSamplingX * FSamplingY));
  3235. end;
  3236. procedure TSuperSampler.SetSamplingY(const Value: TSamplingRange);
  3237. begin
  3238. FSamplingY := Value;
  3239. FDistanceY := Fixed(1 / Value);
  3240. FOffsetY := Fixed(((1 / Value) - 1) * 0.5); // replaced "/2" by "*0.5"
  3241. FScale := Fixed(1 / (FSamplingX * FSamplingY));
  3242. end;
  3243. { TAdaptiveSuperSampler }
  3244. function TAdaptiveSuperSampler.CompareColors(C1, C2: TColor32): Boolean;
  3245. var
  3246. Diff: TColor32Entry;
  3247. begin
  3248. Diff.ARGB := ColorDifference(C1, C2);
  3249. Result := FTolerance < Diff.R + Diff.G + Diff.B;
  3250. end;
  3251. constructor TAdaptiveSuperSampler.Create(Sampler: TCustomSampler);
  3252. begin
  3253. inherited Create(Sampler);
  3254. Level := 4;
  3255. Tolerance := 256;
  3256. end;
  3257. function TAdaptiveSuperSampler.DoRecurse(X, Y, Offset: TFixed; const A, B,
  3258. C, D, E: TColor32): TColor32;
  3259. var
  3260. C1, C2, C3, C4: TColor32;
  3261. begin
  3262. C1 := QuadrantColor(A, E, X - Offset, Y - Offset, Offset, RecurseAC);
  3263. C2 := QuadrantColor(B, E, X + Offset, Y - Offset, Offset, RecurseBD);
  3264. C3 := QuadrantColor(E, C, X + Offset, Y + Offset, Offset, RecurseAC);
  3265. C4 := QuadrantColor(E, D, X - Offset, Y + Offset, Offset, RecurseBD);
  3266. Result := ColorAverage(ColorAverage(C1, C2), ColorAverage(C3, C4));
  3267. end;
  3268. function TAdaptiveSuperSampler.GetSampleFixed(X, Y: TFixed): TColor32;
  3269. var
  3270. A, B, C, D, E: TColor32;
  3271. const
  3272. FIXED_HALF = 32768;
  3273. begin
  3274. A := FGetSampleFixed(X - FIXED_HALF, Y - FIXED_HALF);
  3275. B := FGetSampleFixed(X + FIXED_HALF, Y - FIXED_HALF);
  3276. C := FGetSampleFixed(X + FIXED_HALF, Y + FIXED_HALF);
  3277. D := FGetSampleFixed(X - FIXED_HALF, Y + FIXED_HALF);
  3278. E := FGetSampleFixed(X, Y);
  3279. Result := Self.DoRecurse(X, Y, 16384, A, B, C, D, E);
  3280. EMMS;
  3281. end;
  3282. function TAdaptiveSuperSampler.QuadrantColor(const C1, C2: TColor32; X, Y,
  3283. Offset: TFixed; Proc: TRecurseProc): TColor32;
  3284. begin
  3285. if CompareColors(C1, C2) and (Offset >= FMinOffset) then
  3286. Result := Proc(X, Y, Offset, C1, C2)
  3287. else
  3288. Result := ColorAverage(C1, C2);
  3289. end;
  3290. function TAdaptiveSuperSampler.RecurseAC(X, Y, Offset: TFixed; const A,
  3291. C: TColor32): TColor32;
  3292. var
  3293. B, D, E: TColor32;
  3294. begin
  3295. EMMS;
  3296. B := FGetSampleFixed(X + Offset, Y - Offset);
  3297. D := FGetSampleFixed(X - Offset, Y + Offset);
  3298. E := FGetSampleFixed(X, Y);
  3299. Result := DoRecurse(X, Y, Offset shr 1, A, B, C, D, E);
  3300. end;
  3301. function TAdaptiveSuperSampler.RecurseBD(X, Y, Offset: TFixed; const B,
  3302. D: TColor32): TColor32;
  3303. var
  3304. A, C, E: TColor32;
  3305. begin
  3306. EMMS;
  3307. A := FGetSampleFixed(X - Offset, Y - Offset);
  3308. C := FGetSampleFixed(X + Offset, Y + Offset);
  3309. E := FGetSampleFixed(X, Y);
  3310. Result := DoRecurse(X, Y, Offset shr 1, A, B, C, D, E);
  3311. end;
  3312. procedure TAdaptiveSuperSampler.SetLevel(const Value: Integer);
  3313. begin
  3314. FLevel := Value;
  3315. FMinOffset := Fixed(1 / (1 shl Value));
  3316. end;
  3317. { TPatternSampler }
  3318. destructor TPatternSampler.Destroy;
  3319. begin
  3320. if Assigned(FPattern) then FPattern := nil;
  3321. inherited;
  3322. end;
  3323. function TPatternSampler.GetSampleFixed(X, Y: TFixed): TColor32;
  3324. var
  3325. Points: TArrayOfFixedPoint;
  3326. P: PFixedPoint;
  3327. I, PY: Integer;
  3328. Buffer: TBufferEntry;
  3329. GetSample: TGetSampleFixed;
  3330. WrapProcHorz: TWrapProc;
  3331. begin
  3332. GetSample := FSampler.GetSampleFixed;
  3333. PY := WrapProcVert(TFixedRec(Y).Int, High(FPattern));
  3334. I := High(FPattern[PY]);
  3335. WrapProcHorz := GetOptimalWrap(I);
  3336. Points := FPattern[PY][WrapProcHorz(TFixedRec(X).Int, I)];
  3337. Buffer := EMPTY_ENTRY;
  3338. P := @Points[0];
  3339. for I := 0 to High(Points) do
  3340. begin
  3341. IncBuffer(Buffer, GetSample(P.X + X, P.Y + Y));
  3342. Inc(P);
  3343. end;
  3344. MultiplyBuffer(Buffer, FixedOne div Length(Points));
  3345. Result := BufferToColor32(Buffer, 16);
  3346. end;
  3347. procedure TPatternSampler.SetPattern(const Value: TFixedSamplePattern);
  3348. begin
  3349. if Assigned(Value) then
  3350. begin
  3351. FPattern := nil;
  3352. FPattern := Value;
  3353. WrapProcVert := GetOptimalWrap(High(FPattern));
  3354. end;
  3355. end;
  3356. function JitteredPattern(XRes, YRes: Integer): TArrayOfFixedPoint;
  3357. var
  3358. I, J: Integer;
  3359. begin
  3360. SetLength(Result, XRes * YRes);
  3361. for I := 0 to XRes - 1 do
  3362. for J := 0 to YRes - 1 do
  3363. with Result[I + J * XRes] do
  3364. begin
  3365. X := (Random(65536) + I * 65536) div XRes - 32768;
  3366. Y := (Random(65536) + J * 65536) div YRes - 32768;
  3367. end;
  3368. end;
  3369. function CreateJitteredPattern(TileWidth, TileHeight, SamplesX, SamplesY: Integer): TFixedSamplePattern;
  3370. var
  3371. I, J: Integer;
  3372. begin
  3373. SetLength(Result, TileHeight, TileWidth);
  3374. for I := 0 to TileWidth - 1 do
  3375. for J := 0 to TileHeight - 1 do
  3376. Result[J][I] := JitteredPattern(SamplesX, SamplesY);
  3377. end;
  3378. procedure RegisterResampler(ResamplerClass: TCustomResamplerClass);
  3379. begin
  3380. if not Assigned(ResamplerList) then ResamplerList := TClassList.Create;
  3381. ResamplerList.ADD(ResamplerClass);
  3382. end;
  3383. procedure RegisterKernel(KernelClass: TCustomKernelClass);
  3384. begin
  3385. if not Assigned(KernelList) then KernelList := TClassList.Create;
  3386. KernelList.ADD(KernelClass);
  3387. end;
  3388. { TNestedSampler }
  3389. procedure TNestedSampler.AssignTo(Dst: TPersistent);
  3390. begin
  3391. if Dst is TNestedSampler then
  3392. SmartAssign(Self, Dst)
  3393. else
  3394. inherited;
  3395. end;
  3396. constructor TNestedSampler.Create(ASampler: TCustomSampler);
  3397. begin
  3398. inherited Create;
  3399. Sampler := ASampler;
  3400. end;
  3401. procedure TNestedSampler.FinalizeSampling;
  3402. begin
  3403. if not Assigned(FSampler) then
  3404. raise ENestedException.Create(SSamplerNil)
  3405. else
  3406. FSampler.FinalizeSampling;
  3407. end;
  3408. {$WARNINGS OFF}
  3409. function TNestedSampler.GetSampleBounds: TFloatRect;
  3410. begin
  3411. if not Assigned(FSampler) then
  3412. raise ENestedException.Create(SSamplerNil)
  3413. else
  3414. Result := FSampler.GetSampleBounds;
  3415. end;
  3416. function TNestedSampler.HasBounds: Boolean;
  3417. begin
  3418. if not Assigned(FSampler) then
  3419. raise ENestedException.Create(SSamplerNil)
  3420. else
  3421. Result := FSampler.HasBounds;
  3422. end;
  3423. {$WARNINGS ON}
  3424. procedure TNestedSampler.PrepareSampling;
  3425. begin
  3426. if not Assigned(FSampler) then
  3427. raise ENestedException.Create(SSamplerNil)
  3428. else
  3429. FSampler.PrepareSampling;
  3430. end;
  3431. procedure TNestedSampler.SetSampler(const Value: TCustomSampler);
  3432. begin
  3433. FSampler := Value;
  3434. if Assigned(Value) then
  3435. begin
  3436. FGetSampleInt := FSampler.GetSampleInt;
  3437. FGetSampleFixed := FSampler.GetSampleFixed;
  3438. FGetSampleFloat := FSampler.GetSampleFloat;
  3439. end;
  3440. end;
  3441. { TKernelSampler }
  3442. function TKernelSampler.ConvertBuffer(var Buffer: TBufferEntry): TColor32;
  3443. begin
  3444. Buffer.A := Constrain(Buffer.A, 0, $FFFF);
  3445. Buffer.R := Constrain(Buffer.R, 0, $FFFF);
  3446. Buffer.G := Constrain(Buffer.G, 0, $FFFF);
  3447. Buffer.B := Constrain(Buffer.B, 0, $FFFF);
  3448. Result := BufferToColor32(Buffer, 8);
  3449. end;
  3450. constructor TKernelSampler.Create(ASampler: TCustomSampler);
  3451. begin
  3452. inherited;
  3453. FKernel := TIntegerMap.Create;
  3454. FStartEntry := EMPTY_ENTRY;
  3455. end;
  3456. destructor TKernelSampler.Destroy;
  3457. begin
  3458. FKernel.Free;
  3459. inherited;
  3460. end;
  3461. function TKernelSampler.GetSampleFixed(X, Y: TFixed): TColor32;
  3462. var
  3463. I, J: Integer;
  3464. Buffer: TBufferEntry;
  3465. begin
  3466. X := X + FCenterX shl 16;
  3467. Y := Y + FCenterY shl 16;
  3468. Buffer := FStartEntry;
  3469. for I := 0 to FKernel.Width - 1 do
  3470. for J := 0 to FKernel.Height - 1 do
  3471. UpdateBuffer(Buffer, FGetSampleFixed(X - I shl 16, Y - J shl 16), FKernel[I, J]);
  3472. Result := ConvertBuffer(Buffer);
  3473. end;
  3474. function TKernelSampler.GetSampleInt(X, Y: Integer): TColor32;
  3475. var
  3476. I, J: Integer;
  3477. Buffer: TBufferEntry;
  3478. begin
  3479. X := X + FCenterX;
  3480. Y := Y + FCenterY;
  3481. Buffer := FStartEntry;
  3482. for I := 0 to FKernel.Width - 1 do
  3483. for J := 0 to FKernel.Height - 1 do
  3484. UpdateBuffer(Buffer, FGetSampleInt(X - I, Y - J), FKernel[I, J]);
  3485. Result := ConvertBuffer(Buffer);
  3486. end;
  3487. { TConvolver }
  3488. procedure TConvolver.UpdateBuffer(var Buffer: TBufferEntry; Color: TColor32;
  3489. Weight: Integer);
  3490. begin
  3491. with TColor32Entry(Color) do
  3492. begin
  3493. Inc(Buffer.A, A * Weight);
  3494. Inc(Buffer.R, R * Weight);
  3495. Inc(Buffer.G, G * Weight);
  3496. Inc(Buffer.B, B * Weight);
  3497. end;
  3498. end;
  3499. { TDilater }
  3500. procedure TDilater.UpdateBuffer(var Buffer: TBufferEntry; Color: TColor32;
  3501. Weight: Integer);
  3502. begin
  3503. with TColor32Entry(Color) do
  3504. begin
  3505. Buffer.A := Max(Buffer.A, A + Weight);
  3506. Buffer.R := Max(Buffer.R, R + Weight);
  3507. Buffer.G := Max(Buffer.G, G + Weight);
  3508. Buffer.B := Max(Buffer.B, B + Weight);
  3509. end;
  3510. end;
  3511. { TEroder }
  3512. constructor TEroder.Create(ASampler: TCustomSampler);
  3513. const
  3514. START_ENTRY: TBufferEntry = (B: $FFFF; G: $FFFF; R: $FFFF; A: $FFFF);
  3515. begin
  3516. inherited;
  3517. FStartEntry := START_ENTRY;
  3518. end;
  3519. procedure TEroder.UpdateBuffer(var Buffer: TBufferEntry; Color: TColor32;
  3520. Weight: Integer);
  3521. begin
  3522. with TColor32Entry(Color) do
  3523. begin
  3524. Buffer.A := Min(Buffer.A, A - Weight);
  3525. Buffer.R := Min(Buffer.R, R - Weight);
  3526. Buffer.G := Min(Buffer.G, G - Weight);
  3527. Buffer.B := Min(Buffer.B, B - Weight);
  3528. end;
  3529. end;
  3530. { TExpander }
  3531. procedure TExpander.UpdateBuffer(var Buffer: TBufferEntry; Color: TColor32;
  3532. Weight: Integer);
  3533. begin
  3534. with TColor32Entry(Color) do
  3535. begin
  3536. Buffer.A := Max(Buffer.A, A * Weight);
  3537. Buffer.R := Max(Buffer.R, R * Weight);
  3538. Buffer.G := Max(Buffer.G, G * Weight);
  3539. Buffer.B := Max(Buffer.B, B * Weight);
  3540. end;
  3541. end;
  3542. { TContracter }
  3543. function TContracter.GetSampleFixed(X, Y: TFixed): TColor32;
  3544. begin
  3545. Result := ColorSub(FMaxWeight, inherited GetSampleFixed(X, Y));
  3546. end;
  3547. function TContracter.GetSampleInt(X, Y: Integer): TColor32;
  3548. begin
  3549. Result := ColorSub(FMaxWeight, inherited GetSampleInt(X, Y));
  3550. end;
  3551. procedure TContracter.PrepareSampling;
  3552. var
  3553. I, J, W: Integer;
  3554. begin
  3555. W := Low(Integer);
  3556. for I := 0 to FKernel.Width - 1 do
  3557. for J := 0 to FKernel.Height - 1 do
  3558. W := Max(W, FKernel[I, J]);
  3559. if W > 255 then W := 255;
  3560. FMaxWeight := Gray32(W, W);
  3561. end;
  3562. procedure TContracter.UpdateBuffer(var Buffer: TBufferEntry; Color: TColor32;
  3563. Weight: Integer);
  3564. begin
  3565. inherited UpdateBuffer(Buffer, Color xor $FFFFFFFF, Weight);
  3566. end;
  3567. { TMorphologicalSampler }
  3568. function TMorphologicalSampler.ConvertBuffer(
  3569. var Buffer: TBufferEntry): TColor32;
  3570. begin
  3571. Buffer.A := Constrain(Buffer.A, 0, $FF);
  3572. Buffer.R := Constrain(Buffer.R, 0, $FF);
  3573. Buffer.G := Constrain(Buffer.G, 0, $FF);
  3574. Buffer.B := Constrain(Buffer.B, 0, $FF);
  3575. with TColor32Entry(Result) do
  3576. begin
  3577. A := Buffer.A;
  3578. R := Buffer.R;
  3579. G := Buffer.G;
  3580. B := Buffer.B;
  3581. end;
  3582. end;
  3583. { TSelectiveConvolver }
  3584. function TSelectiveConvolver.ConvertBuffer(var Buffer: TBufferEntry): TColor32;
  3585. begin
  3586. with TColor32Entry(Result) do
  3587. begin
  3588. A := Buffer.A div FWeightSum.A;
  3589. R := Buffer.R div FWeightSum.R;
  3590. G := Buffer.G div FWeightSum.G;
  3591. B := Buffer.B div FWeightSum.B;
  3592. end;
  3593. end;
  3594. constructor TSelectiveConvolver.Create(ASampler: TCustomSampler);
  3595. begin
  3596. inherited;
  3597. FDelta := 30;
  3598. end;
  3599. function TSelectiveConvolver.GetSampleFixed(X, Y: TFixed): TColor32;
  3600. begin
  3601. FRefColor := FGetSampleFixed(X, Y);
  3602. FWeightSum := EMPTY_ENTRY;
  3603. Result := inherited GetSampleFixed(X, Y);
  3604. end;
  3605. function TSelectiveConvolver.GetSampleInt(X, Y: Integer): TColor32;
  3606. begin
  3607. FRefColor := FGetSampleInt(X, Y);
  3608. FWeightSum := EMPTY_ENTRY;
  3609. Result := inherited GetSampleInt(X, Y);
  3610. end;
  3611. procedure TSelectiveConvolver.UpdateBuffer(var Buffer: TBufferEntry;
  3612. Color: TColor32; Weight: Integer);
  3613. begin
  3614. with TColor32Entry(Color) do
  3615. begin
  3616. if Abs(TColor32Entry(FRefColor).A - A) <= FDelta then
  3617. begin
  3618. Inc(Buffer.A, A * Weight);
  3619. Inc(FWeightSum.A, Weight);
  3620. end;
  3621. if Abs(TColor32Entry(FRefColor).R - R) <= FDelta then
  3622. begin
  3623. Inc(Buffer.R, R * Weight);
  3624. Inc(FWeightSum.R, Weight);
  3625. end;
  3626. if Abs(TColor32Entry(FRefColor).G - G) <= FDelta then
  3627. begin
  3628. Inc(Buffer.G, G * Weight);
  3629. Inc(FWeightSum.G, Weight);
  3630. end;
  3631. if Abs(TColor32Entry(FRefColor).B - B) <= FDelta then
  3632. begin
  3633. Inc(Buffer.B, B * Weight);
  3634. Inc(FWeightSum.B, Weight);
  3635. end;
  3636. end;
  3637. end;
  3638. {CPU target and feature function templates}
  3639. const
  3640. FID_BLOCKAVERAGE = 0;
  3641. FID_INTERPOLATOR = 1;
  3642. var
  3643. Registry: TFunctionRegistry;
  3644. procedure RegisterBindings;
  3645. begin
  3646. Registry := NewRegistry('GR32_Resamplers bindings');
  3647. Registry.RegisterBinding(FID_BLOCKAVERAGE, @@BlockAverage);
  3648. Registry.RegisterBinding(FID_INTERPOLATOR, @@Interpolator);
  3649. Registry.ADD(FID_BLOCKAVERAGE, @BlockAverage_Pas);
  3650. Registry.ADD(FID_INTERPOLATOR, @Interpolator_Pas);
  3651. {$IFNDEF PUREPASCAL}
  3652. Registry.ADD(FID_BLOCKAVERAGE, @BlockAverage_MMX, [ciMMX]);
  3653. {$IFDEF USE_3DNOW}
  3654. Registry.ADD(FID_BLOCKAVERAGE, @BlockAverage_3DNow, [ci3DNow]);
  3655. {$ENDIF}
  3656. Registry.ADD(FID_BLOCKAVERAGE, @BlockAverage_SSE2, [ciSSE2]);
  3657. Registry.ADD(FID_INTERPOLATOR, @Interpolator_MMX, [ciMMX, ciSSE]);
  3658. Registry.ADD(FID_INTERPOLATOR, @Interpolator_SSE2, [ciSSE2]);
  3659. {$ENDIF}
  3660. Registry.RebindAll;
  3661. end;
  3662. initialization
  3663. RegisterBindings;
  3664. { Register resamplers }
  3665. RegisterResampler(TNearestResampler);
  3666. RegisterResampler(TLinearResampler);
  3667. RegisterResampler(TDraftResampler);
  3668. RegisterResampler(TKernelResampler);
  3669. { Register kernels }
  3670. RegisterKernel(TBoxKernel);
  3671. RegisterKernel(TLinearKernel);
  3672. RegisterKernel(TCosineKernel);
  3673. RegisterKernel(TSplineKernel);
  3674. RegisterKernel(TCubicKernel);
  3675. RegisterKernel(TMitchellKernel);
  3676. RegisterKernel(TAlbrechtKernel);
  3677. RegisterKernel(TLanczosKernel);
  3678. RegisterKernel(TGaussianKernel);
  3679. RegisterKernel(TBlackmanKernel);
  3680. RegisterKernel(THannKernel);
  3681. RegisterKernel(THammingKernel);
  3682. RegisterKernel(TSinshKernel);
  3683. RegisterKernel(THermiteKernel);
  3684. finalization
  3685. ResamplerList.Free;
  3686. KernelList.Free;
  3687. end.