Bench.dpr 15 KB

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