Main.pas 12 KB

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