GR32_Resamplers.pas 127 KB

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