PageRenderTime 70ms CodeModel.GetById 29ms 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

Large files files are truncated, but you can click here to view the full file

  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 :

Large files files are truncated, but you can click here to view the full file