MainForm.pas 7.7 KB

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