Merge pull request #1253 from rouault/floating_point_irreversible_encoding
[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 + 7) * sizeof(char)); /*6*/
146
147     strncpy(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].bpp = image_read->comps->bpp;
229         param_image_read[it_file].prec = image_read->comps->prec;
230         param_image_read[it_file].sgnd = image_read->comps->sgnd;
231
232         /* Copy data*/
233         data[it_file] = malloc(param_image_read[it_file].h * param_image_read[it_file].w
234                                * sizeof(int));
235         memcpy(data[it_file], image_read->comps->data,
236                image_read->comps->h * image_read->comps->w * sizeof(int));
237
238         /* Free memory*/
239         opj_image_destroy(image_read);
240         free(filenameComponentPGX);
241     }
242
243     image = opj_image_create((OPJ_UINT32)nbFilenamePGX, param_image_read,
244                              OPJ_CLRSPC_UNSPECIFIED);
245     for (it_file = 0; it_file < nbFilenamePGX; it_file++) {
246         /* Copy data into output image and free memory*/
247         memcpy(image->comps[it_file].data, data[it_file],
248                image->comps[it_file].h * image->comps[it_file].w * sizeof(int));
249         free(data[it_file]);
250     }
251
252     /* Free memory*/
253     free(param_image_read);
254     free(data);
255
256     return image;
257 }
258
259 static opj_image_t* readImageFromFileTIF(const char* filename,
260         int nbFilenamePGX, const char *separator)
261 {
262     opj_image_t* image_read = NULL;
263     opj_cparameters_t parameters;
264     (void)nbFilenamePGX;
265     (void)separator;
266
267     /* conformance test suite produce annoying warning/error:
268      * TIFFReadDirectory: Warning, /.../data/baseline/conformance/jp2_1.tif: unknown field with tag 37724 (0x935c) encountered.
269      * TIFFOpen: /.../data/baseline/nonregression/opj_jp2_1.tif: Cannot open.
270      * On Win32 this open a message box by default, so remove it from the test suite:
271      */
272 #ifdef OPJ_HAVE_LIBTIFF
273     TIFFSetWarningHandler(NULL);
274     TIFFSetErrorHandler(NULL);
275 #endif
276
277     if (strlen(separator) != 0) {
278         return NULL;
279     }
280
281     /* set encoding parameters to default values */
282     opj_set_default_encoder_parameters(&parameters);
283     parameters.decod_format = TIF_DFMT;
284     strcpy(parameters.infile, filename);
285
286     /* Read the tif file corresponding to the component */
287 #ifdef OPJ_HAVE_LIBTIFF
288     image_read = tiftoimage(filename, &parameters);
289 #endif
290     if (!image_read) {
291         fprintf(stderr, "Unable to load TIF file\n");
292         return NULL;
293     }
294
295     return image_read;
296 }
297
298 static opj_image_t* readImageFromFilePGX(const char* filename,
299         int nbFilenamePGX, const char *separator)
300 {
301     int it_file;
302     opj_image_t* image_read = NULL;
303     opj_image_t* image = NULL;
304     opj_cparameters_t parameters;
305     opj_image_cmptparm_t* param_image_read;
306     int** data;
307
308     /* If separator is empty => nb file to read is equal to one*/
309     if (strlen(separator) == 0) {
310         nbFilenamePGX = 1;
311     }
312
313     /* set encoding parameters to default values */
314     opj_set_default_encoder_parameters(&parameters);
315     parameters.decod_format = PGX_DFMT;
316     strcpy(parameters.infile, filename);
317
318     /* Allocate memory*/
319     param_image_read = malloc((size_t)nbFilenamePGX * sizeof(opj_image_cmptparm_t));
320     data = malloc((size_t)nbFilenamePGX * sizeof(*data));
321
322     for (it_file = 0; it_file < nbFilenamePGX; it_file++) {
323         /* Create the right filename*/
324         char *filenameComponentPGX;
325         if (strlen(separator) == 0) {
326             filenameComponentPGX = malloc((strlen(filename) + 1) * sizeof(
327                                               *filenameComponentPGX));
328             strcpy(filenameComponentPGX, filename);
329         } else {
330             filenameComponentPGX = createMultiComponentsFilename(filename, it_file,
331                                    separator);
332         }
333
334         /* Read the pgx file corresponding to the component */
335         image_read = pgxtoimage(filenameComponentPGX, &parameters);
336         if (!image_read) {
337             int it_free_data;
338             fprintf(stderr, "Unable to load pgx file\n");
339
340             free(param_image_read);
341
342             for (it_free_data = 0; it_free_data < it_file; it_free_data++) {
343                 free(data[it_free_data]);
344             }
345             free(data);
346
347             free(filenameComponentPGX);
348
349             return NULL;
350         }
351
352         /* Set the image_read parameters*/
353         param_image_read[it_file].x0 = 0;
354         param_image_read[it_file].y0 = 0;
355         param_image_read[it_file].dx = 0;
356         param_image_read[it_file].dy = 0;
357         param_image_read[it_file].h = image_read->comps->h;
358         param_image_read[it_file].w = image_read->comps->w;
359         param_image_read[it_file].bpp = image_read->comps->bpp;
360         param_image_read[it_file].prec = image_read->comps->prec;
361         param_image_read[it_file].sgnd = image_read->comps->sgnd;
362
363         /* Copy data*/
364         data[it_file] = malloc(param_image_read[it_file].h * param_image_read[it_file].w
365                                * sizeof(int));
366         memcpy(data[it_file], image_read->comps->data,
367                image_read->comps->h * image_read->comps->w * sizeof(int));
368
369         /* Free memory*/
370         opj_image_destroy(image_read);
371         free(filenameComponentPGX);
372     }
373
374     image = opj_image_create((OPJ_UINT32)nbFilenamePGX, param_image_read,
375                              OPJ_CLRSPC_UNSPECIFIED);
376     for (it_file = 0; it_file < nbFilenamePGX; it_file++) {
377         /* Copy data into output image and free memory*/
378         memcpy(image->comps[it_file].data, data[it_file],
379                image->comps[it_file].h * image->comps[it_file].w * sizeof(int));
380         free(data[it_file]);
381     }
382
383     /* Free memory*/
384     free(param_image_read);
385     free(data);
386
387     return image;
388 }
389
390 #if defined(OPJ_HAVE_LIBPNG) && 0 /* remove for now */
391 /*******************************************************************************
392  *
393  *******************************************************************************/
394 static int imageToPNG(const opj_image_t* image, const char* filename,
395                       int num_comp_select)
396 {
397     opj_image_cmptparm_t param_image_write;
398     opj_image_t* image_write = NULL;
399
400     param_image_write.x0 = 0;
401     param_image_write.y0 = 0;
402     param_image_write.dx = 0;
403     param_image_write.dy = 0;
404     param_image_write.h = image->comps[num_comp_select].h;
405     param_image_write.w = image->comps[num_comp_select].w;
406     param_image_write.bpp = image->comps[num_comp_select].bpp;
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].bpp = 1;
801         param_image_diff[it_comp].h = imageBase->comps[it_comp].h;
802         param_image_diff[it_comp].w = imageBase->comps[it_comp].w;
803
804         if (imageBase->comps[it_comp].sgnd != imageTest->comps[it_comp].sgnd) {
805             printf("ERROR: sign mismatch [comp %d] (%d><%d)\n", it_comp,
806                    ((imageBase->comps)[it_comp]).sgnd, ((imageTest->comps)[it_comp]).sgnd);
807             goto cleanup;
808         }
809
810         if (((imageBase->comps)[it_comp]).prec != ((imageTest->comps)[it_comp]).prec &&
811                 !inParam.ignore_prec) {
812             printf("ERROR: prec mismatch [comp %d] (%d><%d)\n", it_comp,
813                    ((imageBase->comps)[it_comp]).prec, ((imageTest->comps)[it_comp]).prec);
814             goto cleanup;
815         }
816
817         if (((imageBase->comps)[it_comp]).bpp != ((imageTest->comps)[it_comp]).bpp &&
818                 !inParam.ignore_prec) {
819             printf("ERROR: bit per pixel mismatch [comp %d] (%d><%d)\n", it_comp,
820                    ((imageBase->comps)[it_comp]).bpp, ((imageTest->comps)[it_comp]).bpp);
821             goto cleanup;
822         }
823
824         if (((imageBase->comps)[it_comp]).h != ((imageTest->comps)[it_comp]).h) {
825             printf("ERROR: height mismatch [comp %d] (%d><%d)\n", it_comp,
826                    ((imageBase->comps)[it_comp]).h, ((imageTest->comps)[it_comp]).h);
827             goto cleanup;
828         }
829
830         if (((imageBase->comps)[it_comp]).w != ((imageTest->comps)[it_comp]).w) {
831             printf("ERROR: width mismatch [comp %d] (%d><%d)\n", it_comp,
832                    ((imageBase->comps)[it_comp]).w, ((imageTest->comps)[it_comp]).w);
833             goto cleanup;
834         }
835     }
836
837     imageDiff = opj_image_create(imageBase->numcomps, param_image_diff,
838                                  OPJ_CLRSPC_UNSPECIFIED);
839     /* Free memory*/
840     free(param_image_diff);
841     param_image_diff = NULL;
842
843     /* Measurement computation*/
844     printf("Step 2 -> measurement comparison\n");
845
846     memsizedifffilename = strlen(inParam.test_filename) + 1 + 5 + 2 + 4;
847     filenamePNGdiff = (char*) malloc(memsizedifffilename);
848     strcpy(filenamePNGdiff, inParam.test_filename);
849     strcat(filenamePNGdiff, ".diff");
850     /*printf("filenamePNGdiff = %s [%d / %d octets]\n",filenamePNGdiff, strlen(filenamePNGdiff),memsizedifffilename );*/
851
852     /* Compute pixel diff*/
853     failed = 0;
854     for (it_comp = 0; it_comp < imageDiff->numcomps; it_comp++) {
855         double SE = 0, PEAK = 0;
856         double MSE = 0;
857         unsigned right_shift_input = 0;
858         unsigned right_shift_output = 0;
859         if (((imageBase->comps)[it_comp]).bpp > ((imageTest->comps)[it_comp]).bpp) {
860             right_shift_input = ((imageBase->comps)[it_comp]).bpp - ((
861                                     imageTest->comps)[it_comp]).bpp;
862         } else {
863             right_shift_output = ((imageTest->comps)[it_comp]).bpp - ((
864                                      imageBase->comps)[it_comp]).bpp;
865         }
866         for (itpxl = 0;
867                 itpxl < ((imageDiff->comps)[it_comp]).w * ((imageDiff->comps)[it_comp]).h;
868                 itpxl++) {
869             int valueDiff = (((imageBase->comps)[it_comp]).data[itpxl] >> right_shift_input)
870                             - (((imageTest->comps)[it_comp]).data[itpxl] >> right_shift_output);
871             if (valueDiff != 0) {
872                 ((imageDiff->comps)[it_comp]).data[itpxl] = abs(valueDiff);
873                 sumDiff += valueDiff;
874                 nbPixelDiff++;
875
876                 SE += (double)valueDiff * valueDiff;
877                 PEAK = (PEAK > abs(valueDiff)) ? PEAK : abs(valueDiff);
878             } else {
879                 ((imageDiff->comps)[it_comp]).data[itpxl] = 0;
880             }
881         }/* h*w loop */
882
883         MSE = SE / (((imageDiff->comps)[it_comp]).w * ((imageDiff->comps)[it_comp]).h);
884
885         if (!inParam.nr_flag && (inParam.tabMSEvalues != NULL) &&
886                 (inParam.tabPEAKvalues != NULL)) {
887             /* Conformance test*/
888             printf("<DartMeasurement name=\"PEAK_%d\" type=\"numeric/double\"> %f </DartMeasurement> \n",
889                    it_comp, PEAK);
890             printf("<DartMeasurement name=\"MSE_%d\" type=\"numeric/double\"> %f </DartMeasurement> \n",
891                    it_comp, MSE);
892
893             if ((MSE > inParam.tabMSEvalues[it_comp]) ||
894                     (PEAK > inParam.tabPEAKvalues[it_comp])) {
895                 printf("ERROR: MSE (%f) or PEAK (%f) values produced by the decoded file are greater "
896                        "than the allowable error (respectively %f and %f) \n",
897                        MSE, PEAK, inParam.tabMSEvalues[it_comp], inParam.tabPEAKvalues[it_comp]);
898                 failed = 1;
899             }
900         } else { /* Non regression-test */
901             if (nbPixelDiff > 0) {
902                 char it_compc[255];
903                 it_compc[0] = 0;
904
905                 printf("<DartMeasurement name=\"NumberOfPixelsWithDifferences_%d\" type=\"numeric/int\"> %d </DartMeasurement> \n",
906                        it_comp, nbPixelDiff);
907                 printf("<DartMeasurement name=\"ComponentError_%d\" type=\"numeric/double\"> %f </DartMeasurement> \n",
908                        it_comp, sumDiff);
909                 printf("<DartMeasurement name=\"PEAK_%d\" type=\"numeric/double\"> %f </DartMeasurement> \n",
910                        it_comp, PEAK);
911                 printf("<DartMeasurement name=\"MSE_%d\" type=\"numeric/double\"> %f </DartMeasurement> \n",
912                        it_comp, MSE);
913
914 #ifdef OPJ_HAVE_LIBPNG
915                 {
916                     char *filenamePNGbase_it_comp, *filenamePNGtest_it_comp,
917                          *filenamePNGdiff_it_comp;
918
919                     filenamePNGbase_it_comp = (char*) malloc(memsizebasefilename);
920                     strcpy(filenamePNGbase_it_comp, filenamePNGbase);
921
922                     filenamePNGtest_it_comp = (char*) malloc(memsizetestfilename);
923                     strcpy(filenamePNGtest_it_comp, filenamePNGtest);
924
925                     filenamePNGdiff_it_comp = (char*) malloc(memsizedifffilename);
926                     strcpy(filenamePNGdiff_it_comp, filenamePNGdiff);
927
928                     sprintf(it_compc, "_%i", it_comp);
929                     strcat(it_compc, ".png");
930                     strcat(filenamePNGbase_it_comp, it_compc);
931                     /*printf("filenamePNGbase_it = %s [%d / %d octets]\n",filenamePNGbase_it_comp, strlen(filenamePNGbase_it_comp),memsizebasefilename );*/
932                     strcat(filenamePNGtest_it_comp, it_compc);
933                     /*printf("filenamePNGtest_it = %s [%d / %d octets]\n",filenamePNGtest_it_comp, strlen(filenamePNGtest_it_comp),memsizetestfilename );*/
934                     strcat(filenamePNGdiff_it_comp, it_compc);
935                     /*printf("filenamePNGdiff_it = %s [%d / %d octets]\n",filenamePNGdiff_it_comp, strlen(filenamePNGdiff_it_comp),memsizedifffilename );*/
936
937                     /*
938                     if ( imageToPNG(imageBase, filenamePNGbase_it_comp, it_comp) == EXIT_SUCCESS )
939                     {
940                     printf("<DartMeasurementFile name=\"BaselineImage_%d\" type=\"image/png\"> %s </DartMeasurementFile> \n", it_comp, filenamePNGbase_it_comp);
941                     }
942
943                     if ( imageToPNG(imageTest, filenamePNGtest_it_comp, it_comp) == EXIT_SUCCESS )
944                     {
945                     printf("<DartMeasurementFile name=\"TestImage_%d\" type=\"image/png\"> %s </DartMeasurementFile> \n", it_comp, filenamePNGtest_it_comp);
946                     }
947
948                     if ( imageToPNG(imageDiff, filenamePNGdiff_it_comp, it_comp) == EXIT_SUCCESS )
949                     {
950                     printf("<DartMeasurementFile name=\"DiffferenceImage_%d\" type=\"image/png\"> %s </DartMeasurementFile> \n", it_comp, filenamePNGdiff_it_comp);
951                     }
952                      */
953
954                     free(filenamePNGbase_it_comp);
955                     free(filenamePNGtest_it_comp);
956                     free(filenamePNGdiff_it_comp);
957                 }
958 #endif
959                 failed = 1;
960                 goto cleanup;
961             }
962         }
963     } /* it_comp loop */
964
965     if (!failed) {
966         printf("---- TEST SUCCEED ----\n");
967     }
968 cleanup:
969     /*-----------------------------*/
970     free(param_image_diff);
971     /* Free memory */
972     opj_image_destroy(imageBase);
973     opj_image_destroy(imageTest);
974     opj_image_destroy(imageDiff);
975
976     free(filenamePNGbase);
977     free(filenamePNGtest);
978     free(filenamePNGdiff);
979
980     free(inParam.tabMSEvalues);
981     free(inParam.tabPEAKvalues);
982     free(inParam.base_filename);
983     free(inParam.test_filename);
984
985     return failed ? EXIT_FAILURE : EXIT_SUCCESS;
986 }