X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fbin%2Fjp2%2Fopj_decompress.c;h=f3b1cd5c9a3569ef39b4ed5d18f195f60a674396;hb=74e814358c2530d238e3ada22d8eee6bf1d65283;hp=1164f0619e2aa5f4d78e72a7f0426bb62c04bbf2;hpb=8d93eae64acd18fac3c856e0a311905359233b96;p=openjpeg.git diff --git a/src/bin/jp2/opj_decompress.c b/src/bin/jp2/opj_decompress.c index 1164f061..f3b1cd5c 100644 --- a/src/bin/jp2/opj_decompress.c +++ b/src/bin/jp2/opj_decompress.c @@ -56,6 +56,9 @@ #define strncasecmp _strnicmp #else #include +#include +#include +#include #endif /* _WIN32 */ #include "openjpeg.h" @@ -72,6 +75,7 @@ #include "color.h" #include "format_defs.h" +#include "opj_string.h" typedef struct dircnt{ /** Buffer for holding images read from Directory*/ @@ -93,78 +97,143 @@ typedef struct img_folder{ }img_fol_t; +typedef enum opj_prec_mode +{ + OPJ_PREC_MODE_CLIP, + OPJ_PREC_MODE_SCALE +} opj_precision_mode; + +typedef struct opj_prec +{ + OPJ_UINT32 prec; + opj_precision_mode mode; +}opj_precision; + +typedef struct opj_decompress_params +{ + /** core library parameters */ + opj_dparameters_t core; + + /** input file name */ + char infile[OPJ_PATH_LEN]; + /** output file name */ + char outfile[OPJ_PATH_LEN]; + /** input file format 0: J2K, 1: JP2, 2: JPT */ + int decod_format; + /** output file format 0: PGX, 1: PxM, 2: BMP */ + int cod_format; + /** index file name */ + char indexfilename[OPJ_PATH_LEN]; + + /** Decoding area left boundary */ + OPJ_UINT32 DA_x0; + /** Decoding area right boundary */ + OPJ_UINT32 DA_x1; + /** Decoding area up boundary */ + OPJ_UINT32 DA_y0; + /** Decoding area bottom boundary */ + OPJ_UINT32 DA_y1; + /** Verbose mode */ + OPJ_BOOL m_verbose; + + /** tile number ot the decoded tile*/ + OPJ_UINT32 tile_index; + /** Nb of tile to decode */ + OPJ_UINT32 nb_tile_to_decode; + + opj_precision* precision; + OPJ_UINT32 nb_precision; + + /* force output colorspace to RGB */ + int force_rgb; + /* upsample components according to their dx/dy values */ + int upsample; + /* split output components to different files */ + int split_pnm; +}opj_decompress_parameters; + /* -------------------------------------------------------------------------- */ /* Declarations */ int get_num_images(char *imgdirpath); int load_images(dircnt_t *dirptr, char *imgdirpath); int get_file_format(const char *filename); -char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_dparameters_t *parameters); +char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_decompress_parameters *parameters); static int infile_format(const char *fname); -int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,img_fol_t *img_fol, char *indexfilename); +int parse_cmdline_decoder(int argc, char **argv, opj_decompress_parameters *parameters,img_fol_t *img_fol); int parse_DA_values( char* inArg, unsigned int *DA_x0, unsigned int *DA_y0, unsigned int *DA_x1, unsigned int *DA_y1); +static opj_image_t* convert_gray_to_rgb(opj_image_t* original); + /* -------------------------------------------------------------------------- */ static void decode_help_display(void) { - fprintf(stdout,"HELP for opj_decompress\n----\n\n"); - fprintf(stdout,"- the -h option displays this help information on screen\n\n"); - + fprintf(stdout,"\nThis is the opj_decompress utility from the OpenJPEG project.\n" + "It decompresses JPEG 2000 codestreams to various image formats.\n" + "It has been compiled against openjp2 library v%s.\n\n",opj_version()); + + fprintf(stdout,"Parameters:\n" + "-----------\n" + "\n" + " -ImgDir \n" + " Image file Directory path \n" + " -OutFor \n" + " REQUIRED only if -ImgDir is used\n" + " Output format for decompressed images.\n"); + fprintf(stdout," -i \n" + " REQUIRED only if an Input image directory is not specified\n" + " Currently accepts J2K-files, JP2-files and JPT-files. The file type\n" + " is identified based on its suffix.\n"); + fprintf(stdout," -o \n" + " REQUIRED\n" + " Currently accepts formats specified above (see OutFor option)\n" + " Binary data is written to the file (not ascii). If a PGX\n" + " filename is given, there will be as many output files as there are\n" + " components: an indice starting from 0 will then be appended to the\n" + " output filename, just before the \"pgx\" extension. If a PGM filename\n" + " is given and there are more than one component, only the first component\n" + " will be written to the file.\n"); + fprintf(stdout," -r \n" + " Set the number of highest resolution levels to be discarded. The\n" + " image resolution is effectively divided by 2 to the power of the\n" + " number of discarded levels. The reduce factor is limited by the\n" + " smallest total number of decomposition levels among tiles.\n" + " -l \n" + " Set the maximum number of quality layers to decode. If there are\n" + " less quality layers than the specified number, all the quality layers\n" + " are decoded.\n"); + fprintf(stdout," -x \n" + " Create an index file *.Idx (-x index_name.Idx) \n" + " -d \n" + " OPTIONAL\n" + " Decoding area\n" + " By default all the image is decoded.\n" + " -t \n" + " OPTIONAL\n" + " Set the tile number of the decoded tile. Follow the JPEG2000 convention from left-up to bottom-up\n" + " By default all tiles are decoded.\n"); + fprintf(stdout," -p [C|S][,[C|S][,...]]\n" + " OPTIONAL\n" + " Force the precision (bit depth) of components.\n"); + fprintf(stdout," There shall be at least 1 value. Theres no limit on the number of values (comma separated, last values ignored if too much values).\n" + " If there are less values than components, the last value is used for remaining components.\n" + " If 'C' is specified (default), values are clipped.\n" + " If 'S' is specified, values are scaled.\n" + " A 0 value can be specified (meaning original bit depth).\n"); + fprintf(stdout," -force-rgb\n" + " Force output image colorspace to RGB\n" + " -upsample\n" + " Downsampled components will be upsampled to image size\n" + " -split-pnm\n" + " Split output components to different files when writing to PNM\n" + "\n"); /* UniPG>> */ - fprintf(stdout,"List of parameters for the JPEG 2000 " #ifdef USE_JPWL - "+ JPWL " -#endif /* USE_JPWL */ - "decoder:\n"); -/* < \n"); - fprintf(stdout," Currently accepts PGM, PPM, PNM, PGX, PNG, BMP, TIF, RAW and TGA formats\n"); - fprintf(stdout," -i \n"); - fprintf(stdout," REQUIRED only if an Input image directory not specified\n"); - fprintf(stdout," Currently accepts J2K-files, JP2-files and JPT-files. The file type\n"); - fprintf(stdout," is identified based on its suffix.\n"); - fprintf(stdout," -o \n"); - fprintf(stdout," REQUIRED\n"); - fprintf(stdout," Currently accepts PGM, PPM, PNM, PGX, PNG, BMP, TIF, RAW and TGA files\n"); - fprintf(stdout," Binary data is written to the file (not ascii). If a PGX\n"); - fprintf(stdout," filename is given, there will be as many output files as there are\n"); - fprintf(stdout," components: an indice starting from 0 will then be appended to the\n"); - fprintf(stdout," output filename, just before the \"pgx\" extension. If a PGM filename\n"); - fprintf(stdout," is given and there are more than one component, only the first component\n"); - fprintf(stdout," will be written to the file.\n"); - fprintf(stdout," -r \n"); - fprintf(stdout," Set the number of highest resolution levels to be discarded. The\n"); - fprintf(stdout," image resolution is effectively divided by 2 to the power of the\n"); - fprintf(stdout," number of discarded levels. The reduce factor is limited by the\n"); - fprintf(stdout," smallest total number of decomposition levels among tiles.\n"); - fprintf(stdout," -l \n"); - fprintf(stdout," Set the maximum number of quality layers to decode. If there are\n"); - fprintf(stdout," less quality layers than the specified number, all the quality layers\n"); - fprintf(stdout," are decoded.\n"); - fprintf(stdout," -x \n"); - fprintf(stdout," Create an index file *.Idx (-x index_name.Idx) \n"); - fprintf(stdout," -d \n"); - fprintf(stdout," OPTIONAL\n"); - fprintf(stdout," Decoding area\n"); - fprintf(stdout," By default all the image is decoded.\n"); - fprintf(stdout," -t \n"); - fprintf(stdout," OPTIONAL\n"); - fprintf(stdout," Set the tile number of the decoded tile. Follow the JPEG2000 convention from left-up to bottom-up\n"); - fprintf(stdout," By default all tiles are decoded.\n"); - fprintf(stdout,"\n"); -/* UniPG>> */ -#ifdef USE_JPWL - fprintf(stdout," -W \n"); - fprintf(stdout," Activates the JPWL correction capability, if the codestream complies.\n"); - fprintf(stdout," Options can be a comma separated list of tokens:\n"); - fprintf(stdout," c, c=numcomps\n"); - fprintf(stdout," numcomps is the number of expected components in the codestream\n"); - fprintf(stdout," (search of first EPB rely upon this, default is %d)\n", JPWL_EXPECTED_COMPONENTS); + fprintf(stdout," -W \n" + " Activates the JPWL correction capability, if the codestream complies.\n" + " Options can be a comma separated list of tokens:\n" + " c, c=numcomps\n" + " numcomps is the number of expected components in the codestream\n" + " (search of first EPB rely upon this, default is %d)\n", JPWL_EXPECTED_COMPONENTS); #endif /* USE_JPWL */ /* <precision) { + free(parameters->precision); + parameters->precision = NULL; + } + parameters->nb_precision = 0U; + + for(;;) + { + int prec; + char mode; + char comma; + int count; + + count = sscanf(l_remaining, "%d%c%c", &prec, &mode, &comma); + if (count == 1) { + mode = 'C'; + count++; + } + if ((count == 2) || (mode==',')) { + if (mode==',') { + mode = 'C'; + } + comma=','; + count = 3; + } + if (count == 3) { + if ((prec < 1) || (prec > 32)) { + fprintf(stderr,"Invalid precision %d in precision option %s\n", prec, option); + l_result = OPJ_FALSE; + break; + } + if ((mode != 'C') && (mode != 'S')) { + fprintf(stderr,"Invalid precision mode %c in precision option %s\n", mode, option); + l_result = OPJ_FALSE; + break; + } + if (comma != ',') { + fprintf(stderr,"Invalid character %c in precision option %s\n", comma, option); + l_result = OPJ_FALSE; + break; + } + + if (parameters->precision == NULL) { + /* first one */ + parameters->precision = (opj_precision *)malloc(sizeof(opj_precision)); + if (parameters->precision == NULL) { + fprintf(stderr,"Could not allocate memory for precision option\n"); + l_result = OPJ_FALSE; + break; + } + } else { + OPJ_UINT32 l_new_size = parameters->nb_precision + 1U; + opj_precision* l_new; + + if (l_new_size == 0U) { + fprintf(stderr,"Could not allocate memory for precision option\n"); + l_result = OPJ_FALSE; + break; + } + + l_new = (opj_precision *)realloc(parameters->precision, l_new_size * sizeof(opj_precision)); + if (l_new == NULL) { + fprintf(stderr,"Could not allocate memory for precision option\n"); + l_result = OPJ_FALSE; + break; + } + parameters->precision = l_new; + } + + parameters->precision[parameters->nb_precision].prec = (OPJ_UINT32)prec; + switch (mode) { + case 'C': + parameters->precision[parameters->nb_precision].mode = OPJ_PREC_MODE_CLIP; + break; + case 'S': + parameters->precision[parameters->nb_precision].mode = OPJ_PREC_MODE_SCALE; + break; + default: + break; + } + parameters->nb_precision++; + + l_remaining = strchr(l_remaining, ','); + if (l_remaining == NULL) { + break; + } + l_remaining += 1; + } else { + fprintf(stderr,"Could not parse precision option %s\n", option); + l_result = OPJ_FALSE; + break; + } + } + + return l_result; +} + +/* -------------------------------------------------------------------------- */ + int get_num_images(char *imgdirpath){ DIR *dir; struct dirent* content; @@ -190,6 +364,7 @@ int get_num_images(char *imgdirpath){ continue; num_images++; } + closedir(dir); return num_images; } @@ -216,6 +391,7 @@ int load_images(dircnt_t *dirptr, char *imgdirpath){ strcpy(dirptr->filename[i],content->d_name); i++; } + closedir(dir); return 0; } @@ -224,7 +400,7 @@ int get_file_format(const char *filename) { unsigned int i; static const char *extension[] = {"pgx", "pnm", "pgm", "ppm", "bmp","tif", "raw", "rawl", "tga", "png", "j2k", "jp2", "jpt", "j2c", "jpc" }; static const int format[] = { PGX_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, BMP_DFMT, TIF_DFMT, RAW_DFMT, RAWL_DFMT, TGA_DFMT, PNG_DFMT, J2K_CFMT, JP2_CFMT, JPT_CFMT, J2K_CFMT, J2K_CFMT }; - char * ext = strrchr(filename, '.'); + const char * ext = strrchr(filename, '.'); if (ext == NULL) return -1; ext++; @@ -239,18 +415,26 @@ int get_file_format(const char *filename) { return -1; } +#ifdef _WIN32 +const char* path_separator = "\\"; +#else +const char* path_separator = "/"; +#endif + /* -------------------------------------------------------------------------- */ -char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_dparameters_t *parameters){ +char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_decompress_parameters *parameters){ char image_filename[OPJ_PATH_LEN], infilename[OPJ_PATH_LEN],outfilename[OPJ_PATH_LEN],temp_ofname[OPJ_PATH_LEN]; char *temp_p, temp1[OPJ_PATH_LEN]=""; strcpy(image_filename,dirptr->filename[imageno]); fprintf(stderr,"File Number %d \"%s\"\n",imageno,image_filename); - parameters->decod_format = infile_format(image_filename); + sprintf(infilename, "%s%s%s", img_fol->imgdirpath, path_separator, image_filename); + parameters->decod_format = infile_format(infilename); if (parameters->decod_format == -1) return 1; - sprintf(infilename,"%s/%s",img_fol->imgdirpath,image_filename); - strncpy(parameters->infile, infilename, sizeof(infilename)); + if (opj_strcpy_s(parameters->infile, sizeof(parameters->infile), infilename) != 0) { + return 1; + } /*Set output file*/ strcpy(temp_ofname,strtok(image_filename,".")); @@ -260,7 +444,9 @@ char get_next_file(int imageno,dircnt_t *dirptr,img_fol_t *img_fol, opj_dparamet } if(img_fol->set_out_format==1){ sprintf(outfilename,"%s/%s.%s",img_fol->imgdirpath,temp_ofname,img_fol->out_format); - strncpy(parameters->outfile, outfilename, sizeof(outfilename)); + if (opj_strcpy_s(parameters->outfile, sizeof(parameters->outfile), outfilename) != 0) { + return 1; + } } return 0; } @@ -326,30 +512,39 @@ static int infile_format(const char *fname) * Parse the command line */ /* -------------------------------------------------------------------------- */ -int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,img_fol_t *img_fol, char *indexfilename) { +int parse_cmdline_decoder(int argc, char **argv, opj_decompress_parameters *parameters,img_fol_t *img_fol) { /* parse the command line */ int totlen, c; opj_option_t long_option[]={ - {"ImgDir",REQ_ARG, NULL ,'y'}, - {"OutFor",REQ_ARG, NULL ,'O'}, - {"version",NO_ARG, NULL ,'v'} + {"ImgDir", REQ_ARG, NULL,'y'}, + {"OutFor", REQ_ARG, NULL,'O'}, + {"force-rgb", NO_ARG, NULL, 1}, + {"upsample", NO_ARG, NULL, 1}, + {"split-pnm", NO_ARG, NULL, 1} }; - const char optlist[] = "i:o:r:l:x:d:t:" + const char optlist[] = "i:o:r:l:x:d:t:p:" /* UniPG>> */ #ifdef USE_JPWL "W:" #endif /* USE_JPWL */ /* <force_rgb); + long_option[3].flag = &(parameters->upsample); + long_option[4].flag = &(parameters->split_pnm); totlen=sizeof(long_option); + opj_reset_options_reading(); img_fol->set_out_format = 0; do { c = opj_getopt_long(argc, argv,optlist,long_option,totlen); if (c == -1) break; switch (c) { + case 0: /* long opt with flag */ + break; case 'i': /* input file */ { char *infile = opj_optarg; @@ -373,7 +568,10 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i infile); return 1; } - strncpy(parameters->infile, infile, sizeof(parameters->infile)-1); + if (opj_strcpy_s(parameters->infile, sizeof(parameters->infile), infile) != 0) { + fprintf(stderr, "[ERROR] Path is too long\n"); + return 1; + } } break; @@ -401,10 +599,13 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i case PNG_DFMT: break; default: - fprintf(stderr, "Unknown output format image %s [only *.pnm, *.pgm, *.ppm, *.pgx, *.bmp, *.tif, *.raw or *.tga]!! \n", outfile); + fprintf(stderr, "Unknown output format image %s [only *.png, *.pnm, *.pgm, *.ppm, *.pgx, *.bmp, *.tif, *.raw or *.tga]!!\n", outfile); return 1; } - strncpy(parameters->outfile, outfile, sizeof(parameters->outfile)-1); + if (opj_strcpy_s(parameters->outfile, sizeof(parameters->outfile), outfile) != 0) { + fprintf(stderr, "[ERROR] Path is too long\n"); + return 1; + } } break; @@ -443,7 +644,7 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i img_fol->out_format = "png"; break; default: - fprintf(stderr, "Unknown output format image %s [only *.pnm, *.pgm, *.ppm, *.pgx, *.bmp, *.tif, *.raw or *.tga]!! \n", outformat); + fprintf(stderr, "Unknown output format image %s [only *.png, *.pnm, *.pgm, *.ppm, *.pgx, *.bmp, *.tif, *.raw or *.tga]!!\n", outformat); return 1; break; } @@ -455,7 +656,7 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i case 'r': /* reduce option */ { - sscanf(opj_optarg, "%ud", ¶meters->cp_reduce); + sscanf(opj_optarg, "%u", &(parameters->core.cp_reduce)); } break; @@ -464,7 +665,7 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i case 'l': /* layering option */ { - sscanf(opj_optarg, "%ud", ¶meters->cp_layer); + sscanf(opj_optarg, "%u", &(parameters->core.cp_layer)); } break; @@ -474,13 +675,6 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i decode_help_display(); return 1; - /* ------------------------------------------------------ */ - - case 'v': /* display the openjpeg library version in use */ - fprintf(stdout,"This is the opj_decompress utility from the OpenJPEG project.\n" - "It has been compiled against openjp2 library v%s.\n",opj_version()); - return 1; - /* ----------------------------------------------------- */ case 'y': /* Image Directory path */ @@ -495,11 +689,14 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i case 'd': /* Input decode ROI */ { - int size_optarg = (int)strlen(opj_optarg) + 1; - char *ROI_values = (char*) malloc((size_t)size_optarg); + size_t size_optarg = (size_t)strlen(opj_optarg) + 1U; + char *ROI_values = (char*) malloc(size_optarg); + if (ROI_values == NULL) { + fprintf(stderr, "[ERROR] Couldn't allocate memory\n"); + return 1; + } ROI_values[0] = '\0'; - strncpy(ROI_values, opj_optarg, strlen(opj_optarg)); - ROI_values[strlen(opj_optarg)] = '\0'; + memcpy(ROI_values, opj_optarg, size_optarg); /*printf("ROI_values = %s [%d / %d]\n", ROI_values, strlen(ROI_values), size_optarg ); */ parse_DA_values( ROI_values, ¶meters->DA_x0, ¶meters->DA_y0, ¶meters->DA_x1, ¶meters->DA_y1); @@ -511,7 +708,7 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i case 't': /* Input tile index */ { - sscanf(opj_optarg, "%ud", ¶meters->tile_index); + sscanf(opj_optarg, "%u", ¶meters->tile_index); parameters->nb_tile_to_decode = 1; } break; @@ -520,11 +717,24 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i case 'x': /* Creation of index file */ { - char *index = opj_optarg; - strncpy(indexfilename, index, OPJ_PATH_LEN); + if (opj_strcpy_s(parameters->indexfilename, sizeof(parameters->indexfilename), opj_optarg) != 0) { + fprintf(stderr, "[ERROR] Path is too long\n"); + return 1; + } } break; + /* ----------------------------------------------------- */ + case 'p': /* Force precision */ + { + if (!parse_precision(opj_optarg, parameters)) + { + return 1; + } + } + break; + /* ----------------------------------------------------- */ + /* UniPG>> */ #ifdef USE_JPWL @@ -599,7 +809,7 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i /* ----------------------------------------------------- */ default: - fprintf(stderr, "[WARNING] An invalid option has been ignored\n"); + fprintf(stderr, "[WARNING] An invalid option has been ignored.\n"); break; } }while(c != -1); @@ -607,16 +817,17 @@ int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters,i /* check for possible errors */ if(img_fol->set_imgdir==1){ if(!(parameters->infile[0]==0)){ - fprintf(stderr, "[ERROR] options -ImgDir and -i cannot be used together !!\n"); + fprintf(stderr, "[ERROR] options -ImgDir and -i cannot be used together.\n"); return 1; } if(img_fol->set_out_format == 0){ - fprintf(stderr, "[ERROR] When -ImgDir is used, -OutFor must be used !!\n"); - fprintf(stderr, "Only one format allowed! Valid format PGM, PPM, PNM, PGX, BMP, TIF, RAW and TGA!!\n"); + fprintf(stderr, "[ERROR] When -ImgDir is used, -OutFor must be used.\n"); + fprintf(stderr, "Only one format allowed.\n" + "Valid format are PGM, PPM, PNM, PGX, BMP, TIF, RAW and TGA.\n"); return 1; } if(!((parameters->outfile[0] == 0))){ - fprintf(stderr, "[ERROR] options -ImgDir and -o cannot be used together !!\n"); + fprintf(stderr, "[ERROR] options -ImgDir and -o cannot be used together.\n"); return 1; } }else{ @@ -661,6 +872,30 @@ int parse_DA_values( char* inArg, unsigned int *DA_x0, unsigned int *DA_y0, unsi } } +OPJ_FLOAT64 opj_clock(void) { +#ifdef _WIN32 + /* _WIN32: use QueryPerformance (very accurate) */ + LARGE_INTEGER freq , t ; + /* freq is the clock speed of the CPU */ + QueryPerformanceFrequency(&freq) ; + /* cout << "freq = " << ((double) freq.QuadPart) << endl; */ + /* t is the high resolution performance counter (see MSDN) */ + QueryPerformanceCounter ( & t ) ; + return freq.QuadPart ? (t.QuadPart / (OPJ_FLOAT64)freq.QuadPart) : 0; +#else + /* Unix or Linux: use resource usage */ + struct rusage t; + OPJ_FLOAT64 procTime; + /* (1) Get the rusage data structure at this moment (man getrusage) */ + getrusage(0,&t); + /* (2) What is the elapsed time ? - CPU time = User time + System time */ + /* (2a) Get the seconds */ + procTime = (OPJ_FLOAT64)(t.ru_utime.tv_sec + t.ru_stime.tv_sec); + /* (2b) More precisely! Get the microseconds part ! */ + return ( procTime + (OPJ_FLOAT64)(t.ru_utime.tv_usec + t.ru_stime.tv_usec) * 1e-6 ) ; +#endif +} + /* -------------------------------------------------------------------------- */ /** @@ -685,6 +920,258 @@ static void info_callback(const char *msg, void *client_data) { fprintf(stdout, "[INFO] %s", msg); } +static void set_default_parameters(opj_decompress_parameters* parameters) +{ + if (parameters) { + memset(parameters, 0, sizeof(opj_decompress_parameters)); + + /* default decoding parameters (command line specific) */ + parameters->decod_format = -1; + parameters->cod_format = -1; + + /* default decoding parameters (core) */ + opj_set_default_decoder_parameters(&(parameters->core)); + } +} + +static void destroy_parameters(opj_decompress_parameters* parameters) +{ + if (parameters) { + if (parameters->precision) { + free(parameters->precision); + parameters->precision = NULL; + } + } +} + +/* -------------------------------------------------------------------------- */ + +static opj_image_t* convert_gray_to_rgb(opj_image_t* original) +{ + OPJ_UINT32 compno; + opj_image_t* l_new_image = NULL; + opj_image_cmptparm_t* l_new_components = NULL; + + l_new_components = (opj_image_cmptparm_t*)malloc((original->numcomps + 2U) * sizeof(opj_image_cmptparm_t)); + if (l_new_components == NULL) { + fprintf(stderr, "ERROR -> opj_decompress: failed to allocate memory for RGB image!\n"); + opj_image_destroy(original); + return NULL; + } + + l_new_components[0].bpp = l_new_components[1].bpp = l_new_components[2].bpp = original->comps[0].bpp; + l_new_components[0].dx = l_new_components[1].dx = l_new_components[2].dx = original->comps[0].dx; + l_new_components[0].dy = l_new_components[1].dy = l_new_components[2].dy = original->comps[0].dy; + l_new_components[0].h = l_new_components[1].h = l_new_components[2].h = original->comps[0].h; + l_new_components[0].w = l_new_components[1].w = l_new_components[2].w = original->comps[0].w; + l_new_components[0].prec = l_new_components[1].prec = l_new_components[2].prec = original->comps[0].prec; + l_new_components[0].sgnd = l_new_components[1].sgnd = l_new_components[2].sgnd = original->comps[0].sgnd; + l_new_components[0].x0 = l_new_components[1].x0 = l_new_components[2].x0 = original->comps[0].x0; + l_new_components[0].y0 = l_new_components[1].y0 = l_new_components[2].y0 = original->comps[0].y0; + + for(compno = 1U; compno < original->numcomps; ++compno) { + l_new_components[compno+2U].bpp = original->comps[compno].bpp; + l_new_components[compno+2U].dx = original->comps[compno].dx; + l_new_components[compno+2U].dy = original->comps[compno].dy; + l_new_components[compno+2U].h = original->comps[compno].h; + l_new_components[compno+2U].w = original->comps[compno].w; + l_new_components[compno+2U].prec = original->comps[compno].prec; + l_new_components[compno+2U].sgnd = original->comps[compno].sgnd; + l_new_components[compno+2U].x0 = original->comps[compno].x0; + l_new_components[compno+2U].y0 = original->comps[compno].y0; + } + + l_new_image = opj_image_create(original->numcomps + 2U, l_new_components, OPJ_CLRSPC_SRGB); + free(l_new_components); + if (l_new_image == NULL) { + fprintf(stderr, "ERROR -> opj_decompress: failed to allocate memory for RGB image!\n"); + opj_image_destroy(original); + return NULL; + } + + l_new_image->x0 = original->x0; + l_new_image->x1 = original->x1; + l_new_image->y0 = original->y0; + l_new_image->y1 = original->y1; + + l_new_image->comps[0].factor = l_new_image->comps[1].factor = l_new_image->comps[2].factor = original->comps[0].factor; + l_new_image->comps[0].alpha = l_new_image->comps[1].alpha = l_new_image->comps[2].alpha = original->comps[0].alpha; + l_new_image->comps[0].resno_decoded = l_new_image->comps[1].resno_decoded = l_new_image->comps[2].resno_decoded = original->comps[0].resno_decoded; + + memcpy(l_new_image->comps[0].data, original->comps[0].data, original->comps[0].w * original->comps[0].h * sizeof(OPJ_INT32)); + memcpy(l_new_image->comps[1].data, original->comps[0].data, original->comps[0].w * original->comps[0].h * sizeof(OPJ_INT32)); + memcpy(l_new_image->comps[2].data, original->comps[0].data, original->comps[0].w * original->comps[0].h * sizeof(OPJ_INT32)); + + for(compno = 1U; compno < original->numcomps; ++compno) { + l_new_image->comps[compno+2U].factor = original->comps[compno].factor; + l_new_image->comps[compno+2U].alpha = original->comps[compno].alpha; + l_new_image->comps[compno+2U].resno_decoded = original->comps[compno].resno_decoded; + memcpy(l_new_image->comps[compno+2U].data, original->comps[compno].data, original->comps[compno].w * original->comps[compno].h * sizeof(OPJ_INT32)); + } + opj_image_destroy(original); + return l_new_image; +} + +/* -------------------------------------------------------------------------- */ + +static opj_image_t* upsample_image_components(opj_image_t* original) +{ + opj_image_t* l_new_image = NULL; + opj_image_cmptparm_t* l_new_components = NULL; + OPJ_BOOL l_upsample_need = OPJ_FALSE; + OPJ_UINT32 compno; + + for (compno = 0U; compno < original->numcomps; ++compno) { + if (original->comps[compno].factor > 0U) { + fprintf(stderr, "ERROR -> opj_decompress: -upsample not supported with reduction\n"); + opj_image_destroy(original); + return NULL; + } + if ((original->comps[compno].dx > 1U) || (original->comps[compno].dy > 1U)) { + l_upsample_need = OPJ_TRUE; + break; + } + } + if (!l_upsample_need) { + return original; + } + /* Upsample is needed */ + l_new_components = (opj_image_cmptparm_t*)malloc(original->numcomps * sizeof(opj_image_cmptparm_t)); + if (l_new_components == NULL) { + fprintf(stderr, "ERROR -> opj_decompress: failed to allocate memory for upsampled components!\n"); + opj_image_destroy(original); + return NULL; + } + + for (compno = 0U; compno < original->numcomps; ++compno) { + opj_image_cmptparm_t* l_new_cmp = &(l_new_components[compno]); + opj_image_comp_t* l_org_cmp = &(original->comps[compno]); + + l_new_cmp->bpp = l_org_cmp->bpp; + l_new_cmp->prec = l_org_cmp->prec; + l_new_cmp->sgnd = l_org_cmp->sgnd; + l_new_cmp->x0 = original->x0; + l_new_cmp->y0 = original->y0; + l_new_cmp->dx = 1; + l_new_cmp->dy = 1; + l_new_cmp->w = l_org_cmp->w; /* should be original->x1 - original->x0 for dx==1 */ + l_new_cmp->h = l_org_cmp->h; /* should be original->y1 - original->y0 for dy==0 */ + + if (l_org_cmp->dx > 1U) { + l_new_cmp->w = original->x1 - original->x0; + } + + if (l_org_cmp->dy > 1U) { + l_new_cmp->h = original->y1 - original->y0; + } + } + + l_new_image = opj_image_create(original->numcomps, l_new_components, original->color_space); + free(l_new_components); + if (l_new_image == NULL) { + fprintf(stderr, "ERROR -> opj_decompress: failed to allocate memory for upsampled components!\n"); + opj_image_destroy(original); + return NULL; + } + + l_new_image->x0 = original->x0; + l_new_image->x1 = original->x1; + l_new_image->y0 = original->y0; + l_new_image->y1 = original->y1; + + for (compno = 0U; compno < original->numcomps; ++compno) { + opj_image_comp_t* l_new_cmp = &(l_new_image->comps[compno]); + opj_image_comp_t* l_org_cmp = &(original->comps[compno]); + + l_new_cmp->factor = l_org_cmp->factor; + l_new_cmp->alpha = l_org_cmp->alpha; + l_new_cmp->resno_decoded = l_org_cmp->resno_decoded; + + if ((l_org_cmp->dx > 1U) || (l_org_cmp->dy > 1U)) { + const OPJ_INT32* l_src = l_org_cmp->data; + OPJ_INT32* l_dst = l_new_cmp->data; + OPJ_UINT32 y; + OPJ_UINT32 xoff, yoff; + + /* need to take into account dx & dy */ + xoff = l_org_cmp->dx * l_org_cmp->x0 - original->x0; + yoff = l_org_cmp->dy * l_org_cmp->y0 - original->y0; + if ((xoff >= l_org_cmp->dx) || (yoff >= l_org_cmp->dy)) { + fprintf(stderr, "ERROR -> opj_decompress: Invalid image/component parameters found when upsampling\n"); + opj_image_destroy(original); + opj_image_destroy(l_new_image); + return NULL; + } + + for (y = 0U; y < yoff; ++y) { + memset(l_dst, 0U, l_new_cmp->w * sizeof(OPJ_INT32)); + l_dst += l_new_cmp->w; + } + + if(l_new_cmp->h > (l_org_cmp->dy - 1U)) { /* check subtraction overflow for really small images */ + for (; y < l_new_cmp->h - (l_org_cmp->dy - 1U); y += l_org_cmp->dy) { + OPJ_UINT32 x, dy; + OPJ_UINT32 xorg; + + xorg = 0U; + for (x = 0U; x < xoff; ++x) { + l_dst[x] = 0; + } + if (l_new_cmp->w > (l_org_cmp->dx - 1U)) { /* check subtraction overflow for really small images */ + for (; x < l_new_cmp->w - (l_org_cmp->dx - 1U); x += l_org_cmp->dx, ++xorg) { + OPJ_UINT32 dx; + for (dx = 0U; dx < l_org_cmp->dx; ++dx) { + l_dst[x + dx] = l_src[xorg]; + } + } + } + for (; x < l_new_cmp->w; ++x) { + l_dst[x] = l_src[xorg]; + } + l_dst += l_new_cmp->w; + + for (dy = 1U; dy < l_org_cmp->dy; ++dy) { + memcpy(l_dst, l_dst - l_new_cmp->w, l_new_cmp->w * sizeof(OPJ_INT32)); + l_dst += l_new_cmp->w; + } + l_src += l_org_cmp->w; + } + } + if (y < l_new_cmp->h) { + OPJ_UINT32 x; + OPJ_UINT32 xorg; + + xorg = 0U; + for (x = 0U; x < xoff; ++x) { + l_dst[x] = 0; + } + if (l_new_cmp->w > (l_org_cmp->dx - 1U)) { /* check subtraction overflow for really small images */ + for (; x < l_new_cmp->w - (l_org_cmp->dx - 1U); x += l_org_cmp->dx, ++xorg) { + OPJ_UINT32 dx; + for (dx = 0U; dx < l_org_cmp->dx; ++dx) { + l_dst[x + dx] = l_src[xorg]; + } + } + } + for (; x < l_new_cmp->w; ++x) { + l_dst[x] = l_src[xorg]; + } + l_dst += l_new_cmp->w; + ++y; + for (; y < l_new_cmp->h; ++y) { + memcpy(l_dst, l_dst - l_new_cmp->w, l_new_cmp->w * sizeof(OPJ_INT32)); + l_dst += l_new_cmp->w; + } + } + } + else { + memcpy(l_new_cmp->data, l_org_cmp->data, l_org_cmp->w * l_org_cmp->h * sizeof(OPJ_INT32)); + } + } + opj_image_destroy(original); + return l_new_image; +} + /* -------------------------------------------------------------------------- */ /** * OPJ_DECOMPRESS MAIN @@ -692,30 +1179,28 @@ static void info_callback(const char *msg, void *client_data) { /* -------------------------------------------------------------------------- */ int main(int argc, char **argv) { - opj_dparameters_t parameters; /* decompression parameters */ + opj_decompress_parameters parameters; /* decompression parameters */ opj_image_t* image = NULL; opj_stream_t *l_stream = NULL; /* Stream */ opj_codec_t* l_codec = NULL; /* Handle to a decompressor */ opj_codestream_index_t* cstr_index = NULL; - char indexfilename[OPJ_PATH_LEN]; /* index file name */ - OPJ_INT32 num_images, imageno; img_fol_t img_fol; dircnt_t *dirptr = NULL; int failed = 0; + OPJ_FLOAT64 t, tCumulative = 0; + OPJ_UINT32 numDecompressedImages = 0; /* set decoding parameters to default values */ - opj_set_default_decoder_parameters(¶meters); - - /* FIXME Initialize indexfilename and img_fol */ - *indexfilename = 0; + set_default_parameters(¶meters); /* Initialize img_fol */ memset(&img_fol,0,sizeof(img_fol_t)); /* parse input and get user encoding parameters */ - if(parse_cmdline_decoder(argc, argv, ¶meters,&img_fol, indexfilename) == 1) { + if(parse_cmdline_decoder(argc, argv, ¶meters,&img_fol) == 1) { + destroy_parameters(¶meters); return EXIT_FAILURE; } @@ -730,6 +1215,7 @@ int main(int argc, char **argv) dirptr->filename = (char**) malloc((size_t)num_images*sizeof(char*)); if(!dirptr->filename_buf){ + destroy_parameters(¶meters); return EXIT_FAILURE; } for(it_image=0;it_image failed to create the stream from the file %s\n", parameters.infile); + destroy_parameters(¶meters); return EXIT_FAILURE; } @@ -792,7 +1282,8 @@ int main(int argc, char **argv) } default: fprintf(stderr, "skipping file..\n"); - opj_stream_destroy_v3(l_stream); + destroy_parameters(¶meters); + opj_stream_destroy(l_stream); continue; } @@ -801,10 +1292,13 @@ int main(int argc, char **argv) opj_set_warning_handler(l_codec, warning_callback,00); opj_set_error_handler(l_codec, error_callback,00); + t = opj_clock(); + /* Setup the decoder decoding parameters using user parameters */ - if ( !opj_setup_decoder(l_codec, ¶meters) ){ - fprintf(stderr, "ERROR -> opj_compress: failed to setup the decoder\n"); - opj_stream_destroy_v3(l_stream); + if ( !opj_setup_decoder(l_codec, &(parameters.core)) ){ + fprintf(stderr, "ERROR -> opj_decompress: failed to setup the decoder\n"); + destroy_parameters(¶meters); + opj_stream_destroy(l_stream); opj_destroy_codec(l_codec); return EXIT_FAILURE; } @@ -813,7 +1307,8 @@ int main(int argc, char **argv) /* Read the main header of the codestream and if necessary the JP2 boxes*/ if(! opj_read_header(l_stream, l_codec, &image)){ fprintf(stderr, "ERROR -> opj_decompress: failed to read the header\n"); - opj_stream_destroy_v3(l_stream); + destroy_parameters(¶meters); + opj_stream_destroy(l_stream); opj_destroy_codec(l_codec); opj_image_destroy(image); return EXIT_FAILURE; @@ -824,7 +1319,8 @@ int main(int argc, char **argv) if (!opj_set_decode_area(l_codec, image, (OPJ_INT32)parameters.DA_x0, (OPJ_INT32)parameters.DA_y0, (OPJ_INT32)parameters.DA_x1, (OPJ_INT32)parameters.DA_y1)){ fprintf(stderr, "ERROR -> opj_decompress: failed to set the decoded area\n"); - opj_stream_destroy_v3(l_stream); + destroy_parameters(¶meters); + opj_stream_destroy(l_stream); opj_destroy_codec(l_codec); opj_image_destroy(image); return EXIT_FAILURE; @@ -833,8 +1329,9 @@ int main(int argc, char **argv) /* Get the decoded image */ if (!(opj_decode(l_codec, l_stream, image) && opj_end_decompress(l_codec, l_stream))) { fprintf(stderr,"ERROR -> opj_decompress: failed to decode image!\n"); + destroy_parameters(¶meters); opj_destroy_codec(l_codec); - opj_stream_destroy_v3(l_stream); + opj_stream_destroy(l_stream); opj_image_destroy(image); return EXIT_FAILURE; } @@ -845,28 +1342,28 @@ int main(int argc, char **argv) /*if (!opj_set_decoded_resolution_factor(l_codec, 5)) { fprintf(stderr, "ERROR -> opj_decompress: failed to set the resolution factor tile!\n"); opj_destroy_codec(l_codec); - opj_stream_destroy_v3(l_stream); + opj_stream_destroy(l_stream); opj_image_destroy(image); return EXIT_FAILURE; }*/ if (!opj_get_decoded_tile(l_codec, l_stream, image, parameters.tile_index)) { fprintf(stderr, "ERROR -> opj_decompress: failed to decode tile!\n"); + destroy_parameters(¶meters); opj_destroy_codec(l_codec); - opj_stream_destroy_v3(l_stream); + opj_stream_destroy(l_stream); opj_image_destroy(image); return EXIT_FAILURE; } fprintf(stdout, "tile %d is decoded!\n\n", parameters.tile_index); } + tCumulative += opj_clock() - t; + numDecompressedImages++; + /* Close the byte stream */ - opj_stream_destroy_v3(l_stream); + opj_stream_destroy(l_stream); - if(image->color_space == OPJ_CLRSPC_SYCC){ - color_sycc_to_rgb(image); /* FIXME */ - } - if( image->color_space != OPJ_CLRSPC_SYCC && image->numcomps == 3 && image->comps[0].dx == image->comps[0].dy && image->comps[1].dx != 1 ) @@ -874,19 +1371,102 @@ int main(int argc, char **argv) else if (image->numcomps <= 2) image->color_space = OPJ_CLRSPC_GRAY; + if(image->color_space == OPJ_CLRSPC_SYCC){ + color_sycc_to_rgb(image); + } + else if((image->color_space == OPJ_CLRSPC_CMYK) && (parameters.cod_format != TIF_DFMT)){ + color_cmyk_to_rgb(image); + } + else if(image->color_space == OPJ_CLRSPC_EYCC){ + color_esycc_to_rgb(image); + } + if(image->icc_profile_buf) { #if defined(OPJ_HAVE_LIBLCMS1) || defined(OPJ_HAVE_LIBLCMS2) - color_apply_icc_profile(image); /* FIXME */ + if(image->icc_profile_len) + color_apply_icc_profile(image); + else + color_cielab_to_rgb(image); #endif free(image->icc_profile_buf); image->icc_profile_buf = NULL; image->icc_profile_len = 0; } + + /* Force output precision */ + /* ---------------------- */ + if (parameters.precision != NULL) + { + OPJ_UINT32 compno; + for (compno = 0; compno < image->numcomps; ++compno) + { + OPJ_UINT32 precno = compno; + OPJ_UINT32 prec; + + if (precno >= parameters.nb_precision) { + precno = parameters.nb_precision - 1U; + } + + prec = parameters.precision[precno].prec; + if (prec == 0) { + prec = image->comps[compno].prec; + } + + switch (parameters.precision[precno].mode) { + case OPJ_PREC_MODE_CLIP: + clip_component(&(image->comps[compno]), prec); + break; + case OPJ_PREC_MODE_SCALE: + scale_component(&(image->comps[compno]), prec); + break; + default: + break; + } + + } + } + + /* Upsample components */ + /* ------------------- */ + if (parameters.upsample) + { + image = upsample_image_components(image); + if (image == NULL) { + fprintf(stderr, "ERROR -> opj_decompress: failed to upsample image components!\n"); + destroy_parameters(¶meters); + opj_destroy_codec(l_codec); + return EXIT_FAILURE; + } + } + + /* Force RGB output */ + /* ---------------- */ + if (parameters.force_rgb) + { + switch (image->color_space) { + case OPJ_CLRSPC_SRGB: + break; + case OPJ_CLRSPC_GRAY: + image = convert_gray_to_rgb(image); + break; + default: + fprintf(stderr, "ERROR -> opj_decompress: don't know how to convert image to RGB colorspace!\n"); + opj_image_destroy(image); + image = NULL; + break; + } + if (image == NULL) { + fprintf(stderr, "ERROR -> opj_decompress: failed to convert to RGB image!\n"); + destroy_parameters(¶meters); + opj_destroy_codec(l_codec); + return EXIT_FAILURE; + } + } /* create output image */ /* ------------------- */ switch (parameters.cod_format) { case PXM_DFMT: /* PNM PGM PPM */ - if (imagetopnm(image, parameters.outfile)) { + if (imagetopnm(image, parameters.outfile, parameters.split_pnm)) { fprintf(stderr,"[ERROR] Outfile %s not generated\n",parameters.outfile); failed = 1; } @@ -985,11 +1565,12 @@ int main(int argc, char **argv) /* destroy the codestream index */ opj_destroy_cstr_index(&cstr_index); + if(failed) (void)remove(parameters.outfile); /* ignore return value */ + } + destroy_parameters(¶meters); + if (numDecompressedImages) { + fprintf(stdout, "decode time: %d ms\n", (int)( (tCumulative * 1000.0) / (OPJ_FLOAT64)numDecompressedImages)); } return failed ? EXIT_FAILURE : EXIT_SUCCESS; } /*end main*/ - - - -