MainForm.pas 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. {
  2. Vampyre Imaging Library Demo
  3. FireMonkey Demo (class api, fmx interaction)
  4. This demo is a simple image viewer. On the left of the window is a list box with
  5. information and thumbnail of images loaded from file. Selecting item in
  6. list box displays the image in image viewer component that fills the rest of
  7. the app window. Loaded image can be saved back to disk in one the supported
  8. file formats.
  9. Demo uses ImagingFmx extension to convert between Imaging's and FireMonkey's
  10. image classes.
  11. Image is loaded from the file in a background thread while the UI shows
  12. progress animation.
  13. Note: tested only in Delphi 10.4 now
  14. }
  15. unit MainForm;
  16. {$IF not Defined (DCC) or (CompilerVersion < 25.0)}
  17. {$MESSAGE FATAL 'Needs at least Delphi XE4'}
  18. {$IFEND}
  19. interface
  20. uses
  21. System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  22. FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.Filter.Effects, FMX.Graphics,
  23. FMX.Layouts, FMX.ListBox, FMX.ExtCtrls, FMX.Objects, FMX.StdCtrls, FMX.Effects,
  24. FMX.Controls.Presentation,
  25. ImagingTypes,
  26. Imaging,
  27. ImagingClasses,
  28. ImagingUtility,
  29. ImagingFmx;
  30. type
  31. TFormMain = class(TForm)
  32. Splitter: TSplitter;
  33. ToolBar: TToolBar;
  34. ListImages: TListBox;
  35. BtnOpenImage: TSpeedButton;
  36. ImageViewer: TImageViewer;
  37. StyleBook: TStyleBook;
  38. PanelBack: TPanel;
  39. AniIndicator: TAniIndicator;
  40. OpenDialog: TOpenDialog;
  41. BtnSaveImage: TSpeedButton;
  42. BtnAbout: TSpeedButton;
  43. EmbossEffect: TEmbossEffect;
  44. SaveDialog: TSaveDialog;
  45. procedure BtnOpenImageClick(Sender: TObject);
  46. procedure BtnAboutClick(Sender: TObject);
  47. procedure FormCreate(Sender: TObject);
  48. procedure FormDestroy(Sender: TObject);
  49. procedure BtnSaveImageClick(Sender: TObject);
  50. procedure ListImagesChange(Sender: TObject);
  51. private
  52. FImage: TMultiImage;
  53. FFileName: string;
  54. FLoaderThread: TThread;
  55. procedure LoadingFinished(Success: Boolean; const ErrorMsg: string);
  56. procedure FillListBox(Image: TMultiImage);
  57. procedure SelectImage(Index: Integer);
  58. end;
  59. var
  60. FormMain: TFormMain;
  61. implementation
  62. uses
  63. AboutForm;
  64. {$R *.fmx}
  65. const
  66. ThumbMaxX = 106;
  67. ThumbMaxY = 92;
  68. type
  69. TImgLoaderThread = class(TThread)
  70. private
  71. type
  72. TFinishedHandler = reference to procedure(Success: Boolean; const ErrorMsg: string);
  73. private
  74. FFileName: string;
  75. FImageRef: TMultiImage;
  76. FFinishedHandler: TFinishedHandler;
  77. protected
  78. procedure Execute; override;
  79. public
  80. constructor Create(const FileName: string; ImageRef: TMultiImage;
  81. FinishedHandler: TFinishedHandler);
  82. end;
  83. procedure ClearImagesAndThumbs(Img: TMultiImage);
  84. var
  85. I: Integer;
  86. begin
  87. for I := 0 to Img.ImageCount - 1 do
  88. begin
  89. if Img.DataArray[I].Tag <> nil then
  90. TObject(Img.DataArray[I].Tag).Free;
  91. end;
  92. Img.ClearAll;
  93. end;
  94. { TImgLoaderThread }
  95. constructor TImgLoaderThread.Create(const FileName: string;
  96. ImageRef: TMultiImage; FinishedHandler: TFinishedHandler);
  97. begin
  98. FFileName := FileName;
  99. FImageRef := ImageRef;
  100. FFinishedHandler := FinishedHandler;
  101. FreeOnTerminate := True;
  102. inherited Create(False);
  103. end;
  104. procedure TImgLoaderThread.Execute;
  105. var
  106. I: Integer;
  107. Success: Boolean;
  108. ErrorMsg: string;
  109. Thumb: TSingleImage;
  110. begin
  111. TThread.NameThreadForDebugging('ImageLoaderThread');
  112. ErrorMsg := '';
  113. // Delete old images and thumbnails
  114. ClearImagesAndThumbs(FImageRef);
  115. try
  116. // Load image from file
  117. FImageRef.LoadMultiFromFile(FFileName);
  118. Success := FImageRef.AllImagesValid;
  119. // Generate thumbnails for subimages
  120. for I := 0 to FImageRef.ImageCount - 1 do
  121. begin
  122. Thumb := TSingleImage.Create;
  123. FImageRef.ActiveImage := I;
  124. FImageRef.ResizeToFit(ThumbMaxX, ThumbMaxY, rfBilinear, Thumb);
  125. FImageRef.DataArray[I].Tag := Thumb;
  126. end;
  127. except
  128. on E: Exception do
  129. begin
  130. Success := False;
  131. ErrorMsg := E.Message;
  132. end;
  133. end;
  134. Synchronize(
  135. procedure
  136. begin
  137. FFinishedHandler(Success, ErrorMsg);
  138. end);
  139. end;
  140. { TFormMain }
  141. procedure TFormMain.FillListBox(Image: TMultiImage);
  142. var
  143. Item: TListBoxItem;
  144. I, ImgSize: Integer;
  145. Data: TImageData;
  146. Bmp: TBitmap;
  147. begin
  148. ListImages.Clear;
  149. Bmp := TBitmap.Create(0, 0);
  150. try
  151. for I := 0 to FImage.ImageCount - 1 do
  152. begin
  153. Data := FImage.DataArray[I];
  154. Item := TListBoxItem.Create(ListImages);
  155. Item.Parent := ListImages;
  156. Item.StyleLookup := 'ListBoxItem';
  157. ImgSize := Data.Size;
  158. if ImgSize > 8192 then
  159. ImgSize := ImgSize div 1024;
  160. ImagingFmx.ConvertImageToFmxBitmap(TSingleImage(Data.Tag), Bmp);
  161. Item.StylesData['ImgThumb'] := Bmp;
  162. Item.StylesData['TextTitle'] := Format('Image %d/%d', [I + 1, FImage.ImageCount]);
  163. Item.StylesData['TextInfo'] :=
  164. Format('Resolution: %dx%d', [Data.Width, Data.Height]) + sLineBreak +
  165. Format('Format: %s', [GetFormatName(Data.Format)]) + sLineBreak +
  166. Format('Size: %.0n %s', [ImgSize + 0.0, Iff(ImgSize = Data.Size, 'B', 'KiB')]);
  167. end;
  168. finally
  169. Bmp.Free;
  170. end;
  171. end;
  172. procedure TFormMain.FormCreate(Sender: TObject);
  173. begin
  174. Caption := Caption + ' - ' + Imaging.SImagingLibTitle + ' ' + Imaging.GetVersionStr;
  175. FImage := TMultiImage.Create;
  176. end;
  177. procedure TFormMain.FormDestroy(Sender: TObject);
  178. begin
  179. ClearImagesAndThumbs(FImage);
  180. FImage.Free;
  181. end;
  182. procedure TFormMain.ListImagesChange(Sender: TObject);
  183. begin
  184. if ListImages.ItemIndex >= 0 then
  185. SelectImage(ListImages.ItemIndex);
  186. end;
  187. procedure TFormMain.LoadingFinished(Success: Boolean; const ErrorMsg: string);
  188. begin
  189. if Success then
  190. begin
  191. FillListBox(FImage);
  192. ListImages.ItemIndex := 0;
  193. end
  194. else
  195. begin
  196. MessageDlg('Error loading image: ' + ErrorMsg, TMsgDlgType.mtError, [TMsgDlgBtn.mbOK], 0);
  197. FImage.ClearAll;
  198. end;
  199. AniIndicator.Visible := False;
  200. EmbossEffect.Enabled := False;
  201. ToolBar.Enabled := True;
  202. end;
  203. procedure TFormMain.SelectImage(Index: Integer);
  204. begin
  205. FImage.ActiveImage := Index;
  206. ImageViewer.BeginUpdate;
  207. try
  208. ImagingFmx.ConvertImageToFmxBitmap(FImage, ImageViewer.Bitmap);
  209. ImageViewer.BestFit;
  210. finally
  211. ImageViewer.EndUpdate;
  212. end;
  213. end;
  214. procedure TFormMain.BtnSaveImageClick(Sender: TObject);
  215. begin
  216. if not FImage.AllImagesValid then
  217. begin
  218. MessageDlg('No image is loaded.', TMsgDlgType.mtError, [TMsgDlgBtn.mbOK], 0);
  219. Exit;
  220. end;
  221. SaveDialog.Filter := GetImageFileFormatsFilter(False);
  222. SaveDialog.FileName := ChangeFileExt(ExtractFileName(FFileName), '');
  223. SaveDialog.FilterIndex := GetFileNameFilterIndex(FFileName, False);
  224. if SaveDialog.Execute then
  225. begin
  226. FFileName := ChangeFileExt(SaveDialog.FileName, '.' + GetFilterIndexExtension(SaveDialog.FilterIndex, False));
  227. FImage.SaveMultiToFile(FFileName);
  228. end;
  229. end;
  230. procedure TFormMain.BtnAboutClick(Sender: TObject);
  231. var
  232. X, Y: Integer;
  233. begin
  234. // Place it manually - poMainFormCenter etc. doesn't really work
  235. // when main form has poScreenCenter
  236. X := Left + (Width - FormAbout.Width) div 2;
  237. Y := Top + (Height - FormAbout.Height) div 2;
  238. FormAbout.SetBounds(X, Y, FormAbout.Width, FormAbout.Height);
  239. FormAbout.ShowModal;
  240. end;
  241. procedure TFormMain.BtnOpenImageClick(Sender: TObject);
  242. begin
  243. OpenDialog.Filter := Imaging.GetImageFileFormatsFilter(True);
  244. if OpenDialog.Execute then
  245. begin
  246. FFileName := OpenDialog.FileName;
  247. ListImages.Clear;
  248. ImageViewer.Bitmap.SetSize(0, 0);
  249. ToolBar.Enabled := False;
  250. AniIndicator.Visible := True;
  251. EmbossEffect.Enabled := True;
  252. FLoaderThread := TImgLoaderThread.Create(FFileName, FImage, LoadingFinished);
  253. end;
  254. end;
  255. end.