PageRenderTime 70ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/Graphics32/Source/GR32_Resamplers.pas

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