2
0

DemoUnit.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. {
  2. Vampyre Imaging Library Demo
  3. Benchmark (core low level API)
  4. Simple program which measures time taken by the main Imaging functions
  5. (loading, manipulation, saving) in microsecond resolution.
  6. You can use it to compare the speeds of executables created by the supported
  7. compilers (you can find results for my machine somewhere in Demos directory).
  8. }
  9. unit DemoUnit;
  10. {$I ImagingOptions.inc}
  11. { Define this to write results to log file or undef it to
  12. display them on screen.}
  13. {.$DEFINE LOG_TO_FILE}
  14. { Define this to write images created in saving test on disk.
  15. They are saved only to memory when testing.}
  16. {$DEFINE SAVE_IMAGES_TO_FILES}
  17. interface
  18. procedure RunDemo;
  19. implementation
  20. uses
  21. SysUtils,
  22. Classes,
  23. ImagingTypes,
  24. Imaging,
  25. ImagingUtility,
  26. DemoUtils;
  27. type
  28. TManipulation = (maResize3k, maResize1k, maFlip, maMirror, maSwapChannels,
  29. maConvARGB64, maConvARGBF, maConvARGB16, maConvRGB24, maConvARGB32,
  30. maCompressDXT, maDecompressDXT, maReduceColors, maClone, maMipMaps,
  31. maCopyRect, maMapImage, maFill, maSplit, maMakePal, maReplace,
  32. maRotate180, maRotate90, maStretchRect);
  33. TFileFormatInfo = record
  34. Name: string;
  35. Ext: string;
  36. Masks: string;
  37. CanSave: Boolean;
  38. IsMulti: Boolean;
  39. end;
  40. const
  41. SDataDir = 'Data';
  42. SImageName = 'Tigers';
  43. SSaveImage = '_BenchOut';
  44. SLogFileName = 'ResultsPas.log';
  45. var
  46. Time: Int64;
  47. Img: TImageData;
  48. {$IFDEF LOG_TO_FILE}
  49. Output: TextFile;
  50. {$ENDIF}
  51. procedure WriteTimeDiff(const Msg: string; const OldTime: Int64);
  52. var
  53. Diff: Double;
  54. S: string;
  55. begin
  56. Diff := (GetTimeMicroseconds - OldTime) * 1.0;
  57. S := Format('%-58s %16.0n us', [Msg, Diff], GetFormatSettingsForFloats);
  58. WriteLn(Output, S);
  59. end;
  60. function GetImageName(const Ext: string): string;
  61. begin
  62. Result := GetDataDir + PathDelim + SImageName + '.' + Ext;
  63. end;
  64. procedure LoadImage(const Name: string);
  65. var
  66. Mem: TMemoryStream;
  67. begin
  68. if FileExists(Name) then
  69. begin
  70. Mem := TMemoryStream.Create;
  71. try
  72. WriteLn(Output, 'Loading image: ' + ExtractFileName(Name));
  73. Mem.LoadFromFile(Name);
  74. Time := GetTimeMicroseconds;
  75. // We are loading from memory stream so there is no file system
  76. // overhead measured.
  77. Imaging.LoadImageFromStream(Mem, Img);
  78. WriteTimeDiff('Image loaded in:', Time);
  79. finally
  80. Mem.Free;
  81. end;
  82. end;
  83. end;
  84. procedure SaveImage(const Ext: string);
  85. var
  86. Mem: TMemoryStream;
  87. begin
  88. Mem := TMemoryStream.Create;
  89. WriteLn(Output, 'Saving image to format: ' + Ext);
  90. try
  91. Time := GetTimeMicroseconds;
  92. // We are saving to memory stream so there is no file system
  93. // overhead measured. But if image is in data format which is not
  94. // supported by this file format the measured time will include conversion
  95. // time.
  96. Imaging.SaveImageToStream(Ext, Mem, Img);
  97. WriteTimeDiff('Image saved in:', Time);
  98. {$IFDEF SAVE_IMAGES_TO_FILES}
  99. Mem.SaveToFile(GetAppDir + PathDelim + sSaveImage + '.' + Ext);
  100. {$ENDIF}
  101. finally
  102. Mem.Free;
  103. end;
  104. end;
  105. var
  106. ImgClone: TImageData;
  107. Subs: TDynImageDataArray;
  108. FillColor: TColor32Rec = (Color: $FFFF0000);
  109. NewColor: TColor32Rec = (Color: $FF00CCFF);
  110. I, XCount, YCount: LongInt;
  111. Pal: PPalette32;
  112. Formats: array of TFileFormatInfo;
  113. procedure ManipulateImage(Man: TManipulation);
  114. begin
  115. // According to the enum value image manipulation functions are
  116. // called and measured.
  117. case Man of
  118. maResize3k:
  119. begin
  120. WriteLn(Output, 'Resizing image to 3000x3000 (bilinear) ... ');
  121. Time := GetTimeMicroseconds;
  122. Imaging.ResizeImage(Img, 3000, 3000, rfBilinear);
  123. WriteTimeDiff('Image resized in: ', Time);
  124. end;
  125. maResize1k:
  126. begin
  127. WriteLn(Output, 'Resizing image to 1000x1000 (bicubic) ... ');
  128. Time := GetTimeMicroseconds;
  129. Imaging.ResizeImage(Img, 1000, 1000, rfBicubic);
  130. WriteTimeDiff('Image resized in: ', Time);
  131. end;
  132. maFlip:
  133. begin
  134. WriteLn(Output, 'Flipping image ... ');
  135. Time := GetTimeMicroseconds;
  136. Imaging.FlipImage(Img);
  137. WriteTimeDiff('Image flipped in: ', Time);
  138. end;
  139. maMirror:
  140. begin
  141. WriteLn(Output, 'Mirroring image ... ');
  142. Time := GetTimeMicroseconds;
  143. Imaging.MirrorImage(Img);
  144. WriteTimeDiff('Image mirrored in:', Time);
  145. end;
  146. maSwapChannels:
  147. begin
  148. WriteLn(Output, 'Swapping channels of image ... ');
  149. Time := GetTimeMicroseconds;
  150. Imaging.SwapChannels(Img, ChannelRed, ChannelGreen);
  151. WriteTimeDiff('Channels swapped in: ', Time);
  152. end;
  153. maConvARGB64:
  154. begin
  155. WriteLn(Output, 'Converting image to A16R16G16B16 64bit format ... ');
  156. Time := GetTimeMicroseconds;
  157. Imaging.ConvertImage(Img, ifA16R16G16B16);
  158. WriteTimeDiff('Image converted in: ', Time);
  159. end;
  160. maConvARGBF:
  161. begin
  162. WriteLn(Output, 'Converting image to A32B32G32R32F 128bit floating ' +
  163. 'point format... ');
  164. Time := GetTimeMicroseconds;
  165. Imaging.ConvertImage(Img, ifA32B32G32R32F);
  166. WriteTimeDiff('Image converted in: ', Time);
  167. end;
  168. maConvARGB16:
  169. begin
  170. WriteLn(Output, 'Converting image to A4R4G4B4 16bit format... ');
  171. Time := GetTimeMicroseconds;
  172. Imaging.ConvertImage(Img, ifA4R4G4B4);
  173. WriteTimeDiff('Image converted in: ', Time);
  174. end;
  175. maConvRGB24:
  176. begin
  177. WriteLn(Output, 'Converting image to R8G8B8 24bit format... ');
  178. Time := GetTimeMicroseconds;
  179. Imaging.ConvertImage(Img, ifR8G8B8);
  180. WriteTimeDiff('Image converted in: ', Time);
  181. end;
  182. maConvARGB32:
  183. begin
  184. WriteLn(Output, 'Converting image to A8R8G8B8 32bit format... ');
  185. Time := GetTimeMicroseconds;
  186. Imaging.ConvertImage(Img, ifA8R8G8B8);
  187. WriteTimeDiff('Image converted in: ', Time);
  188. end;
  189. maCompressDXT:
  190. begin
  191. WriteLn(Output, 'Compressing image to DXT1 format... ');
  192. Time := GetTimeMicroseconds;
  193. Imaging.ConvertImage(Img, ifDXT1);
  194. WriteTimeDiff('Image compressed in: ', Time);
  195. end;
  196. maDecompressDXT:
  197. begin
  198. WriteLn(Output, 'Decompressing image from DXT1 format... ');
  199. Time := GetTimeMicroseconds;
  200. Imaging.ConvertImage(Img, ifA8R8G8B8);
  201. WriteTimeDiff('Image decompressed in: ', Time);
  202. end;
  203. maReduceColors:
  204. begin
  205. WriteLn(Output, 'Reducing colors count to 1024... ');
  206. Time := GetTimeMicroseconds;
  207. Imaging.ReduceColors(Img, 1024);
  208. WriteTimeDiff('Colors reduced in: ', Time);
  209. end;
  210. maMipMaps:
  211. begin
  212. WriteLn(Output, 'Creating mipmaps ... ');
  213. SetLength(Subs, 0);
  214. Time := GetTimeMicroseconds;
  215. Imaging.GenerateMipMaps(Img, 0, Subs);
  216. WriteTimeDiff('Mipmaps created in: ', Time);
  217. Imaging.FreeImagesInArray(Subs);
  218. end;
  219. maClone:
  220. begin
  221. WriteLn(Output, 'Cloning image ... ');
  222. Imaging.InitImage(ImgClone);
  223. Time := GetTimeMicroseconds;
  224. Imaging.CloneImage(Img, ImgClone);
  225. WriteTimeDiff('Image cloned in: ', Time);
  226. end;
  227. maCopyRect:
  228. begin
  229. WriteLn(Output, 'Copying rectangle ... ');
  230. Time := GetTimeMicroseconds;
  231. Imaging.CopyRect(ImgClone, 0, 1500, 1500, 1500, Img, 0, 0);
  232. WriteTimeDiff('Rectangle copied in: ', Time);
  233. end;
  234. maStretchRect:
  235. begin
  236. WriteLn(Output, 'Stretching rectangle (bicubic) ... ');
  237. Time := GetTimeMicroseconds;
  238. Imaging.StretchRect(ImgClone, 0, 1500, 1500, 1500, Img, 500, 500, 2000, 2000, rfBicubic);
  239. WriteTimeDiff('Rectangle stretched in: ', Time);
  240. Imaging.FreeImage(ImgClone);
  241. end;
  242. maMapImage:
  243. begin
  244. WriteLn(Output, 'Mapping image to existing palette ... ');
  245. Time := GetTimeMicroseconds;
  246. Imaging.MapImageToPalette(Img, Pal, 256);
  247. WriteTimeDiff('Image mapped in: ', Time);
  248. Imaging.FreePalette(Pal);
  249. end;
  250. maFill:
  251. begin
  252. WriteLn(Output, 'Filling rectangle ... ');
  253. Time := GetTimeMicroseconds;
  254. Imaging.FillRect(Img, 1500, 0, 1500, 1500, @FillColor);
  255. WriteTimeDiff('Rectangle filled in: ', Time);
  256. end;
  257. maReplace:
  258. begin
  259. WriteLn(Output, 'Replacing colors in rectangle ... ');
  260. Time := GetTimeMicroseconds;
  261. Imaging.ReplaceColor(Img, 0, 0, Img.Width, Img.Height, @FillColor, @NewColor);
  262. WriteTimeDiff('Colors replaced in: ', Time);
  263. end;
  264. maSplit:
  265. begin
  266. WriteLn(Output, 'Splitting image ... ');
  267. SetLength(Subs, 0);
  268. Time := GetTimeMicroseconds;
  269. Imaging.SplitImage(Img, Subs, 300, 300, XCount, YCount, True, @FillColor);
  270. WriteTimeDiff('Image split in: ', Time);
  271. Imaging.FreeImagesInArray(Subs);
  272. end;
  273. maMakePal:
  274. begin
  275. WriteLn(Output, 'Making palette for images ... ');
  276. Imaging.NewPalette(256, Pal);
  277. SetLength(Subs, 1);
  278. Subs[0] := Img;
  279. Time := GetTimeMicroseconds;
  280. Imaging.MakePaletteForImages(Subs, Pal, 256, False);
  281. WriteTimeDiff('Palette made in: ', Time);
  282. Img := Subs[0];
  283. end;
  284. maRotate180:
  285. begin
  286. WriteLn(Output, 'Rotating image 180 degrees CCW ... ');
  287. Time := GetTimeMicroseconds;
  288. Imaging.RotateImage(Img, 180);
  289. WriteTimeDiff('Image rotated in: ', Time);
  290. end;
  291. maRotate90:
  292. begin
  293. WriteLn(Output, 'Rotating image 90 degrees CCW ... ');
  294. Time := GetTimeMicroseconds;
  295. Imaging.RotateImage(Img, 90);
  296. WriteTimeDiff('Image rotated in: ', Time);
  297. end;
  298. end;
  299. end;
  300. procedure RunDemo;
  301. begin
  302. WriteLn('Vampyre Imaging Library Benchmark Demo version ', Imaging.GetVersionStr);
  303. WriteLn;
  304. {$IFDEF LOG_TO_FILE}
  305. // If logging to file is defined new output file is created
  306. // and all messages are written into it.
  307. try
  308. AssignFile(Output, GetAppDir + PathDelim + SLogFileName);
  309. Rewrite(Output);
  310. except
  311. on E: Exception do
  312. begin
  313. WriteLn('Exception raised during opening log file for writing: ' +
  314. GetAppDir + PathDelim + SLogFileName);
  315. WriteLn(E.Message);
  316. Halt(1);
  317. end;
  318. end;
  319. WriteLn('Benchmarking ...');
  320. {$ELSE}
  321. // Otherwise standard System.Output file is used.
  322. {$ENDIF}
  323. if not DirectoryExists(GetDataDir) then
  324. begin
  325. // If required testing data is not found program halts.
  326. WriteLn('Error!' + sLineBreak + '"Data" directory with ' +
  327. 'required "Tigers.*" images not found.');
  328. WriteLn;
  329. {$IFDEF DEBUG}
  330. WriteLn('Press RETURN key to exit');
  331. ReadLn;
  332. {$ENDIF}
  333. Halt(1);
  334. end;
  335. // Call this before any manipulation with TImageData record.
  336. Imaging.InitImage(Img);
  337. try
  338. try
  339. I := 0;
  340. SetLength(Formats, 1);
  341. // Enumerate all supported file formats and store their properties
  342. // to dyn array. After each iteration dyn array's size is increased by one
  343. // so next call to EnumFileFormats will have free space for results.
  344. // After enumerating last array item should be deleted because its empty.
  345. while Imaging.EnumFileFormats(I, Formats[I].Name, Formats[I].Ext,
  346. Formats[I].Masks, Formats[I].CanSave, Formats[I].IsMulti) do
  347. begin
  348. SetLength(Formats, I + 1);
  349. end;
  350. SetLength(Formats, I);
  351. // Test image loading functions for all supported image file formats
  352. // note that image loaded in one LoadImage is automatically
  353. // freed in then next LoadImage call so no leaks (should) occur.
  354. WriteLn(Output, '------------- Loading Images -------------');
  355. for I := Low(Formats) to High(Formats) do
  356. LoadImage(GetImageName(Formats[I].Ext));
  357. // Test image manipulation functions like conversions, resizing and other.
  358. WriteLn(Output, sLineBreak + '----------- Image Manipulation -----------');
  359. ManipulateImage(maResize3k);
  360. ManipulateImage(maConvARGB64);
  361. ManipulateImage(maFlip);
  362. ManipulateImage(maMirror);
  363. ManipulateImage(maSwapChannels);
  364. ManipulateImage(maConvARGBF);
  365. ManipulateImage(maConvARGB16);
  366. ManipulateImage(maConvARGB32);
  367. ManipulateImage(maClone);
  368. ManipulateImage(maCopyRect);
  369. ManipulateImage(maFill);
  370. ManipulateImage(maStretchRect);
  371. ManipulateImage(maReplace);
  372. ManipulateImage(maMipMaps);
  373. ManipulateImage(maSplit);
  374. ManipulateImage(maResize1k);
  375. ManipulateImage(maRotate180);
  376. ManipulateImage(maRotate90);
  377. ManipulateImage(maReduceColors);
  378. ManipulateImage(maMakePal);
  379. ManipulateImage(maMapImage);
  380. ManipulateImage(maCompressDXT);
  381. ManipulateImage(maDecompressDXT);
  382. ManipulateImage(maConvRGB24);
  383. // Test image saving functions. Image is now in R8G8B8 format. Note that
  384. // some supported file formats cannot save images in R8G8B8 so their
  385. // time includes conversions.
  386. WriteLn(Output, sLineBreak + '------------- Saving Images --------------');
  387. for I := Low(Formats) to High(Formats) do
  388. begin
  389. if Formats[I].CanSave then
  390. SaveImage(Formats[I].Ext);
  391. end;
  392. except
  393. on E: Exception do
  394. begin
  395. WriteLn('Exception Raised!');
  396. WriteLn(E.Message);
  397. end;
  398. end;
  399. finally
  400. // Image must be freed in the end.
  401. Imaging.FreeImage(Img);
  402. {$IFDEF LOG_TO_FILE}
  403. CloseFile(Output);
  404. WriteLn('Results written to "' + SLogFileName + '" file.');
  405. {$ENDIF}
  406. end;
  407. {$IFDEF DEBUG}
  408. WriteLn;
  409. WriteLn('Press RETURN key to exit');
  410. ReadLn;
  411. {$ENDIF}
  412. end;
  413. {
  414. File Notes:
  415. -- 0.77.1 ---------------------------------------------------
  416. - Refactored the demo (moved stuff to unit from dpr) and
  417. added Lazarus project files.
  418. -- 0.21 Changes/Bug Fixes -----------------------------------
  419. - Now uses file format enumeration so it tries to load/save images in
  420. all supported formats. Plus some minor aesthetic changes.
  421. -- 0.19 Changes/Bug Fixes -----------------------------------
  422. - added thousand separators to output times
  423. -- 0.17 Changes/Bug Fixes -----------------------------------
  424. - added filtered image resizing and rectangle stretching
  425. - added MNG and JNG file saving and loading and exception catcher
  426. }
  427. end.