Merge pull request #1386 from DavidKorczynski/cifuzz
[openjpeg.git] / tests / compare_images.c
1 /*
2  * Copyright (c) 2011-2012, Centre National d'Etudes Spatiales (CNES), France
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24  * POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 /*
28  * compare_images.c
29  *
30  *  Created on: 8 juil. 2011
31  *      Author: mickael
32  */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <math.h>
37 #include <string.h>
38 #include <ctype.h>
39 #include <assert.h>
40
41 #include "opj_apps_config.h"
42 #include "opj_getopt.h"
43
44 #include "openjpeg.h"
45 #include "format_defs.h"
46 #include "convert.h"
47
48 #ifdef OPJ_HAVE_LIBTIFF
49 #include <tiffio.h> /* TIFFSetWarningHandler */
50 #endif /* OPJ_HAVE_LIBTIFF */
51
52 /*******************************************************************************
53  * Parse MSE and PEAK input values (
54  * separator = ":"
55  *******************************************************************************/
56 static double* parseToleranceValues(char* inArg, const int nbcomp)
57 {
58     double* outArgs = malloc((size_t)nbcomp * sizeof(double));
59     int it_comp = 0;
60     const char delims[] = ":";
61     char *result = strtok(inArg, delims);
62
63     while ((result != NULL) && (it_comp < nbcomp)) {
64         outArgs[it_comp] = atof(result);
65         result = strtok(NULL, delims);
66         it_comp++;
67     }
68
69     if (it_comp != nbcomp) {
70         free(outArgs);
71         return NULL;
72     }
73     /* else */
74     return outArgs;
75 }
76
77 /*******************************************************************************
78  * Command line help function
79  *******************************************************************************/
80 static void compare_images_help_display(void)
81 {
82     fprintf(stdout, "\nList of parameters for the compare_images function  \n");
83     fprintf(stdout, "\n");
84     fprintf(stdout,
85             "  -b \t REQUIRED \t filename to the reference/baseline PGX/TIF/PNM image \n");
86     fprintf(stdout, "  -t \t REQUIRED \t filename to the test PGX/TIF/PNM image\n");
87     fprintf(stdout,
88             "  -n \t REQUIRED \t number of component of the image (used to generate correct filename, not used when both input files are TIF)\n");
89     fprintf(stdout,
90             "  -m \t OPTIONAL \t list of MSE tolerances, separated by : (size must correspond to the number of component) of \n");
91     fprintf(stdout,
92             "  -p \t OPTIONAL \t list of PEAK tolerances, separated by : (size must correspond to the number of component) \n");
93     fprintf(stdout,
94             "  -s \t OPTIONAL \t 1 or 2 filename separator to take into account PGX/PNM image with different components, "
95             "please indicate b or t before separator to indicate respectively the separator "
96             "for ref/base file and for test file.  \n");
97     fprintf(stdout,
98             "  -d \t OPTIONAL \t indicate if you want to run this function as conformance test or as non regression test\n");
99     fprintf(stdout,
100             "  -i \t OPTIONAL \t list of features to ignore. Currently 'prec' only supported\n");
101     fprintf(stdout, "\n");
102 }
103
104 static int get_decod_format_from_string(const char *filename)
105 {
106     const int dot = '.';
107     char * ext = strrchr(filename, dot);
108     if (strcmp(ext, ".pgx") == 0) {
109         return PGX_DFMT;
110     }
111     if (strcmp(ext, ".tif") == 0) {
112         return TIF_DFMT;
113     }
114     if (strcmp(ext, ".ppm") == 0) {
115         return PXM_DFMT;
116     }
117     return -1;
118 }
119
120
121 /*******************************************************************************
122  * Create filenames from a filename using separator and nb components
123  * (begin from 0)
124  *******************************************************************************/
125 static char* createMultiComponentsFilename(const char* inFilename,
126         const int indexF, const char* separator)
127 {
128     char s[255];
129     char *outFilename, *ptr;
130     const char token = '.';
131     size_t posToken = 0;
132     int decod_format;
133
134     /*printf("inFilename = %s\n", inFilename);*/
135     if ((ptr = strrchr(inFilename, token)) != NULL) {
136         posToken = strlen(inFilename) - strlen(ptr);
137         /*printf("Position of %c character inside inFilename = %d\n", token, posToken);*/
138     } else {
139         /*printf("Token %c not found\n", token);*/
140         outFilename = (char*)malloc(1);
141         outFilename[0] = '\0';
142         return outFilename;
143     }
144
145     outFilename = (char*)malloc(posToken + 32);
146
147     memcpy(outFilename, inFilename, posToken);
148     outFilename[posToken] = '\0';
149     strcat(outFilename, separator);
150     sprintf(s, "%i", indexF);
151     strcat(outFilename, s);
152
153     decod_format = get_decod_format_from_string(inFilename);
154     if (decod_format == PGX_DFMT) {
155         strcat(outFilename, ".pgx");
156     } else if (decod_format == PXM_DFMT) {
157         strcat(outFilename, ".pgm");
158     }
159
160     /*printf("outfilename: %s\n", outFilename);*/
161     return outFilename;
162 }
163
164 /*******************************************************************************
165  *
166  *******************************************************************************/
167 static opj_image_t* readImageFromFilePPM(const char* filename,
168         int nbFilenamePGX, const char *separator)
169 {
170     int it_file;
171     opj_image_t* image_read = NULL;
172     opj_image_t* image = NULL;
173     opj_cparameters_t parameters;
174     opj_image_cmptparm_t* param_image_read;
175     int** data;
176
177     /* If separator is empty => nb file to read is equal to one*/
178     if (strlen(separator) == 0) {
179         nbFilenamePGX = 1;
180     }
181
182     /* set encoding parameters to default values */
183     opj_set_default_encoder_parameters(&parameters);
184     parameters.decod_format = PXM_DFMT;
185     strcpy(parameters.infile, filename);
186
187     /* Allocate memory*/
188     param_image_read = malloc((size_t)nbFilenamePGX * sizeof(opj_image_cmptparm_t));
189     data = malloc((size_t)nbFilenamePGX * sizeof(*data));
190
191     for (it_file = 0; it_file < nbFilenamePGX; it_file++) {
192         /* Create the right filename*/
193         char *filenameComponentPGX;
194         if (strlen(separator) == 0) {
195             filenameComponentPGX = malloc((strlen(filename) + 1) * sizeof(
196                                               *filenameComponentPGX));
197             strcpy(filenameComponentPGX, filename);
198         } else {
199             filenameComponentPGX = createMultiComponentsFilename(filename, it_file,
200                                    separator);
201         }
202
203         /* Read the tif file corresponding to the component */
204         image_read = pnmtoimage(filenameComponentPGX, &parameters);
205         if (!image_read) {
206             int it_free_data;
207             fprintf(stderr, "Unable to load ppm file: %s\n", filenameComponentPGX);
208
209             free(param_image_read);
210
211             for (it_free_data = 0; it_free_data < it_file; it_free_data++) {
212                 free(data[it_free_data]);
213             }
214             free(data);
215
216             free(filenameComponentPGX);
217
218             return NULL;
219         }
220
221         /* Set the image_read parameters*/
222         param_image_read[it_file].x0 = 0;
223         param_image_read[it_file].y0 = 0;
224         param_image_read[it_file].dx = 0;
225         param_image_read[it_file].dy = 0;
226         param_image_read[it_file].h = image_read->comps->h;
227         param_image_read[it_file].w = image_read->comps->w;
228         param_image_read[it_file].prec = image_read->comps->prec;
229         param_image_read[it_file].sgnd = image_read->comps->sgnd;
230
231         /* Copy data*/
232         data[it_file] = malloc(param_image_read[it_file].h * param_image_read[it_file].w
233                                * sizeof(int));
234         memcpy(data[it_file], image_read->comps->data,
235                image_read->comps->h * image_read->comps->w * sizeof(int));
236
237         /* Free memory*/
238         opj_image_destroy(image_read);
239         free(filenameComponentPGX);
240     }
241
242     image = opj_image_create((OPJ_UINT32)nbFilenamePGX, param_image_read,
243                              OPJ_CLRSPC_UNSPECIFIED);
244     for (it_file = 0; it_file < nbFilenamePGX; it_file++) {
245         /* Copy data into output image and free memory*/
246         memcpy(image->comps[it_file].data, data[it_file],
247                image->comps[it_file].h * image->comps[it_file].w * sizeof(int));
248         free(data[it_file]);
249     }
250
251     /* Free memory*/
252     free(param_image_read);
253     free(data);
254
255     return image;
256 }
257
258 static opj_image_t* readImageFromFileTIF(const char* filename,
259         int nbFilenamePGX, const char *separator)
260 {
261     opj_image_t* image_read = NULL;
262     opj_cparameters_t parameters;
263 #ifdef OPJ_HAVE_LIBTIFF
264     const unsigned int target_bitdepth = 0;
265 #endif
266     (void)nbFilenamePGX;
267     (void)separator;
268
269     /* conformance test suite produce annoying warning/error:
270      * TIFFReadDirectory: Warning, /.../data/baseline/conformance/jp2_1.tif: unknown field with tag 37724 (0x935c) encountered.
271      * TIFFOpen: /.../data/baseline/nonregression/opj_jp2_1.tif: Cannot open.
272      * On Win32 this open a message box by default, so remove it from the test suite:
273      */
274 #ifdef OPJ_HAVE_LIBTIFF
275     TIFFSetWarningHandler(NULL);
276     TIFFSetErrorHandler(NULL);
277 #endif
278
279     if (strlen(separator) != 0) {
280         return NULL;
281     }
282
283     /* set encoding parameters to default values */
284     opj_set_default_encoder_parameters(&parameters);
285     parameters.decod_format = TIF_DFMT;
286     strcpy(parameters.infile, filename);
287
288     /* Read the tif file corresponding to the component */
289 #ifdef OPJ_HAVE_LIBTIFF
290     image_read = tiftoimage(filename, &parameters, target_bitdepth);
291 #endif
292     if (!image_read) {
293         fprintf(stderr, "Unable to load TIF file\n");
294         return NULL;
295     }
296
297     return image_read;
298 }
299
300 static opj_image_t* readImageFromFilePGX(const char* filename,
301         int nbFilenamePGX, const char *separator)
302 {
303     int it_file;
304     opj_image_t* image_read = NULL;
305     opj_image_t* image = NULL;
306     opj_cparameters_t parameters;
307     opj_image_cmptparm_t* param_image_read;
308     int** data;
309
310     /* If separator is empty => nb file to read is equal to one*/
311     if (strlen(separator) == 0) {
312         nbFilenamePGX = 1;
313     }
314
315     /* set encoding parameters to default values */
316     opj_set_default_encoder_parameters(&parameters);
317     parameters.decod_format = PGX_DFMT;
318     strcpy(parameters.infile, filename);
319
320     /* Allocate memory*/
321     param_image_read = malloc((size_t)nbFilenamePGX * sizeof(opj_image_cmptparm_t));
322     data = malloc((size_t)nbFilenamePGX * sizeof(*data));
323
324     for (it_file = 0; it_file < nbFilenamePGX; it_file++) {
325         /* Create the right filename*/
326         char *filenameComponentPGX;
327         if (strlen(separator) == 0) {
328             filenameComponentPGX = malloc((strlen(filename) + 1) * sizeof(
329                                               *filenameComponentPGX));
330             strcpy(filenameComponentPGX, filename);
331         } else {
332             filenameComponentPGX = createMultiComponentsFilename(filename, it_file,
333                                    separator);
334         }
335
336         /* Read the pgx file corresponding to the component */
337         image_read = pgxtoimage(filenameComponentPGX, &parameters);
338         if (!image_read) {
339             int it_free_data;
340             fprintf(stderr, "Unable to load pgx file\n");
341
342             free(param_image_read);
343
344             for (it_free_data = 0; it_free_data < it_file; it_free_data++) {
345                 free(data[it_free_data]);
346             }
347             free(data);
348
349             free(filenameComponentPGX);
350
351             return NULL;
352         }
353
354         /* Set the image_read parameters*/
355         param_image_read[it_file].x0 = 0;
356         param_image_read[it_file].y0 = 0;
357         param_image_read[it_file].dx = 0;
358         param_image_read[it_file].dy = 0;
359         param_image_read[it_file].h = image_read->comps->h;
360         param_image_read[it_file].w = image_read->comps->w;
361         param_image_read[it_file].prec = image_read->comps->prec;
362         param_image_read[it_file].sgnd = image_read->comps->sgnd;
363
364         /* Copy data*/
365         data[it_file] = malloc(param_image_read[it_file].h * param_image_read[it_file].w
366                                * sizeof(int));
367         memcpy(data[it_file], image_read->comps->data,
368                image_read->comps->h * image_read->comps->w * sizeof(int));
369
370         /* Free memory*/
371         opj_image_destroy(image_read);
372         free(filenameComponentPGX);
373     }
374
375     image = opj_image_create((OPJ_UINT32)nbFilenamePGX, param_image_read,
376                              OPJ_CLRSPC_UNSPECIFIED);
377     for (it_file = 0; it_file < nbFilenamePGX; it_file++) {
378         /* Copy data into output image and free memory*/
379         memcpy(image->comps[it_file].data, data[it_file],
380                image->comps[it_file].h * image->comps[it_file].w * sizeof(int));
381         free(data[it_file]);
382     }
383
384     /* Free memory*/
385     free(param_image_read);
386     free(data);
387
388     return image;
389 }
390
391 #if defined(OPJ_HAVE_LIBPNG) && 0 /* remove for now */
392 /*******************************************************************************
393  *
394  *******************************************************************************/
395 static int imageToPNG(const opj_image_t* image, const char* filename,
396                       int num_comp_select)
397 {
398     opj_image_cmptparm_t param_image_write;
399     opj_image_t* image_write = NULL;
400
401     param_image_write.x0 = 0;
402     param_image_write.y0 = 0;
403     param_image_write.dx = 0;
404     param_image_write.dy = 0;
405     param_image_write.h = image->comps[num_comp_select].h;
406     param_image_write.w = image->comps[num_comp_select].w;
407     param_image_write.prec = image->comps[num_comp_select].prec;
408     param_image_write.sgnd = image->comps[num_comp_select].sgnd;
409
410     image_write = opj_image_create(1u, &param_image_write, OPJ_CLRSPC_GRAY);
411     memcpy(image_write->comps->data, image->comps[num_comp_select].data,
412            param_image_write.h * param_image_write.w * sizeof(int));
413
414     imagetopng(image_write, filename);
415
416     opj_image_destroy(image_write);
417
418     return EXIT_SUCCESS;
419 }
420 #endif
421
422 typedef struct test_cmp_parameters {
423     /**  */
424     char* base_filename;
425     /**  */
426     char* test_filename;
427     /** Number of components */
428     int nbcomp;
429     /**  */
430     double* tabMSEvalues;
431     /**  */
432     double* tabPEAKvalues;
433     /**  */
434     int nr_flag;
435     /**  */
436     char separator_base[2];
437     /**  */
438     char separator_test[2];
439     /** whether to ignore prec differences */
440     int ignore_prec;
441
442 } test_cmp_parameters;
443
444 /* return decode format PGX / TIF / PPM , return -1 on error */
445 static int get_decod_format(test_cmp_parameters* param)
446 {
447     int base_format = get_decod_format_from_string(param->base_filename);
448     int test_format = get_decod_format_from_string(param->test_filename);
449     if (base_format != test_format) {
450         return -1;
451     }
452     /* handle case -1: */
453     return base_format;
454 }
455
456 /*******************************************************************************
457  * Parse command line
458  *******************************************************************************/
459 static int parse_cmdline_cmp(int argc, char **argv, test_cmp_parameters* param)
460 {
461     char *MSElistvalues = NULL;
462     char *PEAKlistvalues = NULL;
463     char *separatorList = NULL;
464     size_t sizemembasefile, sizememtestfile;
465     int index, flagM = 0, flagP = 0;
466     const char optlist[] = "b:t:n:m:p:s:di:";
467     char* ignoreList = NULL;
468     int c;
469
470     /* Init parameters*/
471     param->base_filename = NULL;
472     param->test_filename = NULL;
473     param->nbcomp = 0;
474     param->tabMSEvalues = NULL;
475     param->tabPEAKvalues = NULL;
476     param->nr_flag = 0;
477     param->separator_base[0] = 0;
478     param->separator_test[0] = 0;
479     param->ignore_prec = 0;
480
481     opj_opterr = 0;
482
483     while ((c = opj_getopt(argc, argv, optlist)) != -1)
484         switch (c) {
485         case 'b':
486             sizemembasefile = strlen(opj_optarg) + 1;
487             param->base_filename = (char*) malloc(sizemembasefile);
488             strcpy(param->base_filename, opj_optarg);
489             /*printf("param->base_filename = %s [%d / %d]\n", param->base_filename, strlen(param->base_filename), sizemembasefile );*/
490             break;
491         case 't':
492             sizememtestfile = strlen(opj_optarg) + 1;
493             param->test_filename = (char*) malloc(sizememtestfile);
494             strcpy(param->test_filename, opj_optarg);
495             /*printf("param->test_filename = %s [%d / %d]\n", param->test_filename, strlen(param->test_filename), sizememtestfile);*/
496             break;
497         case 'n':
498             param->nbcomp = atoi(opj_optarg);
499             break;
500         case 'm':
501             MSElistvalues = opj_optarg;
502             flagM = 1;
503             break;
504         case 'p':
505             PEAKlistvalues = opj_optarg;
506             flagP = 1;
507             break;
508         case 'd':
509             param->nr_flag = 1;
510             break;
511         case 's':
512             separatorList = opj_optarg;
513             break;
514         case 'i':
515             ignoreList = opj_optarg;
516             break;
517         case '?':
518             if ((opj_optopt == 'b') || (opj_optopt == 't') || (opj_optopt == 'n') ||
519                     (opj_optopt == 'p') || (opj_optopt == 'm') || (opj_optopt
520                             == 's')) {
521                 fprintf(stderr, "Option -%c requires an argument.\n", opj_optopt);
522             } else if (isprint(opj_optopt)) {
523                 fprintf(stderr, "Unknown option `-%c'.\n", opj_optopt);
524             } else {
525                 fprintf(stderr, "Unknown option character `\\x%x'.\n", opj_optopt);
526             }
527             return 1;
528         default:
529             fprintf(stderr, "WARNING -> this option is not valid \"-%c %s\"\n", c,
530                     opj_optarg);
531             break;
532         }
533
534     if (opj_optind != argc) {
535         for (index = opj_optind; index < argc; index++) {
536             fprintf(stderr, "Non-option argument %s\n", argv[index]);
537         }
538         return 1;
539     }
540
541     if (param->nbcomp == 0) {
542         fprintf(stderr, "Need to indicate the number of components !\n");
543         return 1;
544     }
545     /* else */
546     if (flagM && flagP) {
547         param->tabMSEvalues = parseToleranceValues(MSElistvalues, param->nbcomp);
548         param->tabPEAKvalues = parseToleranceValues(PEAKlistvalues, param->nbcomp);
549         if ((param->tabMSEvalues == NULL) || (param->tabPEAKvalues == NULL)) {
550             fprintf(stderr,
551                     "MSE and PEAK values are not correct (respectively need %d values)\n",
552                     param->nbcomp);
553             return 1;
554         }
555     }
556
557     /* Get separators after corresponding letter (b or t)*/
558     if (separatorList != NULL) {
559         if ((strlen(separatorList) == 2) || (strlen(separatorList) == 4)) {
560             /* keep original string*/
561             size_t sizeseplist = strlen(separatorList) + 1;
562             char* separatorList2 = (char*)malloc(sizeseplist);
563             strcpy(separatorList2, separatorList);
564             /*printf("separatorList2 = %s [%d / %d]\n", separatorList2, strlen(separatorList2), sizeseplist);*/
565
566             if (strlen(separatorList) == 2) { /* one separator behind b or t*/
567                 char *resultT = NULL;
568                 resultT = strtok(separatorList2, "t");
569                 if (strlen(resultT) == strlen(
570                             separatorList)) { /* didn't find t character, try to find b*/
571                     char *resultB = NULL;
572                     resultB = strtok(resultT, "b");
573                     if (strlen(resultB) == 1) {
574                         param->separator_base[0] = separatorList[1];
575                         param->separator_base[1] = 0;
576                         param->separator_test[0] = 0;
577                     } else { /* not found b*/
578                         free(separatorList2);
579                         return 1;
580                     }
581                 } else { /* found t*/
582                     param->separator_base[0] = 0;
583                     param->separator_test[0] = separatorList[1];
584                     param->separator_test[1] = 0;
585                 }
586                 /*printf("sep b = %s [%d] and sep t = %s [%d]\n",param->separator_base, strlen(param->separator_base), param->separator_test, strlen(param->separator_test) );*/
587             } else { /* == 4 characters we must found t and b*/
588                 char *resultT = NULL;
589                 resultT = strtok(separatorList2, "t");
590                 if (strlen(resultT) == 3) { /* found t in first place*/
591                     char *resultB = NULL;
592                     resultB = strtok(resultT, "b");
593                     if (strlen(resultB) == 1) { /* found b after t*/
594                         param->separator_test[0] = separatorList[1];
595                         param->separator_test[1] = 0;
596                         param->separator_base[0] = separatorList[3];
597                         param->separator_base[1] = 0;
598                     } else { /* didn't find b after t*/
599                         free(separatorList2);
600                         return 1;
601                     }
602                 } else { /* == 2, didn't find t in first place*/
603                     char *resultB = NULL;
604                     resultB = strtok(resultT, "b");
605                     if (strlen(resultB) == 1) { /* found b in first place*/
606                         param->separator_base[0] = separatorList[1];
607                         param->separator_base[1] = 0;
608                         param->separator_test[0] = separatorList[3];
609                         param->separator_test[1] = 0;
610                     } else { /* didn't found b in first place => problem*/
611                         free(separatorList2);
612                         return 1;
613                     }
614                 }
615             }
616             free(separatorList2);
617         } else { /* wrong number of argument after -s*/
618             return 1;
619         }
620     } else {
621         if (param->nbcomp == 1) {
622             assert(param->separator_base[0] == 0);
623             assert(param->separator_test[0] == 0);
624         } else {
625             fprintf(stderr, "If number of component is > 1, we need separator\n");
626             return 1;
627         }
628     }
629
630     if (ignoreList != NULL) {
631         if (strcmp(ignoreList, "prec") == 0) {
632             param->ignore_prec = 1;
633         } else {
634             fprintf(stderr, "Unsupported value for -i\n");
635             return 1;
636         }
637     }
638
639     if ((param->nr_flag) && (flagP || flagM)) {
640         fprintf(stderr,
641                 "Wrong input parameters list: it is non-regression test or tolerance comparison\n");
642         return 1;
643     }
644     if ((!param->nr_flag) && (!flagP || !flagM)) {
645         fprintf(stderr,
646                 "Wrong input parameters list: it is non-regression test or tolerance comparison\n");
647         return 1;
648     }
649
650     return 0;
651 }
652
653 /*******************************************************************************
654  * MAIN
655  *******************************************************************************/
656 int main(int argc, char **argv)
657 {
658     test_cmp_parameters inParam;
659     OPJ_UINT32 it_comp, itpxl;
660     int failed = 1;
661     int nbFilenamePGXbase = 0, nbFilenamePGXtest = 0;
662     char *filenamePNGtest = NULL, *filenamePNGbase = NULL, *filenamePNGdiff = NULL;
663     size_t memsizebasefilename, memsizetestfilename;
664     size_t memsizedifffilename;
665     int nbPixelDiff = 0;
666     double sumDiff = 0.0;
667     /* Structures to store image parameters and data*/
668     opj_image_t *imageBase = NULL, *imageTest = NULL, *imageDiff = NULL;
669     opj_image_cmptparm_t* param_image_diff = NULL;
670     int decod_format;
671
672     /* Get parameters from command line*/
673     if (parse_cmdline_cmp(argc, argv, &inParam)) {
674         compare_images_help_display();
675         goto cleanup;
676     }
677
678     /* Display Parameters*/
679     printf("******Parameters********* \n");
680     printf(" base_filename = %s\n"
681            " test_filename = %s\n"
682            " nb of Components = %d\n"
683            " Non regression test = %d\n"
684            " separator Base = %s\n"
685            " separator Test = %s\n",
686            inParam.base_filename, inParam.test_filename, inParam.nbcomp,
687            inParam.nr_flag, inParam.separator_base, inParam.separator_test);
688
689     if ((inParam.tabMSEvalues != NULL) && (inParam.tabPEAKvalues != NULL)) {
690         int it_comp2;
691         printf(" MSE values = [");
692         for (it_comp2 = 0; it_comp2 < inParam.nbcomp; it_comp2++) {
693             printf(" %f ", inParam.tabMSEvalues[it_comp2]);
694         }
695         printf("]\n");
696         printf(" PEAK values = [");
697         for (it_comp2 = 0; it_comp2 < inParam.nbcomp; it_comp2++) {
698             printf(" %f ", inParam.tabPEAKvalues[it_comp2]);
699         }
700         printf("]\n");
701         printf(" Non-regression test = %d\n", inParam.nr_flag);
702     }
703
704     if (strlen(inParam.separator_base) != 0) {
705         nbFilenamePGXbase = inParam.nbcomp;
706     }
707
708     if (strlen(inParam.separator_test) != 0) {
709         nbFilenamePGXtest = inParam.nbcomp;
710     }
711
712     printf(" NbFilename to generate from base filename = %d\n", nbFilenamePGXbase);
713     printf(" NbFilename to generate from test filename = %d\n", nbFilenamePGXtest);
714     printf("************************* \n");
715
716     /*----------BASELINE IMAGE--------*/
717     memsizebasefilename = strlen(inParam.test_filename) + 1 + 5 + 2 + 4;
718     memsizetestfilename = strlen(inParam.test_filename) + 1 + 5 + 2 + 4;
719
720     decod_format = get_decod_format(&inParam);
721     if (decod_format == -1) {
722         fprintf(stderr, "Unhandled file format\n");
723         goto cleanup;
724     }
725     assert(decod_format == PGX_DFMT || decod_format == TIF_DFMT ||
726            decod_format == PXM_DFMT);
727
728     if (decod_format == PGX_DFMT) {
729         imageBase = readImageFromFilePGX(inParam.base_filename, nbFilenamePGXbase,
730                                          inParam.separator_base);
731         if (imageBase == NULL) {
732             goto cleanup;
733         }
734     } else if (decod_format == TIF_DFMT) {
735         imageBase = readImageFromFileTIF(inParam.base_filename, nbFilenamePGXbase, "");
736         if (imageBase == NULL) {
737             goto cleanup;
738         }
739     } else if (decod_format == PXM_DFMT) {
740         imageBase = readImageFromFilePPM(inParam.base_filename, nbFilenamePGXbase,
741                                          inParam.separator_base);
742         if (imageBase == NULL) {
743             goto cleanup;
744         }
745     }
746
747     filenamePNGbase = (char*) malloc(memsizebasefilename);
748     strcpy(filenamePNGbase, inParam.test_filename);
749     strcat(filenamePNGbase, ".base");
750     /*printf("filenamePNGbase = %s [%d / %d octets]\n",filenamePNGbase, strlen(filenamePNGbase),memsizebasefilename );*/
751
752     /*----------TEST IMAGE--------*/
753
754     if (decod_format == PGX_DFMT) {
755         imageTest = readImageFromFilePGX(inParam.test_filename, nbFilenamePGXtest,
756                                          inParam.separator_test);
757         if (imageTest == NULL) {
758             goto cleanup;
759         }
760     } else if (decod_format == TIF_DFMT) {
761         imageTest = readImageFromFileTIF(inParam.test_filename, nbFilenamePGXtest, "");
762         if (imageTest == NULL) {
763             goto cleanup;
764         }
765     } else if (decod_format == PXM_DFMT) {
766         imageTest = readImageFromFilePPM(inParam.test_filename, nbFilenamePGXtest,
767                                          inParam.separator_test);
768         if (imageTest == NULL) {
769             goto cleanup;
770         }
771     }
772
773     filenamePNGtest = (char*) malloc(memsizetestfilename);
774     strcpy(filenamePNGtest, inParam.test_filename);
775     strcat(filenamePNGtest, ".test");
776     /*printf("filenamePNGtest = %s [%d / %d octets]\n",filenamePNGtest, strlen(filenamePNGtest),memsizetestfilename );*/
777
778     /*----------DIFF IMAGE--------*/
779
780     /* Allocate memory*/
781     param_image_diff = malloc(imageBase->numcomps * sizeof(opj_image_cmptparm_t));
782
783     /* Comparison of header parameters*/
784     printf("Step 1 -> Header comparison\n");
785
786     /* check dimensions (issue 286)*/
787     if (imageBase->numcomps != imageTest->numcomps) {
788         printf("ERROR: dim mismatch (%d><%d)\n", imageBase->numcomps,
789                imageTest->numcomps);
790         goto cleanup;
791     }
792
793     for (it_comp = 0; it_comp < imageBase->numcomps; it_comp++) {
794         param_image_diff[it_comp].x0 = 0;
795         param_image_diff[it_comp].y0 = 0;
796         param_image_diff[it_comp].dx = 0;
797         param_image_diff[it_comp].dy = 0;
798         param_image_diff[it_comp].sgnd = 0;
799         param_image_diff[it_comp].prec = 8;
800         param_image_diff[it_comp].h = imageBase->comps[it_comp].h;
801         param_image_diff[it_comp].w = imageBase->comps[it_comp].w;
802
803         if (imageBase->comps[it_comp].sgnd != imageTest->comps[it_comp].sgnd) {
804             printf("ERROR: sign mismatch [comp %d] (%d><%d)\n", it_comp,
805                    ((imageBase->comps)[it_comp]).sgnd, ((imageTest->comps)[it_comp]).sgnd);
806             goto cleanup;
807         }
808
809         if (((imageBase->comps)[it_comp]).prec != ((imageTest->comps)[it_comp]).prec &&
810                 !inParam.ignore_prec) {
811             printf("ERROR: prec mismatch [comp %d] (%d><%d)\n", it_comp,
812                    ((imageBase->comps)[it_comp]).prec, ((imageTest->comps)[it_comp]).prec);
813             goto cleanup;
814         }
815
816         if (((imageBase->comps)[it_comp]).h != ((imageTest->comps)[it_comp]).h) {
817             printf("ERROR: height mismatch [comp %d] (%d><%d)\n", it_comp,
818                    ((imageBase->comps)[it_comp]).h, ((imageTest->comps)[it_comp]).h);
819             goto cleanup;
820         }
821
822         if (((imageBase->comps)[it_comp]).w != ((imageTest->comps)[it_comp]).w) {
823             printf("ERROR: width mismatch [comp %d] (%d><%d)\n", it_comp,
824                    ((imageBase->comps)[it_comp]).w, ((imageTest->comps)[it_comp]).w);
825             goto cleanup;
826         }
827     }
828
829     imageDiff = opj_image_create(imageBase->numcomps, param_image_diff,
830                                  OPJ_CLRSPC_UNSPECIFIED);
831     /* Free memory*/
832     free(param_image_diff);
833     param_image_diff = NULL;
834
835     /* Measurement computation*/
836     printf("Step 2 -> measurement comparison\n");
837
838     memsizedifffilename = strlen(inParam.test_filename) + 1 + 5 + 2 + 4;
839     filenamePNGdiff = (char*) malloc(memsizedifffilename);
840     strcpy(filenamePNGdiff, inParam.test_filename);
841     strcat(filenamePNGdiff, ".diff");
842     /*printf("filenamePNGdiff = %s [%d / %d octets]\n",filenamePNGdiff, strlen(filenamePNGdiff),memsizedifffilename );*/
843
844     /* Compute pixel diff*/
845     failed = 0;
846     for (it_comp = 0; it_comp < imageDiff->numcomps; it_comp++) {
847         double SE = 0, PEAK = 0;
848         double MSE = 0;
849         unsigned right_shift_input = 0;
850         unsigned right_shift_output = 0;
851         if (((imageBase->comps)[it_comp]).prec > ((imageTest->comps)[it_comp]).prec) {
852             right_shift_input = ((imageBase->comps)[it_comp]).prec - ((
853                                     imageTest->comps)[it_comp]).prec;
854         } else {
855             right_shift_output = ((imageTest->comps)[it_comp]).prec - ((
856                                      imageBase->comps)[it_comp]).prec;
857         }
858         for (itpxl = 0;
859                 itpxl < ((imageDiff->comps)[it_comp]).w * ((imageDiff->comps)[it_comp]).h;
860                 itpxl++) {
861             int valueDiff = (((imageBase->comps)[it_comp]).data[itpxl] >> right_shift_input)
862                             - (((imageTest->comps)[it_comp]).data[itpxl] >> right_shift_output);
863             if (valueDiff != 0) {
864                 ((imageDiff->comps)[it_comp]).data[itpxl] = abs(valueDiff);
865                 sumDiff += valueDiff;
866                 nbPixelDiff++;
867
868                 SE += (double)valueDiff * valueDiff;
869                 PEAK = (PEAK > abs(valueDiff)) ? PEAK : abs(valueDiff);
870             } else {
871                 ((imageDiff->comps)[it_comp]).data[itpxl] = 0;
872             }
873         }/* h*w loop */
874
875         MSE = SE / (((imageDiff->comps)[it_comp]).w * ((imageDiff->comps)[it_comp]).h);
876
877         if (!inParam.nr_flag && (inParam.tabMSEvalues != NULL) &&
878                 (inParam.tabPEAKvalues != NULL)) {
879             /* Conformance test*/
880             printf("<DartMeasurement name=\"PEAK_%d\" type=\"numeric/double\"> %f </DartMeasurement> \n",
881                    it_comp, PEAK);
882             printf("<DartMeasurement name=\"MSE_%d\" type=\"numeric/double\"> %f </DartMeasurement> \n",
883                    it_comp, MSE);
884
885             if ((MSE > inParam.tabMSEvalues[it_comp]) ||
886                     (PEAK > inParam.tabPEAKvalues[it_comp])) {
887                 printf("ERROR: MSE (%f) or PEAK (%f) values produced by the decoded file are greater "
888                        "than the allowable error (respectively %f and %f) \n",
889                        MSE, PEAK, inParam.tabMSEvalues[it_comp], inParam.tabPEAKvalues[it_comp]);
890                 failed = 1;
891             }
892         } else { /* Non regression-test */
893             if (nbPixelDiff > 0) {
894                 char it_compc[255];
895                 it_compc[0] = 0;
896
897                 printf("<DartMeasurement name=\"NumberOfPixelsWithDifferences_%d\" type=\"numeric/int\"> %d </DartMeasurement> \n",
898                        it_comp, nbPixelDiff);
899                 printf("<DartMeasurement name=\"ComponentError_%d\" type=\"numeric/double\"> %f </DartMeasurement> \n",
900                        it_comp, sumDiff);
901                 printf("<DartMeasurement name=\"PEAK_%d\" type=\"numeric/double\"> %f </DartMeasurement> \n",
902                        it_comp, PEAK);
903                 printf("<DartMeasurement name=\"MSE_%d\" type=\"numeric/double\"> %f </DartMeasurement> \n",
904                        it_comp, MSE);
905
906 #ifdef OPJ_HAVE_LIBPNG
907                 {
908                     char *filenamePNGbase_it_comp, *filenamePNGtest_it_comp,
909                          *filenamePNGdiff_it_comp;
910
911                     filenamePNGbase_it_comp = (char*) malloc(memsizebasefilename);
912                     strcpy(filenamePNGbase_it_comp, filenamePNGbase);
913
914                     filenamePNGtest_it_comp = (char*) malloc(memsizetestfilename);
915                     strcpy(filenamePNGtest_it_comp, filenamePNGtest);
916
917                     filenamePNGdiff_it_comp = (char*) malloc(memsizedifffilename);
918                     strcpy(filenamePNGdiff_it_comp, filenamePNGdiff);
919
920                     sprintf(it_compc, "_%i", it_comp);
921                     strcat(it_compc, ".png");
922                     strcat(filenamePNGbase_it_comp, it_compc);
923                     /*printf("filenamePNGbase_it = %s [%d / %d octets]\n",filenamePNGbase_it_comp, strlen(filenamePNGbase_it_comp),memsizebasefilename );*/
924                     strcat(filenamePNGtest_it_comp, it_compc);
925                     /*printf("filenamePNGtest_it = %s [%d / %d octets]\n",filenamePNGtest_it_comp, strlen(filenamePNGtest_it_comp),memsizetestfilename );*/
926                     strcat(filenamePNGdiff_it_comp, it_compc);
927                     /*printf("filenamePNGdiff_it = %s [%d / %d octets]\n",filenamePNGdiff_it_comp, strlen(filenamePNGdiff_it_comp),memsizedifffilename );*/
928
929                     /*
930                     if ( imageToPNG(imageBase, filenamePNGbase_it_comp, it_comp) == EXIT_SUCCESS )
931                     {
932                     printf("<DartMeasurementFile name=\"BaselineImage_%d\" type=\"image/png\"> %s </DartMeasurementFile> \n", it_comp, filenamePNGbase_it_comp);
933                     }
934
935                     if ( imageToPNG(imageTest, filenamePNGtest_it_comp, it_comp) == EXIT_SUCCESS )
936                     {
937                     printf("<DartMeasurementFile name=\"TestImage_%d\" type=\"image/png\"> %s </DartMeasurementFile> \n", it_comp, filenamePNGtest_it_comp);
938                     }
939
940                     if ( imageToPNG(imageDiff, filenamePNGdiff_it_comp, it_comp) == EXIT_SUCCESS )
941                     {
942                     printf("<DartMeasurementFile name=\"DiffferenceImage_%d\" type=\"image/png\"> %s </DartMeasurementFile> \n", it_comp, filenamePNGdiff_it_comp);
943                     }
944                      */
945
946                     free(filenamePNGbase_it_comp);
947                     free(filenamePNGtest_it_comp);
948                     free(filenamePNGdiff_it_comp);
949                 }
950 #endif
951                 failed = 1;
952                 goto cleanup;
953             }
954         }
955     } /* it_comp loop */
956
957     if (!failed) {
958         printf("---- TEST SUCCEED ----\n");
959     }
960 cleanup:
961     /*-----------------------------*/
962     free(param_image_diff);
963     /* Free memory */
964     opj_image_destroy(imageBase);
965     opj_image_destroy(imageTest);
966     opj_image_destroy(imageDiff);
967
968     free(filenamePNGbase);
969     free(filenamePNGtest);
970     free(filenamePNGdiff);
971
972     free(inParam.tabMSEvalues);
973     free(inParam.tabPEAKvalues);
974     free(inParam.base_filename);
975     free(inParam.test_filename);
976
977     return failed ? EXIT_FAILURE : EXIT_SUCCESS;
978 }