MainUnit.pas 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091
  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 Image View Layers Example
  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. * Andre Beckedorf <[email protected]>
  32. * Christian-W. Budde <[email protected]>
  33. *
  34. * ***** END LICENSE BLOCK ***** *)
  35. interface
  36. {$I GR32.inc}
  37. uses
  38. {$IFDEF FPC}LCLIntf, LResources, LCLType, {$ELSE} Windows, {$ENDIF}
  39. SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Menus, ExtCtrls,
  40. ExtDlgs, StdCtrls, Buttons, GR32, GR32_Image, GR32_Layers, GR32_RangeBars,
  41. GR32_Filters, GR32_Transforms, GR32_Resamplers;
  42. type
  43. { TMainForm }
  44. TMainForm = class(TForm)
  45. BtnLayerRescale: TButton;
  46. BtnLayerResetScale: TButton;
  47. CbxCropped: TCheckBox;
  48. CbxImageInterpolate: TCheckBox;
  49. CbxLayerInterpolate: TCheckBox;
  50. CbxMagnInterpolate: TCheckBox;
  51. CbxOptRedraw: TCheckBox;
  52. GbrBorderRadius: TGaugeBar;
  53. GbrBorderWidth: TGaugeBar;
  54. GbrLayerOpacity: TGaugeBar;
  55. GbrMagnMagnification: TGaugeBar;
  56. GbrMagnOpacity: TGaugeBar;
  57. GbrMagnRotation: TGaugeBar;
  58. ImgView: TImgView32;
  59. LblBorderRadius: TLabel;
  60. LblBorderWidth: TLabel;
  61. LblMagifierOpacity: TLabel;
  62. LblMagnification: TLabel;
  63. LblOpacity: TLabel;
  64. LblRotation: TLabel;
  65. LblScale: TLabel;
  66. MainMenu: TMainMenu;
  67. MimArrange: TMenuItem;
  68. MnuBringFront: TMenuItem;
  69. MnuButtonMockup: TMenuItem;
  70. MnuDelete: TMenuItem;
  71. MnuFile: TMenuItem;
  72. MnuFileNew: TMenuItem;
  73. MnuFileOpen: TMenuItem;
  74. MnuFlatten: TMenuItem;
  75. MnuFlipHorz: TMenuItem;
  76. MnuFlipVert: TMenuItem;
  77. MnuLayers: TMenuItem;
  78. MnuLevelDown: TMenuItem;
  79. MnuLevelUp: TMenuItem;
  80. MnuMagnifier: TMenuItem;
  81. MnuNewBitmapLayer: TMenuItem;
  82. MnuNewBitmapRGBA: TMenuItem;
  83. MnuNewCustomLayer: TMenuItem;
  84. MnuPrint: TMenuItem;
  85. MnuRotate180: TMenuItem;
  86. MnuRotate270: TMenuItem;
  87. MnuRotate90: TMenuItem;
  88. MnuScaled: TMenuItem;
  89. MnuSendBack: TMenuItem;
  90. MnuSimpleDrawing: TMenuItem;
  91. N1: TMenuItem;
  92. N2: TMenuItem;
  93. N3: TMenuItem;
  94. N4: TMenuItem;
  95. N5: TMenuItem;
  96. N6: TMenuItem;
  97. OpenPictureDialog: TOpenPictureDialog;
  98. PnlBitmapLayer: TPanel;
  99. PnlBitmapLayerHeader: TPanel;
  100. PnlButtonMockup: TPanel;
  101. PnlButtonMockupHeader: TPanel;
  102. PnlControl: TPanel;
  103. PnlImage: TPanel;
  104. PnlImageHeader: TPanel;
  105. PnlMagnification: TPanel;
  106. PnlMagnificationHeader: TPanel;
  107. SaveDialog: TSaveDialog;
  108. ScaleCombo: TComboBox;
  109. N7: TMenuItem;
  110. procedure FormCreate(Sender: TObject);
  111. procedure FormDestroy(Sender: TObject);
  112. procedure BtnLayerRescaleClick(Sender: TObject);
  113. procedure BtnLayerResetScaleClick(Sender: TObject);
  114. procedure CbxCroppedClick(Sender: TObject);
  115. procedure CbxImageInterpolateClick(Sender: TObject);
  116. procedure CbxLayerInterpolateClick(Sender: TObject);
  117. procedure CbxOptRedrawClick(Sender: TObject);
  118. procedure ImgViewKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  119. procedure ImgViewMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  120. procedure ImgViewMouseWheelDown(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
  121. procedure ImgViewMouseWheelUp(Sender: TObject; Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
  122. procedure ImgViewPaintStage(Sender: TObject; Buffer: TBitmap32; StageNum: Cardinal);
  123. procedure LayerOpacityChanged(Sender: TObject);
  124. procedure MimArrangeClick(Sender: TObject);
  125. procedure MnuButtonMockupClick(Sender: TObject);
  126. procedure MnuDeleteClick(Sender: TObject);
  127. procedure MnuFileClick(Sender: TObject);
  128. procedure MnuFileNewClick(Sender: TObject);
  129. procedure MnuFileOpenClick(Sender: TObject);
  130. procedure MnuFlattenClick(Sender: TObject);
  131. procedure MnuFlipHorzClick(Sender: TObject);
  132. procedure MnuFlipVertClick(Sender: TObject);
  133. procedure MnuLayersClick(Sender: TObject);
  134. procedure MnuMagnifierClick(Sender: TObject);
  135. procedure MnuNewBitmapLayerClick(Sender: TObject);
  136. procedure MnuNewBitmapRGBAClick(Sender: TObject);
  137. procedure MnuPrintClick(Sender: TObject);
  138. procedure MnuReorderClick(Sender: TObject);
  139. procedure MnuRotate180Click(Sender: TObject);
  140. procedure MnuRotate270Click(Sender: TObject);
  141. procedure MnuRotate90Click(Sender: TObject);
  142. procedure MnuScaledClick(Sender: TObject);
  143. procedure MnuSimpleDrawingClick(Sender: TObject);
  144. procedure PropertyChange(Sender: TObject);
  145. procedure ScaleComboChange(Sender: TObject);
  146. private
  147. FSelection: TPositionedLayer;
  148. procedure SetSelection(Value: TPositionedLayer);
  149. protected
  150. RBLayer: TRubberbandLayer;
  151. function CreatePositionedLayer: TPositionedLayer;
  152. procedure LayerDblClick(Sender: TObject);
  153. procedure LayerMouseDown(Sender: TObject; Buttons: TMouseButton;
  154. Shift: TShiftState; X, Y: Integer);
  155. procedure RBResizing(Sender: TObject; const OldLocation: TFloatRect;
  156. var NewLocation: TFloatRect; DragState: TRBDragState; Shift: TShiftState);
  157. procedure PaintMagnifierHandler(Sender: TObject; Buffer: TBitmap32);
  158. procedure PaintSimpleDrawingHandler(Sender: TObject; Buffer: TBitmap32);
  159. procedure PaintButtonMockupHandler(Sender: TObject; Buffer: TBitmap32);
  160. public
  161. procedure CreateNewImage(AWidth, AHeight: Integer; FillColor: TColor32);
  162. procedure OpenImage(const FileName: string);
  163. property Selection: TPositionedLayer read FSelection write SetSelection;
  164. end;
  165. var
  166. MainForm: TMainForm;
  167. implementation
  168. {$IFDEF FPC}
  169. {$R *.lfm}
  170. {$ELSE}
  171. {$R *.dfm}
  172. {$ENDIF}
  173. uses
  174. {$IFDEF Darwin}
  175. MacOSAll,
  176. {$ENDIF}
  177. {$IFNDEF FPC}
  178. JPEG,
  179. {$ELSE}
  180. LazJPG,
  181. {$ENDIF}
  182. NewImageUnit, RGBALoaderUnit, Math, Printers, GR32_LowLevel, GR32_Paths,
  183. GR32_VectorUtils, GR32_Backends, GR32_Text_VCL, GR32_ColorGradients,
  184. GR32_Polygons, GR32_Geometry;
  185. const
  186. RESAMPLER: array [Boolean] of TCustomResamplerClass = (TNearestResampler, TDraftResampler);
  187. { TMainForm }
  188. procedure TMainForm.FormCreate(Sender: TObject);
  189. begin
  190. // by default, PST_CLEAR_BACKGND is executed at this stage,
  191. // which, in turn, calls ExecClearBackgnd method of ImgView.
  192. // Here I substitute PST_CLEAR_BACKGND with PST_CUSTOM, so force ImgView
  193. // to call the OnPaintStage event instead of performing default action.
  194. with ImgView.PaintStages[0]^ do
  195. begin
  196. if Stage = PST_CLEAR_BACKGND then Stage := PST_CUSTOM;
  197. end;
  198. ImgView.RepaintMode := rmOptimizer;
  199. ImgView.Options := ImgView.Options + [pboWantArrowKeys];
  200. end;
  201. procedure TMainForm.FormDestroy(Sender: TObject);
  202. begin
  203. Selection := nil;
  204. RBLayer := nil;
  205. end;
  206. procedure TMainForm.CreateNewImage(AWidth, AHeight: Integer; FillColor: TColor32);
  207. begin
  208. with ImgView do
  209. begin
  210. Selection := nil;
  211. RBLayer := nil;
  212. Layers.Clear;
  213. Scale := 1;
  214. Bitmap.SetSize(AWidth, AHeight);
  215. Bitmap.Clear(FillColor);
  216. pnlImage.Visible := not Bitmap.Empty;
  217. end;
  218. end;
  219. function TMainForm.CreatePositionedLayer: TPositionedLayer;
  220. var
  221. P: TPoint;
  222. begin
  223. // get coordinates of the center of viewport
  224. with ImgView.GetViewportRect do
  225. P := ImgView.ControlToBitmap(GR32.Point((Right + Left) div 2, (Top + Bottom) div 2));
  226. Result := TPositionedLayer.Create(ImgView.Layers);
  227. Result.Location := FloatRect(P.X - 32, P.Y - 32, P.X + 32, P.Y + 32);
  228. Result.Scaled := True;
  229. Result.MouseEvents := True;
  230. Result.OnMouseDown := LayerMouseDown;
  231. Result.OnDblClick := LayerDblClick;
  232. end;
  233. procedure TMainForm.CbxCroppedClick(Sender: TObject);
  234. begin
  235. if Selection is TBitmapLayer then
  236. TBitmapLayer(Selection).Cropped := CbxCropped.Checked;
  237. end;
  238. procedure TMainForm.CbxImageInterpolateClick(Sender: TObject);
  239. begin
  240. RESAMPLER[CbxImageInterpolate.Checked].Create(ImgView.Bitmap);
  241. end;
  242. procedure TMainForm.CbxLayerInterpolateClick(Sender: TObject);
  243. begin
  244. if Selection is TBitmapLayer then
  245. begin
  246. RESAMPLER[CbxLayerInterpolate.Checked].Create(TBitmapLayer(Selection).Bitmap);
  247. end;
  248. end;
  249. procedure TMainForm.LayerDblClick(Sender: TObject);
  250. begin
  251. if Sender is TRubberbandLayer then
  252. TRubberbandLayer(Sender).Quantize;
  253. end;
  254. procedure TMainForm.LayerMouseDown(Sender: TObject; Buttons: TMouseButton;
  255. Shift: TShiftState; X, Y: Integer);
  256. begin
  257. if Sender <> nil then Selection := TPositionedLayer(Sender);
  258. end;
  259. procedure TMainForm.LayerOpacityChanged(Sender: TObject);
  260. begin
  261. if Selection is TBitmapLayer then
  262. TBitmapLayer(Selection).Bitmap.MasterAlpha := GbrLayerOpacity.Position;
  263. end;
  264. procedure TMainForm.BtnLayerRescaleClick(Sender: TObject);
  265. var
  266. T: TBitmap32;
  267. begin
  268. // resize the layer's bitmap to the size of the layer
  269. if Selection is TBitmapLayer then
  270. with TBitmapLayer(Selection) do
  271. begin
  272. T := TBitmap32.Create;
  273. T.Assign(Bitmap);
  274. with MakeRect(Location) do
  275. Bitmap.SetSize(Right - Left, Bottom - Top);
  276. T.Resampler := TNearestResampler.Create(T);
  277. T.DrawMode := dmOpaque;
  278. T.DrawTo(Bitmap, Classes.Rect(0, 0, Bitmap.Width, Bitmap.Height));
  279. T.Free;
  280. BtnLayerResetScaleClick(Self);
  281. end;
  282. ImgView.GetBitmapRect
  283. end;
  284. procedure TMainForm.BtnLayerResetScaleClick(Sender: TObject);
  285. var
  286. L: TFloatRect;
  287. begin
  288. // resize the layer to the size of its bitmap
  289. if Selection is TBitmapLayer then
  290. with RBLayer, TBitmapLayer(Selection).Bitmap do
  291. begin
  292. L := Location;
  293. L.Right := L.Left + Width;
  294. L.Bottom := L.Top + Height;
  295. Location := L;
  296. Changed;
  297. end;
  298. end;
  299. procedure TMainForm.PropertyChange(Sender: TObject);
  300. begin
  301. ImgView.Invalidate;
  302. end;
  303. procedure TMainForm.MimArrangeClick(Sender: TObject);
  304. var
  305. B: Boolean;
  306. begin
  307. B := Selection <> nil;
  308. MnuBringFront.Enabled := B and (Selection.Index < ImgView.Layers.Count - 2);
  309. MnuSendBack.Enabled := B and (Selection.Index > 0);
  310. MnuLevelUp.Enabled := B and (Selection.Index < ImgView.Layers.Count - 2);
  311. MnuLevelDown.Enabled := B and (Selection.Index > 0);
  312. MnuScaled.Enabled := B;
  313. MnuScaled.Checked := B and Selection.Scaled;
  314. MnuDelete.Enabled := B;
  315. B := B and (Selection is TBitmapLayer);
  316. MnuFlipHorz.Enabled := B;
  317. MnuFlipVert.Enabled := B;
  318. MnuRotate90.Enabled := B;
  319. MnuRotate180.Enabled := B;
  320. MnuRotate270.Enabled := B;
  321. end;
  322. procedure TMainForm.MnuButtonMockupClick(Sender: TObject);
  323. var
  324. L: TPositionedLayer;
  325. begin
  326. L := CreatePositionedLayer;
  327. L.OnPaint := PaintButtonMockupHandler;
  328. L.Tag := 2;
  329. Selection := L;
  330. end;
  331. procedure TMainForm.MnuDeleteClick(Sender: TObject);
  332. var
  333. ALayer: TPositionedLayer;
  334. begin
  335. if Selection <> nil then
  336. begin
  337. ALayer := Selection;
  338. Selection := nil;
  339. ALayer.Free;
  340. end;
  341. end;
  342. procedure TMainForm.MnuFileNewClick(Sender: TObject);
  343. begin
  344. with FrmNewImage do
  345. begin
  346. ShowModal;
  347. if ModalResult = mrOK then
  348. CreateNewImage(BtnUpDownWidth.Position, BtnUpDownHeight.Position,
  349. Color32(PnlColor.Color));
  350. end;
  351. end;
  352. procedure TMainForm.MnuFileOpenClick(Sender: TObject);
  353. begin
  354. with OpenPictureDialog do
  355. if Execute then OpenImage(FileName);
  356. end;
  357. procedure TMainForm.MnuLayersClick(Sender: TObject);
  358. var
  359. B: Boolean;
  360. begin
  361. B := not ImgView.Bitmap.Empty;
  362. MnuNewBitmapLayer.Enabled := B;
  363. MnuNewBitmapRGBA.Enabled := B;
  364. MnuNewCustomLayer.Enabled := B;
  365. MnuFlatten.Enabled := B and (ImgView.Layers.Count > 0);
  366. end;
  367. procedure TMainForm.MnuMagnifierClick(Sender: TObject);
  368. var
  369. L: TPositionedLayer;
  370. begin
  371. L := CreatePositionedLayer;
  372. L.OnPaint := PaintMagnifierHandler;
  373. L.Tag := 3;
  374. Selection := L;
  375. end;
  376. procedure TMainForm.MnuNewBitmapLayerClick(Sender: TObject);
  377. var
  378. B: TBitmapLayer;
  379. P: TPoint;
  380. W, H: Single;
  381. begin
  382. with OpenPictureDialog do
  383. if Execute then
  384. begin
  385. B := TBitmapLayer.Create(ImgView.Layers);
  386. with B do
  387. try
  388. Bitmap.LoadFromFile(FileName);
  389. Bitmap.DrawMode := dmBlend;
  390. with ImgView.GetViewportRect do
  391. P := ImgView.ControlToBitmap(GR32.Point((Right + Left) div 2, (Top + Bottom) div 2));
  392. W := Bitmap.Width * 0.5;
  393. H := Bitmap.Height * 0.5;
  394. with ImgView.Bitmap do
  395. Location := GR32.FloatRect(P.X - W, P.Y - H, P.X + W, P.Y + H);
  396. Scaled := True;
  397. OnMouseDown := LayerMouseDown;
  398. except
  399. Free;
  400. raise;
  401. end;
  402. Selection := B;
  403. end;
  404. end;
  405. procedure TMainForm.MnuNewBitmapRGBAClick(Sender: TObject);
  406. var
  407. B: TBitmapLayer;
  408. P: TPoint;
  409. Tmp: TBitmap32;
  410. W, H: Single;
  411. begin
  412. with RGBALoaderForm do
  413. begin
  414. ImgRGB.Bitmap.Delete;
  415. ImgRGB.Scale := 1;
  416. ImgAlpha.Bitmap.Delete;
  417. ImgAlpha.Scale := 1;
  418. ShowModal;
  419. if (ModalResult = mrOK) and not ImgRGB.Bitmap.Empty then
  420. begin
  421. B := TBitmapLayer.Create(ImgView.Layers);
  422. B.Bitmap := ImgRGB.Bitmap;
  423. B.Bitmap.DrawMode := dmBlend;
  424. if not ImgAlpha.Bitmap.Empty then
  425. begin
  426. Tmp := TBitmap32.Create;
  427. try
  428. Tmp.SetSize(B.Bitmap.Width, B.Bitmap.Height);
  429. ImgAlpha.Bitmap.DrawTo(Tmp, Classes.Rect(0, 0, Tmp.Width, Tmp.Height));
  430. // combine Alpha into already loaded RGB colors
  431. IntensityToAlpha(B.Bitmap, Tmp);
  432. finally
  433. Tmp.Free;
  434. end;
  435. end;
  436. with ImgView.GetViewportRect do
  437. P := ImgView.ControlToBitmap(GR32.Point((Right + Left) div 2, (Top + Bottom) div 2));
  438. with B do
  439. begin
  440. W := Bitmap.Width * 0.5;
  441. H := Bitmap.Height * 0.5;
  442. with ImgView.Bitmap do
  443. Location := GR32.FloatRect(P.X - W, P.Y - H, P.X + W, P.Y + H);
  444. Scaled := True;
  445. OnMouseDown := LayerMouseDown;
  446. end;
  447. Selection := B;
  448. end;
  449. end;
  450. end;
  451. procedure TMainForm.MnuReorderClick(Sender: TObject);
  452. begin
  453. // note that the top-most layer is occupied with the rubber-banding layer
  454. if Selection <> nil then
  455. case TMenuItem(Sender).Tag of
  456. 1: // Bring to front, do not use BringToFront here, see note above
  457. Selection.Index := ImgView.Layers.Count - 2;
  458. 2: Selection.SendToBack;
  459. 3: Selection.Index := Selection.Index + 1; // up one level
  460. 4: Selection.Index := Selection.Index - 1; // down one level
  461. end;
  462. end;
  463. procedure TMainForm.MnuSimpleDrawingClick(Sender: TObject);
  464. var
  465. L: TPositionedLayer;
  466. begin
  467. L := CreatePositionedLayer;
  468. L.OnPaint := PaintSimpleDrawingHandler;
  469. L.Tag := 1;
  470. Selection := L;
  471. end;
  472. procedure TMainForm.OpenImage(const FileName: string);
  473. begin
  474. with ImgView do
  475. try
  476. Selection := nil;
  477. RBLayer := nil;
  478. Layers.Clear;
  479. Scale := 1;
  480. Bitmap.LoadFromFile(FileName);
  481. finally
  482. pnlImage.Visible := not Bitmap.Empty;
  483. end;
  484. end;
  485. procedure TMainForm.PaintButtonMockupHandler(Sender: TObject;
  486. Buffer: TBitmap32);
  487. var
  488. RoundPoly: TArrayOfFloatPoint;
  489. TextPoly: TArrayOfArrayOfFloatPoint;
  490. Bounds, Dst: TFloatRect;
  491. Path: TFlattenedPath;
  492. Intf: ITextToPathSupport;
  493. ColorGradient: TLinearGradientPolygonFiller;
  494. const
  495. CScale = 1 / 200;
  496. begin
  497. if Sender is TPositionedLayer then
  498. with TPositionedLayer(Sender) do
  499. begin
  500. Bounds := GetAdjustedLocation;
  501. InflateRect(Bounds, -1, -1);
  502. RoundPoly := RoundRect(Bounds, GbrBorderRadius.Position);
  503. ColorGradient := TLinearGradientPolygonFiller.Create;
  504. try
  505. ColorGradient.SetPoints(FloatPoint(0, Bounds.Top), FloatPoint(0, Bounds.Bottom));
  506. ColorGradient.Gradient.StartColor := $FFE2E2E2;
  507. ColorGradient.Gradient.AddColorStop(0.499, $FFD3D3D3);
  508. ColorGradient.Gradient.AddColorStop(0.501, $FFDBDBDB);
  509. ColorGradient.Gradient.EndColor := $FFFDFDFD;
  510. PolygonFS(Buffer, RoundPoly, ColorGradient, pfAlternate);
  511. finally
  512. ColorGradient.Free;
  513. end;
  514. PolyPolygonFS(Buffer, BuildPolyPolyLine(PolyPolygon(RoundPoly), True,
  515. 0.1 * GbrBorderWidth.Position), clGray32, pfAlternate);
  516. Path := TFlattenedPath.Create;
  517. try
  518. // Buffer.Font.Assign(FFont);
  519. Buffer.Font.Size := 12;
  520. if Supports(Buffer.Backend, ITextToPathSupport, Intf) then
  521. begin
  522. Intf.TextToPath(Path, 0, 0, 'Button');
  523. TextPoly := Path.Path;
  524. if Length(TextPoly) > 0 then
  525. begin
  526. Dst := PolypolygonBounds(TextPoly);
  527. TextPoly := TranslatePolyPolygon(TextPoly,
  528. 0.5 * (Bounds.Left + Bounds.Right - (Dst.Right - Dst.Left)),
  529. 0.5 * (Bounds.Bottom + Bounds.Top - Dst.Bottom));
  530. PolyPolygonFS_LCD2(Buffer, TextPoly, clBlack32, pfAlternate);
  531. end;
  532. end;
  533. finally
  534. Path.Free;
  535. end;
  536. end;
  537. end;
  538. procedure TMainForm.PaintMagnifierHandler(Sender: TObject; Buffer: TBitmap32);
  539. var
  540. Magnification, Rotation: Single;
  541. SrcRect, DstRect: TFloatRect;
  542. R: TRect;
  543. T: TAffineTransformation;
  544. B: TBitmap32;
  545. W2, H2: Single;
  546. I: Integer;
  547. begin
  548. if Sender is TPositionedLayer then
  549. with TPositionedLayer(Sender) do
  550. begin
  551. DstRect := GetAdjustedLocation;
  552. R := MakeRect(DstRect);
  553. if not Buffer.MeasuringMode then
  554. begin
  555. Magnification := Power(10, (GbrMagnMagnification.Position * 0.02));
  556. Rotation := -GbrMagnRotation.Position;
  557. B := TBitmap32.Create;
  558. try
  559. with R do
  560. begin
  561. B.SetSize(Right - Left, Bottom - Top);
  562. W2 := (Right - Left) * 0.5;
  563. H2 := (Bottom - Top) * 0.5;
  564. end;
  565. SrcRect := DstRect;
  566. with SrcRect do
  567. begin
  568. Left := Left - H2;
  569. Right := Right + H2;
  570. Top := Top - W2;
  571. Bottom := Bottom + W2;
  572. end;
  573. T := TAffineTransformation.Create;
  574. try
  575. T.SrcRect := SrcRect;
  576. T.Translate(-R.Left, -R.Top);
  577. T.Translate(-W2, -H2);
  578. T.Scale(Magnification, Magnification);
  579. T.Rotate(0, 0, Rotation);
  580. T.Translate(W2, H2);
  581. if CbxMagnInterpolate.Checked then
  582. begin
  583. TLinearResampler.Create(Buffer);
  584. Transform(B, Buffer, T);
  585. end
  586. else
  587. begin
  588. TNearestResampler.Create(Buffer);
  589. Transform(B, Buffer, T);
  590. end;
  591. B.ResetAlpha;
  592. B.DrawMode := dmBlend;
  593. B.MasterAlpha := GbrMagnOpacity.Position;
  594. B.DrawTo(Buffer, R);
  595. // draw frame
  596. for I := 0 to 4 do
  597. begin
  598. with R do Buffer.RaiseRectTS(Left, Top, Right, Bottom, 35 - I * 8);
  599. InflateRect(R, -1, -1);
  600. end;
  601. finally
  602. T.Free;
  603. end;
  604. finally
  605. B.Free;
  606. end;
  607. end;
  608. Buffer.Changed;
  609. end;
  610. end;
  611. procedure TMainForm.PaintSimpleDrawingHandler(Sender: TObject; Buffer: TBitmap32);
  612. var
  613. Cx, Cy: Single;
  614. W2, H2: Single;
  615. I: Integer;
  616. const
  617. CScale = 1 / 200;
  618. begin
  619. if Sender is TPositionedLayer then
  620. with TPositionedLayer(Sender).GetAdjustedLocation do
  621. begin
  622. W2 := (Right - Left) * 0.5;
  623. H2 := (Bottom - Top) * 0.5;
  624. Cx := Left + W2;
  625. Cy := Top + H2;
  626. W2 := W2 * CScale;
  627. H2 := H2 * CScale;
  628. Buffer.PenColor := clRed32;
  629. Buffer.MoveToF(Cx, Cy);
  630. for I := 0 to 240 do
  631. Buffer.LineToFS(
  632. Cx + W2 * I * Cos(I * 0.125),
  633. Cy + H2 * I * Sin(I * 0.125));
  634. end;
  635. end;
  636. procedure TMainForm.ScaleComboChange(Sender: TObject);
  637. var
  638. S: string;
  639. I: Integer;
  640. begin
  641. S := ScaleCombo.Text;
  642. S := StringReplace(S, '%', '', [rfReplaceAll]);
  643. S := StringReplace(S, ' ', '', [rfReplaceAll]);
  644. if S = '' then Exit;
  645. I := StrToIntDef(S, -1);
  646. if (I < 1) or (I > 2000) then
  647. I := Round(ImgView.Scale * 100)
  648. else
  649. ImgView.Scale := I * 0.01;
  650. ScaleCombo.Text := IntToStr(I) + '%';
  651. ScaleCombo.SelStart := Length(ScaleCombo.Text) - 1;
  652. end;
  653. procedure TMainForm.SetSelection(Value: TPositionedLayer);
  654. begin
  655. if Value <> FSelection then
  656. begin
  657. if RBLayer <> nil then
  658. begin
  659. RBLayer.ChildLayer := nil;
  660. RBLayer.LayerOptions := LOB_NO_UPDATE;
  661. pnlBitmapLayer.Visible := False;
  662. pnlButtonMockup.Visible := False;
  663. pnlMagnification.Visible := False;
  664. ImgView.Invalidate;
  665. end;
  666. FSelection := Value;
  667. if Value <> nil then
  668. begin
  669. if RBLayer = nil then
  670. begin
  671. RBLayer := TRubberBandLayer.Create(ImgView.Layers);
  672. RBLayer.MinHeight := 1;
  673. RBLayer.MinWidth := 1;
  674. end
  675. else
  676. RBLayer.BringToFront;
  677. RBLayer.ChildLayer := Value;
  678. RBLayer.LayerOptions := LOB_VISIBLE or LOB_MOUSE_EVENTS or LOB_NO_UPDATE;
  679. RBLayer.OnResizing := RBResizing;
  680. RBLayer.OnDblClick := LayerDblClick;
  681. if Value is TBitmapLayer then
  682. with TBitmapLayer(Value) do
  683. begin
  684. pnlBitmapLayer.Visible := True;
  685. GbrLayerOpacity.Position := Bitmap.MasterAlpha;
  686. CbxLayerInterpolate.Checked := Bitmap.Resampler.ClassType = TDraftResampler;
  687. end
  688. else if Value.Tag = 2 then
  689. begin
  690. // tag = 2 for button mockup
  691. pnlButtonMockup.Visible := True;
  692. end
  693. else if Value.Tag = 3 then
  694. begin
  695. // tag = 3 for magnifiers
  696. pnlMagnification.Visible := True;
  697. end;
  698. end;
  699. end;
  700. end;
  701. procedure TMainForm.MnuScaledClick(Sender: TObject);
  702. begin
  703. if Selection <> nil then Selection.Scaled := not Selection.Scaled;
  704. RBLayer.Scaled := Selection.Scaled;
  705. end;
  706. procedure TMainForm.ImgViewKeyDown(Sender: TObject; var Key: Word;
  707. Shift: TShiftState);
  708. var
  709. Location: TFloatRect;
  710. begin
  711. if Assigned(FSelection) then
  712. case Key of
  713. VK_LEFT:
  714. begin
  715. Location := OffsetRect(FSelection.Location, -1, 0);
  716. FSelection.Location := Location;
  717. RBLayer.Location := Location;
  718. end;
  719. VK_RIGHT:
  720. begin
  721. Location := OffsetRect(FSelection.Location, 1, 0);
  722. FSelection.Location := Location;
  723. RBLayer.Location := Location;
  724. end;
  725. VK_UP:
  726. begin
  727. Location := OffsetRect(FSelection.Location, 0, -1);
  728. FSelection.Location := Location;
  729. RBLayer.Location := Location;
  730. end;
  731. VK_DOWN:
  732. begin
  733. Location := OffsetRect(FSelection.Location, 0, 1);
  734. FSelection.Location := Location;
  735. RBLayer.Location := Location;
  736. end;
  737. VK_DELETE:
  738. begin
  739. FreeAndNil(FSelection);
  740. RBLayer.ChildLayer := nil;
  741. RBLayer.LayerOptions := LOB_NO_UPDATE;
  742. end;
  743. end;
  744. end;
  745. procedure TMainForm.ImgViewMouseDown(Sender: TObject; Button: TMouseButton;
  746. Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  747. begin
  748. if Layer = nil then
  749. begin
  750. Selection := nil;
  751. end;
  752. end;
  753. procedure TMainForm.ImgViewPaintStage(Sender: TObject; Buffer: TBitmap32;
  754. StageNum: Cardinal);
  755. const //0..1
  756. Colors: array [Boolean] of TColor32 = ($FFFFFFFF, $FFB0B0B0);
  757. var
  758. R: TRect;
  759. I, J: Integer;
  760. OddY: Integer;
  761. TilesHorz, TilesVert: Integer;
  762. TileX, TileY: Integer;
  763. TileHeight, TileWidth: Integer;
  764. begin
  765. TileHeight := 13;
  766. TileWidth := 13;
  767. TilesHorz := Buffer.Width div TileWidth;
  768. TilesVert := Buffer.Height div TileHeight;
  769. TileY := 0;
  770. for J := 0 to TilesVert do
  771. begin
  772. TileX := 0;
  773. OddY := J and $1;
  774. for I := 0 to TilesHorz do
  775. begin
  776. R.Left := TileX;
  777. R.Top := TileY;
  778. R.Right := TileX + TileWidth;
  779. R.Bottom := TileY + TileHeight;
  780. Buffer.FillRectS(R, Colors[I and $1 = OddY]);
  781. Inc(TileX, TileWidth);
  782. end;
  783. Inc(TileY, TileHeight);
  784. end;
  785. end;
  786. procedure TMainForm.RBResizing(Sender: TObject;
  787. const OldLocation: TFloatRect; var NewLocation: TFloatRect;
  788. DragState: TRBDragState; Shift: TShiftState);
  789. var
  790. w, h, cx, cy: Single;
  791. nw, nh: Single;
  792. begin
  793. if DragState = dsMove then Exit; // we are interested only in scale operations
  794. if Shift = [] then Exit; // special processing is not required
  795. if ssCtrl in Shift then
  796. begin
  797. { make changes symmetrical }
  798. with OldLocation do
  799. begin
  800. cx := (Left + Right) / 2;
  801. cy := (Top + Bottom) / 2;
  802. w := Right - Left;
  803. h := Bottom - Top;
  804. end;
  805. with NewLocation do
  806. begin
  807. nw := w / 2;
  808. nh := h / 2;
  809. case DragState of
  810. dsSizeL: nw := cx - Left;
  811. dsSizeT: nh := cy - Top;
  812. dsSizeR: nw := Right - cx;
  813. dsSizeB: nh := Bottom - cy;
  814. dsSizeTL: begin nw := cx - Left; nh := cy - Top; end;
  815. dsSizeTR: begin nw := Right - cx; nh := cy - Top; end;
  816. dsSizeBL: begin nw := cx - Left; nh := Bottom - cy; end;
  817. dsSizeBR: begin nw := Right - cx; nh := Bottom - cy; end;
  818. end;
  819. if nw < 2 then nw := 2;
  820. if nh < 2 then nh := 2;
  821. Left := cx - nw;
  822. Right := cx + nw;
  823. Top := cy - nh;
  824. Bottom := cy + nh;
  825. end;
  826. end;
  827. end;
  828. procedure TMainForm.MnuFlattenClick(Sender: TObject);
  829. var
  830. B: TBitmap32;
  831. W, H: Integer;
  832. begin
  833. { deselect everything }
  834. Selection := nil;
  835. W := ImgView.Bitmap.Width;
  836. H := ImgView.Bitmap.Height;
  837. { Create a new bitmap to store a flattened image }
  838. B := TBitmap32.Create;
  839. try
  840. B.SetSize(W, H);
  841. ImgView.PaintTo(B, Classes.Rect(0, 0, W, H));
  842. { destroy all the layers of the original image... }
  843. ImgView.Layers.Clear;
  844. RBLayer := nil; // note that RBLayer reference is destroyed here as well.
  845. // The rubber band will be recreated during the next
  846. // SetSelection call. Alternatively, you can delete
  847. // all the layers except the rubber band.
  848. { ...and overwrite it with the flattened one }
  849. ImgView.Bitmap := B;
  850. finally
  851. B.Free;
  852. end;
  853. end;
  854. procedure TMainForm.MnuPrintClick(Sender: TObject);
  855. var
  856. B: TBitmap32;
  857. W, H: Integer;
  858. R: TRect;
  859. function GetCenteredRectToFit(const src, dst: TRect): TRect;
  860. var
  861. srcWidth, srcHeight, dstWidth, dstHeight, ScaledSide: Integer;
  862. begin
  863. with src do begin
  864. srcWidth := Right - Left;
  865. srcHeight := Bottom - Top;
  866. end;
  867. with dst do begin
  868. dstWidth := Right - Left;
  869. dstHeight := Bottom - Top;
  870. end;
  871. if (srcWidth = 0) or (srcHeight = 0) then exit;
  872. if srcWidth / srcHeight > dstWidth / dstHeight then begin
  873. ScaledSide := Round(dstWidth * srcHeight / srcWidth);
  874. with Result do begin
  875. Left := dst.Left;
  876. Top := dst.Top + (dstHeight - ScaledSide) div 2;
  877. Right := dst.Right;
  878. Bottom := Top + ScaledSide;
  879. end;
  880. end else begin
  881. ScaledSide := Round(dstHeight * srcWidth / srcHeight);
  882. with Result do begin
  883. Left := dst.Left + (dstWidth - ScaledSide) div 2;
  884. Top := dst.Top;
  885. Right := Left + ScaledSide;
  886. Bottom := dst.Bottom;
  887. end;
  888. end;
  889. end;
  890. begin
  891. { deselect everything }
  892. Selection := nil;
  893. W := ImgView.Bitmap.Width;
  894. H := ImgView.Bitmap.Height;
  895. { Create a new bitmap to store a flattened image }
  896. B := TBitmap32.Create;
  897. Screen.Cursor := crHourGlass;
  898. try
  899. B.SetSize(W, H);
  900. ImgView.PaintTo(B, Classes.Rect(0, 0, W, H));
  901. Printer.BeginDoc;
  902. Printer.Title := 'Image View Layers Example';
  903. B.Resampler := TLinearResampler.Create(B);
  904. R := GetCenteredRectToFit(Classes.Rect(0, 0, W, H), Classes.Rect(0, 0, Printer.PageWidth, Printer.PageHeight));
  905. B.TileTo(Printer.Canvas.Handle, R, Classes.Rect(0, 0, W, H));
  906. Printer.EndDoc;
  907. finally
  908. B.Free;
  909. Screen.Cursor := crDefault;
  910. end;
  911. end;
  912. procedure TMainForm.ImgViewMouseWheelUp(Sender: TObject;
  913. Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
  914. var
  915. s: Single;
  916. begin
  917. s := ImgView.Scale / 1.1;
  918. if s < 0.2 then s := 0.2;
  919. ImgView.Scale := s;
  920. ScaleCombo.Text := IntToStr(Round(s * 100)) + '%';
  921. end;
  922. procedure TMainForm.ImgViewMouseWheelDown(Sender: TObject;
  923. Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
  924. var
  925. s: Single;
  926. begin
  927. s := ImgView.Scale * 1.1;
  928. if s > 20 then s := 20;
  929. ImgView.Scale := s;
  930. ScaleCombo.Text := IntToStr(Round(s * 100)) + '%';
  931. end;
  932. procedure TMainForm.MnuFlipHorzClick(Sender: TObject);
  933. begin
  934. if Selection is TBitmapLayer then
  935. TBitmapLayer(Selection).Bitmap.FlipHorz;
  936. end;
  937. procedure TMainForm.MnuFlipVertClick(Sender: TObject);
  938. begin
  939. if Selection is TBitmapLayer then
  940. TBitmapLayer(Selection).Bitmap.FlipVert;
  941. end;
  942. procedure TMainForm.MnuRotate90Click(Sender: TObject);
  943. var
  944. R: TFloatRect;
  945. Cx, Cy, W2, H2: Single;
  946. begin
  947. if Selection is TBitmapLayer then
  948. begin
  949. R := Selection.Location;
  950. TBitmapLayer(Selection).Bitmap.Rotate90;
  951. Cx := (R.Left + R.Right) * 0.5;
  952. Cy := (R.Top + R.Bottom) * 0.5;
  953. W2 := (R.Right - R.Left) * 0.5;
  954. H2 := (R.Bottom - R.Top) * 0.5;
  955. RBLayer.Location := FloatRect(Cx - H2, Cy - W2, Cx + H2, Cy + W2);
  956. end;
  957. end;
  958. procedure TMainForm.MnuRotate180Click(Sender: TObject);
  959. begin
  960. if Selection is TBitmapLayer then
  961. TBitmapLayer(Selection).Bitmap.Rotate180;
  962. end;
  963. procedure TMainForm.MnuRotate270Click(Sender: TObject);
  964. var
  965. R: TFloatRect;
  966. Cx, Cy, W2, H2: Single;
  967. begin
  968. if Selection is TBitmapLayer then
  969. begin
  970. R := Selection.Location;
  971. TBitmapLayer(Selection).Bitmap.Rotate270;
  972. Cx := (R.Left + R.Right) * 0.5;
  973. Cy := (R.Top + R.Bottom) * 0.5;
  974. W2 := (R.Right - R.Left) * 0.5;
  975. H2 := (R.Bottom - R.Top) * 0.5;
  976. RBLayer.Location := FloatRect(Cx - H2, Cy - W2, Cx + H2, Cy + W2);
  977. end;
  978. end;
  979. procedure TMainForm.MnuFileClick(Sender: TObject);
  980. begin
  981. MnuPrint.Enabled := not ImgView.Bitmap.Empty;
  982. end;
  983. procedure TMainForm.CbxOptRedrawClick(Sender: TObject);
  984. const
  985. RepaintMode: array[Boolean] of TRepaintMode = (rmFull, rmOptimizer);
  986. begin
  987. ImgView.RepaintMode := RepaintMode[CbxOptRedraw.Checked];
  988. end;
  989. end.