Main.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. {
  2. Vampyre Imaging Library Demo
  3. Image Browser (class api, canvas, VCL/LCL interaction)
  4. This simple viewer application shows usage of high level class interface
  5. to Imaging library and also drawing images onto standard VCL/LCL TCanvas.
  6. TImagingCanvas class is also used here.
  7. In the left part of the window is shell tree view component. Here you can
  8. select files located in your computer. If the selected file is in one of the
  9. supported formats it is displayed in the viewer
  10. area and some information about the file is displayed in the info area.
  11. If image file contains subimages you can view them too. Select active subimage
  12. by clicking on buttons with arrows (Previous/Next).
  13. When supported file is selected in shell tree view it is loaded to
  14. TMultiImage and converted to ifA8R8G8B8
  15. data format. Active subimage is then drawn TPainBox component's
  16. client area using DisplayImage procedure (direct bit copy, no need to
  17. convert Imaging's data to TGraphic).
  18. You need ShellCtrls unit and its components installed in Delphi for this demo.
  19. In BDS 2006 you can find them in Demos\DelphiWin32\VCLWin32\ShellControls
  20. directory. In some other versions of Delphi it is installed by default during
  21. IDE installation.
  22. }
  23. unit Main;
  24. {$I ImagingOptions.inc}
  25. interface
  26. uses
  27. {$IFDEF MSWINDOWS}
  28. Windows,
  29. {$ENDIF}
  30. Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  31. Dialogs, ComCtrls, ShellCtrls, ExtCtrls, StdCtrls, Buttons, ExtDlgs,
  32. ImagingTypes,
  33. Imaging,
  34. ImagingClasses,
  35. ImagingComponents,
  36. ImagingCanvases,
  37. ImagingFormats,
  38. ImagingUtility;
  39. type
  40. TMainForm = class(TForm)
  41. ImageList: TImageList;
  42. LeftPanel: TPanel;
  43. RightPanel: TPanel;
  44. InfoPanel: TPanel;
  45. LabDataFormat: TLabel;
  46. LabFileFormat: TLabel;
  47. LabDim: TLabel;
  48. LabFileName: TLabel;
  49. Label3: TLabel;
  50. Label2: TLabel;
  51. Label1: TLabel;
  52. Lab1: TLabel;
  53. ViewPanel: TPanel;
  54. PaintBox: TPaintBox;
  55. Tree: TShellTreeView;
  56. Splitter1: TSplitter;
  57. Label4: TLabel;
  58. LabActImage: TLabel;
  59. StatusBar: TStatusBar;
  60. BtnPrev: TSpeedButton;
  61. BtnNext: TSpeedButton;
  62. BtnFirst: TSpeedButton;
  63. BtnLast: TSpeedButton;
  64. BtnSave: TButton;
  65. SaveDialog: TSavePictureDialog;
  66. CheckFilter: TCheckBox;
  67. procedure PaintBoxPaint(Sender: TObject);
  68. procedure FormCreate(Sender: TObject);
  69. procedure FormDestroy(Sender: TObject);
  70. procedure TreeChange(Sender: TObject; Node: TTreeNode);
  71. procedure BtnPrevClick(Sender: TObject);
  72. procedure BtnNextClick(Sender: TObject);
  73. procedure TreeKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  74. procedure BtnFirstClick(Sender: TObject);
  75. procedure BtnLastClick(Sender: TObject);
  76. procedure BtnSaveClick(Sender: TObject);
  77. procedure ViewPanelResize(Sender: TObject);
  78. procedure CheckFilterClick(Sender: TObject);
  79. private
  80. // Class that holds multiple images (loaded from MNG or DDS files for instance)
  81. FImage: ImagingClasses.TMultiImage;
  82. // Canvas for drawing on loaded images
  83. FImageCanvas: ImagingCanvases.TImagingCanvas;
  84. // Image background
  85. FBack: ImagingClasses.TSingleImage;
  86. // Canvas for background image
  87. FBackCanvas: ImagingCanvases.TImagingCanvas;
  88. FFileName: string;
  89. FLastTime: LongInt;
  90. FOriginalFormats: array of TImageFormat;
  91. FOriginalSizes: array of Integer;
  92. FSupported: Boolean;
  93. {$IFDEF FPC}
  94. procedure TreeGetImageIndex(Sender: TObject; Node: TTreeNode);
  95. procedure TreeGetSelectedIndex(Sender: TObject; Node: TTreeNode);
  96. {$ENDIF}
  97. public
  98. procedure SetSupported;
  99. procedure SetUnsupported;
  100. procedure LoadFile;
  101. procedure FillDefault;
  102. end;
  103. const
  104. FillColor = $FFE6F2FF;
  105. CheckersDensity = 32;
  106. SUnsupportedFormat = 'Selected item format not supported';
  107. var
  108. MainForm: TMainForm;
  109. implementation
  110. {$IFDEF FPC}
  111. {$R *.lfm}
  112. uses
  113. LCLType;
  114. {$ELSE}
  115. {$R *.dfm}
  116. {$ENDIF}
  117. procedure TMainForm.FormCreate(Sender: TObject);
  118. begin
  119. Caption := Caption + ' version ' + Imaging.GetVersionStr;
  120. FImage := TMultiImage.Create;
  121. FImageCanvas := TImagingCanvas.Create;
  122. FBack := TSingleImage.CreateFromParams(128, 128, ifA8R8G8B8);
  123. FBackCanvas := FindBestCanvasForImage(FBack).CreateForImage(FBack);
  124. SetUnsupported;
  125. {$IFDEF FPC}
  126. Tree.OnGetImageIndex := TreeGetImageIndex;
  127. Tree.OnGetSelectedIndex := TreeGetSelectedIndex;
  128. {$ENDIF}
  129. end;
  130. procedure TMainForm.FormDestroy(Sender: TObject);
  131. begin
  132. FImage.Free;
  133. FImageCanvas.Free;
  134. FBack.Free;
  135. FBackCanvas.Free;
  136. end;
  137. procedure TMainForm.LoadFile;
  138. var
  139. I: LongInt;
  140. T: Int64;
  141. begin
  142. try
  143. // DetermineFileFormat reads file header and returns image
  144. // file format identifier (like 'jpg', 'tga') if file is valid,
  145. // otherwise empty string is returned
  146. if Imaging.DetermineFileFormat(FFileName) <> '' then
  147. try
  148. // Load all subimages in file
  149. T := ImagingUtility.GetTimeMicroseconds;
  150. FImage.LoadMultiFromFile(FFileName);
  151. if not FImage.AllImagesValid then
  152. begin
  153. SetUnsupported;
  154. Exit;
  155. end;
  156. FLastTime := (ImagingUtility.GetTimeMicroseconds - T) div 1000;
  157. StatusBar.SimpleText := Format('Last image loaded in: %.0n ms', [FLastTime * 1.0]);
  158. // Store original data formats and sizes for later use
  159. SetLength(FOriginalFormats, FImage.ImageCount);
  160. SetLength(FOriginalSizes, FImage.ImageCount);
  161. for I := 0 to FImage.ImageCount - 1 do
  162. begin
  163. FImage.ActiveImage := I;
  164. FOriginalFormats[I] := FImage.Format;
  165. FOriginalSizes[I] := FImage.Size;
  166. // Convert image to 32bit ARGB format if current format is not supported
  167. // by canvas class
  168. if not (FImage.Format in TImagingCanvas.GetSupportedFormats) then
  169. FImage.Format := ifA8R8G8B8;
  170. end;
  171. // Activate first image and update UI
  172. FImage.ActiveImage := 0;
  173. SetSupported;
  174. PaintBox.Repaint;
  175. except
  176. SetUnsupported;
  177. raise;
  178. end
  179. else
  180. SetUnsupported;
  181. except
  182. SetUnsupported;
  183. end;
  184. end;
  185. procedure TMainForm.SetSupported;
  186. var
  187. XRes, YRes: Single;
  188. ImgSize: Integer;
  189. begin
  190. // Update image info and enable previous/next buttons
  191. ImgSize := FOriginalSizes[FImage.ActiveImage];
  192. if ImgSize > 8192 then
  193. ImgSize := ImgSize div 1024;
  194. LabDim.Caption := Format('%dx%d pixels', [FImage.Width, FImage.Height]);
  195. if GlobalMetadata.GetPhysicalPixelSize(ruDpi, XRes, YRes) then
  196. LabDim.Caption := LabDim.Caption + Format(' (DPI %.0nx%.0n)', [XRes, YRes]);
  197. LabFileFormat.Caption := Imaging.FindImageFileFormatByName(FFileName).Name;
  198. LabDataFormat.Caption := Imaging.GetFormatName(FOriginalFormats[FImage.ActiveImage]);
  199. LabDataFormat.Caption := LabDataFormat.Caption +
  200. Format(' (Size in memory: %s %s)', [IntToStrFmt(ImgSize), Iff(ImgSize = FOriginalSizes[FImage.ActiveImage], 'B', 'KiB')]);
  201. LabActImage.Caption := Format('%d/%d', [FImage.ActiveImage + 1, FImage.ImageCount]);
  202. BtnPrev.Enabled := True;
  203. BtnNext.Enabled := True;
  204. BtnFirst.Enabled := True;
  205. BtnLast.Enabled := True;
  206. BtnSave.Enabled := True;
  207. CheckFilter.Enabled := True;
  208. FSupported := True;
  209. end;
  210. procedure TMainForm.SetUnsupported;
  211. var
  212. X, Y, Step: LongInt;
  213. begin
  214. // Set info texts to 'unsupported' and create default image to show
  215. LabDim.Caption := SUnsupportedFormat;
  216. LabFileFormat.Caption := SUnsupportedFormat;
  217. LabDataFormat.Caption := SUnsupportedFormat;
  218. LabActImage.Caption := '0/0';
  219. StatusBar.SimpleText := 'No image loaded';
  220. BtnPrev.Enabled := False;
  221. BtnNext.Enabled := False;
  222. BtnFirst.Enabled := False;
  223. BtnLast.Enabled := False;
  224. BtnSave.Enabled := False;
  225. CheckFilter.Enabled := False;
  226. FSupported := False;
  227. if Assigned(FImage) then
  228. begin
  229. FImage.CreateFromParams(CheckersDensity, CheckersDensity, ifA8R8G8B8, 1);
  230. FImageCanvas.Free;
  231. FImageCanvas := FindBestCanvasForImage(FImage).CreateForImage(FImage);
  232. Step := FImage.Width div CheckersDensity;
  233. for Y := 0 to CheckersDensity - 1 do
  234. for X := 0 to CheckersDensity - 1 do
  235. begin
  236. FImageCanvas.FillColor32 := IffUnsigned((Odd(X) and not Odd(Y)) or (not Odd(X) and Odd(Y)),
  237. pcWhite, pcGray);
  238. FImageCanvas.FillRect(Rect(X * Step, Y * Step, (X + 1) * Step, (Y + 1) * Step));
  239. end;
  240. end;
  241. // Paint current image
  242. PaintBox.Repaint;
  243. end;
  244. procedure TMainForm.BtnPrevClick(Sender: TObject);
  245. begin
  246. FImage.ActiveImage := FImage.ActiveImage - 1;
  247. SetSupported;
  248. PaintBox.Repaint;
  249. end;
  250. procedure TMainForm.BtnSaveClick(Sender: TObject);
  251. var
  252. CopyPath: string;
  253. begin
  254. SaveDialog.Filter := Imaging.GetImageFileFormatsFilter(False);
  255. SaveDialog.FileName := ChangeFileExt(ExtractFileName(FFileName), '');
  256. SaveDialog.FilterIndex := Imaging.GetFileNameFilterIndex(FFileName, False);
  257. if SaveDialog.Execute then
  258. begin
  259. CopyPath := ChangeFileExt(SaveDialog.FileName, '.' +
  260. Imaging.GetFilterIndexExtension(SaveDialog.FilterIndex, False));
  261. FImage.SaveMultiToFile(CopyPath);
  262. end;
  263. end;
  264. procedure TMainForm.CheckFilterClick(Sender: TObject);
  265. begin
  266. PaintBox.Repaint;
  267. end;
  268. procedure TMainForm.BtnFirstClick(Sender: TObject);
  269. begin
  270. FImage.ActiveImage := 0;
  271. SetSupported;
  272. PaintBox.Repaint;
  273. end;
  274. procedure TMainForm.BtnLastClick(Sender: TObject);
  275. begin
  276. FImage.ActiveImage := FImage.ImageCount - 1;
  277. SetSupported;
  278. PaintBox.Repaint;
  279. end;
  280. procedure TMainForm.BtnNextClick(Sender: TObject);
  281. begin
  282. FImage.ActiveImage := FImage.ActiveImage + 1;
  283. SetSupported;
  284. PaintBox.Repaint;
  285. end;
  286. procedure TMainForm.TreeChange(Sender: TObject; Node: TTreeNode);
  287. begin
  288. // Selected item in the shell tree view has been changed
  289. // we check whether the selected item is valid file in one of the
  290. // supported formats
  291. FFileName := Tree.Path;
  292. LabFileName.Caption := ExtractFileName(FFileName);
  293. if FileExists(FFileName) and Assigned(Imaging.FindImageFileFormatByName(FFileName)) then
  294. LoadFile
  295. else
  296. SetUnsupported;
  297. end;
  298. {$IFDEF FPC}
  299. procedure TMainForm.TreeGetImageIndex(Sender: TObject; Node: TTreeNode);
  300. begin
  301. if Node.HasChildren then
  302. Node.ImageIndex := 1
  303. else if IsFileFormatSupported(Node.Text) then
  304. Node.ImageIndex := 0;
  305. end;
  306. procedure TMainForm.TreeGetSelectedIndex(Sender: TObject; Node: TTreeNode);
  307. begin
  308. Node.SelectedIndex := Node.ImageIndex;
  309. end;
  310. {$ENDIF}
  311. procedure TMainForm.TreeKeyDown(Sender: TObject; var Key: Word;
  312. Shift: TShiftState);
  313. begin
  314. if FImage.ImageCount > 1 then
  315. begin
  316. if Key = VK_SPACE then
  317. BtnNextClick(Self);
  318. end;
  319. end;
  320. procedure TMainForm.ViewPanelResize(Sender: TObject);
  321. begin
  322. // Resize background image to fit the paint box
  323. FBack.Resize(PaintBox.ClientWidth, PaintBox.ClientHeight, rfNearest);
  324. // Update back canvas state after resizing of associated image
  325. FBackCanvas.UpdateCanvasState;
  326. end;
  327. procedure TMainForm.PaintBoxPaint(Sender: TObject);
  328. var
  329. R: TRect;
  330. Filter: TResizeFilter;
  331. begin
  332. // Fill background with default color
  333. FillDefault;
  334. // Determine which stretching filter to use
  335. if FSupported and CheckFilter.Checked then
  336. Filter := rfBicubic
  337. else
  338. Filter := rfNearest;
  339. // Scale image to fit the paint box
  340. R := ImagingUtility.ScaleRectToRect(FImage.BoundsRect, PaintBox.ClientRect);
  341. // Create canvas for current image frame
  342. FImageCanvas.Free;
  343. FImageCanvas := FindBestCanvasForImage(FImage).CreateForImage(FImage);
  344. // Stretch image over background canvas
  345. FImageCanvas.StretchDrawAlpha(FImage.BoundsRect, FBackCanvas, R, Filter);
  346. // Draw image to canvas (without conversion) using OS drawing functions.
  347. // Note that DisplayImage only supports images in ifA8R8G8B8 format so
  348. // if you have image in different format you must convert it or
  349. // create standard TBitmap by calling ImagingComponents.ConvertImageToBitmap
  350. ImagingComponents.DisplayImage(PaintBox.Canvas, PaintBox.BoundsRect, FBack);
  351. end;
  352. procedure TMainForm.FillDefault;
  353. begin
  354. // Fill background canvas with default color
  355. FBackCanvas.FillColor32 := FillColor;
  356. FBackCanvas.FillRect(Rect(0, 0, FBack.Width, FBack.Height));
  357. end;
  358. {
  359. File Notes:
  360. -- 0.80 Changes/Bug Fixes ---------------------------------
  361. - Added Lazarus support so dropped "VCL" prefix.
  362. -- 0.77 Changes/Bug Fixes ---------------------------------
  363. - Displays size of image in memory.
  364. -- 0.26.5 Changes/Bug Fixes ---------------------------------
  365. - Displays image physical resolution if present.
  366. -- 0.26.3 Changes/Bug Fixes ---------------------------------
  367. - Creates best canvas class for given image for faster
  368. blending and scaling.
  369. -- 0.25.0 Changes/Bug Fixes ---------------------------------
  370. - Added alpha blended drawing with optional filtered stretching.
  371. -- 0.21 Changes/Bug Fixes -----------------------------------
  372. - Added Save Image Copy button and related stuff.
  373. - Added XP controls manifest (no TXPManifest since its not
  374. in older Delphis).
  375. - Wrong active image index was shown sometimes after several
  376. clicks on Prev/Next buttons.
  377. - Added First/Last subimage buttons.
  378. - Original data format of subimages at index >1 is displayed right now
  379. (was always A8R8G8B8)
  380. - Space key now shows next subimage if multi-images is loaded.
  381. -- 0.19 Changes/Bug Fixes -----------------------------------
  382. - added canvas usage too
  383. - added support for viewing multiimages (like MNG)
  384. - change drawing to use stuff from ImagingComponents unit instead of
  385. converting to TBitmap
  386. - changed demo to use high level interface instead of low level
  387. }
  388. end.