testil.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. #include <IL/il.h>
  2. /* This program (testil) is free software: you can redistribute it and/or modify
  3. * it under the terms of the GNU General Public License as published by
  4. * the Free Software Foundation, either version 3 of the License, or
  5. * (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. #ifdef HAVE_CONFIG_H
  16. #include "config.h"
  17. #endif /* HAVE_CONFIG_H */
  18. #define _USE_MATH_DEFINES // Have to add for MSVC++ to use M_PI properly.
  19. #include <stdlib.h>
  20. #include <math.h>
  21. #include <string.h>
  22. #ifdef WORDS_BIGENDIAN
  23. enum colors {ALPHA, BLUE, GREEN, RED};
  24. #else /* not WORDS_BIGENDIAN */
  25. enum colors {RED, GREEN, BLUE, ALPHA};
  26. #endif /* not WORDS_BIGENDIAN */
  27. /* We would need ILU just because of iluErrorString() function... */
  28. /* So make it possible for both with and without ILU! */
  29. #ifdef ILU_ENABLED
  30. #include <IL/ilu.h>
  31. #define ERROR_LOADING_FILE_MACRO(filename, code) fprintf(stderr, "Error loading file '%s'\nReason: %s\n", (filename), iluErrorString((code)))
  32. #define ERROR_SAVING_FILE_MACRO(filename, code) fprintf(stderr, "Error saving file '%s'\nReason: %s\n", (filename), iluErrorString((code)))
  33. #else /* not ILU_ENABLED */
  34. #define ERROR_LOADING_FILE_MACRO(filename, code) fprintf(stderr, "Error loading file '%s'\nError code: 0x%X\n", (filename), (unsigned int)(code))
  35. #define ERROR_SAVING_FILE_MACRO(filename, code) fprintf(stderr, "Error saving file '%s'\nError code: 0x%X\n", (filename), (unsigned int)(code))
  36. #endif /* not ILU_ENABLED */
  37. /** How did the tests ended? */
  38. enum test_results {TEST_OK = 0, TEST_FAIL = 0x1, TEST_FAIL_QUANTIL = 0x2, TEST_FAIL_INTEGRAL = 0x4 };
  39. /** Parsing and parsing results (Parameters.flags) related: What options were passed? */
  40. enum {ACTION_HELP = 0x1, ACTION_VERBOSE = 0x2, ACTION_PRESERVE_TESTFILE = 0x4, ACTION_ROUGH_MODE = 0x8, ACTION_TEST_ALPHA = 0x10 };
  41. /** Parsing only: What sort of options to expect? */
  42. enum {EXPECT_EXTENSION = 0x1, EXPECT_QUANTILE = 0x2, EXPECT_FILENAME = 0x4, EXPECT_RESOLUTION = 0x8, EXPECT_IMAGES = 0x10};
  43. /** What to test for? */
  44. enum {TEST_NOTHING, TEST_EXTENSION, TEST_IS_TEST_IMAGE, TEST_IMAGES_ARE_SAME};
  45. int compare_ILubyte (const void * a, const void * b)
  46. { return ( *(ILubyte * )a - *(ILubyte * )b ); }
  47. /*
  48. struct PIXEL
  49. {
  50. ILubyte color[4];
  51. };
  52. typedef struct PIXEL pixel;*/
  53. /** What we collect from the comand line...
  54. */
  55. struct parameters
  56. {
  57. /* ** Input parameters ** */
  58. /** In the case we want to test filename */
  59. char first_filename[64];
  60. /** In the case we want to compare two filenames */
  61. char second_filename[64];
  62. /** or test extension... */
  63. char * extension;
  64. /*** Tests parameters ***/
  65. /** how talkative should we be? */
  66. int verbose;
  67. /** what about preserve-testfile, rough mode? */
  68. int flags;
  69. /* How many bytes per pixel? */
  70. int bpp;
  71. /** If we want to tweak test image sizes... */
  72. int resolution[2];
  73. /** Quantile test specs */
  74. double quantile_spec;
  75. int quantile_treshold;
  76. /** Integral test specs */
  77. double integral_treshold;
  78. };
  79. typedef struct parameters Parameters;
  80. /** Function generates test pattern when given data and dimensions
  81. * \param data Image data. 32bits per pixel
  82. * \param w, h Width and height of the image
  83. */
  84. void generate_test_image(ILubyte * data, int w, int h, Parameters params)
  85. {
  86. int test_alpha = params.flags & ACTION_TEST_ALPHA;
  87. int bpp = params.bpp;
  88. int i, j, index, j_index;
  89. double red, green, blue, sum;
  90. /* For easier notations */
  91. int h_5 = h / 5;
  92. for (j = 0, index = 0; j < h_5 * 3; j++)
  93. for (i = 0; i < w * bpp; i += bpp) /* We jump bpp bytes ahead with each pixel */
  94. {/* Making 27 samples from the RGB cube. */
  95. index = 9 * (j / h_5) + (i * 9) / w / bpp;
  96. j_index = j * w * bpp; /* just to make stuff look nice */
  97. data[j_index + i + RED] = 255 / 6 + (255 / 3) * (index % 3) ;
  98. data[j_index + i + GREEN] = 255 / 6 + (255 / 3) * ((index % 9) / 3 );
  99. data[j_index + i + BLUE] = 255 / 6 + (255 / 3) * (index / 9);
  100. if (test_alpha)
  101. data[j_index + i + ALPHA] = 255 - 63 * ((j * 4 / h_5) % 4);
  102. }
  103. for (j = 3 * h_5; j < 4 * h_5; j++)
  104. for (i = 0; i < w * bpp; i += bpp)
  105. {/* Making color gradient */
  106. red = cos(2 * M_PI / (double)w * i / bpp) / 2.0 + 0.5;
  107. green = cos(2 * M_PI / (double)w * i / bpp + M_PI * 1.0 / 3.0) / 2.0 + 0.5;
  108. blue = cos(2 * M_PI / (double)w * i / bpp + M_PI * 2.0 / 3.0) / 2.0 + 0.5;
  109. sum = sqrt(red * red + green * green + blue * blue);
  110. j_index = j * w * bpp;
  111. data[j_index + i + RED] = 255 * red / sum;
  112. data[j_index + i + GREEN] = 255 * green / sum;
  113. data[j_index + i + BLUE] = 255 * blue / sum;
  114. if (test_alpha)
  115. data[j_index + i + ALPHA] = 255;
  116. }
  117. for (j = 4 * h_5; j < 5 * h_5; j++)
  118. for (i = 0; i < w * bpp; i += bpp)
  119. {/* Making smooth B&W gradient */
  120. j_index = j * w * bpp;
  121. data[j_index + i + RED] = (i / bpp * 255) / w;
  122. data[j_index + i + GREEN] = (i / bpp * 255) / w;
  123. data[j_index + i + BLUE] = (i / bpp * 255) / w;
  124. if (test_alpha)
  125. data[j_index + i + ALPHA] = 255;
  126. }
  127. }
  128. /** Functions saves the test image of given dimensions and given name
  129. * \param name Filename
  130. * \param w, h Image dimensions
  131. *
  132. * The image is defined in the generate_test_image function and this function just calls it...
  133. */
  134. int save_test_image(const char * name, int w, int h, Parameters params)
  135. {
  136. /* Set constants so that there are no div rounding errors */
  137. ILuint handle;
  138. /* Generate the paperwork for our test image... */
  139. ilGenImages(1, & handle);
  140. ilBindImage(handle);
  141. /* how much memory will we need? */
  142. int memory_needed = w * h * params.bpp;
  143. ILubyte * data = (ILubyte * )malloc(memory_needed);
  144. if (data == NULL)
  145. {
  146. fprintf(stderr, "Out of memory, %s:%d\n", __FILE__, __LINE__);
  147. return IL_OUT_OF_MEMORY;
  148. }
  149. generate_test_image(data, w, h, params);
  150. /* finally set the image data */
  151. ilTexImage(w, h, 1, params.bpp, ( (params.flags & ACTION_TEST_ALPHA) == 0 ? IL_RGB : IL_RGBA), IL_UNSIGNED_BYTE, data);
  152. /* and dump them to the disc... */
  153. ILboolean saved = ilSaveImage(name);
  154. int return_value = IL_NO_ERROR;
  155. if (saved == IL_FALSE)
  156. {
  157. return_value = ilGetError();
  158. ERROR_SAVING_FILE_MACRO(name,return_value);
  159. }
  160. /* Finally, clean the mess! */
  161. ilDeleteImages(1, & handle);
  162. free(data);
  163. return return_value;
  164. }
  165. /** Returns the sum value of quantile of absolute differences among subpixels.
  166. * \param reference Left hand side image (LHS == RHS ?)
  167. * \param sample Right hand side image
  168. * \param num_subpixels BPP of image, usually 4 (RGBA)
  169. * \param quantile What quantile value are we interested in
  170. * \return Value of the quantile
  171. *
  172. * First of all, absolute differences are computed.
  173. * Then they are stored in an array and sorted using quicksort.
  174. * Finally, the quantile is determined and returned.
  175. */
  176. int calculate_median_pixel_distance_abs(ILubyte * reference, ILubyte * sample, int num_subpixels, double quantile)
  177. {
  178. ILubyte * differences = (ILubyte *)malloc(sizeof(ILubyte) * num_subpixels);
  179. if (differences == NULL)
  180. {
  181. fprintf(stderr, "Out of memory, %s:%d\n", __FILE__, __LINE__);
  182. return IL_OUT_OF_MEMORY;
  183. }
  184. int ii, difference;
  185. for (ii = 0; ii < num_subpixels; ii++)
  186. {/* Going through all pixel components and assigning the absolute difference to differences array */
  187. difference = (int)sample[ii] - reference[ii]; /* avoiding: overflow + need to have abs() */
  188. differences[ii] = (difference >= 0) ? difference : - difference;
  189. }
  190. /* We need the quantile, so we have to sort the array */
  191. qsort (differences, num_subpixels, sizeof(ILubyte), compare_ILubyte);
  192. if (quantile > 1.0 || quantile < 0.0) /* The quantile has totally wrong value... */
  193. {
  194. fprintf(stderr, "Come on... Quantile should be between 0.0 and 1.0 (you wanted %.3f)\n", quantile);
  195. return -1;
  196. }
  197. int index = (int)(quantile * num_subpixels); /* Which member of the sorted array is the quantile? */
  198. int result = differences[index];
  199. free(differences); /* Clean the mess */
  200. differences = 0;
  201. return result;
  202. }
  203. /** Returns the sum of squared differences between component color values, normed.
  204. *
  205. */
  206. double calculate_averaged_distance_sqr_integral(ILubyte * reference, ILubyte * sample, int num_subpixels)
  207. {
  208. long long differences = 0;
  209. int ii, difference;
  210. for (ii = 0; ii < num_subpixels; ii++)
  211. {/* Going through all pixel components and assigning the absolute difference to differences array */
  212. difference = sample[ii] - reference[ii]; /* avoiding overflow + need to have abs() */
  213. differences += difference * difference;
  214. }
  215. return sqrt(differences / (double)num_subpixels);
  216. }
  217. /** Do the comparison and return results through parameters.
  218. */
  219. void compare_fields(int w, int h, ILubyte * sample, ILubyte * reference, Parameters params, int * quantile, double * integral)
  220. {
  221. * quantile = calculate_median_pixel_distance_abs(reference, sample, w * h * params.bpp, params.quantile_spec);
  222. * integral = calculate_averaged_distance_sqr_integral(reference, sample, w * h * params.bpp);
  223. }
  224. /** We have some results of test of similarity of two images. Are they the same?
  225. * \param filename What filename are we actually testing? (Needed gor report purposes only.)
  226. * \param quantile What is the value of the quantile we have acquired earlier?
  227. * \param integral And what is the value of normed integral distance?
  228. * \return 0 on success or TEST_FAIL or'd with the cause.
  229. */
  230. int interpret_results(const char * filename, Parameters params, int quantile, double integral)
  231. {
  232. int return_value = 0;
  233. if (quantile > params.quantile_treshold)
  234. {
  235. printf("Quantile test failed: More than %d%% of subpixels have greater error than %d (should be less than %d)\n", (int)(100 - 100 * params.quantile_spec), quantile, params.quantile_treshold);
  236. return_value |= TEST_FAIL_QUANTIL | TEST_FAIL;
  237. }
  238. if (integral > params.integral_treshold)
  239. {
  240. printf("Integral test failed: Deviation is %.3f, should be below %.3f\n", integral, params.integral_treshold);
  241. return_value |= TEST_FAIL_INTEGRAL | TEST_FAIL;
  242. }
  243. if (params.verbose > 0)
  244. printf("Testing file '%s'. \nQuantile[%.3f]: %d (max %d)\nIngegral: %f (max %f)\n", filename, params.quantile_spec, quantile, params.quantile_treshold, integral, params.integral_treshold);
  245. return return_value;
  246. }
  247. /** Is the passed params.first_filename a test image?
  248. * Useful for testing whether the various format load functions alre OK
  249. * if we can't save the test image in DevIL.
  250. * So we take some test image, convert it to another format in some exernal editor
  251. * and then we try to load it. Smart, isn't it? :-)
  252. */
  253. int test_is_testimage(Parameters params)
  254. {
  255. /* First, we load the generated and saved image */
  256. ILuint handle;
  257. ilGenImages(1, & handle);
  258. ilBindImage(handle);
  259. int loaded = ilLoadImage(params.first_filename);
  260. if (loaded == IL_FALSE)
  261. {/* something went wrong */
  262. ERROR_LOADING_FILE_MACRO(params.first_filename, loaded);
  263. return loaded;
  264. }
  265. /* getting image width and height */
  266. int w, h;
  267. w = ilGetInteger(IL_IMAGE_WIDTH);
  268. h = ilGetInteger(IL_IMAGE_HEIGHT);
  269. /* Then we save image data into arrays that we allocate now */
  270. ILubyte * reference, * sample;
  271. reference = malloc(w * h * params.bpp * sizeof(ILubyte));
  272. sample = malloc(w * h * params.bpp * sizeof(ILubyte));
  273. if (reference == NULL || sample == NULL)
  274. {
  275. if ((params.flags & ACTION_PRESERVE_TESTFILE) == 0)
  276. remove(params.first_filename);
  277. fprintf(stderr, "Out of memory, %s:%d\n", __FILE__, __LINE__);
  278. return IL_OUT_OF_MEMORY;
  279. }
  280. /* Allocation went fine and now we get what SHOULD BE on the loaded image... */
  281. generate_test_image((ILubyte *)reference, w, h, params);
  282. ilCopyPixels(0, 0, 0, w, h, 1, ((params.flags & ACTION_TEST_ALPHA) == 0 ? IL_RGB : IL_RGBA), IL_UNSIGNED_BYTE, sample);
  283. int quantile;
  284. double integral;
  285. compare_fields(w, h, sample, reference, params, & quantile, & integral);
  286. int return_value = interpret_results(params.first_filename, params, quantile, integral);
  287. free(sample);
  288. free(reference);
  289. /* We do not want to keep the saved test image by default... */
  290. if ((params.flags & ACTION_PRESERVE_TESTFILE) == 0)
  291. remove(params.first_filename);
  292. return return_value;
  293. }
  294. /** Tests whether we can save and load the test data to a specified extension
  295. * \param params Test options in a nice box
  296. * \return 0 if all is OK, or an error code (see interpret_results)
  297. */
  298. int test_format(Parameters params)
  299. {
  300. /* First, let's generate and save a test image */
  301. const char * base_name = "test.";
  302. char filename [64];
  303. if (strlen(params.extension) + strlen(base_name) >= sizeof(filename))
  304. return -1; /* buffer overflow */
  305. sprintf(filename, "%s%s", base_name, params.extension);
  306. int saved = save_test_image(filename, params.resolution[0], params.resolution[1], params);
  307. if (saved != 0) /* something went wrong, no point in continuing, the user already knows */
  308. return saved;
  309. strncpy(params.first_filename, filename, sizeof(params.first_filename));
  310. /* Will we be able to load that very test image? */
  311. return test_is_testimage(params);
  312. }
  313. int test_are_same(Parameters params)
  314. {
  315. const int images_count = 2;
  316. ILuint handle[images_count];
  317. int i;
  318. ILubyte * image_data[images_count];
  319. for (i = 0; i < images_count; i++)
  320. image_data[i] = NULL;
  321. ilGenImages(images_count, & handle[0]);
  322. const char * filenames [] = {params.first_filename, params.second_filename};
  323. int w, h;
  324. for (i = 0; i < images_count; i++)
  325. {
  326. ilBindImage(handle[i]);
  327. int loaded = ilLoadImage(filenames[i]);
  328. if (loaded == IL_FALSE)
  329. {/* something went wrong */
  330. ERROR_LOADING_FILE_MACRO(filenames[i], loaded);
  331. for (i--; i >= 0; i--)
  332. {/* We might allocated something, so let's clean it up :)) */
  333. free(image_data[i]);
  334. image_data[i] = NULL;
  335. }
  336. return loaded;
  337. }
  338. /* getting image width and height */
  339. if (i == 0)
  340. {
  341. w = ilGetInteger(IL_IMAGE_WIDTH);
  342. h = ilGetInteger(IL_IMAGE_HEIGHT);
  343. }
  344. else
  345. {
  346. if (w != ilGetInteger(IL_IMAGE_WIDTH)
  347. || h != ilGetInteger(IL_IMAGE_HEIGHT))
  348. {
  349. printf("Of course that images '%s' and '%s' are not the same. How could they be as they have different dimensions?\n", filenames[0], filenames[i]);
  350. return -1;
  351. }
  352. }
  353. /* Then we save image data into arrays that we allocate now */
  354. image_data[i] = malloc(w * h * params.bpp * sizeof(ILubyte));
  355. if (image_data[i] == NULL)
  356. {
  357. fprintf(stderr, "Out of memory, %s:%d\n", __FILE__, __LINE__);
  358. return IL_OUT_OF_MEMORY;
  359. }
  360. ilCopyPixels(0, 0, 0, w, h, 1, ((params.flags & ACTION_TEST_ALPHA) == 0 ? IL_RGB : IL_RGBA), IL_UNSIGNED_BYTE, image_data[i]);
  361. }
  362. int return_value = 0, result;
  363. int quantile;
  364. double integral;
  365. if (params.verbose > 0)
  366. printf("Testing against '%s'\n", filenames[0]);
  367. for (i = 1; i < images_count; i++)
  368. {
  369. compare_fields(w, h, image_data[0], image_data[i], params, & quantile, & integral);
  370. result = interpret_results(filenames[i], params, quantile, integral);
  371. return_value = (result > return_value) ? result : return_value;
  372. free(image_data[i]);
  373. image_data[i] = 0;
  374. }
  375. free(image_data[0]);
  376. image_data[0] = 0;
  377. ilDeleteImages(images_count, & handle[0]);
  378. return return_value;
  379. }
  380. /** Examines the command line like no tomorrow :-)
  381. *
  382. * Huge code, I am sorry for that.
  383. * On the other hand, cross-platformness of popt is catastrophical
  384. * and usage of boost is also too much for this simple purpose.
  385. */
  386. int parse_commandline(int argc, char ** argv, Parameters * params)
  387. {
  388. int actions = 0, expectations = 0;
  389. const int long_str = 63;
  390. int return_value = TEST_NOTHING;
  391. int i;
  392. for (i = 1; i < argc; i++)
  393. {
  394. actions = 0;
  395. /* Find out what to do and what to expect */
  396. if (argv[i][0] == '-')
  397. {/* Ho, an option was passed... */
  398. if (argv[i][1] == '-')
  399. {/* Deal with long options */
  400. if(strncmp(argv[i], "--extension", long_str))
  401. {
  402. expectations |= EXPECT_EXTENSION;
  403. }
  404. else if (strncmp(argv[i], "--quantile", long_str))
  405. {
  406. expectations |= EXPECT_QUANTILE;
  407. }
  408. else if (strncmp(argv[i], "--help", long_str))
  409. {
  410. actions |= ACTION_HELP;
  411. }
  412. else if (strncmp(argv[i], "--verbose", long_str))
  413. {
  414. actions |= ACTION_VERBOSE;
  415. }
  416. else if (strncmp(argv[i], "--test-alpha", long_str))
  417. {
  418. actions |= ACTION_TEST_ALPHA;
  419. }
  420. else if (strncmp(argv[i], "--preserve", long_str))
  421. {
  422. actions |= ACTION_PRESERVE_TESTFILE;
  423. }
  424. else if (strncmp(argv[i], "--use-resolution", long_str))
  425. {
  426. expectations |= EXPECT_RESOLUTION;
  427. }
  428. else if (strncmp(argv[i], "--are-same", long_str))
  429. {
  430. expectations |= EXPECT_IMAGES;
  431. }
  432. else if (strncmp(argv[i], "--image-complies", long_str))
  433. {
  434. expectations |= EXPECT_FILENAME;
  435. }
  436. }
  437. else /* if not (argv[i][1] == '-') */
  438. {/* Deal with short options */
  439. int j;
  440. for (j = 1; j < strlen(argv[i]); j++)
  441. switch(argv[i][j])
  442. {
  443. case 'h':
  444. case '?':
  445. actions |= ACTION_HELP;
  446. break;
  447. case 'v':
  448. actions |= ACTION_VERBOSE;
  449. break;
  450. case 'a':
  451. actions |= ACTION_TEST_ALPHA;
  452. break;
  453. case 'e':
  454. expectations |= EXPECT_EXTENSION;
  455. break;
  456. case 'q':
  457. expectations |= EXPECT_QUANTILE;
  458. break;
  459. case 'p':
  460. actions |= ACTION_PRESERVE_TESTFILE;
  461. break;
  462. case 'r':
  463. expectations |= EXPECT_RESOLUTION;
  464. break;
  465. case 's':
  466. expectations |= EXPECT_IMAGES;
  467. break;
  468. case 'c':
  469. expectations |= EXPECT_FILENAME;
  470. break;
  471. }/* end switch(argv[i][j]) */
  472. }/* if not (argv[i][1] == '-') */
  473. }
  474. else /* (! argv[i][0] == '-') */
  475. {/* Now handle expectations... */
  476. if (expectations & EXPECT_EXTENSION)
  477. {/* point extension to the extension string so we will be able to read it afterwards */
  478. params->extension = argv[i];
  479. return_value = TEST_EXTENSION;
  480. }
  481. else if (expectations & EXPECT_QUANTILE)
  482. {/* This parameter SHOULD BE the quantile we wanted... */
  483. sscanf(argv[i], "%lf", & params->quantile_spec);
  484. }
  485. else if (expectations & EXPECT_RESOLUTION)
  486. {/* This parameter SHOULD specify the geometry... */
  487. sscanf(argv[i], "%dx%d", & params->resolution[0], & params->resolution[1]);
  488. }
  489. else if (expectations & EXPECT_FILENAME)
  490. {/* This parameter SHOULD specify one filename... */
  491. strncpy(params->first_filename, argv[i], sizeof(params->first_filename));
  492. if ((params->flags & ACTION_PRESERVE_TESTFILE) == 0)
  493. {
  494. params->flags |= ACTION_PRESERVE_TESTFILE;
  495. printf("Issued a command to preserve the input file :-)\n");
  496. }
  497. return_value = TEST_IS_TEST_IMAGE;
  498. }
  499. else if (expectations & EXPECT_IMAGES)
  500. {/* Masterpiece, this parameter SHOULD specify two comma separated filenames... */
  501. sscanf(argv[i], "%30[^,],%30s", params->first_filename, params->second_filename);
  502. if ((params->flags & ACTION_PRESERVE_TESTFILE) == 0)
  503. {
  504. params->flags |= ACTION_PRESERVE_TESTFILE;
  505. printf("Issued a command to preserve the input file :-)\n");
  506. }
  507. return_value = TEST_IMAGES_ARE_SAME;
  508. /* just debug: * printf ("Acquired strings: %s %s\n", params->first_filename, params->second_filename); **/
  509. }
  510. expectations = 0;
  511. }/* (! argv[i][0] == '-') */
  512. /* now handle actions... */
  513. if (actions & ACTION_VERBOSE)
  514. {
  515. params->verbose++;
  516. }
  517. if (actions & ACTION_HELP)
  518. {
  519. printf(" *** Beware, manually generated help (=> may not be 100%% up-to-date :-) ***\n");
  520. printf(" If you miss something, examine the source code\n");
  521. printf("Run %s with this arguments:\n", argv[0]);
  522. printf("\t-h, -? | --help: This help message\n");
  523. printf("\t-v | --verbose: Verbose run\n");
  524. printf("\t-a | --test-alpha: Make and test image alpha channel as well\n");
  525. printf("\t-e | --extension <extension, like BMP, PNG etc.>: Test saving and loading of this extension\n");
  526. printf("\t-p | --preserve: Don't remove any generated files\n");
  527. printf("\t-c | --image-complies <filename, like image.jpg>: Test whether the filename is the image of our test pattern (useful for testing opening capabilities)\n");
  528. printf("\t-r | --use-resolution <widthxheight, like 400x300>: If this makes sense, use this resolution), default 603x300\n");
  529. printf("\t-s | --are-same <first,second filename, like test.png,something.jpg>: Tests whether the first and second images are the same. Pass two filenames separated by comma.\n");
  530. printf("This will be helpful one day...\n");
  531. }
  532. if (actions & ACTION_PRESERVE_TESTFILE)
  533. {
  534. params->flags |= ACTION_PRESERVE_TESTFILE;
  535. }
  536. if (actions & ACTION_TEST_ALPHA)
  537. {
  538. params->flags |= ACTION_TEST_ALPHA;
  539. params->bpp = 4;
  540. }
  541. }/* endfor <going through argv> */
  542. return return_value;
  543. }
  544. int main(int argc, char ** argv)
  545. {
  546. /* has to be done */
  547. ilInit();
  548. #ifdef ILU_ENABLED
  549. iluInit();
  550. #endif
  551. /* Consistent loading stuff... */
  552. ilEnable(IL_ORIGIN_SET);
  553. Parameters params = { /* ***SHOULD BE*** first_filename*/ "",
  554. /* second filename */ "",
  555. /* extension */ (char *)NULL,
  556. /* verbose */ (int)0,
  557. /* flags */(int)0,
  558. /* bpp */(int)3,
  559. /* resolution */ {603, 300},
  560. /* quantile spec */ (double)0.80,
  561. /* quantile tresh */ (int)5,
  562. /* integral tresh */ (double)5};
  563. int to_do = parse_commandline(argc, argv, & params);
  564. int return_value = 0;
  565. if (to_do & TEST_EXTENSION && params.extension != NULL)
  566. {
  567. return_value = test_format(params);
  568. if (return_value != 0)
  569. fprintf(stderr, "Format test: FAIL (.%s)\n", params.extension);
  570. }
  571. else if (to_do & TEST_IS_TEST_IMAGE
  572. && strlen(params.first_filename) > 0
  573. && strlen(params.second_filename) == 0)
  574. {
  575. if (params.verbose > 0)
  576. printf ("Testing whether %s is the test image\n", params.first_filename);
  577. return_value = test_is_testimage(params);
  578. if (return_value != 0)
  579. fprintf(stderr, "Is test image test: FAIL (%s)\n", params.first_filename);
  580. }
  581. else if (to_do & TEST_IMAGES_ARE_SAME
  582. && strlen(params.first_filename) > 0
  583. && strlen(params.second_filename) > 0 )
  584. {
  585. if (params.verbose > 0)
  586. printf ("Testing whether %s and %s are +- the same\n", params.first_filename, params.second_filename);
  587. return_value = test_are_same(params);
  588. if (return_value != 0)
  589. fprintf(stderr, "Images are the same test: FAIL ('%s' != '%s')\n", params.first_filename, params.second_filename);
  590. }
  591. return return_value;
  592. }