unewimage.pas 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. // SPDX-License-Identifier: GPL-3.0-only
  2. unit UNewimage;
  3. {$mode objfpc}{$H+}
  4. interface
  5. uses
  6. Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
  7. StdCtrls, Spin, Buttons, ComCtrls, ExtCtrls, BGRAVirtualScreen, BGRAShape,
  8. uimage, LazPaintType, LCScaleDPI, BGRABitmap, BGRABitmapTypes;
  9. const
  10. shadowOffsetX = 3;
  11. shadowOffsetY = 3;
  12. shadowBlur= 3;
  13. type
  14. TLastEnteredValue = (valWidth,valHeight,valRatio);
  15. { TFNewImage }
  16. TFNewImage = class(TForm)
  17. BGRAShape1: TBGRAShape;
  18. BGRAShape10: TBGRAShape;
  19. BGRAShape2: TBGRAShape;
  20. BGRAShape3: TBGRAShape;
  21. BGRAShape4: TBGRAShape;
  22. BGRAShape5: TBGRAShape;
  23. BGRAShape6: TBGRAShape;
  24. BGRAShape7: TBGRAShape;
  25. BGRAShape8: TBGRAShape;
  26. BGRAShape9: TBGRAShape;
  27. ComboBox_Ratio: TComboBox;
  28. ComboBox_BitDepth: TComboBox;
  29. Image1: TImage;
  30. Label_BitDepth: TLabel;
  31. Label_MemoryRequiredValue: TLabel;
  32. Label_Height1: TLabel;
  33. Label_MemoryRequired: TLabel;
  34. ToolBar_Rotate: TToolBar;
  35. ToolButton_Rotate: TToolButton;
  36. vsPreview: TBGRAVirtualScreen;
  37. Button_OK: TButton;
  38. Button_Cancel: TButton;
  39. Label_Width: TLabel;
  40. Label_Height: TLabel;
  41. SpinEdit_Height: TSpinEdit;
  42. SpinEdit_Width: TSpinEdit;
  43. procedure BGRAShapeClick(Sender: TObject);
  44. procedure ComboBox_BitDepthChange(Sender: TObject);
  45. procedure ComboBox_RatioChange(Sender: TObject);
  46. procedure ComboBox_RatioEnter(Sender: TObject);
  47. procedure ComboBox_RatioExit(Sender: TObject);
  48. procedure SpinEdit_HeightChange(Sender: TObject);
  49. procedure ToolButton_RotateClick(Sender: TObject);
  50. procedure vsPreviewRedraw(Sender: TObject; Bitmap: TBGRABitmap);
  51. procedure Button_OKClick(Sender: TObject);
  52. procedure FormCreate(Sender: TObject);
  53. procedure FormShow(Sender: TObject);
  54. procedure SpinEdit_WidthChange(Sender: TObject);
  55. private
  56. FLastEnteredValue: TLastEnteredValue;
  57. FRatio: double;
  58. FRatioWasChanged: boolean;
  59. FRecomputing: boolean;
  60. FBackColor: TBGRAPixel;
  61. procedure UpdatePreview;
  62. function GetBitDepth: integer;
  63. public
  64. LazPaintInstance: TLazPaintCustomInstance;
  65. ForIcon: boolean;
  66. newImageResult: TBGRABitmap;
  67. end;
  68. function ShowNewImageDlg(AInstance: TLazPaintCustomInstance; AForIcon: boolean; out tx,ty,bpp: integer; out back: TBGRAPixel):boolean;
  69. implementation
  70. uses umac, UMySLV, UResourceStrings, UGraph;
  71. { TFNewImage }
  72. function ShowNewImageDlg(AInstance: TLazPaintCustomInstance; AForIcon: boolean; out tx,ty,bpp: integer; out back: TBGRAPixel):boolean;
  73. var
  74. NewImage: TFNewImage;
  75. begin
  76. tx := 0;
  77. ty := 0;
  78. result := false;
  79. NewImage := nil;
  80. try
  81. Application.ProcessMessages; //avoid unexpected exit on linux
  82. NewImage:= TFNewImage.Create(nil);
  83. NewImage.LazPaintInstance := AInstance;
  84. NewImage.ForIcon := AForIcon;
  85. result:= (NewImage.ShowModal = mrOk);
  86. tx:= NewImage.SpinEdit_Width.Value;
  87. ty:= NewImage.SpinEdit_Height.Value;
  88. back:= NewImage.FBackColor;
  89. bpp := NewImage.GetBitDepth;
  90. except
  91. on ex:Exception do
  92. begin
  93. AInstance.ShowError('ShowNewImageDlg',ex.Message);
  94. result := false;
  95. end;
  96. end;
  97. NewImage.free;
  98. end;
  99. procedure TFNewImage.Button_OKClick(Sender: TObject);
  100. begin
  101. if ForIcon then
  102. begin
  103. LazPaintInstance.Config.SetDefaultIconImageWidth(SpinEdit_Width.Value);
  104. LazPaintInstance.Config.SetDefaultIconImageHeight(SpinEdit_Height.Value);
  105. LazPaintInstance.Config.SetDefaultIconImageBackgroundColor(FBackColor);
  106. end else
  107. begin
  108. LazPaintInstance.Config.SetDefaultImageWidth(SpinEdit_Width.Value);
  109. LazPaintInstance.Config.SetDefaultImageHeight(SpinEdit_Height.Value);
  110. LazPaintInstance.Config.SetDefaultImageBackgroundColor(FBackColor);
  111. end;
  112. ModalResult:= mrOk;
  113. end;
  114. procedure TFNewImage.vsPreviewRedraw(Sender: TObject;
  115. Bitmap: TBGRABitmap);
  116. var
  117. tx,ty,px,py,x,y: NativeInt;
  118. ratio: double;
  119. sx,sy: NativeInt;
  120. blur: TBGRACustomBitmap;
  121. begin
  122. sx := vsPreview.Width- shadowOffsetX - shadowBlur;
  123. sy := vsPreview.Height- shadowOffsetY - shadowBlur;
  124. tx := SpinEdit_Width.Value;
  125. ty := SpinEdit_Height.Value;
  126. if (tx > 0) and (ty > 0) then
  127. begin
  128. ratio := tx/ty;
  129. if sx/ratio < vsPreview.Height then
  130. begin
  131. px := sx;
  132. py := round(sx/ratio);
  133. if py <= 0 then py := 1;
  134. end else
  135. begin
  136. px := round(sy*ratio);
  137. if px <= 0 then px := 1;
  138. py := sy;
  139. end;
  140. x := (sx-px) div 2;
  141. y := (sy-py) div 2;
  142. Bitmap.FillRect(x+shadowOffsetX,y+shadowOffsetY,x+shadowOffsetX+px,y+shadowOffsetY+py,BGRA(0,0,0,192),dmDrawWithTransparency);
  143. blur := bitmap.FilterBlurRadial(shadowBlur,rbFast);
  144. Bitmap.PutImage(0,0, blur,dmSet);
  145. blur.free;
  146. if (px = 1) or (py = 1) then
  147. Bitmap.FillRect(x,y,x+px,y+py,BGRABlack,dmSet)
  148. else
  149. begin
  150. ugraph.DrawCheckers(Bitmap,rect(x,y,x+px,y+py));
  151. Bitmap.Rectangle(x,y,x+px,y+py,BGRABlack,FBackColor,dmDrawWithTransparency);
  152. end;
  153. end;
  154. end;
  155. procedure TFNewImage.ToolButton_RotateClick(Sender: TObject);
  156. var tx,ty: integer;
  157. s: string;
  158. idxCol: integer;
  159. begin
  160. if FRecomputing then exit;
  161. FRecomputing:= true;
  162. tx := SpinEdit_Width.Value;
  163. ty := SpinEdit_Height.Value;
  164. SpinEdit_Width.Value := ty;
  165. SpinEdit_Height.Value := tx;
  166. if FRatio <> 0 then
  167. begin
  168. FRatio := 1/FRatio;
  169. s := ComboBox_Ratio.Text;
  170. idxCol := pos(':',s);
  171. if idxCol <> 0 then
  172. begin
  173. s := copy(s,idxCol+1,length(s)-idxCol)+':'+ copy(s,1,idxCol-1);
  174. ComboBox_Ratio.Text := s;
  175. end;
  176. end;
  177. FRecomputing:= false;
  178. if FLastEnteredValue = valWidth then
  179. FLastEnteredValue:= valHeight else
  180. if FLastEnteredValue = valHeight then
  181. FLastEnteredValue:= valWidth;
  182. UpdatePreview;
  183. end;
  184. procedure TFNewImage.ComboBox_RatioChange(Sender: TObject);
  185. begin
  186. if FRecomputing then exit;
  187. FRatio := ComputeRatio(ComboBox_Ratio.Text);
  188. if FRatio = 0 then exit;
  189. FRatioWasChanged := true;
  190. FRecomputing:= true;
  191. if FLastEnteredValue = valHeight then
  192. SpinEdit_Width.Value := round(SpinEdit_Height.Value*FRatio)
  193. else
  194. SpinEdit_Height.Value := round(SpinEdit_Width.Value/FRatio);
  195. FRecomputing:= false;
  196. UpdatePreview;
  197. end;
  198. procedure TFNewImage.ComboBox_RatioEnter(Sender: TObject);
  199. begin
  200. FRatioWasChanged := false;
  201. end;
  202. procedure TFNewImage.ComboBox_RatioExit(Sender: TObject);
  203. begin
  204. if FRatioWasChanged then
  205. FLastEnteredValue := valRatio;
  206. end;
  207. procedure TFNewImage.BGRAShapeClick(Sender: TObject);
  208. begin
  209. with (Sender as TBGRAShape) do
  210. FBackColor:= ColorToBGRA(FillColor,FillOpacity);
  211. UpdatePreview;
  212. end;
  213. procedure TFNewImage.ComboBox_BitDepthChange(Sender: TObject);
  214. begin
  215. if FRecomputing then exit;
  216. UpdatePreview;
  217. end;
  218. procedure TFNewImage.SpinEdit_HeightChange(Sender: TObject);
  219. begin
  220. if FRecomputing then exit;
  221. FRecomputing:= true;
  222. if (FLastEnteredValue = valRatio) and (FRatio <> 0) then
  223. begin
  224. SpinEdit_Width.Value := round(SpinEdit_Height.Value*FRatio);
  225. end else
  226. begin
  227. FLastEnteredValue:= valHeight;
  228. FRatio := 0;
  229. ComboBox_Ratio.Text := '';
  230. end;
  231. FRecomputing:= false;
  232. UpdatePreview;
  233. end;
  234. procedure TFNewImage.FormCreate(Sender: TObject);
  235. begin
  236. ScaleControl(Self,OriginalDPI);
  237. FRecomputing := true;
  238. SpinEdit_Width.MaxValue := MaxImageWidth;
  239. SpinEdit_Height.MaxValue := MaxImageHeight;
  240. FLastEnteredValue:= valWidth;
  241. FRecomputing := false;
  242. CheckOKCancelBtns(Button_OK,Button_Cancel);
  243. CheckSpinEdit(SpinEdit_Width);
  244. CheckSpinEdit(SpinEdit_Height);
  245. newImageResult := nil;
  246. end;
  247. procedure TFNewImage.FormShow(Sender: TObject);
  248. begin
  249. ToolBar_Rotate.Images := LazPaintInstance.Icons[DoScaleY(16,OriginalDPI)];
  250. Label_MemoryRequiredValue.Left := Label_MemoryRequired.BoundsRect.Right + DoScaleX(4,OriginalDPI);
  251. FRecomputing := true;
  252. if ForIcon then
  253. begin
  254. SpinEdit_Width.Value := LazPaintInstance.Config.DefaultIconImageWidth;
  255. SpinEdit_Height.Value := LazPaintInstance.Config.DefaultIconImageHeight;
  256. SpinEdit_Width.Increment := 16;
  257. SpinEdit_Height.Increment := 16;
  258. FBackColor:= LazPaintInstance.Config.DefaultIconImageBackgroundColor;
  259. ToolBar_Rotate.Visible := false;
  260. Label_BitDepth.Visible := true;
  261. ComboBox_BitDepth.Visible := true;
  262. ComboBox_BitDepth.Text := IntToStr(LazPaintInstance.Config.DefaultIconImageBitDepth);
  263. end else
  264. begin
  265. SpinEdit_Width.Value := LazPaintInstance.Config.DefaultImageWidth;
  266. SpinEdit_Height.Value := LazPaintInstance.Config.DefaultImageHeight;
  267. SpinEdit_Width.Increment := 10;
  268. SpinEdit_Height.Increment := 10;
  269. FBackColor:= LazPaintInstance.Config.DefaultImageBackgroundColor;
  270. ToolBar_Rotate.Visible := true;
  271. Label_BitDepth.Visible := false;
  272. ComboBox_BitDepth.Visible := false;
  273. ComboBox_BitDepth.Text := '32';
  274. end;
  275. if SpinEdit_Width.Value = SpinEdit_Height.Value then
  276. begin
  277. ComboBox_Ratio.Text := '1:1';
  278. FRatio := ComputeRatio(ComboBox_Ratio.Text);
  279. FLastEnteredValue := valRatio;
  280. end;
  281. FRecomputing := false;
  282. UpdatePreview;
  283. SafeSetFocus(SpinEdit_Width);
  284. SpinEdit_Width.SelectAll;
  285. end;
  286. procedure TFNewImage.SpinEdit_WidthChange(Sender: TObject);
  287. begin
  288. if FRecomputing then exit;
  289. FRecomputing:= true;
  290. if (FLastEnteredValue = valRatio) and (FRatio <> 0) then
  291. begin
  292. SpinEdit_Height.Value := round(SpinEdit_Width.Value/FRatio);
  293. end else
  294. begin
  295. FLastEnteredValue := valWidth;
  296. FRatio := 0;
  297. ComboBox_Ratio.Text := '';
  298. end;
  299. FRecomputing:= false;
  300. UpdatePreview;
  301. end;
  302. procedure TFNewImage.UpdatePreview;
  303. begin
  304. vsPreview.DiscardBitmap;
  305. Label_MemoryRequiredValue.Caption := FileSizeToStr(int64((SpinEdit_Width.Value*GetBitDepth+7) div 8)*SpinEdit_Height.Value,rsBytes);
  306. end;
  307. function TFNewImage.GetBitDepth: integer;
  308. begin
  309. result := StrToInt(ComboBox_BitDepth.Text);
  310. end;
  311. {$R *.lfm}
  312. end.