MainUnit.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. unit MainUnit;
  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 Resamplers Example
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Michael Hansen <[email protected]>
  26. * Mattias Andersson <[email protected]>
  27. * (parts of this example were taken from the previously published example,
  28. * FineResample Example by Alex A. Denisov)
  29. *
  30. * Portions created by the Initial Developer are Copyright (C) 2000-2005
  31. * the Initial Developer. All Rights Reserved.
  32. *
  33. * Contributor(s):
  34. *
  35. * Christian Budde (added parametrisation for some kernel resamplers)
  36. *
  37. * ***** END LICENSE BLOCK ***** *)
  38. interface
  39. {$include GR32.inc}
  40. uses
  41. {$IFNDEF FPC} Windows, {$ELSE} LCLIntf, LCLType, LResources, {$ENDIF}
  42. SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls,
  43. ComCtrls,
  44. GR32,
  45. GR32_Image,
  46. GR32_RangeBars,
  47. GR32_Resamplers;
  48. type
  49. TFrmResamplersExample = class(TForm)
  50. ImagePattern: TImage32;
  51. ComboBoxPixelAccessMode: TComboBox;
  52. GaugeBarParameter: TGaugeBar;
  53. GaugeBarTableSize: TGaugeBar;
  54. ComboBoxKernelClassName: TComboBox;
  55. ComboBoxKernelMode: TComboBox;
  56. LblKernelClass: TLabel;
  57. LblKernelMode: TLabel;
  58. LblParameter: TLabel;
  59. LblPixelAccessMode: TLabel;
  60. LblResamplersClass: TLabel;
  61. LblTableSize: TLabel;
  62. LblWrapMode: TLabel;
  63. PageControl: TPageControl;
  64. PnlKernelProperties: TPanel;
  65. PanelKernel: TPanel;
  66. PnlResampler: TPanel;
  67. PnlResamplerProperties: TPanel;
  68. ComboBoxResamplerClassName: TComboBox;
  69. PaintBoxResampling: TPaintBox32;
  70. TabResampling: TTabSheet;
  71. SidePanel: TPanel;
  72. StatusBar: TStatusBar;
  73. TabManual: TTabSheet;
  74. TabKernel: TTabSheet;
  75. ComboBoxWrapMode: TComboBox;
  76. PaintBoxCurve: TPaintBox32;
  77. TimerTableSize: TTimer;
  78. TimerParameter: TTimer;
  79. TabStretchTransfer: TTabSheet;
  80. PaintBoxStretchTransfer: TPaintBox32;
  81. procedure ImagePatternResize(Sender: TObject);
  82. procedure ComboBoxResamplerClassNameChange(Sender: TObject);
  83. procedure ComboBoxPixelAccessModeChange(Sender: TObject);
  84. procedure ComboBoxKernelClassNameChange(Sender: TObject);
  85. procedure ComboBoxKernelModeChange(Sender: TObject);
  86. procedure GaugeBarParameterChange(Sender: TObject);
  87. procedure GaugeBarTableSizeChange(Sender: TObject);
  88. procedure PaintBoxStretchTransferPaintBuffer(Sender: TObject);
  89. procedure PaintBoxResamplingPaintBuffer(Sender: TObject);
  90. procedure PaintBoxCurvePaintBuffer(Sender: TObject);
  91. procedure TimerTableSizeTimer(Sender: TObject);
  92. procedure TimerParameterTimer(Sender: TObject);
  93. private
  94. procedure SetKernelParameter(Kernel: TCustomKernel);
  95. procedure GetKernelParameter(Kernel: TCustomKernel);
  96. procedure BuildTestBitmap(Bitmap: TBitmap32);
  97. procedure BitmapPatternChanged(Sender: TObject);
  98. private
  99. FBitmapPattern : TBitmap32;
  100. FBitmapSource: TBitmap32;
  101. FAlbrechtParam: integer;
  102. FGaussianParam: Single;
  103. FSinshParam: Single;
  104. public
  105. constructor Create(AOwner: TComponent); override;
  106. destructor Destroy; override;
  107. end;
  108. var
  109. FrmResamplersExample: TFrmResamplersExample;
  110. implementation
  111. {$R *.dfm}
  112. uses
  113. TypInfo,
  114. Math,
  115. GR32.ImageFormats.JPG,
  116. GR32_Polygons,
  117. GR32_LowLevel,
  118. GR32_System;
  119. { TfmResamplersExample }
  120. constructor TFrmResamplersExample.Create(AOwner: TComponent);
  121. procedure LoadWrapModes;
  122. var
  123. WrapMode: TWrapMode;
  124. s: string;
  125. begin
  126. ComboBoxWrapMode.Items.Clear;
  127. for WrapMode := Low(TWrapMode) to High(TWrapMode) do
  128. begin
  129. s := GetEnumName(TypeInfo(TWrapMode), Ord(WrapMode));
  130. ComboBoxWrapMode.Items.Add(s);
  131. end;
  132. end;
  133. procedure LoadPixelAccessModes;
  134. var
  135. PixelAccessMode: TPixelAccessMode;
  136. s: string;
  137. begin
  138. ComboBoxPixelAccessMode.Items.Clear;
  139. for PixelAccessMode := Low(TPixelAccessMode) to High(TPixelAccessMode) do
  140. begin
  141. s := GetEnumName(TypeInfo(TPixelAccessMode), Ord(PixelAccessMode));
  142. ComboBoxPixelAccessMode.Items.Add(s);
  143. end;
  144. end;
  145. var
  146. Stream: TStream;
  147. begin
  148. inherited;
  149. FBitmapPattern := TBitmap32.Create;
  150. FBitmapPattern.OuterColor := $FFFF7F7F;
  151. FBitmapPattern.OnChange := BitmapPatternChanged;
  152. ImagePattern.Bitmap.OuterColor := FBitmapPattern.OuterColor;
  153. ImagePattern.SetupBitmap;
  154. FBitmapSource := TBitmap32.Create;
  155. // load example image
  156. Stream := TResourceStream.Create(HInstance, 'Iceland', RT_RCDATA);
  157. try
  158. FBitmapSource.LoadFromStream(Stream);
  159. finally
  160. Stream.Free;
  161. end;
  162. ResamplerList.GetClassNames(ComboBoxResamplerClassName.Items);
  163. KernelList.GetClassNames(ComboBoxKernelClassName.Items);
  164. LoadWrapModes;
  165. LoadPixelAccessModes;
  166. PaintBoxResampling.BufferOversize := 0;
  167. PaintBoxStretchTransfer.BufferOversize := 0;
  168. // build 16 x 16 test bitmap
  169. FBitmapPattern.BeginUpdate;
  170. try
  171. BuildTestBitmap(FBitmapPattern);
  172. ComboBoxResamplerClassName.ItemIndex := 0;
  173. ComboBoxResamplerClassNameChange(nil);
  174. ComboBoxPixelAccessMode.ItemIndex := Ord(pamSafe);
  175. ComboBoxWrapMode.ItemIndex := Ord(wmClamp);
  176. ComboBoxPixelAccessModeChange(nil);
  177. ComboBoxKernelClassName.ItemIndex := 0;
  178. ComboBoxKernelClassNameChange(nil);
  179. finally
  180. FBitmapPattern.EndUpdate;
  181. end;
  182. {$ifndef FPC}
  183. ComboBoxResamplerClassName.AutoDropDownWidth := True;
  184. ComboBoxPixelAccessMode.AutoDropDownWidth := True;
  185. ComboBoxWrapMode.AutoDropDownWidth := True;
  186. ComboBoxKernelClassName.AutoDropDownWidth := True;
  187. ComboBoxKernelMode.AutoDropDownWidth := True;
  188. PanelKernel.Margins.SetBounds(0, 4, 0, 0);
  189. PanelKernel.AlignWithMargins := True;
  190. {$endif}
  191. end;
  192. destructor TFrmResamplersExample.Destroy;
  193. begin
  194. FBitmapPattern.Free;
  195. FBitmapSource.Free;
  196. inherited;
  197. end;
  198. (*
  199. ** Build a bitmap with a test pattern for upsampling
  200. *)
  201. procedure TFrmResamplersExample.BuildTestBitmap(Bitmap: TBitmap32);
  202. var
  203. i, j: Integer;
  204. Color: TColor32;
  205. const
  206. CBlackWhite32: array [0..1] of TColor32 = (clBlack32, clWhite32);
  207. begin
  208. Bitmap.SetSize(16, 16);
  209. for i := 0 to 15 do
  210. for j := 0 to 15 do
  211. Bitmap.Pixel[i, j] := CBlackWhite32[(i + j) mod 2];
  212. for i := 0 to 15 do
  213. begin
  214. Color := Gray32(i * 255 div 15);
  215. Bitmap.PixelX[Fixed(i), Fixed( 9)] := Color;
  216. Bitmap.PixelX[Fixed(i), Fixed(10)] := Color;
  217. end;
  218. for i := 0 to 7 do
  219. begin
  220. Color := Gray32(i * 255 div 7);
  221. Bitmap.Pixel[i * 2, 11] := Color;
  222. Bitmap.Pixel[i * 2 + 1, 11] := Color;
  223. Bitmap.Pixel[i * 2, 12] := Color;
  224. Bitmap.Pixel[i * 2 + 1, 12] := Color;
  225. Bitmap.Pixel[i * 2, 13] := Color;
  226. Bitmap.Pixel[i * 2 + 1, 13] := Color;
  227. end;
  228. for i := 1 to 4 do
  229. for j := 1 to 4 do
  230. Bitmap.Pixel[i, j] := $FF5F5F5F;
  231. for i := 2 to 3 do
  232. for j := 2 to 3 do
  233. Bitmap.Pixel[i, j] := $FFAFAFAF;
  234. end;
  235. (*
  236. ** Update kernel with users' parameter value
  237. *)
  238. procedure TFrmResamplersExample.SetKernelParameter(Kernel : TCustomKernel);
  239. begin
  240. if Kernel is TAlbrechtKernel then
  241. begin
  242. TAlbrechtKernel(Kernel).Terms := Round(GaugeBarParameter.Position * 0.1) + 1;
  243. FAlbrechtParam := TAlbrechtKernel(Kernel).Terms;
  244. end else
  245. if Kernel is TGaussianKernel then
  246. begin
  247. TGaussianKernel(Kernel).Sigma := 0.3 + GaugeBarParameter.Position * 0.1;
  248. FGaussianParam := TGaussianKernel(Kernel).Sigma;
  249. end else
  250. if Kernel is TSinshKernel then
  251. begin
  252. TSinshKernel(Kernel).Coeff := 20 / GaugeBarParameter.Position;
  253. FSinshParam := TSinshKernel(Kernel).Coeff;
  254. end;
  255. end;
  256. (*
  257. ** Update kernel with parameter value and update UI
  258. *)
  259. procedure TFrmResamplersExample.GetKernelParameter(Kernel : TCustomKernel);
  260. begin
  261. if Kernel is TAlbrechtKernel then
  262. begin
  263. if (FAlbrechtParam <> 0) then
  264. TAlbrechtKernel(Kernel).Terms := FAlbrechtParam;
  265. GaugeBarParameter.Position := (TAlbrechtKernel(Kernel).Terms - 1) * 10;
  266. end else
  267. if Kernel is TGaussianKernel then
  268. begin
  269. if (FGaussianParam <> 0) then
  270. TGaussianKernel(Kernel).Sigma := FGaussianParam;
  271. GaugeBarParameter.Position := Round((TGaussianKernel(Kernel).Sigma - 0.3) * 10);
  272. end else
  273. if Kernel is TSinshKernel then
  274. begin
  275. if (FSinshParam <> 0) then
  276. TSinshKernel(Kernel).Coeff := FSinshParam;
  277. GaugeBarParameter.Position := Round(20 / TSinshKernel(Kernel).Coeff);
  278. end;
  279. end;
  280. (*
  281. ** Pattern image resized. Rebuild test pattern and redraw resample examples.
  282. *)
  283. procedure TFrmResamplersExample.ImagePatternResize(Sender: TObject);
  284. begin
  285. ImagePattern.SetupBitmap;
  286. BitmapPatternChanged(Self);
  287. end;
  288. (*
  289. ** Redraw resample examples.
  290. *)
  291. procedure TFrmResamplersExample.BitmapPatternChanged(Sender: TObject);
  292. var
  293. X, Y: Integer;
  294. sw, sh: Single;
  295. HasResampled: boolean;
  296. StopWatch: TStopWatch;
  297. begin
  298. sw := FBitmapPattern.Width / ImagePattern.Bitmap.Width;
  299. sh := FBitmapPattern.Height / ImagePattern.Bitmap.Height;
  300. HasResampled := False;
  301. Screen.Cursor := crAppStart;
  302. StopWatch := TStopWatch.StartNew;
  303. if TabResampling.Visible then
  304. begin
  305. PaintBoxResampling.Invalidate;
  306. end else
  307. if TabStretchTransfer.Visible then
  308. PaintBoxStretchTransfer.Invalidate
  309. else
  310. if TabManual.Visible then
  311. begin
  312. // Manual resampling
  313. FBitmapPattern.Resampler.PrepareSampling;
  314. try
  315. for Y := 0 to ImagePattern.Bitmap.Height - 1 do
  316. for X := 0 to ImagePattern.Bitmap.Width - 1 do
  317. ImagePattern.Bitmap.Pixel[X, Y] := FBitmapPattern.Resampler.GetSampleFloat(X * sw - 0.5, Y * sh - 0.5);
  318. finally
  319. FBitmapPattern.Resampler.FinalizeSampling;
  320. end;
  321. ImagePattern.Changed;
  322. HasResampled := True;
  323. end;
  324. if (HasResampled) then
  325. StatusBar.Panels[0].Text := Format('%.0n ms for resampling.', [1.0*StopWatch.ElapsedMilliseconds]);
  326. Screen.Cursor := crDefault;
  327. end;
  328. (*
  329. ** Resampler Class changed
  330. *)
  331. procedure TFrmResamplersExample.ComboBoxResamplerClassNameChange(Sender: TObject);
  332. var
  333. Resampler: TCustomResampler;
  334. begin
  335. if (ComboBoxResamplerClassName.ItemIndex = -1) then
  336. exit;
  337. FBitmapPattern.BeginUpdate;
  338. try
  339. Resampler := ResamplerList[ComboBoxResamplerClassName.ItemIndex].Create(FBitmapPattern);
  340. ComboBoxKernelClassNameChange(nil);
  341. ComboBoxPixelAccessModeChange(nil);
  342. finally
  343. FBitmapPattern.EndUpdate;
  344. end;
  345. PanelKernel.Visible := (Resampler is TKernelResampler);
  346. TabKernel.TabVisible := (Resampler is TKernelResampler);
  347. end;
  348. (*
  349. ** Pixel Access or Wrap mode changed
  350. *)
  351. procedure TFrmResamplersExample.ComboBoxPixelAccessModeChange(Sender: TObject);
  352. begin
  353. // Note: This event handler is shared by ComboBoxWrapMode and ComboBoxPixelAccessMode
  354. FBitmapPattern.BeginUpdate;
  355. try
  356. FBitmapPattern.WrapMode := TWrapMode(ComboBoxWrapMode.ItemIndex);
  357. TCustomResampler(FBitmapPattern.Resampler).PixelAccessMode := TPixelAccessMode(ComboBoxPixelAccessMode.ItemIndex);
  358. finally
  359. FBitmapPattern.EndUpdate;
  360. end;
  361. ComboBoxWrapMode.Enabled := (TCustomResampler(FBitmapPattern.Resampler).PixelAccessMode = pamWrap);
  362. end;
  363. (*
  364. ** Kernel Class changed
  365. *)
  366. procedure TFrmResamplersExample.ComboBoxKernelClassNameChange(Sender: TObject);
  367. var
  368. Index: Integer;
  369. KernelResampler: TKernelResampler;
  370. begin
  371. if (not (FBitmapPattern.Resampler is TKernelResampler)) then
  372. exit;
  373. Index := ComboBoxKernelClassName.ItemIndex;
  374. KernelResampler := TKernelResampler(FBitmapPattern.Resampler);
  375. FBitmapPattern.BeginUpdate;
  376. try
  377. KernelResampler.Kernel := KernelList[Index].Create;
  378. LblParameter.Visible :=
  379. (KernelResampler.Kernel is TAlbrechtKernel) or
  380. (KernelResampler.Kernel is TGaussianKernel) or
  381. (KernelResampler.Kernel is TSinshKernel);
  382. GaugeBarParameter.Visible := LblParameter.Visible;
  383. GetKernelParameter(KernelResampler.Kernel);
  384. ComboBoxKernelModeChange(nil);
  385. finally
  386. FBitmapPattern.EndUpdate;
  387. end;
  388. PaintBoxCurve.Invalidate;
  389. end;
  390. (*
  391. ** Kernel Mode changed
  392. *)
  393. procedure TFrmResamplersExample.ComboBoxKernelModeChange(Sender: TObject);
  394. begin
  395. if (ComboBoxKernelMode.ItemIndex >= 0) and (FBitmapPattern.Resampler is TKernelResampler) then
  396. begin
  397. TKernelResampler(FBitmapPattern.Resampler).KernelMode := TKernelMode(ComboBoxKernelMode.ItemIndex);
  398. GaugeBarTableSize.Enabled := (TKernelResampler(FBitmapPattern.Resampler).KernelMode in [kmTableNearest, kmTableLinear]);
  399. end else
  400. GaugeBarTableSize.Enabled := False;
  401. end;
  402. (*
  403. ** Kernel Table Size changed
  404. *)
  405. procedure TFrmResamplersExample.GaugeBarTableSizeChange(Sender: TObject);
  406. begin
  407. // Queue update
  408. TimerTableSize.Enabled := False;
  409. TimerTableSize.Enabled := (FBitmapPattern.Resampler is TKernelResampler);
  410. LblTableSize.Caption := Format('Table Size (%d/100):', [GaugeBarTableSize.Position]);
  411. end;
  412. procedure TFrmResamplersExample.TimerTableSizeTimer(Sender: TObject);
  413. begin
  414. TimerTableSize.Enabled := False;
  415. TKernelResampler(FBitmapPattern.Resampler).TableSize := GaugeBarTableSize.Position;
  416. end;
  417. (*
  418. ** Kernel parameter changed
  419. *)
  420. procedure TFrmResamplersExample.GaugeBarParameterChange(Sender: TObject);
  421. begin
  422. // Queue update
  423. TimerParameter.Enabled := False;
  424. TimerParameter.Enabled := (FBitmapPattern.Resampler is TKernelResampler);
  425. end;
  426. procedure TFrmResamplersExample.TimerParameterTimer(Sender: TObject);
  427. begin
  428. TimerParameter.Enabled := False;
  429. SetKernelParameter(TKernelResampler(FBitmapPattern.Resampler).Kernel);
  430. PaintBoxCurve.Invalidate;
  431. end;
  432. (*
  433. ** Draw kernel curve
  434. *)
  435. procedure TFrmResamplersExample.PaintBoxCurvePaintBuffer(Sender: TObject);
  436. var
  437. Buffer: TBitmap32;
  438. Kernel: TCustomKernel;
  439. i: Integer;
  440. KernelWidth, Scale: Single;
  441. X, Y: integer;
  442. MaxY: integer;
  443. OffsetY: integer;
  444. Color: TColor32;
  445. Curve: TArrayOfFloatPoint;
  446. const
  447. ScaleX: Single = 1.5;
  448. RangeY = 2.1;
  449. RangeYHalf: Single = RangeY / 2;
  450. ScaleY: Single = 1 / RangeY;
  451. MarginY = 8;
  452. begin
  453. Buffer := PaintBoxCurve.Buffer;
  454. Buffer.Clear(clBlack32);
  455. if (not (FBitmapPattern.Resampler is TKernelResampler)) then
  456. exit;
  457. Kernel := TKernelResampler(FBitmapPattern.Resampler).Kernel;
  458. SetKernelParameter(Kernel);
  459. KernelWidth := Kernel.GetWidth * ScaleX;
  460. OffsetY := Buffer.Height div 5;
  461. MaxY := Buffer.Height - MarginY - OffsetY;
  462. // Vertical X grid lines
  463. Scale := 2 * KernelWidth / Buffer.Width;
  464. for i := Floor(-KernelWidth * 2) to Ceil(KernelWidth * 2) do
  465. begin
  466. X := Trunc(0.5 * (i / Scale + Buffer.Width));
  467. if (i = 0) then
  468. Color := clWhite32
  469. else
  470. Color := clGray32;
  471. Buffer.VertLineTS(X, 0, Buffer.Height-1, Color);
  472. end;
  473. // Horizontal Y grid lines
  474. for i := -2 to 1 do
  475. begin
  476. Y := Trunc(0.5 * MaxY * (i * ScaleY + 1)) + OffsetY;
  477. if (i = 0) then
  478. Color := clWhite32
  479. else
  480. Color := clGray32;
  481. Buffer.HorzLineTS(0, Y, Buffer.Width - 1, Color);
  482. end;
  483. // Kernel curve
  484. Setlength(Curve, Buffer.Width+2);
  485. for i := 0 to Buffer.Width-1 do
  486. begin
  487. Curve[i+1].X := i;
  488. Curve[i+1].Y := (RangeYHalf - Kernel.Filter(i * Scale - KernelWidth)) * MaxY * ScaleY + OffsetY;
  489. end;
  490. // Make sure first and last start on axis, but out of view
  491. Curve[0].X := -1;
  492. Curve[0].Y := RangeYHalf * MaxY * ScaleY + OffsetY;
  493. Curve[High(Curve)].X := Buffer.Width;
  494. Curve[High(Curve)].Y := Curve[0].Y;
  495. PolygonFS(Buffer, Curve, SetAlpha(clLime32, 64));
  496. PolylineFS(Buffer, Curve, SetAlpha(clLime32, 128));
  497. end;
  498. (*
  499. ** Upsample using StretchTransfer
  500. *)
  501. procedure TFrmResamplersExample.PaintBoxStretchTransferPaintBuffer(Sender: TObject);
  502. var
  503. StopWatch: TStopWatch;
  504. begin
  505. Screen.Cursor := crAppStart;
  506. StopWatch := TStopWatch.StartNew;
  507. FBitmapPattern.DrawTo(TPaintBox32(Sender).Buffer, TPaintBox32(Sender).Buffer.BoundsRect);
  508. StatusBar.Panels[0].Text := Format('%.0n ms for resampling.', [1.0*StopWatch.ElapsedMilliseconds]);
  509. Screen.Cursor := crDefault;
  510. end;
  511. (*
  512. ** Downsample using StretchTransfer
  513. *)
  514. procedure TFrmResamplersExample.PaintBoxResamplingPaintBuffer(Sender: TObject);
  515. procedure SetupResampler(Bitmap:TBitmap32);
  516. var
  517. KernelResampler: TKernelResampler;
  518. begin
  519. ResamplerList[ComboBoxResamplerClassName.ItemIndex].Create(Bitmap);
  520. // Setup kernel resampler
  521. if (Bitmap.Resampler is TKernelResampler) then
  522. begin
  523. KernelResampler := TKernelResampler(Bitmap.Resampler);
  524. KernelResampler.Kernel := KernelList[ComboBoxKernelClassName.ItemIndex].Create;
  525. SetKernelParameter(KernelResampler.Kernel);
  526. KernelResampler.KernelMode := TKernelMode(ComboBoxKernelMode.ItemIndex);
  527. KernelResampler.TableSize := GaugeBarTableSize.Position;
  528. end;
  529. end;
  530. var
  531. ExpandWidth, ExpandHeight: Integer;
  532. SmallerBitmap: TBitmap32;
  533. R: TRect;
  534. ScaleRatioX, ScaleRatioY: Single;
  535. StopWatch: TStopWatch;
  536. begin
  537. if not TabResampling.Visible then
  538. Exit;
  539. Screen.Cursor := crAppStart;
  540. SmallerBitmap := TBitmap32.Create;
  541. try
  542. SetupResampler(SmallerBitmap);
  543. SetupResampler(FBitmapSource);
  544. StopWatch := TStopWatch.StartNew;
  545. PaintBoxResampling.Buffer.BeginUpdate;
  546. try
  547. // Shrink
  548. ScaleRatioX := PaintBoxResampling.Buffer.Width / (3 * FBitmapSource.Width);
  549. ScaleRatioY := PaintBoxResampling.Buffer.Height / (4 * FBitmapSource.Height);
  550. SmallerBitmap.SetSize(Round(FBitmapSource.Width * ScaleRatioX), Round(FBitmapSource.Height * ScaleRatioY));
  551. // Draw source to SmallerBitmap using resamler
  552. SmallerBitmap.Draw(SmallerBitmap.BoundsRect, FBitmapSource.BoundsRect, FBitmapSource);
  553. // Draw SmallerBitmap to paint box, centered horizontally
  554. // We're drawing 1:1 so no resampling done here
  555. PaintBoxResampling.Buffer.Draw((PaintBoxResampling.Buffer.Width - SmallerBitmap.Width) div 2, 10, SmallerBitmap);
  556. // Expand
  557. // Note that we're expanding the bitmap we just shrunk so the result
  558. // will exacerbate any precision loss caused by the resampling. This
  559. // is done on purpose in order to make any quality loss more visible.
  560. ScaleRatioX := (PaintBoxResampling.Buffer.Width - 20) / FBitmapSource.Width;
  561. ScaleRatioY := (((PaintBoxResampling.Buffer.Height - 20) * 0.25) * 3) / (FBitmapSource.Height);
  562. ExpandWidth := Round(FBitmapSource.Width * ScaleRatioX);
  563. ExpandHeight := Round(FBitmapSource.Height * ScaleRatioY);
  564. R.Left := (PaintBoxResampling.Buffer.Width - ExpandWidth) div 2;
  565. R.Right := R.Left + ExpandWidth;
  566. R.Top := SmallerBitmap.Height + 20;
  567. R.Bottom := SmallerBitmap.Height + 5 + ExpandHeight;
  568. // Draw SmallerBitmap to paintbox using resamler, centered horizontally
  569. PaintBoxResampling.Buffer.Draw(R, SmallerBitmap.BoundsRect, SmallerBitmap);
  570. finally
  571. PaintBoxResampling.Buffer.EndUpdate;
  572. end;
  573. StatusBar.Panels[0].Text := Format('%.0n ms for rendering.', [1.0*StopWatch.ElapsedMilliseconds]);
  574. finally
  575. SmallerBitmap.Free;
  576. end;
  577. Screen.Cursor := crDefault;
  578. end;
  579. end.