Merge pull request #1518 from dg0yt/static-windows
[openjpeg.git] / src / bin / jp2 / opj_dump.c
1 /*
2  * The copyright in this software is being made available under the 2-clauses
3  * BSD License, included below. This software may be subject to other third
4  * party and contributor rights, including patent rights, and no such rights
5  * are granted under this license.
6  *
7  * Copyright (c) 2010, Mathieu Malaterre, GDCM
8  * Copyright (c) 2011-2012, Centre National d'Etudes Spatiales (CNES), France
9  * Copyright (c) 2012, CS Systemes d'Information, France
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 #include "opj_config.h"
34
35 #include <stdio.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <math.h>
39 #include <limits.h>
40
41 #ifdef _WIN32
42 #include "windirent.h"
43 #else
44 #include <dirent.h>
45 #endif /* _WIN32 */
46
47 #ifdef _WIN32
48 #include <windows.h>
49 #else
50 #include <strings.h>
51 #define _stricmp strcasecmp
52 #define _strnicmp strncasecmp
53 #endif /* _WIN32 */
54
55 #include "openjpeg.h"
56 #include "opj_getopt.h"
57 #include "convert.h"
58 #include "index.h"
59
60 #include "format_defs.h"
61 #include "opj_string.h"
62
63 typedef struct dircnt {
64     /** Buffer for holding images read from Directory*/
65     char *filename_buf;
66     /** Pointer to the buffer*/
67     char **filename;
68 } dircnt_t;
69
70
71 typedef struct img_folder {
72     /** The directory path of the folder containing input images*/
73     char *imgdirpath;
74     /** Output format*/
75     const char *out_format;
76     /** Enable option*/
77     char set_imgdir;
78     /** Enable Cod Format for output*/
79     char set_out_format;
80
81     int flag;
82 } img_fol_t;
83
84 /* -------------------------------------------------------------------------- */
85 /* Declarations                                                               */
86 static unsigned int get_num_images(char *imgdirpath);
87 static int load_images(dircnt_t *dirptr, char *imgdirpath);
88 static int get_file_format(const char *filename);
89 static char get_next_file(unsigned int imageno, dircnt_t *dirptr,
90                           img_fol_t *img_fol,
91                           opj_dparameters_t *parameters);
92 static int infile_format(const char *fname);
93
94 static int parse_cmdline_decoder(int argc, char **argv,
95                                  opj_dparameters_t *parameters, img_fol_t *img_fol);
96
97 /* -------------------------------------------------------------------------- */
98 static void decode_help_display(void)
99 {
100     fprintf(stdout, "\nThis is the opj_dump utility from the OpenJPEG project.\n"
101             "It dumps JPEG 2000 codestream info to stdout or a given file.\n"
102             "It has been compiled against openjp2 library v%s.\n\n", opj_version());
103
104     fprintf(stdout, "Parameters:\n");
105     fprintf(stdout, "-----------\n");
106     fprintf(stdout, "\n");
107     fprintf(stdout, "  -ImgDir <directory>\n");
108     fprintf(stdout, "   Image file Directory path \n");
109     fprintf(stdout, "  -i <compressed file>\n");
110     fprintf(stdout,
111             "    REQUIRED only if an Input image directory not specified\n");
112     fprintf(stdout,
113             "    Currently accepts J2K-files, JP2-files and JPT-files. The file type\n");
114     fprintf(stdout, "    is identified based on its suffix.\n");
115     fprintf(stdout, "  -o <output file>\n");
116     fprintf(stdout, "    OPTIONAL\n");
117     fprintf(stdout, "    Output file where file info will be dump.\n");
118     fprintf(stdout, "    By default it will be in the stdout.\n");
119     fprintf(stdout, "  -v "); /* FIXME WIP_MSD */
120     fprintf(stdout, "    OPTIONAL\n");
121     fprintf(stdout, "    Enable informative messages\n");
122     fprintf(stdout, "    By default verbose mode is off.\n");
123     fprintf(stdout, "\n");
124 }
125
126 /* -------------------------------------------------------------------------- */
127 static unsigned int get_num_images(char *imgdirpath)
128 {
129     DIR *dir;
130     struct dirent* content;
131     unsigned int num_images = 0;
132
133     /*Reading the input images from given input directory*/
134
135     dir = opendir(imgdirpath);
136     if (!dir) {
137         fprintf(stderr, "Could not open Folder %s\n", imgdirpath);
138         return 0;
139     }
140
141     while ((content = readdir(dir)) != NULL) {
142         if (strcmp(".", content->d_name) == 0 || strcmp("..", content->d_name) == 0) {
143             continue;
144         }
145         if (num_images == UINT_MAX) {
146             fprintf(stderr, "Too many files in folder %s\n", imgdirpath);
147             num_images = 0;
148             break;
149         }
150         num_images++;
151     }
152     closedir(dir);
153     return num_images;
154 }
155
156 /* -------------------------------------------------------------------------- */
157 static int load_images(dircnt_t *dirptr, char *imgdirpath)
158 {
159     DIR *dir;
160     struct dirent* content;
161     int i = 0;
162
163     /*Reading the input images from given input directory*/
164
165     dir = opendir(imgdirpath);
166     if (!dir) {
167         fprintf(stderr, "Could not open Folder %s\n", imgdirpath);
168         return 1;
169     } else   {
170         fprintf(stderr, "Folder opened successfully\n");
171     }
172
173     while ((content = readdir(dir)) != NULL) {
174         if (strcmp(".", content->d_name) == 0 || strcmp("..", content->d_name) == 0) {
175             continue;
176         }
177
178         strcpy(dirptr->filename[i], content->d_name);
179         i++;
180     }
181     closedir(dir);
182     return 0;
183 }
184
185 /* -------------------------------------------------------------------------- */
186 static int get_file_format(const char *filename)
187 {
188     unsigned int i;
189     static const char * const extension[] = {
190         "pgx", "pnm", "pgm", "ppm", "bmp",
191         "tif", "tiff",
192         "raw", "yuv", "rawl",
193         "tga", "png",
194         "j2k", "jp2", "jpt", "j2c", "jpc",
195         "jph", /* HTJ2K with JP2 boxes */
196         "jhc" /* HTJ2K codestream */
197     };
198     static const int format[] = {
199         PGX_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, BMP_DFMT,
200         TIF_DFMT, TIF_DFMT,
201         RAW_DFMT, RAW_DFMT, RAWL_DFMT,
202         TGA_DFMT, PNG_DFMT,
203         J2K_CFMT, JP2_CFMT, JPT_CFMT, J2K_CFMT, J2K_CFMT,
204         JP2_CFMT, /* HTJ2K with JP2 boxes */
205         J2K_CFMT /* HTJ2K codestream */
206     };
207     const char *ext = strrchr(filename, '.');
208     if (ext == NULL) {
209         return -1;
210     }
211     ext++;
212     if (ext) {
213         for (i = 0; i < sizeof(format) / sizeof(*format); i++) {
214             if (_strnicmp(ext, extension[i], 3) == 0) {
215                 return format[i];
216             }
217         }
218     }
219
220     return -1;
221 }
222
223 /* -------------------------------------------------------------------------- */
224 static char get_next_file(unsigned int imageno, dircnt_t *dirptr,
225                           img_fol_t *img_fol,
226                           opj_dparameters_t *parameters)
227 {
228     char image_filename[OPJ_PATH_LEN], infilename[OPJ_PATH_LEN],
229          outfilename[OPJ_PATH_LEN], temp_ofname[OPJ_PATH_LEN];
230     char *temp_p, temp1[OPJ_PATH_LEN] = "";
231
232     strcpy(image_filename, dirptr->filename[imageno]);
233     fprintf(stderr, "File Number %u \"%s\"\n", imageno, image_filename);
234     parameters->decod_format = get_file_format(image_filename);
235     if (parameters->decod_format == -1) {
236         return 1;
237     }
238     if (strlen(img_fol->imgdirpath) + 1 + strlen(
239                 image_filename) + 1 > sizeof(infilename)) {
240         return 1;
241     }
242     strcpy(infilename, img_fol->imgdirpath);
243     strcat(infilename, "/");
244     strcat(infilename, image_filename);
245     if (opj_strcpy_s(parameters->infile, sizeof(parameters->infile),
246                      infilename) != 0) {
247         return 1;
248     }
249
250     /*Set output file*/
251     strcpy(temp_ofname, strtok(image_filename, "."));
252     while ((temp_p = strtok(NULL, ".")) != NULL) {
253         strcat(temp_ofname, temp1);
254         sprintf(temp1, ".%s", temp_p);
255     }
256     if (img_fol->set_out_format == 1) {
257         if (strlen(img_fol->imgdirpath) + 1 + strlen(temp_ofname) + 1 + strlen(
258                     img_fol->out_format) + 1 > sizeof(outfilename)) {
259             return 1;
260         }
261         strcpy(outfilename, img_fol->imgdirpath);
262         strcat(outfilename, "/");
263         strcat(outfilename, temp_ofname);
264         strcat(outfilename, ".");
265         strcat(outfilename, img_fol->out_format);
266         if (opj_strcpy_s(parameters->outfile, sizeof(parameters->outfile),
267                          outfilename) != 0) {
268             return 1;
269         }
270     }
271     return 0;
272 }
273
274 /* -------------------------------------------------------------------------- */
275 #define JP2_RFC3745_MAGIC "\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a"
276 #define JP2_MAGIC "\x0d\x0a\x87\x0a"
277 /* position 45: "\xff\x52" */
278 #define J2K_CODESTREAM_MAGIC "\xff\x4f\xff\x51"
279
280 static int infile_format(const char *fname)
281 {
282     FILE *reader;
283     const char *s, *magic_s;
284     int ext_format, magic_format;
285     unsigned char buf[12];
286     size_t l_nb_read;
287
288     reader = fopen(fname, "rb");
289
290     if (reader == NULL) {
291         return -1;
292     }
293
294     memset(buf, 0, 12);
295     l_nb_read = fread(buf, 1, 12, reader);
296     fclose(reader);
297     if (l_nb_read != 12) {
298         return -1;
299     }
300
301
302
303     ext_format = get_file_format(fname);
304
305     if (ext_format == JPT_CFMT) {
306         return JPT_CFMT;
307     }
308
309     if (memcmp(buf, JP2_RFC3745_MAGIC, 12) == 0 || memcmp(buf, JP2_MAGIC, 4) == 0) {
310         magic_format = JP2_CFMT;
311         magic_s = ".jp2 or .jph";
312     } else if (memcmp(buf, J2K_CODESTREAM_MAGIC, 4) == 0) {
313         magic_format = J2K_CFMT;
314         magic_s = ".j2k or .jpc or .j2c or .jhc";
315     } else {
316         return -1;
317     }
318
319     if (magic_format == ext_format) {
320         return ext_format;
321     }
322
323     s = fname + strlen(fname) - 4;
324
325     fputs("\n===========================================\n", stderr);
326     fprintf(stderr, "The extension of this file is incorrect.\n"
327             "FOUND %s. SHOULD BE %s\n", s, magic_s);
328     fputs("===========================================\n", stderr);
329
330     return magic_format;
331 }
332 /* -------------------------------------------------------------------------- */
333 /**
334  * Parse the command line
335  */
336 /* -------------------------------------------------------------------------- */
337 static int parse_cmdline_decoder(int argc, char **argv,
338                                  opj_dparameters_t *parameters, img_fol_t *img_fol)
339 {
340     int totlen, c;
341     opj_option_t long_option[] = {
342         {"ImgDir", REQ_ARG, NULL, 'y'}
343     };
344     const char optlist[] = "i:o:f:hv";
345
346     totlen = sizeof(long_option);
347     img_fol->set_out_format = 0;
348     do {
349         c = opj_getopt_long(argc, argv, optlist, long_option, totlen);
350         if (c == -1) {
351             break;
352         }
353         switch (c) {
354         case 'i': {         /* input file */
355             char *infile = opj_optarg;
356             parameters->decod_format = infile_format(infile);
357             switch (parameters->decod_format) {
358             case J2K_CFMT:
359                 break;
360             case JP2_CFMT:
361                 break;
362             case JPT_CFMT:
363                 break;
364             default:
365                 fprintf(stderr,
366                         "[ERROR] Unknown input file format: %s \n"
367                         "        Known file formats are *.j2k, *.jp2, *.jpc or *.jpt\n",
368                         infile);
369                 return 1;
370             }
371             if (opj_strcpy_s(parameters->infile, sizeof(parameters->infile), infile) != 0) {
372                 fprintf(stderr, "[ERROR] Path is too long\n");
373                 return 1;
374             }
375         }
376         break;
377
378         /* ------------------------------------------------------ */
379
380         case 'o': {   /* output file */
381             if (opj_strcpy_s(parameters->outfile, sizeof(parameters->outfile),
382                              opj_optarg) != 0) {
383                 fprintf(stderr, "[ERROR] Path is too long\n");
384                 return 1;
385             }
386         }
387         break;
388
389         /* ----------------------------------------------------- */
390         case 'f':             /* flag */
391             img_fol->flag = atoi(opj_optarg);
392             break;
393         /* ----------------------------------------------------- */
394
395         case 'h':           /* display an help description */
396             decode_help_display();
397             return 1;
398
399         /* ------------------------------------------------------ */
400
401         case 'y': {         /* Image Directory path */
402             img_fol->imgdirpath = (char*)malloc(strlen(opj_optarg) + 1);
403             if (img_fol->imgdirpath == NULL) {
404                 return 1;
405             }
406             strcpy(img_fol->imgdirpath, opj_optarg);
407             img_fol->set_imgdir = 1;
408         }
409         break;
410
411         /* ----------------------------------------------------- */
412
413         case 'v': {         /* Verbose mode */
414             parameters->m_verbose = 1;
415         }
416         break;
417
418         /* ----------------------------------------------------- */
419         default:
420             fprintf(stderr, "[WARNING] An invalid option has been ignored.\n");
421             break;
422         }
423     } while (c != -1);
424
425     /* check for possible errors */
426     if (img_fol->set_imgdir == 1) {
427         if (!(parameters->infile[0] == 0)) {
428             fprintf(stderr, "[ERROR] options -ImgDir and -i cannot be used together.\n");
429             return 1;
430         }
431         if (img_fol->set_out_format == 0) {
432             fprintf(stderr,
433                     "[ERROR] When -ImgDir is used, -OutFor <FORMAT> must be used.\n");
434             fprintf(stderr, "Only one format allowed.\n"
435                     "Valid format are PGM, PPM, PNM, PGX, BMP, TIF, TIFF, RAW, YUV and TGA.\n");
436             return 1;
437         }
438         if (!(parameters->outfile[0] == 0)) {
439             fprintf(stderr, "[ERROR] options -ImgDir and -o cannot be used together\n");
440             return 1;
441         }
442     } else {
443         if (parameters->infile[0] == 0) {
444             fprintf(stderr, "[ERROR] Required parameter is missing\n");
445             fprintf(stderr, "Example: %s -i image.j2k\n", argv[0]);
446             fprintf(stderr, "   Help: %s -h\n", argv[0]);
447             return 1;
448         }
449     }
450
451     return 0;
452 }
453
454 /* -------------------------------------------------------------------------- */
455
456 /**
457 sample error debug callback expecting no client object
458 */
459 static void error_callback(const char *msg, void *client_data)
460 {
461     (void)client_data;
462     fprintf(stdout, "[ERROR] %s", msg);
463 }
464 /**
465 sample warning debug callback expecting no client object
466 */
467 static void warning_callback(const char *msg, void *client_data)
468 {
469     (void)client_data;
470     fprintf(stdout, "[WARNING] %s", msg);
471 }
472 /**
473 sample debug callback expecting no client object
474 */
475 static void info_callback(const char *msg, void *client_data)
476 {
477     (void)client_data;
478     fprintf(stdout, "[INFO] %s", msg);
479 }
480
481 /* -------------------------------------------------------------------------- */
482 /**
483  * OPJ_DUMP MAIN
484  */
485 /* -------------------------------------------------------------------------- */
486 int main(int argc, char *argv[])
487 {
488     FILE *fout = NULL;
489
490     opj_dparameters_t parameters;           /* Decompression parameters */
491     opj_image_t* image = NULL;                  /* Image structure */
492     opj_codec_t* l_codec = NULL;                /* Handle to a decompressor */
493     opj_stream_t *l_stream = NULL;              /* Stream */
494     opj_codestream_info_v2_t* cstr_info = NULL;
495     opj_codestream_index_t* cstr_index = NULL;
496
497     unsigned int num_images, imageno;
498     img_fol_t img_fol;
499     dircnt_t *dirptr = NULL;
500
501     /* Set decoding parameters to default values */
502     opj_set_default_decoder_parameters(&parameters);
503
504     /* Initialize img_fol */
505     memset(&img_fol, 0, sizeof(img_fol_t));
506     img_fol.flag = OPJ_IMG_INFO | OPJ_J2K_MH_INFO | OPJ_J2K_MH_IND;
507
508     /* Parse input and get user encoding parameters */
509     if (parse_cmdline_decoder(argc, argv, &parameters, &img_fol) == 1) {
510         if (img_fol.imgdirpath) {
511             free(img_fol.imgdirpath);
512         }
513
514         return EXIT_FAILURE;
515     }
516
517     /* Initialize reading of directory */
518     if (img_fol.set_imgdir == 1) {
519         unsigned int it_image;
520         num_images = get_num_images(img_fol.imgdirpath);
521         if (num_images == 0) {
522             fprintf(stdout, "Folder is empty\n");
523             goto fails;
524         }
525         dirptr = (dircnt_t*)malloc(sizeof(dircnt_t));
526         if (!dirptr) {
527             return EXIT_FAILURE;
528         }
529         /* Stores at max 10 image file names*/
530         dirptr->filename_buf = (char*) calloc((size_t) num_images,
531                                               OPJ_PATH_LEN * sizeof(char));
532         if (!dirptr->filename_buf) {
533             free(dirptr);
534             return EXIT_FAILURE;
535         }
536         dirptr->filename = (char**) calloc((size_t) num_images, sizeof(char*));
537
538         if (!dirptr->filename) {
539             goto fails;
540         }
541
542         for (it_image = 0; it_image < num_images; it_image++) {
543             dirptr->filename[it_image] = dirptr->filename_buf + (size_t)it_image *
544                                          OPJ_PATH_LEN;
545         }
546
547         if (load_images(dirptr, img_fol.imgdirpath) == 1) {
548             goto fails;
549         }
550
551     } else {
552         num_images = 1;
553     }
554
555     /* Try to open for writing the output file if necessary */
556     if (parameters.outfile[0] != 0) {
557         fout = fopen(parameters.outfile, "w");
558         if (!fout) {
559             fprintf(stderr, "ERROR -> failed to open %s for writing\n", parameters.outfile);
560             goto fails;
561         }
562     } else {
563         fout = stdout;
564     }
565
566     /* Read the header of each image one by one */
567     for (imageno = 0; imageno < num_images ; imageno++) {
568
569         fprintf(stderr, "\n");
570
571         if (img_fol.set_imgdir == 1) {
572             if (get_next_file(imageno, dirptr, &img_fol, &parameters)) {
573                 fprintf(stderr, "skipping file...\n");
574                 continue;
575             }
576         }
577
578         /* Read the input file and put it in memory */
579         /* ---------------------------------------- */
580
581         l_stream = opj_stream_create_default_file_stream(parameters.infile, 1);
582         if (!l_stream) {
583             fprintf(stderr, "ERROR -> failed to create the stream from the file %s\n",
584                     parameters.infile);
585             goto fails;
586         }
587
588         /* Read the JPEG2000 stream */
589         /* ------------------------ */
590
591         switch (parameters.decod_format) {
592         case J2K_CFMT: { /* JPEG-2000 codestream */
593             /* Get a decoder handle */
594             l_codec = opj_create_decompress(OPJ_CODEC_J2K);
595             break;
596         }
597         case JP2_CFMT: { /* JPEG 2000 compressed image data */
598             /* Get a decoder handle */
599             l_codec = opj_create_decompress(OPJ_CODEC_JP2);
600             break;
601         }
602         case JPT_CFMT: { /* JPEG 2000, JPIP */
603             /* Get a decoder handle */
604             l_codec = opj_create_decompress(OPJ_CODEC_JPT);
605             break;
606         }
607         default:
608             fprintf(stderr, "skipping file..\n");
609             opj_stream_destroy(l_stream);
610             continue;
611         }
612
613         /* catch events using our callbacks and give a local context */
614         opj_set_info_handler(l_codec, info_callback, 00);
615         opj_set_warning_handler(l_codec, warning_callback, 00);
616         opj_set_error_handler(l_codec, error_callback, 00);
617
618         parameters.flags |= OPJ_DPARAMETERS_DUMP_FLAG;
619
620         /* Setup the decoder decoding parameters using user parameters */
621         if (!opj_setup_decoder(l_codec, &parameters)) {
622             fprintf(stderr, "ERROR -> opj_dump: failed to setup the decoder\n");
623             opj_stream_destroy(l_stream);
624             opj_destroy_codec(l_codec);
625             fclose(fout);
626             goto fails;
627         }
628
629         /* Read the main header of the codestream and if necessary the JP2 boxes*/
630         if (! opj_read_header(l_stream, l_codec, &image)) {
631             fprintf(stderr, "ERROR -> opj_dump: failed to read the header\n");
632             opj_stream_destroy(l_stream);
633             opj_destroy_codec(l_codec);
634             opj_image_destroy(image);
635             fclose(fout);
636             goto fails;
637         }
638
639         opj_dump_codec(l_codec, img_fol.flag, fout);
640
641         cstr_info = opj_get_cstr_info(l_codec);
642
643         cstr_index = opj_get_cstr_index(l_codec);
644
645         /* close the byte stream */
646         opj_stream_destroy(l_stream);
647
648         /* free remaining structures */
649         if (l_codec) {
650             opj_destroy_codec(l_codec);
651         }
652
653         /* destroy the image header */
654         opj_image_destroy(image);
655
656         /* destroy the codestream index */
657         opj_destroy_cstr_index(&cstr_index);
658
659         /* destroy the codestream info */
660         opj_destroy_cstr_info(&cstr_info);
661
662     }
663
664     /* Close the output file */
665     fclose(fout);
666
667     return EXIT_SUCCESS;
668
669 fails:
670     if (dirptr) {
671         if (dirptr->filename) {
672             free(dirptr->filename);
673         }
674         if (dirptr->filename_buf) {
675             free(dirptr->filename_buf);
676         }
677         free(dirptr);
678     }
679     return EXIT_FAILURE;
680 }