MainUnit.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800
  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 Graphics32
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Alex A. Denisov
  26. *
  27. * Portions created by the Initial Developer are Copyright (C) 2000-2005
  28. * the Initial Developer. All Rights Reserved.
  29. *
  30. * Contributor(s):
  31. * Michael Hansen <[email protected]>
  32. *
  33. * ***** END LICENSE BLOCK ***** *)
  34. interface
  35. {$I GR32.inc}
  36. uses
  37. {$IFNDEF FPC} Windows, {$ELSE} LResources, {$ENDIF}
  38. System.Types,
  39. SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls, Grids,
  40. ExtCtrls, StdCtrls, Buttons, GR32, GR32_Image, GR32_Transforms,
  41. GR32_Resamplers, GR32_Layers, GR32_RangeBars;
  42. type
  43. TOpType = (opNone, opTranslate, opScale, opRotate, opSkew);
  44. TOpRec = record
  45. OpType: TOpType;
  46. Dx, Dy: Extended; // shifts for opTranslate mode
  47. Sx, Sy: Extended; // scale factors for opScale mode
  48. Cx, Cy, Alpha: Extended; // rotation center and angle (deg) for opRotate mode
  49. Fx, Fy: Extended; // skew factors for opSkew mode
  50. end;
  51. TOpRecs = array[0..7] of TOpRec;
  52. const
  53. OpTypes: array [0..4] of TOpType = (opNone, opTranslate, opScale, opRotate,
  54. opSkew);
  55. type
  56. TTransformMode = (tmAffine, tmProjective, tmBilinear);
  57. { TFormTranformExample }
  58. TFormTranformExample = class(TForm)
  59. BtnClearAll: TButton;
  60. CbxRepeat: TCheckBox;
  61. CmbKernelClassNames: TComboBox;
  62. CmbResamplerClassNames: TComboBox;
  63. ComboBox: TComboBox;
  64. Dst: TImage32;
  65. EdtAlpha: TEdit;
  66. EdtCodeString: TEdit;
  67. EdtCx: TEdit;
  68. EdtCy: TEdit;
  69. EdtDx: TEdit;
  70. EdtDy: TEdit;
  71. EdtFx: TEdit;
  72. EdtFy: TEdit;
  73. EdtSx: TEdit;
  74. EdtSy: TEdit;
  75. GbrAlpha: TGaugeBar;
  76. GbrDx: TGaugeBar;
  77. GbrDy: TGaugeBar;
  78. GbrFx: TGaugeBar;
  79. GbrFy: TGaugeBar;
  80. GbrSx: TGaugeBar;
  81. GbrSy: TGaugeBar;
  82. LblAlpha: TLabel;
  83. LblCodeString: TLabel;
  84. LblCx: TLabel;
  85. LblCy: TLabel;
  86. LblDx: TLabel;
  87. LblDy: TLabel;
  88. LblFx: TLabel;
  89. LblFy: TLabel;
  90. LblInfoRotate: TLabel;
  91. LblInfoSkew: TLabel;
  92. LblInfoTranslate: TLabel;
  93. LblKernel: TLabel;
  94. LblNoOperation: TLabel;
  95. LblProjectiveNote: TLabel;
  96. LblResampler: TLabel;
  97. LblScale: TLabel;
  98. LblSx: TLabel;
  99. LblSy: TLabel;
  100. LblTransformationMatrix: TLabel;
  101. LblType: TLabel;
  102. ListBox: TListBox;
  103. Notebook: TNotebook;
  104. OpacityBar: TGaugeBar;
  105. PageControl: TPageControl;
  106. {$IFDEF FPC}
  107. PageNone: TPage;
  108. PageTranslate: TPage;
  109. PageScale: TPage;
  110. PageRotate: TPage;
  111. PageSkew: TPage;
  112. {$ENDIF}
  113. PnlOpacity: TPanel;
  114. PnlOperation: TPanel;
  115. PnlTransformationMatrix: TPanel;
  116. Shape1: TShape;
  117. Shape2: TShape;
  118. Src: TImage32;
  119. StringGrid: TStringGrid;
  120. TstAffine: TTabSheet;
  121. TstProjective: TTabSheet;
  122. procedure FormCreate(Sender: TObject);
  123. procedure FormDestroy(Sender: TObject);
  124. procedure BtnClearAllClick(Sender: TObject);
  125. procedure ComboBoxChange(Sender: TObject);
  126. procedure ListBoxClick(Sender: TObject);
  127. procedure OpacityChange(Sender: TObject);
  128. procedure PageControlChange(Sender: TObject);
  129. procedure RotationChanged(Sender: TObject);
  130. procedure RotationScrolled(Sender: TObject);
  131. procedure ScaleChanged(Sender: TObject);
  132. procedure ScaleScrolled(Sender: TObject);
  133. procedure SkewChanged(Sender: TObject);
  134. procedure SkewScrolled(Sender: TObject);
  135. procedure TranslationChanged(Sender: TObject);
  136. procedure TranslationScrolled(Sender: TObject);
  137. procedure SrcRBResizingEvent(Sender: TObject; const OldLocation: TFloatRect;
  138. var NewLocation: TFloatRect; DragState: TRBDragState; Shift: TShiftState);
  139. procedure RubberLayerMouseDown(Sender: TObject; Button: TMouseButton;
  140. Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  141. procedure RubberLayerMouseMove(Sender: TObject; Shift: TShiftState; X,
  142. Y: Integer; Layer: TCustomLayer);
  143. procedure RubberLayerMouseUp(Sender: TObject; Button: TMouseButton;
  144. Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  145. procedure AppEventsIdle(Sender: TObject; var Done: Boolean);
  146. procedure ResamplerClassNamesListClick(Sender: TObject);
  147. procedure CmbResamplerClassNamesChange(Sender: TObject);
  148. procedure CmbKernelClassNamesChange(Sender: TObject);
  149. procedure DstPaintStage(Sender: TObject; Buffer: TBitmap32;
  150. StageNum: Cardinal);
  151. procedure CbxRepeatClick(Sender: TObject);
  152. procedure SrcDblClick(Sender: TObject);
  153. protected
  154. LoadingValues: Boolean;
  155. DraggedVertex: Integer;
  156. LastMousePos: TPoint;
  157. StippleStart: Single;
  158. procedure PaintHandles(Sender: TObject; BackBuffer: TBitmap32);
  159. public
  160. SrcRubberBandLayer: TRubberBandLayer;
  161. Operation: TOpRecs;
  162. Current: ^TOpRec;
  163. AffineTransformation: TAffineTransformation;
  164. ProjectiveTransformation: TProjectiveTransformation;
  165. Transformation: TTransformation;
  166. Vertices: array [0..3] of TPoint;
  167. Mode: TTransformMode;
  168. procedure ClearTransformations;
  169. procedure DoTransform;
  170. procedure GenTransform;
  171. procedure PrepareSource;
  172. procedure ShowSettings(OperationNum: Integer);
  173. procedure InitVertices; // for projective mapping
  174. end;
  175. var
  176. FormTranformExample: TFormTranformExample;
  177. implementation
  178. {$IFDEF FPC}
  179. {$R *.lfm}
  180. {$ELSE}
  181. {$R *.dfm}
  182. {$ENDIF}
  183. uses
  184. {$IFDEF Darwin}
  185. MacOSAll,
  186. {$ENDIF}
  187. {$IFNDEF FPC}
  188. JPEG;
  189. {$ELSE}
  190. LazJPG;
  191. {$ENDIF}
  192. const
  193. CAccessMode: array [Boolean] of TPixelAccessMode = (pamSafe, pamWrap);
  194. function GetVal(Src: string; var Dst: Extended): Boolean;
  195. var
  196. Code: Integer;
  197. begin
  198. Val(Src, Dst, Code);
  199. Result := Code = 0;
  200. end;
  201. procedure TFormTranformExample.FormCreate(Sender: TObject);
  202. var
  203. ResStream: TResourceStream;
  204. JPEG: TJPEGImage;
  205. begin
  206. // load example image
  207. JPEG := TJPEGImage.Create;
  208. try
  209. ResStream := TResourceStream.Create(HInstance, 'Delphi', RT_RCDATA);
  210. try
  211. JPEG.LoadFromStream(ResStream);
  212. finally
  213. ResStream.Free;
  214. end;
  215. Src.Bitmap.Assign(JPEG);
  216. finally
  217. JPEG.Free;
  218. end;
  219. //Setup custom paintstages ("checkerboard" and border)
  220. with Dst do
  221. begin
  222. with PaintStages[0]^ do //Set up custom paintstage to draw checkerboard
  223. begin
  224. Stage := PST_CUSTOM;
  225. Parameter := 1; // use parameter to tag the stage, we inspect this in OnPaintStage
  226. end;
  227. with PaintStages.Add^ do //Insert new paintstage on top of everything else, we use this to draw border
  228. begin
  229. Stage := PST_CUSTOM;
  230. Parameter := 2;
  231. end;
  232. end;
  233. with Src do
  234. begin
  235. with PaintStages[0]^ do
  236. begin
  237. Stage := PST_CUSTOM;
  238. Parameter := 1;
  239. end;
  240. with PaintStages.Add^ do
  241. begin
  242. Stage := PST_CUSTOM;
  243. Parameter := 2;
  244. end;
  245. end;
  246. ResamplerList.GetClassNames(CmbResamplerClassNames.Items);
  247. KernelList.GetClassNames(CmbKernelClassNames.Items);
  248. CmbResamplerClassNames.ItemIndex := 0;
  249. CmbKernelClassNames.ItemIndex := 0;
  250. SrcRubberBandLayer := TRubberBandLayer.Create(Src.Layers);
  251. SrcRubberBandLayer.OnResizing := SrcRBResizingEvent;
  252. SrcRubberBandLayer.Location := FloatRect(0, 0, Src.Bitmap.Width - 1, Src.Bitmap.Height - 1);
  253. with TCustomLayer.Create(Dst.Layers) do
  254. begin
  255. OnPaint := PaintHandles;
  256. end;
  257. DraggedVertex := -1;
  258. Dst.SetupBitmap; // set the destination bitmap size to match the image size
  259. PrepareSource;
  260. ClearTransformations;
  261. ShowSettings(0);
  262. AffineTransformation := TAffineTransformation.Create;
  263. ProjectiveTransformation := TProjectiveTransformation.Create;
  264. Transformation := AffineTransformation;
  265. DoTransform;
  266. Application.OnIdle := AppEventsIdle;
  267. end;
  268. procedure TFormTranformExample.ClearTransformations;
  269. var
  270. I: Integer;
  271. begin
  272. FillChar(Operation[0], SizeOf(TOpRecs), 0);
  273. for I := 0 to 7 do
  274. begin
  275. Operation[I].Sx := 1;
  276. Operation[I].Sy := 1;
  277. Operation[I].Cx := Src.Bitmap.Width * 0.5;
  278. Operation[I].Cy := Src.Bitmap.Height * 0.5;
  279. end;
  280. end;
  281. procedure TFormTranformExample.PrepareSource;
  282. begin
  283. // make the border pixels transparent while keeping their RGB components
  284. if not CbxRepeat.Checked then
  285. SetBorderTransparent(Src.Bitmap, Src.Bitmap.BoundsRect);
  286. end;
  287. procedure TFormTranformExample.DoTransform;
  288. var
  289. i, j: Integer;
  290. begin
  291. GenTransform;
  292. Dst.BeginUpdate;
  293. Dst.Bitmap.Clear($00000000);
  294. Transform(Dst.Bitmap, Src.Bitmap, Transformation);
  295. Dst.EndUpdate;
  296. Dst.Invalidate;
  297. if Mode = tmAffine then
  298. begin
  299. // fill the string grid
  300. for j := 0 to 2 do
  301. for i := 0 to 2 do
  302. StringGrid.Cells[i, j] := Format('%.3g', [AffineTransformation.Matrix[i, j]]);
  303. StringGrid.Col := 3; // hide grid cursor
  304. end;
  305. end;
  306. procedure TFormTranformExample.GenTransform;
  307. var
  308. I: Integer;
  309. Rec: TOpRec;
  310. S: string;
  311. begin
  312. if Mode = tmProjective then
  313. begin
  314. ProjectiveTransformation.X0 := Vertices[0].X;
  315. ProjectiveTransformation.Y0 := Vertices[0].Y;
  316. ProjectiveTransformation.X1 := Vertices[1].X;
  317. ProjectiveTransformation.Y1 := Vertices[1].Y;
  318. ProjectiveTransformation.X2 := Vertices[2].X;
  319. ProjectiveTransformation.Y2 := Vertices[2].Y;
  320. ProjectiveTransformation.X3 := Vertices[3].X;
  321. ProjectiveTransformation.Y3 := Vertices[3].Y;
  322. end
  323. else
  324. begin
  325. // affine mode
  326. AffineTransformation.Clear;
  327. for I := 0 to 7 do
  328. begin
  329. Rec := Operation[I];
  330. case Rec.OpType of
  331. opTranslate: AffineTransformation.Translate(Rec.Dx, Rec.Dy);
  332. opScale: AffineTransformation.Scale(Rec.Sx, Rec.Sy);
  333. opRotate: AffineTransformation.Rotate(Rec.Cx, Rec.Cy, Rec.Alpha);
  334. opSkew: AffineTransformation.Skew(Rec.Fx, Rec.Fy);
  335. end;
  336. case Rec.OpType of
  337. opTranslate: s := s + Format('Translate(%.3g, %.3g); ', [Rec.Dx, Rec.Dy]);
  338. opScale: s := s + Format('Scale(%.3g, %.3g); ', [Rec.Sx, Rec.Sy]);
  339. opRotate: s := s + Format('Rotate(%.3g, %.3g, %3g); ', [Rec.Cx, Rec.Cy, Rec.Alpha]);
  340. opSkew: s := s + Format('Skew(%.3g, %.3g); ', [Rec.Fx, Rec.Fy]);
  341. end;
  342. end;
  343. if Length(s) = 0 then s := 'Clear;';
  344. EdtCodeString.Text := s;
  345. end;
  346. Transformation.SrcRect := SrcRubberBandLayer.Location;
  347. end;
  348. procedure TFormTranformExample.FormDestroy(Sender: TObject);
  349. begin
  350. AffineTransformation.Free;
  351. ProjectiveTransformation.Free;
  352. end;
  353. procedure TFormTranformExample.BtnClearAllClick(Sender: TObject);
  354. begin
  355. ClearTransformations;
  356. ShowSettings(Listbox.ItemIndex);
  357. DoTransform;
  358. end;
  359. procedure TFormTranformExample.ListBoxClick(Sender: TObject);
  360. begin
  361. ShowSettings(ListBox.ItemIndex);
  362. end;
  363. procedure TFormTranformExample.ShowSettings(OperationNum: Integer);
  364. begin
  365. LoadingValues := True;
  366. ListBox.ItemIndex := OperationNum;
  367. Current := @Operation[OperationNum];
  368. Combobox.ItemIndex := Ord(Current.OpType);
  369. NoteBook.PageIndex := Ord(Current.OpType);
  370. EdtDx.Text := Format('%.4g', [Current.Dx]);
  371. EdtDy.Text := Format('%.4g', [Current.Dy]);
  372. GbrDx.Position := Round(Current.Dx * 10);
  373. GbrDy.Position := Round(Current.Dy * 10);
  374. EdtSx.Text := Format('%.4g', [Current.Sx]);
  375. EdtSy.Text := Format('%.4g', [Current.Sy]);
  376. GbrSx.Position := Round(Current.Sx * 100);
  377. GbrSy.Position := Round(Current.Sy * 100);
  378. EdtCx.Text := Format('%.4g', [Current.Cx]);
  379. EdtCy.Text := Format('%.4g', [Current.Cy]);
  380. EdtAlpha.Text := Format('%.4g', [Current.Alpha]);
  381. GbrAlpha.Position := Round(Current.Alpha * 2);
  382. EdtFx.Text := Format('%.4g', [Current.Fx]);
  383. EdtFy.Text := Format('%.4g', [Current.Fy]);
  384. GbrFx.Position := Round(Current.Fx * 100);
  385. GbrFy.Position := Round(Current.Fy * 100);
  386. LoadingValues := False;
  387. end;
  388. procedure TFormTranformExample.ComboBoxChange(Sender: TObject);
  389. begin
  390. Current.OpType := OpTypes[ComboBox.ItemIndex];
  391. ShowSettings(ListBox.ItemIndex);
  392. DoTransform;
  393. end;
  394. procedure TFormTranformExample.TranslationChanged(Sender: TObject);
  395. var
  396. Tx, Ty: Extended;
  397. begin
  398. if LoadingValues then Exit;
  399. if GetVal(EdtDx.Text, Tx) and GetVal(EdtDy.Text, Ty) then
  400. begin
  401. Current.Dx := Tx;
  402. Current.Dy := Ty;
  403. DoTransform;
  404. LoadingValues := True;
  405. GbrDx.Position := Round(Current.Dx * 10);
  406. GbrDy.Position := Round(Current.Dy * 10);
  407. LoadingValues := False;
  408. end;
  409. end;
  410. procedure TFormTranformExample.TranslationScrolled(Sender: TObject);
  411. begin
  412. if LoadingValues then Exit;
  413. Current.Dx := GbrDx.Position * 0.1;
  414. Current.Dy := GbrDy.Position * 0.1;
  415. DoTransform;
  416. LoadingValues := True;
  417. EdtDx.Text := FloatToStr(Current.Dx);
  418. EdtDy.Text := FloatToStr(Current.Dy);
  419. LoadingValues := False;
  420. end;
  421. procedure TFormTranformExample.ScaleChanged(Sender: TObject);
  422. var
  423. Sx, Sy: Extended;
  424. begin
  425. if LoadingValues then Exit;
  426. if GetVal(EdtSx.Text, Sx) and GetVal(EdtSy.Text, Sy) then
  427. begin
  428. Current.Sx := Sx;
  429. Current.Sy := Sy;
  430. DoTransform;
  431. LoadingValues := True;
  432. GbrSx.Position := Round(Current.Sx * 100);
  433. GbrSy.Position := Round(Current.Sy * 100);
  434. LoadingValues := False;
  435. end;
  436. end;
  437. procedure TFormTranformExample.ScaleScrolled(Sender: TObject);
  438. begin
  439. if LoadingValues then Exit;
  440. Current.Sx := GbrSx.Position * 0.01;
  441. Current.Sy := GbrSy.Position * 0.01;
  442. DoTransform;
  443. LoadingValues := True;
  444. EdtSx.Text := FloatToStr(Current.Sx);
  445. EdtSy.Text := FloatToStr(Current.Sy);
  446. LoadingValues := False;
  447. end;
  448. procedure TFormTranformExample.RotationChanged(Sender: TObject);
  449. var
  450. Cx, Cy, Alpha: Extended;
  451. begin
  452. if LoadingValues then Exit;
  453. if GetVal(EdtCx.Text, Cx) and GetVal(EdtCy.Text, Cy) and
  454. GetVal(EdtAlpha.Text, Alpha) then
  455. begin
  456. Current.Cx := Cx;
  457. Current.Cy := Cy;
  458. Current.Alpha := Alpha;
  459. DoTransform;
  460. LoadingValues := True;
  461. GbrAlpha.Position := Round(Alpha * 2);
  462. LoadingValues := False;
  463. end;
  464. end;
  465. procedure TFormTranformExample.RotationScrolled(Sender: TObject);
  466. begin
  467. if LoadingValues then Exit;
  468. Current.Alpha := GbrAlpha.Position * 0.5;
  469. DoTransform;
  470. LoadingValues := True;
  471. EdtAlpha.Text := FloatToStr(Current.Alpha * 0.5);
  472. LoadingValues := False;
  473. end;
  474. procedure TFormTranformExample.SkewChanged(Sender: TObject);
  475. var
  476. Fx, Fy: Extended;
  477. begin
  478. if LoadingValues then Exit;
  479. if GetVal(EdtFx.Text, Fx) and GetVal(EdtFy.Text, Fy) then
  480. begin
  481. Current.Fx := Fx;
  482. Current.Fy := Fy;
  483. DoTransform;
  484. LoadingValues := True;
  485. GbrFx.Position := Round(Current.Fx * 10);
  486. GbrFy.Position := Round(Current.Fy * 10);
  487. LoadingValues := False;
  488. end;
  489. end;
  490. procedure TFormTranformExample.SkewScrolled(Sender: TObject);
  491. begin
  492. if LoadingValues then Exit;
  493. Current.Fx := GbrFx.Position * 0.1;
  494. Current.Fy := GbrFy.Position * 0.1;
  495. DoTransform;
  496. LoadingValues := True;
  497. EdtFx.Text := FloatToStr(Current.Fx);
  498. EdtFy.Text := FloatToStr(Current.Fy);
  499. LoadingValues := False;
  500. end;
  501. procedure TFormTranformExample.OpacityChange(Sender: TObject);
  502. begin
  503. OpacityBar.Update;
  504. Src.Bitmap.MasterAlpha := OpacityBar.Position;
  505. DoTransform;
  506. end;
  507. procedure TFormTranformExample.InitVertices;
  508. begin
  509. Vertices[0].X := 0;
  510. Vertices[0].Y := 0;
  511. Vertices[1].X := Src.Bitmap.Width - 1;
  512. Vertices[1].Y := 0;
  513. Vertices[2].X := Src.Bitmap.Width - 1;
  514. Vertices[2].Y := Src.Bitmap.Height - 1;
  515. Vertices[3].X := 0;
  516. Vertices[3].Y := Src.Bitmap.Height - 1;
  517. end;
  518. procedure TFormTranformExample.PageControlChange(Sender: TObject);
  519. begin
  520. if Src = nil then
  521. Exit;
  522. if PageControl.ActivePage = TstAffine then
  523. begin
  524. Mode := tmAffine;
  525. Transformation := AffineTransformation;
  526. CmbResamplerClassNames.Parent := TstAffine;
  527. LblResampler.Parent := TstAffine;
  528. CmbKernelClassNames.Parent := TstAffine;
  529. LblKernel.Parent := TstAffine;
  530. end
  531. else
  532. begin
  533. // set current transformation as projective
  534. Mode := tmProjective;
  535. Transformation := ProjectiveTransformation;
  536. InitVertices;
  537. CmbResamplerClassNames.Parent := TstProjective;
  538. LblResampler.Parent := TstProjective;
  539. CmbKernelClassNames.Parent := TstProjective;
  540. LblKernel.Parent := TstProjective;
  541. end;
  542. DoTransform;
  543. end;
  544. procedure TFormTranformExample.RubberLayerMouseDown(Sender: TObject;
  545. Button: TMouseButton; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  546. var
  547. I: Integer;
  548. begin
  549. if Mode = tmAffine then Exit;
  550. DraggedVertex := -1;
  551. // find the vertex to drag
  552. for I := 0 to 3 do
  553. if (Abs(Vertices[I].X - X) < 3) and (Abs(Vertices[I].Y - Y) < 3) then
  554. begin
  555. DraggedVertex := I;
  556. Break;
  557. end;
  558. // or drag all of them, (DragVertex = 4)
  559. if DraggedVertex = -1 then DraggedVertex := 4;
  560. // store current mouse position
  561. LastMousePos := Classes.Point(X, Y);
  562. end;
  563. procedure TFormTranformExample.RubberLayerMouseMove(Sender: TObject; Shift: TShiftState;
  564. X, Y: Integer; Layer: TCustomLayer);
  565. var
  566. Dx, Dy, I: Integer;
  567. begin
  568. if Mode = tmAffine then Exit;
  569. if DraggedVertex = -1 then Exit; // mouse is not pressed
  570. Dx := X - LastMousePos.X;
  571. Dy := Y - LastMousePos.Y;
  572. LastMousePos := Classes.Point(X, Y);
  573. // update coords
  574. if DraggedVertex = 4 then
  575. begin
  576. for I := 0 to 3 do
  577. begin
  578. Inc(Vertices[I].X, Dx);
  579. Inc(Vertices[I].Y, Dy);
  580. end;
  581. end
  582. else
  583. begin
  584. Inc(Vertices[DraggedVertex].X, Dx);
  585. Inc(Vertices[DraggedVertex].Y, Dy);
  586. end;
  587. DoTransform;
  588. end;
  589. procedure TFormTranformExample.RubberLayerMouseUp(Sender: TObject; Button: TMouseButton;
  590. Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  591. begin
  592. DraggedVertex := -1;
  593. end;
  594. procedure TFormTranformExample.AppEventsIdle(Sender: TObject; var Done: Boolean);
  595. begin
  596. if DraggedVertex >= 0 then Exit;
  597. StippleStart := StippleStart - 0.05;
  598. Dst.Invalidate;
  599. end;
  600. procedure TFormTranformExample.PaintHandles(Sender: TObject; BackBuffer: TBitmap32);
  601. var
  602. I, X0, Y0, X1, Y1: Integer;
  603. procedure PaintVertex(X, Y: Integer);
  604. begin
  605. BackBuffer.FillRectS(X - 2, Y - 2, X + 2, Y + 2, clWhite32);
  606. BackBuffer.FrameRectS(X - 3, Y - 3, X + 3, Y + 3, clBlack32);
  607. end;
  608. begin
  609. if PageControl.ActivePage = TstAffine then Exit;
  610. BackBuffer.SetStipple([clBlack32, clBlack32, clWhite32, clWhite32]);
  611. BackBuffer.StippleStep := 0.5;
  612. BackBuffer.StippleCounter := StippleStart;
  613. X0 := Vertices[3].X;
  614. Y0 := Vertices[3].Y;
  615. for I := 0 to 3 do
  616. begin
  617. X1 := Vertices[I].X;
  618. Y1 := Vertices[I].Y;
  619. BackBuffer.LineFSP(X0, Y0, X1, Y1);
  620. X0 := X1;
  621. Y0 := Y1;
  622. end;
  623. for I := 0 to 3 do PaintVertex(Vertices[I].X, Vertices[I].Y);
  624. end;
  625. procedure TFormTranformExample.ResamplerClassNamesListClick(Sender: TObject);
  626. begin
  627. with CmbResamplerClassNames do
  628. if ItemIndex >= 0 then
  629. Src.Bitmap.ResamplerClassName:= Items[ ItemIndex ];
  630. DoTransform;
  631. end;
  632. procedure TFormTranformExample.SrcDblClick(Sender: TObject);
  633. begin
  634. SrcRubberBandLayer.Location := FloatRect(0, 0, Src.Bitmap.Width - 1,
  635. Src.Bitmap.Height - 1);
  636. end;
  637. procedure TFormTranformExample.SrcRBResizingEvent(Sender: TObject;
  638. const OldLocation: TFloatRect; var NewLocation: TFloatRect;
  639. DragState: TRBDragState; Shift: TShiftState);
  640. begin
  641. Src.Invalidate;
  642. DoTransform;
  643. end;
  644. procedure TFormTranformExample.CmbResamplerClassNamesChange(Sender: TObject);
  645. var
  646. R: TCustomResampler;
  647. begin
  648. with CmbResamplerClassNames do
  649. if ItemIndex >= 0 then
  650. begin
  651. Src.Bitmap.BeginUpdate;
  652. R := TCustomResamplerClass(ResamplerList[ItemIndex]).Create(Src.Bitmap);
  653. if CbxRepeat.Checked then
  654. begin
  655. Src.Bitmap.WrapMode := wmRepeat;
  656. Src.Bitmap.Resampler.PixelAccessMode := CAccessMode[CbxRepeat.Checked];
  657. end;
  658. CmbKernelClassNamesChange(nil);
  659. Src.Bitmap.EndUpdate;
  660. Src.Bitmap.Changed;
  661. CmbKernelClassNames.Visible := R is TKernelResampler;
  662. LblKernel.Visible := CmbKernelClassNames.Visible;
  663. end;
  664. end;
  665. procedure TFormTranformExample.CmbKernelClassNamesChange(Sender: TObject);
  666. var
  667. Index: Integer;
  668. begin
  669. Index := CmbKernelClassNames.ItemIndex;
  670. if Src.Bitmap.Resampler is TKernelResampler then
  671. begin
  672. TKernelResampler(Src.Bitmap.Resampler).Kernel := TCustomKernelClass(KernelList[Index]).Create;
  673. end;
  674. DoTransform;
  675. end;
  676. procedure TFormTranformExample.DstPaintStage(Sender: TObject; Buffer: TBitmap32;
  677. StageNum: Cardinal);
  678. const //0..1
  679. Colors: array [Boolean] of TColor32 = ($FFFFFFFF, $FFB0B0B0);
  680. var
  681. R: TRect;
  682. I, J: Integer;
  683. OddY: Integer;
  684. TilesHorz, TilesVert: Integer;
  685. TileX, TileY: Integer;
  686. TileHeight, TileWidth: Integer;
  687. begin
  688. if Sender is TImage32 then with TImage32(Sender) do
  689. begin
  690. BeginUpdate;
  691. R := GetViewportRect;
  692. case PaintStages[StageNum].Parameter of
  693. 1: begin //Draw Checkerboard
  694. TileHeight := 8;
  695. TileWidth := 8;
  696. TilesHorz := (R.Right - R.Left) div TileWidth;
  697. TilesVert := (R.Bottom - R.Top) div TileHeight;
  698. TileY := 0;
  699. for J := 0 to TilesVert do
  700. begin
  701. TileX := 0;
  702. OddY := J and $1;
  703. for I := 0 to TilesHorz do
  704. begin
  705. Buffer.FillRectS(TileX, TileY, TileX + TileWidth, TileY + TileHeight,Colors[I and $1 = OddY]);
  706. Inc(TileX, TileWidth);
  707. end;
  708. Inc(TileY, TileHeight);
  709. end
  710. end;
  711. 2: Buffer.FrameRectS(R , $FF000000); //Draw Frame
  712. end;
  713. EndUpdate;
  714. end;
  715. end;
  716. procedure TFormTranformExample.CbxRepeatClick(Sender: TObject);
  717. begin
  718. Src.Bitmap.WrapMode := wmRepeat;
  719. Src.Bitmap.Resampler.PixelAccessMode := CAccessMode[CbxRepeat.Checked];
  720. DoTransform;
  721. end;
  722. end.