MainUnit.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. unit MainUnit;
  2. {$include GR32.inc}
  3. interface
  4. uses
  5. {$IFNDEF FPC} Windows, {$ELSE} LCLIntf, LCLType, {$ENDIF}
  6. SysUtils, Classes, Graphics, Controls, Forms, Menus, Dialogs, ComCtrls,
  7. ExtCtrls, StdCtrls, Math,
  8. GR32,
  9. GR32_Image,
  10. GR32_Layers;
  11. type
  12. TFrmBlurs = class(TForm)
  13. MnuBlurType: TMenuItem;
  14. CbxBidirectional: TCheckBox;
  15. MnuFile: TMenuItem;
  16. ImgViewPage1: TImgView32;
  17. ImgViewPage2: TImgView32;
  18. ImgViewPage3: TImgView32;
  19. LblBlurAngle: TLabel;
  20. LblBlurRadius: TLabel;
  21. MainMenu: TMainMenu;
  22. MnuExit: TMenuItem;
  23. MnuGaussianType: TMenuItem;
  24. MnuMotion: TMenuItem;
  25. MnuNone: TMenuItem;
  26. N1: TMenuItem;
  27. MnuOpen: TMenuItem;
  28. OpenDialog: TOpenDialog;
  29. PageControl: TPageControl;
  30. PnlControl: TPanel;
  31. RgpBlurType: TRadioGroup;
  32. SbrMain: TStatusBar;
  33. TabSheet1: TTabSheet;
  34. TabSheet2: TTabSheet;
  35. TabSheet3: TTabSheet;
  36. TbrBlurAngle: TTrackBar;
  37. TbrBlurRadius: TTrackBar;
  38. CheckBoxCorrectGamma: TCheckBox;
  39. LabelDelta: TLabel;
  40. TrackBarDelta: TTrackBar;
  41. PanelSelective: TPanel;
  42. MnuSelective: TMenuItem;
  43. PanelMotion: TPanel;
  44. TimerUpdate: TTimer;
  45. PanelRadius: TPanel;
  46. procedure FormCreate(Sender: TObject);
  47. procedure FormDestroy(Sender: TObject);
  48. procedure MnuExitClick(Sender: TObject);
  49. procedure MnuGaussianTypeClick(Sender: TObject);
  50. procedure MnuOpenClick(Sender: TObject);
  51. procedure PageControlChange(Sender: TObject);
  52. procedure RgpBlurTypeClick(Sender: TObject);
  53. procedure TbrBlurAngleChange(Sender: TObject);
  54. procedure TbrBlurRadiusChange(Sender: TObject);
  55. procedure TrackBarDeltaChange(Sender: TObject);
  56. procedure TimerUpdateTimer(Sender: TObject);
  57. private
  58. FBitmapStoneWeed: TBitmap32;
  59. FBitmapIceland: TBitmap32;
  60. FBitmapRandBox: TBitmap32;
  61. FLayerBitmap: TBitmapLayer;
  62. FRedrawFlag: Boolean;
  63. procedure Redraw;
  64. procedure QueueUpdate;
  65. end;
  66. var
  67. FrmBlurs: TFrmBlurs;
  68. implementation
  69. uses
  70. {$if defined(UseInlining)}
  71. Types,
  72. {$ifend}
  73. GR32.ImageFormats.JPG,
  74. GR32_Polygons,
  75. GR32_VectorUtils,
  76. GR32_System,
  77. GR32.Blur,
  78. GR32.Blur.SelectiveGaussian,
  79. GR32_Blurs;
  80. {$R *.dfm}
  81. const
  82. GaussianBlurSimple: array [Boolean] of TBlurFunction = (Blur32, GammaBlur32);
  83. GaussianBlurBounds: array [Boolean] of TBlurFunctionBounds = (Blur32, GammaBlur32);
  84. GaussianBlurRegion: array [Boolean] of TBlurFunctionRegion = (Blur32, GammaBlur32);
  85. { Miscellaneous functions }
  86. procedure DrawFramedBox(Bmp32: TBitmap32; const Rec: TRect;
  87. Color1, Color2: TColor32; LineWidth: TFloat);
  88. var
  89. Pts: TArrayOfFloatPoint;
  90. begin
  91. if LineWidth < 1 then
  92. LineWidth := 1;
  93. SetLength(Pts, 6);
  94. Pts[0] := FloatPoint(Rec.Left, Rec.Bottom);
  95. Pts[1] := FloatPoint(Rec.Left, Rec.Top);
  96. Pts[2] := FloatPoint(Rec.Right, Rec.Top);
  97. Pts[3] := FloatPoint(Rec.Right - LineWidth, Rec.Top + LineWidth);
  98. Pts[4] := FloatPoint(Rec.Left + LineWidth, Rec.Top + LineWidth);
  99. Pts[5] := FloatPoint(Rec.Left + LineWidth, Rec.Bottom - LineWidth);
  100. PolygonFS(Bmp32, Pts, Color1);
  101. Pts[1] := FloatPoint(Rec.Right, Rec.Bottom);
  102. Pts[2] := FloatPoint(Rec.Right, Rec.Top);
  103. Pts[3] := FloatPoint(Rec.Right - LineWidth, Rec.Top + LineWidth);
  104. Pts[4] := FloatPoint(Rec.Right - LineWidth, Rec.Bottom - LineWidth);
  105. Pts[5] := FloatPoint(Rec.Left + LineWidth, Rec.Bottom - LineWidth);
  106. PolygonFS(Bmp32, Pts, Color2);
  107. end;
  108. { TFrmBlurs }
  109. procedure TFrmBlurs.FormCreate(Sender: TObject);
  110. var
  111. X, Y: Integer;
  112. const
  113. Colors: array [0 .. 21] of TColor32 = (clAliceBlue32, clAquamarine32,
  114. clAzure32, clBeige32, clBlueViolet32, clCadetblue32, clChocolate32,
  115. clCoral32, clCornFlowerBlue32, clCornSilk32, clCrimson32,
  116. clDarkBlue32, clDarkCyan32, clDarkGoldenRod32, clDarkGreen32,
  117. clDarkMagenta32, clDarkOrange32, clDarkOrchid32, clDarkRed32,
  118. clDarkSalmon32, clDarkSeaGreen32, clDarkSlateBlue32);
  119. begin
  120. FBitmapStoneWeed := TBitmap32.create;
  121. FBitmapStoneWeed.DrawMode := dmBlend;
  122. FBitmapStoneWeed.LoadFromResourceName(hInstance, 'STONEWEED', RT_RCDATA);
  123. FBitmapIceland := TBitmap32.create;
  124. FBitmapIceland.DrawMode := dmBlend;
  125. FBitmapIceland.LoadFromResourceName(hInstance, 'ICELAND', RT_RCDATA);
  126. Randomize;
  127. FBitmapRandBox := TBitmap32.create;
  128. // Generate an image of full of random, semi-transparent, colored boxes ...
  129. FBitmapRandBox.SetSize(192, 272);
  130. for X := 0 to 11 do
  131. for Y := 0 to 16 do
  132. FBitmapRandBox.FillRectS(X * 16, Y * 16, 300 + (X + 1) * 16,
  133. 40 + (Y + 1) * 16, SetAlpha(Colors[Random(22)], 128));
  134. FLayerBitmap := TBitmapLayer(ImgViewPage3.Layers.Add(TBitmapLayer));
  135. FLayerBitmap.Bitmap.DrawMode := dmBlend;
  136. RgpBlurType.ItemIndex := 1;
  137. {$ifndef FPC}
  138. PnlControl.Padding.Left := 8;
  139. PnlControl.Padding.Right := 8;
  140. PnlControl.Padding.Top := 8;
  141. PnlControl.Padding.Bottom := 8;
  142. PanelSelective.Padding.Top := 8;
  143. PanelMotion.Padding.Top := 8;
  144. PanelRadius.Padding.Top := 8;
  145. {$else}
  146. PnlControl.BorderSpacing.Around := 8;
  147. PanelSelective.BorderSpacing.Top := 8;
  148. PanelMotion.BorderSpacing.Top := 8;
  149. PanelRadius.BorderSpacing.Top := 8;
  150. {$endif}
  151. end;
  152. procedure TFrmBlurs.FormDestroy(Sender: TObject);
  153. begin
  154. FBitmapStoneWeed.Free;
  155. FBitmapIceland.Free;
  156. FBitmapRandBox.Free;
  157. end;
  158. procedure TFrmBlurs.Redraw;
  159. var
  160. Radius: Integer;
  161. Rec, Rec2: TRect;
  162. Pts, Pts2: TArrayOfFloatPoint;
  163. WithGamma: Boolean;
  164. Stopwatch: TStopwatch;
  165. begin
  166. if FRedrawFlag then
  167. Exit;
  168. FRedrawFlag := True;
  169. try
  170. Screen.Cursor := crHourGlass;
  171. Radius := TbrBlurRadius.Position;
  172. WithGamma := CheckBoxCorrectGamma.Checked;
  173. case PageControl.ActivePageIndex of
  174. 0:
  175. begin
  176. ImgViewPage1.BeginUpdate;
  177. try
  178. ImgViewPage1.Bitmap.Assign(FBitmapIceland);
  179. Stopwatch := TStopwatch.StartNew;
  180. case RgpBlurType.ItemIndex of
  181. 1:
  182. GaussianBlurSimple[WithGamma](ImgViewPage1.Bitmap, Radius);
  183. 2:
  184. if WithGamma then
  185. MotionBlurGamma(ImgViewPage1.Bitmap, Radius, TbrBlurAngle.Position, CbxBidirectional.Checked)
  186. else
  187. MotionBlur(ImgViewPage1.Bitmap, Radius, TbrBlurAngle.Position, CbxBidirectional.Checked);
  188. 3:
  189. if WithGamma then
  190. GammaSelectiveGaussianBlur32(FBitmapIceland, ImgViewPage1.Bitmap, Radius, TrackBarDelta.Position)
  191. else
  192. SelectiveGaussianBlur32(FBitmapIceland, ImgViewPage1.Bitmap, Radius, TrackBarDelta.Position);
  193. end;
  194. Stopwatch.Stop;
  195. finally
  196. ImgViewPage1.EndUpdate;
  197. end;
  198. end;
  199. 1:
  200. begin
  201. ImgViewPage2.BeginUpdate;
  202. try
  203. ImgViewPage2.Bitmap.Assign(FBitmapStoneWeed);
  204. Pts := Star(130, 150, 90, 5, -0.5 * Pi);
  205. Pts2 := Ellipse(350, 250, 100, 60);
  206. Stopwatch := TStopwatch.StartNew;
  207. case RgpBlurType.ItemIndex of
  208. 1:
  209. begin
  210. GaussianBlurRegion[WithGamma](ImgViewPage2.Bitmap, Radius, Pts);
  211. GaussianBlurRegion[WithGamma](ImgViewPage2.Bitmap, Radius, Pts2);
  212. end;
  213. 2:
  214. if WithGamma then
  215. begin
  216. MotionBlurGamma(ImgViewPage2.Bitmap, Radius, TbrBlurAngle.Position, Pts, CbxBidirectional.Checked);
  217. MotionBlurGamma(ImgViewPage2.Bitmap, Radius, TbrBlurAngle.Position, Pts2, CbxBidirectional.Checked);
  218. end
  219. else
  220. begin
  221. MotionBlur(ImgViewPage2.Bitmap, Radius, TbrBlurAngle.Position, Pts, CbxBidirectional.Checked);
  222. MotionBlur(ImgViewPage2.Bitmap, Radius, TbrBlurAngle.Position, Pts2, CbxBidirectional.Checked);
  223. end;
  224. end;
  225. Stopwatch.Stop;
  226. PolylineFS(ImgViewPage2.Bitmap, Pts, clBlack32, True, 2.5);
  227. PolylineFS(ImgViewPage2.Bitmap, Pts2, clBlack32, True, 2.5);
  228. finally
  229. ImgViewPage2.EndUpdate;
  230. end;
  231. end;
  232. 2:
  233. begin
  234. ImgViewPage3.BeginUpdate;
  235. try
  236. ImgViewPage3.SetupBitmap(True, Color32(clBtnFace));
  237. Rec := ImgViewPage3.GetBitmapRect;
  238. FLayerBitmap.Location := FloatRect(Rec);
  239. FLayerBitmap.Bitmap.SetSize(Rec.Width, Rec.Height);
  240. FLayerBitmap.Bitmap.Clear(0);
  241. // Colored squares on layer
  242. FLayerBitmap.Bitmap.Draw(300, 40, FBitmapRandBox);
  243. // Beveled box on background image
  244. Rec := Rect(40, 40, 240, 120);
  245. DrawFramedBox(ImgViewPage3.Bitmap, Rec, clWhite32, clGray32, Radius div 2);
  246. // Red rectangle on layer
  247. Rec2 := Rect(40, 160, 240, 320);
  248. FLayerBitmap.Bitmap.FillRectTS(Rec2, clRed32);
  249. GR32.InflateRect(Rec2, 20, 20);
  250. // Ellipse on top of colored squares
  251. Pts := Ellipse(395, 175, 60, 100);
  252. Stopwatch := TStopwatch.StartNew;
  253. case RgpBlurType.ItemIndex of
  254. 1:
  255. begin
  256. GaussianBlurBounds[WithGamma](ImgViewPage3.Bitmap, Radius, Rec);
  257. GaussianBlurBounds[WithGamma](FLayerBitmap.Bitmap, Radius, Rec2);
  258. GaussianBlurRegion[WithGamma](FLayerBitmap.Bitmap, Radius, Pts);
  259. end;
  260. 2:
  261. if WithGamma then
  262. begin
  263. MotionBlurGamma(ImgViewPage3.Bitmap, Radius, TbrBlurAngle.Position, Rec, CbxBidirectional.Checked);
  264. MotionBlurGamma(FLayerBitmap.Bitmap, Radius, TbrBlurAngle.Position, Rec2, CbxBidirectional.Checked);
  265. MotionBlurGamma(FLayerBitmap.Bitmap, Radius, TbrBlurAngle.Position, Pts, CbxBidirectional.Checked);
  266. end
  267. else
  268. begin
  269. MotionBlur(ImgViewPage3.Bitmap, Radius, TbrBlurAngle.Position, Rec, CbxBidirectional.Checked);
  270. MotionBlur(FLayerBitmap.Bitmap, Radius, TbrBlurAngle.Position, Rec2, CbxBidirectional.Checked);
  271. MotionBlur(FLayerBitmap.Bitmap, Radius, TbrBlurAngle.Position, Pts, CbxBidirectional.Checked);
  272. end;
  273. end;
  274. Stopwatch.Stop;
  275. // Outline ellipse
  276. PolylineFS(FLayerBitmap.Bitmap, Pts, clTrBlack32, True, 2.5);
  277. // Outline red rectangle
  278. GR32.InflateRect(Rec2, 1, 1);
  279. PolylineFS(
  280. FLayerBitmap.Bitmap,
  281. Rectangle(Rec2),
  282. clBlack32,
  283. True,
  284. 0.5);
  285. finally
  286. ImgViewPage3.EndUpdate;
  287. end;
  288. end;
  289. end;
  290. SbrMain.SimpleText := Format(' Blur drawing time: %d ms', [Stopwatch.ElapsedMilliseconds]);
  291. finally
  292. FRedrawFlag := False;
  293. Screen.Cursor := crDefault;
  294. end;
  295. end;
  296. procedure TFrmBlurs.MnuExitClick(Sender: TObject);
  297. begin
  298. Close;
  299. end;
  300. procedure TFrmBlurs.RgpBlurTypeClick(Sender: TObject);
  301. procedure EnableGroup(Parent: TControl; State: boolean);
  302. var
  303. i: integer;
  304. begin
  305. Parent.Enabled := State;
  306. if (Parent is TWinControl) then
  307. for i := 0 to TWinControl(Parent).ControlCount-1 do
  308. EnableGroup(TWinControl(Parent).Controls[i], State);
  309. end;
  310. begin
  311. MnuNone.Checked := (RgpBlurType.ItemIndex = 0);
  312. MnuGaussianType.Checked := (RgpBlurType.ItemIndex = 1);
  313. MnuMotion.Checked := (RgpBlurType.ItemIndex = 2);
  314. MnuSelective.Checked := (RgpBlurType.ItemIndex = 3);
  315. EnableGroup(PanelRadius, (RgpBlurType.ItemIndex <> 0));
  316. EnableGroup(PanelMotion, (RgpBlurType.ItemIndex = 2));
  317. EnableGroup(PanelSelective, (RgpBlurType.ItemIndex = 3));
  318. case RgpBlurType.ItemIndex of
  319. 1: // The current Gaussian Blur begins introducing overflow artifacts at around radius=200
  320. TbrBlurRadius.Max := 200;
  321. 2: // Motion blur internally limits the radius to 256
  322. TbrBlurRadius.Max := 256;
  323. 3: // Selective blur is very slow, so limit the damage
  324. TbrBlurRadius.Max := 20;
  325. end;
  326. Redraw;
  327. end;
  328. procedure TFrmBlurs.TimerUpdateTimer(Sender: TObject);
  329. begin
  330. TimerUpdate.Enabled := False;
  331. Redraw;
  332. end;
  333. procedure TFrmBlurs.TbrBlurRadiusChange(Sender: TObject);
  334. begin
  335. LblBlurRadius.Caption := Format('Blur &Radius (%d)', [TbrBlurRadius.Position]);
  336. QueueUpdate;
  337. end;
  338. procedure TFrmBlurs.TrackBarDeltaChange(Sender: TObject);
  339. begin
  340. LabelDelta.Caption := Format('Delta (%d)', [TrackBarDelta.Position]);
  341. QueueUpdate;
  342. end;
  343. procedure TFrmBlurs.TbrBlurAngleChange(Sender: TObject);
  344. begin
  345. LblBlurAngle.Caption := Format('Blur &Angle (%d)', [TbrBlurAngle.Position]);
  346. QueueUpdate;
  347. end;
  348. procedure TFrmBlurs.MnuGaussianTypeClick(Sender: TObject);
  349. begin
  350. if Sender = MnuGaussianType then
  351. RgpBlurType.ItemIndex := 1
  352. else
  353. if Sender = MnuMotion then
  354. RgpBlurType.ItemIndex := 2
  355. else
  356. if Sender = MnuSelective then
  357. RgpBlurType.ItemIndex := 3
  358. else
  359. RgpBlurType.ItemIndex := 0
  360. end;
  361. procedure TFrmBlurs.MnuOpenClick(Sender: TObject);
  362. begin
  363. if OpenDialog.Execute then
  364. begin
  365. FBitmapIceland.LoadFromFile(OpenDialog.FileName);
  366. PageControl.ActivePageIndex := 0;
  367. Redraw;
  368. end;
  369. end;
  370. procedure TFrmBlurs.PageControlChange(Sender: TObject);
  371. begin
  372. Redraw;
  373. end;
  374. procedure TFrmBlurs.QueueUpdate;
  375. begin
  376. TimerUpdate.Enabled := False;
  377. TimerUpdate.Enabled := True;
  378. end;
  379. end.