uprint.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. // SPDX-License-Identifier: GPL-3.0-only
  2. unit uprint;
  3. {$mode objfpc}{$H+}
  4. {$IFDEF LINUX}
  5. {$DEFINE PRINTER_COMBO}
  6. {$ENDIF}
  7. interface
  8. uses
  9. Classes, SysUtils, FileUtil, PrintersDlgs, LResources, Forms, Controls,
  10. Graphics, Dialogs, StdCtrls, Spin, BGRAVirtualScreen, BGRABitmap,
  11. BGRABitmapTypes, LazPaintType, BGRATransform, ExtCtrls;
  12. type
  13. { TFPrint }
  14. TFPrint = class(TForm)
  15. Label_SelectedPrinterAndPaper: TLabel;
  16. Panel1: TPanel;
  17. Label_PrinterAndPaper: TLabel;
  18. Button_ConfigurePrinter: TButton;
  19. Panel10: TPanel;
  20. Panel2: TPanel;
  21. Label_Orientation: TLabel;
  22. ComboBox_Orientation: TComboBox;
  23. GroupBox_Margins: TGroupBox;
  24. Panel3: TPanel;
  25. Label_Top: TLabel;
  26. SpinEdit_Top: TSpinEdit;
  27. Panel8: TPanel;
  28. Panel4: TPanel;
  29. Label_Left: TLabel;
  30. SpinEdit_Left: TSpinEdit;
  31. Label_Right: TLabel;
  32. SpinEdit_Right: TSpinEdit;
  33. Panel5: TPanel;
  34. Label_Bottom: TLabel;
  35. SpinEdit_Bottom: TSpinEdit;
  36. Panel7: TPanel;
  37. GroupBox_ImageSize: TGroupBox;
  38. CheckBox_Ratio: TCheckBox;
  39. Panel6: TPanel;
  40. Label_DpiX: TLabel;
  41. Label_DpiY: TLabel;
  42. SpinEdit_DpiX: TSpinEdit;
  43. SpinEdit_DpiY: TSpinEdit;
  44. Label_Width: TLabel;
  45. Label_Height: TLabel;
  46. SpinEdit_Width: TSpinEdit;
  47. SpinEdit_Height: TSpinEdit;
  48. Button_ZoomFit: TButton;
  49. Button_Print: TButton;
  50. PrinterSetupDialog1: TPrinterSetupDialog;
  51. procedure BGRAVirtualScreen1MouseDown(Sender: TObject;
  52. Button: TMouseButton; {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: Integer);
  53. procedure BGRAVirtualScreen1MouseMove(Sender: TObject; {%H-}Shift: TShiftState;
  54. X, Y: Integer);
  55. procedure BGRAVirtualScreen1MouseUp(Sender: TObject; Button: TMouseButton;
  56. {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: Integer);
  57. procedure BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);
  58. procedure BGRAVirtualScreen1Resize(Sender: TObject);
  59. procedure Button_ConfigurePrinterClick(Sender: TObject);
  60. procedure Button_PrintClick(Sender: TObject);
  61. procedure Button_ZoomFitClick(Sender: TObject);
  62. procedure CheckBox_RatioChange(Sender: TObject);
  63. procedure ComboBox_OrientationChange(Sender: TObject);
  64. procedure FormCreate(Sender: TObject);
  65. procedure FormShow(Sender: TObject);
  66. procedure Label_SelectedPrinterAndPaperClick(Sender: TObject);
  67. procedure SpinEdit_Change(Sender: TObject);
  68. procedure SpinEdit_DPIChange(Sender: TObject);
  69. procedure SpinEdit_SizeChange(Sender: TObject);
  70. private
  71. function GetDpiX: single;
  72. function GetDpiY: single;
  73. function GetRotatedSpinBottom: TSpinEdit;
  74. function GetRotatedSpinTop: TSpinEdit;
  75. function GetRotatedSpinRight: TSpinEdit;
  76. function GetRotatedSpinLeft: TSpinEdit;
  77. procedure AddPrinterCombo;
  78. procedure ComboBox_PrinterChange(Sender: TObject);
  79. private
  80. { private declarations }
  81. FInitializing: boolean;
  82. FImagePos, FImageSize: TPointF;
  83. FPreviewTransform: TAffineMatrix;
  84. FHoveringImage, FMovingImage: boolean;
  85. FWantedImagePos: TPointF;
  86. FPrevMousePos: TPoint;
  87. FDpiAspectRatio,FAspectRatio: single;
  88. invZoom: TPointF;
  89. FLabelCount: TLabel;
  90. FPrintCount: integer;
  91. property RotatedSpinTop: TSpinEdit read GetRotatedSpinTop;
  92. property RotatedSpinLeft: TSpinEdit read GetRotatedSpinLeft;
  93. property RotatedSpinRight: TSpinEdit read GetRotatedSpinRight;
  94. property RotatedSpinBottom: TSpinEdit read GetRotatedSpinBottom;
  95. property DpiX: single read GetDpiX;
  96. property DpiY: single read GetDpiY;
  97. public
  98. Instance: TLazPaintCustomInstance;
  99. BGRAVirtualScreen1: TBGRAVirtualScreen;
  100. ComboBox_Printer: TComboBox;
  101. Label_Paper: TLabel;
  102. { public declarations }
  103. procedure UpdatePrinterConfig;
  104. procedure UpdatePrintMargins;
  105. procedure UpdatePrintPreview;
  106. procedure UpdateImageSize(AUpdateX,AUpdateY: boolean);
  107. end;
  108. implementation
  109. uses printers, UResourceStrings, Types, LCScaleDPI, umac, ULoading;
  110. var
  111. marginLeft, marginRight, marginTop, marginBottom: integer;
  112. function marginLeftInPoints: single;
  113. begin
  114. result := marginLeft / 25.4 * 72;
  115. end;
  116. function marginTopInPoints: single;
  117. begin
  118. result := marginTop / 25.4 * 72;
  119. end;
  120. function marginRightInPoints: single;
  121. begin
  122. result := marginRight / 25.4 * 72;
  123. end;
  124. function marginBottomInPoints: single;
  125. begin
  126. result := marginBottom / 25.4 * 72;
  127. end;
  128. function unrotatedMarginLeft: integer;
  129. begin
  130. if Printer.Orientation in[poPortrait,poReversePortrait] then
  131. result := marginLeft else result := marginBottom;
  132. end;
  133. function unrotatedMarginRight: integer;
  134. begin
  135. if Printer.Orientation in[poPortrait,poReversePortrait] then
  136. result := marginRight else result := marginTop;
  137. end;
  138. function unrotatedMarginBottom: integer;
  139. begin
  140. if Printer.Orientation in[poPortrait,poReversePortrait] then
  141. result := marginBottom else result := marginRight;
  142. end;
  143. function unrotatedMarginTop: integer;
  144. begin
  145. if Printer.Orientation in[poPortrait,poReversePortrait] then
  146. result := marginTop else result := marginLeft;
  147. end;
  148. function unrotatedMarginLeftInPoints: single;
  149. begin
  150. result := unrotatedMarginLeft / 25.4 * 72;
  151. end;
  152. function unrotatedMarginTopInPoints: single;
  153. begin
  154. result := unrotatedMarginTop / 25.4 * 72;
  155. end;
  156. function unrotatedMarginTopLeftInPoints: TPointF;
  157. begin
  158. result.x := unrotatedMarginLeftInPoints;
  159. result.y := unrotatedMarginTopInPoints;
  160. end;
  161. function unrotatedMarginRightInPoints: single;
  162. begin
  163. result := unrotatedMarginRight / 25.4 * 72;
  164. end;
  165. function unrotatedMarginBottomInPoints: single;
  166. begin
  167. result := unrotatedMarginBottom / 25.4 * 72;
  168. end;
  169. function unrotatedMarginBottomRightInPoints: TPointF;
  170. begin
  171. result.x := unrotatedMarginRightInPoints;
  172. result.y := unrotatedMarginBottomInPoints;
  173. end;
  174. function unrotatedTotalMarginInPoints: TPointF;
  175. begin
  176. result := unrotatedMarginTopLeftInPoints + unrotatedMarginBottomRightInPoints;
  177. end;
  178. function paperWidthInPoints: single;
  179. begin
  180. result := printer.PaperSize.Width * 72 / printer.XDPI;
  181. end;
  182. function paperHeightInPoints: single;
  183. begin
  184. result := printer.PaperSize.Height * 72 / printer.YDPI;
  185. end;
  186. function paperSizeInPoints: TPointF;
  187. begin
  188. result.x := paperWidthInPoints;
  189. result.y := paperHeightInPoints;
  190. end;
  191. { TFPrint }
  192. procedure TFPrint.FormShow(Sender: TObject);
  193. begin
  194. FInitializing:= true;
  195. ComboBox_Orientation.Items.Clear;
  196. ComboBox_Orientation.Items.Add(rsPortait);
  197. ComboBox_Orientation.Items.Add(rsLandscape);
  198. GroupBox_Margins.Caption := GroupBox_Margins.Caption+' (mm)';
  199. if instance.Image.Height = 0 then FAspectRatio := 1 else
  200. FAspectRatio:= instance.Image.Width / instance.Image.Height;
  201. FDpiAspectRatio:=1;
  202. Label_DpiX.Caption := 'DPI';
  203. Label_DpiY.Caption := 'DPI y';
  204. FInitializing := false;
  205. UpdateImageSize(true,true);
  206. UpdatePrinterConfig;
  207. end;
  208. procedure TFPrint.Label_SelectedPrinterAndPaperClick(Sender: TObject);
  209. begin
  210. Button_ConfigurePrinterClick(Sender);
  211. end;
  212. procedure TFPrint.SpinEdit_Change(Sender: TObject);
  213. begin
  214. if not FInitializing then
  215. begin
  216. marginLeft:= RotatedSpinLeft.Value;
  217. marginTop:= RotatedSpinTop.Value;
  218. marginRight:= RotatedSpinRight.Value;
  219. marginBottom:= RotatedSpinBottom.Value;
  220. UpdatePrintPreview;
  221. end;
  222. end;
  223. procedure TFPrint.SpinEdit_DPIChange(Sender: TObject);
  224. begin
  225. if FInitializing then exit;
  226. if CheckBox_Ratio.Checked then
  227. begin
  228. FInitializing := true;
  229. if (Sender = SpinEdit_DpiX) and (FDpiAspectRatio <> 0) then
  230. SpinEdit_DpiY.Value := round(SpinEdit_DpiX.Value/FDpiAspectRatio)
  231. else if (Sender = SpinEdit_DpiY) then
  232. SpinEdit_DpiX.Value := round(SpinEdit_DpiY.Value*FDpiAspectRatio);
  233. FInitializing := false;
  234. end;
  235. UpdateImageSize((Sender = SpinEdit_DpiX) or CheckBox_Ratio.Checked, (Sender = SpinEdit_DpiY) or CheckBox_Ratio.Checked);
  236. UpdatePrintPreview;
  237. end;
  238. procedure TFPrint.SpinEdit_SizeChange(Sender: TObject);
  239. begin
  240. if not FInitializing then
  241. begin
  242. if Sender = SpinEdit_Width then
  243. FImageSize.x := SpinEdit_Width.Value/25.4*72;
  244. if Sender = SpinEdit_Height then
  245. FImageSize.y := SpinEdit_Height.Value/25.4*72;
  246. if CheckBox_Ratio.Checked then
  247. begin
  248. FInitializing := true;
  249. if (Sender = SpinEdit_Width) and (FAspectRatio <> 0) then
  250. begin
  251. FImageSize.y := FImageSize.x / FAspectRatio;
  252. SpinEdit_Height.Value := round(FImageSize.y / 72 * 25.4);
  253. end;
  254. if Sender = SpinEdit_Height then
  255. begin
  256. FImageSize.x := FImageSize.y * FAspectRatio;
  257. SpinEdit_Width.Value := round(FImageSize.x / 72 * 25.4);
  258. end;
  259. FInitializing := false;
  260. end;
  261. FInitializing := true;
  262. if (Sender = SpinEdit_Width) or CheckBox_Ratio.Checked then
  263. begin
  264. if FImageSize.x <> 0 then
  265. SpinEdit_DpiX.Value := round(Instance.Image.Width / FImageSize.x * 72);
  266. end;
  267. if (Sender = SpinEdit_Height) or CheckBox_Ratio.Checked then
  268. begin
  269. if FImageSize.y <> 0 then
  270. SpinEdit_DpiY.Value := round(Instance.Image.Height / FImageSize.y * 72);
  271. end;
  272. FInitializing := false;
  273. UpdatePrintPreview;
  274. end;
  275. end;
  276. function TFPrint.GetDpiX: single;
  277. begin
  278. result := SpinEdit_DpiX.Value;
  279. end;
  280. function TFPrint.GetDpiY: single;
  281. begin
  282. result := SpinEdit_DpiY.Value;
  283. end;
  284. function TFPrint.GetRotatedSpinBottom: TSpinEdit;
  285. begin
  286. if printer.Orientation in[poPortrait,poReversePortrait] then
  287. result := SpinEdit_Bottom
  288. else
  289. result := SpinEdit_Left;
  290. end;
  291. function TFPrint.GetRotatedSpinLeft: TSpinEdit;
  292. begin
  293. if printer.Orientation in[poPortrait,poReversePortrait] then
  294. result := SpinEdit_Left
  295. else
  296. result := SpinEdit_Top;
  297. end;
  298. procedure TFPrint.AddPrinterCombo;
  299. var
  300. i: Integer;
  301. begin
  302. Panel10.RemoveControl(Label_SelectedPrinterAndPaper);
  303. Panel10.ChildSizing.Layout:= cclNone;
  304. Label_Paper := TLabel.Create(self);
  305. Label_Paper.AutoSize:= true;
  306. Label_Paper.Layout:= tlCenter;
  307. Label_Paper.Alignment := taCenter;
  308. Label_Paper.Caption := ' (?)';
  309. Label_Paper.Align := alRight;
  310. Panel10.InsertControl(Label_Paper);
  311. ComboBox_Printer := TComboBox.Create(self);
  312. ComboBox_Printer.Style:= csDropDownList;
  313. for i := 0 to Printer.Printers.Count-1 do
  314. ComboBox_Printer.Items.Add(Printer.Printers[i]);
  315. ComboBox_Printer.Align := alClient;
  316. ComboBox_Printer.OnChange:= @ComboBox_PrinterChange;
  317. Panel10.InsertControl(ComboBox_Printer);
  318. end;
  319. procedure TFPrint.ComboBox_PrinterChange(Sender: TObject);
  320. begin
  321. if FInitializing or (ComboBox_Printer.ItemIndex = -1) then exit;
  322. Printer.PrinterIndex:= ComboBox_Printer.ItemIndex;
  323. UpdatePrinterConfig;
  324. end;
  325. function TFPrint.GetRotatedSpinRight: TSpinEdit;
  326. begin
  327. if printer.Orientation in[poPortrait,poReversePortrait] then
  328. result := SpinEdit_Right
  329. else
  330. result := SpinEdit_Bottom;
  331. end;
  332. function TFPrint.GetRotatedSpinTop: TSpinEdit;
  333. begin
  334. if printer.Orientation in[poPortrait,poReversePortrait] then
  335. result := SpinEdit_Top
  336. else
  337. result := SpinEdit_Right;
  338. end;
  339. procedure TFPrint.UpdatePrinterConfig;
  340. begin
  341. FInitializing := true;
  342. Label_SelectedPrinterAndPaper.Caption := ' ' + printer.PrinterName + ' (' + printer.PaperSize.PaperName + ')';
  343. if Assigned(Label_Paper) then
  344. Label_Paper.Caption := ' (' + printer.PaperSize.PaperName + ')';
  345. if Assigned(ComboBox_Printer) then
  346. ComboBox_Printer.ItemIndex := Printer.PrinterIndex;;
  347. if printer.Orientation in[poPortrait,poReversePortrait] then
  348. ComboBox_Orientation.ItemIndex := 0 else
  349. ComboBox_Orientation.ItemIndex := 1;
  350. FInitializing := false;
  351. UpdatePrintMargins;
  352. end;
  353. procedure TFPrint.UpdatePrintMargins;
  354. begin
  355. FInitializing := true;
  356. RotatedSpinTop.Value := marginTop;
  357. RotatedSpinLeft.Value := marginLeft;
  358. RotatedSpinRight.Value := marginRight;
  359. RotatedSpinBottom.Value := marginBottom;
  360. FInitializing := false;
  361. UpdatePrintPreview;
  362. end;
  363. procedure TFPrint.UpdatePrintPreview;
  364. begin
  365. BGRAVirtualScreen1.DiscardBitmap;
  366. end;
  367. procedure TFPrint.UpdateImageSize(AUpdateX, AUpdateY: boolean);
  368. begin
  369. FInitializing := true;
  370. if AUpdateX and (DpiX <> 0) then FImageSize.x := Instance.Image.Width / DpiX * 72;
  371. if AUpdateY and (DpiY <> 0) then FImageSize.y := Instance.Image.Height / DpiY * 72;
  372. if AUpdateX then SpinEdit_Width.Value := round(FImageSize.X / 72 * 25.4);
  373. if AUpdateY then SpinEdit_Height.Value := round(FImageSize.Y / 72 * 25.4);
  374. FInitializing := false;
  375. end;
  376. procedure TFPrint.Button_ConfigurePrinterClick(Sender: TObject);
  377. begin
  378. if PrinterSetupDialog1.Execute then UpdatePrinterConfig;
  379. end;
  380. procedure TFPrint.Button_PrintClick(Sender: TObject);
  381. var FPrintTransform: TAffineMatrix;
  382. marTopLeft,marBottomRight,imgTopLeft,imgBottomRight: TPointF;
  383. bmp: TBitmap;
  384. area: TRect;
  385. begin
  386. if (unrotatedTotalMarginInPoints.x >= paperSizeInPoints.x) or
  387. (unrotatedTotalMarginInPoints.y >= paperSizeInPoints.y) then exit;
  388. if FLabelCount = nil then
  389. begin
  390. FLabelCount := TLabel.Create(self);
  391. FLabelCount.AutoSize := false;
  392. FLabelCount.Layout := tlCenter;
  393. FLabelCount.Alignment := taCenter;
  394. Panel2.InsertControl(FLabelCount);
  395. end;
  396. FLabelCount.Caption:= '...';
  397. MessagePopupForever(rsActionInProgress);
  398. Self.Enabled:= false;
  399. Application.ProcessMessages;
  400. try
  401. FPrintTransform := AffineMatrixScale(Printer.XDPI/72, Printer.YDPI/72);
  402. Printer.BeginDoc;
  403. marTopLeft := FPrintTransform*unrotatedMarginTopLeftInPoints;
  404. marBottomRight := FPrintTransform*(paperSizeInPoints - unrotatedMarginBottomRightInPoints);
  405. area := rect(round(marTopLeft.x),round(marTopLeft.y),round(marBottomRight.x),round(marBottomRight.y));
  406. Printer.Canvas.ClipRect := area;
  407. Printer.Canvas.Clipping := true;
  408. imgTopLeft := FPrintTransform*FImagePos;
  409. imgBottomRight := FPrintTransform*(FImagePos+FImageSize);
  410. bmp := Instance.Image.RenderedImage.MakeBitmapCopy(clWhite);
  411. try
  412. Printer.Canvas.StretchDraw(rect(round(imgTopLeft.x),round(imgTopLeft.y),
  413. round(imgBottomRight.x),round(imgBottomRight.y)), bmp);
  414. finally
  415. bmp.Free;
  416. end;
  417. Printer.Canvas.Clipping := false;
  418. Printer.EndDoc;
  419. MessagePopup(rsOkay, 4000);
  420. inc(FPrintCount);
  421. except on ex:exception do
  422. begin
  423. Instance.ShowError(Caption, ex.Message);
  424. if Printer.Printing then Printer.Abort;
  425. end;
  426. end;
  427. Self.Enabled := true;
  428. FLabelCount.Caption := IntToStr(FPrintCount);
  429. end;
  430. procedure TFPrint.Button_ZoomFitClick(Sender: TObject);
  431. var maxImageSize: TPointF;
  432. ratio: single;
  433. begin
  434. maxImageSize := paperSizeInPoints - unrotatedTotalMarginInPoints;
  435. if (maxImageSize.x <= 0) or (maxImageSize.y <= 0) or (FImageSize.x <= 0) or (FImageSize.y <= 0) then exit;
  436. if CheckBox_Ratio.Checked then
  437. begin
  438. ratio := maxImageSize.x/FImageSize.x;
  439. if FImageSize.y*ratio > maxImageSize.y then
  440. ratio := maxImageSize.y/FImageSize.y;
  441. FImageSize := FImageSize*ratio;
  442. end else
  443. FImageSize := maxImageSize;
  444. FInitializing := true;
  445. SpinEdit_Height.Value := round(FImageSize.y / 72 * 25.4);
  446. SpinEdit_Width.Value := round(FImageSize.x / 72 * 25.4);
  447. if FImageSize.x <> 0 then
  448. SpinEdit_DpiX.Value := round(Instance.Image.Width / FImageSize.x * 72);
  449. if FImageSize.y <> 0 then
  450. SpinEdit_DpiY.Value := round(Instance.Image.Height / FImageSize.y * 72);
  451. FInitializing := false;
  452. UpdatePrintPreview;
  453. end;
  454. procedure TFPrint.CheckBox_RatioChange(Sender: TObject);
  455. begin
  456. if not FInitializing then
  457. begin
  458. if CheckBox_Ratio.Checked then
  459. begin
  460. if FImageSize.y = 0 then FAspectRatio := 1 else
  461. FAspectRatio:= FImageSize.x/FImageSize.y;
  462. if DpiY = 0 then FDpiAspectRatio := 1 else
  463. FDpiAspectRatio:= DpiX/DpiY;
  464. end;
  465. Label_DpiY.Visible := not (CheckBox_Ratio.Checked and (FDpiAspectRatio = 1));
  466. SpinEdit_DpiY.Visible := not (CheckBox_Ratio.Checked and (FDpiAspectRatio = 1));
  467. if SpinEdit_DpiY.visible then
  468. Label_DpiX.Caption := 'DPI x'
  469. else
  470. Label_DpiX.Caption := 'DPI';
  471. end;
  472. end;
  473. procedure TFPrint.BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap
  474. );
  475. var
  476. ratio, scaling: single;
  477. x,y,w,h: integer;
  478. marTopLeft,marBottomRight,
  479. imgTopLeft,imgBottomRight: TPointF;
  480. area,imgRect,bounds: TRect;
  481. zoom: TPointF;
  482. begin
  483. if (printer.PaperSize.Height = 0) or (printer.PaperSize.Width = 0) then exit;
  484. scaling := DoScaleX(60, OriginalDPI)/60 * BGRAVirtualScreen1.GetCanvasScaleFactor;
  485. ratio := printer.PaperSize.Width/printer.PaperSize.Height;
  486. if Bitmap.Height * ratio > Bitmap.Width then
  487. begin
  488. w := Bitmap.Width;
  489. h := round(w / ratio);
  490. end else
  491. begin
  492. h := Bitmap.Height;
  493. w := round(h * ratio);
  494. end;
  495. x := (Bitmap.Width-w) div 2;
  496. y := (Bitmap.Height-h) div 2;
  497. Bitmap.Rectangle(x,y,x+w,y+h,BGRABlack,BGRAWhite,dmSet);
  498. if (unrotatedTotalMarginInPoints.x >= paperSizeInPoints.x) or
  499. (unrotatedTotalMarginInPoints.y >= paperSizeInPoints.y) then
  500. begin
  501. Button_Print.Enabled := false;
  502. exit;
  503. end;
  504. Button_Print.Enabled := true;
  505. Bitmap.ClipRect := rect(x,y,x+w,y+h);
  506. zoom := PointF(w/paperWidthInPoints,h/paperHeightInPoints);
  507. FPreviewTransform := AffineMatrixTranslation(x,y) *
  508. AffineMatrixScale(zoom.x, zoom.y);
  509. if zoom.x > 0 then invZoom.x := 1/zoom.x else invZoom.x := 0;
  510. if zoom.y > 0 then invZoom.y := 1/zoom.y else invZoom.y := 0;
  511. marTopLeft := FPreviewTransform*unrotatedMarginTopLeftInPoints;
  512. marBottomRight := FPreviewTransform*(paperSizeInPoints - unrotatedMarginBottomRightInPoints);
  513. area := rect(round(marTopLeft.x),round(marTopLeft.y),round(marBottomRight.x),round(marBottomRight.y));
  514. Bitmap.RectangleAntialias(area.left, area.top, area.right, area.bottom, BGRA(128,160,192,128),
  515. scaling);
  516. if IntersectRect(area,area,Bitmap.ClipRect) then
  517. begin
  518. Bitmap.ClipRect := area;
  519. if FImagePos.x + FImageSize.x > paperSizeInPoints.x - unrotatedMarginBottomRightInPoints.x then
  520. FImagePos.x := paperSizeInPoints.x - unrotatedMarginBottomRightInPoints.x - FImageSize.x;
  521. if FImagePos.y + FImageSize.y > paperSizeInPoints.y - unrotatedMarginBottomRightInPoints.y then
  522. FImagePos.y := paperSizeInPoints.y - unrotatedMarginBottomRightInPoints.y - FImageSize.y;
  523. if FImagePos.x < unrotatedMarginTopLeftInPoints.x then FImagePos.x := unrotatedMarginTopLeftInPoints.x;
  524. if FImagePos.y < unrotatedMarginTopLeftInPoints.y then FImagePos.y := unrotatedMarginTopLeftInPoints.y;
  525. imgTopLeft := FPreviewTransform*FImagePos;
  526. imgBottomRight := FPreviewTransform*(FImagePos+FImageSize);
  527. imgRect := rect(round(imgTopLeft.x),round(imgTopLeft.y),round(imgBottomRight.x),round(imgBottomRight.y));
  528. Bitmap.StretchPutImage(imgRect,Instance.Image.RenderedImage,dmDrawWithTransparency);
  529. Bitmap.NoClip;
  530. bounds := Bitmap.ClipRect;
  531. InflateRect(bounds,1,1);
  532. IntersectRect(imgRect, imgRect,bounds);
  533. Bitmap.DrawPolyLineAntialias([imgRect.TopLeft,Point(imgRect.Right-1,imgRect.Top),Point(imgRect.Right-1, imgRect.Bottom-1),
  534. Point(imgRect.left, imgRect.Bottom-1),imgRect.TopLeft], BGRA(0,0,0,128),
  535. BGRA(255,255,255,128), round(2*scaling), False);
  536. end;
  537. Bitmap.NoClip;
  538. end;
  539. procedure TFPrint.BGRAVirtualScreen1Resize(Sender: TObject);
  540. begin
  541. BGRAVirtualScreen1.DiscardBitmap;
  542. end;
  543. procedure TFPrint.BGRAVirtualScreen1MouseMove(Sender: TObject;
  544. Shift: TShiftState; X, Y: Integer);
  545. var
  546. imgTopLeft,imgBottomRight: TPointF;
  547. factor: double;
  548. begin
  549. factor := GetCanvasScaleFactor;
  550. X := Round(X*Factor);
  551. Y := Round(Y*Factor);
  552. if FMovingImage then
  553. begin
  554. FWantedImagePos += PointF((x-FPrevMousePos.x)*invZoom.x,(y-FPrevMousePos.y)*invZoom.y);
  555. FImagePos := FWantedImagePos;
  556. BGRAVirtualScreen1.DiscardBitmap;
  557. end else
  558. begin
  559. imgTopLeft := FPreviewTransform*FImagePos;
  560. imgBottomRight := FPreviewTransform*(FImagePos+FImageSize);
  561. if (X >= imgTopLeft.X) and (X <= imgBottomRight.X) and
  562. (Y >= imgTopLeft.Y) and (Y <= imgBottomRight.Y) then
  563. begin
  564. FHoveringImage:= true;
  565. BGRAVirtualScreen1.Cursor := crSizeAll;
  566. end else
  567. begin
  568. FHoveringImage:= false;
  569. BGRAVirtualScreen1.Cursor := crDefault;
  570. end;
  571. end;
  572. FPrevMousePos := Point(x,y);
  573. end;
  574. procedure TFPrint.BGRAVirtualScreen1MouseUp(Sender: TObject;
  575. Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  576. begin
  577. if (Button= mbLeft) and FMovingImage then
  578. begin
  579. FMovingImage:= false;
  580. end;
  581. end;
  582. procedure TFPrint.BGRAVirtualScreen1MouseDown(Sender: TObject;
  583. Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  584. begin
  585. if (Button = mbLeft) and FHoveringImage then
  586. begin
  587. FWantedImagePos := FImagePos;
  588. FMovingImage := true;
  589. end;
  590. end;
  591. procedure TFPrint.ComboBox_OrientationChange(Sender: TObject);
  592. begin
  593. if not FInitializing then
  594. begin
  595. if ComboBox_Orientation.ItemIndex = 0 then
  596. Printer.Orientation := poPortrait
  597. else
  598. printer.Orientation:= poLandscape;
  599. UpdatePrintMargins;
  600. end;
  601. end;
  602. procedure TFPrint.FormCreate(Sender: TObject);
  603. begin
  604. ScaleControl(Self,OriginalDPI);
  605. BGRAVirtualScreen1 := TBGRAVirtualScreen.Create(self);
  606. BGRAVirtualScreen1.Align := alClient;
  607. BGRAVirtualScreen1.BitmapAutoScale:= false;
  608. BGRAVirtualScreen1.Color := clDkGray;
  609. BGRAVirtualScreen1.OnMouseDown := @BGRAVirtualScreen1MouseDown;
  610. BGRAVirtualScreen1.OnMouseMove := @BGRAVirtualScreen1MouseMove;
  611. BGRAVirtualScreen1.OnMouseUp := @BGRAVirtualScreen1MouseUp;
  612. BGRAVirtualScreen1.OnRedraw := @BGRAVirtualScreen1Redraw;
  613. BGRAVirtualScreen1.OnResize := @BGRAVirtualScreen1Resize;
  614. InsertControl(BGRAVirtualScreen1);
  615. CheckSpinEdit(SpinEdit_DpiY);
  616. CheckSpinEdit(SpinEdit_DpiX);
  617. CheckSpinEdit(SpinEdit_Left);
  618. CheckSpinEdit(SpinEdit_Right);
  619. CheckSpinEdit(SpinEdit_Top);
  620. CheckSpinEdit(SpinEdit_Bottom);
  621. CheckSpinEdit(SpinEdit_Width);
  622. CheckSpinEdit(SpinEdit_Height);
  623. Panel8.Constraints.MinWidth := Label_Top.Width;
  624. Panel7.Constraints.MinWidth := Label_Bottom.Width;
  625. {$IFDEF PRINTER_COMBO}
  626. AddPrinterCombo;
  627. {$ENDIF}
  628. end;
  629. {$R *.lfm}
  630. initialization
  631. marginLeft := 10;
  632. marginTop := 10;
  633. marginRight := 10;
  634. marginBottom := 10;
  635. end.