diff options
Diffstat (limited to 'openjpeg/src')
143 files changed, 50079 insertions, 940 deletions
diff --git a/openjpeg/src/bin/CMakeLists.txt b/openjpeg/src/bin/CMakeLists.txt new file mode 100644 index 000000000..edf85feba --- /dev/null +++ b/openjpeg/src/bin/CMakeLists.txt @@ -0,0 +1,21 @@ +# source code for openjpeg apps: +add_subdirectory(common) +# Part 1 & 2: +add_subdirectory(jp2) + +# optionals components: +if(BUILD_JPWL) + add_subdirectory(jpwl) +endif() +if(BUILD_MJ2) + add_subdirectory(mj2) +endif() +if(BUILD_JPIP) + add_subdirectory(jpip) +endif() +if(BUILD_JP3D) + add_subdirectory(jp3d) +endif() + +# wx apps: +add_subdirectory(wx) diff --git a/openjpeg/src/bin/common/CMakeLists.txt b/openjpeg/src/bin/common/CMakeLists.txt new file mode 100644 index 000000000..017c23df3 --- /dev/null +++ b/openjpeg/src/bin/common/CMakeLists.txt @@ -0,0 +1,7 @@ +#----------------------------------------------------------------------------- +# opj_apps_config.h generation +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/opj_apps_config.h.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/opj_apps_config.h + @ONLY + ) diff --git a/openjpeg/src/bin/common/color.c b/openjpeg/src/bin/common/color.c new file mode 100644 index 000000000..a97d49f12 --- /dev/null +++ b/openjpeg/src/bin/common/color.c @@ -0,0 +1,1127 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * Copyright (c) 2003-2014, Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <math.h> +#include <assert.h> + +#include "opj_apps_config.h" +#include "openjpeg.h" +#include "color.h" + +#ifdef OPJ_HAVE_LIBLCMS2 +#include <lcms2.h> +#endif +#ifdef OPJ_HAVE_LIBLCMS1 +#include <lcms.h> +#endif + +#ifdef OPJ_USE_LEGACY +#define OPJ_CLRSPC_GRAY CLRSPC_GRAY +#define OPJ_CLRSPC_SRGB CLRSPC_SRGB +#endif + +/*-------------------------------------------------------- +Matrix for sYCC, Amendment 1 to IEC 61966-2-1 + +Y : 0.299 0.587 0.114 :R +Cb: -0.1687 -0.3312 0.5 :G +Cr: 0.5 -0.4187 -0.0812 :B + +Inverse: + +R: 1 -3.68213e-05 1.40199 :Y +G: 1.00003 -0.344125 -0.714128 :Cb - 2^(prec - 1) +B: 0.999823 1.77204 -8.04142e-06 :Cr - 2^(prec - 1) + +-----------------------------------------------------------*/ +static void sycc_to_rgb(int offset, int upb, int y, int cb, int cr, + int *out_r, int *out_g, int *out_b) +{ + int r, g, b; + + cb -= offset; + cr -= offset; + r = y + (int)(1.402 * (float)cr); + if (r < 0) { + r = 0; + } else if (r > upb) { + r = upb; + } + *out_r = r; + + g = y - (int)(0.344 * (float)cb + 0.714 * (float)cr); + if (g < 0) { + g = 0; + } else if (g > upb) { + g = upb; + } + *out_g = g; + + b = y + (int)(1.772 * (float)cb); + if (b < 0) { + b = 0; + } else if (b > upb) { + b = upb; + } + *out_b = b; +} + +static void sycc444_to_rgb(opj_image_t *img) +{ + int *d0, *d1, *d2, *r, *g, *b; + const int *y, *cb, *cr; + size_t maxw, maxh, max, i; + int offset, upb; + + upb = (int)img->comps[0].prec; + offset = 1 << (upb - 1); + upb = (1 << upb) - 1; + + maxw = (size_t)img->comps[0].w; + maxh = (size_t)img->comps[0].h; + max = maxw * maxh; + + y = img->comps[0].data; + cb = img->comps[1].data; + cr = img->comps[2].data; + + d0 = r = (int*)opj_image_data_alloc(sizeof(int) * max); + d1 = g = (int*)opj_image_data_alloc(sizeof(int) * max); + d2 = b = (int*)opj_image_data_alloc(sizeof(int) * max); + + if (r == NULL || g == NULL || b == NULL) { + goto fails; + } + + for (i = 0U; i < max; ++i) { + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + ++y; + ++cb; + ++cr; + ++r; + ++g; + ++b; + } + opj_image_data_free(img->comps[0].data); + img->comps[0].data = d0; + opj_image_data_free(img->comps[1].data); + img->comps[1].data = d1; + opj_image_data_free(img->comps[2].data); + img->comps[2].data = d2; + img->color_space = OPJ_CLRSPC_SRGB; + return; + +fails: + opj_image_data_free(r); + opj_image_data_free(g); + opj_image_data_free(b); +}/* sycc444_to_rgb() */ + +static void sycc422_to_rgb(opj_image_t *img) +{ + int *d0, *d1, *d2, *r, *g, *b; + const int *y, *cb, *cr; + size_t maxw, maxh, max, offx, loopmaxw; + int offset, upb; + size_t i; + + upb = (int)img->comps[0].prec; + offset = 1 << (upb - 1); + upb = (1 << upb) - 1; + + maxw = (size_t)img->comps[0].w; + maxh = (size_t)img->comps[0].h; + max = maxw * maxh; + + y = img->comps[0].data; + cb = img->comps[1].data; + cr = img->comps[2].data; + + d0 = r = (int*)opj_image_data_alloc(sizeof(int) * max); + d1 = g = (int*)opj_image_data_alloc(sizeof(int) * max); + d2 = b = (int*)opj_image_data_alloc(sizeof(int) * max); + + if (r == NULL || g == NULL || b == NULL) { + goto fails; + } + + /* if img->x0 is odd, then first column shall use Cb/Cr = 0 */ + offx = img->x0 & 1U; + loopmaxw = maxw - offx; + + for (i = 0U; i < maxh; ++i) { + size_t j; + + if (offx > 0U) { + sycc_to_rgb(offset, upb, *y, 0, 0, r, g, b); + ++y; + ++r; + ++g; + ++b; + } + + for (j = 0U; j < (loopmaxw & ~(size_t)1U); j += 2U) { + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + ++y; + ++r; + ++g; + ++b; + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + ++y; + ++r; + ++g; + ++b; + ++cb; + ++cr; + } + if (j < loopmaxw) { + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + ++y; + ++r; + ++g; + ++b; + ++cb; + ++cr; + } + } + + opj_image_data_free(img->comps[0].data); + img->comps[0].data = d0; + opj_image_data_free(img->comps[1].data); + img->comps[1].data = d1; + opj_image_data_free(img->comps[2].data); + img->comps[2].data = d2; + + img->comps[1].w = img->comps[2].w = img->comps[0].w; + img->comps[1].h = img->comps[2].h = img->comps[0].h; + img->comps[1].dx = img->comps[2].dx = img->comps[0].dx; + img->comps[1].dy = img->comps[2].dy = img->comps[0].dy; + img->color_space = OPJ_CLRSPC_SRGB; + return; + +fails: + opj_image_data_free(r); + opj_image_data_free(g); + opj_image_data_free(b); +}/* sycc422_to_rgb() */ + +static void sycc420_to_rgb(opj_image_t *img) +{ + int *d0, *d1, *d2, *r, *g, *b, *nr, *ng, *nb; + const int *y, *cb, *cr, *ny; + size_t maxw, maxh, max, offx, loopmaxw, offy, loopmaxh; + int offset, upb; + size_t i; + + upb = (int)img->comps[0].prec; + offset = 1 << (upb - 1); + upb = (1 << upb) - 1; + + maxw = (size_t)img->comps[0].w; + maxh = (size_t)img->comps[0].h; + max = maxw * maxh; + + y = img->comps[0].data; + cb = img->comps[1].data; + cr = img->comps[2].data; + + d0 = r = (int*)opj_image_data_alloc(sizeof(int) * max); + d1 = g = (int*)opj_image_data_alloc(sizeof(int) * max); + d2 = b = (int*)opj_image_data_alloc(sizeof(int) * max); + + if (r == NULL || g == NULL || b == NULL) { + goto fails; + } + + /* if img->x0 is odd, then first column shall use Cb/Cr = 0 */ + offx = img->x0 & 1U; + loopmaxw = maxw - offx; + /* if img->y0 is odd, then first line shall use Cb/Cr = 0 */ + offy = img->y0 & 1U; + loopmaxh = maxh - offy; + + if (offy > 0U) { + size_t j; + + for (j = 0; j < maxw; ++j) { + sycc_to_rgb(offset, upb, *y, 0, 0, r, g, b); + ++y; + ++r; + ++g; + ++b; + } + } + + for (i = 0U; i < (loopmaxh & ~(size_t)1U); i += 2U) { + size_t j; + + ny = y + maxw; + nr = r + maxw; + ng = g + maxw; + nb = b + maxw; + + if (offx > 0U) { + sycc_to_rgb(offset, upb, *y, 0, 0, r, g, b); + ++y; + ++r; + ++g; + ++b; + sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb); + ++ny; + ++nr; + ++ng; + ++nb; + } + + for (j = 0; j < (loopmaxw & ~(size_t)1U); j += 2U) { + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + ++y; + ++r; + ++g; + ++b; + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + ++y; + ++r; + ++g; + ++b; + + sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb); + ++ny; + ++nr; + ++ng; + ++nb; + sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb); + ++ny; + ++nr; + ++ng; + ++nb; + ++cb; + ++cr; + } + if (j < loopmaxw) { + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + ++y; + ++r; + ++g; + ++b; + + sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb); + ++ny; + ++nr; + ++ng; + ++nb; + ++cb; + ++cr; + } + y += maxw; + r += maxw; + g += maxw; + b += maxw; + } + if (i < loopmaxh) { + size_t j; + + for (j = 0U; j < (maxw & ~(size_t)1U); j += 2U) { + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + + ++y; + ++r; + ++g; + ++b; + + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + + ++y; + ++r; + ++g; + ++b; + ++cb; + ++cr; + } + if (j < maxw) { + sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b); + } + } + + opj_image_data_free(img->comps[0].data); + img->comps[0].data = d0; + opj_image_data_free(img->comps[1].data); + img->comps[1].data = d1; + opj_image_data_free(img->comps[2].data); + img->comps[2].data = d2; + + img->comps[1].w = img->comps[2].w = img->comps[0].w; + img->comps[1].h = img->comps[2].h = img->comps[0].h; + img->comps[1].dx = img->comps[2].dx = img->comps[0].dx; + img->comps[1].dy = img->comps[2].dy = img->comps[0].dy; + img->color_space = OPJ_CLRSPC_SRGB; + return; + +fails: + opj_image_data_free(r); + opj_image_data_free(g); + opj_image_data_free(b); +}/* sycc420_to_rgb() */ + +void color_sycc_to_rgb(opj_image_t *img) +{ + if (img->numcomps < 3) { + img->color_space = OPJ_CLRSPC_GRAY; + return; + } + + if ((img->comps[0].dx == 1) + && (img->comps[1].dx == 2) + && (img->comps[2].dx == 2) + && (img->comps[0].dy == 1) + && (img->comps[1].dy == 2) + && (img->comps[2].dy == 2)) { /* horizontal and vertical sub-sample */ + sycc420_to_rgb(img); + } else if ((img->comps[0].dx == 1) + && (img->comps[1].dx == 2) + && (img->comps[2].dx == 2) + && (img->comps[0].dy == 1) + && (img->comps[1].dy == 1) + && (img->comps[2].dy == 1)) { /* horizontal sub-sample only */ + sycc422_to_rgb(img); + } else if ((img->comps[0].dx == 1) + && (img->comps[1].dx == 1) + && (img->comps[2].dx == 1) + && (img->comps[0].dy == 1) + && (img->comps[1].dy == 1) + && (img->comps[2].dy == 1)) { /* no sub-sample */ + sycc444_to_rgb(img); + } else { + fprintf(stderr, "%s:%d:color_sycc_to_rgb\n\tCAN NOT CONVERT\n", __FILE__, + __LINE__); + return; + } +}/* color_sycc_to_rgb() */ + +#if defined(OPJ_HAVE_LIBLCMS2) || defined(OPJ_HAVE_LIBLCMS1) + +#ifdef OPJ_HAVE_LIBLCMS1 +/* Bob Friesenhahn proposed:*/ +#define cmsSigXYZData icSigXYZData +#define cmsSigLabData icSigLabData +#define cmsSigCmykData icSigCmykData +#define cmsSigYCbCrData icSigYCbCrData +#define cmsSigLuvData icSigLuvData +#define cmsSigGrayData icSigGrayData +#define cmsSigRgbData icSigRgbData +#define cmsUInt32Number DWORD + +#define cmsColorSpaceSignature icColorSpaceSignature +#define cmsGetHeaderRenderingIntent cmsTakeRenderingIntent + +#endif /* OPJ_HAVE_LIBLCMS1 */ + +/*#define DEBUG_PROFILE*/ +void color_apply_icc_profile(opj_image_t *image) +{ + cmsHPROFILE in_prof, out_prof; + cmsHTRANSFORM transform; + cmsColorSpaceSignature in_space, out_space; + cmsUInt32Number intent, in_type, out_type; + int *r, *g, *b; + size_t nr_samples, i, max, max_w, max_h; + int prec, ok = 0; + OPJ_COLOR_SPACE new_space; + + in_prof = cmsOpenProfileFromMem(image->icc_profile_buf, image->icc_profile_len); +#ifdef DEBUG_PROFILE + FILE *icm = fopen("debug.icm", "wb"); + fwrite(image->icc_profile_buf, 1, image->icc_profile_len, icm); + fclose(icm); +#endif + + if (in_prof == NULL) { + return; + } + + in_space = cmsGetPCS(in_prof); + out_space = cmsGetColorSpace(in_prof); + intent = cmsGetHeaderRenderingIntent(in_prof); + + + max_w = image->comps[0].w; + max_h = image->comps[0].h; + prec = (int)image->comps[0].prec; + + if (out_space == cmsSigRgbData) { /* enumCS 16 */ + unsigned int i, nr_comp = image->numcomps; + + if (nr_comp > 4) { + nr_comp = 4; + } + for (i = 1; i < nr_comp; ++i) { /* AFL test */ + if (image->comps[0].dx != image->comps[i].dx) { + break; + } + + if (image->comps[0].dy != image->comps[i].dy) { + break; + } + + if (image->comps[0].prec != image->comps[i].prec) { + break; + } + + if (image->comps[0].sgnd != image->comps[i].sgnd) { + break; + } + + } + if (i != nr_comp) { + cmsCloseProfile(in_prof); + return; + } + + if (prec <= 8) { + in_type = TYPE_RGB_8; + out_type = TYPE_RGB_8; + } else { + in_type = TYPE_RGB_16; + out_type = TYPE_RGB_16; + } + out_prof = cmsCreate_sRGBProfile(); + new_space = OPJ_CLRSPC_SRGB; + } else if (out_space == cmsSigGrayData) { /* enumCS 17 */ + in_type = TYPE_GRAY_8; + out_type = TYPE_RGB_8; + out_prof = cmsCreate_sRGBProfile(); + new_space = OPJ_CLRSPC_SRGB; + } else if (out_space == cmsSigYCbCrData) { /* enumCS 18 */ + in_type = TYPE_YCbCr_16; + out_type = TYPE_RGB_16; + out_prof = cmsCreate_sRGBProfile(); + new_space = OPJ_CLRSPC_SRGB; + } else { +#ifdef DEBUG_PROFILE + fprintf(stderr, "%s:%d: color_apply_icc_profile\n\tICC Profile has unknown " + "output colorspace(%#x)(%c%c%c%c)\n\tICC Profile ignored.\n", + __FILE__, __LINE__, out_space, + (out_space >> 24) & 0xff, (out_space >> 16) & 0xff, + (out_space >> 8) & 0xff, out_space & 0xff); +#endif + cmsCloseProfile(in_prof); + + return; + } + if (out_prof == NULL) { + cmsCloseProfile(in_prof); + return; + } + +#ifdef DEBUG_PROFILE + fprintf(stderr, + "%s:%d:color_apply_icc_profile\n\tchannels(%d) prec(%d) w(%d) h(%d)" + "\n\tprofile: in(%p) out(%p)\n", __FILE__, __LINE__, image->numcomps, prec, + max_w, max_h, (void*)in_prof, (void*)out_prof); + + fprintf(stderr, "\trender_intent (%u)\n\t" + "color_space: in(%#x)(%c%c%c%c) out:(%#x)(%c%c%c%c)\n\t" + " type: in(%u) out:(%u)\n", + intent, + in_space, + (in_space >> 24) & 0xff, (in_space >> 16) & 0xff, + (in_space >> 8) & 0xff, in_space & 0xff, + + out_space, + (out_space >> 24) & 0xff, (out_space >> 16) & 0xff, + (out_space >> 8) & 0xff, out_space & 0xff, + + in_type, out_type + ); +#else + (void)prec; + (void)in_space; +#endif /* DEBUG_PROFILE */ + + transform = cmsCreateTransform(in_prof, in_type, out_prof, out_type, intent, 0); + +#ifdef OPJ_HAVE_LIBLCMS2 + /* Possible for: LCMS_VERSION >= 2000 :*/ + cmsCloseProfile(in_prof); + cmsCloseProfile(out_prof); +#endif + + if (transform == NULL) { +#ifdef DEBUG_PROFILE + fprintf(stderr, "%s:%d:color_apply_icc_profile\n\tcmsCreateTransform failed. " + "ICC Profile ignored.\n", __FILE__, __LINE__); +#endif + +#ifdef OPJ_HAVE_LIBLCMS1 + cmsCloseProfile(in_prof); + cmsCloseProfile(out_prof); +#endif + return; + } + + if (image->numcomps > 2) { /* RGB, RGBA */ + if (prec <= 8) { + unsigned char *inbuf, *outbuf, *in, *out; + + max = max_w * max_h; + nr_samples = (size_t)(max * 3U * sizeof(unsigned char)); + in = inbuf = (unsigned char*)opj_image_data_alloc(nr_samples); + out = outbuf = (unsigned char*)opj_image_data_alloc(nr_samples); + + if (inbuf == NULL || outbuf == NULL) { + goto fails0; + } + + r = image->comps[0].data; + g = image->comps[1].data; + b = image->comps[2].data; + + for (i = 0U; i < max; ++i) { + *in++ = (unsigned char) * r++; + *in++ = (unsigned char) * g++; + *in++ = (unsigned char) * b++; + } + + cmsDoTransform(transform, inbuf, outbuf, (cmsUInt32Number)max); + + r = image->comps[0].data; + g = image->comps[1].data; + b = image->comps[2].data; + + for (i = 0U; i < max; ++i) { + *r++ = (int) * out++; + *g++ = (int) * out++; + *b++ = (int) * out++; + } + ok = 1; + +fails0: + opj_image_data_free(inbuf); + opj_image_data_free(outbuf); + } else { /* prec > 8 */ + unsigned short *inbuf, *outbuf, *in, *out; + + max = max_w * max_h; + nr_samples = (size_t)(max * 3U * sizeof(unsigned short)); + in = inbuf = (unsigned short*)opj_image_data_alloc(nr_samples); + out = outbuf = (unsigned short*)opj_image_data_alloc(nr_samples); + + if (inbuf == NULL || outbuf == NULL) { + goto fails1; + } + + r = image->comps[0].data; + g = image->comps[1].data; + b = image->comps[2].data; + + for (i = 0U ; i < max; ++i) { + *in++ = (unsigned short) * r++; + *in++ = (unsigned short) * g++; + *in++ = (unsigned short) * b++; + } + + cmsDoTransform(transform, inbuf, outbuf, (cmsUInt32Number)max); + + r = image->comps[0].data; + g = image->comps[1].data; + b = image->comps[2].data; + + for (i = 0; i < max; ++i) { + *r++ = (int) * out++; + *g++ = (int) * out++; + *b++ = (int) * out++; + } + ok = 1; + +fails1: + opj_image_data_free(inbuf); + opj_image_data_free(outbuf); + } + } else { /* image->numcomps <= 2 : GRAY, GRAYA */ + if (prec <= 8) { + unsigned char *in, *inbuf, *out, *outbuf; + opj_image_comp_t *new_comps; + + max = max_w * max_h; + nr_samples = (size_t)(max * 3 * sizeof(unsigned char)); + in = inbuf = (unsigned char*)opj_image_data_alloc(nr_samples); + out = outbuf = (unsigned char*)opj_image_data_alloc(nr_samples); + g = (int*)opj_image_data_alloc((size_t)max * sizeof(int)); + b = (int*)opj_image_data_alloc((size_t)max * sizeof(int)); + + if (inbuf == NULL || outbuf == NULL || g == NULL || b == NULL) { + goto fails2; + } + + new_comps = (opj_image_comp_t*)realloc(image->comps, + (image->numcomps + 2) * sizeof(opj_image_comp_t)); + + if (new_comps == NULL) { + goto fails2; + } + + image->comps = new_comps; + + if (image->numcomps == 2) { + image->comps[3] = image->comps[1]; + } + + image->comps[1] = image->comps[0]; + image->comps[2] = image->comps[0]; + + image->comps[1].data = g; + image->comps[2].data = b; + + image->numcomps += 2; + + r = image->comps[0].data; + + for (i = 0U; i < max; ++i) { + *in++ = (unsigned char) * r++; + } + cmsDoTransform(transform, inbuf, outbuf, (cmsUInt32Number)max); + + r = image->comps[0].data; + g = image->comps[1].data; + b = image->comps[2].data; + + for (i = 0U; i < max; ++i) { + *r++ = (int) * out++; + *g++ = (int) * out++; + *b++ = (int) * out++; + } + r = g = b = NULL; + ok = 1; + +fails2: + opj_image_data_free(inbuf); + opj_image_data_free(outbuf); + opj_image_data_free(g); + opj_image_data_free(b); + } else { /* prec > 8 */ + unsigned short *in, *inbuf, *out, *outbuf; + opj_image_comp_t *new_comps; + + max = max_w * max_h; + nr_samples = (size_t)(max * 3U * sizeof(unsigned short)); + in = inbuf = (unsigned short*)opj_image_data_alloc(nr_samples); + out = outbuf = (unsigned short*)opj_image_data_alloc(nr_samples); + g = (int*)opj_image_data_alloc((size_t)max * sizeof(int)); + b = (int*)opj_image_data_alloc((size_t)max * sizeof(int)); + + if (inbuf == NULL || outbuf == NULL || g == NULL || b == NULL) { + goto fails3; + } + + new_comps = (opj_image_comp_t*)realloc(image->comps, + (image->numcomps + 2) * sizeof(opj_image_comp_t)); + + if (new_comps == NULL) { + goto fails3; + } + + image->comps = new_comps; + + if (image->numcomps == 2) { + image->comps[3] = image->comps[1]; + } + + image->comps[1] = image->comps[0]; + image->comps[2] = image->comps[0]; + + image->comps[1].data = g; + image->comps[2].data = b; + + image->numcomps += 2; + + r = image->comps[0].data; + + for (i = 0U; i < max; ++i) { + *in++ = (unsigned short) * r++; + } + cmsDoTransform(transform, inbuf, outbuf, (cmsUInt32Number)max); + + r = image->comps[0].data; + g = image->comps[1].data; + b = image->comps[2].data; + + for (i = 0; i < max; ++i) { + *r++ = (int) * out++; + *g++ = (int) * out++; + *b++ = (int) * out++; + } + r = g = b = NULL; + ok = 1; + +fails3: + opj_image_data_free(inbuf); + opj_image_data_free(outbuf); + opj_image_data_free(g); + opj_image_data_free(b); + } + }/* if(image->numcomps > 2) */ + + cmsDeleteTransform(transform); + +#ifdef OPJ_HAVE_LIBLCMS1 + cmsCloseProfile(in_prof); + cmsCloseProfile(out_prof); +#endif + if (ok) { + image->color_space = new_space; + } +}/* color_apply_icc_profile() */ + +static int are_comps_same_dimensions(opj_image_t * image) +{ + unsigned int i; + for (i = 1; i < image->numcomps; i++) { + if (image->comps[0].dx != image->comps[i].dx || + image->comps[0].dy != image->comps[i].dy) { + return OPJ_FALSE; + } + } + return OPJ_TRUE; +} + +void color_cielab_to_rgb(opj_image_t *image) +{ + int *row; + int enumcs, numcomps; + OPJ_COLOR_SPACE new_space; + + numcomps = (int)image->numcomps; + + if (numcomps != 3) { + fprintf(stderr, "%s:%d:\n\tnumcomps %d not handled. Quitting.\n", + __FILE__, __LINE__, numcomps); + return; + } + if (!are_comps_same_dimensions(image)) { + fprintf(stderr, + "%s:%d:\n\tcomponents are not all of the same dimension. Quitting.\n", + __FILE__, __LINE__); + return; + } + + row = (int*)image->icc_profile_buf; + enumcs = row[0]; + + if (enumcs == 14) { /* CIELab */ + int *L, *a, *b, *red, *green, *blue; + int *src0, *src1, *src2, *dst0, *dst1, *dst2; + double rl, ol, ra, oa, rb, ob, prec0, prec1, prec2; + double minL, maxL, mina, maxa, minb, maxb; + unsigned int default_type; + unsigned int i, max; + cmsHPROFILE in, out; + cmsHTRANSFORM transform; + cmsUInt16Number RGB[3]; + cmsCIELab Lab; + + in = cmsCreateLab4Profile(NULL); + if (in == NULL) { + return; + } + out = cmsCreate_sRGBProfile(); + if (out == NULL) { + cmsCloseProfile(in); + return; + } + transform = cmsCreateTransform(in, TYPE_Lab_DBL, out, TYPE_RGB_16, + INTENT_PERCEPTUAL, 0); + +#ifdef OPJ_HAVE_LIBLCMS2 + cmsCloseProfile(in); + cmsCloseProfile(out); +#endif + if (transform == NULL) { +#ifdef OPJ_HAVE_LIBLCMS1 + cmsCloseProfile(in); + cmsCloseProfile(out); +#endif + return; + } + new_space = OPJ_CLRSPC_SRGB; + + prec0 = (double)image->comps[0].prec; + prec1 = (double)image->comps[1].prec; + prec2 = (double)image->comps[2].prec; + + default_type = (unsigned int)row[1]; + + if (default_type == 0x44454600) { /* DEF : default */ + rl = 100; + ra = 170; + rb = 200; + ol = 0; + oa = pow(2, prec1 - 1); + ob = pow(2, prec2 - 2) + pow(2, prec2 - 3); + } else { + rl = row[2]; + ra = row[4]; + rb = row[6]; + ol = row[3]; + oa = row[5]; + ob = row[7]; + } + + L = src0 = image->comps[0].data; + a = src1 = image->comps[1].data; + b = src2 = image->comps[2].data; + + max = image->comps[0].w * image->comps[0].h; + + red = dst0 = (int*)opj_image_data_alloc(max * sizeof(int)); + green = dst1 = (int*)opj_image_data_alloc(max * sizeof(int)); + blue = dst2 = (int*)opj_image_data_alloc(max * sizeof(int)); + + if (red == NULL || green == NULL || blue == NULL) { + goto fails; + } + + minL = -(rl * ol) / (pow(2, prec0) - 1); + maxL = minL + rl; + + mina = -(ra * oa) / (pow(2, prec1) - 1); + maxa = mina + ra; + + minb = -(rb * ob) / (pow(2, prec2) - 1); + maxb = minb + rb; + + for (i = 0; i < max; ++i) { + Lab.L = minL + (double)(*L) * (maxL - minL) / (pow(2, prec0) - 1); + ++L; + Lab.a = mina + (double)(*a) * (maxa - mina) / (pow(2, prec1) - 1); + ++a; + Lab.b = minb + (double)(*b) * (maxb - minb) / (pow(2, prec2) - 1); + ++b; + + cmsDoTransform(transform, &Lab, RGB, 1); + + *red++ = RGB[0]; + *green++ = RGB[1]; + *blue++ = RGB[2]; + } + cmsDeleteTransform(transform); +#ifdef OPJ_HAVE_LIBLCMS1 + cmsCloseProfile(in); + cmsCloseProfile(out); +#endif + opj_image_data_free(src0); + image->comps[0].data = dst0; + opj_image_data_free(src1); + image->comps[1].data = dst1; + opj_image_data_free(src2); + image->comps[2].data = dst2; + + image->color_space = new_space; + image->comps[0].prec = 16; + image->comps[1].prec = 16; + image->comps[2].prec = 16; + + return; + +fails: + cmsDeleteTransform(transform); +#ifdef OPJ_HAVE_LIBLCMS1 + cmsCloseProfile(in); + cmsCloseProfile(out); +#endif + if (red) { + opj_image_data_free(red); + } + if (green) { + opj_image_data_free(green); + } + if (blue) { + opj_image_data_free(blue); + } + return; + } + + fprintf(stderr, "%s:%d:\n\tenumCS %d not handled. Ignoring.\n", __FILE__, + __LINE__, enumcs); +}/* color_cielab_to_rgb() */ + +#endif /* OPJ_HAVE_LIBLCMS2 || OPJ_HAVE_LIBLCMS1 */ + +void color_cmyk_to_rgb(opj_image_t *image) +{ + float C, M, Y, K; + float sC, sM, sY, sK; + unsigned int w, h, max, i; + + w = image->comps[0].w; + h = image->comps[0].h; + + if ( + (image->numcomps < 4) + || (image->comps[0].dx != image->comps[1].dx) || + (image->comps[0].dx != image->comps[2].dx) || + (image->comps[0].dx != image->comps[3].dx) + || (image->comps[0].dy != image->comps[1].dy) || + (image->comps[0].dy != image->comps[2].dy) || + (image->comps[0].dy != image->comps[3].dy) + ) { + fprintf(stderr, "%s:%d:color_cmyk_to_rgb\n\tCAN NOT CONVERT\n", __FILE__, + __LINE__); + return; + } + + max = w * h; + + sC = 1.0F / (float)((1 << image->comps[0].prec) - 1); + sM = 1.0F / (float)((1 << image->comps[1].prec) - 1); + sY = 1.0F / (float)((1 << image->comps[2].prec) - 1); + sK = 1.0F / (float)((1 << image->comps[3].prec) - 1); + + for (i = 0; i < max; ++i) { + /* CMYK values from 0 to 1 */ + C = (float)(image->comps[0].data[i]) * sC; + M = (float)(image->comps[1].data[i]) * sM; + Y = (float)(image->comps[2].data[i]) * sY; + K = (float)(image->comps[3].data[i]) * sK; + + /* Invert all CMYK values */ + C = 1.0F - C; + M = 1.0F - M; + Y = 1.0F - Y; + K = 1.0F - K; + + /* CMYK -> RGB : RGB results from 0 to 255 */ + image->comps[0].data[i] = (int)(255.0F * C * K); /* R */ + image->comps[1].data[i] = (int)(255.0F * M * K); /* G */ + image->comps[2].data[i] = (int)(255.0F * Y * K); /* B */ + } + + opj_image_data_free(image->comps[3].data); + image->comps[3].data = NULL; + image->comps[0].prec = 8; + image->comps[1].prec = 8; + image->comps[2].prec = 8; + image->numcomps -= 1; + image->color_space = OPJ_CLRSPC_SRGB; + + for (i = 3; i < image->numcomps; ++i) { + memcpy(&(image->comps[i]), &(image->comps[i + 1]), sizeof(image->comps[i])); + } + +}/* color_cmyk_to_rgb() */ + +/* + * This code has been adopted from sjpx_openjpeg.c of ghostscript + */ +void color_esycc_to_rgb(opj_image_t *image) +{ + int y, cb, cr, sign1, sign2, val; + unsigned int w, h, max, i; + int flip_value = (1 << (image->comps[0].prec - 1)); + int max_value = (1 << image->comps[0].prec) - 1; + + if ( + (image->numcomps < 3) + || (image->comps[0].dx != image->comps[1].dx) || + (image->comps[0].dx != image->comps[2].dx) + || (image->comps[0].dy != image->comps[1].dy) || + (image->comps[0].dy != image->comps[2].dy) + ) { + fprintf(stderr, "%s:%d:color_esycc_to_rgb\n\tCAN NOT CONVERT\n", __FILE__, + __LINE__); + return; + } + + w = image->comps[0].w; + h = image->comps[0].h; + + sign1 = (int)image->comps[1].sgnd; + sign2 = (int)image->comps[2].sgnd; + + max = w * h; + + for (i = 0; i < max; ++i) { + + y = image->comps[0].data[i]; + cb = image->comps[1].data[i]; + cr = image->comps[2].data[i]; + + if (!sign1) { + cb -= flip_value; + } + if (!sign2) { + cr -= flip_value; + } + + val = (int) + ((float)y - (float)0.0000368 * (float)cb + + (float)1.40199 * (float)cr + (float)0.5); + + if (val > max_value) { + val = max_value; + } else if (val < 0) { + val = 0; + } + image->comps[0].data[i] = val; + + val = (int) + ((float)1.0003 * (float)y - (float)0.344125 * (float)cb + - (float)0.7141128 * (float)cr + (float)0.5); + + if (val > max_value) { + val = max_value; + } else if (val < 0) { + val = 0; + } + image->comps[1].data[i] = val; + + val = (int) + ((float)0.999823 * (float)y + (float)1.77204 * (float)cb + - (float)0.000008 * (float)cr + (float)0.5); + + if (val > max_value) { + val = max_value; + } else if (val < 0) { + val = 0; + } + image->comps[2].data[i] = val; + } + image->color_space = OPJ_CLRSPC_SRGB; + +}/* color_esycc_to_rgb() */ diff --git a/openjpeg/src/bin/common/color.h b/openjpeg/src/bin/common/color.h new file mode 100644 index 000000000..24792544a --- /dev/null +++ b/openjpeg/src/bin/common/color.h @@ -0,0 +1,47 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * Copyright (c) 2003-2014, Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _OPJ_COLOR_H_ +#define _OPJ_COLOR_H_ + +extern void color_sycc_to_rgb(opj_image_t *img); +extern void color_apply_icc_profile(opj_image_t *image); +extern void color_cielab_to_rgb(opj_image_t *image); + +extern void color_cmyk_to_rgb(opj_image_t *image); +extern void color_esycc_to_rgb(opj_image_t *image); +#endif /* _OPJ_COLOR_H_ */ diff --git a/openjpeg/src/bin/common/format_defs.h b/openjpeg/src/bin/common/format_defs.h new file mode 100644 index 000000000..1985b54f7 --- /dev/null +++ b/openjpeg/src/bin/common/format_defs.h @@ -0,0 +1,55 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * Copyright (c) 2003-2014, Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _OPJ_FORMAT_DEFS_H_ +#define _OPJ_FORMAT_DEFS_H_ + +#define J2K_CFMT 0 +#define JP2_CFMT 1 +#define JPT_CFMT 2 + +#define PXM_DFMT 10 +#define PGX_DFMT 11 +#define BMP_DFMT 12 +#define YUV_DFMT 13 +#define TIF_DFMT 14 +#define RAW_DFMT 15 /* MSB / Big Endian */ +#define TGA_DFMT 16 +#define PNG_DFMT 17 +#define RAWL_DFMT 18 /* LSB / Little Endian */ + +#endif /* _OPJ_FORMAT_DEFS_H_ */ diff --git a/openjpeg/src/bin/common/opj_apps_config.h.cmake.in b/openjpeg/src/bin/common/opj_apps_config.h.cmake.in new file mode 100644 index 000000000..607c07868 --- /dev/null +++ b/openjpeg/src/bin/common/opj_apps_config.h.cmake.in @@ -0,0 +1,15 @@ +#include "opj_config_private.h" + +/* create opj_apps_config.h for CMake */ + +#cmakedefine OPJ_HAVE_LIBPNG @HAVE_LIBPNG@ +#cmakedefine OPJ_HAVE_PNG_H @HAVE_PNG_H@ +#cmakedefine OPJ_HAVE_LIBTIFF @HAVE_LIBTIFF@ +#cmakedefine OPJ_HAVE_TIFF_H @HAVE_TIFF_H@ + +#cmakedefine OPJ_HAVE_LIBLCMS1 +#cmakedefine OPJ_HAVE_LIBLCMS2 +#cmakedefine OPJ_HAVE_LCMS1_H +#cmakedefine OPJ_HAVE_LCMS2_H + + diff --git a/openjpeg/src/bin/common/opj_getopt.c b/openjpeg/src/bin/common/opj_getopt.c new file mode 100644 index 000000000..11ccfc59b --- /dev/null +++ b/openjpeg/src/bin/common/opj_getopt.c @@ -0,0 +1,277 @@ +/* + * The copyright in this software is being made available under the 3-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* last review : october 29th, 2002 */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)opj_getopt.c 8.3 (Berkeley) 4/27/95"; +#endif /* LIBC_SCCS and not lint */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "opj_getopt.h" + +int opj_opterr = 1, /* if error message should be printed */ + opj_optind = 1, /* index into parent argv vector */ + opj_optopt, /* character checked for validity */ + opj_optreset; /* reset getopt */ +char *opj_optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +static char EMSG[] = {""}; + +/* As this class remembers its values from one Java call to the other, reset the values before each use */ +void opj_reset_options_reading(void) +{ + opj_opterr = 1; + opj_optind = 1; +} + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int opj_getopt(int nargc, char *const *nargv, const char *ostr) +{ +# define __progname nargv[0] + static char *place = EMSG; /* option letter processing */ + const char *oli = NULL; /* option letter list index */ + + if (opj_optreset || !*place) { /* update scanning pointer */ + opj_optreset = 0; + if (opj_optind >= nargc || *(place = nargv[opj_optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++opj_optind; + place = EMSG; + return (-1); + } + } /* option letter okay? */ + if ((opj_optopt = (int) * place++) == (int) ':' || + !(oli = strchr(ostr, opj_optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (opj_optopt == (int) '-') { + return (-1); + } + if (!*place) { + ++opj_optind; + } + if (opj_opterr && *ostr != ':') { + fprintf(stderr, + "%s: illegal option -- %c\n", __progname, opj_optopt); + return (BADCH); + } + } + if (*++oli != ':') { /* don't need argument */ + opj_optarg = NULL; + if (!*place) { + ++opj_optind; + } + } else { /* need an argument */ + if (*place) { /* no white space */ + opj_optarg = place; + } else if (nargc <= ++opj_optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') { + return (BADARG); + } + if (opj_opterr) { + fprintf(stderr, + "%s: option requires an argument -- %c\n", + __progname, opj_optopt); + return (BADCH); + } + } else { /* white space */ + opj_optarg = nargv[opj_optind]; + } + place = EMSG; + ++opj_optind; + } + return (opj_optopt); /* dump back option letter */ +} + + +int opj_getopt_long(int argc, char * const argv[], const char *optstring, + const opj_option_t *longopts, int totlen) +{ + static int lastidx, lastofs; + const char *tmp; + int i, len; + char param = 1; + +again: + if (opj_optind >= argc || !argv[opj_optind] || *argv[opj_optind] != '-') { + return -1; + } + + if (argv[opj_optind][0] == '-' && argv[opj_optind][1] == 0) { + if (opj_optind >= (argc - 1)) { /* no more input parameters */ + param = 0; + } else { /* more input parameters */ + if (argv[opj_optind + 1][0] == '-') { + param = 0; /* Missing parameter after '-' */ + } else { + param = 2; + } + } + } + + if (param == 0) { + ++opj_optind; + return (BADCH); + } + + if (argv[opj_optind][0] == '-') { /* long option */ + char* arg; + const opj_option_t* o; + o = longopts; + len = sizeof(longopts[0]); + + if (param > 1) { + if (opj_optind + 1 >= argc) { + return -1; + } + arg = argv[opj_optind + 1]; + opj_optind++; + } else { + arg = argv[opj_optind] + 1; + } + + if (strlen(arg) > 1) { + for (i = 0; i < totlen; i = i + len, o++) { + if (!strcmp(o->name, arg)) { /* match */ + if (o->has_arg == 0) { + if ((argv[opj_optind + 1]) && (!(argv[opj_optind + 1][0] == '-'))) { + fprintf(stderr, "%s: option does not require an argument. Ignoring %s\n", arg, + argv[opj_optind + 1]); + ++opj_optind; + } + } else { + opj_optarg = argv[opj_optind + 1]; + if (opj_optarg) { + if (opj_optarg[0] == + '-') { /* Has read next input parameter: No arg for current parameter */ + if (opj_opterr) { + fprintf(stderr, "%s: option requires an argument\n", arg); + return (BADCH); + } + } + } + if (!opj_optarg && o->has_arg == 1) { /* no argument there */ + if (opj_opterr) { + fprintf(stderr, "%s: option requires an argument \n", arg); + return (BADCH); + } + } + ++opj_optind; + } + ++opj_optind; + if (o->flag) { + *(o->flag) = o->val; + } else { + return o->val; + } + return 0; + } + }/*(end for)String not found in the list*/ + fprintf(stderr, "Invalid option %s\n", arg); + ++opj_optind; + return (BADCH); + } else { /*Single character input parameter*/ + if (*optstring == ':') { + return ':'; + } + if (lastidx != opj_optind) { + lastidx = opj_optind; + lastofs = 0; + } + opj_optopt = argv[opj_optind][lastofs + 1]; + if ((tmp = strchr(optstring, opj_optopt))) { /*Found input parameter in list*/ + if (*tmp == 0) { /* apparently, we looked for \0, i.e. end of argument */ + ++opj_optind; + goto again; + } + if (tmp[1] == ':') { /* argument expected */ + if (tmp[2] == ':' || + argv[opj_optind][lastofs + 2]) { /* "-foo", return "oo" as opj_optarg */ + if (!*(opj_optarg = argv[opj_optind] + lastofs + 2)) { + opj_optarg = 0; + } + goto found; + } + opj_optarg = argv[opj_optind + 1]; + if (opj_optarg) { + if (opj_optarg[0] == + '-') { /* Has read next input parameter: No arg for current parameter */ + if (opj_opterr) { + fprintf(stderr, "%s: option requires an argument\n", arg); + ++opj_optind; + return (BADCH); + } + } + } + if (!opj_optarg) { /* missing argument */ + if (opj_opterr) { + fprintf(stderr, "%s: option requires an argument\n", arg); + ++opj_optind; + return (BADCH); + } + } + ++opj_optind; + } else {/*Argument not expected*/ + ++lastofs; + return opj_optopt; + } +found: + ++opj_optind; + return opj_optopt; + } else { /* not found */ + fprintf(stderr, "Invalid option %s\n", arg); + ++opj_optind; + return (BADCH); + }/*end of not found*/ + + }/* end of single character*/ + }/*end '-'*/ + fprintf(stderr, "Invalid option\n"); + ++opj_optind; + return (BADCH);; +}/*end function*/ diff --git a/openjpeg/src/bin/common/opj_getopt.h b/openjpeg/src/bin/common/opj_getopt.h new file mode 100644 index 000000000..18ac24d46 --- /dev/null +++ b/openjpeg/src/bin/common/opj_getopt.h @@ -0,0 +1,28 @@ +/* last review : october 29th, 2002 */ + +#ifndef _GETOPT_H_ +#define _GETOPT_H_ + +typedef struct opj_option { + const char *name; + int has_arg; + int *flag; + int val; +} opj_option_t; + +#define NO_ARG 0 +#define REQ_ARG 1 +#define OPT_ARG 2 + +extern int opj_opterr; +extern int opj_optind; +extern int opj_optopt; +extern int opj_optreset; +extern char *opj_optarg; + +extern int opj_getopt(int nargc, char *const *nargv, const char *ostr); +extern int opj_getopt_long(int argc, char * const argv[], const char *optstring, + const opj_option_t *longopts, int totlen); +extern void opj_reset_options_reading(void); + +#endif /* _GETOPT_H_ */ diff --git a/openjpeg/src/bin/common/opj_string.h b/openjpeg/src/bin/common/opj_string.h new file mode 100644 index 000000000..f704a8c95 --- /dev/null +++ b/openjpeg/src/bin/common/opj_string.h @@ -0,0 +1,72 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2015, Matthieu Darbois + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef OPJ_STRING_H +#define OPJ_STRING_H + +#include <errno.h> +#include <string.h> + +/* strnlen is not standard, strlen_s is C11... */ +/* keep in mind there still is a buffer read overflow possible */ +static size_t opj_strnlen_s(const char *src, size_t max_len) +{ + size_t len; + + if (src == NULL) { + return 0U; + } + for (len = 0U; (*src != '\0') && (len < max_len); src++, len++); + return len; +} + +/* should be equivalent to C11 function except for the handler */ +/* keep in mind there still is a buffer read overflow possible */ +static int opj_strcpy_s(char* dst, size_t dst_size, const char* src) +{ + size_t src_len = 0U; + if ((dst == NULL) || (dst_size == 0U)) { + return EINVAL; + } + if (src == NULL) { + dst[0] = '\0'; + return EINVAL; + } + src_len = opj_strnlen_s(src, dst_size); + if (src_len >= dst_size) { + return ERANGE; + } + memcpy(dst, src, src_len); + dst[src_len] = '\0'; + return 0; +} + +#endif /* OPJ_STRING_H */ diff --git a/openjpeg/src/bin/jp2/CMakeLists.txt b/openjpeg/src/bin/jp2/CMakeLists.txt new file mode 100644 index 000000000..4324c36d0 --- /dev/null +++ b/openjpeg/src/bin/jp2/CMakeLists.txt @@ -0,0 +1,88 @@ +# Build the demo app, small examples + +# First thing define the common source: +set(common_SRCS + convert.c + convert.h + convertbmp.c + index.c + index.h + ${OPENJPEG_SOURCE_DIR}/src/bin/common/color.c + ${OPENJPEG_SOURCE_DIR}/src/bin/common/color.h + ${OPENJPEG_SOURCE_DIR}/src/bin/common/opj_getopt.c + ${OPENJPEG_SOURCE_DIR}/src/bin/common/opj_getopt.h + ${OPENJPEG_SOURCE_DIR}/src/bin/common/opj_string.h + ) + +if(OPJ_HAVE_LIBTIFF) + list(APPEND common_SRCS converttif.c) +endif() +if(OPJ_HAVE_LIBPNG) + list(APPEND common_SRCS convertpng.c) +endif() + +# Headers file are located here: +include_directories( + ${OPENJPEG_BINARY_DIR}/src/lib/openjp2 # opj_config.h + ${OPENJPEG_BINARY_DIR}/src/bin/common # opj_apps_config.h + ${OPENJPEG_SOURCE_DIR}/src/lib/openjp2 + ${OPENJPEG_SOURCE_DIR}/src/bin/common + ${LCMS_INCLUDE_DIRNAME} + ${Z_INCLUDE_DIRNAME} + ${PNG_INCLUDE_DIRNAME} + ${TIFF_INCLUDE_DIRNAME} + ) + +if(WIN32) + if(BUILD_SHARED_LIBS) + add_definitions(-DOPJ_EXPORTS) + else() + add_definitions(-DOPJ_STATIC) + endif() +endif() + +# Loop over all executables: +foreach(exe opj_decompress opj_compress opj_dump) + add_executable(${exe} ${exe}.c ${common_SRCS}) + if(${CMAKE_VERSION} VERSION_GREATER "2.8.11") + target_compile_options(${exe} PRIVATE ${OPENJP2_COMPILE_OPTIONS}) + endif() + target_link_libraries(${exe} ${OPENJPEG_LIBRARY_NAME} + ${PNG_LIBNAME} ${TIFF_LIBNAME} ${LCMS_LIBNAME} + ) + # To support universal exe: + if(ZLIB_FOUND AND APPLE) + target_link_libraries(${exe} z) + else(ZLIB_FOUND AND APPLE) + target_link_libraries(${exe} ${Z_LIBNAME}) + endif() + + # On unix you need to link to the math library: + if(UNIX) + target_link_libraries(${exe} m) + IF("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") + target_link_libraries(${exe} rt) + endif() + endif() + # Install exe + install(TARGETS ${exe} + EXPORT OpenJPEGTargets + DESTINATION ${OPENJPEG_INSTALL_BIN_DIR} COMPONENT Applications + ) + if(OPJ_USE_DSYMUTIL) + add_custom_command(TARGET ${exe} POST_BUILD + COMMAND "dsymutil" "$<TARGET_FILE:${exe}>" + COMMENT "dsymutil $<TARGET_FILE:${exe}>" + DEPENDS ${exe}) + endif() +endforeach() + +if(BUILD_DOC) +# Install man pages +install( + FILES ${OPENJPEG_SOURCE_DIR}/doc/man/man1/opj_compress.1 + ${OPENJPEG_SOURCE_DIR}/doc/man/man1/opj_decompress.1 + ${OPENJPEG_SOURCE_DIR}/doc/man/man1/opj_dump.1 + DESTINATION ${OPENJPEG_INSTALL_MAN_DIR}/man1) +# +endif() diff --git a/openjpeg/src/bin/jp2/convert.c b/openjpeg/src/bin/jp2/convert.c new file mode 100644 index 000000000..7040969d2 --- /dev/null +++ b/openjpeg/src/bin/jp2/convert.c @@ -0,0 +1,2595 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * Copyright (c) 2003-2014, Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "opj_apps_config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <limits.h> + +#include "openjpeg.h" +#include "convert.h" + +/* + * Get logarithm of an integer and round downwards. + * + * log2(a) + */ +static int int_floorlog2(int a) +{ + int l; + for (l = 0; a > 1; l++) { + a >>= 1; + } + return l; +} + +/* Component precision scaling */ +void clip_component(opj_image_comp_t* component, OPJ_UINT32 precision) +{ + OPJ_SIZE_T i; + OPJ_SIZE_T len; + OPJ_UINT32 umax = (OPJ_UINT32)((OPJ_INT32) - 1); + + len = (OPJ_SIZE_T)component->w * (OPJ_SIZE_T)component->h; + if (precision < 32) { + umax = (1U << precision) - 1U; + } + + if (component->sgnd) { + OPJ_INT32* l_data = component->data; + OPJ_INT32 max = (OPJ_INT32)(umax / 2U); + OPJ_INT32 min = -max - 1; + for (i = 0; i < len; ++i) { + if (l_data[i] > max) { + l_data[i] = max; + } else if (l_data[i] < min) { + l_data[i] = min; + } + } + } else { + OPJ_UINT32* l_data = (OPJ_UINT32*)component->data; + for (i = 0; i < len; ++i) { + if (l_data[i] > umax) { + l_data[i] = umax; + } + } + } + component->prec = precision; +} + +/* Component precision scaling */ +static void scale_component_up(opj_image_comp_t* component, + OPJ_UINT32 precision) +{ + OPJ_SIZE_T i, len; + + len = (OPJ_SIZE_T)component->w * (OPJ_SIZE_T)component->h; + if (component->sgnd) { + OPJ_INT64 newMax = (OPJ_INT64)(1U << (precision - 1)); + OPJ_INT64 oldMax = (OPJ_INT64)(1U << (component->prec - 1)); + OPJ_INT32* l_data = component->data; + for (i = 0; i < len; ++i) { + l_data[i] = (OPJ_INT32)(((OPJ_INT64)l_data[i] * newMax) / oldMax); + } + } else { + OPJ_UINT64 newMax = (OPJ_UINT64)((1U << precision) - 1U); + OPJ_UINT64 oldMax = (OPJ_UINT64)((1U << component->prec) - 1U); + OPJ_UINT32* l_data = (OPJ_UINT32*)component->data; + for (i = 0; i < len; ++i) { + l_data[i] = (OPJ_UINT32)(((OPJ_UINT64)l_data[i] * newMax) / oldMax); + } + } + component->prec = precision; + component->bpp = precision; +} +void scale_component(opj_image_comp_t* component, OPJ_UINT32 precision) +{ + int shift; + OPJ_SIZE_T i, len; + + if (component->prec == precision) { + return; + } + if (component->prec < precision) { + scale_component_up(component, precision); + return; + } + shift = (int)(component->prec - precision); + len = (OPJ_SIZE_T)component->w * (OPJ_SIZE_T)component->h; + if (component->sgnd) { + OPJ_INT32* l_data = component->data; + for (i = 0; i < len; ++i) { + l_data[i] >>= shift; + } + } else { + OPJ_UINT32* l_data = (OPJ_UINT32*)component->data; + for (i = 0; i < len; ++i) { + l_data[i] >>= shift; + } + } + component->bpp = precision; + component->prec = precision; +} + + +/* planar / interleaved conversions */ +/* used by PNG/TIFF */ +static void convert_32s_C1P1(const OPJ_INT32* pSrc, OPJ_INT32* const* pDst, + OPJ_SIZE_T length) +{ + memcpy(pDst[0], pSrc, length * sizeof(OPJ_INT32)); +} +static void convert_32s_C2P2(const OPJ_INT32* pSrc, OPJ_INT32* const* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + OPJ_INT32* pDst0 = pDst[0]; + OPJ_INT32* pDst1 = pDst[1]; + + for (i = 0; i < length; i++) { + pDst0[i] = pSrc[2 * i + 0]; + pDst1[i] = pSrc[2 * i + 1]; + } +} +static void convert_32s_C3P3(const OPJ_INT32* pSrc, OPJ_INT32* const* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + OPJ_INT32* pDst0 = pDst[0]; + OPJ_INT32* pDst1 = pDst[1]; + OPJ_INT32* pDst2 = pDst[2]; + + for (i = 0; i < length; i++) { + pDst0[i] = pSrc[3 * i + 0]; + pDst1[i] = pSrc[3 * i + 1]; + pDst2[i] = pSrc[3 * i + 2]; + } +} +static void convert_32s_C4P4(const OPJ_INT32* pSrc, OPJ_INT32* const* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + OPJ_INT32* pDst0 = pDst[0]; + OPJ_INT32* pDst1 = pDst[1]; + OPJ_INT32* pDst2 = pDst[2]; + OPJ_INT32* pDst3 = pDst[3]; + + for (i = 0; i < length; i++) { + pDst0[i] = pSrc[4 * i + 0]; + pDst1[i] = pSrc[4 * i + 1]; + pDst2[i] = pSrc[4 * i + 2]; + pDst3[i] = pSrc[4 * i + 3]; + } +} +const convert_32s_CXPX convert_32s_CXPX_LUT[5] = { + NULL, + convert_32s_C1P1, + convert_32s_C2P2, + convert_32s_C3P3, + convert_32s_C4P4 +}; + +static void convert_32s_P1C1(OPJ_INT32 const* const* pSrc, OPJ_INT32* pDst, + OPJ_SIZE_T length, OPJ_INT32 adjust) +{ + OPJ_SIZE_T i; + const OPJ_INT32* pSrc0 = pSrc[0]; + + for (i = 0; i < length; i++) { + pDst[i] = pSrc0[i] + adjust; + } +} +static void convert_32s_P2C2(OPJ_INT32 const* const* pSrc, OPJ_INT32* pDst, + OPJ_SIZE_T length, OPJ_INT32 adjust) +{ + OPJ_SIZE_T i; + const OPJ_INT32* pSrc0 = pSrc[0]; + const OPJ_INT32* pSrc1 = pSrc[1]; + + for (i = 0; i < length; i++) { + pDst[2 * i + 0] = pSrc0[i] + adjust; + pDst[2 * i + 1] = pSrc1[i] + adjust; + } +} +static void convert_32s_P3C3(OPJ_INT32 const* const* pSrc, OPJ_INT32* pDst, + OPJ_SIZE_T length, OPJ_INT32 adjust) +{ + OPJ_SIZE_T i; + const OPJ_INT32* pSrc0 = pSrc[0]; + const OPJ_INT32* pSrc1 = pSrc[1]; + const OPJ_INT32* pSrc2 = pSrc[2]; + + for (i = 0; i < length; i++) { + pDst[3 * i + 0] = pSrc0[i] + adjust; + pDst[3 * i + 1] = pSrc1[i] + adjust; + pDst[3 * i + 2] = pSrc2[i] + adjust; + } +} +static void convert_32s_P4C4(OPJ_INT32 const* const* pSrc, OPJ_INT32* pDst, + OPJ_SIZE_T length, OPJ_INT32 adjust) +{ + OPJ_SIZE_T i; + const OPJ_INT32* pSrc0 = pSrc[0]; + const OPJ_INT32* pSrc1 = pSrc[1]; + const OPJ_INT32* pSrc2 = pSrc[2]; + const OPJ_INT32* pSrc3 = pSrc[3]; + + for (i = 0; i < length; i++) { + pDst[4 * i + 0] = pSrc0[i] + adjust; + pDst[4 * i + 1] = pSrc1[i] + adjust; + pDst[4 * i + 2] = pSrc2[i] + adjust; + pDst[4 * i + 3] = pSrc3[i] + adjust; + } +} +const convert_32s_PXCX convert_32s_PXCX_LUT[5] = { + NULL, + convert_32s_P1C1, + convert_32s_P2C2, + convert_32s_P3C3, + convert_32s_P4C4 +}; + +/* bit depth conversions */ +/* used by PNG/TIFF up to 8bpp */ +static void convert_1u32s_C1R(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)7U); i += 8U) { + OPJ_UINT32 val = *pSrc++; + pDst[i + 0] = (OPJ_INT32)(val >> 7); + pDst[i + 1] = (OPJ_INT32)((val >> 6) & 0x1U); + pDst[i + 2] = (OPJ_INT32)((val >> 5) & 0x1U); + pDst[i + 3] = (OPJ_INT32)((val >> 4) & 0x1U); + pDst[i + 4] = (OPJ_INT32)((val >> 3) & 0x1U); + pDst[i + 5] = (OPJ_INT32)((val >> 2) & 0x1U); + pDst[i + 6] = (OPJ_INT32)((val >> 1) & 0x1U); + pDst[i + 7] = (OPJ_INT32)(val & 0x1U); + } + if (length & 7U) { + OPJ_UINT32 val = *pSrc++; + length = length & 7U; + pDst[i + 0] = (OPJ_INT32)(val >> 7); + + if (length > 1U) { + pDst[i + 1] = (OPJ_INT32)((val >> 6) & 0x1U); + if (length > 2U) { + pDst[i + 2] = (OPJ_INT32)((val >> 5) & 0x1U); + if (length > 3U) { + pDst[i + 3] = (OPJ_INT32)((val >> 4) & 0x1U); + if (length > 4U) { + pDst[i + 4] = (OPJ_INT32)((val >> 3) & 0x1U); + if (length > 5U) { + pDst[i + 5] = (OPJ_INT32)((val >> 2) & 0x1U); + if (length > 6U) { + pDst[i + 6] = (OPJ_INT32)((val >> 1) & 0x1U); + } + } + } + } + } + } + } +} +static void convert_2u32s_C1R(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)3U); i += 4U) { + OPJ_UINT32 val = *pSrc++; + pDst[i + 0] = (OPJ_INT32)(val >> 6); + pDst[i + 1] = (OPJ_INT32)((val >> 4) & 0x3U); + pDst[i + 2] = (OPJ_INT32)((val >> 2) & 0x3U); + pDst[i + 3] = (OPJ_INT32)(val & 0x3U); + } + if (length & 3U) { + OPJ_UINT32 val = *pSrc++; + length = length & 3U; + pDst[i + 0] = (OPJ_INT32)(val >> 6); + + if (length > 1U) { + pDst[i + 1] = (OPJ_INT32)((val >> 4) & 0x3U); + if (length > 2U) { + pDst[i + 2] = (OPJ_INT32)((val >> 2) & 0x3U); + + } + } + } +} +static void convert_4u32s_C1R(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)1U); i += 2U) { + OPJ_UINT32 val = *pSrc++; + pDst[i + 0] = (OPJ_INT32)(val >> 4); + pDst[i + 1] = (OPJ_INT32)(val & 0xFU); + } + if (length & 1U) { + OPJ_UINT8 val = *pSrc++; + pDst[i + 0] = (OPJ_INT32)(val >> 4); + } +} +static void convert_6u32s_C1R(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)3U); i += 4U) { + OPJ_UINT32 val0 = *pSrc++; + OPJ_UINT32 val1 = *pSrc++; + OPJ_UINT32 val2 = *pSrc++; + pDst[i + 0] = (OPJ_INT32)(val0 >> 2); + pDst[i + 1] = (OPJ_INT32)(((val0 & 0x3U) << 4) | (val1 >> 4)); + pDst[i + 2] = (OPJ_INT32)(((val1 & 0xFU) << 2) | (val2 >> 6)); + pDst[i + 3] = (OPJ_INT32)(val2 & 0x3FU); + + } + if (length & 3U) { + OPJ_UINT32 val0 = *pSrc++; + length = length & 3U; + pDst[i + 0] = (OPJ_INT32)(val0 >> 2); + + if (length > 1U) { + OPJ_UINT32 val1 = *pSrc++; + pDst[i + 1] = (OPJ_INT32)(((val0 & 0x3U) << 4) | (val1 >> 4)); + if (length > 2U) { + OPJ_UINT32 val2 = *pSrc++; + pDst[i + 2] = (OPJ_INT32)(((val1 & 0xFU) << 2) | (val2 >> 6)); + } + } + } +} +static void convert_8u32s_C1R(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < length; i++) { + pDst[i] = pSrc[i]; + } +} +const convert_XXx32s_C1R convert_XXu32s_C1R_LUT[9] = { + NULL, + convert_1u32s_C1R, + convert_2u32s_C1R, + NULL, + convert_4u32s_C1R, + NULL, + convert_6u32s_C1R, + NULL, + convert_8u32s_C1R +}; + + +static void convert_32s1u_C1R(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)7U); i += 8U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i + 0]; + OPJ_UINT32 src1 = (OPJ_UINT32)pSrc[i + 1]; + OPJ_UINT32 src2 = (OPJ_UINT32)pSrc[i + 2]; + OPJ_UINT32 src3 = (OPJ_UINT32)pSrc[i + 3]; + OPJ_UINT32 src4 = (OPJ_UINT32)pSrc[i + 4]; + OPJ_UINT32 src5 = (OPJ_UINT32)pSrc[i + 5]; + OPJ_UINT32 src6 = (OPJ_UINT32)pSrc[i + 6]; + OPJ_UINT32 src7 = (OPJ_UINT32)pSrc[i + 7]; + + *pDst++ = (OPJ_BYTE)((src0 << 7) | (src1 << 6) | (src2 << 5) | (src3 << 4) | + (src4 << 3) | (src5 << 2) | (src6 << 1) | src7); + } + + if (length & 7U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i + 0]; + OPJ_UINT32 src1 = 0U; + OPJ_UINT32 src2 = 0U; + OPJ_UINT32 src3 = 0U; + OPJ_UINT32 src4 = 0U; + OPJ_UINT32 src5 = 0U; + OPJ_UINT32 src6 = 0U; + length = length & 7U; + + if (length > 1U) { + src1 = (OPJ_UINT32)pSrc[i + 1]; + if (length > 2U) { + src2 = (OPJ_UINT32)pSrc[i + 2]; + if (length > 3U) { + src3 = (OPJ_UINT32)pSrc[i + 3]; + if (length > 4U) { + src4 = (OPJ_UINT32)pSrc[i + 4]; + if (length > 5U) { + src5 = (OPJ_UINT32)pSrc[i + 5]; + if (length > 6U) { + src6 = (OPJ_UINT32)pSrc[i + 6]; + } + } + } + } + } + } + *pDst++ = (OPJ_BYTE)((src0 << 7) | (src1 << 6) | (src2 << 5) | (src3 << 4) | + (src4 << 3) | (src5 << 2) | (src6 << 1)); + } +} + +static void convert_32s2u_C1R(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)3U); i += 4U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i + 0]; + OPJ_UINT32 src1 = (OPJ_UINT32)pSrc[i + 1]; + OPJ_UINT32 src2 = (OPJ_UINT32)pSrc[i + 2]; + OPJ_UINT32 src3 = (OPJ_UINT32)pSrc[i + 3]; + + *pDst++ = (OPJ_BYTE)((src0 << 6) | (src1 << 4) | (src2 << 2) | src3); + } + + if (length & 3U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i + 0]; + OPJ_UINT32 src1 = 0U; + OPJ_UINT32 src2 = 0U; + length = length & 3U; + + if (length > 1U) { + src1 = (OPJ_UINT32)pSrc[i + 1]; + if (length > 2U) { + src2 = (OPJ_UINT32)pSrc[i + 2]; + } + } + *pDst++ = (OPJ_BYTE)((src0 << 6) | (src1 << 4) | (src2 << 2)); + } +} + +static void convert_32s4u_C1R(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)1U); i += 2U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i + 0]; + OPJ_UINT32 src1 = (OPJ_UINT32)pSrc[i + 1]; + + *pDst++ = (OPJ_BYTE)((src0 << 4) | src1); + } + + if (length & 1U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i + 0]; + *pDst++ = (OPJ_BYTE)((src0 << 4)); + } +} + +static void convert_32s6u_C1R(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)3U); i += 4U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i + 0]; + OPJ_UINT32 src1 = (OPJ_UINT32)pSrc[i + 1]; + OPJ_UINT32 src2 = (OPJ_UINT32)pSrc[i + 2]; + OPJ_UINT32 src3 = (OPJ_UINT32)pSrc[i + 3]; + + *pDst++ = (OPJ_BYTE)((src0 << 2) | (src1 >> 4)); + *pDst++ = (OPJ_BYTE)(((src1 & 0xFU) << 4) | (src2 >> 2)); + *pDst++ = (OPJ_BYTE)(((src2 & 0x3U) << 6) | src3); + } + + if (length & 3U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i + 0]; + OPJ_UINT32 src1 = 0U; + OPJ_UINT32 src2 = 0U; + length = length & 3U; + + if (length > 1U) { + src1 = (OPJ_UINT32)pSrc[i + 1]; + if (length > 2U) { + src2 = (OPJ_UINT32)pSrc[i + 2]; + } + } + *pDst++ = (OPJ_BYTE)((src0 << 2) | (src1 >> 4)); + if (length > 1U) { + *pDst++ = (OPJ_BYTE)(((src1 & 0xFU) << 4) | (src2 >> 2)); + if (length > 2U) { + *pDst++ = (OPJ_BYTE)(((src2 & 0x3U) << 6)); + } + } + } +} +static void convert_32s8u_C1R(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < length; ++i) { + pDst[i] = (OPJ_BYTE)pSrc[i]; + } +} +const convert_32sXXx_C1R convert_32sXXu_C1R_LUT[9] = { + NULL, + convert_32s1u_C1R, + convert_32s2u_C1R, + NULL, + convert_32s4u_C1R, + NULL, + convert_32s6u_C1R, + NULL, + convert_32s8u_C1R +}; + +/* -->> -->> -->> -->> + + TGA IMAGE FORMAT + + <<-- <<-- <<-- <<-- */ + +#ifdef INFORMATION_ONLY +/* TGA header definition. */ +struct tga_header { + unsigned char id_length; /* Image id field length */ + unsigned char colour_map_type; /* Colour map type */ + unsigned char image_type; /* Image type */ + /* + ** Colour map specification + */ + unsigned short colour_map_index; /* First entry index */ + unsigned short colour_map_length; /* Colour map length */ + unsigned char colour_map_entry_size; /* Colour map entry size */ + /* + ** Image specification + */ + unsigned short x_origin; /* x origin of image */ + unsigned short y_origin; /* u origin of image */ + unsigned short image_width; /* Image width */ + unsigned short image_height; /* Image height */ + unsigned char pixel_depth; /* Pixel depth */ + unsigned char image_desc; /* Image descriptor */ +}; +#endif /* INFORMATION_ONLY */ + +/* Returns a ushort from a little-endian serialized value */ +static unsigned short get_tga_ushort(const unsigned char *data) +{ + return (unsigned short)(data[0] | (data[1] << 8)); +} + +#define TGA_HEADER_SIZE 18 + +static int tga_readheader(FILE *fp, unsigned int *bits_per_pixel, + unsigned int *width, unsigned int *height, int *flip_image) +{ + int palette_size; + unsigned char tga[TGA_HEADER_SIZE]; + unsigned char id_len, /*cmap_type,*/ image_type; + unsigned char pixel_depth, image_desc; + unsigned short /*cmap_index,*/ cmap_len, cmap_entry_size; + unsigned short /*x_origin, y_origin,*/ image_w, image_h; + + if (!bits_per_pixel || !width || !height || !flip_image) { + return 0; + } + + if (fread(tga, TGA_HEADER_SIZE, 1, fp) != 1) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + return 0 ; + } + id_len = tga[0]; + /*cmap_type = tga[1];*/ + image_type = tga[2]; + /*cmap_index = get_tga_ushort(&tga[3]);*/ + cmap_len = get_tga_ushort(&tga[5]); + cmap_entry_size = tga[7]; + + +#if 0 + x_origin = get_tga_ushort(&tga[8]); + y_origin = get_tga_ushort(&tga[10]); +#endif + image_w = get_tga_ushort(&tga[12]); + image_h = get_tga_ushort(&tga[14]); + pixel_depth = tga[16]; + image_desc = tga[17]; + + *bits_per_pixel = (unsigned int)pixel_depth; + *width = (unsigned int)image_w; + *height = (unsigned int)image_h; + + /* Ignore tga identifier, if present ... */ + if (id_len) { + unsigned char *id = (unsigned char *) malloc(id_len); + if (id == 0) { + fprintf(stderr, "tga_readheader: memory out\n"); + return 0; + } + if (!fread(id, id_len, 1, fp)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + free(id); + return 0 ; + } + free(id); + } + + /* Test for compressed formats ... not yet supported ... + // Note :- 9 - RLE encoded palettized. + // 10 - RLE encoded RGB. */ + if (image_type > 8) { + fprintf(stderr, "Sorry, compressed tga files are not currently supported.\n"); + return 0 ; + } + + *flip_image = !(image_desc & 32); + + /* Palettized formats are not yet supported, skip over the palette, if present ... */ + palette_size = cmap_len * (cmap_entry_size / 8); + + if (palette_size > 0) { + fprintf(stderr, "File contains a palette - not yet supported."); + fseek(fp, palette_size, SEEK_CUR); + } + return 1; +} + +#ifdef OPJ_BIG_ENDIAN + +static INLINE OPJ_UINT16 swap16(OPJ_UINT16 x) +{ + return (OPJ_UINT16)(((x & 0x00ffU) << 8) | ((x & 0xff00U) >> 8)); +} + +#endif + +static int tga_writeheader(FILE *fp, int bits_per_pixel, int width, int height, + OPJ_BOOL flip_image) +{ + OPJ_UINT16 image_w, image_h, us0; + unsigned char uc0, image_type; + unsigned char pixel_depth, image_desc; + + if (!bits_per_pixel || !width || !height) { + return 0; + } + + pixel_depth = 0; + + if (bits_per_pixel < 256) { + pixel_depth = (unsigned char)bits_per_pixel; + } else { + fprintf(stderr, "ERROR: Wrong bits per pixel inside tga_header"); + return 0; + } + uc0 = 0; + + if (fwrite(&uc0, 1, 1, fp) != 1) { + goto fails; /* id_length */ + } + if (fwrite(&uc0, 1, 1, fp) != 1) { + goto fails; /* colour_map_type */ + } + + image_type = 2; /* Uncompressed. */ + if (fwrite(&image_type, 1, 1, fp) != 1) { + goto fails; + } + + us0 = 0; + if (fwrite(&us0, 2, 1, fp) != 1) { + goto fails; /* colour_map_index */ + } + if (fwrite(&us0, 2, 1, fp) != 1) { + goto fails; /* colour_map_length */ + } + if (fwrite(&uc0, 1, 1, fp) != 1) { + goto fails; /* colour_map_entry_size */ + } + + if (fwrite(&us0, 2, 1, fp) != 1) { + goto fails; /* x_origin */ + } + if (fwrite(&us0, 2, 1, fp) != 1) { + goto fails; /* y_origin */ + } + + image_w = (unsigned short)width; + image_h = (unsigned short) height; + +#ifndef OPJ_BIG_ENDIAN + if (fwrite(&image_w, 2, 1, fp) != 1) { + goto fails; + } + if (fwrite(&image_h, 2, 1, fp) != 1) { + goto fails; + } +#else + image_w = swap16(image_w); + image_h = swap16(image_h); + if (fwrite(&image_w, 2, 1, fp) != 1) { + goto fails; + } + if (fwrite(&image_h, 2, 1, fp) != 1) { + goto fails; + } +#endif + + if (fwrite(&pixel_depth, 1, 1, fp) != 1) { + goto fails; + } + + image_desc = 8; /* 8 bits per component. */ + + if (flip_image) { + image_desc |= 32; + } + if (fwrite(&image_desc, 1, 1, fp) != 1) { + goto fails; + } + + return 1; + +fails: + fputs("\nwrite_tgaheader: write ERROR\n", stderr); + return 0; +} + +opj_image_t* tgatoimage(const char *filename, opj_cparameters_t *parameters) +{ + FILE *f; + opj_image_t *image; + unsigned int image_width, image_height, pixel_bit_depth; + unsigned int x, y; + int flip_image = 0; + opj_image_cmptparm_t cmptparm[4]; /* maximum 4 components */ + int numcomps; + OPJ_COLOR_SPACE color_space; + OPJ_BOOL mono ; + OPJ_BOOL save_alpha; + int subsampling_dx, subsampling_dy; + int i; + + f = fopen(filename, "rb"); + if (!f) { + fprintf(stderr, "Failed to open %s for reading !!\n", filename); + return 0; + } + + if (!tga_readheader(f, &pixel_bit_depth, &image_width, &image_height, + &flip_image)) { + fclose(f); + return NULL; + } + + /* We currently only support 24 & 32 bit tga's ... */ + if (!((pixel_bit_depth == 24) || (pixel_bit_depth == 32))) { + fclose(f); + return NULL; + } + + /* initialize image components */ + memset(&cmptparm[0], 0, 4 * sizeof(opj_image_cmptparm_t)); + + mono = (pixel_bit_depth == 8) || + (pixel_bit_depth == 16); /* Mono with & without alpha. */ + save_alpha = (pixel_bit_depth == 16) || + (pixel_bit_depth == 32); /* Mono with alpha, or RGB with alpha */ + + if (mono) { + color_space = OPJ_CLRSPC_GRAY; + numcomps = save_alpha ? 2 : 1; + } else { + numcomps = save_alpha ? 4 : 3; + color_space = OPJ_CLRSPC_SRGB; + } + + /* If the declared file size is > 10 MB, check that the file is big */ + /* enough to avoid excessive memory allocations */ + if (image_height != 0 && + image_width > 10000000U / image_height / (OPJ_UINT32)numcomps) { + char ch; + OPJ_UINT64 expected_file_size = + (OPJ_UINT64)image_width * image_height * (OPJ_UINT32)numcomps; + long curpos = ftell(f); + if (expected_file_size > (OPJ_UINT64)INT_MAX) { + expected_file_size = (OPJ_UINT64)INT_MAX; + } + fseek(f, (long)expected_file_size - 1, SEEK_SET); + if (fread(&ch, 1, 1, f) != 1) { + fclose(f); + return NULL; + } + fseek(f, curpos, SEEK_SET); + } + + subsampling_dx = parameters->subsampling_dx; + subsampling_dy = parameters->subsampling_dy; + + for (i = 0; i < numcomps; i++) { + cmptparm[i].prec = 8; + cmptparm[i].bpp = 8; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = (OPJ_UINT32)subsampling_dx; + cmptparm[i].dy = (OPJ_UINT32)subsampling_dy; + cmptparm[i].w = image_width; + cmptparm[i].h = image_height; + } + + /* create the image */ + image = opj_image_create((OPJ_UINT32)numcomps, &cmptparm[0], color_space); + + if (!image) { + fclose(f); + return NULL; + } + + + /* set image offset and reference grid */ + image->x0 = (OPJ_UINT32)parameters->image_offset_x0; + image->y0 = (OPJ_UINT32)parameters->image_offset_y0; + image->x1 = !image->x0 ? (OPJ_UINT32)(image_width - 1) * + (OPJ_UINT32)subsampling_dx + 1 : image->x0 + (OPJ_UINT32)(image_width - 1) * + (OPJ_UINT32)subsampling_dx + 1; + image->y1 = !image->y0 ? (OPJ_UINT32)(image_height - 1) * + (OPJ_UINT32)subsampling_dy + 1 : image->y0 + (OPJ_UINT32)(image_height - 1) * + (OPJ_UINT32)subsampling_dy + 1; + + /* set image data */ + for (y = 0; y < image_height; y++) { + int index; + + if (flip_image) { + index = (int)((image_height - y - 1) * image_width); + } else { + index = (int)(y * image_width); + } + + if (numcomps == 3) { + for (x = 0; x < image_width; x++) { + unsigned char r, g, b; + + if (!fread(&b, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + opj_image_destroy(image); + fclose(f); + return NULL; + } + if (!fread(&g, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + opj_image_destroy(image); + fclose(f); + return NULL; + } + if (!fread(&r, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + opj_image_destroy(image); + fclose(f); + return NULL; + } + + image->comps[0].data[index] = r; + image->comps[1].data[index] = g; + image->comps[2].data[index] = b; + index++; + } + } else if (numcomps == 4) { + for (x = 0; x < image_width; x++) { + unsigned char r, g, b, a; + if (!fread(&b, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + opj_image_destroy(image); + fclose(f); + return NULL; + } + if (!fread(&g, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + opj_image_destroy(image); + fclose(f); + return NULL; + } + if (!fread(&r, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + opj_image_destroy(image); + fclose(f); + return NULL; + } + if (!fread(&a, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + opj_image_destroy(image); + fclose(f); + return NULL; + } + + image->comps[0].data[index] = r; + image->comps[1].data[index] = g; + image->comps[2].data[index] = b; + image->comps[3].data[index] = a; + index++; + } + } else { + fprintf(stderr, "Currently unsupported bit depth : %s\n", filename); + } + } + fclose(f); + return image; +} + +int imagetotga(opj_image_t * image, const char *outfile) +{ + int width, height, bpp, x, y; + OPJ_BOOL write_alpha; + unsigned int i; + int adjustR, adjustG = 0, adjustB = 0, fails; + unsigned int alpha_channel; + float r, g, b, a; + unsigned char value; + float scale; + FILE *fdest; + size_t res; + fails = 1; + + fdest = fopen(outfile, "wb"); + if (!fdest) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", outfile); + return 1; + } + + for (i = 0; i < image->numcomps - 1; i++) { + if ((image->comps[0].dx != image->comps[i + 1].dx) + || (image->comps[0].dy != image->comps[i + 1].dy) + || (image->comps[0].prec != image->comps[i + 1].prec) + || (image->comps[0].sgnd != image->comps[i + 1].sgnd)) { + fclose(fdest); + fprintf(stderr, + "Unable to create a tga file with such J2K image charateristics.\n"); + return 1; + } + } + + width = (int)image->comps[0].w; + height = (int)image->comps[0].h; + + /* Mono with alpha, or RGB with alpha. */ + write_alpha = (image->numcomps == 2) || (image->numcomps == 4); + + /* Write TGA header */ + bpp = write_alpha ? 32 : 24; + + if (!tga_writeheader(fdest, bpp, width, height, OPJ_TRUE)) { + goto fin; + } + + alpha_channel = image->numcomps - 1; + + scale = 255.0f / (float)((1 << image->comps[0].prec) - 1); + + adjustR = (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + if (image->numcomps >= 3) { + adjustG = (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); + adjustB = (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); + } + + for (y = 0; y < height; y++) { + unsigned int index = (unsigned int)(y * width); + + for (x = 0; x < width; x++, index++) { + r = (float)(image->comps[0].data[index] + adjustR); + + if (image->numcomps > 2) { + g = (float)(image->comps[1].data[index] + adjustG); + b = (float)(image->comps[2].data[index] + adjustB); + } else { + /* Greyscale ... */ + g = r; + b = r; + } + + /* TGA format writes BGR ... */ + if (b > 255.) { + b = 255.; + } else if (b < 0.) { + b = 0.; + } + value = (unsigned char)(b * scale); + res = fwrite(&value, 1, 1, fdest); + + if (res < 1) { + fprintf(stderr, "failed to write 1 byte for %s\n", outfile); + goto fin; + } + if (g > 255.) { + g = 255.; + } else if (g < 0.) { + g = 0.; + } + value = (unsigned char)(g * scale); + res = fwrite(&value, 1, 1, fdest); + + if (res < 1) { + fprintf(stderr, "failed to write 1 byte for %s\n", outfile); + goto fin; + } + if (r > 255.) { + r = 255.; + } else if (r < 0.) { + r = 0.; + } + value = (unsigned char)(r * scale); + res = fwrite(&value, 1, 1, fdest); + + if (res < 1) { + fprintf(stderr, "failed to write 1 byte for %s\n", outfile); + goto fin; + } + + if (write_alpha) { + a = (float)(image->comps[alpha_channel].data[index]); + if (a > 255.) { + a = 255.; + } else if (a < 0.) { + a = 0.; + } + value = (unsigned char)(a * scale); + res = fwrite(&value, 1, 1, fdest); + + if (res < 1) { + fprintf(stderr, "failed to write 1 byte for %s\n", outfile); + goto fin; + } + } + } + } + fails = 0; +fin: + fclose(fdest); + + return fails; +} + +/* -->> -->> -->> -->> + +PGX IMAGE FORMAT + +<<-- <<-- <<-- <<-- */ + + +static unsigned char readuchar(FILE * f) +{ + unsigned char c1; + if (!fread(&c1, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + return 0; + } + return c1; +} + +static unsigned short readushort(FILE * f, int bigendian) +{ + unsigned char c1, c2; + if (!fread(&c1, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + return 0; + } + if (!fread(&c2, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + return 0; + } + if (bigendian) { + return (unsigned short)((c1 << 8) + c2); + } else { + return (unsigned short)((c2 << 8) + c1); + } +} + +static unsigned int readuint(FILE * f, int bigendian) +{ + unsigned char c1, c2, c3, c4; + if (!fread(&c1, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + return 0; + } + if (!fread(&c2, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + return 0; + } + if (!fread(&c3, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + return 0; + } + if (!fread(&c4, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + return 0; + } + if (bigendian) { + return (unsigned int)(c1 << 24) + (unsigned int)(c2 << 16) + (unsigned int)( + c3 << 8) + c4; + } else { + return (unsigned int)(c4 << 24) + (unsigned int)(c3 << 16) + (unsigned int)( + c2 << 8) + c1; + } +} + +opj_image_t* pgxtoimage(const char *filename, opj_cparameters_t *parameters) +{ + FILE *f = NULL; + int w, h, prec; + int i, numcomps, max; + OPJ_COLOR_SPACE color_space; + opj_image_cmptparm_t cmptparm; /* maximum of 1 component */ + opj_image_t * image = NULL; + int adjustS, ushift, dshift, force8; + OPJ_UINT64 expected_file_size; + + char endian1, endian2, sign; + char signtmp[32]; + + char temp[32]; + int bigendian; + opj_image_comp_t *comp = NULL; + + numcomps = 1; + color_space = OPJ_CLRSPC_GRAY; + + memset(&cmptparm, 0, sizeof(opj_image_cmptparm_t)); + + max = 0; + + f = fopen(filename, "rb"); + if (!f) { + fprintf(stderr, "Failed to open %s for reading !\n", filename); + return NULL; + } + + fseek(f, 0, SEEK_SET); + if (fscanf(f, "PG%31[ \t]%c%c%31[ \t+-]%d%31[ \t]%d%31[ \t]%d", temp, &endian1, + &endian2, signtmp, &prec, temp, &w, temp, &h) != 9) { + fclose(f); + fprintf(stderr, + "ERROR: Failed to read the right number of element from the fscanf() function!\n"); + return NULL; + } + + i = 0; + sign = '+'; + while (signtmp[i] != '\0') { + if (signtmp[i] == '-') { + sign = '-'; + } + i++; + } + + fgetc(f); + if (endian1 == 'M' && endian2 == 'L') { + bigendian = 1; + } else if (endian2 == 'M' && endian1 == 'L') { + bigendian = 0; + } else { + fclose(f); + fprintf(stderr, "Bad pgx header, please check input file\n"); + return NULL; + } + + if (w < 1 || h < 1 || prec < 1 || prec > 31) { + fclose(f); + fprintf(stderr, "Bad pgx header, please check input file\n"); + return NULL; + } + + expected_file_size = + (OPJ_UINT64)w * (OPJ_UINT64)h * (prec > 16 ? 4 : prec > 8 ? 2 : 1); + if (expected_file_size > 10000000U) { + char ch; + long curpos = ftell(f); + if (expected_file_size > (OPJ_UINT64)INT_MAX) { + expected_file_size = (OPJ_UINT64)INT_MAX; + } + fseek(f, (long)expected_file_size - 1, SEEK_SET); + if (fread(&ch, 1, 1, f) != 1) { + fprintf(stderr, "File too short\n"); + fclose(f); + return NULL; + } + fseek(f, curpos, SEEK_SET); + } + + /* initialize image component */ + + cmptparm.x0 = (OPJ_UINT32)parameters->image_offset_x0; + cmptparm.y0 = (OPJ_UINT32)parameters->image_offset_y0; + cmptparm.w = !cmptparm.x0 ? (OPJ_UINT32)((w - 1) * parameters->subsampling_dx + + 1) : cmptparm.x0 + (OPJ_UINT32)(w - 1) * (OPJ_UINT32)parameters->subsampling_dx + + 1; + cmptparm.h = !cmptparm.y0 ? (OPJ_UINT32)((h - 1) * parameters->subsampling_dy + + 1) : cmptparm.y0 + (OPJ_UINT32)(h - 1) * (OPJ_UINT32)parameters->subsampling_dy + + 1; + + if (sign == '-') { + cmptparm.sgnd = 1; + } else { + cmptparm.sgnd = 0; + } + if (prec < 8) { + force8 = 1; + ushift = 8 - prec; + dshift = prec - ushift; + if (cmptparm.sgnd) { + adjustS = (1 << (prec - 1)); + } else { + adjustS = 0; + } + cmptparm.sgnd = 0; + prec = 8; + } else { + ushift = dshift = force8 = adjustS = 0; + } + + cmptparm.prec = (OPJ_UINT32)prec; + cmptparm.bpp = (OPJ_UINT32)prec; + cmptparm.dx = (OPJ_UINT32)parameters->subsampling_dx; + cmptparm.dy = (OPJ_UINT32)parameters->subsampling_dy; + + /* create the image */ + image = opj_image_create((OPJ_UINT32)numcomps, &cmptparm, color_space); + if (!image) { + fclose(f); + return NULL; + } + /* set image offset and reference grid */ + image->x0 = cmptparm.x0; + image->y0 = cmptparm.x0; + image->x1 = cmptparm.w; + image->y1 = cmptparm.h; + + /* set image data */ + + comp = &image->comps[0]; + + for (i = 0; i < w * h; i++) { + int v; + if (force8) { + v = readuchar(f) + adjustS; + v = (v << ushift) + (v >> dshift); + comp->data[i] = (unsigned char)v; + + if (v > max) { + max = v; + } + + continue; + } + if (comp->prec == 8) { + if (!comp->sgnd) { + v = readuchar(f); + } else { + v = (char) readuchar(f); + } + } else if (comp->prec <= 16) { + if (!comp->sgnd) { + v = readushort(f, bigendian); + } else { + v = (short) readushort(f, bigendian); + } + } else { + if (!comp->sgnd) { + v = (int)readuint(f, bigendian); + } else { + v = (int) readuint(f, bigendian); + } + } + if (v > max) { + max = v; + } + comp->data[i] = v; + } + fclose(f); + comp->bpp = (OPJ_UINT32)int_floorlog2(max) + 1; + + return image; +} + +#define CLAMP(x,a,b) ((x) < (a) ? (a) : ((x) > (b) ? (b) : (x))) + +static INLINE int clamp(const int value, const int prec, const int sgnd) +{ + if (sgnd) { + if (prec <= 8) { + return CLAMP(value, -128, 127); + } else if (prec <= 16) { + return CLAMP(value, -32768, 32767); + } else { + return CLAMP(value, -2147483647 - 1, 2147483647); + } + } else { + if (prec <= 8) { + return CLAMP(value, 0, 255); + } else if (prec <= 16) { + return CLAMP(value, 0, 65535); + } else { + return value; /*CLAMP(value,0,4294967295);*/ + } + } +} + +int imagetopgx(opj_image_t * image, const char *outfile) +{ + int w, h; + int i, j, fails = 1; + unsigned int compno; + FILE *fdest = NULL; + + for (compno = 0; compno < image->numcomps; compno++) { + opj_image_comp_t *comp = &image->comps[compno]; + char bname[256]; /* buffer for name */ + char *name = bname; /* pointer */ + int nbytes = 0; + size_t res; + const size_t olen = strlen(outfile); + const size_t dotpos = olen - 4; + const size_t total = dotpos + 1 + 1 + 4; /* '-' + '[1-3]' + '.pgx' */ + + if (outfile[dotpos] != '.') { + /* `pgx` was recognized but there is no dot at expected position */ + fprintf(stderr, "ERROR -> Impossible happen."); + goto fin; + } + if (total > 256) { + name = (char*)malloc(total + 1); + if (name == NULL) { + fprintf(stderr, "imagetopgx: memory out\n"); + goto fin; + } + } + strncpy(name, outfile, dotpos); + sprintf(name + dotpos, "_%u.pgx", compno); + fdest = fopen(name, "wb"); + /* don't need name anymore */ + + if (!fdest) { + + fprintf(stderr, "ERROR -> failed to open %s for writing\n", name); + if (total > 256) { + free(name); + } + goto fin; + } + + w = (int)image->comps[compno].w; + h = (int)image->comps[compno].h; + + fprintf(fdest, "PG ML %c %d %d %d\n", comp->sgnd ? '-' : '+', comp->prec, + w, h); + + if (comp->prec <= 8) { + nbytes = 1; + } else if (comp->prec <= 16) { + nbytes = 2; + } else { + nbytes = 4; + } + + if (nbytes == 1) { + unsigned char* line_buffer = malloc((size_t)w); + if (line_buffer == NULL) { + fprintf(stderr, "Out of memory"); + goto fin; + } + for (j = 0; j < h; j++) { + if (comp->prec == 8 && comp->sgnd == 0) { + for (i = 0; i < w; i++) { + line_buffer[i] = (unsigned char)CLAMP(image->comps[compno].data[j * w + i], 0, + 255); + } + } else { + for (i = 0; i < w; i++) { + line_buffer[i] = (unsigned char) + clamp(image->comps[compno].data[j * w + i], + (int)comp->prec, (int)comp->sgnd); + } + } + res = fwrite(line_buffer, 1, (size_t)w, fdest); + if (res != (size_t)w) { + fprintf(stderr, "failed to write %d bytes for %s\n", w, name); + if (total > 256) { + free(name); + } + free(line_buffer); + goto fin; + } + } + free(line_buffer); + } else { + + for (i = 0; i < w * h; i++) { + /* FIXME: clamp func is being called within a loop */ + const int val = clamp(image->comps[compno].data[i], + (int)comp->prec, (int)comp->sgnd); + + for (j = nbytes - 1; j >= 0; j--) { + int v = (int)(val >> (j * 8)); + unsigned char byte = (unsigned char)v; + res = fwrite(&byte, 1, 1, fdest); + + if (res < 1) { + fprintf(stderr, "failed to write 1 byte for %s\n", name); + if (total > 256) { + free(name); + } + goto fin; + } + } + } + } + + if (total > 256) { + free(name); + } + fclose(fdest); + fdest = NULL; + } + fails = 0; +fin: + if (fdest) { + fclose(fdest); + } + + return fails; +} + +/* -->> -->> -->> -->> + +PNM IMAGE FORMAT + +<<-- <<-- <<-- <<-- */ + +struct pnm_header { + int width, height, maxval, depth, format; + char rgb, rgba, gray, graya, bw; + char ok; +}; + +static char *skip_white(char *s) +{ + if (s != NULL) { + while (*s) { + if (*s == '\n' || *s == '\r') { + return NULL; + } + if (isspace(*s)) { + ++s; + continue; + } + return s; + } + } + return NULL; +} + +static char *skip_int(char *start, int *out_n) +{ + char *s; + char c; + + *out_n = 0; + + s = skip_white(start); + if (s == NULL) { + return NULL; + } + start = s; + + while (*s) { + if (!isdigit(*s)) { + break; + } + ++s; + } + c = *s; + *s = 0; + *out_n = atoi(start); + *s = c; + return s; +} + +static char *skip_idf(char *start, char out_idf[256]) +{ + char *s; + char c; + + s = skip_white(start); + if (s == NULL) { + return NULL; + } + start = s; + + while (*s) { + if (isalpha(*s) || *s == '_') { + ++s; + continue; + } + break; + } + c = *s; + *s = 0; + strncpy(out_idf, start, 255); + *s = c; + return s; +} + +static void read_pnm_header(FILE *reader, struct pnm_header *ph) +{ + int format, end, ttype; + char idf[256], type[256]; + char line[256]; + + if (fgets(line, 250, reader) == NULL) { + fprintf(stderr, "\nWARNING: fgets return a NULL value"); + return; + } + + if (line[0] != 'P') { + fprintf(stderr, "read_pnm_header:PNM:magic P missing\n"); + return; + } + format = atoi(line + 1); + if (format < 1 || format > 7) { + fprintf(stderr, "read_pnm_header:magic format %d invalid\n", format); + return; + } + ph->format = format; + ttype = end = 0; + + while (fgets(line, 250, reader)) { + char *s; + int allow_null = 0; + + if (*line == '#') { + continue; + } + + s = line; + + if (format == 7) { + s = skip_idf(s, idf); + + if (s == NULL || *s == 0) { + return; + } + + if (strcmp(idf, "ENDHDR") == 0) { + end = 1; + break; + } + if (strcmp(idf, "WIDTH") == 0) { + s = skip_int(s, &ph->width); + if (s == NULL || *s == 0) { + return; + } + + continue; + } + if (strcmp(idf, "HEIGHT") == 0) { + s = skip_int(s, &ph->height); + if (s == NULL || *s == 0) { + return; + } + + continue; + } + if (strcmp(idf, "DEPTH") == 0) { + s = skip_int(s, &ph->depth); + if (s == NULL || *s == 0) { + return; + } + + continue; + } + if (strcmp(idf, "MAXVAL") == 0) { + s = skip_int(s, &ph->maxval); + if (s == NULL || *s == 0) { + return; + } + + continue; + } + if (strcmp(idf, "TUPLTYPE") == 0) { + s = skip_idf(s, type); + if (s == NULL || *s == 0) { + return; + } + + if (strcmp(type, "BLACKANDWHITE") == 0) { + ph->bw = 1; + ttype = 1; + continue; + } + if (strcmp(type, "GRAYSCALE") == 0) { + ph->gray = 1; + ttype = 1; + continue; + } + if (strcmp(type, "GRAYSCALE_ALPHA") == 0) { + ph->graya = 1; + ttype = 1; + continue; + } + if (strcmp(type, "RGB") == 0) { + ph->rgb = 1; + ttype = 1; + continue; + } + if (strcmp(type, "RGB_ALPHA") == 0) { + ph->rgba = 1; + ttype = 1; + continue; + } + fprintf(stderr, "read_pnm_header:unknown P7 TUPLTYPE %s\n", type); + return; + } + fprintf(stderr, "read_pnm_header:unknown P7 idf %s\n", idf); + return; + } /* if(format == 7) */ + + /* Here format is in range [1,6] */ + if (ph->width == 0) { + s = skip_int(s, &ph->width); + if ((s == NULL) || (*s == 0) || (ph->width < 1)) { + return; + } + allow_null = 1; + } + if (ph->height == 0) { + s = skip_int(s, &ph->height); + if ((s == NULL) && allow_null) { + continue; + } + if ((s == NULL) || (*s == 0) || (ph->height < 1)) { + return; + } + if (format == 1 || format == 4) { + break; + } + allow_null = 1; + } + /* here, format is in P2, P3, P5, P6 */ + s = skip_int(s, &ph->maxval); + if ((s == NULL) && allow_null) { + continue; + } + if ((s == NULL) || (*s == 0)) { + return; + } + break; + }/* while(fgets( ) */ + if (format == 2 || format == 3 || format > 4) { + if (ph->maxval < 1 || ph->maxval > 65535) { + return; + } + } + if (ph->width < 1 || ph->height < 1) { + return; + } + + if (format == 7) { + if (!end) { + fprintf(stderr, "read_pnm_header:P7 without ENDHDR\n"); + return; + } + if (ph->depth < 1 || ph->depth > 4) { + return; + } + + if (ttype) { + ph->ok = 1; + } + } else { + ph->ok = 1; + if (format == 1 || format == 4) { + ph->maxval = 255; + } + } +} + +static int has_prec(int val) +{ + if (val < 2) { + return 1; + } + if (val < 4) { + return 2; + } + if (val < 8) { + return 3; + } + if (val < 16) { + return 4; + } + if (val < 32) { + return 5; + } + if (val < 64) { + return 6; + } + if (val < 128) { + return 7; + } + if (val < 256) { + return 8; + } + if (val < 512) { + return 9; + } + if (val < 1024) { + return 10; + } + if (val < 2048) { + return 11; + } + if (val < 4096) { + return 12; + } + if (val < 8192) { + return 13; + } + if (val < 16384) { + return 14; + } + if (val < 32768) { + return 15; + } + return 16; +} + +opj_image_t* pnmtoimage(const char *filename, opj_cparameters_t *parameters) +{ + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + + FILE *fp = NULL; + int i, compno, numcomps, w, h, prec, format; + OPJ_COLOR_SPACE color_space; + opj_image_cmptparm_t cmptparm[4]; /* RGBA: max. 4 components */ + opj_image_t * image = NULL; + struct pnm_header header_info; + + if ((fp = fopen(filename, "rb")) == NULL) { + fprintf(stderr, "pnmtoimage:Failed to open %s for reading!\n", filename); + return NULL; + } + memset(&header_info, 0, sizeof(struct pnm_header)); + + read_pnm_header(fp, &header_info); + + if (!header_info.ok) { + fclose(fp); + return NULL; + } + + /* This limitation could be removed by making sure to use size_t below */ + if (header_info.height != 0 && + header_info.width > INT_MAX / header_info.height) { + fprintf(stderr, "pnmtoimage:Image %dx%d too big!\n", + header_info.width, header_info.height); + fclose(fp); + return NULL; + } + + format = header_info.format; + + switch (format) { + case 1: /* ascii bitmap */ + case 4: /* raw bitmap */ + numcomps = 1; + break; + + case 2: /* ascii greymap */ + case 5: /* raw greymap */ + numcomps = 1; + break; + + case 3: /* ascii pixmap */ + case 6: /* raw pixmap */ + numcomps = 3; + break; + + case 7: /* arbitrary map */ + numcomps = header_info.depth; + break; + + default: + fclose(fp); + return NULL; + } + if (numcomps < 3) { + color_space = OPJ_CLRSPC_GRAY; /* GRAY, GRAYA */ + } else { + color_space = OPJ_CLRSPC_SRGB; /* RGB, RGBA */ + } + + prec = has_prec(header_info.maxval); + + if (prec < 8) { + prec = 8; + } + + w = header_info.width; + h = header_info.height; + subsampling_dx = parameters->subsampling_dx; + subsampling_dy = parameters->subsampling_dy; + + memset(&cmptparm[0], 0, (size_t)numcomps * sizeof(opj_image_cmptparm_t)); + + for (i = 0; i < numcomps; i++) { + cmptparm[i].prec = (OPJ_UINT32)prec; + cmptparm[i].bpp = (OPJ_UINT32)prec; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = (OPJ_UINT32)subsampling_dx; + cmptparm[i].dy = (OPJ_UINT32)subsampling_dy; + cmptparm[i].w = (OPJ_UINT32)w; + cmptparm[i].h = (OPJ_UINT32)h; + } + image = opj_image_create((OPJ_UINT32)numcomps, &cmptparm[0], color_space); + + if (!image) { + fclose(fp); + return NULL; + } + + /* set image offset and reference grid */ + image->x0 = (OPJ_UINT32)parameters->image_offset_x0; + image->y0 = (OPJ_UINT32)parameters->image_offset_y0; + image->x1 = (OPJ_UINT32)(parameters->image_offset_x0 + (w - 1) * subsampling_dx + + 1); + image->y1 = (OPJ_UINT32)(parameters->image_offset_y0 + (h - 1) * subsampling_dy + + 1); + + if ((format == 2) || (format == 3)) { /* ascii pixmap */ + unsigned int index; + + for (i = 0; i < w * h; i++) { + for (compno = 0; compno < numcomps; compno++) { + index = 0; + if (fscanf(fp, "%u", &index) != 1) { + fprintf(stderr, + "\nWARNING: fscanf return a number of element different from the expected.\n"); + } + + image->comps[compno].data[i] = (OPJ_INT32)(index * 255) / header_info.maxval; + } + } + } else if ((format == 5) + || (format == 6) + || ((format == 7) + && (header_info.gray || header_info.graya + || header_info.rgb || header_info.rgba))) { /* binary pixmap */ + unsigned char c0, c1, one; + + one = (prec < 9); + + for (i = 0; i < w * h; i++) { + for (compno = 0; compno < numcomps; compno++) { + if (!fread(&c0, 1, 1, fp)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + opj_image_destroy(image); + fclose(fp); + return NULL; + } + if (one) { + image->comps[compno].data[i] = c0; + } else { + if (!fread(&c1, 1, 1, fp)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + } + /* netpbm: */ + image->comps[compno].data[i] = ((c0 << 8) | c1); + } + } + } + } else if (format == 1) { /* ascii bitmap */ + for (i = 0; i < w * h; i++) { + unsigned int index; + + if (fscanf(fp, "%u", &index) != 1) { + fprintf(stderr, + "\nWARNING: fscanf return a number of element different from the expected.\n"); + } + + image->comps[0].data[i] = (index ? 0 : 255); + } + } else if (format == 4) { + int x, y, bit; + unsigned char uc; + + i = 0; + for (y = 0; y < h; ++y) { + bit = -1; + uc = 0; + + for (x = 0; x < w; ++x) { + if (bit == -1) { + bit = 7; + uc = (unsigned char)getc(fp); + } + image->comps[0].data[i] = (((uc >> bit) & 1) ? 0 : 255); + --bit; + ++i; + } + } + } else if ((format == 7 && header_info.bw)) { /*MONO*/ + unsigned char uc; + + for (i = 0; i < w * h; ++i) { + if (!fread(&uc, 1, 1, fp)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + } + image->comps[0].data[i] = (uc & 1) ? 0 : 255; + } + } + fclose(fp); + + return image; +}/* pnmtoimage() */ + +static int are_comps_similar(opj_image_t * image) +{ + unsigned int i; + for (i = 1; i < image->numcomps; i++) { + if (image->comps[0].dx != image->comps[i].dx || + image->comps[0].dy != image->comps[i].dy || + (i <= 2 && + (image->comps[0].prec != image->comps[i].prec || + image->comps[0].sgnd != image->comps[i].sgnd))) { + return OPJ_FALSE; + } + } + return OPJ_TRUE; +} + + +int imagetopnm(opj_image_t * image, const char *outfile, int force_split) +{ + int *red, *green, *blue, *alpha; + int wr, hr, max; + int i; + unsigned int compno, ncomp; + int adjustR, adjustG, adjustB, adjustA; + int fails, two, want_gray, has_alpha, triple; + int prec, v; + FILE *fdest = NULL; + const char *tmp = outfile; + char *destname; + + alpha = NULL; + + if ((prec = (int)image->comps[0].prec) > 16) { + fprintf(stderr, "%s:%d:imagetopnm\n\tprecision %d is larger than 16" + "\n\t: refused.\n", __FILE__, __LINE__, prec); + return 1; + } + two = has_alpha = 0; + fails = 1; + ncomp = image->numcomps; + + while (*tmp) { + ++tmp; + } + tmp -= 2; + want_gray = (*tmp == 'g' || *tmp == 'G'); + ncomp = image->numcomps; + + if (want_gray) { + ncomp = 1; + } + + if ((force_split == 0) && ncomp >= 2 && + are_comps_similar(image)) { + fdest = fopen(outfile, "wb"); + + if (!fdest) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", outfile); + return fails; + } + two = (prec > 8); + triple = (ncomp > 2); + wr = (int)image->comps[0].w; + hr = (int)image->comps[0].h; + max = (1 << prec) - 1; + has_alpha = (ncomp == 4 || ncomp == 2); + + red = image->comps[0].data; + + if (triple) { + green = image->comps[1].data; + blue = image->comps[2].data; + } else { + green = blue = NULL; + } + + if (has_alpha) { + const char *tt = (triple ? "RGB_ALPHA" : "GRAYSCALE_ALPHA"); + + fprintf(fdest, "P7\n# OpenJPEG-%s\nWIDTH %d\nHEIGHT %d\nDEPTH %u\n" + "MAXVAL %d\nTUPLTYPE %s\nENDHDR\n", opj_version(), + wr, hr, ncomp, max, tt); + alpha = image->comps[ncomp - 1].data; + adjustA = (image->comps[ncomp - 1].sgnd ? + 1 << (image->comps[ncomp - 1].prec - 1) : 0); + } else { + fprintf(fdest, "P6\n# OpenJPEG-%s\n%d %d\n%d\n", + opj_version(), wr, hr, max); + adjustA = 0; + } + adjustR = (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + + if (triple) { + adjustG = (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); + adjustB = (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); + } else { + adjustG = adjustB = 0; + } + + for (i = 0; i < wr * hr; ++i) { + if (two) { + v = *red + adjustR; + ++red; + if (v > 65535) { + v = 65535; + } else if (v < 0) { + v = 0; + } + + /* netpbm: */ + fprintf(fdest, "%c%c", (unsigned char)(v >> 8), (unsigned char)v); + + if (triple) { + v = *green + adjustG; + ++green; + if (v > 65535) { + v = 65535; + } else if (v < 0) { + v = 0; + } + + /* netpbm: */ + fprintf(fdest, "%c%c", (unsigned char)(v >> 8), (unsigned char)v); + + v = *blue + adjustB; + ++blue; + if (v > 65535) { + v = 65535; + } else if (v < 0) { + v = 0; + } + + /* netpbm: */ + fprintf(fdest, "%c%c", (unsigned char)(v >> 8), (unsigned char)v); + + }/* if(triple) */ + + if (has_alpha) { + v = *alpha + adjustA; + ++alpha; + if (v > 65535) { + v = 65535; + } else if (v < 0) { + v = 0; + } + + /* netpbm: */ + fprintf(fdest, "%c%c", (unsigned char)(v >> 8), (unsigned char)v); + } + continue; + + } /* if(two) */ + + /* prec <= 8: */ + v = *red++; + if (v > 255) { + v = 255; + } else if (v < 0) { + v = 0; + } + + fprintf(fdest, "%c", (unsigned char)v); + if (triple) { + v = *green++; + if (v > 255) { + v = 255; + } else if (v < 0) { + v = 0; + } + + fprintf(fdest, "%c", (unsigned char)v); + v = *blue++; + if (v > 255) { + v = 255; + } else if (v < 0) { + v = 0; + } + + fprintf(fdest, "%c", (unsigned char)v); + } + if (has_alpha) { + v = *alpha++; + if (v > 255) { + v = 255; + } else if (v < 0) { + v = 0; + } + + fprintf(fdest, "%c", (unsigned char)v); + } + } /* for(i */ + + fclose(fdest); + return 0; + } + + /* YUV or MONO: */ + + if (image->numcomps > ncomp) { + fprintf(stderr, "WARNING -> [PGM file] Only the first component\n"); + fprintf(stderr, " is written to the file\n"); + } + destname = (char*)malloc(strlen(outfile) + 8); + if (destname == NULL) { + fprintf(stderr, "imagetopnm: memory out\n"); + return 1; + } + for (compno = 0; compno < ncomp; compno++) { + if (ncomp > 1) { + /*sprintf(destname, "%d.%s", compno, outfile);*/ + const size_t olen = strlen(outfile); + const size_t dotpos = olen - 4; + + strncpy(destname, outfile, dotpos); + sprintf(destname + dotpos, "_%u.pgm", compno); + } else { + sprintf(destname, "%s", outfile); + } + + fdest = fopen(destname, "wb"); + if (!fdest) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", destname); + free(destname); + return 1; + } + wr = (int)image->comps[compno].w; + hr = (int)image->comps[compno].h; + prec = (int)image->comps[compno].prec; + max = (1 << prec) - 1; + + fprintf(fdest, "P5\n#OpenJPEG-%s\n%d %d\n%d\n", + opj_version(), wr, hr, max); + + red = image->comps[compno].data; + adjustR = + (image->comps[compno].sgnd ? 1 << (image->comps[compno].prec - 1) : 0); + + if (prec > 8) { + for (i = 0; i < wr * hr; i++) { + v = *red + adjustR; + ++red; + if (v > 65535) { + v = 65535; + } else if (v < 0) { + v = 0; + } + + /* netpbm: */ + fprintf(fdest, "%c%c", (unsigned char)(v >> 8), (unsigned char)v); + + if (has_alpha) { + v = *alpha++; + if (v > 65535) { + v = 65535; + } else if (v < 0) { + v = 0; + } + + /* netpbm: */ + fprintf(fdest, "%c%c", (unsigned char)(v >> 8), (unsigned char)v); + } + }/* for(i */ + } else { /* prec <= 8 */ + for (i = 0; i < wr * hr; ++i) { + v = *red + adjustR; + ++red; + if (v > 255) { + v = 255; + } else if (v < 0) { + v = 0; + } + + fprintf(fdest, "%c", (unsigned char)v); + } + } + fclose(fdest); + } /* for (compno */ + free(destname); + + return 0; +}/* imagetopnm() */ + +/* -->> -->> -->> -->> + + RAW IMAGE FORMAT + + <<-- <<-- <<-- <<-- */ +static opj_image_t* rawtoimage_common(const char *filename, + opj_cparameters_t *parameters, raw_cparameters_t *raw_cp, OPJ_BOOL big_endian) +{ + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + + FILE *f = NULL; + int i, compno, numcomps, w, h; + OPJ_COLOR_SPACE color_space; + opj_image_cmptparm_t *cmptparm; + opj_image_t * image = NULL; + unsigned short ch; + + if ((!(raw_cp->rawWidth & raw_cp->rawHeight & raw_cp->rawComp & + raw_cp->rawBitDepth)) == 0) { + fprintf(stderr, "\nError: invalid raw image parameters\n"); + fprintf(stderr, "Please use the Format option -F:\n"); + fprintf(stderr, + "-F <width>,<height>,<ncomp>,<bitdepth>,{s,u}@<dx1>x<dy1>:...:<dxn>x<dyn>\n"); + fprintf(stderr, + "If subsampling is omitted, 1x1 is assumed for all components\n"); + fprintf(stderr, + "Example: -i image.raw -o image.j2k -F 512,512,3,8,u@1x1:2x2:2x2\n"); + fprintf(stderr, " for raw 512x512 image with 4:2:0 subsampling\n"); + fprintf(stderr, "Aborting.\n"); + return NULL; + } + + f = fopen(filename, "rb"); + if (!f) { + fprintf(stderr, "Failed to open %s for reading !!\n", filename); + fprintf(stderr, "Aborting\n"); + return NULL; + } + numcomps = raw_cp->rawComp; + + /* FIXME ADE at this point, tcp_mct has not been properly set in calling function */ + if (numcomps == 1) { + color_space = OPJ_CLRSPC_GRAY; + } else if ((numcomps >= 3) && (parameters->tcp_mct == 0)) { + color_space = OPJ_CLRSPC_SYCC; + } else if ((numcomps >= 3) && (parameters->tcp_mct != 2)) { + color_space = OPJ_CLRSPC_SRGB; + } else { + color_space = OPJ_CLRSPC_UNKNOWN; + } + w = raw_cp->rawWidth; + h = raw_cp->rawHeight; + cmptparm = (opj_image_cmptparm_t*) calloc((OPJ_UINT32)numcomps, + sizeof(opj_image_cmptparm_t)); + if (!cmptparm) { + fprintf(stderr, "Failed to allocate image components parameters !!\n"); + fprintf(stderr, "Aborting\n"); + fclose(f); + return NULL; + } + /* initialize image components */ + for (i = 0; i < numcomps; i++) { + cmptparm[i].prec = (OPJ_UINT32)raw_cp->rawBitDepth; + cmptparm[i].bpp = (OPJ_UINT32)raw_cp->rawBitDepth; + cmptparm[i].sgnd = (OPJ_UINT32)raw_cp->rawSigned; + cmptparm[i].dx = (OPJ_UINT32)(subsampling_dx * raw_cp->rawComps[i].dx); + cmptparm[i].dy = (OPJ_UINT32)(subsampling_dy * raw_cp->rawComps[i].dy); + cmptparm[i].w = (OPJ_UINT32)w; + cmptparm[i].h = (OPJ_UINT32)h; + } + /* create the image */ + image = opj_image_create((OPJ_UINT32)numcomps, &cmptparm[0], color_space); + free(cmptparm); + if (!image) { + fclose(f); + return NULL; + } + /* set image offset and reference grid */ + image->x0 = (OPJ_UINT32)parameters->image_offset_x0; + image->y0 = (OPJ_UINT32)parameters->image_offset_y0; + image->x1 = (OPJ_UINT32)parameters->image_offset_x0 + (OPJ_UINT32)(w - 1) * + (OPJ_UINT32)subsampling_dx + 1; + image->y1 = (OPJ_UINT32)parameters->image_offset_y0 + (OPJ_UINT32)(h - 1) * + (OPJ_UINT32)subsampling_dy + 1; + + if (raw_cp->rawBitDepth <= 8) { + unsigned char value = 0; + for (compno = 0; compno < numcomps; compno++) { + int nloop = (w * h) / (raw_cp->rawComps[compno].dx * + raw_cp->rawComps[compno].dy); + for (i = 0; i < nloop; i++) { + if (!fread(&value, 1, 1, f)) { + fprintf(stderr, "Error reading raw file. End of file probably reached.\n"); + opj_image_destroy(image); + fclose(f); + return NULL; + } + image->comps[compno].data[i] = raw_cp->rawSigned ? (char)value : value; + } + } + } else if (raw_cp->rawBitDepth <= 16) { + unsigned short value; + for (compno = 0; compno < numcomps; compno++) { + int nloop = (w * h) / (raw_cp->rawComps[compno].dx * + raw_cp->rawComps[compno].dy); + for (i = 0; i < nloop; i++) { + unsigned char temp1; + unsigned char temp2; + if (!fread(&temp1, 1, 1, f)) { + fprintf(stderr, "Error reading raw file. End of file probably reached.\n"); + opj_image_destroy(image); + fclose(f); + return NULL; + } + if (!fread(&temp2, 1, 1, f)) { + fprintf(stderr, "Error reading raw file. End of file probably reached.\n"); + opj_image_destroy(image); + fclose(f); + return NULL; + } + if (big_endian) { + value = (unsigned short)((temp1 << 8) + temp2); + } else { + value = (unsigned short)((temp2 << 8) + temp1); + } + image->comps[compno].data[i] = raw_cp->rawSigned ? (short)value : value; + } + } + } else { + fprintf(stderr, + "OpenJPEG cannot encode raw components with bit depth higher than 16 bits.\n"); + opj_image_destroy(image); + fclose(f); + return NULL; + } + + if (fread(&ch, 1, 1, f)) { + fprintf(stderr, "Warning. End of raw file not reached... processing anyway\n"); + } + fclose(f); + + return image; +} + +opj_image_t* rawltoimage(const char *filename, opj_cparameters_t *parameters, + raw_cparameters_t *raw_cp) +{ + return rawtoimage_common(filename, parameters, raw_cp, OPJ_FALSE); +} + +opj_image_t* rawtoimage(const char *filename, opj_cparameters_t *parameters, + raw_cparameters_t *raw_cp) +{ + return rawtoimage_common(filename, parameters, raw_cp, OPJ_TRUE); +} + +static int imagetoraw_common(opj_image_t * image, const char *outfile, + OPJ_BOOL big_endian) +{ + FILE *rawFile = NULL; + size_t res; + unsigned int compno, numcomps; + int w, h, fails; + int line, row, curr, mask; + int *ptr; + unsigned char uc; + (void)big_endian; + + if ((image->numcomps * image->x1 * image->y1) == 0) { + fprintf(stderr, "\nError: invalid raw image parameters\n"); + return 1; + } + + numcomps = image->numcomps; + + if (numcomps > 4) { + numcomps = 4; + } + + for (compno = 1; compno < numcomps; ++compno) { + if (image->comps[0].dx != image->comps[compno].dx) { + break; + } + if (image->comps[0].dy != image->comps[compno].dy) { + break; + } + if (image->comps[0].prec != image->comps[compno].prec) { + break; + } + if (image->comps[0].sgnd != image->comps[compno].sgnd) { + break; + } + } + if (compno != numcomps) { + fprintf(stderr, + "imagetoraw_common: All components shall have the same subsampling, same bit depth, same sign.\n"); + fprintf(stderr, "\tAborting\n"); + return 1; + } + + rawFile = fopen(outfile, "wb"); + if (!rawFile) { + fprintf(stderr, "Failed to open %s for writing !!\n", outfile); + return 1; + } + + fails = 1; + fprintf(stdout, "Raw image characteristics: %d components\n", image->numcomps); + + for (compno = 0; compno < image->numcomps; compno++) { + fprintf(stdout, "Component %u characteristics: %dx%dx%d %s\n", compno, + image->comps[compno].w, + image->comps[compno].h, image->comps[compno].prec, + image->comps[compno].sgnd == 1 ? "signed" : "unsigned"); + + w = (int)image->comps[compno].w; + h = (int)image->comps[compno].h; + + if (image->comps[compno].prec <= 8) { + if (image->comps[compno].sgnd == 1) { + mask = (1 << image->comps[compno].prec) - 1; + ptr = image->comps[compno].data; + for (line = 0; line < h; line++) { + for (row = 0; row < w; row++) { + curr = *ptr; + if (curr > 127) { + curr = 127; + } else if (curr < -128) { + curr = -128; + } + uc = (unsigned char)(curr & mask); + res = fwrite(&uc, 1, 1, rawFile); + if (res < 1) { + fprintf(stderr, "failed to write 1 byte for %s\n", outfile); + goto fin; + } + ptr++; + } + } + } else if (image->comps[compno].sgnd == 0) { + mask = (1 << image->comps[compno].prec) - 1; + ptr = image->comps[compno].data; + for (line = 0; line < h; line++) { + for (row = 0; row < w; row++) { + curr = *ptr; + if (curr > 255) { + curr = 255; + } else if (curr < 0) { + curr = 0; + } + uc = (unsigned char)(curr & mask); + res = fwrite(&uc, 1, 1, rawFile); + if (res < 1) { + fprintf(stderr, "failed to write 1 byte for %s\n", outfile); + goto fin; + } + ptr++; + } + } + } + } else if (image->comps[compno].prec <= 16) { + if (image->comps[compno].sgnd == 1) { + union { + signed short val; + signed char vals[2]; + } uc16; + mask = (1 << image->comps[compno].prec) - 1; + ptr = image->comps[compno].data; + for (line = 0; line < h; line++) { + for (row = 0; row < w; row++) { + curr = *ptr; + if (curr > 32767) { + curr = 32767; + } else if (curr < -32768) { + curr = -32768; + } + uc16.val = (signed short)(curr & mask); + res = fwrite(uc16.vals, 1, 2, rawFile); + if (res < 2) { + fprintf(stderr, "failed to write 2 byte for %s\n", outfile); + goto fin; + } + ptr++; + } + } + } else if (image->comps[compno].sgnd == 0) { + union { + unsigned short val; + unsigned char vals[2]; + } uc16; + mask = (1 << image->comps[compno].prec) - 1; + ptr = image->comps[compno].data; + for (line = 0; line < h; line++) { + for (row = 0; row < w; row++) { + curr = *ptr; + if (curr > 65535) { + curr = 65535; + } else if (curr < 0) { + curr = 0; + } + uc16.val = (unsigned short)(curr & mask); + res = fwrite(uc16.vals, 1, 2, rawFile); + if (res < 2) { + fprintf(stderr, "failed to write 2 byte for %s\n", outfile); + goto fin; + } + ptr++; + } + } + } + } else if (image->comps[compno].prec <= 32) { + fprintf(stderr, "More than 16 bits per component not handled yet\n"); + goto fin; + } else { + fprintf(stderr, "Error: invalid precision: %d\n", image->comps[compno].prec); + goto fin; + } + } + fails = 0; +fin: + fclose(rawFile); + return fails; +} + +int imagetoraw(opj_image_t * image, const char *outfile) +{ + return imagetoraw_common(image, outfile, OPJ_TRUE); +} + +int imagetorawl(opj_image_t * image, const char *outfile) +{ + return imagetoraw_common(image, outfile, OPJ_FALSE); +} + diff --git a/openjpeg/src/bin/jp2/convert.h b/openjpeg/src/bin/jp2/convert.h new file mode 100644 index 000000000..61439d49a --- /dev/null +++ b/openjpeg/src/bin/jp2/convert.h @@ -0,0 +1,126 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * Copyright (c) 2003-2014, Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __J2K_CONVERT_H +#define __J2K_CONVERT_H + +/**@name RAW component encoding parameters */ +/*@{*/ +typedef struct raw_comp_cparameters { + /** subsampling in X direction */ + int dx; + /** subsampling in Y direction */ + int dy; + /*@}*/ +} raw_comp_cparameters_t; + +/**@name RAW image encoding parameters */ +/*@{*/ +typedef struct raw_cparameters { + /** width of the raw image */ + int rawWidth; + /** height of the raw image */ + int rawHeight; + /** number of components of the raw image */ + int rawComp; + /** bit depth of the raw image */ + int rawBitDepth; + /** signed/unsigned raw image */ + OPJ_BOOL rawSigned; + /** raw components parameters */ + raw_comp_cparameters_t *rawComps; + /*@}*/ +} raw_cparameters_t; + +/* Component precision clipping */ +void clip_component(opj_image_comp_t* component, OPJ_UINT32 precision); +/* Component precision scaling */ +void scale_component(opj_image_comp_t* component, OPJ_UINT32 precision); + +/* planar / interleaved conversions */ +typedef void (* convert_32s_CXPX)(const OPJ_INT32* pSrc, OPJ_INT32* const* pDst, + OPJ_SIZE_T length); +extern const convert_32s_CXPX convert_32s_CXPX_LUT[5]; +typedef void (* convert_32s_PXCX)(OPJ_INT32 const* const* pSrc, OPJ_INT32* pDst, + OPJ_SIZE_T length, OPJ_INT32 adjust); +extern const convert_32s_PXCX convert_32s_PXCX_LUT[5]; +/* bit depth conversions */ +typedef void (* convert_XXx32s_C1R)(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, + OPJ_SIZE_T length); +extern const convert_XXx32s_C1R convert_XXu32s_C1R_LUT[9]; /* up to 8bpp */ +typedef void (* convert_32sXXx_C1R)(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, + OPJ_SIZE_T length); +extern const convert_32sXXx_C1R convert_32sXXu_C1R_LUT[9]; /* up to 8bpp */ + + +/* TGA conversion */ +opj_image_t* tgatoimage(const char *filename, opj_cparameters_t *parameters); +int imagetotga(opj_image_t * image, const char *outfile); + +/* BMP conversion */ +opj_image_t* bmptoimage(const char *filename, opj_cparameters_t *parameters); +int imagetobmp(opj_image_t *image, const char *outfile); + +/* TIFF conversion*/ +opj_image_t* tiftoimage(const char *filename, opj_cparameters_t *parameters); +int imagetotif(opj_image_t *image, const char *outfile); +/** +Load a single image component encoded in PGX file format +@param filename Name of the PGX file to load +@param parameters *List ?* +@return Returns a greyscale image if successful, returns NULL otherwise +*/ +opj_image_t* pgxtoimage(const char *filename, opj_cparameters_t *parameters); +int imagetopgx(opj_image_t *image, const char *outfile); + +opj_image_t* pnmtoimage(const char *filename, opj_cparameters_t *parameters); +int imagetopnm(opj_image_t *image, const char *outfile, int force_split); + +/* RAW conversion */ +int imagetoraw(opj_image_t * image, const char *outfile); +int imagetorawl(opj_image_t * image, const char *outfile); +opj_image_t* rawtoimage(const char *filename, opj_cparameters_t *parameters, + raw_cparameters_t *raw_cp); +opj_image_t* rawltoimage(const char *filename, opj_cparameters_t *parameters, + raw_cparameters_t *raw_cp); + +/* PNG conversion*/ +extern int imagetopng(opj_image_t *image, const char *write_idf); +extern opj_image_t* pngtoimage(const char *filename, + opj_cparameters_t *parameters); + +#endif /* __J2K_CONVERT_H */ + diff --git a/openjpeg/src/bin/jp2/convertbmp.c b/openjpeg/src/bin/jp2/convertbmp.c new file mode 100644 index 000000000..084f70bb7 --- /dev/null +++ b/openjpeg/src/bin/jp2/convertbmp.c @@ -0,0 +1,1106 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * Copyright (c) 2003-2014, Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "opj_apps_config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include "openjpeg.h" +#include "convert.h" + +typedef struct { + OPJ_UINT16 bfType; /* 'BM' for Bitmap (19776) */ + OPJ_UINT32 bfSize; /* Size of the file */ + OPJ_UINT16 bfReserved1; /* Reserved : 0 */ + OPJ_UINT16 bfReserved2; /* Reserved : 0 */ + OPJ_UINT32 bfOffBits; /* Offset */ +} OPJ_BITMAPFILEHEADER; + +typedef struct { + OPJ_UINT32 biSize; /* Size of the structure in bytes */ + OPJ_UINT32 biWidth; /* Width of the image in pixels */ + OPJ_UINT32 biHeight; /* Height of the image in pixels */ + OPJ_UINT16 biPlanes; /* 1 */ + OPJ_UINT16 biBitCount; /* Number of color bits by pixels */ + OPJ_UINT32 biCompression; /* Type of encoding 0: none 1: RLE8 2: RLE4 */ + OPJ_UINT32 biSizeImage; /* Size of the image in bytes */ + OPJ_UINT32 biXpelsPerMeter; /* Horizontal (X) resolution in pixels/meter */ + OPJ_UINT32 biYpelsPerMeter; /* Vertical (Y) resolution in pixels/meter */ + OPJ_UINT32 biClrUsed; /* Number of color used in the image (0: ALL) */ + OPJ_UINT32 biClrImportant; /* Number of important color (0: ALL) */ + OPJ_UINT32 biRedMask; /* Red channel bit mask */ + OPJ_UINT32 biGreenMask; /* Green channel bit mask */ + OPJ_UINT32 biBlueMask; /* Blue channel bit mask */ + OPJ_UINT32 biAlphaMask; /* Alpha channel bit mask */ + OPJ_UINT32 biColorSpaceType; /* Color space type */ + OPJ_UINT8 biColorSpaceEP[36]; /* Color space end points */ + OPJ_UINT32 biRedGamma; /* Red channel gamma */ + OPJ_UINT32 biGreenGamma; /* Green channel gamma */ + OPJ_UINT32 biBlueGamma; /* Blue channel gamma */ + OPJ_UINT32 biIntent; /* Intent */ + OPJ_UINT32 biIccProfileData; /* ICC profile data */ + OPJ_UINT32 biIccProfileSize; /* ICC profile size */ + OPJ_UINT32 biReserved; /* Reserved */ +} OPJ_BITMAPINFOHEADER; + +static void opj_applyLUT8u_8u32s_C1R( + OPJ_UINT8 const* pSrc, OPJ_INT32 srcStride, + OPJ_INT32* pDst, OPJ_INT32 dstStride, + OPJ_UINT8 const* pLUT, + OPJ_UINT32 width, OPJ_UINT32 height) +{ + OPJ_UINT32 y; + + for (y = height; y != 0U; --y) { + OPJ_UINT32 x; + + for (x = 0; x < width; x++) { + pDst[x] = (OPJ_INT32)pLUT[pSrc[x]]; + } + pSrc += srcStride; + pDst += dstStride; + } +} + +static void opj_applyLUT8u_8u32s_C1P3R( + OPJ_UINT8 const* pSrc, OPJ_INT32 srcStride, + OPJ_INT32* const* pDst, OPJ_INT32 const* pDstStride, + OPJ_UINT8 const* const* pLUT, + OPJ_UINT32 width, OPJ_UINT32 height) +{ + OPJ_UINT32 y; + OPJ_INT32* pR = pDst[0]; + OPJ_INT32* pG = pDst[1]; + OPJ_INT32* pB = pDst[2]; + OPJ_UINT8 const* pLUT_R = pLUT[0]; + OPJ_UINT8 const* pLUT_G = pLUT[1]; + OPJ_UINT8 const* pLUT_B = pLUT[2]; + + for (y = height; y != 0U; --y) { + OPJ_UINT32 x; + + for (x = 0; x < width; x++) { + OPJ_UINT8 idx = pSrc[x]; + pR[x] = (OPJ_INT32)pLUT_R[idx]; + pG[x] = (OPJ_INT32)pLUT_G[idx]; + pB[x] = (OPJ_INT32)pLUT_B[idx]; + } + pSrc += srcStride; + pR += pDstStride[0]; + pG += pDstStride[1]; + pB += pDstStride[2]; + } +} + +static void bmp24toimage(const OPJ_UINT8* pData, OPJ_UINT32 stride, + opj_image_t* image) +{ + int index; + OPJ_UINT32 width, height; + OPJ_UINT32 x, y; + const OPJ_UINT8 *pSrc = NULL; + + width = image->comps[0].w; + height = image->comps[0].h; + + index = 0; + pSrc = pData + (height - 1U) * stride; + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + image->comps[0].data[index] = (OPJ_INT32)pSrc[3 * x + 2]; /* R */ + image->comps[1].data[index] = (OPJ_INT32)pSrc[3 * x + 1]; /* G */ + image->comps[2].data[index] = (OPJ_INT32)pSrc[3 * x + 0]; /* B */ + index++; + } + pSrc -= stride; + } +} + +static void bmp_mask_get_shift_and_prec(OPJ_UINT32 mask, OPJ_UINT32* shift, + OPJ_UINT32* prec) +{ + OPJ_UINT32 l_shift, l_prec; + + l_shift = l_prec = 0U; + + if (mask != 0U) { + while ((mask & 1U) == 0U) { + mask >>= 1; + l_shift++; + } + while (mask & 1U) { + mask >>= 1; + l_prec++; + } + } + *shift = l_shift; + *prec = l_prec; +} + +static void bmpmask32toimage(const OPJ_UINT8* pData, OPJ_UINT32 stride, + opj_image_t* image, OPJ_UINT32 redMask, OPJ_UINT32 greenMask, + OPJ_UINT32 blueMask, OPJ_UINT32 alphaMask) +{ + int index; + OPJ_UINT32 width, height; + OPJ_UINT32 x, y; + const OPJ_UINT8 *pSrc = NULL; + OPJ_BOOL hasAlpha; + OPJ_UINT32 redShift, redPrec; + OPJ_UINT32 greenShift, greenPrec; + OPJ_UINT32 blueShift, bluePrec; + OPJ_UINT32 alphaShift, alphaPrec; + + width = image->comps[0].w; + height = image->comps[0].h; + + hasAlpha = image->numcomps > 3U; + + bmp_mask_get_shift_and_prec(redMask, &redShift, &redPrec); + bmp_mask_get_shift_and_prec(greenMask, &greenShift, &greenPrec); + bmp_mask_get_shift_and_prec(blueMask, &blueShift, &bluePrec); + bmp_mask_get_shift_and_prec(alphaMask, &alphaShift, &alphaPrec); + + image->comps[0].bpp = redPrec; + image->comps[0].prec = redPrec; + image->comps[1].bpp = greenPrec; + image->comps[1].prec = greenPrec; + image->comps[2].bpp = bluePrec; + image->comps[2].prec = bluePrec; + if (hasAlpha) { + image->comps[3].bpp = alphaPrec; + image->comps[3].prec = alphaPrec; + } + + index = 0; + pSrc = pData + (height - 1U) * stride; + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + OPJ_UINT32 value = 0U; + + value |= ((OPJ_UINT32)pSrc[4 * x + 0]) << 0; + value |= ((OPJ_UINT32)pSrc[4 * x + 1]) << 8; + value |= ((OPJ_UINT32)pSrc[4 * x + 2]) << 16; + value |= ((OPJ_UINT32)pSrc[4 * x + 3]) << 24; + + image->comps[0].data[index] = (OPJ_INT32)((value & redMask) >> + redShift); /* R */ + image->comps[1].data[index] = (OPJ_INT32)((value & greenMask) >> + greenShift); /* G */ + image->comps[2].data[index] = (OPJ_INT32)((value & blueMask) >> + blueShift); /* B */ + if (hasAlpha) { + image->comps[3].data[index] = (OPJ_INT32)((value & alphaMask) >> + alphaShift); /* A */ + } + index++; + } + pSrc -= stride; + } +} + +static void bmpmask16toimage(const OPJ_UINT8* pData, OPJ_UINT32 stride, + opj_image_t* image, OPJ_UINT32 redMask, OPJ_UINT32 greenMask, + OPJ_UINT32 blueMask, OPJ_UINT32 alphaMask) +{ + int index; + OPJ_UINT32 width, height; + OPJ_UINT32 x, y; + const OPJ_UINT8 *pSrc = NULL; + OPJ_BOOL hasAlpha; + OPJ_UINT32 redShift, redPrec; + OPJ_UINT32 greenShift, greenPrec; + OPJ_UINT32 blueShift, bluePrec; + OPJ_UINT32 alphaShift, alphaPrec; + + width = image->comps[0].w; + height = image->comps[0].h; + + hasAlpha = image->numcomps > 3U; + + bmp_mask_get_shift_and_prec(redMask, &redShift, &redPrec); + bmp_mask_get_shift_and_prec(greenMask, &greenShift, &greenPrec); + bmp_mask_get_shift_and_prec(blueMask, &blueShift, &bluePrec); + bmp_mask_get_shift_and_prec(alphaMask, &alphaShift, &alphaPrec); + + image->comps[0].bpp = redPrec; + image->comps[0].prec = redPrec; + image->comps[1].bpp = greenPrec; + image->comps[1].prec = greenPrec; + image->comps[2].bpp = bluePrec; + image->comps[2].prec = bluePrec; + if (hasAlpha) { + image->comps[3].bpp = alphaPrec; + image->comps[3].prec = alphaPrec; + } + + index = 0; + pSrc = pData + (height - 1U) * stride; + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + OPJ_UINT32 value = 0U; + + value |= ((OPJ_UINT32)pSrc[2 * x + 0]) << 0; + value |= ((OPJ_UINT32)pSrc[2 * x + 1]) << 8; + + image->comps[0].data[index] = (OPJ_INT32)((value & redMask) >> + redShift); /* R */ + image->comps[1].data[index] = (OPJ_INT32)((value & greenMask) >> + greenShift); /* G */ + image->comps[2].data[index] = (OPJ_INT32)((value & blueMask) >> + blueShift); /* B */ + if (hasAlpha) { + image->comps[3].data[index] = (OPJ_INT32)((value & alphaMask) >> + alphaShift); /* A */ + } + index++; + } + pSrc -= stride; + } +} + +static opj_image_t* bmp8toimage(const OPJ_UINT8* pData, OPJ_UINT32 stride, + opj_image_t* image, OPJ_UINT8 const* const* pLUT) +{ + OPJ_UINT32 width, height; + const OPJ_UINT8 *pSrc = NULL; + + width = image->comps[0].w; + height = image->comps[0].h; + + pSrc = pData + (height - 1U) * stride; + if (image->numcomps == 1U) { + opj_applyLUT8u_8u32s_C1R(pSrc, -(OPJ_INT32)stride, image->comps[0].data, + (OPJ_INT32)width, pLUT[0], width, height); + } else { + OPJ_INT32* pDst[3]; + OPJ_INT32 pDstStride[3]; + + pDst[0] = image->comps[0].data; + pDst[1] = image->comps[1].data; + pDst[2] = image->comps[2].data; + pDstStride[0] = (OPJ_INT32)width; + pDstStride[1] = (OPJ_INT32)width; + pDstStride[2] = (OPJ_INT32)width; + opj_applyLUT8u_8u32s_C1P3R(pSrc, -(OPJ_INT32)stride, pDst, pDstStride, pLUT, + width, height); + } + return image; +} + +static OPJ_BOOL bmp_read_file_header(FILE* IN, OPJ_BITMAPFILEHEADER* header) +{ + header->bfType = (OPJ_UINT16)getc(IN); + header->bfType |= (OPJ_UINT16)((OPJ_UINT32)getc(IN) << 8); + + if (header->bfType != 19778) { + fprintf(stderr, "Error, not a BMP file!\n"); + return OPJ_FALSE; + } + + /* FILE HEADER */ + /* ------------- */ + header->bfSize = (OPJ_UINT32)getc(IN); + header->bfSize |= (OPJ_UINT32)getc(IN) << 8; + header->bfSize |= (OPJ_UINT32)getc(IN) << 16; + header->bfSize |= (OPJ_UINT32)getc(IN) << 24; + + header->bfReserved1 = (OPJ_UINT16)getc(IN); + header->bfReserved1 |= (OPJ_UINT16)((OPJ_UINT32)getc(IN) << 8); + + header->bfReserved2 = (OPJ_UINT16)getc(IN); + header->bfReserved2 |= (OPJ_UINT16)((OPJ_UINT32)getc(IN) << 8); + + header->bfOffBits = (OPJ_UINT32)getc(IN); + header->bfOffBits |= (OPJ_UINT32)getc(IN) << 8; + header->bfOffBits |= (OPJ_UINT32)getc(IN) << 16; + header->bfOffBits |= (OPJ_UINT32)getc(IN) << 24; + return OPJ_TRUE; +} +static OPJ_BOOL bmp_read_info_header(FILE* IN, OPJ_BITMAPINFOHEADER* header) +{ + memset(header, 0, sizeof(*header)); + /* INFO HEADER */ + /* ------------- */ + header->biSize = (OPJ_UINT32)getc(IN); + header->biSize |= (OPJ_UINT32)getc(IN) << 8; + header->biSize |= (OPJ_UINT32)getc(IN) << 16; + header->biSize |= (OPJ_UINT32)getc(IN) << 24; + + switch (header->biSize) { + case 12U: /* BITMAPCOREHEADER */ + case 40U: /* BITMAPINFOHEADER */ + case 52U: /* BITMAPV2INFOHEADER */ + case 56U: /* BITMAPV3INFOHEADER */ + case 108U: /* BITMAPV4HEADER */ + case 124U: /* BITMAPV5HEADER */ + break; + default: + fprintf(stderr, "Error, unknown BMP header size %d\n", header->biSize); + return OPJ_FALSE; + } + + header->biWidth = (OPJ_UINT32)getc(IN); + header->biWidth |= (OPJ_UINT32)getc(IN) << 8; + header->biWidth |= (OPJ_UINT32)getc(IN) << 16; + header->biWidth |= (OPJ_UINT32)getc(IN) << 24; + + header->biHeight = (OPJ_UINT32)getc(IN); + header->biHeight |= (OPJ_UINT32)getc(IN) << 8; + header->biHeight |= (OPJ_UINT32)getc(IN) << 16; + header->biHeight |= (OPJ_UINT32)getc(IN) << 24; + + header->biPlanes = (OPJ_UINT16)getc(IN); + header->biPlanes |= (OPJ_UINT16)((OPJ_UINT32)getc(IN) << 8); + + header->biBitCount = (OPJ_UINT16)getc(IN); + header->biBitCount |= (OPJ_UINT16)((OPJ_UINT32)getc(IN) << 8); + if (header->biBitCount == 0) { + fprintf(stderr, "Error, invalid biBitCount %d\n", 0); + return OPJ_FALSE; + } + + if (header->biSize >= 40U) { + header->biCompression = (OPJ_UINT32)getc(IN); + header->biCompression |= (OPJ_UINT32)getc(IN) << 8; + header->biCompression |= (OPJ_UINT32)getc(IN) << 16; + header->biCompression |= (OPJ_UINT32)getc(IN) << 24; + + header->biSizeImage = (OPJ_UINT32)getc(IN); + header->biSizeImage |= (OPJ_UINT32)getc(IN) << 8; + header->biSizeImage |= (OPJ_UINT32)getc(IN) << 16; + header->biSizeImage |= (OPJ_UINT32)getc(IN) << 24; + + header->biXpelsPerMeter = (OPJ_UINT32)getc(IN); + header->biXpelsPerMeter |= (OPJ_UINT32)getc(IN) << 8; + header->biXpelsPerMeter |= (OPJ_UINT32)getc(IN) << 16; + header->biXpelsPerMeter |= (OPJ_UINT32)getc(IN) << 24; + + header->biYpelsPerMeter = (OPJ_UINT32)getc(IN); + header->biYpelsPerMeter |= (OPJ_UINT32)getc(IN) << 8; + header->biYpelsPerMeter |= (OPJ_UINT32)getc(IN) << 16; + header->biYpelsPerMeter |= (OPJ_UINT32)getc(IN) << 24; + + header->biClrUsed = (OPJ_UINT32)getc(IN); + header->biClrUsed |= (OPJ_UINT32)getc(IN) << 8; + header->biClrUsed |= (OPJ_UINT32)getc(IN) << 16; + header->biClrUsed |= (OPJ_UINT32)getc(IN) << 24; + + header->biClrImportant = (OPJ_UINT32)getc(IN); + header->biClrImportant |= (OPJ_UINT32)getc(IN) << 8; + header->biClrImportant |= (OPJ_UINT32)getc(IN) << 16; + header->biClrImportant |= (OPJ_UINT32)getc(IN) << 24; + } + + if (header->biSize >= 56U) { + header->biRedMask = (OPJ_UINT32)getc(IN); + header->biRedMask |= (OPJ_UINT32)getc(IN) << 8; + header->biRedMask |= (OPJ_UINT32)getc(IN) << 16; + header->biRedMask |= (OPJ_UINT32)getc(IN) << 24; + + header->biGreenMask = (OPJ_UINT32)getc(IN); + header->biGreenMask |= (OPJ_UINT32)getc(IN) << 8; + header->biGreenMask |= (OPJ_UINT32)getc(IN) << 16; + header->biGreenMask |= (OPJ_UINT32)getc(IN) << 24; + + header->biBlueMask = (OPJ_UINT32)getc(IN); + header->biBlueMask |= (OPJ_UINT32)getc(IN) << 8; + header->biBlueMask |= (OPJ_UINT32)getc(IN) << 16; + header->biBlueMask |= (OPJ_UINT32)getc(IN) << 24; + + header->biAlphaMask = (OPJ_UINT32)getc(IN); + header->biAlphaMask |= (OPJ_UINT32)getc(IN) << 8; + header->biAlphaMask |= (OPJ_UINT32)getc(IN) << 16; + header->biAlphaMask |= (OPJ_UINT32)getc(IN) << 24; + } + + if (header->biSize >= 108U) { + header->biColorSpaceType = (OPJ_UINT32)getc(IN); + header->biColorSpaceType |= (OPJ_UINT32)getc(IN) << 8; + header->biColorSpaceType |= (OPJ_UINT32)getc(IN) << 16; + header->biColorSpaceType |= (OPJ_UINT32)getc(IN) << 24; + + if (fread(&(header->biColorSpaceEP), 1U, sizeof(header->biColorSpaceEP), + IN) != sizeof(header->biColorSpaceEP)) { + fprintf(stderr, "Error, can't read BMP header\n"); + return OPJ_FALSE; + } + + header->biRedGamma = (OPJ_UINT32)getc(IN); + header->biRedGamma |= (OPJ_UINT32)getc(IN) << 8; + header->biRedGamma |= (OPJ_UINT32)getc(IN) << 16; + header->biRedGamma |= (OPJ_UINT32)getc(IN) << 24; + + header->biGreenGamma = (OPJ_UINT32)getc(IN); + header->biGreenGamma |= (OPJ_UINT32)getc(IN) << 8; + header->biGreenGamma |= (OPJ_UINT32)getc(IN) << 16; + header->biGreenGamma |= (OPJ_UINT32)getc(IN) << 24; + + header->biBlueGamma = (OPJ_UINT32)getc(IN); + header->biBlueGamma |= (OPJ_UINT32)getc(IN) << 8; + header->biBlueGamma |= (OPJ_UINT32)getc(IN) << 16; + header->biBlueGamma |= (OPJ_UINT32)getc(IN) << 24; + } + + if (header->biSize >= 124U) { + header->biIntent = (OPJ_UINT32)getc(IN); + header->biIntent |= (OPJ_UINT32)getc(IN) << 8; + header->biIntent |= (OPJ_UINT32)getc(IN) << 16; + header->biIntent |= (OPJ_UINT32)getc(IN) << 24; + + header->biIccProfileData = (OPJ_UINT32)getc(IN); + header->biIccProfileData |= (OPJ_UINT32)getc(IN) << 8; + header->biIccProfileData |= (OPJ_UINT32)getc(IN) << 16; + header->biIccProfileData |= (OPJ_UINT32)getc(IN) << 24; + + header->biIccProfileSize = (OPJ_UINT32)getc(IN); + header->biIccProfileSize |= (OPJ_UINT32)getc(IN) << 8; + header->biIccProfileSize |= (OPJ_UINT32)getc(IN) << 16; + header->biIccProfileSize |= (OPJ_UINT32)getc(IN) << 24; + + header->biReserved = (OPJ_UINT32)getc(IN); + header->biReserved |= (OPJ_UINT32)getc(IN) << 8; + header->biReserved |= (OPJ_UINT32)getc(IN) << 16; + header->biReserved |= (OPJ_UINT32)getc(IN) << 24; + } + return OPJ_TRUE; +} + +static OPJ_BOOL bmp_read_raw_data(FILE* IN, OPJ_UINT8* pData, OPJ_UINT32 stride, + OPJ_UINT32 width, OPJ_UINT32 height) +{ + OPJ_ARG_NOT_USED(width); + + if (fread(pData, sizeof(OPJ_UINT8), stride * height, IN) != (stride * height)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + return OPJ_FALSE; + } + return OPJ_TRUE; +} + +static OPJ_BOOL bmp_read_rle8_data(FILE* IN, OPJ_UINT8* pData, + OPJ_UINT32 stride, OPJ_UINT32 width, OPJ_UINT32 height) +{ + OPJ_UINT32 x, y; + OPJ_UINT8 *pix; + const OPJ_UINT8 *beyond; + + beyond = pData + stride * height; + pix = pData; + + x = y = 0U; + while (y < height) { + int c = getc(IN); + if (c == EOF) { + return OPJ_FALSE; + } + + if (c) { + int j, c1_int; + OPJ_UINT8 c1; + + c1_int = getc(IN); + if (c1_int == EOF) { + return OPJ_FALSE; + } + c1 = (OPJ_UINT8)c1_int; + + for (j = 0; (j < c) && (x < width) && + ((OPJ_SIZE_T)pix < (OPJ_SIZE_T)beyond); j++, x++, pix++) { + *pix = c1; + } + } else { + c = getc(IN); + if (c == EOF) { + return OPJ_FALSE; + } + + if (c == 0x00) { /* EOL */ + x = 0; + ++y; + pix = pData + y * stride + x; + } else if (c == 0x01) { /* EOP */ + break; + } else if (c == 0x02) { /* MOVE by dxdy */ + c = getc(IN); + if (c == EOF) { + return OPJ_FALSE; + } + x += (OPJ_UINT32)c; + c = getc(IN); + if (c == EOF) { + return OPJ_FALSE; + } + y += (OPJ_UINT32)c; + pix = pData + y * stride + x; + } else { /* 03 .. 255 */ + int j; + for (j = 0; (j < c) && (x < width) && + ((OPJ_SIZE_T)pix < (OPJ_SIZE_T)beyond); j++, x++, pix++) { + int c1_int; + OPJ_UINT8 c1; + c1_int = getc(IN); + if (c1_int == EOF) { + return OPJ_FALSE; + } + c1 = (OPJ_UINT8)c1_int; + *pix = c1; + } + if ((OPJ_UINT32)c & 1U) { /* skip padding byte */ + c = getc(IN); + if (c == EOF) { + return OPJ_FALSE; + } + } + } + } + }/* while() */ + return OPJ_TRUE; +} + +static OPJ_BOOL bmp_read_rle4_data(FILE* IN, OPJ_UINT8* pData, + OPJ_UINT32 stride, OPJ_UINT32 width, OPJ_UINT32 height) +{ + OPJ_UINT32 x, y; + OPJ_UINT8 *pix; + const OPJ_UINT8 *beyond; + + beyond = pData + stride * height; + pix = pData; + x = y = 0U; + while (y < height) { + int c = getc(IN); + if (c == EOF) { + break; + } + + if (c) { /* encoded mode */ + int j; + OPJ_UINT8 c1 = (OPJ_UINT8)getc(IN); + + for (j = 0; (j < c) && (x < width) && + ((OPJ_SIZE_T)pix < (OPJ_SIZE_T)beyond); j++, x++, pix++) { + *pix = (OPJ_UINT8)((j & 1) ? (c1 & 0x0fU) : ((c1 >> 4) & 0x0fU)); + } + } else { /* absolute mode */ + c = getc(IN); + if (c == EOF) { + break; + } + + if (c == 0x00) { /* EOL */ + x = 0; + y++; + pix = pData + y * stride; + } else if (c == 0x01) { /* EOP */ + break; + } else if (c == 0x02) { /* MOVE by dxdy */ + c = getc(IN); + x += (OPJ_UINT32)c; + c = getc(IN); + y += (OPJ_UINT32)c; + pix = pData + y * stride + x; + } else { /* 03 .. 255 : absolute mode */ + int j; + OPJ_UINT8 c1 = 0U; + + for (j = 0; (j < c) && (x < width) && + ((OPJ_SIZE_T)pix < (OPJ_SIZE_T)beyond); j++, x++, pix++) { + if ((j & 1) == 0) { + c1 = (OPJ_UINT8)getc(IN); + } + *pix = (OPJ_UINT8)((j & 1) ? (c1 & 0x0fU) : ((c1 >> 4) & 0x0fU)); + } + if (((c & 3) == 1) || ((c & 3) == 2)) { /* skip padding byte */ + getc(IN); + } + } + } + } /* while(y < height) */ + return OPJ_TRUE; +} + +opj_image_t* bmptoimage(const char *filename, opj_cparameters_t *parameters) +{ + opj_image_cmptparm_t cmptparm[4]; /* maximum of 4 components */ + OPJ_UINT8 lut_R[256], lut_G[256], lut_B[256]; + OPJ_UINT8 const* pLUT[3]; + opj_image_t * image = NULL; + FILE *IN; + OPJ_BITMAPFILEHEADER File_h; + OPJ_BITMAPINFOHEADER Info_h; + OPJ_UINT32 i, palette_len, numcmpts = 1U; + OPJ_BOOL l_result = OPJ_FALSE; + OPJ_UINT8* pData = NULL; + OPJ_UINT32 stride; + + pLUT[0] = lut_R; + pLUT[1] = lut_G; + pLUT[2] = lut_B; + + IN = fopen(filename, "rb"); + if (!IN) { + fprintf(stderr, "Failed to open %s for reading !!\n", filename); + return NULL; + } + + if (!bmp_read_file_header(IN, &File_h)) { + fclose(IN); + return NULL; + } + if (!bmp_read_info_header(IN, &Info_h)) { + fclose(IN); + return NULL; + } + + /* Load palette */ + if (Info_h.biBitCount <= 8U) { + memset(&lut_R[0], 0, sizeof(lut_R)); + memset(&lut_G[0], 0, sizeof(lut_G)); + memset(&lut_B[0], 0, sizeof(lut_B)); + + palette_len = Info_h.biClrUsed; + if ((palette_len == 0U) && (Info_h.biBitCount <= 8U)) { + palette_len = (1U << Info_h.biBitCount); + } + if (palette_len > 256U) { + palette_len = 256U; + } + if (palette_len > 0U) { + OPJ_UINT8 has_color = 0U; + for (i = 0U; i < palette_len; i++) { + lut_B[i] = (OPJ_UINT8)getc(IN); + lut_G[i] = (OPJ_UINT8)getc(IN); + lut_R[i] = (OPJ_UINT8)getc(IN); + (void)getc(IN); /* padding */ + has_color |= (lut_B[i] ^ lut_G[i]) | (lut_G[i] ^ lut_R[i]); + } + if (has_color) { + numcmpts = 3U; + } + } + } else { + numcmpts = 3U; + if ((Info_h.biCompression == 3) && (Info_h.biAlphaMask != 0U)) { + numcmpts++; + } + } + + if (Info_h.biWidth == 0 || Info_h.biHeight == 0) { + fclose(IN); + return NULL; + } + + if (Info_h.biBitCount > (((OPJ_UINT32) - 1) - 31) / Info_h.biWidth) { + fclose(IN); + return NULL; + } + stride = ((Info_h.biWidth * Info_h.biBitCount + 31U) / 32U) * + 4U; /* rows are aligned on 32bits */ + if (Info_h.biBitCount == 4 && + Info_h.biCompression == 2) { /* RLE 4 gets decoded as 8 bits data for now... */ + if (8 > (((OPJ_UINT32) - 1) - 31) / Info_h.biWidth) { + fclose(IN); + return NULL; + } + stride = ((Info_h.biWidth * 8U + 31U) / 32U) * 4U; + } + + if (stride > ((OPJ_UINT32) - 1) / sizeof(OPJ_UINT8) / Info_h.biHeight) { + fclose(IN); + return NULL; + } + pData = (OPJ_UINT8 *) calloc(1, stride * Info_h.biHeight * sizeof(OPJ_UINT8)); + if (pData == NULL) { + fclose(IN); + return NULL; + } + /* Place the cursor at the beginning of the image information */ + fseek(IN, 0, SEEK_SET); + fseek(IN, (long)File_h.bfOffBits, SEEK_SET); + + switch (Info_h.biCompression) { + case 0: + case 3: + /* read raw data */ + l_result = bmp_read_raw_data(IN, pData, stride, Info_h.biWidth, + Info_h.biHeight); + break; + case 1: + /* read rle8 data */ + l_result = bmp_read_rle8_data(IN, pData, stride, Info_h.biWidth, + Info_h.biHeight); + break; + case 2: + /* read rle4 data */ + l_result = bmp_read_rle4_data(IN, pData, stride, Info_h.biWidth, + Info_h.biHeight); + break; + default: + fprintf(stderr, "Unsupported BMP compression\n"); + l_result = OPJ_FALSE; + break; + } + if (!l_result) { + free(pData); + fclose(IN); + return NULL; + } + + /* create the image */ + memset(&cmptparm[0], 0, sizeof(cmptparm)); + for (i = 0; i < 4U; i++) { + cmptparm[i].prec = 8; + cmptparm[i].bpp = 8; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = (OPJ_UINT32)parameters->subsampling_dx; + cmptparm[i].dy = (OPJ_UINT32)parameters->subsampling_dy; + cmptparm[i].w = Info_h.biWidth; + cmptparm[i].h = Info_h.biHeight; + } + + image = opj_image_create(numcmpts, &cmptparm[0], + (numcmpts == 1U) ? OPJ_CLRSPC_GRAY : OPJ_CLRSPC_SRGB); + if (!image) { + fclose(IN); + free(pData); + return NULL; + } + if (numcmpts == 4U) { + image->comps[3].alpha = 1; + } + + /* set image offset and reference grid */ + image->x0 = (OPJ_UINT32)parameters->image_offset_x0; + image->y0 = (OPJ_UINT32)parameters->image_offset_y0; + image->x1 = image->x0 + (Info_h.biWidth - 1U) * (OPJ_UINT32) + parameters->subsampling_dx + 1U; + image->y1 = image->y0 + (Info_h.biHeight - 1U) * (OPJ_UINT32) + parameters->subsampling_dy + 1U; + + /* Read the data */ + if (Info_h.biBitCount == 24 && Info_h.biCompression == 0) { /*RGB */ + bmp24toimage(pData, stride, image); + } else if (Info_h.biBitCount == 8 && + Info_h.biCompression == 0) { /* RGB 8bpp Indexed */ + bmp8toimage(pData, stride, image, pLUT); + } else if (Info_h.biBitCount == 8 && Info_h.biCompression == 1) { /*RLE8*/ + bmp8toimage(pData, stride, image, pLUT); + } else if (Info_h.biBitCount == 4 && Info_h.biCompression == 2) { /*RLE4*/ + bmp8toimage(pData, stride, image, + pLUT); /* RLE 4 gets decoded as 8 bits data for now */ + } else if (Info_h.biBitCount == 32 && Info_h.biCompression == 0) { /* RGBX */ + bmpmask32toimage(pData, stride, image, 0x00FF0000U, 0x0000FF00U, 0x000000FFU, + 0x00000000U); + } else if (Info_h.biBitCount == 32 && Info_h.biCompression == 3) { /* bitmask */ + bmpmask32toimage(pData, stride, image, Info_h.biRedMask, Info_h.biGreenMask, + Info_h.biBlueMask, Info_h.biAlphaMask); + } else if (Info_h.biBitCount == 16 && Info_h.biCompression == 0) { /* RGBX */ + bmpmask16toimage(pData, stride, image, 0x7C00U, 0x03E0U, 0x001FU, 0x0000U); + } else if (Info_h.biBitCount == 16 && Info_h.biCompression == 3) { /* bitmask */ + if ((Info_h.biRedMask == 0U) && (Info_h.biGreenMask == 0U) && + (Info_h.biBlueMask == 0U)) { + Info_h.biRedMask = 0xF800U; + Info_h.biGreenMask = 0x07E0U; + Info_h.biBlueMask = 0x001FU; + } + bmpmask16toimage(pData, stride, image, Info_h.biRedMask, Info_h.biGreenMask, + Info_h.biBlueMask, Info_h.biAlphaMask); + } else { + opj_image_destroy(image); + image = NULL; + fprintf(stderr, + "Other system than 24 bits/pixels or 8 bits (no RLE coding) is not yet implemented [%d]\n", + Info_h.biBitCount); + } + free(pData); + fclose(IN); + return image; +} + +int imagetobmp(opj_image_t * image, const char *outfile) +{ + int w, h; + int i, pad; + FILE *fdest = NULL; + int adjustR, adjustG, adjustB; + + if (image->comps[0].prec < 8) { + fprintf(stderr, "imagetobmp: Unsupported precision: %d\n", + image->comps[0].prec); + return 1; + } + if (image->numcomps >= 3 && image->comps[0].dx == image->comps[1].dx + && image->comps[1].dx == image->comps[2].dx + && image->comps[0].dy == image->comps[1].dy + && image->comps[1].dy == image->comps[2].dy + && image->comps[0].prec == image->comps[1].prec + && image->comps[1].prec == image->comps[2].prec + && image->comps[0].sgnd == image->comps[1].sgnd + && image->comps[1].sgnd == image->comps[2].sgnd) { + + /* -->> -->> -->> -->> + 24 bits color + <<-- <<-- <<-- <<-- */ + + fdest = fopen(outfile, "wb"); + if (!fdest) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", outfile); + return 1; + } + + w = (int)image->comps[0].w; + h = (int)image->comps[0].h; + + fprintf(fdest, "BM"); + + /* FILE HEADER */ + /* ------------- */ + fprintf(fdest, "%c%c%c%c", + (OPJ_UINT8)(h * w * 3 + 3 * h * (w % 2) + 54) & 0xff, + (OPJ_UINT8)((h * w * 3 + 3 * h * (w % 2) + 54) >> 8) & 0xff, + (OPJ_UINT8)((h * w * 3 + 3 * h * (w % 2) + 54) >> 16) & 0xff, + (OPJ_UINT8)((h * w * 3 + 3 * h * (w % 2) + 54) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, + ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (54) & 0xff, ((54) >> 8) & 0xff, ((54) >> 16) & 0xff, + ((54) >> 24) & 0xff); + + /* INFO HEADER */ + /* ------------- */ + fprintf(fdest, "%c%c%c%c", (40) & 0xff, ((40) >> 8) & 0xff, ((40) >> 16) & 0xff, + ((40) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (OPJ_UINT8)((w) & 0xff), + (OPJ_UINT8)((w) >> 8) & 0xff, + (OPJ_UINT8)((w) >> 16) & 0xff, + (OPJ_UINT8)((w) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (OPJ_UINT8)((h) & 0xff), + (OPJ_UINT8)((h) >> 8) & 0xff, + (OPJ_UINT8)((h) >> 16) & 0xff, + (OPJ_UINT8)((h) >> 24) & 0xff); + fprintf(fdest, "%c%c", (1) & 0xff, ((1) >> 8) & 0xff); + fprintf(fdest, "%c%c", (24) & 0xff, ((24) >> 8) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, + ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (OPJ_UINT8)(3 * h * w + 3 * h * (w % 2)) & 0xff, + (OPJ_UINT8)((h * w * 3 + 3 * h * (w % 2)) >> 8) & 0xff, + (OPJ_UINT8)((h * w * 3 + 3 * h * (w % 2)) >> 16) & 0xff, + (OPJ_UINT8)((h * w * 3 + 3 * h * (w % 2)) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, + ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, + ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, + ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, + ((0) >> 24) & 0xff); + + if (image->comps[0].prec > 8) { + adjustR = (int)image->comps[0].prec - 8; + printf("BMP CONVERSION: Truncating component 0 from %d bits to 8 bits\n", + image->comps[0].prec); + } else { + adjustR = 0; + } + if (image->comps[1].prec > 8) { + adjustG = (int)image->comps[1].prec - 8; + printf("BMP CONVERSION: Truncating component 1 from %d bits to 8 bits\n", + image->comps[1].prec); + } else { + adjustG = 0; + } + if (image->comps[2].prec > 8) { + adjustB = (int)image->comps[2].prec - 8; + printf("BMP CONVERSION: Truncating component 2 from %d bits to 8 bits\n", + image->comps[2].prec); + } else { + adjustB = 0; + } + + for (i = 0; i < w * h; i++) { + OPJ_UINT8 rc, gc, bc; + int r, g, b; + + r = image->comps[0].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + if (adjustR > 0) { + r = ((r >> adjustR) + ((r >> (adjustR - 1)) % 2)); + } + if (r > 255) { + r = 255; + } else if (r < 0) { + r = 0; + } + rc = (OPJ_UINT8)r; + + g = image->comps[1].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); + if (adjustG > 0) { + g = ((g >> adjustG) + ((g >> (adjustG - 1)) % 2)); + } + if (g > 255) { + g = 255; + } else if (g < 0) { + g = 0; + } + gc = (OPJ_UINT8)g; + + b = image->comps[2].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); + if (adjustB > 0) { + b = ((b >> adjustB) + ((b >> (adjustB - 1)) % 2)); + } + if (b > 255) { + b = 255; + } else if (b < 0) { + b = 0; + } + bc = (OPJ_UINT8)b; + + fprintf(fdest, "%c%c%c", bc, gc, rc); + + if ((i + 1) % w == 0) { + for (pad = ((3 * w) % 4) ? (4 - (3 * w) % 4) : 0; pad > 0; pad--) { /* ADD */ + fprintf(fdest, "%c", 0); + } + } + } + fclose(fdest); + } else { /* Gray-scale */ + + /* -->> -->> -->> -->> + 8 bits non code (Gray scale) + <<-- <<-- <<-- <<-- */ + + fdest = fopen(outfile, "wb"); + if (!fdest) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", outfile); + return 1; + } + if (image->numcomps > 1) { + fprintf(stderr, "imagetobmp: only first component of %d is used.\n", + image->numcomps); + } + w = (int)image->comps[0].w; + h = (int)image->comps[0].h; + + fprintf(fdest, "BM"); + + /* FILE HEADER */ + /* ------------- */ + fprintf(fdest, "%c%c%c%c", (OPJ_UINT8)(h * w + 54 + 1024 + h * (w % 2)) & 0xff, + (OPJ_UINT8)((h * w + 54 + 1024 + h * (w % 2)) >> 8) & 0xff, + (OPJ_UINT8)((h * w + 54 + 1024 + h * (w % 2)) >> 16) & 0xff, + (OPJ_UINT8)((h * w + 54 + 1024 + w * (w % 2)) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, + ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (54 + 1024) & 0xff, ((54 + 1024) >> 8) & 0xff, + ((54 + 1024) >> 16) & 0xff, + ((54 + 1024) >> 24) & 0xff); + + /* INFO HEADER */ + /* ------------- */ + fprintf(fdest, "%c%c%c%c", (40) & 0xff, ((40) >> 8) & 0xff, ((40) >> 16) & 0xff, + ((40) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (OPJ_UINT8)((w) & 0xff), + (OPJ_UINT8)((w) >> 8) & 0xff, + (OPJ_UINT8)((w) >> 16) & 0xff, + (OPJ_UINT8)((w) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (OPJ_UINT8)((h) & 0xff), + (OPJ_UINT8)((h) >> 8) & 0xff, + (OPJ_UINT8)((h) >> 16) & 0xff, + (OPJ_UINT8)((h) >> 24) & 0xff); + fprintf(fdest, "%c%c", (1) & 0xff, ((1) >> 8) & 0xff); + fprintf(fdest, "%c%c", (8) & 0xff, ((8) >> 8) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, + ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (OPJ_UINT8)(h * w + h * (w % 2)) & 0xff, + (OPJ_UINT8)((h * w + h * (w % 2)) >> 8) & 0xff, + (OPJ_UINT8)((h * w + h * (w % 2)) >> 16) & 0xff, + (OPJ_UINT8)((h * w + h * (w % 2)) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, + ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, + ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (256) & 0xff, ((256) >> 8) & 0xff, + ((256) >> 16) & 0xff, ((256) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (256) & 0xff, ((256) >> 8) & 0xff, + ((256) >> 16) & 0xff, ((256) >> 24) & 0xff); + + if (image->comps[0].prec > 8) { + adjustR = (int)image->comps[0].prec - 8; + printf("BMP CONVERSION: Truncating component 0 from %d bits to 8 bits\n", + image->comps[0].prec); + } else { + adjustR = 0; + } + + for (i = 0; i < 256; i++) { + fprintf(fdest, "%c%c%c%c", i, i, i, 0); + } + + for (i = 0; i < w * h; i++) { + int r; + + r = image->comps[0].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + if (adjustR > 0) { + r = ((r >> adjustR) + ((r >> (adjustR - 1)) % 2)); + } + if (r > 255) { + r = 255; + } else if (r < 0) { + r = 0; + } + + fprintf(fdest, "%c", (OPJ_UINT8)r); + + if ((i + 1) % w == 0) { + for (pad = (w % 4) ? (4 - w % 4) : 0; pad > 0; pad--) { /* ADD */ + fprintf(fdest, "%c", 0); + } + } + } + fclose(fdest); + } + + return 0; +} diff --git a/openjpeg/src/bin/jp2/convertpng.c b/openjpeg/src/bin/jp2/convertpng.c new file mode 100644 index 000000000..44d985f23 --- /dev/null +++ b/openjpeg/src/bin/jp2/convertpng.c @@ -0,0 +1,517 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * Copyright (c) 2003-2014, Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * Copyright (c) 2015, Matthieu Darbois + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "opj_apps_config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include <zlib.h> +#include <png.h> + +#include "openjpeg.h" +#include "convert.h" + +#define PNG_MAGIC "\x89PNG\x0d\x0a\x1a\x0a" +#define MAGIC_SIZE 8 +/* PNG allows bits per sample: 1, 2, 4, 8, 16 */ + + +static void convert_16u32s_C1R(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < length; i++) { + OPJ_INT32 val0 = *pSrc++; + OPJ_INT32 val1 = *pSrc++; + pDst[i] = val0 << 8 | val1; + } +} + +opj_image_t *pngtoimage(const char *read_idf, opj_cparameters_t * params) +{ + png_structp png = NULL; + png_infop info = NULL; + double gamma; + int bit_depth, interlace_type, compression_type, filter_type; + OPJ_UINT32 i; + png_uint_32 width, height = 0U; + int color_type; + FILE *reader = NULL; + OPJ_BYTE** rows = NULL; + OPJ_INT32* row32s = NULL; + /* j2k: */ + opj_image_t *image = NULL; + opj_image_cmptparm_t cmptparm[4]; + OPJ_UINT32 nr_comp; + OPJ_BYTE sigbuf[8]; + convert_XXx32s_C1R cvtXXTo32s = NULL; + convert_32s_CXPX cvtCxToPx = NULL; + OPJ_INT32* planes[4]; + + if ((reader = fopen(read_idf, "rb")) == NULL) { + fprintf(stderr, "pngtoimage: can not open %s\n", read_idf); + return NULL; + } + + if (fread(sigbuf, 1, MAGIC_SIZE, reader) != MAGIC_SIZE + || memcmp(sigbuf, PNG_MAGIC, MAGIC_SIZE) != 0) { + fprintf(stderr, "pngtoimage: %s is no valid PNG file\n", read_idf); + goto fin; + } + + if ((png = png_create_read_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL)) == NULL) { + goto fin; + } + if ((info = png_create_info_struct(png)) == NULL) { + goto fin; + } + + if (setjmp(png_jmpbuf(png))) { + goto fin; + } + + png_init_io(png, reader); + png_set_sig_bytes(png, MAGIC_SIZE); + + png_read_info(png, info); + + if (png_get_IHDR(png, info, &width, &height, + &bit_depth, &color_type, &interlace_type, + &compression_type, &filter_type) == 0) { + goto fin; + } + + /* png_set_expand(): + * expand paletted images to RGB, expand grayscale images of + * less than 8-bit depth to 8-bit depth, and expand tRNS chunks + * to alpha channels. + */ + if (color_type == PNG_COLOR_TYPE_PALETTE) { + png_set_expand(png); + } + + if (png_get_valid(png, info, PNG_INFO_tRNS)) { + png_set_expand(png); + } + /* We might wan't to expand background */ + /* + if(png_get_valid(png, info, PNG_INFO_bKGD)) { + png_color_16p bgnd; + png_get_bKGD(png, info, &bgnd); + png_set_background(png, bgnd, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + } + */ + + if (!png_get_gAMA(png, info, &gamma)) { + gamma = 1.0; + } + + /* we're not displaying but converting, screen gamma == 1.0 */ + png_set_gamma(png, 1.0, gamma); + + png_read_update_info(png, info); + + color_type = png_get_color_type(png, info); + + switch (color_type) { + case PNG_COLOR_TYPE_GRAY: + nr_comp = 1; + break; + case PNG_COLOR_TYPE_GRAY_ALPHA: + nr_comp = 2; + break; + case PNG_COLOR_TYPE_RGB: + nr_comp = 3; + break; + case PNG_COLOR_TYPE_RGB_ALPHA: + nr_comp = 4; + break; + default: + fprintf(stderr, "pngtoimage: colortype %d is not supported\n", color_type); + goto fin; + } + cvtCxToPx = convert_32s_CXPX_LUT[nr_comp]; + bit_depth = png_get_bit_depth(png, info); + + switch (bit_depth) { + case 1: + case 2: + case 4: + case 8: + cvtXXTo32s = convert_XXu32s_C1R_LUT[bit_depth]; + break; + case 16: /* 16 bpp is specific to PNG */ + cvtXXTo32s = convert_16u32s_C1R; + break; + default: + fprintf(stderr, "pngtoimage: bit depth %d is not supported\n", bit_depth); + goto fin; + } + + + rows = (OPJ_BYTE**)calloc(height + 1, sizeof(OPJ_BYTE*)); + if (rows == NULL) { + fprintf(stderr, "pngtoimage: memory out\n"); + goto fin; + } + for (i = 0; i < height; ++i) { + rows[i] = (OPJ_BYTE*)malloc(png_get_rowbytes(png, info)); + if (rows[i] == NULL) { + fprintf(stderr, "pngtoimage: memory out\n"); + goto fin; + } + } + png_read_image(png, rows); + + /* Create image */ + memset(cmptparm, 0, sizeof(cmptparm)); + for (i = 0; i < nr_comp; ++i) { + cmptparm[i].prec = (OPJ_UINT32)bit_depth; + /* bits_per_pixel: 8 or 16 */ + cmptparm[i].bpp = (OPJ_UINT32)bit_depth; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = (OPJ_UINT32)params->subsampling_dx; + cmptparm[i].dy = (OPJ_UINT32)params->subsampling_dy; + cmptparm[i].w = (OPJ_UINT32)width; + cmptparm[i].h = (OPJ_UINT32)height; + } + + image = opj_image_create(nr_comp, &cmptparm[0], + (nr_comp > 2U) ? OPJ_CLRSPC_SRGB : OPJ_CLRSPC_GRAY); + if (image == NULL) { + goto fin; + } + image->x0 = (OPJ_UINT32)params->image_offset_x0; + image->y0 = (OPJ_UINT32)params->image_offset_y0; + image->x1 = (OPJ_UINT32)(image->x0 + (width - 1) * (OPJ_UINT32) + params->subsampling_dx + 1 + image->x0); + image->y1 = (OPJ_UINT32)(image->y0 + (height - 1) * (OPJ_UINT32) + params->subsampling_dy + 1 + image->y0); + + row32s = (OPJ_INT32 *)malloc((size_t)width * nr_comp * sizeof(OPJ_INT32)); + if (row32s == NULL) { + goto fin; + } + + /* Set alpha channel */ + image->comps[nr_comp - 1U].alpha = 1U - (nr_comp & 1U); + + for (i = 0; i < nr_comp; i++) { + planes[i] = image->comps[i].data; + } + + for (i = 0; i < height; ++i) { + cvtXXTo32s(rows[i], row32s, (OPJ_SIZE_T)width * nr_comp); + cvtCxToPx(row32s, planes, width); + planes[0] += width; + planes[1] += width; + planes[2] += width; + planes[3] += width; + } +fin: + if (rows) { + for (i = 0; i < height; ++i) + if (rows[i]) { + free(rows[i]); + } + free(rows); + } + if (row32s) { + free(row32s); + } + if (png) { + png_destroy_read_struct(&png, &info, NULL); + } + + fclose(reader); + + return image; + +}/* pngtoimage() */ + + +static void convert_32s16u_C1R(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < length; i++) { + OPJ_UINT32 val = (OPJ_UINT32)pSrc[i]; + *pDst++ = (OPJ_BYTE)(val >> 8); + *pDst++ = (OPJ_BYTE)val; + } +} +int imagetopng(opj_image_t * image, const char *write_idf) +{ + FILE * volatile writer = NULL; + png_structp png = NULL; + png_infop info = NULL; + png_bytep volatile row_buf = NULL; + int nr_comp, color_type; + volatile int prec; + png_color_8 sig_bit; + OPJ_INT32 const* planes[4]; + int i; + OPJ_INT32* volatile buffer32s = NULL; + + volatile int fails = 1; + + memset(&sig_bit, 0, sizeof(sig_bit)); + prec = (int)image->comps[0].prec; + planes[0] = image->comps[0].data; + nr_comp = (int)image->numcomps; + + if (nr_comp > 4) { + nr_comp = 4; + } + for (i = 1; i < nr_comp; ++i) { + if (image->comps[0].dx != image->comps[i].dx) { + break; + } + if (image->comps[0].dy != image->comps[i].dy) { + break; + } + if (image->comps[0].prec != image->comps[i].prec) { + break; + } + if (image->comps[0].sgnd != image->comps[i].sgnd) { + break; + } + planes[i] = image->comps[i].data; + } + if (i != nr_comp) { + fprintf(stderr, + "imagetopng: All components shall have the same subsampling, same bit depth, same sign.\n"); + fprintf(stderr, "\tAborting\n"); + return 1; + } + for (i = 0; i < nr_comp; ++i) { + clip_component(&(image->comps[i]), image->comps[0].prec); + } + if (prec > 8 && prec < 16) { + for (i = 0; i < nr_comp; ++i) { + scale_component(&(image->comps[i]), 16); + } + prec = 16; + } else if (prec < 8 && nr_comp > 1) { /* GRAY_ALPHA, RGB, RGB_ALPHA */ + for (i = 0; i < nr_comp; ++i) { + scale_component(&(image->comps[i]), 8); + } + prec = 8; + } else if ((prec > 1) && (prec < 8) && ((prec == 6) || + ((prec & 1) == 1))) { /* GRAY with non native precision */ + if ((prec == 5) || (prec == 6)) { + prec = 8; + } else { + prec++; + } + for (i = 0; i < nr_comp; ++i) { + scale_component(&(image->comps[i]), (OPJ_UINT32)prec); + } + } + + if (prec != 1 && prec != 2 && prec != 4 && prec != 8 && prec != 16) { + fprintf(stderr, "imagetopng: can not create %s\n\twrong bit_depth %d\n", + write_idf, prec); + return fails; + } + + writer = fopen(write_idf, "wb"); + + if (writer == NULL) { + return fails; + } + + /* Create and initialize the png_struct with the desired error handler + * functions. If you want to use the default stderr and longjump method, + * you can supply NULL for the last three parameters. We also check that + * the library version is compatible with the one used at compile time, + * in case we are using dynamically linked libraries. REQUIRED. + */ + png = png_create_write_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + /*png_voidp user_error_ptr, user_error_fn, user_warning_fn); */ + + if (png == NULL) { + goto fin; + } + + /* Allocate/initialize the image information data. REQUIRED + */ + info = png_create_info_struct(png); + + if (info == NULL) { + goto fin; + } + + /* Set error handling. REQUIRED if you are not supplying your own + * error handling functions in the png_create_write_struct() call. + */ + if (setjmp(png_jmpbuf(png))) { + goto fin; + } + + /* I/O initialization functions is REQUIRED + */ + png_init_io(png, writer); + + /* Set the image information here. Width and height are up to 2^31, + * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on + * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, + * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, + * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or + * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST + * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. + * REQUIRED + * + * ERRORS: + * + * color_type == PNG_COLOR_TYPE_PALETTE && bit_depth > 8 + * color_type == PNG_COLOR_TYPE_RGB && bit_depth < 8 + * color_type == PNG_COLOR_TYPE_GRAY_ALPHA && bit_depth < 8 + * color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8 + * + */ + png_set_compression_level(png, Z_BEST_COMPRESSION); + + if (nr_comp >= 3) { /* RGB(A) */ + color_type = PNG_COLOR_TYPE_RGB; + sig_bit.red = sig_bit.green = sig_bit.blue = (png_byte)prec; + } else { /* GRAY(A) */ + color_type = PNG_COLOR_TYPE_GRAY; + sig_bit.gray = (png_byte)prec; + } + if ((nr_comp & 1) == 0) { /* ALPHA */ + color_type |= PNG_COLOR_MASK_ALPHA; + sig_bit.alpha = (png_byte)prec; + } + + png_set_IHDR(png, info, image->comps[0].w, image->comps[0].h, prec, color_type, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + png_set_sBIT(png, info, &sig_bit); + /* png_set_gamma(png, 2.2, 1./2.2); */ + /* png_set_sRGB(png, info, PNG_sRGB_INTENT_PERCEPTUAL); */ + png_write_info(png, info); + + /* setup conversion */ + { + OPJ_SIZE_T rowStride; + png_size_t png_row_size; + + png_row_size = png_get_rowbytes(png, info); + rowStride = ((OPJ_SIZE_T)image->comps[0].w * (OPJ_SIZE_T)nr_comp * + (OPJ_SIZE_T)prec + 7U) / 8U; + if (rowStride != (OPJ_SIZE_T)png_row_size) { + fprintf(stderr, "Invalid PNG row size\n"); + goto fin; + } + row_buf = (png_bytep)malloc(png_row_size); + if (row_buf == NULL) { + fprintf(stderr, "Can't allocate memory for PNG row\n"); + goto fin; + } + buffer32s = (OPJ_INT32*)malloc((OPJ_SIZE_T)image->comps[0].w * + (OPJ_SIZE_T)nr_comp * sizeof(OPJ_INT32)); + if (buffer32s == NULL) { + fprintf(stderr, "Can't allocate memory for interleaved 32s row\n"); + goto fin; + } + } + + /* convert */ + { + OPJ_SIZE_T width = image->comps[0].w; + OPJ_UINT32 y; + convert_32s_PXCX cvtPxToCx = convert_32s_PXCX_LUT[nr_comp]; + convert_32sXXx_C1R cvt32sToPack = NULL; + OPJ_INT32 adjust = image->comps[0].sgnd ? 1 << (prec - 1) : 0; + png_bytep row_buf_cpy = row_buf; + OPJ_INT32* buffer32s_cpy = buffer32s; + + switch (prec) { + case 1: + case 2: + case 4: + case 8: + cvt32sToPack = convert_32sXXu_C1R_LUT[prec]; + break; + case 16: + cvt32sToPack = convert_32s16u_C1R; + break; + default: + /* never here */ + break; + } + + for (y = 0; y < image->comps[0].h; ++y) { + cvtPxToCx(planes, buffer32s_cpy, width, adjust); + cvt32sToPack(buffer32s_cpy, row_buf_cpy, width * (OPJ_SIZE_T)nr_comp); + png_write_row(png, row_buf_cpy); + planes[0] += width; + planes[1] += width; + planes[2] += width; + planes[3] += width; + } + } + + png_write_end(png, info); + + fails = 0; + +fin: + if (png) { + png_destroy_write_struct(&png, &info); + } + if (row_buf) { + free(row_buf); + } + if (buffer32s) { + free(buffer32s); + } + fclose(writer); + + if (fails) { + (void)remove(write_idf); /* ignore return value */ + } + + return fails; +}/* imagetopng() */ diff --git a/openjpeg/src/bin/jp2/converttif.c b/openjpeg/src/bin/jp2/converttif.c new file mode 100644 index 000000000..6e5c4f400 --- /dev/null +++ b/openjpeg/src/bin/jp2/converttif.c @@ -0,0 +1,1510 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * Copyright (c) 2003-2014, Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * Copyright (c) 2015, Matthieu Darbois + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "opj_apps_config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <limits.h> + +#ifndef OPJ_HAVE_LIBTIFF +# error OPJ_HAVE_LIBTIFF_NOT_DEFINED +#endif /* OPJ_HAVE_LIBTIFF */ + +#include <tiffio.h> +#include "openjpeg.h" +#include "convert.h" +#include "opj_inttypes.h" + +/* -->> -->> -->> -->> + + TIFF IMAGE FORMAT + + <<-- <<-- <<-- <<-- */ +#define PUTBITS2(s, nb) \ + trailing <<= remaining; \ + trailing |= (unsigned int)((s) >> (nb - remaining)); \ + *pDst++ = (OPJ_BYTE)trailing; \ + trailing = (unsigned int)((s) & ((1U << (nb - remaining)) - 1U)); \ + if (nb >= (remaining + 8)) { \ + *pDst++ = (OPJ_BYTE)(trailing >> (nb - (remaining + 8))); \ + trailing &= (unsigned int)((1U << (nb - (remaining + 8))) - 1U); \ + remaining += 16 - nb; \ + } else { \ + remaining += 8 - nb; \ + } + +#define PUTBITS(s, nb) \ + if (nb >= remaining) { \ + PUTBITS2(s, nb) \ + } else { \ + trailing <<= nb; \ + trailing |= (unsigned int)(s); \ + remaining -= nb; \ + } +#define FLUSHBITS() \ + if (remaining != 8) { \ + trailing <<= remaining; \ + *pDst++ = (OPJ_BYTE)trailing; \ + } + +static void tif_32sto3u(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + + for (i = 0; i < (length & ~(OPJ_SIZE_T)7U); i += 8U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i + 0]; + OPJ_UINT32 src1 = (OPJ_UINT32)pSrc[i + 1]; + OPJ_UINT32 src2 = (OPJ_UINT32)pSrc[i + 2]; + OPJ_UINT32 src3 = (OPJ_UINT32)pSrc[i + 3]; + OPJ_UINT32 src4 = (OPJ_UINT32)pSrc[i + 4]; + OPJ_UINT32 src5 = (OPJ_UINT32)pSrc[i + 5]; + OPJ_UINT32 src6 = (OPJ_UINT32)pSrc[i + 6]; + OPJ_UINT32 src7 = (OPJ_UINT32)pSrc[i + 7]; + + *pDst++ = (OPJ_BYTE)((src0 << 5) | (src1 << 2) | (src2 >> 1)); + *pDst++ = (OPJ_BYTE)((src2 << 7) | (src3 << 4) | (src4 << 1) | (src5 >> 2)); + *pDst++ = (OPJ_BYTE)((src5 << 6) | (src6 << 3) | (src7)); + } + + if (length & 7U) { + unsigned int trailing = 0U; + int remaining = 8U; + length &= 7U; + PUTBITS((OPJ_UINT32)pSrc[i + 0], 3) + if (length > 1U) { + PUTBITS((OPJ_UINT32)pSrc[i + 1], 3) + if (length > 2U) { + PUTBITS((OPJ_UINT32)pSrc[i + 2], 3) + if (length > 3U) { + PUTBITS((OPJ_UINT32)pSrc[i + 3], 3) + if (length > 4U) { + PUTBITS((OPJ_UINT32)pSrc[i + 4], 3) + if (length > 5U) { + PUTBITS((OPJ_UINT32)pSrc[i + 5], 3) + if (length > 6U) { + PUTBITS((OPJ_UINT32)pSrc[i + 6], 3) + } + } + } + } + } + } + FLUSHBITS() + } +} + +static void tif_32sto5u(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + + for (i = 0; i < (length & ~(OPJ_SIZE_T)7U); i += 8U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i + 0]; + OPJ_UINT32 src1 = (OPJ_UINT32)pSrc[i + 1]; + OPJ_UINT32 src2 = (OPJ_UINT32)pSrc[i + 2]; + OPJ_UINT32 src3 = (OPJ_UINT32)pSrc[i + 3]; + OPJ_UINT32 src4 = (OPJ_UINT32)pSrc[i + 4]; + OPJ_UINT32 src5 = (OPJ_UINT32)pSrc[i + 5]; + OPJ_UINT32 src6 = (OPJ_UINT32)pSrc[i + 6]; + OPJ_UINT32 src7 = (OPJ_UINT32)pSrc[i + 7]; + + *pDst++ = (OPJ_BYTE)((src0 << 3) | (src1 >> 2)); + *pDst++ = (OPJ_BYTE)((src1 << 6) | (src2 << 1) | (src3 >> 4)); + *pDst++ = (OPJ_BYTE)((src3 << 4) | (src4 >> 1)); + *pDst++ = (OPJ_BYTE)((src4 << 7) | (src5 << 2) | (src6 >> 3)); + *pDst++ = (OPJ_BYTE)((src6 << 5) | (src7)); + + } + + if (length & 7U) { + unsigned int trailing = 0U; + int remaining = 8U; + length &= 7U; + PUTBITS((OPJ_UINT32)pSrc[i + 0], 5) + if (length > 1U) { + PUTBITS((OPJ_UINT32)pSrc[i + 1], 5) + if (length > 2U) { + PUTBITS((OPJ_UINT32)pSrc[i + 2], 5) + if (length > 3U) { + PUTBITS((OPJ_UINT32)pSrc[i + 3], 5) + if (length > 4U) { + PUTBITS((OPJ_UINT32)pSrc[i + 4], 5) + if (length > 5U) { + PUTBITS((OPJ_UINT32)pSrc[i + 5], 5) + if (length > 6U) { + PUTBITS((OPJ_UINT32)pSrc[i + 6], 5) + } + } + } + } + } + } + FLUSHBITS() + } +} + +static void tif_32sto7u(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + + for (i = 0; i < (length & ~(OPJ_SIZE_T)7U); i += 8U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i + 0]; + OPJ_UINT32 src1 = (OPJ_UINT32)pSrc[i + 1]; + OPJ_UINT32 src2 = (OPJ_UINT32)pSrc[i + 2]; + OPJ_UINT32 src3 = (OPJ_UINT32)pSrc[i + 3]; + OPJ_UINT32 src4 = (OPJ_UINT32)pSrc[i + 4]; + OPJ_UINT32 src5 = (OPJ_UINT32)pSrc[i + 5]; + OPJ_UINT32 src6 = (OPJ_UINT32)pSrc[i + 6]; + OPJ_UINT32 src7 = (OPJ_UINT32)pSrc[i + 7]; + + *pDst++ = (OPJ_BYTE)((src0 << 1) | (src1 >> 6)); + *pDst++ = (OPJ_BYTE)((src1 << 2) | (src2 >> 5)); + *pDst++ = (OPJ_BYTE)((src2 << 3) | (src3 >> 4)); + *pDst++ = (OPJ_BYTE)((src3 << 4) | (src4 >> 3)); + *pDst++ = (OPJ_BYTE)((src4 << 5) | (src5 >> 2)); + *pDst++ = (OPJ_BYTE)((src5 << 6) | (src6 >> 1)); + *pDst++ = (OPJ_BYTE)((src6 << 7) | (src7)); + } + + if (length & 7U) { + unsigned int trailing = 0U; + int remaining = 8U; + length &= 7U; + PUTBITS((OPJ_UINT32)pSrc[i + 0], 7) + if (length > 1U) { + PUTBITS((OPJ_UINT32)pSrc[i + 1], 7) + if (length > 2U) { + PUTBITS((OPJ_UINT32)pSrc[i + 2], 7) + if (length > 3U) { + PUTBITS((OPJ_UINT32)pSrc[i + 3], 7) + if (length > 4U) { + PUTBITS((OPJ_UINT32)pSrc[i + 4], 7) + if (length > 5U) { + PUTBITS((OPJ_UINT32)pSrc[i + 5], 7) + if (length > 6U) { + PUTBITS((OPJ_UINT32)pSrc[i + 6], 7) + } + } + } + } + } + } + FLUSHBITS() + } +} + +static void tif_32sto9u(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + + for (i = 0; i < (length & ~(OPJ_SIZE_T)7U); i += 8U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i + 0]; + OPJ_UINT32 src1 = (OPJ_UINT32)pSrc[i + 1]; + OPJ_UINT32 src2 = (OPJ_UINT32)pSrc[i + 2]; + OPJ_UINT32 src3 = (OPJ_UINT32)pSrc[i + 3]; + OPJ_UINT32 src4 = (OPJ_UINT32)pSrc[i + 4]; + OPJ_UINT32 src5 = (OPJ_UINT32)pSrc[i + 5]; + OPJ_UINT32 src6 = (OPJ_UINT32)pSrc[i + 6]; + OPJ_UINT32 src7 = (OPJ_UINT32)pSrc[i + 7]; + + *pDst++ = (OPJ_BYTE)((src0 >> 1)); + *pDst++ = (OPJ_BYTE)((src0 << 7) | (src1 >> 2)); + *pDst++ = (OPJ_BYTE)((src1 << 6) | (src2 >> 3)); + *pDst++ = (OPJ_BYTE)((src2 << 5) | (src3 >> 4)); + *pDst++ = (OPJ_BYTE)((src3 << 4) | (src4 >> 5)); + *pDst++ = (OPJ_BYTE)((src4 << 3) | (src5 >> 6)); + *pDst++ = (OPJ_BYTE)((src5 << 2) | (src6 >> 7)); + *pDst++ = (OPJ_BYTE)((src6 << 1) | (src7 >> 8)); + *pDst++ = (OPJ_BYTE)(src7); + } + + if (length & 7U) { + unsigned int trailing = 0U; + int remaining = 8U; + length &= 7U; + PUTBITS2((OPJ_UINT32)pSrc[i + 0], 9) + if (length > 1U) { + PUTBITS2((OPJ_UINT32)pSrc[i + 1], 9) + if (length > 2U) { + PUTBITS2((OPJ_UINT32)pSrc[i + 2], 9) + if (length > 3U) { + PUTBITS2((OPJ_UINT32)pSrc[i + 3], 9) + if (length > 4U) { + PUTBITS2((OPJ_UINT32)pSrc[i + 4], 9) + if (length > 5U) { + PUTBITS2((OPJ_UINT32)pSrc[i + 5], 9) + if (length > 6U) { + PUTBITS2((OPJ_UINT32)pSrc[i + 6], 9) + } + } + } + } + } + } + FLUSHBITS() + } +} + +static void tif_32sto10u(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)3U); i += 4U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i + 0]; + OPJ_UINT32 src1 = (OPJ_UINT32)pSrc[i + 1]; + OPJ_UINT32 src2 = (OPJ_UINT32)pSrc[i + 2]; + OPJ_UINT32 src3 = (OPJ_UINT32)pSrc[i + 3]; + + *pDst++ = (OPJ_BYTE)(src0 >> 2); + *pDst++ = (OPJ_BYTE)(((src0 & 0x3U) << 6) | (src1 >> 4)); + *pDst++ = (OPJ_BYTE)(((src1 & 0xFU) << 4) | (src2 >> 6)); + *pDst++ = (OPJ_BYTE)(((src2 & 0x3FU) << 2) | (src3 >> 8)); + *pDst++ = (OPJ_BYTE)(src3); + } + + if (length & 3U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i + 0]; + OPJ_UINT32 src1 = 0U; + OPJ_UINT32 src2 = 0U; + length = length & 3U; + + if (length > 1U) { + src1 = (OPJ_UINT32)pSrc[i + 1]; + if (length > 2U) { + src2 = (OPJ_UINT32)pSrc[i + 2]; + } + } + *pDst++ = (OPJ_BYTE)(src0 >> 2); + *pDst++ = (OPJ_BYTE)(((src0 & 0x3U) << 6) | (src1 >> 4)); + if (length > 1U) { + *pDst++ = (OPJ_BYTE)(((src1 & 0xFU) << 4) | (src2 >> 6)); + if (length > 2U) { + *pDst++ = (OPJ_BYTE)(((src2 & 0x3FU) << 2)); + } + } + } +} +static void tif_32sto11u(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + + for (i = 0; i < (length & ~(OPJ_SIZE_T)7U); i += 8U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i + 0]; + OPJ_UINT32 src1 = (OPJ_UINT32)pSrc[i + 1]; + OPJ_UINT32 src2 = (OPJ_UINT32)pSrc[i + 2]; + OPJ_UINT32 src3 = (OPJ_UINT32)pSrc[i + 3]; + OPJ_UINT32 src4 = (OPJ_UINT32)pSrc[i + 4]; + OPJ_UINT32 src5 = (OPJ_UINT32)pSrc[i + 5]; + OPJ_UINT32 src6 = (OPJ_UINT32)pSrc[i + 6]; + OPJ_UINT32 src7 = (OPJ_UINT32)pSrc[i + 7]; + + *pDst++ = (OPJ_BYTE)((src0 >> 3)); + *pDst++ = (OPJ_BYTE)((src0 << 5) | (src1 >> 6)); + *pDst++ = (OPJ_BYTE)((src1 << 2) | (src2 >> 9)); + *pDst++ = (OPJ_BYTE)((src2 >> 1)); + *pDst++ = (OPJ_BYTE)((src2 << 7) | (src3 >> 4)); + *pDst++ = (OPJ_BYTE)((src3 << 4) | (src4 >> 7)); + *pDst++ = (OPJ_BYTE)((src4 << 1) | (src5 >> 10)); + *pDst++ = (OPJ_BYTE)((src5 >> 2)); + *pDst++ = (OPJ_BYTE)((src5 << 6) | (src6 >> 5)); + *pDst++ = (OPJ_BYTE)((src6 << 3) | (src7 >> 8)); + *pDst++ = (OPJ_BYTE)(src7); + } + + if (length & 7U) { + unsigned int trailing = 0U; + int remaining = 8U; + length &= 7U; + PUTBITS2((OPJ_UINT32)pSrc[i + 0], 11) + if (length > 1U) { + PUTBITS2((OPJ_UINT32)pSrc[i + 1], 11) + if (length > 2U) { + PUTBITS2((OPJ_UINT32)pSrc[i + 2], 11) + if (length > 3U) { + PUTBITS2((OPJ_UINT32)pSrc[i + 3], 11) + if (length > 4U) { + PUTBITS2((OPJ_UINT32)pSrc[i + 4], 11) + if (length > 5U) { + PUTBITS2((OPJ_UINT32)pSrc[i + 5], 11) + if (length > 6U) { + PUTBITS2((OPJ_UINT32)pSrc[i + 6], 11) + } + } + } + } + } + } + FLUSHBITS() + } +} +static void tif_32sto12u(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)1U); i += 2U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i + 0]; + OPJ_UINT32 src1 = (OPJ_UINT32)pSrc[i + 1]; + + *pDst++ = (OPJ_BYTE)(src0 >> 4); + *pDst++ = (OPJ_BYTE)(((src0 & 0xFU) << 4) | (src1 >> 8)); + *pDst++ = (OPJ_BYTE)(src1); + } + + if (length & 1U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i + 0]; + *pDst++ = (OPJ_BYTE)(src0 >> 4); + *pDst++ = (OPJ_BYTE)(((src0 & 0xFU) << 4)); + } +} +static void tif_32sto13u(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + + for (i = 0; i < (length & ~(OPJ_SIZE_T)7U); i += 8U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i + 0]; + OPJ_UINT32 src1 = (OPJ_UINT32)pSrc[i + 1]; + OPJ_UINT32 src2 = (OPJ_UINT32)pSrc[i + 2]; + OPJ_UINT32 src3 = (OPJ_UINT32)pSrc[i + 3]; + OPJ_UINT32 src4 = (OPJ_UINT32)pSrc[i + 4]; + OPJ_UINT32 src5 = (OPJ_UINT32)pSrc[i + 5]; + OPJ_UINT32 src6 = (OPJ_UINT32)pSrc[i + 6]; + OPJ_UINT32 src7 = (OPJ_UINT32)pSrc[i + 7]; + + *pDst++ = (OPJ_BYTE)((src0 >> 5)); + *pDst++ = (OPJ_BYTE)((src0 << 3) | (src1 >> 10)); + *pDst++ = (OPJ_BYTE)((src1 >> 2)); + *pDst++ = (OPJ_BYTE)((src1 << 6) | (src2 >> 7)); + *pDst++ = (OPJ_BYTE)((src2 << 1) | (src3 >> 12)); + *pDst++ = (OPJ_BYTE)((src3 >> 4)); + *pDst++ = (OPJ_BYTE)((src3 << 4) | (src4 >> 9)); + *pDst++ = (OPJ_BYTE)((src4 >> 1)); + *pDst++ = (OPJ_BYTE)((src4 << 7) | (src5 >> 6)); + *pDst++ = (OPJ_BYTE)((src5 << 2) | (src6 >> 11)); + *pDst++ = (OPJ_BYTE)((src6 >> 3)); + *pDst++ = (OPJ_BYTE)((src6 << 5) | (src7 >> 8)); + *pDst++ = (OPJ_BYTE)(src7); + } + + if (length & 7U) { + unsigned int trailing = 0U; + int remaining = 8U; + length &= 7U; + PUTBITS2((OPJ_UINT32)pSrc[i + 0], 13) + if (length > 1U) { + PUTBITS2((OPJ_UINT32)pSrc[i + 1], 13) + if (length > 2U) { + PUTBITS2((OPJ_UINT32)pSrc[i + 2], 13) + if (length > 3U) { + PUTBITS2((OPJ_UINT32)pSrc[i + 3], 13) + if (length > 4U) { + PUTBITS2((OPJ_UINT32)pSrc[i + 4], 13) + if (length > 5U) { + PUTBITS2((OPJ_UINT32)pSrc[i + 5], 13) + if (length > 6U) { + PUTBITS2((OPJ_UINT32)pSrc[i + 6], 13) + } + } + } + } + } + } + FLUSHBITS() + } +} +static void tif_32sto14u(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)3U); i += 4U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i + 0]; + OPJ_UINT32 src1 = (OPJ_UINT32)pSrc[i + 1]; + OPJ_UINT32 src2 = (OPJ_UINT32)pSrc[i + 2]; + OPJ_UINT32 src3 = (OPJ_UINT32)pSrc[i + 3]; + + *pDst++ = (OPJ_BYTE)(src0 >> 6); + *pDst++ = (OPJ_BYTE)(((src0 & 0x3FU) << 2) | (src1 >> 12)); + *pDst++ = (OPJ_BYTE)(src1 >> 4); + *pDst++ = (OPJ_BYTE)(((src1 & 0xFU) << 4) | (src2 >> 10)); + *pDst++ = (OPJ_BYTE)(src2 >> 2); + *pDst++ = (OPJ_BYTE)(((src2 & 0x3U) << 6) | (src3 >> 8)); + *pDst++ = (OPJ_BYTE)(src3); + } + + if (length & 3U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i + 0]; + OPJ_UINT32 src1 = 0U; + OPJ_UINT32 src2 = 0U; + length = length & 3U; + + if (length > 1U) { + src1 = (OPJ_UINT32)pSrc[i + 1]; + if (length > 2U) { + src2 = (OPJ_UINT32)pSrc[i + 2]; + } + } + *pDst++ = (OPJ_BYTE)(src0 >> 6); + *pDst++ = (OPJ_BYTE)(((src0 & 0x3FU) << 2) | (src1 >> 12)); + if (length > 1U) { + *pDst++ = (OPJ_BYTE)(src1 >> 4); + *pDst++ = (OPJ_BYTE)(((src1 & 0xFU) << 4) | (src2 >> 10)); + if (length > 2U) { + *pDst++ = (OPJ_BYTE)(src2 >> 2); + *pDst++ = (OPJ_BYTE)(((src2 & 0x3U) << 6)); + } + } + } +} +static void tif_32sto15u(const OPJ_INT32* pSrc, OPJ_BYTE* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + + for (i = 0; i < (length & ~(OPJ_SIZE_T)7U); i += 8U) { + OPJ_UINT32 src0 = (OPJ_UINT32)pSrc[i + 0]; + OPJ_UINT32 src1 = (OPJ_UINT32)pSrc[i + 1]; + OPJ_UINT32 src2 = (OPJ_UINT32)pSrc[i + 2]; + OPJ_UINT32 src3 = (OPJ_UINT32)pSrc[i + 3]; + OPJ_UINT32 src4 = (OPJ_UINT32)pSrc[i + 4]; + OPJ_UINT32 src5 = (OPJ_UINT32)pSrc[i + 5]; + OPJ_UINT32 src6 = (OPJ_UINT32)pSrc[i + 6]; + OPJ_UINT32 src7 = (OPJ_UINT32)pSrc[i + 7]; + + *pDst++ = (OPJ_BYTE)((src0 >> 7)); + *pDst++ = (OPJ_BYTE)((src0 << 1) | (src1 >> 14)); + *pDst++ = (OPJ_BYTE)((src1 >> 6)); + *pDst++ = (OPJ_BYTE)((src1 << 2) | (src2 >> 13)); + *pDst++ = (OPJ_BYTE)((src2 >> 5)); + *pDst++ = (OPJ_BYTE)((src2 << 3) | (src3 >> 12)); + *pDst++ = (OPJ_BYTE)((src3 >> 4)); + *pDst++ = (OPJ_BYTE)((src3 << 4) | (src4 >> 11)); + *pDst++ = (OPJ_BYTE)((src4 >> 3)); + *pDst++ = (OPJ_BYTE)((src4 << 5) | (src5 >> 10)); + *pDst++ = (OPJ_BYTE)((src5 >> 2)); + *pDst++ = (OPJ_BYTE)((src5 << 6) | (src6 >> 9)); + *pDst++ = (OPJ_BYTE)((src6 >> 1)); + *pDst++ = (OPJ_BYTE)((src6 << 7) | (src7 >> 8)); + *pDst++ = (OPJ_BYTE)(src7); + } + + if (length & 7U) { + unsigned int trailing = 0U; + int remaining = 8U; + length &= 7U; + PUTBITS2((OPJ_UINT32)pSrc[i + 0], 15) + if (length > 1U) { + PUTBITS2((OPJ_UINT32)pSrc[i + 1], 15) + if (length > 2U) { + PUTBITS2((OPJ_UINT32)pSrc[i + 2], 15) + if (length > 3U) { + PUTBITS2((OPJ_UINT32)pSrc[i + 3], 15) + if (length > 4U) { + PUTBITS2((OPJ_UINT32)pSrc[i + 4], 15) + if (length > 5U) { + PUTBITS2((OPJ_UINT32)pSrc[i + 5], 15) + if (length > 6U) { + PUTBITS2((OPJ_UINT32)pSrc[i + 6], 15) + } + } + } + } + } + } + FLUSHBITS() + } +} +static void tif_32sto16u(const OPJ_INT32* pSrc, OPJ_UINT16* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < length; ++i) { + pDst[i] = (OPJ_UINT16)pSrc[i]; + } +} + +int imagetotif(opj_image_t * image, const char *outfile) +{ + TIFF *tif; + tdata_t buf; + uint32 width, height; + uint16 bps, tiPhoto; + int adjust, sgnd; + int64_t strip_size, rowStride, TIFF_MAX; + OPJ_UINT32 i, numcomps; + OPJ_INT32* buffer32s = NULL; + OPJ_INT32 const* planes[4]; + convert_32s_PXCX cvtPxToCx = NULL; + convert_32sXXx_C1R cvt32sToTif = NULL; + + bps = (uint16)image->comps[0].prec; + planes[0] = image->comps[0].data; + + numcomps = image->numcomps; + + if (image->color_space == OPJ_CLRSPC_CMYK) { + if (numcomps < 4U) { + fprintf(stderr, + "imagetotif: CMYK images shall be composed of at least 4 planes.\n"); + fprintf(stderr, "\tAborting\n"); + return 1; + } + tiPhoto = PHOTOMETRIC_SEPARATED; + if (numcomps > 4U) { + numcomps = 4U; /* Alpha not supported */ + } + } else if (numcomps > 2U) { + tiPhoto = PHOTOMETRIC_RGB; + if (numcomps > 4U) { + numcomps = 4U; + } + } else { + tiPhoto = PHOTOMETRIC_MINISBLACK; + } + for (i = 1U; i < numcomps; ++i) { + if (image->comps[0].dx != image->comps[i].dx) { + break; + } + if (image->comps[0].dy != image->comps[i].dy) { + break; + } + if (image->comps[0].prec != image->comps[i].prec) { + break; + } + if (image->comps[0].sgnd != image->comps[i].sgnd) { + break; + } + planes[i] = image->comps[i].data; + } + if (i != numcomps) { + fprintf(stderr, + "imagetotif: All components shall have the same subsampling, same bit depth.\n"); + fprintf(stderr, "\tAborting\n"); + return 1; + } + + if (bps > 16) { + bps = 0; + } + if (bps == 0) { + fprintf(stderr, "imagetotif: Bits=%d, Only 1 to 16 bits implemented\n", bps); + fprintf(stderr, "\tAborting\n"); + return 1; + } + tif = TIFFOpen(outfile, "wb"); + if (!tif) { + fprintf(stderr, "imagetotif:failed to open %s for writing\n", outfile); + return 1; + } + for (i = 0U; i < numcomps; ++i) { + clip_component(&(image->comps[i]), image->comps[0].prec); + } + cvtPxToCx = convert_32s_PXCX_LUT[numcomps]; + switch (bps) { + case 1: + case 2: + case 4: + case 6: + case 8: + cvt32sToTif = convert_32sXXu_C1R_LUT[bps]; + break; + case 3: + cvt32sToTif = tif_32sto3u; + break; + case 5: + cvt32sToTif = tif_32sto5u; + break; + case 7: + cvt32sToTif = tif_32sto7u; + break; + case 9: + cvt32sToTif = tif_32sto9u; + break; + case 10: + cvt32sToTif = tif_32sto10u; + break; + case 11: + cvt32sToTif = tif_32sto11u; + break; + case 12: + cvt32sToTif = tif_32sto12u; + break; + case 13: + cvt32sToTif = tif_32sto13u; + break; + case 14: + cvt32sToTif = tif_32sto14u; + break; + case 15: + cvt32sToTif = tif_32sto15u; + break; + case 16: + cvt32sToTif = (convert_32sXXx_C1R)tif_32sto16u; + break; + default: + /* never here */ + break; + } + sgnd = (int)image->comps[0].sgnd; + adjust = sgnd ? (int)(1 << (image->comps[0].prec - 1)) : 0; + width = (uint32)image->comps[0].w; + height = (uint32)image->comps[0].h; + + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (uint16)numcomps); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps); + TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, tiPhoto); + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1); + if (sizeof(tsize_t) == 4) { + TIFF_MAX = INT_MAX; + } else { + TIFF_MAX = UINT_MAX; + } + strip_size = (int64_t)TIFFStripSize(tif); + + if ((int64_t)width > (int64_t)(TIFF_MAX / numcomps) || + (int64_t)(width * numcomps) > (int64_t)(TIFF_MAX / bps) || + (int64_t)(width * numcomps) > (int64_t)(TIFF_MAX / (int64_t)sizeof( + OPJ_INT32))) { + fprintf(stderr, "Buffer overflow\n"); + TIFFClose(tif); + return 1; + } + rowStride = (int64_t)((width * numcomps * bps + 7U) / 8U); + if (rowStride != strip_size) { + fprintf(stderr, "Invalid TIFF strip size\n"); + TIFFClose(tif); + return 1; + } + buf = malloc((OPJ_SIZE_T)strip_size); + if (buf == NULL) { + TIFFClose(tif); + return 1; + } + buffer32s = (OPJ_INT32 *)malloc((OPJ_SIZE_T)(width * numcomps * sizeof( + OPJ_INT32))); + if (buffer32s == NULL) { + _TIFFfree(buf); + TIFFClose(tif); + return 1; + } + + for (i = 0; i < image->comps[0].h; ++i) { + cvtPxToCx(planes, buffer32s, (OPJ_SIZE_T)width, adjust); + cvt32sToTif(buffer32s, (OPJ_BYTE *)buf, (OPJ_SIZE_T)width * numcomps); + (void)TIFFWriteEncodedStrip(tif, i, (void*)buf, (tsize_t)strip_size); + planes[0] += width; + planes[1] += width; + planes[2] += width; + planes[3] += width; + } + _TIFFfree((void*)buf); + TIFFClose(tif); + free(buffer32s); + + return 0; +}/* imagetotif() */ + +#define GETBITS(dest, nb) { \ + int needed = (nb); \ + unsigned int dst = 0U; \ + if (available == 0) { \ + val = *pSrc++; \ + available = 8; \ + } \ + while (needed > available) { \ + dst |= val & ((1U << available) - 1U); \ + needed -= available; \ + dst <<= needed; \ + val = *pSrc++; \ + available = 8; \ + } \ + dst |= (val >> (available - needed)) & ((1U << needed) - 1U); \ + available -= needed; \ + dest = (OPJ_INT32)dst; \ +} + +static void tif_3uto32s(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)7U); i += 8U) { + OPJ_UINT32 val0 = *pSrc++; + OPJ_UINT32 val1 = *pSrc++; + OPJ_UINT32 val2 = *pSrc++; + + pDst[i + 0] = (OPJ_INT32)((val0 >> 5)); + pDst[i + 1] = (OPJ_INT32)(((val0 & 0x1FU) >> 2)); + pDst[i + 2] = (OPJ_INT32)(((val0 & 0x3U) << 1) | (val1 >> 7)); + pDst[i + 3] = (OPJ_INT32)(((val1 & 0x7FU) >> 4)); + pDst[i + 4] = (OPJ_INT32)(((val1 & 0xFU) >> 1)); + pDst[i + 5] = (OPJ_INT32)(((val1 & 0x1U) << 2) | (val2 >> 6)); + pDst[i + 6] = (OPJ_INT32)(((val2 & 0x3FU) >> 3)); + pDst[i + 7] = (OPJ_INT32)(((val2 & 0x7U))); + + } + if (length & 7U) { + unsigned int val; + int available = 0; + + length = length & 7U; + + GETBITS(pDst[i + 0], 3) + + if (length > 1U) { + GETBITS(pDst[i + 1], 3) + if (length > 2U) { + GETBITS(pDst[i + 2], 3) + if (length > 3U) { + GETBITS(pDst[i + 3], 3) + if (length > 4U) { + GETBITS(pDst[i + 4], 3) + if (length > 5U) { + GETBITS(pDst[i + 5], 3) + if (length > 6U) { + GETBITS(pDst[i + 6], 3) + } + } + } + } + } + } + } +} +static void tif_5uto32s(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)7U); i += 8U) { + OPJ_UINT32 val0 = *pSrc++; + OPJ_UINT32 val1 = *pSrc++; + OPJ_UINT32 val2 = *pSrc++; + OPJ_UINT32 val3 = *pSrc++; + OPJ_UINT32 val4 = *pSrc++; + + pDst[i + 0] = (OPJ_INT32)((val0 >> 3)); + pDst[i + 1] = (OPJ_INT32)(((val0 & 0x7U) << 2) | (val1 >> 6)); + pDst[i + 2] = (OPJ_INT32)(((val1 & 0x3FU) >> 1)); + pDst[i + 3] = (OPJ_INT32)(((val1 & 0x1U) << 4) | (val2 >> 4)); + pDst[i + 4] = (OPJ_INT32)(((val2 & 0xFU) << 1) | (val3 >> 7)); + pDst[i + 5] = (OPJ_INT32)(((val3 & 0x7FU) >> 2)); + pDst[i + 6] = (OPJ_INT32)(((val3 & 0x3U) << 3) | (val4 >> 5)); + pDst[i + 7] = (OPJ_INT32)(((val4 & 0x1FU))); + + } + if (length & 7U) { + unsigned int val; + int available = 0; + + length = length & 7U; + + GETBITS(pDst[i + 0], 5) + + if (length > 1U) { + GETBITS(pDst[i + 1], 5) + if (length > 2U) { + GETBITS(pDst[i + 2], 5) + if (length > 3U) { + GETBITS(pDst[i + 3], 5) + if (length > 4U) { + GETBITS(pDst[i + 4], 5) + if (length > 5U) { + GETBITS(pDst[i + 5], 5) + if (length > 6U) { + GETBITS(pDst[i + 6], 5) + } + } + } + } + } + } + } +} +static void tif_7uto32s(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)7U); i += 8U) { + OPJ_UINT32 val0 = *pSrc++; + OPJ_UINT32 val1 = *pSrc++; + OPJ_UINT32 val2 = *pSrc++; + OPJ_UINT32 val3 = *pSrc++; + OPJ_UINT32 val4 = *pSrc++; + OPJ_UINT32 val5 = *pSrc++; + OPJ_UINT32 val6 = *pSrc++; + + pDst[i + 0] = (OPJ_INT32)((val0 >> 1)); + pDst[i + 1] = (OPJ_INT32)(((val0 & 0x1U) << 6) | (val1 >> 2)); + pDst[i + 2] = (OPJ_INT32)(((val1 & 0x3U) << 5) | (val2 >> 3)); + pDst[i + 3] = (OPJ_INT32)(((val2 & 0x7U) << 4) | (val3 >> 4)); + pDst[i + 4] = (OPJ_INT32)(((val3 & 0xFU) << 3) | (val4 >> 5)); + pDst[i + 5] = (OPJ_INT32)(((val4 & 0x1FU) << 2) | (val5 >> 6)); + pDst[i + 6] = (OPJ_INT32)(((val5 & 0x3FU) << 1) | (val6 >> 7)); + pDst[i + 7] = (OPJ_INT32)(((val6 & 0x7FU))); + + } + if (length & 7U) { + unsigned int val; + int available = 0; + + length = length & 7U; + + GETBITS(pDst[i + 0], 7) + + if (length > 1U) { + GETBITS(pDst[i + 1], 7) + if (length > 2U) { + GETBITS(pDst[i + 2], 7) + if (length > 3U) { + GETBITS(pDst[i + 3], 7) + if (length > 4U) { + GETBITS(pDst[i + 4], 7) + if (length > 5U) { + GETBITS(pDst[i + 5], 7) + if (length > 6U) { + GETBITS(pDst[i + 6], 7) + } + } + } + } + } + } + } +} +static void tif_9uto32s(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)7U); i += 8U) { + OPJ_UINT32 val0 = *pSrc++; + OPJ_UINT32 val1 = *pSrc++; + OPJ_UINT32 val2 = *pSrc++; + OPJ_UINT32 val3 = *pSrc++; + OPJ_UINT32 val4 = *pSrc++; + OPJ_UINT32 val5 = *pSrc++; + OPJ_UINT32 val6 = *pSrc++; + OPJ_UINT32 val7 = *pSrc++; + OPJ_UINT32 val8 = *pSrc++; + + pDst[i + 0] = (OPJ_INT32)((val0 << 1) | (val1 >> 7)); + pDst[i + 1] = (OPJ_INT32)(((val1 & 0x7FU) << 2) | (val2 >> 6)); + pDst[i + 2] = (OPJ_INT32)(((val2 & 0x3FU) << 3) | (val3 >> 5)); + pDst[i + 3] = (OPJ_INT32)(((val3 & 0x1FU) << 4) | (val4 >> 4)); + pDst[i + 4] = (OPJ_INT32)(((val4 & 0xFU) << 5) | (val5 >> 3)); + pDst[i + 5] = (OPJ_INT32)(((val5 & 0x7U) << 6) | (val6 >> 2)); + pDst[i + 6] = (OPJ_INT32)(((val6 & 0x3U) << 7) | (val7 >> 1)); + pDst[i + 7] = (OPJ_INT32)(((val7 & 0x1U) << 8) | (val8)); + + } + if (length & 7U) { + unsigned int val; + int available = 0; + + length = length & 7U; + + GETBITS(pDst[i + 0], 9) + + if (length > 1U) { + GETBITS(pDst[i + 1], 9) + if (length > 2U) { + GETBITS(pDst[i + 2], 9) + if (length > 3U) { + GETBITS(pDst[i + 3], 9) + if (length > 4U) { + GETBITS(pDst[i + 4], 9) + if (length > 5U) { + GETBITS(pDst[i + 5], 9) + if (length > 6U) { + GETBITS(pDst[i + 6], 9) + } + } + } + } + } + } + } +} +static void tif_10uto32s(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)3U); i += 4U) { + OPJ_UINT32 val0 = *pSrc++; + OPJ_UINT32 val1 = *pSrc++; + OPJ_UINT32 val2 = *pSrc++; + OPJ_UINT32 val3 = *pSrc++; + OPJ_UINT32 val4 = *pSrc++; + + pDst[i + 0] = (OPJ_INT32)((val0 << 2) | (val1 >> 6)); + pDst[i + 1] = (OPJ_INT32)(((val1 & 0x3FU) << 4) | (val2 >> 4)); + pDst[i + 2] = (OPJ_INT32)(((val2 & 0xFU) << 6) | (val3 >> 2)); + pDst[i + 3] = (OPJ_INT32)(((val3 & 0x3U) << 8) | val4); + + } + if (length & 3U) { + OPJ_UINT32 val0 = *pSrc++; + OPJ_UINT32 val1 = *pSrc++; + length = length & 3U; + pDst[i + 0] = (OPJ_INT32)((val0 << 2) | (val1 >> 6)); + + if (length > 1U) { + OPJ_UINT32 val2 = *pSrc++; + pDst[i + 1] = (OPJ_INT32)(((val1 & 0x3FU) << 4) | (val2 >> 4)); + if (length > 2U) { + OPJ_UINT32 val3 = *pSrc++; + pDst[i + 2] = (OPJ_INT32)(((val2 & 0xFU) << 6) | (val3 >> 2)); + } + } + } +} +static void tif_11uto32s(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)7U); i += 8U) { + OPJ_UINT32 val0 = *pSrc++; + OPJ_UINT32 val1 = *pSrc++; + OPJ_UINT32 val2 = *pSrc++; + OPJ_UINT32 val3 = *pSrc++; + OPJ_UINT32 val4 = *pSrc++; + OPJ_UINT32 val5 = *pSrc++; + OPJ_UINT32 val6 = *pSrc++; + OPJ_UINT32 val7 = *pSrc++; + OPJ_UINT32 val8 = *pSrc++; + OPJ_UINT32 val9 = *pSrc++; + OPJ_UINT32 val10 = *pSrc++; + + pDst[i + 0] = (OPJ_INT32)((val0 << 3) | (val1 >> 5)); + pDst[i + 1] = (OPJ_INT32)(((val1 & 0x1FU) << 6) | (val2 >> 2)); + pDst[i + 2] = (OPJ_INT32)(((val2 & 0x3U) << 9) | (val3 << 1) | (val4 >> 7)); + pDst[i + 3] = (OPJ_INT32)(((val4 & 0x7FU) << 4) | (val5 >> 4)); + pDst[i + 4] = (OPJ_INT32)(((val5 & 0xFU) << 7) | (val6 >> 1)); + pDst[i + 5] = (OPJ_INT32)(((val6 & 0x1U) << 10) | (val7 << 2) | (val8 >> 6)); + pDst[i + 6] = (OPJ_INT32)(((val8 & 0x3FU) << 5) | (val9 >> 3)); + pDst[i + 7] = (OPJ_INT32)(((val9 & 0x7U) << 8) | (val10)); + + } + if (length & 7U) { + unsigned int val; + int available = 0; + + length = length & 7U; + + GETBITS(pDst[i + 0], 11) + + if (length > 1U) { + GETBITS(pDst[i + 1], 11) + if (length > 2U) { + GETBITS(pDst[i + 2], 11) + if (length > 3U) { + GETBITS(pDst[i + 3], 11) + if (length > 4U) { + GETBITS(pDst[i + 4], 11) + if (length > 5U) { + GETBITS(pDst[i + 5], 11) + if (length > 6U) { + GETBITS(pDst[i + 6], 11) + } + } + } + } + } + } + } +} +static void tif_12uto32s(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)1U); i += 2U) { + OPJ_UINT32 val0 = *pSrc++; + OPJ_UINT32 val1 = *pSrc++; + OPJ_UINT32 val2 = *pSrc++; + + pDst[i + 0] = (OPJ_INT32)((val0 << 4) | (val1 >> 4)); + pDst[i + 1] = (OPJ_INT32)(((val1 & 0xFU) << 8) | val2); + } + if (length & 1U) { + OPJ_UINT32 val0 = *pSrc++; + OPJ_UINT32 val1 = *pSrc++; + pDst[i + 0] = (OPJ_INT32)((val0 << 4) | (val1 >> 4)); + } +} +static void tif_13uto32s(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)7U); i += 8U) { + OPJ_UINT32 val0 = *pSrc++; + OPJ_UINT32 val1 = *pSrc++; + OPJ_UINT32 val2 = *pSrc++; + OPJ_UINT32 val3 = *pSrc++; + OPJ_UINT32 val4 = *pSrc++; + OPJ_UINT32 val5 = *pSrc++; + OPJ_UINT32 val6 = *pSrc++; + OPJ_UINT32 val7 = *pSrc++; + OPJ_UINT32 val8 = *pSrc++; + OPJ_UINT32 val9 = *pSrc++; + OPJ_UINT32 val10 = *pSrc++; + OPJ_UINT32 val11 = *pSrc++; + OPJ_UINT32 val12 = *pSrc++; + + pDst[i + 0] = (OPJ_INT32)((val0 << 5) | (val1 >> 3)); + pDst[i + 1] = (OPJ_INT32)(((val1 & 0x7U) << 10) | (val2 << 2) | (val3 >> 6)); + pDst[i + 2] = (OPJ_INT32)(((val3 & 0x3FU) << 7) | (val4 >> 1)); + pDst[i + 3] = (OPJ_INT32)(((val4 & 0x1U) << 12) | (val5 << 4) | (val6 >> 4)); + pDst[i + 4] = (OPJ_INT32)(((val6 & 0xFU) << 9) | (val7 << 1) | (val8 >> 7)); + pDst[i + 5] = (OPJ_INT32)(((val8 & 0x7FU) << 6) | (val9 >> 2)); + pDst[i + 6] = (OPJ_INT32)(((val9 & 0x3U) << 11) | (val10 << 3) | (val11 >> 5)); + pDst[i + 7] = (OPJ_INT32)(((val11 & 0x1FU) << 8) | (val12)); + + } + if (length & 7U) { + unsigned int val; + int available = 0; + + length = length & 7U; + + GETBITS(pDst[i + 0], 13) + + if (length > 1U) { + GETBITS(pDst[i + 1], 13) + if (length > 2U) { + GETBITS(pDst[i + 2], 13) + if (length > 3U) { + GETBITS(pDst[i + 3], 13) + if (length > 4U) { + GETBITS(pDst[i + 4], 13) + if (length > 5U) { + GETBITS(pDst[i + 5], 13) + if (length > 6U) { + GETBITS(pDst[i + 6], 13) + } + } + } + } + } + } + } +} +static void tif_14uto32s(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)3U); i += 4U) { + OPJ_UINT32 val0 = *pSrc++; + OPJ_UINT32 val1 = *pSrc++; + OPJ_UINT32 val2 = *pSrc++; + OPJ_UINT32 val3 = *pSrc++; + OPJ_UINT32 val4 = *pSrc++; + OPJ_UINT32 val5 = *pSrc++; + OPJ_UINT32 val6 = *pSrc++; + + pDst[i + 0] = (OPJ_INT32)((val0 << 6) | (val1 >> 2)); + pDst[i + 1] = (OPJ_INT32)(((val1 & 0x3U) << 12) | (val2 << 4) | (val3 >> 4)); + pDst[i + 2] = (OPJ_INT32)(((val3 & 0xFU) << 10) | (val4 << 2) | (val5 >> 6)); + pDst[i + 3] = (OPJ_INT32)(((val5 & 0x3FU) << 8) | val6); + + } + if (length & 3U) { + OPJ_UINT32 val0 = *pSrc++; + OPJ_UINT32 val1 = *pSrc++; + length = length & 3U; + pDst[i + 0] = (OPJ_INT32)((val0 << 6) | (val1 >> 2)); + + if (length > 1U) { + OPJ_UINT32 val2 = *pSrc++; + OPJ_UINT32 val3 = *pSrc++; + pDst[i + 1] = (OPJ_INT32)(((val1 & 0x3U) << 12) | (val2 << 4) | (val3 >> 4)); + if (length > 2U) { + OPJ_UINT32 val4 = *pSrc++; + OPJ_UINT32 val5 = *pSrc++; + pDst[i + 2] = (OPJ_INT32)(((val3 & 0xFU) << 10) | (val4 << 2) | (val5 >> 6)); + } + } + } +} +static void tif_15uto32s(const OPJ_BYTE* pSrc, OPJ_INT32* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < (length & ~(OPJ_SIZE_T)7U); i += 8U) { + OPJ_UINT32 val0 = *pSrc++; + OPJ_UINT32 val1 = *pSrc++; + OPJ_UINT32 val2 = *pSrc++; + OPJ_UINT32 val3 = *pSrc++; + OPJ_UINT32 val4 = *pSrc++; + OPJ_UINT32 val5 = *pSrc++; + OPJ_UINT32 val6 = *pSrc++; + OPJ_UINT32 val7 = *pSrc++; + OPJ_UINT32 val8 = *pSrc++; + OPJ_UINT32 val9 = *pSrc++; + OPJ_UINT32 val10 = *pSrc++; + OPJ_UINT32 val11 = *pSrc++; + OPJ_UINT32 val12 = *pSrc++; + OPJ_UINT32 val13 = *pSrc++; + OPJ_UINT32 val14 = *pSrc++; + + pDst[i + 0] = (OPJ_INT32)((val0 << 7) | (val1 >> 1)); + pDst[i + 1] = (OPJ_INT32)(((val1 & 0x1U) << 14) | (val2 << 6) | (val3 >> 2)); + pDst[i + 2] = (OPJ_INT32)(((val3 & 0x3U) << 13) | (val4 << 5) | (val5 >> 3)); + pDst[i + 3] = (OPJ_INT32)(((val5 & 0x7U) << 12) | (val6 << 4) | (val7 >> 4)); + pDst[i + 4] = (OPJ_INT32)(((val7 & 0xFU) << 11) | (val8 << 3) | (val9 >> 5)); + pDst[i + 5] = (OPJ_INT32)(((val9 & 0x1FU) << 10) | (val10 << 2) | (val11 >> 6)); + pDst[i + 6] = (OPJ_INT32)(((val11 & 0x3FU) << 9) | (val12 << 1) | (val13 >> 7)); + pDst[i + 7] = (OPJ_INT32)(((val13 & 0x7FU) << 8) | (val14)); + + } + if (length & 7U) { + unsigned int val; + int available = 0; + + length = length & 7U; + + GETBITS(pDst[i + 0], 15) + + if (length > 1U) { + GETBITS(pDst[i + 1], 15) + if (length > 2U) { + GETBITS(pDst[i + 2], 15) + if (length > 3U) { + GETBITS(pDst[i + 3], 15) + if (length > 4U) { + GETBITS(pDst[i + 4], 15) + if (length > 5U) { + GETBITS(pDst[i + 5], 15) + if (length > 6U) { + GETBITS(pDst[i + 6], 15) + } + } + } + } + } + } + } +} + +/* seems that libtiff decodes this to machine endianness */ +static void tif_16uto32s(const OPJ_UINT16* pSrc, OPJ_INT32* pDst, + OPJ_SIZE_T length) +{ + OPJ_SIZE_T i; + for (i = 0; i < length; i++) { + pDst[i] = pSrc[i]; + } +} + +/* + * libtiff/tif_getimage.c : 1,2,4,8,16 bitspersample accepted + * CINEMA : 12 bit precision + */ +opj_image_t* tiftoimage(const char *filename, opj_cparameters_t *parameters) +{ + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + TIFF *tif; + tdata_t buf; + tstrip_t strip; + int64_t strip_size, rowStride, TIFF_MAX; + int j, currentPlane, numcomps = 0, w, h; + OPJ_COLOR_SPACE color_space = OPJ_CLRSPC_UNKNOWN; + opj_image_cmptparm_t cmptparm[4]; /* RGBA */ + opj_image_t *image = NULL; + uint16 tiBps, tiPhoto, tiSf, tiSpp, tiPC; + uint32 tiWidth, tiHeight; + OPJ_BOOL is_cinema = OPJ_IS_CINEMA(parameters->rsiz); + convert_XXx32s_C1R cvtTifTo32s = NULL; + convert_32s_CXPX cvtCxToPx = NULL; + OPJ_INT32* buffer32s = NULL; + OPJ_INT32* planes[4]; + + tif = TIFFOpen(filename, "r"); + + if (!tif) { + fprintf(stderr, "tiftoimage:Failed to open %s for reading\n", filename); + return 0; + } + tiBps = tiPhoto = tiSf = tiSpp = tiPC = 0; + tiWidth = tiHeight = 0; + + TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &tiWidth); + TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &tiHeight); + TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &tiBps); + TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &tiSf); + TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &tiSpp); + TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &tiPhoto); + TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &tiPC); + w = (int)tiWidth; + h = (int)tiHeight; + + if (tiSpp == 0 || tiSpp > 4) { /* should be 1 ... 4 */ + fprintf(stderr, "tiftoimage: Bad value for samples per pixel == %d.\n" + "\tAborting.\n", tiSpp); + TIFFClose(tif); + return NULL; + } + if (tiBps > 16U || tiBps == 0) { + fprintf(stderr, "tiftoimage: Bad values for Bits == %d.\n" + "\tMax. 16 Bits are allowed here.\n\tAborting.\n", tiBps); + TIFFClose(tif); + return NULL; + } + if (tiPhoto != PHOTOMETRIC_MINISBLACK && tiPhoto != PHOTOMETRIC_RGB) { + fprintf(stderr, + "tiftoimage: Bad color format %d.\n\tOnly RGB(A) and GRAY(A) has been implemented\n\tAborting.\n", + (int) tiPhoto); + TIFFClose(tif); + return NULL; + } + if (tiWidth == 0 || tiHeight == 0) { + fprintf(stderr, "tiftoimage: Bad values for width(%u) " + "and/or height(%u)\n\tAborting.\n", tiWidth, tiHeight); + TIFFClose(tif); + return NULL; + } + w = (int)tiWidth; + h = (int)tiHeight; + + switch (tiBps) { + case 1: + case 2: + case 4: + case 6: + case 8: + cvtTifTo32s = convert_XXu32s_C1R_LUT[tiBps]; + break; + /* others are specific to TIFF */ + case 3: + cvtTifTo32s = tif_3uto32s; + break; + case 5: + cvtTifTo32s = tif_5uto32s; + break; + case 7: + cvtTifTo32s = tif_7uto32s; + break; + case 9: + cvtTifTo32s = tif_9uto32s; + break; + case 10: + cvtTifTo32s = tif_10uto32s; + break; + case 11: + cvtTifTo32s = tif_11uto32s; + break; + case 12: + cvtTifTo32s = tif_12uto32s; + break; + case 13: + cvtTifTo32s = tif_13uto32s; + break; + case 14: + cvtTifTo32s = tif_14uto32s; + break; + case 15: + cvtTifTo32s = tif_15uto32s; + break; + case 16: + cvtTifTo32s = (convert_XXx32s_C1R)tif_16uto32s; + break; + default: + /* never here */ + break; + } + + /* initialize image components */ + memset(&cmptparm[0], 0, 4 * sizeof(opj_image_cmptparm_t)); + + if ((tiPhoto == PHOTOMETRIC_RGB) && (is_cinema) && (tiBps != 12U)) { + fprintf(stdout, "WARNING:\n" + "Input image bitdepth is %d bits\n" + "TIF conversion has automatically rescaled to 12-bits\n" + "to comply with cinema profiles.\n", + tiBps); + } else { + is_cinema = 0U; + } + + numcomps = tiSpp; + if (tiPhoto == PHOTOMETRIC_RGB) { /* RGB(A) */ + color_space = OPJ_CLRSPC_SRGB; + } else if (tiPhoto == PHOTOMETRIC_MINISBLACK) { /* GRAY(A) */ + color_space = OPJ_CLRSPC_GRAY; + } + + cvtCxToPx = convert_32s_CXPX_LUT[numcomps]; + if (tiPC == PLANARCONFIG_SEPARATE) { + cvtCxToPx = convert_32s_CXPX_LUT[1]; /* override */ + tiSpp = 1U; /* consider only one sample per plane */ + } + + for (j = 0; j < numcomps; j++) { + cmptparm[j].prec = tiBps; + cmptparm[j].bpp = tiBps; + cmptparm[j].dx = (OPJ_UINT32)subsampling_dx; + cmptparm[j].dy = (OPJ_UINT32)subsampling_dy; + cmptparm[j].w = (OPJ_UINT32)w; + cmptparm[j].h = (OPJ_UINT32)h; + } + + image = opj_image_create((OPJ_UINT32)numcomps, &cmptparm[0], color_space); + if (!image) { + TIFFClose(tif); + return NULL; + } + /* set image offset and reference grid */ + image->x0 = (OPJ_UINT32)parameters->image_offset_x0; + image->y0 = (OPJ_UINT32)parameters->image_offset_y0; + image->x1 = !image->x0 ? (OPJ_UINT32)(w - 1) * (OPJ_UINT32)subsampling_dx + 1 : + image->x0 + (OPJ_UINT32)(w - 1) * (OPJ_UINT32)subsampling_dx + 1; + if (image->x1 <= image->x0) { + fprintf(stderr, "tiftoimage: Bad value for image->x1(%d) vs. " + "image->x0(%d)\n\tAborting.\n", image->x1, image->x0); + TIFFClose(tif); + opj_image_destroy(image); + return NULL; + } + image->y1 = !image->y0 ? (OPJ_UINT32)(h - 1) * (OPJ_UINT32)subsampling_dy + 1 : + image->y0 + (OPJ_UINT32)(h - 1) * (OPJ_UINT32)subsampling_dy + 1; + if (image->y1 <= image->y0) { + fprintf(stderr, "tiftoimage: Bad value for image->y1(%d) vs. " + "image->y0(%d)\n\tAborting.\n", image->y1, image->y0); + TIFFClose(tif); + opj_image_destroy(image); + return NULL; + } + + for (j = 0; j < numcomps; j++) { + planes[j] = image->comps[j].data; + } + image->comps[numcomps - 1].alpha = (OPJ_UINT16)(1 - (numcomps & 1)); + + strip_size = (int64_t)TIFFStripSize(tif); + + buf = malloc((OPJ_SIZE_T)strip_size); + if (buf == NULL) { + TIFFClose(tif); + opj_image_destroy(image); + return NULL; + } + if (sizeof(tsize_t) == 4) { + TIFF_MAX = INT_MAX; + } else { + TIFF_MAX = UINT_MAX; + } + if ((int64_t)tiWidth > (int64_t)(TIFF_MAX / tiSpp) || + (int64_t)(tiWidth * tiSpp) > (int64_t)(TIFF_MAX / tiBps) || + (int64_t)(tiWidth * tiSpp) > (int64_t)(TIFF_MAX / (int64_t)sizeof(OPJ_INT32))) { + fprintf(stderr, "Buffer overflow\n"); + _TIFFfree(buf); + TIFFClose(tif); + opj_image_destroy(image); + return NULL; + } + + rowStride = (int64_t)((tiWidth * tiSpp * tiBps + 7U) / 8U); + buffer32s = (OPJ_INT32 *)malloc((OPJ_SIZE_T)(tiWidth * tiSpp * sizeof( + OPJ_INT32))); + if (buffer32s == NULL) { + _TIFFfree(buf); + TIFFClose(tif); + opj_image_destroy(image); + return NULL; + } + + strip = 0; + currentPlane = 0; + do { + planes[0] = image->comps[currentPlane].data; /* to manage planar data */ + h = (int)tiHeight; + /* Read the Image components */ + for (; (h > 0) && (strip < TIFFNumberOfStrips(tif)); strip++) { + const OPJ_UINT8 *dat8; + int64_t ssize; + + ssize = (int64_t)TIFFReadEncodedStrip(tif, strip, buf, (tsize_t)strip_size); + + if (ssize < 1 || ssize > strip_size) { + fprintf(stderr, "tiftoimage: Bad value for ssize(%" PRId64 ") " + "vs. strip_size(%" PRId64 ").\n\tAborting.\n", ssize, strip_size); + _TIFFfree(buf); + _TIFFfree(buffer32s); + TIFFClose(tif); + opj_image_destroy(image); + return NULL; + } + dat8 = (const OPJ_UINT8*)buf; + + while (ssize >= rowStride) { + cvtTifTo32s(dat8, buffer32s, (OPJ_SIZE_T)w * tiSpp); + cvtCxToPx(buffer32s, planes, (OPJ_SIZE_T)w); + planes[0] += w; + planes[1] += w; + planes[2] += w; + planes[3] += w; + dat8 += rowStride; + ssize -= rowStride; + h--; + } + } + currentPlane++; + } while ((tiPC == PLANARCONFIG_SEPARATE) && (currentPlane < numcomps)); + + free(buffer32s); + _TIFFfree(buf); + TIFFClose(tif); + + if (is_cinema) { + for (j = 0; j < numcomps; ++j) { + scale_component(&(image->comps[j]), 12); + } + + } + return image; + +}/* tiftoimage() */ + diff --git a/openjpeg/src/bin/jp2/index.c b/openjpeg/src/bin/jp2/index.c new file mode 100644 index 000000000..3eae2f974 --- /dev/null +++ b/openjpeg/src/bin/jp2/index.c @@ -0,0 +1,456 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <math.h> +#include <string.h> +#include "openjpeg.h" +#include "index.h" +#include "opj_inttypes.h" + +/* ------------------------------------------------------------------------------------ */ + +/** +Write a structured index to a file +@param cstr_info Codestream information +@param index Index filename +@return Returns 0 if successful, returns 1 otherwise +*/ +int write_index_file(opj_codestream_info_t *cstr_info, char *index) +{ + int tileno, compno, layno, resno, precno, pack_nb, x, y; + FILE *stream = NULL; + double total_disto = 0; + /* UniPG>> */ + int tilepartno; + char disto_on, numpix_on; + +#ifdef USE_JPWL + if (!strcmp(index, JPWL_PRIVATEINDEX_NAME)) { + return 0; + } +#endif /* USE_JPWL */ + /* <<UniPG */ + + if (!cstr_info) { + return 1; + } + + stream = fopen(index, "w"); + if (!stream) { + fprintf(stderr, "failed to open index file [%s] for writing\n", index); + return 1; + } + + if (cstr_info->tile[0].distotile > 0.0) { + disto_on = 1; + } else { + disto_on = 0; + } + + if (cstr_info->tile[0].numpix) { + numpix_on = 1; + } else { + numpix_on = 0; + } + + fprintf(stream, "%d %d\n", cstr_info->image_w, cstr_info->image_h); + fprintf(stream, "%d\n", cstr_info->prog); + fprintf(stream, "%d %d\n", cstr_info->tile_x, cstr_info->tile_y); + fprintf(stream, "%d %d\n", cstr_info->tw, cstr_info->th); + fprintf(stream, "%d\n", cstr_info->numcomps); + fprintf(stream, "%d\n", cstr_info->numlayers); + fprintf(stream, "%d\n", cstr_info->numdecompos[0]); /* based on component 0 */ + + for (resno = cstr_info->numdecompos[0]; resno >= 0; resno--) { + fprintf(stream, "[%d,%d] ", + (1 << cstr_info->tile[0].pdx[resno]), + (1 << cstr_info->tile[0].pdx[resno])); /* based on tile 0 and component 0 */ + } + + fprintf(stream, "\n"); + /* UniPG>> */ + fprintf(stream, "%d\n", cstr_info->main_head_start); + /* <<UniPG */ + fprintf(stream, "%d\n", cstr_info->main_head_end); + fprintf(stream, "%d\n", cstr_info->codestream_size); + + fprintf(stream, "\nINFO ON TILES\n"); + fprintf(stream, "tileno start_pos end_hd end_tile nbparts"); + if (disto_on) { + fprintf(stream, " disto"); + } + if (numpix_on) { + fprintf(stream, " nbpix"); + } + if (disto_on && numpix_on) { + fprintf(stream, " disto/nbpix"); + } + fprintf(stream, "\n"); + + for (tileno = 0; tileno < cstr_info->tw * cstr_info->th; tileno++) { + fprintf(stream, "%4d %9d %9d %9d %9d", + cstr_info->tile[tileno].tileno, + cstr_info->tile[tileno].start_pos, + cstr_info->tile[tileno].end_header, + cstr_info->tile[tileno].end_pos, + cstr_info->tile[tileno].num_tps); + if (disto_on) { + fprintf(stream, " %9e", cstr_info->tile[tileno].distotile); + } + if (numpix_on) { + fprintf(stream, " %9d", cstr_info->tile[tileno].numpix); + } + if (disto_on && numpix_on) { + fprintf(stream, " %9e", cstr_info->tile[tileno].distotile / + cstr_info->tile[tileno].numpix); + } + fprintf(stream, "\n"); + } + + for (tileno = 0; tileno < cstr_info->tw * cstr_info->th; tileno++) { + OPJ_OFF_T start_pos, end_ph_pos, end_pos; + double disto = 0; + int max_numdecompos = 0; + pack_nb = 0; + + for (compno = 0; compno < cstr_info->numcomps; compno++) { + if (max_numdecompos < cstr_info->numdecompos[compno]) { + max_numdecompos = cstr_info->numdecompos[compno]; + } + } + + fprintf(stream, "\nTILE %d DETAILS\n", tileno); + fprintf(stream, + "part_nb tileno start_pack num_packs start_pos end_tph_pos end_pos\n"); + for (tilepartno = 0; tilepartno < cstr_info->tile[tileno].num_tps; tilepartno++) + fprintf(stream, "%4d %9d %9d %9d %9d %11d %9d\n", + tilepartno, tileno, + cstr_info->tile[tileno].tp[tilepartno].tp_start_pack, + cstr_info->tile[tileno].tp[tilepartno].tp_numpacks, + cstr_info->tile[tileno].tp[tilepartno].tp_start_pos, + cstr_info->tile[tileno].tp[tilepartno].tp_end_header, + cstr_info->tile[tileno].tp[tilepartno].tp_end_pos + ); + + if (cstr_info->prog == OPJ_LRCP) { /* LRCP */ + fprintf(stream, + "LRCP\npack_nb tileno layno resno compno precno start_pos end_ph_pos end_pos"); + if (disto_on) { + fprintf(stream, " disto"); + } + fprintf(stream, "\n"); + + for (layno = 0; layno < cstr_info->numlayers; layno++) { + for (resno = 0; resno < max_numdecompos + 1; resno++) { + for (compno = 0; compno < cstr_info->numcomps; compno++) { + int prec_max; + if (resno > cstr_info->numdecompos[compno]) { + break; + } + prec_max = cstr_info->tile[tileno].pw[resno] * + cstr_info->tile[tileno].ph[resno]; + for (precno = 0; precno < prec_max; precno++) { + start_pos = cstr_info->tile[tileno].packet[pack_nb].start_pos; + end_ph_pos = cstr_info->tile[tileno].packet[pack_nb].end_ph_pos; + end_pos = cstr_info->tile[tileno].packet[pack_nb].end_pos; + disto = cstr_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %7d %5d %6d %6d %6" PRId64 " %6" PRId64 " %7" + PRId64, + pack_nb, tileno, layno, resno, compno, precno, start_pos, end_ph_pos, end_pos); + if (disto_on) { + fprintf(stream, " %8e", disto); + } + fprintf(stream, "\n"); + total_disto += disto; + pack_nb++; + } + } + } + } + } /* LRCP */ + + else if (cstr_info->prog == OPJ_RLCP) { /* RLCP */ + fprintf(stream, + "RLCP\npack_nb tileno resno layno compno precno start_pos end_ph_pos end_pos\n"); + if (disto_on) { + fprintf(stream, " disto"); + } + fprintf(stream, "\n"); + + for (resno = 0; resno < max_numdecompos + 1; resno++) { + for (layno = 0; layno < cstr_info->numlayers; layno++) { + for (compno = 0; compno < cstr_info->numcomps; compno++) { + int prec_max; + if (resno > cstr_info->numdecompos[compno]) { + break; + } + prec_max = cstr_info->tile[tileno].pw[resno] * + cstr_info->tile[tileno].ph[resno]; + for (precno = 0; precno < prec_max; precno++) { + start_pos = cstr_info->tile[tileno].packet[pack_nb].start_pos; + end_ph_pos = cstr_info->tile[tileno].packet[pack_nb].end_ph_pos; + end_pos = cstr_info->tile[tileno].packet[pack_nb].end_pos; + disto = cstr_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %5d %7d %6d %6d %9" PRId64 " %9" PRId64 " %7" PRId64, + pack_nb, tileno, resno, layno, compno, precno, start_pos, end_ph_pos, end_pos); + if (disto_on) { + fprintf(stream, " %8e", disto); + } + fprintf(stream, "\n"); + total_disto += disto; + pack_nb++; + } + } + } + } + } /* RLCP */ + + else if (cstr_info->prog == OPJ_RPCL) { /* RPCL */ + + fprintf(stream, + "RPCL\npack_nb tileno resno precno compno layno start_pos end_ph_pos end_pos"); + if (disto_on) { + fprintf(stream, " disto"); + } + fprintf(stream, "\n"); + + for (resno = 0; resno < max_numdecompos + 1; resno++) { + int numprec = cstr_info->tile[tileno].pw[resno] * + cstr_info->tile[tileno].ph[resno]; + for (precno = 0; precno < numprec; precno++) { + /* I suppose components have same XRsiz, YRsiz */ + int x0 = cstr_info->tile_Ox + tileno - (int)floor((float)tileno / + (float)cstr_info->tw) * cstr_info->tw * cstr_info->tile_x; + int y0 = cstr_info->tile_Ox + (int)floor((float)tileno / + (float)cstr_info->tw) * cstr_info->tile_y; + int x1 = x0 + cstr_info->tile_x; + int y1 = y0 + cstr_info->tile_y; + for (compno = 0; compno < cstr_info->numcomps; compno++) { + int pcnx = cstr_info->tile[tileno].pw[resno]; + int pcx = (int) pow(2, cstr_info->tile[tileno].pdx[resno] + + cstr_info->numdecompos[compno] - resno); + int pcy = (int) pow(2, cstr_info->tile[tileno].pdy[resno] + + cstr_info->numdecompos[compno] - resno); + int precno_x = precno - (int) floor((float)precno / (float)pcnx) * pcnx; + int precno_y = (int) floor((float)precno / (float)pcnx); + if (resno > cstr_info->numdecompos[compno]) { + break; + } + for (y = y0; y < y1; y++) { + if (precno_y * pcy == y) { + for (x = x0; x < x1; x++) { + if (precno_x * pcx == x) { + for (layno = 0; layno < cstr_info->numlayers; layno++) { + start_pos = cstr_info->tile[tileno].packet[pack_nb].start_pos; + end_ph_pos = cstr_info->tile[tileno].packet[pack_nb].end_ph_pos; + end_pos = cstr_info->tile[tileno].packet[pack_nb].end_pos; + disto = cstr_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %5d %6d %6d %7d %9" PRId64 " %9" PRId64 " %7" PRId64, + pack_nb, tileno, resno, precno, compno, layno, start_pos, end_ph_pos, end_pos); + if (disto_on) { + fprintf(stream, " %8e", disto); + } + fprintf(stream, "\n"); + total_disto += disto; + pack_nb++; + } + } + }/* x = x0..x1 */ + } + } /* y = y0..y1 */ + } /* precno */ + } /* compno */ + } /* resno */ + } /* RPCL */ + + else if (cstr_info->prog == OPJ_PCRL) { /* PCRL */ + /* I suppose components have same XRsiz, YRsiz */ + int x0 = cstr_info->tile_Ox + tileno - (int)floor((float)tileno / + (float)cstr_info->tw) * cstr_info->tw * cstr_info->tile_x; + int y0 = cstr_info->tile_Ox + (int)floor((float)tileno / + (float)cstr_info->tw) * cstr_info->tile_y; + int x1 = x0 + cstr_info->tile_x; + int y1 = y0 + cstr_info->tile_y; + + /* Count the maximum number of precincts */ + int max_numprec = 0; + for (resno = 0; resno < max_numdecompos + 1; resno++) { + int numprec = cstr_info->tile[tileno].pw[resno] * + cstr_info->tile[tileno].ph[resno]; + if (numprec > max_numprec) { + max_numprec = numprec; + } + } + + fprintf(stream, + "PCRL\npack_nb tileno precno compno resno layno start_pos end_ph_pos end_pos"); + if (disto_on) { + fprintf(stream, " disto"); + } + fprintf(stream, "\n"); + + for (precno = 0; precno < max_numprec; precno++) { + for (compno = 0; compno < cstr_info->numcomps; compno++) { + for (resno = 0; resno < cstr_info->numdecompos[compno] + 1; resno++) { + int numprec = cstr_info->tile[tileno].pw[resno] * + cstr_info->tile[tileno].ph[resno]; + int pcnx = cstr_info->tile[tileno].pw[resno]; + int pcx = (int) pow(2, cstr_info->tile[tileno].pdx[resno] + + cstr_info->numdecompos[compno] - resno); + int pcy = (int) pow(2, cstr_info->tile[tileno].pdy[resno] + + cstr_info->numdecompos[compno] - resno); + int precno_x = precno - (int) floor((float)precno / (float)pcnx) * pcnx; + int precno_y = (int) floor((float)precno / (float)pcnx); + if (precno >= numprec) { + continue; + } + for (y = y0; y < y1; y++) { + if (precno_y * pcy == y) { + for (x = x0; x < x1; x++) { + if (precno_x * pcx == x) { + for (layno = 0; layno < cstr_info->numlayers; layno++) { + start_pos = cstr_info->tile[tileno].packet[pack_nb].start_pos; + end_ph_pos = cstr_info->tile[tileno].packet[pack_nb].end_ph_pos; + end_pos = cstr_info->tile[tileno].packet[pack_nb].end_pos; + disto = cstr_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %6d %6d %5d %7d %9" PRId64 " %9" PRId64 " %7" PRId64, + pack_nb, tileno, precno, compno, resno, layno, start_pos, end_ph_pos, end_pos); + if (disto_on) { + fprintf(stream, " %8e", disto); + } + fprintf(stream, "\n"); + total_disto += disto; + pack_nb++; + } + } + }/* x = x0..x1 */ + } + } /* y = y0..y1 */ + } /* resno */ + } /* compno */ + } /* precno */ + } /* PCRL */ + + else { /* CPRL */ + /* Count the maximum number of precincts */ + int max_numprec = 0; + for (resno = 0; resno < max_numdecompos + 1; resno++) { + int numprec = cstr_info->tile[tileno].pw[resno] * + cstr_info->tile[tileno].ph[resno]; + if (numprec > max_numprec) { + max_numprec = numprec; + } + } + + fprintf(stream, + "CPRL\npack_nb tileno compno precno resno layno start_pos end_ph_pos end_pos"); + if (disto_on) { + fprintf(stream, " disto"); + } + fprintf(stream, "\n"); + + for (compno = 0; compno < cstr_info->numcomps; compno++) { + /* I suppose components have same XRsiz, YRsiz */ + int x0 = cstr_info->tile_Ox + tileno - (int)floor((float)tileno / + (float)cstr_info->tw) * cstr_info->tw * cstr_info->tile_x; + int y0 = cstr_info->tile_Ox + (int)floor((float)tileno / + (float)cstr_info->tw) * cstr_info->tile_y; + int x1 = x0 + cstr_info->tile_x; + int y1 = y0 + cstr_info->tile_y; + + for (precno = 0; precno < max_numprec; precno++) { + for (resno = 0; resno < cstr_info->numdecompos[compno] + 1; resno++) { + int numprec = cstr_info->tile[tileno].pw[resno] * + cstr_info->tile[tileno].ph[resno]; + int pcnx = cstr_info->tile[tileno].pw[resno]; + int pcx = (int) pow(2, cstr_info->tile[tileno].pdx[resno] + + cstr_info->numdecompos[compno] - resno); + int pcy = (int) pow(2, cstr_info->tile[tileno].pdy[resno] + + cstr_info->numdecompos[compno] - resno); + int precno_x = precno - (int) floor((float)precno / (float)pcnx) * pcnx; + int precno_y = (int) floor((float)precno / (float)pcnx); + if (precno >= numprec) { + continue; + } + + for (y = y0; y < y1; y++) { + if (precno_y * pcy == y) { + for (x = x0; x < x1; x++) { + if (precno_x * pcx == x) { + for (layno = 0; layno < cstr_info->numlayers; layno++) { + start_pos = cstr_info->tile[tileno].packet[pack_nb].start_pos; + end_ph_pos = cstr_info->tile[tileno].packet[pack_nb].end_ph_pos; + end_pos = cstr_info->tile[tileno].packet[pack_nb].end_pos; + disto = cstr_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %6d %6d %5d %7d %9" PRId64 " %9" PRId64 " %7" PRId64, + pack_nb, tileno, compno, precno, resno, layno, start_pos, end_ph_pos, end_pos); + if (disto_on) { + fprintf(stream, " %8e", disto); + } + fprintf(stream, "\n"); + total_disto += disto; + pack_nb++; + } + } + }/* x = x0..x1 */ + } + } /* y = y0..y1 */ + } /* resno */ + } /* precno */ + } /* compno */ + } /* CPRL */ + } /* tileno */ + + if (disto_on) { + fprintf(stream, "%8e\n", cstr_info->D_max); /* SE max */ + fprintf(stream, "%.8e\n", total_disto); /* SE totale */ + } + /* UniPG>> */ + /* print the markers' list */ + if (cstr_info->marknum) { + fprintf(stream, "\nMARKER LIST\n"); + fprintf(stream, "%d\n", cstr_info->marknum); + fprintf(stream, "type\tstart_pos length\n"); + for (x = 0; x < cstr_info->marknum; x++) { + fprintf(stream, "%X\t%9" PRId64 " %9d\n", cstr_info->marker[x].type, + cstr_info->marker[x].pos, cstr_info->marker[x].len); + } + } + /* <<UniPG */ + fclose(stream); + + fprintf(stderr, "Generated index file %s\n", index); + + return 0; +} diff --git a/openjpeg/src/bin/jp2/index.h b/openjpeg/src/bin/jp2/index.h new file mode 100644 index 000000000..b461e91b1 --- /dev/null +++ b/openjpeg/src/bin/jp2/index.h @@ -0,0 +1,54 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __J2K_INDEX_H +#define __J2K_INDEX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** +Write a structured index to a file +@param cstr_info Codestream information +@param index Index filename +@return Returns 0 if successful, returns 1 otherwise +*/ +int write_index_file(opj_codestream_info_t *cstr_info, char *index); + +#ifdef __cplusplus +} +#endif + +#endif /* __J2K_INDEX_H */ + diff --git a/openjpeg/src/bin/jp2/opj_compress.c b/openjpeg/src/bin/jp2/opj_compress.c new file mode 100644 index 000000000..26454d9e7 --- /dev/null +++ b/openjpeg/src/bin/jp2/opj_compress.c @@ -0,0 +1,2069 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * Copyright (c) 2003-2014, Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr> + * Copyright (c) 2011-2012, Centre National d'Etudes Spatiales (CNES), France + * Copyright (c) 2012, CS Systemes d'Information, France + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <math.h> +#include <assert.h> + +#ifdef _WIN32 +#include "windirent.h" +#else +#include <dirent.h> +#endif /* _WIN32 */ + +#ifdef _WIN32 +#include <windows.h> +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#else +#include <strings.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/times.h> +#endif /* _WIN32 */ + +#include "opj_apps_config.h" +#include "openjpeg.h" +#include "opj_getopt.h" +#include "convert.h" +#include "index.h" + +#include "format_defs.h" +#include "opj_string.h" + +typedef struct dircnt { + /** Buffer for holding images read from Directory*/ + char *filename_buf; + /** Pointer to the buffer*/ + char **filename; +} dircnt_t; + +typedef struct img_folder { + /** The directory path of the folder containing input images*/ + char *imgdirpath; + /** Output format*/ + char *out_format; + /** Enable option*/ + char set_imgdir; + /** Enable Cod Format for output*/ + char set_out_format; +} img_fol_t; + +static void encode_help_display(void) +{ + fprintf(stdout, + "\nThis is the opj_compress utility from the OpenJPEG project.\n" + "It compresses various image formats with the JPEG 2000 algorithm.\n" + "It has been compiled against openjp2 library v%s.\n\n", opj_version()); + + fprintf(stdout, "Default encoding options:\n"); + fprintf(stdout, "-------------------------\n"); + fprintf(stdout, "\n"); + fprintf(stdout, " * Lossless\n"); + fprintf(stdout, " * 1 tile\n"); + fprintf(stdout, " * RGB->YCC conversion if at least 3 components\n"); + fprintf(stdout, " * Size of precinct : 2^15 x 2^15 (means 1 precinct)\n"); + fprintf(stdout, " * Size of code-block : 64 x 64\n"); + fprintf(stdout, " * Number of resolutions: 6\n"); + fprintf(stdout, " * No SOP marker in the codestream\n"); + fprintf(stdout, " * No EPH marker in the codestream\n"); + fprintf(stdout, " * No sub-sampling in x or y direction\n"); + fprintf(stdout, " * No mode switch activated\n"); + fprintf(stdout, " * Progression order: LRCP\n"); +#ifdef FIXME_INDEX + fprintf(stdout, " * No index file\n"); +#endif /* FIXME_INDEX */ + fprintf(stdout, " * No ROI upshifted\n"); + fprintf(stdout, " * No offset of the origin of the image\n"); + fprintf(stdout, " * No offset of the origin of the tiles\n"); + fprintf(stdout, " * Reversible DWT 5-3\n"); + /* UniPG>> */ +#ifdef USE_JPWL + fprintf(stdout, " * No JPWL protection\n"); +#endif /* USE_JPWL */ + /* <<UniPG */ + fprintf(stdout, "\n"); + + fprintf(stdout, "Note:\n"); + fprintf(stdout, "-----\n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "The markers written to the main_header are : SOC SIZ COD QCD COM.\n"); + fprintf(stdout, "COD and QCD never appear in the tile_header.\n"); + fprintf(stdout, "\n"); + + fprintf(stdout, "Parameters:\n"); + fprintf(stdout, "-----------\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "Required Parameters (except with -h):\n"); + fprintf(stdout, "One of the two options -ImgDir or -i must be used\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "-i <file>\n"); + fprintf(stdout, " Input file\n"); + fprintf(stdout, + " Known extensions are <PBM|PGM|PPM|PNM|PAM|PGX|PNG|BMP|TIF|RAW|RAWL|TGA>\n"); + fprintf(stdout, " If used, '-o <file>' must be provided\n"); + fprintf(stdout, "-o <compressed file>\n"); + fprintf(stdout, " Output file (accepted extensions are j2k or jp2).\n"); + fprintf(stdout, "-ImgDir <dir>\n"); + fprintf(stdout, " Image file Directory path (example ../Images) \n"); + fprintf(stdout, " When using this option -OutFor must be used\n"); + fprintf(stdout, "-OutFor <J2K|J2C|JP2>\n"); + fprintf(stdout, " Output format for compressed files.\n"); + fprintf(stdout, " Required only if -ImgDir is used\n"); + fprintf(stdout, + "-F <width>,<height>,<ncomp>,<bitdepth>,{s,u}@<dx1>x<dy1>:...:<dxn>x<dyn>\n"); + fprintf(stdout, " Characteristics of the raw input image\n"); + fprintf(stdout, + " If subsampling is omitted, 1x1 is assumed for all components\n"); + fprintf(stdout, " Example: -F 512,512,3,8,u@1x1:2x2:2x2\n"); + fprintf(stdout, + " for raw 512x512 image with 4:2:0 subsampling\n"); + fprintf(stdout, " Required only if RAW or RAWL input file is provided.\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "Optional Parameters:\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "-h\n"); + fprintf(stdout, " Display the help information.\n"); + fprintf(stdout, "-r <compression ratio>,<compression ratio>,...\n"); + fprintf(stdout, " Different compression ratios for successive layers.\n"); + fprintf(stdout, + " The rate specified for each quality level is the desired\n"); + fprintf(stdout, " compression factor (use 1 for lossless)\n"); + fprintf(stdout, " Decreasing ratios required.\n"); + fprintf(stdout, " Example: -r 20,10,1 means \n"); + fprintf(stdout, " quality layer 1: compress 20x, \n"); + fprintf(stdout, " quality layer 2: compress 10x \n"); + fprintf(stdout, " quality layer 3: compress lossless\n"); + fprintf(stdout, " Options -r and -q cannot be used together.\n"); + fprintf(stdout, "-q <psnr value>,<psnr value>,<psnr value>,...\n"); + fprintf(stdout, " Different psnr for successive layers (-q 30,40,50).\n"); + fprintf(stdout, " Increasing PSNR values required, except 0 which can\n"); + fprintf(stdout, " be used for the last layer to indicate it is lossless.\n"); + fprintf(stdout, " Options -r and -q cannot be used together.\n"); + fprintf(stdout, "-n <number of resolutions>\n"); + fprintf(stdout, " Number of resolutions.\n"); + fprintf(stdout, + " It corresponds to the number of DWT decompositions +1. \n"); + fprintf(stdout, " Default: 6.\n"); + fprintf(stdout, "-b <cblk width>,<cblk height>\n"); + fprintf(stdout, + " Code-block size. The dimension must respect the constraint \n"); + fprintf(stdout, + " defined in the JPEG-2000 standard (no dimension smaller than 4 \n"); + fprintf(stdout, + " or greater than 1024, no code-block with more than 4096 coefficients).\n"); + fprintf(stdout, " The maximum value authorized is 64x64. \n"); + fprintf(stdout, " Default: 64x64.\n"); + fprintf(stdout, + "-c [<prec width>,<prec height>],[<prec width>,<prec height>],...\n"); + fprintf(stdout, " Precinct size. Values specified must be power of 2. \n"); + fprintf(stdout, + " Multiple records may be supplied, in which case the first record refers\n"); + fprintf(stdout, + " to the highest resolution level and subsequent records to lower \n"); + fprintf(stdout, + " resolution levels. The last specified record is right-shifted for each \n"); + fprintf(stdout, " remaining lower resolution levels.\n"); + fprintf(stdout, " Default: 215x215 at each resolution.\n"); + fprintf(stdout, "-t <tile width>,<tile height>\n"); + fprintf(stdout, " Tile size.\n"); + fprintf(stdout, + " Default: the dimension of the whole image, thus only one tile.\n"); + fprintf(stdout, "-p <LRCP|RLCP|RPCL|PCRL|CPRL>\n"); + fprintf(stdout, " Progression order.\n"); + fprintf(stdout, " Default: LRCP.\n"); + fprintf(stdout, "-s <subX,subY>\n"); + fprintf(stdout, " Subsampling factor.\n"); + fprintf(stdout, " Subsampling bigger than 2 can produce error\n"); + fprintf(stdout, " Default: no subsampling.\n"); + fprintf(stdout, + "-POC <progression order change>/<progression order change>/...\n"); + fprintf(stdout, " Progression order change.\n"); + fprintf(stdout, + " The syntax of a progression order change is the following:\n"); + fprintf(stdout, + " T<tile>=<resStart>,<compStart>,<layerEnd>,<resEnd>,<compEnd>,<progOrder>\n"); + fprintf(stdout, " Example: -POC T1=0,0,1,5,3,CPRL/T1=5,0,1,6,3,CPRL\n"); + fprintf(stdout, "-SOP\n"); + fprintf(stdout, " Write SOP marker before each packet.\n"); + fprintf(stdout, "-EPH\n"); + fprintf(stdout, " Write EPH marker after each header packet.\n"); + fprintf(stdout, "-M <key value>\n"); + fprintf(stdout, " Mode switch.\n"); + fprintf(stdout, " [1=BYPASS(LAZY) 2=RESET 4=RESTART(TERMALL)\n"); + fprintf(stdout, " 8=VSC 16=ERTERM(SEGTERM) 32=SEGMARK(SEGSYM)]\n"); + fprintf(stdout, " Indicate multiple modes by adding their values.\n"); + fprintf(stdout, + " Example: RESTART(4) + RESET(2) + SEGMARK(32) => -M 38\n"); + fprintf(stdout, "-TP <R|L|C>\n"); + fprintf(stdout, " Divide packets of every tile into tile-parts.\n"); + fprintf(stdout, + " Division is made by grouping Resolutions (R), Layers (L)\n"); + fprintf(stdout, " or Components (C).\n"); +#ifdef FIXME_INDEX + fprintf(stdout, "-x <index file>\n"); + fprintf(stdout, " Create an index file.\n"); +#endif /*FIXME_INDEX*/ + fprintf(stdout, "-ROI c=<component index>,U=<upshifting value>\n"); + fprintf(stdout, " Quantization indices upshifted for a component. \n"); + fprintf(stdout, + " Warning: This option does not implement the usual ROI (Region of Interest).\n"); + fprintf(stdout, + " It should be understood as a 'Component of Interest'. It offers the \n"); + fprintf(stdout, + " possibility to upshift the value of a component during quantization step.\n"); + fprintf(stdout, + " The value after c= is the component number [0, 1, 2, ...] and the value \n"); + fprintf(stdout, + " after U= is the value of upshifting. U must be in the range [0, 37].\n"); + fprintf(stdout, "-d <image offset X,image offset Y>\n"); + fprintf(stdout, " Offset of the origin of the image.\n"); + fprintf(stdout, "-T <tile offset X,tile offset Y>\n"); + fprintf(stdout, " Offset of the origin of the tiles.\n"); + fprintf(stdout, "-I\n"); + fprintf(stdout, " Use the irreversible DWT 9-7.\n"); + fprintf(stdout, "-mct <0|1|2>\n"); + fprintf(stdout, + " Explicitly specifies if a Multiple Component Transform has to be used.\n"); + fprintf(stdout, " 0: no MCT ; 1: RGB->YCC conversion ; 2: custom MCT.\n"); + fprintf(stdout, + " If custom MCT, \"-m\" option has to be used (see hereunder).\n"); + fprintf(stdout, + " By default, RGB->YCC conversion is used if there are 3 components or more,\n"); + fprintf(stdout, " no conversion otherwise.\n"); + fprintf(stdout, "-m <file>\n"); + fprintf(stdout, + " Use array-based MCT, values are coma separated, line by line\n"); + fprintf(stdout, + " No specific separators between lines, no space allowed between values.\n"); + fprintf(stdout, + " If this option is used, it automatically sets \"-mct\" option to 2.\n"); + fprintf(stdout, "-cinema2K <24|48>\n"); + fprintf(stdout, " Digital Cinema 2K profile compliant codestream.\n"); + fprintf(stdout, + " Need to specify the frames per second for a 2K resolution.\n"); + fprintf(stdout, " Only 24 or 48 fps are currently allowed.\n"); + fprintf(stdout, "-cinema4K\n"); + fprintf(stdout, " Digital Cinema 4K profile compliant codestream.\n"); + fprintf(stdout, " Frames per second not required. Default value is 24fps.\n"); + fprintf(stdout, "-jpip\n"); + fprintf(stdout, " Write jpip codestream index box in JP2 output file.\n"); + fprintf(stdout, " Currently supports only RPCL order.\n"); + fprintf(stdout, "-C <comment>\n"); + fprintf(stdout, " Add <comment> in the comment marker segment.\n"); + /* UniPG>> */ +#ifdef USE_JPWL + fprintf(stdout, "-W <params>\n"); + fprintf(stdout, " Adoption of JPWL (Part 11) capabilities (-W params)\n"); + fprintf(stdout, + " The <params> field can be written and repeated in any order:\n"); + fprintf(stdout, " [h<tilepart><=type>,s<tilepart><=method>,a=<addr>,...\n"); + fprintf(stdout, " ...,z=<size>,g=<range>,p<tilepart:pack><=type>]\n"); + fprintf(stdout, + " h selects the header error protection (EPB): 'type' can be\n"); + fprintf(stdout, + " [0=none 1,absent=predefined 16=CRC-16 32=CRC-32 37-128=RS]\n"); + fprintf(stdout, + " if 'tilepart' is absent, it is for main and tile headers\n"); + fprintf(stdout, " if 'tilepart' is present, it applies from that tile\n"); + fprintf(stdout, + " onwards, up to the next h<> spec, or to the last tilepart\n"); + fprintf(stdout, " in the codestream (max. %d specs)\n", + JPWL_MAX_NO_TILESPECS); + fprintf(stdout, + " p selects the packet error protection (EEP/UEP with EPBs)\n"); + fprintf(stdout, " to be applied to raw data: 'type' can be\n"); + fprintf(stdout, + " [0=none 1,absent=predefined 16=CRC-16 32=CRC-32 37-128=RS]\n"); + fprintf(stdout, + " if 'tilepart:pack' is absent, it is from tile 0, packet 0\n"); + fprintf(stdout, + " if 'tilepart:pack' is present, it applies from that tile\n"); + fprintf(stdout, + " and that packet onwards, up to the next packet spec\n"); + fprintf(stdout, + " or to the last packet in the last tilepart in the stream\n"); + fprintf(stdout, " (max. %d specs)\n", JPWL_MAX_NO_PACKSPECS); + fprintf(stdout, + " s enables sensitivity data insertion (ESD): 'method' can be\n"); + fprintf(stdout, + " [-1=NO ESD 0=RELATIVE ERROR 1=MSE 2=MSE REDUCTION 3=PSNR\n"); + fprintf(stdout, " 4=PSNR INCREMENT 5=MAXERR 6=TSE 7=RESERVED]\n"); + fprintf(stdout, " if 'tilepart' is absent, it is for main header only\n"); + fprintf(stdout, " if 'tilepart' is present, it applies from that tile\n"); + fprintf(stdout, + " onwards, up to the next s<> spec, or to the last tilepart\n"); + fprintf(stdout, " in the codestream (max. %d specs)\n", + JPWL_MAX_NO_TILESPECS); + fprintf(stdout, " g determines the addressing mode: <range> can be\n"); + fprintf(stdout, " [0=PACKET 1=BYTE RANGE 2=PACKET RANGE]\n"); + fprintf(stdout, + " a determines the size of data addressing: <addr> can be\n"); + fprintf(stdout, + " 2/4 bytes (small/large codestreams). If not set, auto-mode\n"); + fprintf(stdout, + " z determines the size of sensitivity values: <size> can be\n"); + fprintf(stdout, + " 1/2 bytes, for the transformed pseudo-floating point value\n"); + fprintf(stdout, " ex.:\n"); + fprintf(stdout, + " h,h0=64,h3=16,h5=32,p0=78,p0:24=56,p1,p3:0=0,p3:20=32,s=0,\n"); + fprintf(stdout, " s0=6,s3=-1,a=0,g=1,z=1\n"); + fprintf(stdout, " means\n"); + fprintf(stdout, + " predefined EPB in MH, rs(64,32) from TPH 0 to TPH 2,\n"); + fprintf(stdout, + " CRC-16 in TPH 3 and TPH 4, CRC-32 in remaining TPHs,\n"); + fprintf(stdout, " UEP rs(78,32) for packets 0 to 23 of tile 0,\n"); + fprintf(stdout, + " UEP rs(56,32) for packs. 24 to the last of tilepart 0,\n"); + fprintf(stdout, " UEP rs default for packets of tilepart 1,\n"); + fprintf(stdout, " no UEP for packets 0 to 19 of tilepart 3,\n"); + fprintf(stdout, + " UEP CRC-32 for packs. 20 of tilepart 3 to last tilepart,\n"); + fprintf(stdout, " relative sensitivity ESD for MH,\n"); + fprintf(stdout, + " TSE ESD from TPH 0 to TPH 2, byte range with automatic\n"); + fprintf(stdout, + " size of addresses and 1 byte for each sensitivity value\n"); + fprintf(stdout, " ex.:\n"); + fprintf(stdout, " h,s,p\n"); + fprintf(stdout, " means\n"); + fprintf(stdout, + " default protection to headers (MH and TPHs) as well as\n"); + fprintf(stdout, " data packets, one ESD in MH\n"); + fprintf(stdout, + " N.B.: use the following recommendations when specifying\n"); + fprintf(stdout, " the JPWL parameters list\n"); + fprintf(stdout, + " - when you use UEP, always pair the 'p' option with 'h'\n"); +#endif /* USE_JPWL */ + /* <<UniPG */ + fprintf(stdout, "\n"); +#ifdef FIXME_INDEX + fprintf(stdout, "Index structure:\n"); + fprintf(stdout, "----------------\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "Image_height Image_width\n"); + fprintf(stdout, "progression order\n"); + fprintf(stdout, "Tiles_size_X Tiles_size_Y\n"); + fprintf(stdout, "Tiles_nb_X Tiles_nb_Y\n"); + fprintf(stdout, "Components_nb\n"); + fprintf(stdout, "Layers_nb\n"); + fprintf(stdout, "decomposition_levels\n"); + fprintf(stdout, "[Precincts_size_X_res_Nr Precincts_size_Y_res_Nr]...\n"); + fprintf(stdout, " [Precincts_size_X_res_0 Precincts_size_Y_res_0]\n"); + fprintf(stdout, "Main_header_start_position\n"); + fprintf(stdout, "Main_header_end_position\n"); + fprintf(stdout, "Codestream_size\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "INFO ON TILES\n"); + fprintf(stdout, + "tileno start_pos end_hd end_tile nbparts disto nbpix disto/nbpix\n"); + fprintf(stdout, + "Tile_0 start_pos end_Theader end_pos NumParts TotalDisto NumPix MaxMSE\n"); + fprintf(stdout, + "Tile_1 '' '' '' '' '' '' ''\n"); + fprintf(stdout, "...\n"); + fprintf(stdout, + "Tile_Nt '' '' '' '' '' '' ''\n"); + fprintf(stdout, "...\n"); + fprintf(stdout, "TILE 0 DETAILS\n"); + fprintf(stdout, "part_nb tileno num_packs start_pos end_tph_pos end_pos\n"); + fprintf(stdout, "...\n"); + fprintf(stdout, "Progression_string\n"); + fprintf(stdout, + "pack_nb tileno layno resno compno precno start_pos end_ph_pos end_pos disto\n"); + fprintf(stdout, + "Tpacket_0 Tile layer res. comp. prec. start_pos end_pos disto\n"); + fprintf(stdout, "...\n"); + fprintf(stdout, + "Tpacket_Np '' '' '' '' '' '' '' ''\n"); + fprintf(stdout, "MaxDisto\n"); + fprintf(stdout, "TotalDisto\n\n"); +#endif /*FIXME_INDEX*/ +} + +static OPJ_PROG_ORDER give_progression(const char progression[4]) +{ + if (strncmp(progression, "LRCP", 4) == 0) { + return OPJ_LRCP; + } + if (strncmp(progression, "RLCP", 4) == 0) { + return OPJ_RLCP; + } + if (strncmp(progression, "RPCL", 4) == 0) { + return OPJ_RPCL; + } + if (strncmp(progression, "PCRL", 4) == 0) { + return OPJ_PCRL; + } + if (strncmp(progression, "CPRL", 4) == 0) { + return OPJ_CPRL; + } + + return OPJ_PROG_UNKNOWN; +} + +static unsigned int get_num_images(char *imgdirpath) +{ + DIR *dir; + struct dirent* content; + unsigned int num_images = 0; + + /*Reading the input images from given input directory*/ + + dir = opendir(imgdirpath); + if (!dir) { + fprintf(stderr, "Could not open Folder %s\n", imgdirpath); + return 0; + } + + num_images = 0; + while ((content = readdir(dir)) != NULL) { + if (strcmp(".", content->d_name) == 0 || strcmp("..", content->d_name) == 0) { + continue; + } + num_images++; + } + closedir(dir); + return num_images; +} + +static int load_images(dircnt_t *dirptr, char *imgdirpath) +{ + DIR *dir; + struct dirent* content; + int i = 0; + + /*Reading the input images from given input directory*/ + + dir = opendir(imgdirpath); + if (!dir) { + fprintf(stderr, "Could not open Folder %s\n", imgdirpath); + return 1; + } else { + fprintf(stderr, "Folder opened successfully\n"); + } + + while ((content = readdir(dir)) != NULL) { + if (strcmp(".", content->d_name) == 0 || strcmp("..", content->d_name) == 0) { + continue; + } + + strcpy(dirptr->filename[i], content->d_name); + i++; + } + closedir(dir); + return 0; +} + +static int get_file_format(char *filename) +{ + unsigned int i; + static const char *extension[] = { + "pgx", "pnm", "pgm", "ppm", "pbm", "pam", "bmp", "tif", "raw", "rawl", "tga", "png", "j2k", "jp2", "j2c", "jpc" + }; + static const int format[] = { + PGX_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, BMP_DFMT, TIF_DFMT, RAW_DFMT, RAWL_DFMT, TGA_DFMT, PNG_DFMT, J2K_CFMT, JP2_CFMT, J2K_CFMT, J2K_CFMT + }; + char * ext = strrchr(filename, '.'); + if (ext == NULL) { + return -1; + } + ext++; + for (i = 0; i < sizeof(format) / sizeof(*format); i++) { + if (strcasecmp(ext, extension[i]) == 0) { + return format[i]; + } + } + return -1; +} + +static char * get_file_name(char *name) +{ + char *fname = strtok(name, "."); + return fname; +} + +static char get_next_file(int imageno, dircnt_t *dirptr, img_fol_t *img_fol, + opj_cparameters_t *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 = get_file_format(image_filename); + if (parameters->decod_format == -1) { + return 1; + } + sprintf(infilename, "%s/%s", img_fol->imgdirpath, image_filename); + if (opj_strcpy_s(parameters->infile, sizeof(parameters->infile), + infilename) != 0) { + return 1; + } + + /*Set output file*/ + strcpy(temp_ofname, get_file_name(image_filename)); + while ((temp_p = strtok(NULL, ".")) != NULL) { + strcat(temp_ofname, temp1); + sprintf(temp1, ".%s", temp_p); + } + if (img_fol->set_out_format == 1) { + sprintf(outfilename, "%s/%s.%s", img_fol->imgdirpath, temp_ofname, + img_fol->out_format); + if (opj_strcpy_s(parameters->outfile, sizeof(parameters->outfile), + outfilename) != 0) { + return 1; + } + } + return 0; +} + +/* ------------------------------------------------------------------------------------ */ + +static int parse_cmdline_encoder(int argc, char **argv, + opj_cparameters_t *parameters, + img_fol_t *img_fol, raw_cparameters_t *raw_cp, char *indexfilename, + size_t indexfilename_size) +{ + OPJ_UINT32 i, j; + int totlen, c; + opj_option_t long_option[] = { + {"cinema2K", REQ_ARG, NULL, 'w'}, + {"cinema4K", NO_ARG, NULL, 'y'}, + {"ImgDir", REQ_ARG, NULL, 'z'}, + {"TP", REQ_ARG, NULL, 'u'}, + {"SOP", NO_ARG, NULL, 'S'}, + {"EPH", NO_ARG, NULL, 'E'}, + {"OutFor", REQ_ARG, NULL, 'O'}, + {"POC", REQ_ARG, NULL, 'P'}, + {"ROI", REQ_ARG, NULL, 'R'}, + {"jpip", NO_ARG, NULL, 'J'}, + {"mct", REQ_ARG, NULL, 'Y'} + }; + + /* parse the command line */ + const char optlist[] = "i:o:r:q:n:b:c:t:p:s:SEM:x:R:d:T:If:P:C:F:u:JY:" +#ifdef USE_JPWL + "W:" +#endif /* USE_JPWL */ + "h"; + + totlen = sizeof(long_option); + img_fol->set_out_format = 0; + raw_cp->rawWidth = 0; + + do { + c = opj_getopt_long(argc, argv, optlist, long_option, totlen); + if (c == -1) { + break; + } + switch (c) { + case 'i': { /* input file */ + char *infile = opj_optarg; + parameters->decod_format = get_file_format(infile); + switch (parameters->decod_format) { + case PGX_DFMT: + case PXM_DFMT: + case BMP_DFMT: + case TIF_DFMT: + case RAW_DFMT: + case RAWL_DFMT: + case TGA_DFMT: + case PNG_DFMT: + break; + default: + fprintf(stderr, + "[ERROR] Unknown input file format: %s \n" + " Known file formats are *.pnm, *.pgm, *.ppm, *.pgx, *png, *.bmp, *.tif, *.raw or *.tga\n", + infile); + return 1; + } + if (opj_strcpy_s(parameters->infile, sizeof(parameters->infile), infile) != 0) { + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 'o': { /* output file */ + char *outfile = opj_optarg; + parameters->cod_format = get_file_format(outfile); + switch (parameters->cod_format) { + case J2K_CFMT: + case JP2_CFMT: + break; + default: + fprintf(stderr, + "Unknown output format image %s [only *.j2k, *.j2c or *.jp2]!! \n", outfile); + return 1; + } + if (opj_strcpy_s(parameters->outfile, sizeof(parameters->outfile), + outfile) != 0) { + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + case 'O': { /* output format */ + char outformat[50]; + char *of = opj_optarg; + sprintf(outformat, ".%s", of); + img_fol->set_out_format = 1; + parameters->cod_format = get_file_format(outformat); + switch (parameters->cod_format) { + case J2K_CFMT: + case JP2_CFMT: + img_fol->out_format = opj_optarg; + break; + default: + fprintf(stderr, "Unknown output format image [only j2k, j2c, jp2]!! \n"); + return 1; + } + } + break; + + + /* ----------------------------------------------------- */ + + + case 'r': { /* rates rates/distorsion */ + char *s = opj_optarg; + parameters->tcp_numlayers = 0; + while (sscanf(s, "%f", ¶meters->tcp_rates[parameters->tcp_numlayers]) == + 1) { + parameters->tcp_numlayers++; + while (*s && *s != ',') { + s++; + } + if (!*s) { + break; + } + s++; + } + parameters->cp_disto_alloc = 1; + } + break; + + /* ----------------------------------------------------- */ + + + case 'F': { /* Raw image format parameters */ + OPJ_BOOL wrong = OPJ_FALSE; + char *substr1; + char *substr2; + char *sep; + char signo; + int width, height, bitdepth, ncomp; + OPJ_UINT32 len; + OPJ_BOOL raw_signed = OPJ_FALSE; + substr2 = strchr(opj_optarg, '@'); + if (substr2 == NULL) { + len = (OPJ_UINT32) strlen(opj_optarg); + } else { + len = (OPJ_UINT32)(substr2 - opj_optarg); + substr2++; /* skip '@' character */ + } + substr1 = (char*) malloc((len + 1) * sizeof(char)); + if (substr1 == NULL) { + return 1; + } + memcpy(substr1, opj_optarg, len); + substr1[len] = '\0'; + if (sscanf(substr1, "%d,%d,%d,%d,%c", &width, &height, &ncomp, &bitdepth, + &signo) == 5) { + if (signo == 's') { + raw_signed = OPJ_TRUE; + } else if (signo == 'u') { + raw_signed = OPJ_FALSE; + } else { + wrong = OPJ_TRUE; + } + } else { + wrong = OPJ_TRUE; + } + if (!wrong) { + int compno; + int lastdx = 1; + int lastdy = 1; + raw_cp->rawWidth = width; + raw_cp->rawHeight = height; + raw_cp->rawComp = ncomp; + raw_cp->rawBitDepth = bitdepth; + raw_cp->rawSigned = raw_signed; + raw_cp->rawComps = (raw_comp_cparameters_t*) malloc(((OPJ_UINT32)( + ncomp)) * sizeof(raw_comp_cparameters_t)); + if (raw_cp->rawComps == NULL) { + free(substr1); + return 1; + } + for (compno = 0; compno < ncomp && !wrong; compno++) { + if (substr2 == NULL) { + raw_cp->rawComps[compno].dx = lastdx; + raw_cp->rawComps[compno].dy = lastdy; + } else { + int dx, dy; + sep = strchr(substr2, ':'); + if (sep == NULL) { + if (sscanf(substr2, "%dx%d", &dx, &dy) == 2) { + lastdx = dx; + lastdy = dy; + raw_cp->rawComps[compno].dx = dx; + raw_cp->rawComps[compno].dy = dy; + substr2 = NULL; + } else { + wrong = OPJ_TRUE; + } + } else { + if (sscanf(substr2, "%dx%d:%s", &dx, &dy, substr2) == 3) { + raw_cp->rawComps[compno].dx = dx; + raw_cp->rawComps[compno].dy = dy; + } else { + wrong = OPJ_TRUE; + } + } + } + } + } + free(substr1); + if (wrong) { + fprintf(stderr, "\nError: invalid raw image parameters\n"); + fprintf(stderr, "Please use the Format option -F:\n"); + fprintf(stderr, + "-F <width>,<height>,<ncomp>,<bitdepth>,{s,u}@<dx1>x<dy1>:...:<dxn>x<dyn>\n"); + fprintf(stderr, + "If subsampling is omitted, 1x1 is assumed for all components\n"); + fprintf(stderr, + "Example: -i image.raw -o image.j2k -F 512,512,3,8,u@1x1:2x2:2x2\n"); + fprintf(stderr, " for raw 512x512 image with 4:2:0 subsampling\n"); + fprintf(stderr, "Aborting.\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 'q': { /* add fixed_quality */ + char *s = opj_optarg; + while (sscanf(s, "%f", ¶meters->tcp_distoratio[parameters->tcp_numlayers]) + == 1) { + parameters->tcp_numlayers++; + while (*s && *s != ',') { + s++; + } + if (!*s) { + break; + } + s++; + } + parameters->cp_fixed_quality = 1; + } + break; + + /* dda */ + /* ----------------------------------------------------- */ + + case 'f': { /* mod fixed_quality (before : -q) */ + int *row = NULL, *col = NULL; + OPJ_UINT32 numlayers = 0, numresolution = 0, matrix_width = 0; + + char *s = opj_optarg; + sscanf(s, "%u", &numlayers); + s++; + if (numlayers > 9) { + s++; + } + + parameters->tcp_numlayers = (int)numlayers; + numresolution = (OPJ_UINT32)parameters->numresolution; + matrix_width = numresolution * 3; + parameters->cp_matrice = (int *) malloc(numlayers * matrix_width * sizeof(int)); + if (parameters->cp_matrice == NULL) { + return 1; + } + s = s + 2; + + for (i = 0; i < numlayers; i++) { + row = ¶meters->cp_matrice[i * matrix_width]; + col = row; + parameters->tcp_rates[i] = 1; + sscanf(s, "%d,", &col[0]); + s += 2; + if (col[0] > 9) { + s++; + } + col[1] = 0; + col[2] = 0; + for (j = 1; j < numresolution; j++) { + col += 3; + sscanf(s, "%d,%d,%d", &col[0], &col[1], &col[2]); + s += 6; + if (col[0] > 9) { + s++; + } + if (col[1] > 9) { + s++; + } + if (col[2] > 9) { + s++; + } + } + if (i < numlayers - 1) { + s++; + } + } + parameters->cp_fixed_alloc = 1; + } + break; + + /* ----------------------------------------------------- */ + + case 't': { /* tiles */ + sscanf(opj_optarg, "%d,%d", ¶meters->cp_tdx, ¶meters->cp_tdy); + parameters->tile_size_on = OPJ_TRUE; + } + break; + + /* ----------------------------------------------------- */ + + case 'n': { /* resolution */ + sscanf(opj_optarg, "%d", ¶meters->numresolution); + } + break; + + /* ----------------------------------------------------- */ + case 'c': { /* precinct dimension */ + char sep; + int res_spec = 0; + + char *s = opj_optarg; + int ret; + do { + sep = 0; + ret = sscanf(s, "[%d,%d]%c", ¶meters->prcw_init[res_spec], + ¶meters->prch_init[res_spec], &sep); + if (!(ret == 2 && sep == 0) && !(ret == 3 && sep == ',')) { + fprintf(stderr, "\nError: could not parse precinct dimension: '%s' %x\n", s, + sep); + fprintf(stderr, "Example: -i lena.raw -o lena.j2k -c [128,128],[128,128]\n"); + return 1; + } + parameters->csty |= 0x01; + res_spec++; + s = strpbrk(s, "]") + 2; + } while (sep == ','); + parameters->res_spec = res_spec; + } + break; + + /* ----------------------------------------------------- */ + + case 'b': { /* code-block dimension */ + int cblockw_init = 0, cblockh_init = 0; + sscanf(opj_optarg, "%d,%d", &cblockw_init, &cblockh_init); + if (cblockw_init > 1024 || cblockw_init < 4 || + cblockh_init > 1024 || cblockh_init < 4 || + cblockw_init * cblockh_init > 4096) { + fprintf(stderr, + "!! Size of code_block error (option -b) !!\n\nRestriction :\n" + " * width*height<=4096\n * 4<=width,height<= 1024\n\n"); + return 1; + } + parameters->cblockw_init = cblockw_init; + parameters->cblockh_init = cblockh_init; + } + break; + + /* ----------------------------------------------------- */ + + case 'x': { /* creation of index file */ + if (opj_strcpy_s(indexfilename, indexfilename_size, opj_optarg) != 0) { + return 1; + } + /* FIXME ADE INDEX >> */ + fprintf(stderr, + "[WARNING] Index file generation is currently broken.\n" + " '-x' option ignored.\n"); + /* << FIXME ADE INDEX */ + } + break; + + /* ----------------------------------------------------- */ + + case 'p': { /* progression order */ + char progression[4]; + + strncpy(progression, opj_optarg, 4); + parameters->prog_order = give_progression(progression); + if (parameters->prog_order == -1) { + fprintf(stderr, "Unrecognized progression order " + "[LRCP, RLCP, RPCL, PCRL, CPRL] !!\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 's': { /* subsampling factor */ + if (sscanf(opj_optarg, "%d,%d", ¶meters->subsampling_dx, + ¶meters->subsampling_dy) != 2) { + fprintf(stderr, "'-s' sub-sampling argument error ! [-s dx,dy]\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 'd': { /* coordonnate of the reference grid */ + if (sscanf(opj_optarg, "%d,%d", ¶meters->image_offset_x0, + ¶meters->image_offset_y0) != 2) { + fprintf(stderr, "-d 'coordonnate of the reference grid' argument " + "error !! [-d x0,y0]\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 'h': /* display an help description */ + encode_help_display(); + return 1; + + /* ----------------------------------------------------- */ + + case 'P': { /* POC */ + int numpocs = 0; /* number of progression order change (POC) default 0 */ + opj_poc_t *POC = NULL; /* POC : used in case of Progression order change */ + + char *s = opj_optarg; + POC = parameters->POC; + + while (sscanf(s, "T%u=%u,%u,%u,%u,%u,%4s", &POC[numpocs].tile, + &POC[numpocs].resno0, &POC[numpocs].compno0, + &POC[numpocs].layno1, &POC[numpocs].resno1, + &POC[numpocs].compno1, POC[numpocs].progorder) == 7) { + POC[numpocs].prg1 = give_progression(POC[numpocs].progorder); + numpocs++; + while (*s && *s != '/') { + s++; + } + if (!*s) { + break; + } + s++; + } + parameters->numpocs = (OPJ_UINT32)numpocs; + } + break; + + /* ------------------------------------------------------ */ + + case 'S': { /* SOP marker */ + parameters->csty |= 0x02; + } + break; + + /* ------------------------------------------------------ */ + + case 'E': { /* EPH marker */ + parameters->csty |= 0x04; + } + break; + + /* ------------------------------------------------------ */ + + case 'M': { /* Mode switch pas tous au point !! */ + int value = 0; + if (sscanf(opj_optarg, "%d", &value) == 1) { + for (i = 0; i <= 5; i++) { + int cache = value & (1 << i); + if (cache) { + parameters->mode |= (1 << i); + } + } + } + } + break; + + /* ------------------------------------------------------ */ + + case 'R': { /* ROI */ + if (sscanf(opj_optarg, "c=%d,U=%d", ¶meters->roi_compno, + ¶meters->roi_shift) != 2) { + fprintf(stderr, "ROI error !! [-ROI c='compno',U='shift']\n"); + return 1; + } + } + break; + + /* ------------------------------------------------------ */ + + case 'T': { /* Tile offset */ + if (sscanf(opj_optarg, "%d,%d", ¶meters->cp_tx0, + ¶meters->cp_ty0) != 2) { + fprintf(stderr, "-T 'tile offset' argument error !! [-T X0,Y0]"); + return 1; + } + } + break; + + /* ------------------------------------------------------ */ + + case 'C': { /* add a comment */ + parameters->cp_comment = (char*)malloc(strlen(opj_optarg) + 1); + if (parameters->cp_comment) { + strcpy(parameters->cp_comment, opj_optarg); + } + } + break; + + + /* ------------------------------------------------------ */ + + case 'I': { /* reversible or not */ + parameters->irreversible = 1; + } + break; + + /* ------------------------------------------------------ */ + + case 'u': { /* Tile part generation*/ + parameters->tp_flag = opj_optarg[0]; + parameters->tp_on = 1; + } + break; + + /* ------------------------------------------------------ */ + + case 'z': { /* Image Directory path */ + img_fol->imgdirpath = (char*)malloc(strlen(opj_optarg) + 1); + if (img_fol->imgdirpath == NULL) { + return 1; + } + strcpy(img_fol->imgdirpath, opj_optarg); + img_fol->set_imgdir = 1; + } + break; + + /* ------------------------------------------------------ */ + + case 'w': { /* Digital Cinema 2K profile compliance*/ + int fps = 0; + sscanf(opj_optarg, "%d", &fps); + if (fps == 24) { + parameters->rsiz = OPJ_PROFILE_CINEMA_2K; + parameters->max_comp_size = OPJ_CINEMA_24_COMP; + parameters->max_cs_size = OPJ_CINEMA_24_CS; + } else if (fps == 48) { + parameters->rsiz = OPJ_PROFILE_CINEMA_2K; + parameters->max_comp_size = OPJ_CINEMA_48_COMP; + parameters->max_cs_size = OPJ_CINEMA_48_CS; + } else { + fprintf(stderr, "Incorrect value!! must be 24 or 48\n"); + return 1; + } + fprintf(stdout, "CINEMA 2K profile activated\n" + "Other options specified could be overridden\n"); + + } + break; + + /* ------------------------------------------------------ */ + + case 'y': { /* Digital Cinema 4K profile compliance*/ + parameters->rsiz = OPJ_PROFILE_CINEMA_4K; + fprintf(stdout, "CINEMA 4K profile activated\n" + "Other options specified could be overridden\n"); + } + break; + + /* ------------------------------------------------------ */ + + case 'Y': { /* Shall we do an MCT ? 0:no_mct;1:rgb->ycc;2:custom mct (-m option required)*/ + int mct_mode = 0; + sscanf(opj_optarg, "%d", &mct_mode); + if (mct_mode < 0 || mct_mode > 2) { + fprintf(stderr, + "MCT incorrect value!! Current accepted values are 0, 1 or 2.\n"); + return 1; + } + parameters->tcp_mct = (char) mct_mode; + } + break; + + /* ------------------------------------------------------ */ + + + case 'm': { /* mct input file */ + char *lFilename = opj_optarg; + char *lMatrix; + char *lCurrentPtr ; + float *lCurrentDoublePtr; + float *lSpace; + int *l_int_ptr; + int lNbComp = 0, lTotalComp, lMctComp, i2; + size_t lStrLen, lStrFread; + + /* Open file */ + FILE * lFile = fopen(lFilename, "r"); + if (lFile == NULL) { + return 1; + } + + /* Set size of file and read its content*/ + fseek(lFile, 0, SEEK_END); + lStrLen = (size_t)ftell(lFile); + fseek(lFile, 0, SEEK_SET); + lMatrix = (char *) malloc(lStrLen + 1); + if (lMatrix == NULL) { + fclose(lFile); + return 1; + } + lStrFread = fread(lMatrix, 1, lStrLen, lFile); + fclose(lFile); + if (lStrLen != lStrFread) { + free(lMatrix); + return 1; + } + + lMatrix[lStrLen] = 0; + lCurrentPtr = lMatrix; + + /* replace ',' by 0 */ + while (*lCurrentPtr != 0) { + if (*lCurrentPtr == ' ') { + *lCurrentPtr = 0; + ++lNbComp; + } + ++lCurrentPtr; + } + ++lNbComp; + lCurrentPtr = lMatrix; + + lNbComp = (int)(sqrt(4 * lNbComp + 1) / 2. - 0.5); + lMctComp = lNbComp * lNbComp; + lTotalComp = lMctComp + lNbComp; + lSpace = (float *) malloc((size_t)lTotalComp * sizeof(float)); + if (lSpace == NULL) { + free(lMatrix); + return 1; + } + lCurrentDoublePtr = lSpace; + for (i2 = 0; i2 < lMctComp; ++i2) { + lStrLen = strlen(lCurrentPtr) + 1; + *lCurrentDoublePtr++ = (float) atof(lCurrentPtr); + lCurrentPtr += lStrLen; + } + + l_int_ptr = (int*) lCurrentDoublePtr; + for (i2 = 0; i2 < lNbComp; ++i2) { + lStrLen = strlen(lCurrentPtr) + 1; + *l_int_ptr++ = atoi(lCurrentPtr); + lCurrentPtr += lStrLen; + } + + /* TODO should not be here ! */ + opj_set_MCT(parameters, lSpace, (int *)(lSpace + lMctComp), + (OPJ_UINT32)lNbComp); + + /* Free memory*/ + free(lSpace); + free(lMatrix); + } + break; + + + /* ------------------------------------------------------ */ + + /* UniPG>> */ +#ifdef USE_JPWL + /* ------------------------------------------------------ */ + + case 'W': { /* JPWL capabilities switched on */ + char *token = NULL; + int hprot, pprot, sens, addr, size, range; + + /* we need to enable indexing */ + if (!indexfilename || !*indexfilename) { + if (opj_strcpy_s(indexfilename, indexfilename_size, + JPWL_PRIVATEINDEX_NAME) != 0) { + return 1; + } + } + + /* search for different protection methods */ + + /* break the option in comma points and parse the result */ + token = strtok(opj_optarg, ","); + while (token != NULL) { + + /* search header error protection method */ + if (*token == 'h') { + + static int tile = 0, tilespec = 0, lasttileno = 0; + + hprot = 1; /* predefined method */ + + if (sscanf(token, "h=%d", &hprot) == 1) { + /* Main header, specified */ + if (!((hprot == 0) || (hprot == 1) || (hprot == 16) || (hprot == 32) || + ((hprot >= 37) && (hprot <= 128)))) { + fprintf(stderr, "ERROR -> invalid main header protection method h = %d\n", + hprot); + return 1; + } + parameters->jpwl_hprot_MH = hprot; + + } else if (sscanf(token, "h%d=%d", &tile, &hprot) == 2) { + /* Tile part header, specified */ + if (!((hprot == 0) || (hprot == 1) || (hprot == 16) || (hprot == 32) || + ((hprot >= 37) && (hprot <= 128)))) { + fprintf(stderr, "ERROR -> invalid tile part header protection method h = %d\n", + hprot); + return 1; + } + if (tile < 0) { + fprintf(stderr, + "ERROR -> invalid tile part number on protection method t = %d\n", tile); + return 1; + } + if (tilespec < JPWL_MAX_NO_TILESPECS) { + parameters->jpwl_hprot_TPH_tileno[tilespec] = lasttileno = tile; + parameters->jpwl_hprot_TPH[tilespec++] = hprot; + } + + } else if (sscanf(token, "h%d", &tile) == 1) { + /* Tile part header, unspecified */ + if (tile < 0) { + fprintf(stderr, + "ERROR -> invalid tile part number on protection method t = %d\n", tile); + return 1; + } + if (tilespec < JPWL_MAX_NO_TILESPECS) { + parameters->jpwl_hprot_TPH_tileno[tilespec] = lasttileno = tile; + parameters->jpwl_hprot_TPH[tilespec++] = hprot; + } + + + } else if (!strcmp(token, "h")) { + /* Main header, unspecified */ + parameters->jpwl_hprot_MH = hprot; + + } else { + fprintf(stderr, "ERROR -> invalid protection method selection = %s\n", token); + return 1; + }; + + } + + /* search packet error protection method */ + if (*token == 'p') { + + static int pack = 0, tile = 0, packspec = 0; + + pprot = 1; /* predefined method */ + + if (sscanf(token, "p=%d", &pprot) == 1) { + /* Method for all tiles and all packets */ + if (!((pprot == 0) || (pprot == 1) || (pprot == 16) || (pprot == 32) || + ((pprot >= 37) && (pprot <= 128)))) { + fprintf(stderr, "ERROR -> invalid default packet protection method p = %d\n", + pprot); + return 1; + } + parameters->jpwl_pprot_tileno[0] = 0; + parameters->jpwl_pprot_packno[0] = 0; + parameters->jpwl_pprot[0] = pprot; + + } else if (sscanf(token, "p%d=%d", &tile, &pprot) == 2) { + /* method specified from that tile on */ + if (!((pprot == 0) || (pprot == 1) || (pprot == 16) || (pprot == 32) || + ((pprot >= 37) && (pprot <= 128)))) { + fprintf(stderr, "ERROR -> invalid packet protection method p = %d\n", pprot); + return 1; + } + if (tile < 0) { + fprintf(stderr, + "ERROR -> invalid tile part number on protection method p = %d\n", tile); + return 1; + } + if (packspec < JPWL_MAX_NO_PACKSPECS) { + parameters->jpwl_pprot_tileno[packspec] = tile; + parameters->jpwl_pprot_packno[packspec] = 0; + parameters->jpwl_pprot[packspec++] = pprot; + } + + } else if (sscanf(token, "p%d:%d=%d", &tile, &pack, &pprot) == 3) { + /* method fully specified from that tile and that packet on */ + if (!((pprot == 0) || (pprot == 1) || (pprot == 16) || (pprot == 32) || + ((pprot >= 37) && (pprot <= 128)))) { + fprintf(stderr, "ERROR -> invalid packet protection method p = %d\n", pprot); + return 1; + } + if (tile < 0) { + fprintf(stderr, + "ERROR -> invalid tile part number on protection method p = %d\n", tile); + return 1; + } + if (pack < 0) { + fprintf(stderr, "ERROR -> invalid packet number on protection method p = %d\n", + pack); + return 1; + } + if (packspec < JPWL_MAX_NO_PACKSPECS) { + parameters->jpwl_pprot_tileno[packspec] = tile; + parameters->jpwl_pprot_packno[packspec] = pack; + parameters->jpwl_pprot[packspec++] = pprot; + } + + } else if (sscanf(token, "p%d:%d", &tile, &pack) == 2) { + /* default method from that tile and that packet on */ + if (!((pprot == 0) || (pprot == 1) || (pprot == 16) || (pprot == 32) || + ((pprot >= 37) && (pprot <= 128)))) { + fprintf(stderr, "ERROR -> invalid packet protection method p = %d\n", pprot); + return 1; + } + if (tile < 0) { + fprintf(stderr, + "ERROR -> invalid tile part number on protection method p = %d\n", tile); + return 1; + } + if (pack < 0) { + fprintf(stderr, "ERROR -> invalid packet number on protection method p = %d\n", + pack); + return 1; + } + if (packspec < JPWL_MAX_NO_PACKSPECS) { + parameters->jpwl_pprot_tileno[packspec] = tile; + parameters->jpwl_pprot_packno[packspec] = pack; + parameters->jpwl_pprot[packspec++] = pprot; + } + + } else if (sscanf(token, "p%d", &tile) == 1) { + /* default from a tile on */ + if (tile < 0) { + fprintf(stderr, + "ERROR -> invalid tile part number on protection method p = %d\n", tile); + return 1; + } + if (packspec < JPWL_MAX_NO_PACKSPECS) { + parameters->jpwl_pprot_tileno[packspec] = tile; + parameters->jpwl_pprot_packno[packspec] = 0; + parameters->jpwl_pprot[packspec++] = pprot; + } + + + } else if (!strcmp(token, "p")) { + /* all default */ + parameters->jpwl_pprot_tileno[0] = 0; + parameters->jpwl_pprot_packno[0] = 0; + parameters->jpwl_pprot[0] = pprot; + + } else { + fprintf(stderr, "ERROR -> invalid protection method selection = %s\n", token); + return 1; + }; + + } + + /* search sensitivity method */ + if (*token == 's') { + + static int tile = 0, tilespec = 0, lasttileno = 0; + + sens = 0; /* predefined: relative error */ + + if (sscanf(token, "s=%d", &sens) == 1) { + /* Main header, specified */ + if ((sens < -1) || (sens > 7)) { + fprintf(stderr, "ERROR -> invalid main header sensitivity method s = %d\n", + sens); + return 1; + } + parameters->jpwl_sens_MH = sens; + + } else if (sscanf(token, "s%d=%d", &tile, &sens) == 2) { + /* Tile part header, specified */ + if ((sens < -1) || (sens > 7)) { + fprintf(stderr, "ERROR -> invalid tile part header sensitivity method s = %d\n", + sens); + return 1; + } + if (tile < 0) { + fprintf(stderr, + "ERROR -> invalid tile part number on sensitivity method t = %d\n", tile); + return 1; + } + if (tilespec < JPWL_MAX_NO_TILESPECS) { + parameters->jpwl_sens_TPH_tileno[tilespec] = lasttileno = tile; + parameters->jpwl_sens_TPH[tilespec++] = sens; + } + + } else if (sscanf(token, "s%d", &tile) == 1) { + /* Tile part header, unspecified */ + if (tile < 0) { + fprintf(stderr, + "ERROR -> invalid tile part number on sensitivity method t = %d\n", tile); + return 1; + } + if (tilespec < JPWL_MAX_NO_TILESPECS) { + parameters->jpwl_sens_TPH_tileno[tilespec] = lasttileno = tile; + parameters->jpwl_sens_TPH[tilespec++] = hprot; + } + + } else if (!strcmp(token, "s")) { + /* Main header, unspecified */ + parameters->jpwl_sens_MH = sens; + + } else { + fprintf(stderr, "ERROR -> invalid sensitivity method selection = %s\n", token); + return 1; + }; + + parameters->jpwl_sens_size = 2; /* 2 bytes for default size */ + } + + /* search addressing size */ + if (*token == 'a') { + + + addr = 0; /* predefined: auto */ + + if (sscanf(token, "a=%d", &addr) == 1) { + /* Specified */ + if ((addr != 0) && (addr != 2) && (addr != 4)) { + fprintf(stderr, "ERROR -> invalid addressing size a = %d\n", addr); + return 1; + } + parameters->jpwl_sens_addr = addr; + + } else if (!strcmp(token, "a")) { + /* default */ + parameters->jpwl_sens_addr = addr; /* auto for default size */ + + } else { + fprintf(stderr, "ERROR -> invalid addressing selection = %s\n", token); + return 1; + }; + + } + + /* search sensitivity size */ + if (*token == 'z') { + + + size = 1; /* predefined: 1 byte */ + + if (sscanf(token, "z=%d", &size) == 1) { + /* Specified */ + if ((size != 0) && (size != 1) && (size != 2)) { + fprintf(stderr, "ERROR -> invalid sensitivity size z = %d\n", size); + return 1; + } + parameters->jpwl_sens_size = size; + + } else if (!strcmp(token, "a")) { + /* default */ + parameters->jpwl_sens_size = size; /* 1 for default size */ + + } else { + fprintf(stderr, "ERROR -> invalid size selection = %s\n", token); + return 1; + }; + + } + + /* search range method */ + if (*token == 'g') { + + + range = 0; /* predefined: 0 (packet) */ + + if (sscanf(token, "g=%d", &range) == 1) { + /* Specified */ + if ((range < 0) || (range > 3)) { + fprintf(stderr, "ERROR -> invalid sensitivity range method g = %d\n", range); + return 1; + } + parameters->jpwl_sens_range = range; + + } else if (!strcmp(token, "g")) { + /* default */ + parameters->jpwl_sens_range = range; + + } else { + fprintf(stderr, "ERROR -> invalid range selection = %s\n", token); + return 1; + }; + + } + + /* next token or bust */ + token = strtok(NULL, ","); + }; + + + /* some info */ + fprintf(stdout, "Info: JPWL capabilities enabled\n"); + parameters->jpwl_epc_on = OPJ_TRUE; + + } + break; +#endif /* USE_JPWL */ + /* <<UniPG */ + /* ------------------------------------------------------ */ + + case 'J': { /* jpip on */ + parameters->jpip_on = OPJ_TRUE; + } + break; + /* ------------------------------------------------------ */ + + + default: + fprintf(stderr, "[WARNING] An invalid option has been ignored\n"); + break; + } + } while (c != -1); + + if (img_fol->set_imgdir == 1) { + if (!(parameters->infile[0] == 0)) { + 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 <FORMAT> must be used !!\n"); + fprintf(stderr, "Only one format allowed! Valid formats are j2k and jp2!!\n"); + return 1; + } + if (!((parameters->outfile[0] == 0))) { + fprintf(stderr, "[ERROR] options -ImgDir and -o cannot be used together !!\n"); + fprintf(stderr, "Specify OutputFormat using -OutFor<FORMAT> !!\n"); + return 1; + } + } else { + if ((parameters->infile[0] == 0) || (parameters->outfile[0] == 0)) { + fprintf(stderr, "[ERROR] Required parameters are missing\n" + "Example: %s -i image.pgm -o image.j2k\n", argv[0]); + fprintf(stderr, " Help: %s -h\n", argv[0]); + return 1; + } + } + + if ((parameters->decod_format == RAW_DFMT && raw_cp->rawWidth == 0) + || (parameters->decod_format == RAWL_DFMT && raw_cp->rawWidth == 0)) { + fprintf(stderr, "[ERROR] invalid raw image parameters\n"); + fprintf(stderr, "Please use the Format option -F:\n"); + fprintf(stderr, + "-F rawWidth,rawHeight,rawComp,rawBitDepth,s/u (Signed/Unsigned)\n"); + fprintf(stderr, "Example: -i lena.raw -o lena.j2k -F 512,512,3,8,u\n"); + fprintf(stderr, "Aborting\n"); + return 1; + } + + if ((parameters->cp_disto_alloc || parameters->cp_fixed_alloc || + parameters->cp_fixed_quality) + && (!(parameters->cp_disto_alloc ^ parameters->cp_fixed_alloc ^ + parameters->cp_fixed_quality))) { + fprintf(stderr, "[ERROR] options -r -q and -f cannot be used together !!\n"); + return 1; + } /* mod fixed_quality */ + + + /* if no rate entered, lossless by default */ + /* Note: post v2.2.0, this is no longer necessary, but for released */ + /* versions at the time of writing, this is needed to avoid crashes */ + if (parameters->tcp_numlayers == 0) { + parameters->tcp_rates[0] = 0; + parameters->tcp_numlayers++; + parameters->cp_disto_alloc = 1; + } + + if ((parameters->cp_tx0 > parameters->image_offset_x0) || + (parameters->cp_ty0 > parameters->image_offset_y0)) { + fprintf(stderr, + "[ERROR] Tile offset dimension is unnappropriate --> TX0(%d)<=IMG_X0(%d) TYO(%d)<=IMG_Y0(%d) \n", + parameters->cp_tx0, parameters->image_offset_x0, parameters->cp_ty0, + parameters->image_offset_y0); + return 1; + } + + for (i = 0; i < parameters->numpocs; i++) { + if (parameters->POC[i].prg == -1) { + fprintf(stderr, + "Unrecognized progression order in option -P (POC n %d) [LRCP, RLCP, RPCL, PCRL, CPRL] !!\n", + i + 1); + } + } + + /* If subsampled image is provided, automatically disable MCT */ + if (((parameters->decod_format == RAW_DFMT) || + (parameters->decod_format == RAWL_DFMT)) + && (((raw_cp->rawComp > 1) && ((raw_cp->rawComps[1].dx > 1) || + (raw_cp->rawComps[1].dy > 1))) + || ((raw_cp->rawComp > 2) && ((raw_cp->rawComps[2].dx > 1) || + (raw_cp->rawComps[2].dy > 1))) + )) { + parameters->tcp_mct = 0; + } + + return 0; + +} + +/* -------------------------------------------------------------------------- */ + +/** +sample error debug callback expecting no client object +*/ +static void error_callback(const char *msg, void *client_data) +{ + (void)client_data; + fprintf(stdout, "[ERROR] %s", msg); +} +/** +sample warning debug callback expecting no client object +*/ +static void warning_callback(const char *msg, void *client_data) +{ + (void)client_data; + fprintf(stdout, "[WARNING] %s", msg); +} +/** +sample debug callback expecting no client object +*/ +static void info_callback(const char *msg, void *client_data) +{ + (void)client_data; + fprintf(stdout, "[INFO] %s", msg); +} + +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 ? ((OPJ_FLOAT64) 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 +} + + +/* -------------------------------------------------------------------------- */ +/** + * OPJ_COMPRESS MAIN + */ +/* -------------------------------------------------------------------------- */ +int main(int argc, char **argv) +{ + + opj_cparameters_t parameters; /* compression parameters */ + + opj_stream_t *l_stream = 00; + opj_codec_t* l_codec = 00; + opj_image_t *image = NULL; + raw_cparameters_t raw_cp; + OPJ_SIZE_T num_compressed_files = 0; + + char indexfilename[OPJ_PATH_LEN]; /* index file name */ + + unsigned int i, num_images, imageno; + img_fol_t img_fol; + dircnt_t *dirptr = NULL; + + OPJ_BOOL bSuccess; + OPJ_BOOL bUseTiles = OPJ_FALSE; /* OPJ_TRUE */ + OPJ_UINT32 l_nb_tiles = 4; + OPJ_FLOAT64 t = opj_clock(); + + /* set encoding parameters to default values */ + opj_set_default_encoder_parameters(¶meters); + + /* Initialize indexfilename and img_fol */ + *indexfilename = 0; + memset(&img_fol, 0, sizeof(img_fol_t)); + + /* raw_cp initialization */ + raw_cp.rawBitDepth = 0; + raw_cp.rawComp = 0; + raw_cp.rawComps = 0; + raw_cp.rawHeight = 0; + raw_cp.rawSigned = 0; + raw_cp.rawWidth = 0; + + /* parse input and get user encoding parameters */ + parameters.tcp_mct = (char) + 255; /* This will be set later according to the input image or the provided option */ + if (parse_cmdline_encoder(argc, argv, ¶meters, &img_fol, &raw_cp, + indexfilename, sizeof(indexfilename)) == 1) { + goto fails; + } + + /* Read directory if necessary */ + if (img_fol.set_imgdir == 1) { + num_images = get_num_images(img_fol.imgdirpath); + dirptr = (dircnt_t*)malloc(sizeof(dircnt_t)); + if (dirptr) { + dirptr->filename_buf = (char*)malloc(num_images * OPJ_PATH_LEN * sizeof( + char)); /* Stores at max 10 image file names*/ + dirptr->filename = (char**) malloc(num_images * sizeof(char*)); + if (!dirptr->filename_buf) { + return 0; + } + for (i = 0; i < num_images; i++) { + dirptr->filename[i] = dirptr->filename_buf + i * OPJ_PATH_LEN; + } + } + if (load_images(dirptr, img_fol.imgdirpath) == 1) { + return 0; + } + if (num_images == 0) { + fprintf(stdout, "Folder is empty\n"); + return 0; + } + } else { + num_images = 1; + } + /*Encoding image one by one*/ + for (imageno = 0; imageno < num_images; imageno++) { + image = NULL; + fprintf(stderr, "\n"); + + if (img_fol.set_imgdir == 1) { + if (get_next_file((int)imageno, dirptr, &img_fol, ¶meters)) { + fprintf(stderr, "skipping file...\n"); + continue; + } + } + + switch (parameters.decod_format) { + case PGX_DFMT: + break; + case PXM_DFMT: + break; + case BMP_DFMT: + break; + case TIF_DFMT: + break; + case RAW_DFMT: + case RAWL_DFMT: + break; + case TGA_DFMT: + break; + case PNG_DFMT: + break; + default: + fprintf(stderr, "skipping file...\n"); + continue; + } + + /* decode the source image */ + /* ----------------------- */ + + switch (parameters.decod_format) { + case PGX_DFMT: + image = pgxtoimage(parameters.infile, ¶meters); + if (!image) { + fprintf(stderr, "Unable to load pgx file\n"); + return 1; + } + break; + + case PXM_DFMT: + image = pnmtoimage(parameters.infile, ¶meters); + if (!image) { + fprintf(stderr, "Unable to load pnm file\n"); + return 1; + } + break; + + case BMP_DFMT: + image = bmptoimage(parameters.infile, ¶meters); + if (!image) { + fprintf(stderr, "Unable to load bmp file\n"); + return 1; + } + break; + +#ifdef OPJ_HAVE_LIBTIFF + case TIF_DFMT: + image = tiftoimage(parameters.infile, ¶meters); + if (!image) { + fprintf(stderr, "Unable to load tiff file\n"); + return 1; + } + break; +#endif /* OPJ_HAVE_LIBTIFF */ + + case RAW_DFMT: + image = rawtoimage(parameters.infile, ¶meters, &raw_cp); + if (!image) { + fprintf(stderr, "Unable to load raw file\n"); + return 1; + } + break; + + case RAWL_DFMT: + image = rawltoimage(parameters.infile, ¶meters, &raw_cp); + if (!image) { + fprintf(stderr, "Unable to load raw file\n"); + return 1; + } + break; + + case TGA_DFMT: + image = tgatoimage(parameters.infile, ¶meters); + if (!image) { + fprintf(stderr, "Unable to load tga file\n"); + return 1; + } + break; + +#ifdef OPJ_HAVE_LIBPNG + case PNG_DFMT: + image = pngtoimage(parameters.infile, ¶meters); + if (!image) { + fprintf(stderr, "Unable to load png file\n"); + return 1; + } + break; +#endif /* OPJ_HAVE_LIBPNG */ + } + + /* Can happen if input file is TIFF or PNG + * and OPJ_HAVE_LIBTIF or OPJ_HAVE_LIBPNG is undefined + */ + if (!image) { + fprintf(stderr, "Unable to load file: got no image\n"); + return 1; + } + + /* Decide if MCT should be used */ + if (parameters.tcp_mct == (char) + 255) { /* mct mode has not been set in commandline */ + parameters.tcp_mct = (image->numcomps >= 3) ? 1 : 0; + } else { /* mct mode has been set in commandline */ + if ((parameters.tcp_mct == 1) && (image->numcomps < 3)) { + fprintf(stderr, "RGB->YCC conversion cannot be used:\n"); + fprintf(stderr, "Input image has less than 3 components\n"); + return 1; + } + if ((parameters.tcp_mct == 2) && (!parameters.mct_data)) { + fprintf(stderr, "Custom MCT has been set but no array-based MCT\n"); + fprintf(stderr, "has been provided. Aborting.\n"); + return 1; + } + } + + /* encode the destination image */ + /* ---------------------------- */ + + switch (parameters.cod_format) { + case J2K_CFMT: { /* JPEG-2000 codestream */ + /* Get a decoder handle */ + l_codec = opj_create_compress(OPJ_CODEC_J2K); + break; + } + case JP2_CFMT: { /* JPEG 2000 compressed image data */ + /* Get a decoder handle */ + l_codec = opj_create_compress(OPJ_CODEC_JP2); + break; + } + default: + fprintf(stderr, "skipping file..\n"); + opj_stream_destroy(l_stream); + continue; + } + + /* catch events using our callbacks and give a local context */ + opj_set_info_handler(l_codec, info_callback, 00); + opj_set_warning_handler(l_codec, warning_callback, 00); + opj_set_error_handler(l_codec, error_callback, 00); + + if (bUseTiles) { + parameters.cp_tx0 = 0; + parameters.cp_ty0 = 0; + parameters.tile_size_on = OPJ_TRUE; + parameters.cp_tdx = 512; + parameters.cp_tdy = 512; + } + if (! opj_setup_encoder(l_codec, ¶meters, image)) { + fprintf(stderr, "failed to encode image: opj_setup_encoder\n"); + opj_destroy_codec(l_codec); + opj_image_destroy(image); + return 1; + } + + /* open a byte stream for writing and allocate memory for all tiles */ + l_stream = opj_stream_create_default_file_stream(parameters.outfile, OPJ_FALSE); + if (! l_stream) { + return 1; + } + + /* encode the image */ + bSuccess = opj_start_compress(l_codec, image, l_stream); + if (!bSuccess) { + fprintf(stderr, "failed to encode image: opj_start_compress\n"); + } + if (bSuccess && bUseTiles) { + OPJ_BYTE *l_data; + OPJ_UINT32 l_data_size = 512 * 512 * 3; + l_data = (OPJ_BYTE*) calloc(1, l_data_size); + if (l_data == NULL) { + goto fails; + } + for (i = 0; i < l_nb_tiles; ++i) { + if (! opj_write_tile(l_codec, i, l_data, l_data_size, l_stream)) { + fprintf(stderr, "ERROR -> test_tile_encoder: failed to write the tile %d!\n", + i); + opj_stream_destroy(l_stream); + opj_destroy_codec(l_codec); + opj_image_destroy(image); + return 1; + } + } + free(l_data); + } else { + bSuccess = bSuccess && opj_encode(l_codec, l_stream); + if (!bSuccess) { + fprintf(stderr, "failed to encode image: opj_encode\n"); + } + } + bSuccess = bSuccess && opj_end_compress(l_codec, l_stream); + if (!bSuccess) { + fprintf(stderr, "failed to encode image: opj_end_compress\n"); + } + + if (!bSuccess) { + opj_stream_destroy(l_stream); + opj_destroy_codec(l_codec); + opj_image_destroy(image); + fprintf(stderr, "failed to encode image\n"); + remove(parameters.outfile); + return 1; + } + + num_compressed_files++; + fprintf(stdout, "[INFO] Generated outfile %s\n", parameters.outfile); + /* close and free the byte stream */ + opj_stream_destroy(l_stream); + + /* free remaining compression structures */ + opj_destroy_codec(l_codec); + + /* free image data */ + opj_image_destroy(image); + + } + + /* free user parameters structure */ + if (parameters.cp_comment) { + free(parameters.cp_comment); + } + if (parameters.cp_matrice) { + free(parameters.cp_matrice); + } + if (raw_cp.rawComps) { + free(raw_cp.rawComps); + } + + t = opj_clock() - t; + if (num_compressed_files) { + fprintf(stdout, "encode time: %d ms \n", + (int)((t * 1000.0) / (OPJ_FLOAT64)num_compressed_files)); + } + + return 0; + +fails: + if (parameters.cp_comment) { + free(parameters.cp_comment); + } + if (parameters.cp_matrice) { + free(parameters.cp_matrice); + } + if (raw_cp.rawComps) { + free(raw_cp.rawComps); + } + if (img_fol.imgdirpath) { + free(img_fol.imgdirpath); + } + if (dirptr) { + if (dirptr->filename_buf) { + free(dirptr->filename_buf); + } + if (dirptr->filename) { + free(dirptr->filename); + } + free(dirptr); + } + return 1; +} diff --git a/openjpeg/src/bin/jp2/opj_decompress.c b/openjpeg/src/bin/jp2/opj_decompress.c new file mode 100644 index 000000000..8c5a125df --- /dev/null +++ b/openjpeg/src/bin/jp2/opj_decompress.c @@ -0,0 +1,1812 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * Copyright (c) 2003-2014, Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * Copyright (c) 2008, 2011-2012, Centre National d'Etudes Spatiales (CNES), FR + * Copyright (c) 2012, CS Systemes d'Information, France + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "opj_apps_config.h" + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <math.h> +#include <time.h> + +#ifdef _WIN32 +#include "windirent.h" +#else +#include <dirent.h> +#endif /* _WIN32 */ + +#ifdef _WIN32 +#include <windows.h> +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#else +#include <strings.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/times.h> +#endif /* _WIN32 */ + +#include "openjpeg.h" +#include "opj_getopt.h" +#include "convert.h" +#include "index.h" + +#ifdef OPJ_HAVE_LIBLCMS2 +#include <lcms2.h> +#endif +#ifdef OPJ_HAVE_LIBLCMS1 +#include <lcms.h> +#endif +#include "color.h" + +#include "format_defs.h" +#include "opj_string.h" + +typedef struct dircnt { + /** Buffer for holding images read from Directory*/ + char *filename_buf; + /** Pointer to the buffer*/ + char **filename; +} dircnt_t; + + +typedef struct img_folder { + /** The directory path of the folder containing input images*/ + char *imgdirpath; + /** Output format*/ + const char *out_format; + /** Enable option*/ + char set_imgdir; + /** Enable Cod Format for output*/ + char set_out_format; + +} 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; + /** number of threads */ + int num_threads; + /* Quiet */ + int quiet; + /** number of components to decode */ + OPJ_UINT32 numcomps; + /** indices of components to decode */ + OPJ_UINT32* comps_indices; +} 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_decompress_parameters *parameters); +static int infile_format(const char *fname); + +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, + "\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 <directory> \n" + " Image file Directory path \n" + " -OutFor <PBM|PGM|PPM|PNM|PAM|PGX|PNG|BMP|TIF|RAW|RAWL|TGA>\n" + " REQUIRED only if -ImgDir is used\n" + " Output format for decompressed images.\n"); + fprintf(stdout, " -i <compressed file>\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 <decompressed file>\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 <reduce factor>\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 <number of quality layers to decode>\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 <x0,y0,x1,y1>\n" + " OPTIONAL\n" + " Decoding area\n" + " By default all the image is decoded.\n" + " -t <tile_number>\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 <comp 0 precision>[C|S][,<comp 1 precision>[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, " -c first_comp_index[,second_comp_index][,...]\n" + " OPTIONAL\n" + " To limit the number of components to decoded.\n" + " Component indices are numbered starting at 0.\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"); + if (opj_has_thread_support()) { + fprintf(stdout, " -threads <num_threads>\n" + " Number of threads to use for decoding.\n"); + } + fprintf(stdout, " -quiet\n" + " Disable output from the library and other output.\n"); + /* UniPG>> */ +#ifdef USE_JPWL + fprintf(stdout, " -W <options>\n" + " Activates the JPWL correction capability, if the codestream complies.\n" + " Options can be a comma separated list of <param=val> 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 */ + /* <<UniPG */ + fprintf(stdout, "\n"); +} + +/* -------------------------------------------------------------------------- */ + +static OPJ_BOOL parse_precision(const char* option, + opj_decompress_parameters* parameters) +{ + const char* l_remaining = option; + OPJ_BOOL l_result = OPJ_TRUE; + + /* reset */ + if (parameters->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; + int num_images = 0; + + /*Reading the input images from given input directory*/ + + dir = opendir(imgdirpath); + if (!dir) { + fprintf(stderr, "Could not open Folder %s\n", imgdirpath); + return 0; + } + + while ((content = readdir(dir)) != NULL) { + if (strcmp(".", content->d_name) == 0 || strcmp("..", content->d_name) == 0) { + continue; + } + num_images++; + } + closedir(dir); + return num_images; +} + +/* -------------------------------------------------------------------------- */ +int load_images(dircnt_t *dirptr, char *imgdirpath) +{ + DIR *dir; + struct dirent* content; + int i = 0; + + /*Reading the input images from given input directory*/ + + dir = opendir(imgdirpath); + if (!dir) { + fprintf(stderr, "Could not open Folder %s\n", imgdirpath); + return 1; + } else { + fprintf(stderr, "Folder opened successfully\n"); + } + + while ((content = readdir(dir)) != NULL) { + if (strcmp(".", content->d_name) == 0 || strcmp("..", content->d_name) == 0) { + continue; + } + + strcpy(dirptr->filename[i], content->d_name); + i++; + } + closedir(dir); + return 0; +} + +/* -------------------------------------------------------------------------- */ +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 }; + const char * ext = strrchr(filename, '.'); + if (ext == NULL) { + return -1; + } + ext++; + if (*ext) { + for (i = 0; i < sizeof(format) / sizeof(*format); i++) { + if (strcasecmp(ext, extension[i]) == 0) { + return format[i]; + } + } + } + + 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_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); + 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; + } + if (opj_strcpy_s(parameters->infile, sizeof(parameters->infile), + infilename) != 0) { + return 1; + } + + /*Set output file*/ + strcpy(temp_ofname, strtok(image_filename, ".")); + while ((temp_p = strtok(NULL, ".")) != NULL) { + strcat(temp_ofname, temp1); + sprintf(temp1, ".%s", temp_p); + } + if (img_fol->set_out_format == 1) { + sprintf(outfilename, "%s/%s.%s", img_fol->imgdirpath, temp_ofname, + img_fol->out_format); + if (opj_strcpy_s(parameters->outfile, sizeof(parameters->outfile), + outfilename) != 0) { + return 1; + } + } + return 0; +} + +/* -------------------------------------------------------------------------- */ +#define JP2_RFC3745_MAGIC "\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a" +#define JP2_MAGIC "\x0d\x0a\x87\x0a" +/* position 45: "\xff\x52" */ +#define J2K_CODESTREAM_MAGIC "\xff\x4f\xff\x51" + +static int infile_format(const char *fname) +{ + FILE *reader; + const char *s, *magic_s; + int ext_format, magic_format; + unsigned char buf[12]; + OPJ_SIZE_T l_nb_read; + + reader = fopen(fname, "rb"); + + if (reader == NULL) { + return -2; + } + + memset(buf, 0, 12); + l_nb_read = fread(buf, 1, 12, reader); + fclose(reader); + if (l_nb_read != 12) { + return -1; + } + + + + ext_format = get_file_format(fname); + + if (ext_format == JPT_CFMT) { + return JPT_CFMT; + } + + if (memcmp(buf, JP2_RFC3745_MAGIC, 12) == 0 || memcmp(buf, JP2_MAGIC, 4) == 0) { + magic_format = JP2_CFMT; + magic_s = ".jp2"; + } else if (memcmp(buf, J2K_CODESTREAM_MAGIC, 4) == 0) { + magic_format = J2K_CFMT; + magic_s = ".j2k or .jpc or .j2c"; + } else { + return -1; + } + + if (magic_format == ext_format) { + return ext_format; + } + + s = fname + strlen(fname) - 4; + + fputs("\n===========================================\n", stderr); + fprintf(stderr, "The extension of this file is incorrect.\n" + "FOUND %s. SHOULD BE %s\n", s, magic_s); + fputs("===========================================\n", stderr); + + return magic_format; +} + +/* -------------------------------------------------------------------------- */ +/** + * Parse the command line + */ +/* -------------------------------------------------------------------------- */ +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'}, + {"force-rgb", NO_ARG, NULL, 1}, + {"upsample", NO_ARG, NULL, 1}, + {"split-pnm", NO_ARG, NULL, 1}, + {"threads", REQ_ARG, NULL, 'T'}, + {"quiet", NO_ARG, NULL, 1}, + }; + + const char optlist[] = "i:o:r:l:x:d:t:p:c:" + + /* UniPG>> */ +#ifdef USE_JPWL + "W:" +#endif /* USE_JPWL */ + /* <<UniPG */ + "h" ; + + long_option[2].flag = &(parameters->force_rgb); + long_option[3].flag = &(parameters->upsample); + long_option[4].flag = &(parameters->split_pnm); + long_option[6].flag = &(parameters->quiet); + 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; + parameters->decod_format = infile_format(infile); + switch (parameters->decod_format) { + case J2K_CFMT: + break; + case JP2_CFMT: + break; + case JPT_CFMT: + break; + case -2: + fprintf(stderr, + "!! infile cannot be read: %s !!\n\n", + infile); + return 1; + default: + fprintf(stderr, + "[ERROR] Unknown input file format: %s \n" + " Known file formats are *.j2k, *.jp2, *.jpc or *.jpt\n", + infile); + return 1; + } + if (opj_strcpy_s(parameters->infile, sizeof(parameters->infile), infile) != 0) { + fprintf(stderr, "[ERROR] Path is too long\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 'o': { /* output file */ + char *outfile = opj_optarg; + parameters->cod_format = get_file_format(outfile); + switch (parameters->cod_format) { + case PGX_DFMT: + break; + case PXM_DFMT: + break; + case BMP_DFMT: + break; + case TIF_DFMT: + break; + case RAW_DFMT: + break; + case RAWL_DFMT: + break; + case TGA_DFMT: + break; + case PNG_DFMT: + break; + default: + fprintf(stderr, + "Unknown output format image %s [only *.png, *.pnm, *.pgm, *.ppm, *.pgx, *.bmp, *.tif, *.raw or *.tga]!!\n", + outfile); + return 1; + } + if (opj_strcpy_s(parameters->outfile, sizeof(parameters->outfile), + outfile) != 0) { + fprintf(stderr, "[ERROR] Path is too long\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 'O': { /* output format */ + char outformat[50]; + char *of = opj_optarg; + sprintf(outformat, ".%s", of); + img_fol->set_out_format = 1; + parameters->cod_format = get_file_format(outformat); + switch (parameters->cod_format) { + case PGX_DFMT: + img_fol->out_format = "pgx"; + break; + case PXM_DFMT: + img_fol->out_format = "ppm"; + break; + case BMP_DFMT: + img_fol->out_format = "bmp"; + break; + case TIF_DFMT: + img_fol->out_format = "tif"; + break; + case RAW_DFMT: + img_fol->out_format = "raw"; + break; + case RAWL_DFMT: + img_fol->out_format = "rawl"; + break; + case TGA_DFMT: + img_fol->out_format = "raw"; + break; + case PNG_DFMT: + img_fol->out_format = "png"; + break; + default: + fprintf(stderr, + "Unknown output format image %s [only *.png, *.pnm, *.pgm, *.ppm, *.pgx, *.bmp, *.tif, *.raw or *.tga]!!\n", + outformat); + return 1; + break; + } + } + break; + + /* ----------------------------------------------------- */ + + + case 'r': { /* reduce option */ + sscanf(opj_optarg, "%u", &(parameters->core.cp_reduce)); + } + break; + + /* ----------------------------------------------------- */ + + + case 'l': { /* layering option */ + sscanf(opj_optarg, "%u", &(parameters->core.cp_layer)); + } + break; + + /* ----------------------------------------------------- */ + + case 'h': /* display an help description */ + decode_help_display(); + return 1; + + /* ----------------------------------------------------- */ + + case 'y': { /* Image Directory path */ + img_fol->imgdirpath = (char*)malloc(strlen(opj_optarg) + 1); + if (img_fol->imgdirpath == NULL) { + return 1; + } + strcpy(img_fol->imgdirpath, opj_optarg); + img_fol->set_imgdir = 1; + } + break; + + /* ----------------------------------------------------- */ + + case 'd': { /* Input decode ROI */ + 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'; + 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); + + free(ROI_values); + } + break; + + /* ----------------------------------------------------- */ + + case 't': { /* Input tile index */ + sscanf(opj_optarg, "%u", ¶meters->tile_index); + parameters->nb_tile_to_decode = 1; + } + break; + + /* ----------------------------------------------------- */ + + case 'x': { /* Creation of index file */ + 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; + + /* ----------------------------------------------------- */ + case 'c': { /* Componenets */ + const char* iter = opj_optarg; + while (1) { + parameters->numcomps ++; + parameters->comps_indices = (OPJ_UINT32*) realloc( + parameters->comps_indices, + parameters->numcomps * sizeof(OPJ_UINT32)); + parameters->comps_indices[parameters->numcomps - 1] = + (OPJ_UINT32) atoi(iter); + iter = strchr(iter, ','); + if (iter == NULL) { + break; + } + iter ++; + } + } + break; + /* ----------------------------------------------------- */ + + /* UniPG>> */ +#ifdef USE_JPWL + + case 'W': { /* activate JPWL correction */ + char *token = NULL; + + token = strtok(opj_optarg, ","); + while (token != NULL) { + + /* search expected number of components */ + if (*token == 'c') { + + static int compno; + + compno = JPWL_EXPECTED_COMPONENTS; /* predefined no. of components */ + + if (sscanf(token, "c=%d", &compno) == 1) { + /* Specified */ + if ((compno < 1) || (compno > 256)) { + fprintf(stderr, "ERROR -> invalid number of components c = %d\n", compno); + return 1; + } + parameters->jpwl_exp_comps = compno; + + } else if (!strcmp(token, "c")) { + /* default */ + parameters->jpwl_exp_comps = compno; /* auto for default size */ + + } else { + fprintf(stderr, "ERROR -> invalid components specified = %s\n", token); + return 1; + }; + } + + /* search maximum number of tiles */ + if (*token == 't') { + + static int tileno; + + tileno = JPWL_MAXIMUM_TILES; /* maximum no. of tiles */ + + if (sscanf(token, "t=%d", &tileno) == 1) { + /* Specified */ + if ((tileno < 1) || (tileno > JPWL_MAXIMUM_TILES)) { + fprintf(stderr, "ERROR -> invalid number of tiles t = %d\n", tileno); + return 1; + } + parameters->jpwl_max_tiles = tileno; + + } else if (!strcmp(token, "t")) { + /* default */ + parameters->jpwl_max_tiles = tileno; /* auto for default size */ + + } else { + fprintf(stderr, "ERROR -> invalid tiles specified = %s\n", token); + return 1; + }; + } + + /* next token or bust */ + token = strtok(NULL, ","); + }; + parameters->jpwl_correct = OPJ_TRUE; + if (!(parameter->quiet)) { + fprintf(stdout, "JPWL correction capability activated\n"); + fprintf(stdout, "- expecting %d components\n", parameters->jpwl_exp_comps); + } + } + break; +#endif /* USE_JPWL */ + /* <<UniPG */ + + /* ----------------------------------------------------- */ + case 'T': { /* Number of threads */ + if (strcmp(opj_optarg, "ALL_CPUS") == 0) { + parameters->num_threads = opj_get_num_cpus(); + if (parameters->num_threads == 1) { + parameters->num_threads = 0; + } + } else { + sscanf(opj_optarg, "%d", ¶meters->num_threads); + } + } + break; + + /* ----------------------------------------------------- */ + + default: + fprintf(stderr, "[WARNING] An invalid option has been ignored.\n"); + break; + } + } while (c != -1); + + /* 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"); + return 1; + } + if (img_fol->set_out_format == 0) { + fprintf(stderr, + "[ERROR] When -ImgDir is used, -OutFor <FORMAT> 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"); + return 1; + } + } else { + if ((parameters->infile[0] == 0) || (parameters->outfile[0] == 0)) { + fprintf(stderr, "[ERROR] Required parameters are missing\n" + "Example: %s -i image.j2k -o image.pgm\n", argv[0]); + fprintf(stderr, " Help: %s -h\n", argv[0]); + return 1; + } + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/** + * Parse decoding area input values + * separator = "," + */ +/* -------------------------------------------------------------------------- */ +int parse_DA_values(char* inArg, unsigned int *DA_x0, unsigned int *DA_y0, + unsigned int *DA_x1, unsigned int *DA_y1) +{ + int it = 0; + int values[4]; + char delims[] = ","; + char *result = NULL; + result = strtok(inArg, delims); + + while ((result != NULL) && (it < 4)) { + values[it] = atoi(result); + result = strtok(NULL, delims); + it++; + } + + if (it != 4) { + return EXIT_FAILURE; + } else { + *DA_x0 = (OPJ_UINT32)values[0]; + *DA_y0 = (OPJ_UINT32)values[1]; + *DA_x1 = (OPJ_UINT32)values[2]; + *DA_y1 = (OPJ_UINT32)values[3]; + return EXIT_SUCCESS; + } +} + +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 ? ((OPJ_FLOAT64)t.QuadPart / (OPJ_FLOAT64)freq.QuadPart) : + 0; +#elif defined(__linux) + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + return ((OPJ_FLOAT64)ts.tv_sec + (OPJ_FLOAT64)ts.tv_nsec * 1e-9); +#else + /* Unix : use resource usage */ + /* FIXME: this counts the total CPU time, instead of the user perceived time */ + 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 +} + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +static void error_callback(const char *msg, void *client_data) +{ + (void)client_data; + fprintf(stdout, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +static void warning_callback(const char *msg, void *client_data) +{ + (void)client_data; + fprintf(stdout, "[WARNING] %s", msg); +} +/** +sample debug callback expecting no client object +*/ +static void info_callback(const char *msg, void *client_data) +{ + (void)client_data; + fprintf(stdout, "[INFO] %s", msg); +} +/** +sample quiet callback expecting no client object +*/ +static void quiet_callback(const char *msg, void *client_data) +{ + (void)msg; + (void)client_data; +} + +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; + } + + free(parameters->comps_indices); + parameters->comps_indices = 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 + */ +/* -------------------------------------------------------------------------- */ +int main(int argc, char **argv) +{ + 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; + + 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; + OPJ_UINT32 cp_reduce; + + /* set decoding parameters to default values */ + 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) == 1) { + failed = 1; + goto fin; + } + + cp_reduce = parameters.core.cp_reduce; + if (getenv("USE_OPJ_SET_DECODED_RESOLUTION_FACTOR") != NULL) { + /* For debugging/testing purposes, do not set the cp_reduce member */ + /* if USE_OPJ_SET_DECODED_RESOLUTION_FACTOR is defined, but used */ + /* the opj_set_decoded_resolution_factor() API instead */ + parameters.core.cp_reduce = 0; + } + + + /* Initialize reading of directory */ + if (img_fol.set_imgdir == 1) { + int it_image; + num_images = get_num_images(img_fol.imgdirpath); + + dirptr = (dircnt_t*)malloc(sizeof(dircnt_t)); + if (!dirptr) { + destroy_parameters(¶meters); + return EXIT_FAILURE; + } + dirptr->filename_buf = (char*)malloc((size_t)num_images * OPJ_PATH_LEN * sizeof( + char)); /* Stores at max 10 image file names*/ + if (!dirptr->filename_buf) { + failed = 1; + goto fin; + } + + dirptr->filename = (char**) malloc((size_t)num_images * sizeof(char*)); + + if (!dirptr->filename) { + failed = 1; + goto fin; + } + for (it_image = 0; it_image < num_images; it_image++) { + dirptr->filename[it_image] = dirptr->filename_buf + it_image * OPJ_PATH_LEN; + } + + if (load_images(dirptr, img_fol.imgdirpath) == 1) { + failed = 1; + goto fin; + } + if (num_images == 0) { + fprintf(stderr, "Folder is empty\n"); + failed = 1; + goto fin; + } + } else { + num_images = 1; + } + + /*Decoding image one by one*/ + for (imageno = 0; imageno < num_images ; imageno++) { + + if (!parameters.quiet) { + fprintf(stderr, "\n"); + } + + if (img_fol.set_imgdir == 1) { + if (get_next_file(imageno, dirptr, &img_fol, ¶meters)) { + fprintf(stderr, "skipping file...\n"); + destroy_parameters(¶meters); + continue; + } + } + + /* read the input file and put it in memory */ + /* ---------------------------------------- */ + + l_stream = opj_stream_create_default_file_stream(parameters.infile, 1); + if (!l_stream) { + fprintf(stderr, "ERROR -> failed to create the stream from the file %s\n", + parameters.infile); + failed = 1; + goto fin; + } + + /* decode the JPEG2000 stream */ + /* ---------------------- */ + + switch (parameters.decod_format) { + case J2K_CFMT: { /* JPEG-2000 codestream */ + /* Get a decoder handle */ + l_codec = opj_create_decompress(OPJ_CODEC_J2K); + break; + } + case JP2_CFMT: { /* JPEG 2000 compressed image data */ + /* Get a decoder handle */ + l_codec = opj_create_decompress(OPJ_CODEC_JP2); + break; + } + case JPT_CFMT: { /* JPEG 2000, JPIP */ + /* Get a decoder handle */ + l_codec = opj_create_decompress(OPJ_CODEC_JPT); + break; + } + default: + fprintf(stderr, "skipping file..\n"); + destroy_parameters(¶meters); + opj_stream_destroy(l_stream); + continue; + } + + if (parameters.quiet) { + /* Set all callbacks to quiet */ + opj_set_info_handler(l_codec, quiet_callback, 00); + opj_set_warning_handler(l_codec, quiet_callback, 00); + opj_set_error_handler(l_codec, quiet_callback, 00); + } else { + /* catch events using our callbacks and give a local context */ + opj_set_info_handler(l_codec, info_callback, 00); + 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, &(parameters.core))) { + fprintf(stderr, "ERROR -> opj_decompress: failed to setup the decoder\n"); + opj_stream_destroy(l_stream); + opj_destroy_codec(l_codec); + failed = 1; + goto fin; + } + + if (parameters.num_threads >= 1 && + !opj_codec_set_threads(l_codec, parameters.num_threads)) { + fprintf(stderr, "ERROR -> opj_decompress: failed to set number of threads\n"); + opj_stream_destroy(l_stream); + opj_destroy_codec(l_codec); + failed = 1; + goto fin; + } + + /* 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(l_stream); + opj_destroy_codec(l_codec); + opj_image_destroy(image); + failed = 1; + goto fin; + } + + if (parameters.numcomps) { + if (! opj_set_decoded_components(l_codec, + parameters.numcomps, + parameters.comps_indices, + OPJ_FALSE)) { + fprintf(stderr, + "ERROR -> opj_decompress: failed to set the component indices!\n"); + opj_destroy_codec(l_codec); + opj_stream_destroy(l_stream); + opj_image_destroy(image); + failed = 1; + goto fin; + } + } + + if (getenv("USE_OPJ_SET_DECODED_RESOLUTION_FACTOR") != NULL) { + /* For debugging/testing purposes, and also an illustration on how to */ + /* use the alternative API opj_set_decoded_resolution_factor() instead */ + /* of setting parameters.cp_reduce */ + if (! opj_set_decoded_resolution_factor(l_codec, cp_reduce)) { + fprintf(stderr, + "ERROR -> opj_decompress: failed to set the resolution factor tile!\n"); + opj_destroy_codec(l_codec); + opj_stream_destroy(l_stream); + opj_image_destroy(image); + failed = 1; + goto fin; + } + } + + if (!parameters.nb_tile_to_decode) { + if (getenv("SKIP_OPJ_SET_DECODE_AREA") != NULL && + parameters.DA_x0 == 0 && + parameters.DA_y0 == 0 && + parameters.DA_x1 == 0 && + parameters.DA_y1 == 0) { + /* For debugging/testing purposes, */ + /* do nothing if SKIP_OPJ_SET_DECODE_AREA env variable */ + /* is defined and no decoded area has been set */ + } + /* Optional if you want decode the entire image */ + else 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(l_stream); + opj_destroy_codec(l_codec); + opj_image_destroy(image); + failed = 1; + goto fin; + } + + /* 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"); + opj_destroy_codec(l_codec); + opj_stream_destroy(l_stream); + opj_image_destroy(image); + failed = 1; + goto fin; + } + } else { + if (!(parameters.DA_x0 == 0 && + parameters.DA_y0 == 0 && + parameters.DA_x1 == 0 && + parameters.DA_y1 == 0)) { + if (!(parameters.quiet)) { + fprintf(stderr, "WARNING: -d option ignored when used together with -t\n"); + } + } + + if (!opj_get_decoded_tile(l_codec, l_stream, image, parameters.tile_index)) { + fprintf(stderr, "ERROR -> opj_decompress: failed to decode tile!\n"); + opj_destroy_codec(l_codec); + opj_stream_destroy(l_stream); + opj_image_destroy(image); + failed = 1; + goto fin; + } + if (!(parameters.quiet)) { + fprintf(stdout, "tile %d is decoded!\n\n", parameters.tile_index); + } + } + + /* FIXME? Shouldn't that situation be considered as an error of */ + /* opj_decode() / opj_get_decoded_tile() ? */ + if (image->comps[0].data == NULL) { + fprintf(stderr, "ERROR -> opj_decompress: no image data!\n"); + opj_destroy_codec(l_codec); + opj_stream_destroy(l_stream); + opj_image_destroy(image); + failed = 1; + goto fin; + } + + tCumulative += opj_clock() - t; + numDecompressedImages++; + + /* Close the byte stream */ + opj_stream_destroy(l_stream); + + if (image->color_space != OPJ_CLRSPC_SYCC + && image->numcomps == 3 && image->comps[0].dx == image->comps[0].dy + && image->comps[1].dx != 1) { + image->color_space = OPJ_CLRSPC_SYCC; + } 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) + 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"); + opj_destroy_codec(l_codec); + failed = 1; + goto fin; + } + } + + /* 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"); + opj_destroy_codec(l_codec); + failed = 1; + goto fin; + } + } + + /* create output image */ + /* ------------------- */ + switch (parameters.cod_format) { + case PXM_DFMT: /* PNM PGM PPM */ + if (imagetopnm(image, parameters.outfile, parameters.split_pnm)) { + fprintf(stderr, "[ERROR] Outfile %s not generated\n", parameters.outfile); + failed = 1; + } else if (!(parameters.quiet)) { + fprintf(stdout, "[INFO] Generated Outfile %s\n", parameters.outfile); + } + break; + + case PGX_DFMT: /* PGX */ + if (imagetopgx(image, parameters.outfile)) { + fprintf(stderr, "[ERROR] Outfile %s not generated\n", parameters.outfile); + failed = 1; + } else if (!(parameters.quiet)) { + fprintf(stdout, "[INFO] Generated Outfile %s\n", parameters.outfile); + } + break; + + case BMP_DFMT: /* BMP */ + if (imagetobmp(image, parameters.outfile)) { + fprintf(stderr, "[ERROR] Outfile %s not generated\n", parameters.outfile); + failed = 1; + } else if (!(parameters.quiet)) { + fprintf(stdout, "[INFO] Generated Outfile %s\n", parameters.outfile); + } + break; +#ifdef OPJ_HAVE_LIBTIFF + case TIF_DFMT: /* TIFF */ + if (imagetotif(image, parameters.outfile)) { + fprintf(stderr, "[ERROR] Outfile %s not generated\n", parameters.outfile); + failed = 1; + } else if (!(parameters.quiet)) { + fprintf(stdout, "[INFO] Generated Outfile %s\n", parameters.outfile); + } + break; +#endif /* OPJ_HAVE_LIBTIFF */ + case RAW_DFMT: /* RAW */ + if (imagetoraw(image, parameters.outfile)) { + fprintf(stderr, "[ERROR] Error generating raw file. Outfile %s not generated\n", + parameters.outfile); + failed = 1; + } else if (!(parameters.quiet)) { + fprintf(stdout, "[INFO] Generated Outfile %s\n", parameters.outfile); + } + break; + + case RAWL_DFMT: /* RAWL */ + if (imagetorawl(image, parameters.outfile)) { + fprintf(stderr, + "[ERROR] Error generating rawl file. Outfile %s not generated\n", + parameters.outfile); + failed = 1; + } else if (!(parameters.quiet)) { + fprintf(stdout, "[INFO] Generated Outfile %s\n", parameters.outfile); + } + break; + + case TGA_DFMT: /* TGA */ + if (imagetotga(image, parameters.outfile)) { + fprintf(stderr, "[ERROR] Error generating tga file. Outfile %s not generated\n", + parameters.outfile); + failed = 1; + } else if (!(parameters.quiet)) { + fprintf(stdout, "[INFO] Generated Outfile %s\n", parameters.outfile); + } + break; +#ifdef OPJ_HAVE_LIBPNG + case PNG_DFMT: /* PNG */ + if (imagetopng(image, parameters.outfile)) { + fprintf(stderr, "[ERROR] Error generating png file. Outfile %s not generated\n", + parameters.outfile); + failed = 1; + } else if (!(parameters.quiet)) { + fprintf(stdout, "[INFO] Generated Outfile %s\n", parameters.outfile); + } + break; +#endif /* OPJ_HAVE_LIBPNG */ + /* Can happen if output file is TIFF or PNG + * and OPJ_HAVE_LIBTIF or OPJ_HAVE_LIBPNG is undefined + */ + default: + fprintf(stderr, "[ERROR] Outfile %s not generated\n", parameters.outfile); + failed = 1; + } + + /* free remaining structures */ + if (l_codec) { + opj_destroy_codec(l_codec); + } + + + /* free image data structure */ + opj_image_destroy(image); + + /* destroy the codestream index */ + opj_destroy_cstr_index(&cstr_index); + + if (failed) { + (void)remove(parameters.outfile); /* ignore return value */ + } + } +fin: + destroy_parameters(¶meters); + if (failed && img_fol.imgdirpath) { + free(img_fol.imgdirpath); + } + if (dirptr) { + if (dirptr->filename) { + free(dirptr->filename); + } + if (dirptr->filename_buf) { + free(dirptr->filename_buf); + } + free(dirptr); + } + if (numDecompressedImages && !failed && !(parameters.quiet)) { + fprintf(stdout, "decode time: %d ms\n", + (int)((tCumulative * 1000.0) / (OPJ_FLOAT64)numDecompressedImages)); + } + return failed ? EXIT_FAILURE : EXIT_SUCCESS; +} +/*end main()*/ diff --git a/openjpeg/src/bin/jp2/opj_dump.c b/openjpeg/src/bin/jp2/opj_dump.c new file mode 100644 index 000000000..6e15fee48 --- /dev/null +++ b/openjpeg/src/bin/jp2/opj_dump.c @@ -0,0 +1,642 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2010, Mathieu Malaterre, GDCM + * Copyright (c) 2011-2012, Centre National d'Etudes Spatiales (CNES), France + * Copyright (c) 2012, CS Systemes d'Information, France + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "opj_config.h" + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <math.h> + +#ifdef _WIN32 +#include "windirent.h" +#else +#include <dirent.h> +#endif /* _WIN32 */ + +#ifdef _WIN32 +#include <windows.h> +#else +#include <strings.h> +#define _stricmp strcasecmp +#define _strnicmp strncasecmp +#endif /* _WIN32 */ + +#include "openjpeg.h" +#include "opj_getopt.h" +#include "convert.h" +#include "index.h" + +#include "format_defs.h" +#include "opj_string.h" + +typedef struct dircnt { + /** Buffer for holding images read from Directory*/ + char *filename_buf; + /** Pointer to the buffer*/ + char **filename; +} dircnt_t; + + +typedef struct img_folder { + /** The directory path of the folder containing input images*/ + char *imgdirpath; + /** Output format*/ + const char *out_format; + /** Enable option*/ + char set_imgdir; + /** Enable Cod Format for output*/ + char set_out_format; + + int flag; +} img_fol_t; + +/* -------------------------------------------------------------------------- */ +/* Declarations */ +static int get_num_images(char *imgdirpath); +static int load_images(dircnt_t *dirptr, char *imgdirpath); +static int get_file_format(const char *filename); +static char get_next_file(int imageno, dircnt_t *dirptr, img_fol_t *img_fol, + opj_dparameters_t *parameters); +static int infile_format(const char *fname); + +static int parse_cmdline_decoder(int argc, char **argv, + opj_dparameters_t *parameters, img_fol_t *img_fol); + +/* -------------------------------------------------------------------------- */ +static void decode_help_display(void) +{ + fprintf(stdout, "\nThis is the opj_dump utility from the OpenJPEG project.\n" + "It dumps JPEG 2000 codestream info to stdout or a given file.\n" + "It has been compiled against openjp2 library v%s.\n\n", opj_version()); + + fprintf(stdout, "Parameters:\n"); + fprintf(stdout, "-----------\n"); + fprintf(stdout, "\n"); + fprintf(stdout, " -ImgDir <directory>\n"); + fprintf(stdout, " Image file Directory path \n"); + fprintf(stdout, " -i <compressed file>\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 <output file>\n"); + fprintf(stdout, " OPTIONAL\n"); + fprintf(stdout, " Output file where file info will be dump.\n"); + fprintf(stdout, " By default it will be in the stdout.\n"); + fprintf(stdout, " -v "); /* FIXME WIP_MSD */ + fprintf(stdout, " OPTIONAL\n"); + fprintf(stdout, " Enable informative messages\n"); + fprintf(stdout, " By default verbose mode is off.\n"); + fprintf(stdout, "\n"); +} + +/* -------------------------------------------------------------------------- */ +static int get_num_images(char *imgdirpath) +{ + DIR *dir; + struct dirent* content; + int num_images = 0; + + /*Reading the input images from given input directory*/ + + dir = opendir(imgdirpath); + if (!dir) { + fprintf(stderr, "Could not open Folder %s\n", imgdirpath); + return 0; + } + + while ((content = readdir(dir)) != NULL) { + if (strcmp(".", content->d_name) == 0 || strcmp("..", content->d_name) == 0) { + continue; + } + num_images++; + } + closedir(dir); + return num_images; +} + +/* -------------------------------------------------------------------------- */ +static int load_images(dircnt_t *dirptr, char *imgdirpath) +{ + DIR *dir; + struct dirent* content; + int i = 0; + + /*Reading the input images from given input directory*/ + + dir = opendir(imgdirpath); + if (!dir) { + fprintf(stderr, "Could not open Folder %s\n", imgdirpath); + return 1; + } else { + fprintf(stderr, "Folder opened successfully\n"); + } + + while ((content = readdir(dir)) != NULL) { + if (strcmp(".", content->d_name) == 0 || strcmp("..", content->d_name) == 0) { + continue; + } + + strcpy(dirptr->filename[i], content->d_name); + i++; + } + closedir(dir); + return 0; +} + +/* -------------------------------------------------------------------------- */ +static int get_file_format(const char *filename) +{ + unsigned int i; + static const char *extension[] = {"pgx", "pnm", "pgm", "ppm", "bmp", "tif", "raw", "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, TGA_DFMT, PNG_DFMT, J2K_CFMT, JP2_CFMT, JPT_CFMT, J2K_CFMT, J2K_CFMT }; + const char *ext = strrchr(filename, '.'); + if (ext == NULL) { + return -1; + } + ext++; + if (ext) { + for (i = 0; i < sizeof(format) / sizeof(*format); i++) { + if (_strnicmp(ext, extension[i], 3) == 0) { + return format[i]; + } + } + } + + return -1; +} + +/* -------------------------------------------------------------------------- */ +static char get_next_file(int imageno, dircnt_t *dirptr, img_fol_t *img_fol, + opj_dparameters_t *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 = get_file_format(image_filename); + if (parameters->decod_format == -1) { + return 1; + } + sprintf(infilename, "%s/%s", img_fol->imgdirpath, image_filename); + if (opj_strcpy_s(parameters->infile, sizeof(parameters->infile), + infilename) != 0) { + return 1; + } + + /*Set output file*/ + strcpy(temp_ofname, strtok(image_filename, ".")); + while ((temp_p = strtok(NULL, ".")) != NULL) { + strcat(temp_ofname, temp1); + sprintf(temp1, ".%s", temp_p); + } + if (img_fol->set_out_format == 1) { + sprintf(outfilename, "%s/%s.%s", img_fol->imgdirpath, temp_ofname, + img_fol->out_format); + if (opj_strcpy_s(parameters->outfile, sizeof(parameters->outfile), + outfilename) != 0) { + return 1; + } + } + return 0; +} + +/* -------------------------------------------------------------------------- */ +#define JP2_RFC3745_MAGIC "\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a" +#define JP2_MAGIC "\x0d\x0a\x87\x0a" +/* position 45: "\xff\x52" */ +#define J2K_CODESTREAM_MAGIC "\xff\x4f\xff\x51" + +static int infile_format(const char *fname) +{ + FILE *reader; + const char *s, *magic_s; + int ext_format, magic_format; + unsigned char buf[12]; + size_t l_nb_read; + + reader = fopen(fname, "rb"); + + if (reader == NULL) { + return -1; + } + + memset(buf, 0, 12); + l_nb_read = fread(buf, 1, 12, reader); + fclose(reader); + if (l_nb_read != 12) { + return -1; + } + + + + ext_format = get_file_format(fname); + + if (ext_format == JPT_CFMT) { + return JPT_CFMT; + } + + if (memcmp(buf, JP2_RFC3745_MAGIC, 12) == 0 || memcmp(buf, JP2_MAGIC, 4) == 0) { + magic_format = JP2_CFMT; + magic_s = ".jp2"; + } else if (memcmp(buf, J2K_CODESTREAM_MAGIC, 4) == 0) { + magic_format = J2K_CFMT; + magic_s = ".j2k or .jpc or .j2c"; + } else { + return -1; + } + + if (magic_format == ext_format) { + return ext_format; + } + + s = fname + strlen(fname) - 4; + + fputs("\n===========================================\n", stderr); + fprintf(stderr, "The extension of this file is incorrect.\n" + "FOUND %s. SHOULD BE %s\n", s, magic_s); + fputs("===========================================\n", stderr); + + return magic_format; +} +/* -------------------------------------------------------------------------- */ +/** + * Parse the command line + */ +/* -------------------------------------------------------------------------- */ +static int parse_cmdline_decoder(int argc, char **argv, + opj_dparameters_t *parameters, img_fol_t *img_fol) +{ + int totlen, c; + opj_option_t long_option[] = { + {"ImgDir", REQ_ARG, NULL, 'y'} + }; + const char optlist[] = "i:o:f:hv"; + + totlen = sizeof(long_option); + img_fol->set_out_format = 0; + do { + c = opj_getopt_long(argc, argv, optlist, long_option, totlen); + if (c == -1) { + break; + } + switch (c) { + case 'i': { /* input file */ + char *infile = opj_optarg; + parameters->decod_format = infile_format(infile); + switch (parameters->decod_format) { + case J2K_CFMT: + break; + case JP2_CFMT: + break; + case JPT_CFMT: + break; + default: + fprintf(stderr, + "[ERROR] Unknown input file format: %s \n" + " Known file formats are *.j2k, *.jp2, *.jpc or *.jpt\n", + infile); + return 1; + } + if (opj_strcpy_s(parameters->infile, sizeof(parameters->infile), infile) != 0) { + fprintf(stderr, "[ERROR] Path is too long\n"); + return 1; + } + } + break; + + /* ------------------------------------------------------ */ + + case 'o': { /* output file */ + if (opj_strcpy_s(parameters->outfile, sizeof(parameters->outfile), + opj_optarg) != 0) { + fprintf(stderr, "[ERROR] Path is too long\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + case 'f': /* flag */ + img_fol->flag = atoi(opj_optarg); + break; + /* ----------------------------------------------------- */ + + case 'h': /* display an help description */ + decode_help_display(); + return 1; + + /* ------------------------------------------------------ */ + + case 'y': { /* Image Directory path */ + img_fol->imgdirpath = (char*)malloc(strlen(opj_optarg) + 1); + if (img_fol->imgdirpath == NULL) { + return 1; + } + strcpy(img_fol->imgdirpath, opj_optarg); + img_fol->set_imgdir = 1; + } + break; + + /* ----------------------------------------------------- */ + + case 'v': { /* Verbose mode */ + parameters->m_verbose = 1; + } + break; + + /* ----------------------------------------------------- */ + default: + fprintf(stderr, "[WARNING] An invalid option has been ignored.\n"); + break; + } + } while (c != -1); + + /* 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"); + return 1; + } + if (img_fol->set_out_format == 0) { + fprintf(stderr, + "[ERROR] When -ImgDir is used, -OutFor <FORMAT> 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"); + return 1; + } + } else { + if (parameters->infile[0] == 0) { + fprintf(stderr, "[ERROR] Required parameter is missing\n"); + fprintf(stderr, "Example: %s -i image.j2k\n", argv[0]); + fprintf(stderr, " Help: %s -h\n", argv[0]); + return 1; + } + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +/** +sample error debug callback expecting no client object +*/ +static void error_callback(const char *msg, void *client_data) +{ + (void)client_data; + fprintf(stdout, "[ERROR] %s", msg); +} +/** +sample warning debug callback expecting no client object +*/ +static void warning_callback(const char *msg, void *client_data) +{ + (void)client_data; + fprintf(stdout, "[WARNING] %s", msg); +} +/** +sample debug callback expecting no client object +*/ +static void info_callback(const char *msg, void *client_data) +{ + (void)client_data; + fprintf(stdout, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ +/** + * OPJ_DUMP MAIN + */ +/* -------------------------------------------------------------------------- */ +int main(int argc, char *argv[]) +{ + FILE *fout = NULL; + + opj_dparameters_t parameters; /* Decompression parameters */ + opj_image_t* image = NULL; /* Image structure */ + opj_codec_t* l_codec = NULL; /* Handle to a decompressor */ + opj_stream_t *l_stream = NULL; /* Stream */ + opj_codestream_info_v2_t* cstr_info = NULL; + opj_codestream_index_t* cstr_index = NULL; + + OPJ_INT32 num_images, imageno; + img_fol_t img_fol; + dircnt_t *dirptr = NULL; + + /* Set decoding parameters to default values */ + opj_set_default_decoder_parameters(¶meters); + + /* Initialize img_fol */ + memset(&img_fol, 0, sizeof(img_fol_t)); + img_fol.flag = OPJ_IMG_INFO | OPJ_J2K_MH_INFO | OPJ_J2K_MH_IND; + + /* Parse input and get user encoding parameters */ + if (parse_cmdline_decoder(argc, argv, ¶meters, &img_fol) == 1) { + if (img_fol.imgdirpath) { + free(img_fol.imgdirpath); + } + + return EXIT_FAILURE; + } + + /* Initialize reading of directory */ + if (img_fol.set_imgdir == 1) { + int it_image; + num_images = get_num_images(img_fol.imgdirpath); + + dirptr = (dircnt_t*)malloc(sizeof(dircnt_t)); + if (!dirptr) { + return EXIT_FAILURE; + } + dirptr->filename_buf = (char*)malloc((size_t)num_images * OPJ_PATH_LEN * sizeof( + char)); /* Stores at max 10 image file names*/ + if (!dirptr->filename_buf) { + free(dirptr); + return EXIT_FAILURE; + } + dirptr->filename = (char**) malloc((size_t)num_images * sizeof(char*)); + + if (!dirptr->filename) { + goto fails; + } + + for (it_image = 0; it_image < num_images; it_image++) { + dirptr->filename[it_image] = dirptr->filename_buf + it_image * OPJ_PATH_LEN; + } + + if (load_images(dirptr, img_fol.imgdirpath) == 1) { + goto fails; + } + + if (num_images == 0) { + fprintf(stdout, "Folder is empty\n"); + goto fails; + } + } else { + num_images = 1; + } + + /* Try to open for writing the output file if necessary */ + if (parameters.outfile[0] != 0) { + fout = fopen(parameters.outfile, "w"); + if (!fout) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", parameters.outfile); + goto fails; + } + } else { + fout = stdout; + } + + /* Read the header of each image one by one */ + for (imageno = 0; imageno < num_images ; imageno++) { + + fprintf(stderr, "\n"); + + if (img_fol.set_imgdir == 1) { + if (get_next_file(imageno, dirptr, &img_fol, ¶meters)) { + fprintf(stderr, "skipping file...\n"); + continue; + } + } + + /* Read the input file and put it in memory */ + /* ---------------------------------------- */ + + l_stream = opj_stream_create_default_file_stream(parameters.infile, 1); + if (!l_stream) { + fprintf(stderr, "ERROR -> failed to create the stream from the file %s\n", + parameters.infile); + goto fails; + } + + /* Read the JPEG2000 stream */ + /* ------------------------ */ + + switch (parameters.decod_format) { + case J2K_CFMT: { /* JPEG-2000 codestream */ + /* Get a decoder handle */ + l_codec = opj_create_decompress(OPJ_CODEC_J2K); + break; + } + case JP2_CFMT: { /* JPEG 2000 compressed image data */ + /* Get a decoder handle */ + l_codec = opj_create_decompress(OPJ_CODEC_JP2); + break; + } + case JPT_CFMT: { /* JPEG 2000, JPIP */ + /* Get a decoder handle */ + l_codec = opj_create_decompress(OPJ_CODEC_JPT); + break; + } + default: + fprintf(stderr, "skipping file..\n"); + opj_stream_destroy(l_stream); + continue; + } + + /* catch events using our callbacks and give a local context */ + opj_set_info_handler(l_codec, info_callback, 00); + opj_set_warning_handler(l_codec, warning_callback, 00); + opj_set_error_handler(l_codec, error_callback, 00); + + parameters.flags |= OPJ_DPARAMETERS_DUMP_FLAG; + + /* Setup the decoder decoding parameters using user parameters */ + if (!opj_setup_decoder(l_codec, ¶meters)) { + fprintf(stderr, "ERROR -> opj_dump: failed to setup the decoder\n"); + opj_stream_destroy(l_stream); + opj_destroy_codec(l_codec); + fclose(fout); + goto fails; + } + + /* 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_dump: failed to read the header\n"); + opj_stream_destroy(l_stream); + opj_destroy_codec(l_codec); + opj_image_destroy(image); + fclose(fout); + goto fails; + } + + opj_dump_codec(l_codec, img_fol.flag, fout); + + cstr_info = opj_get_cstr_info(l_codec); + + cstr_index = opj_get_cstr_index(l_codec); + + /* close the byte stream */ + opj_stream_destroy(l_stream); + + /* free remaining structures */ + if (l_codec) { + opj_destroy_codec(l_codec); + } + + /* destroy the image header */ + opj_image_destroy(image); + + /* destroy the codestream index */ + opj_destroy_cstr_index(&cstr_index); + + /* destroy the codestream info */ + opj_destroy_cstr_info(&cstr_info); + + } + + /* Close the output file */ + fclose(fout); + + return EXIT_SUCCESS; + +fails: + if (dirptr) { + if (dirptr->filename) { + free(dirptr->filename); + } + if (dirptr->filename_buf) { + free(dirptr->filename_buf); + } + free(dirptr); + } + return EXIT_FAILURE; +} diff --git a/openjpeg/src/bin/jp2/windirent.h b/openjpeg/src/bin/jp2/windirent.h new file mode 100644 index 000000000..19509822a --- /dev/null +++ b/openjpeg/src/bin/jp2/windirent.h @@ -0,0 +1,683 @@ + +/* + * uce-dirent.h - operating system independent dirent implementation + * + * Copyright (C) 1998-2002 Toni Ronkko + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * ``Software''), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * + * May 28 1998, Toni Ronkko <tronkko@messi.uku.fi> + * + * $Id: uce-dirent.h,v 1.7 2002/05/13 10:48:35 tr Exp $ + * + * $Log: uce-dirent.h,v $ + * Revision 1.7 2002/05/13 10:48:35 tr + * embedded some source code directly to the header so that no source + * modules need to be included in the MS Visual C project using the + * interface, removed all the dependencies to other headers of the `uce' + * library so that the header can be made public + * + * Revision 1.6 2002/04/12 16:22:04 tr + * Unified Compiling Environment (UCE) replaced `std' library + * + * Revision 1.5 2001/07/20 16:33:40 tr + * moved to `std' library and re-named defines accordingly + * + * Revision 1.4 2001/07/10 16:47:18 tronkko + * revised comments + * + * Revision 1.3 2001/01/11 13:16:43 tr + * using ``uce-machine.h'' for finding out defines such as `FREEBSD' + * + * Revision 1.2 2000/10/08 16:00:41 tr + * copy of FreeBSD man page + * + * Revision 1.1 2000/07/10 05:53:16 tr + * Initial revision + * + * Revision 1.2 1998/07/19 18:29:14 tr + * Added error reporting capabilities and some asserts. + * + * Revision 1.1 1998/07/04 16:27:51 tr + * Initial revision + * + * + * MSVC 1.0 scans automatic dependencies incorrectly when your project + * contains this very header. The problem is that MSVC cannot handle + * include directives inside #if..#endif block those are never entered. + * Since this header ought to compile in many different operating systems, + * there had to be several conditional blocks that are compiled only in + * operating systems for what they were designed for. MSVC 1.0 cannot + * handle inclusion of sys/dir.h in a part that is compiled only in Apollo + * operating system. To fix the problem you need to insert DIR.H into + * SYSINCL.DAT located in MSVC\BIN directory and restart visual C++. + * Consult manuals for more informaton about the problem. + * + * Since many UNIX systems have dirent.h we assume to have one also. + * However, if your UNIX system does not have dirent.h you can download one + * for example at: http://ftp.uni-mannheim.de/ftp/GNU/dirent/dirent.tar.gz. + * You can also see if you have one of dirent.h, direct.h, dir.h, ndir.h, + * sys/dir.h and sys/ndir.h somewhere. Try defining HAVE_DIRENT_H, + * HAVE_DIRECT_H, HAVE_DIR_H, HAVE_NDIR_H, HAVE_SYS_DIR_H and + * HAVE_SYS_NDIR_H according to the files found. + */ +#ifndef DIRENT_H +#define DIRENT_H +#define DIRENT_H_INCLUDED + +/* find out platform */ +#if defined(MSDOS) /* MS-DOS */ +#elif defined(__MSDOS__) /* Turbo C/Borland */ +# define MSDOS +#elif defined(__DOS__) /* Watcom */ +# define MSDOS +#endif + +#if defined(WIN32) /* MS-Windows */ +#elif defined(__NT__) /* Watcom */ +# define WIN32 +#elif defined(_WIN32) /* Microsoft */ +# define WIN32 +#elif defined(__WIN32__) /* Borland */ +# define WIN32 +#endif + +/* + * See what kind of dirent interface we have unless autoconf has already + * determinated that. + */ +#if !defined(HAVE_DIRENT_H) && !defined(HAVE_DIRECT_H) && !defined(HAVE_SYS_DIR_H) && !defined(HAVE_NDIR_H) && !defined(HAVE_SYS_NDIR_H) && !defined(HAVE_DIR_H) +# if defined(_MSC_VER) /* Microsoft C/C++ */ +/* no dirent.h */ +# elif defined(__MINGW32__) /* MinGW */ +/* no dirent.h */ +# elif defined(__BORLANDC__) /* Borland C/C++ */ +# define HAVE_DIRENT_H +# define VOID_CLOSEDIR +# elif defined(__TURBOC__) /* Borland Turbo C */ +/* no dirent.h */ +# elif defined(__WATCOMC__) /* Watcom C/C++ */ +# define HAVE_DIRECT_H +# elif defined(__apollo) /* Apollo */ +# define HAVE_SYS_DIR_H +# elif defined(__hpux) /* HP-UX */ +# define HAVE_DIRENT_H +# elif (defined(__alpha) || defined(__alpha__)) && !defined(__linux__) /* Alpha OSF1 */ +# error "not implemented" +# elif defined(__sgi) /* Silicon Graphics */ +# define HAVE_DIRENT_H +# elif defined(sun) || defined(__sun) /* Sun Solaris */ +# define HAVE_DIRENT_H +# elif defined(__FreeBSD__) /* FreeBSD */ +# define HAVE_DIRENT_H +# elif defined(__linux__) /* Linux */ +# define HAVE_DIRENT_H +# elif defined(__GNUC__) /* GNU C/C++ */ +# define HAVE_DIRENT_H +# else +# error "not implemented" +# endif +#endif + +/* include proper interface headers */ +#if defined(HAVE_DIRENT_H) +# include <dirent.h> +# ifdef FREEBSD +# define NAMLEN(dp) ((int)((dp)->d_namlen)) +# else +# define NAMLEN(dp) ((int)(strlen((dp)->d_name))) +# endif + +#elif defined(HAVE_NDIR_H) +# include <ndir.h> +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_SYS_NDIR_H) +# include <sys/ndir.h> +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_DIRECT_H) +# include <direct.h> +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_DIR_H) +# include <dir.h> +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_SYS_DIR_H) +# include <sys/types.h> +# include <sys/dir.h> +# ifndef dirent +# define dirent direct +# endif +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(MSDOS) || defined(WIN32) + +/* figure out type of underlaying directory interface to be used */ +# if defined(WIN32) +# define DIRENT_WIN32_INTERFACE +# elif defined(MSDOS) +# define DIRENT_MSDOS_INTERFACE +# else +# error "missing native dirent interface" +# endif + +/*** WIN32 specifics ***/ +# if defined(DIRENT_WIN32_INTERFACE) +# include <windows.h> +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN (MAX_PATH) +# endif + + +/*** MS-DOS specifics ***/ +# elif defined(DIRENT_MSDOS_INTERFACE) +# include <dos.h> + +/* Borland defines file length macros in dir.h */ +# if defined(__BORLANDC__) +# include <dir.h> +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN ((MAXFILE)+(MAXEXT)) +# endif +# if !defined(_find_t) +# define _find_t find_t +# endif + +/* Turbo C defines ffblk structure in dir.h */ +# elif defined(__TURBOC__) +# include <dir.h> +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN ((MAXFILE)+(MAXEXT)) +# endif +# define DIRENT_USE_FFBLK + +/* MSVC */ +# elif defined(_MSC_VER) +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN (12) +# endif + +/* Watcom */ +# elif defined(__WATCOMC__) +# if !defined(DIRENT_MAXNAMLEN) +# if defined(__OS2__) || defined(__NT__) +# define DIRENT_MAXNAMLEN (255) +# else +# define DIRENT_MAXNAMLEN (12) +# endif +# endif + +# endif +# endif + +/*** generic MS-DOS and MS-Windows stuff ***/ +# if !defined(NAME_MAX) && defined(DIRENT_MAXNAMLEN) +# define NAME_MAX DIRENT_MAXNAMLEN +# endif +# if NAME_MAX < DIRENT_MAXNAMLEN +# error "assertion failed: NAME_MAX >= DIRENT_MAXNAMLEN" +# endif + + +/* + * Substitute for real dirent structure. Note that `d_name' field is a + * true character array although we have it copied in the implementation + * dependent data. We could save some memory if we had declared `d_name' + * as a pointer referring the name within implementation dependent data. + * We have not done that since some code may rely on sizeof(d_name) to be + * something other than four. Besides, directory entries are typically so + * small that it takes virtually no time to copy them from place to place. + */ +typedef struct dirent { + char d_name[NAME_MAX + 1]; + + /*** Operating system specific part ***/ +# if defined(DIRENT_WIN32_INTERFACE) /*WIN32*/ + WIN32_FIND_DATA data; +# elif defined(DIRENT_MSDOS_INTERFACE) /*MSDOS*/ +# if defined(DIRENT_USE_FFBLK) + struct ffblk data; +# else + struct _find_t data; +# endif +# endif +} dirent; + +/* DIR substitute structure containing directory name. The name is + * essential for the operation of ``rewinndir'' function. */ +typedef struct DIR { + char *dirname; /* directory being scanned */ + dirent current; /* current entry */ + int dirent_filled; /* is current un-processed? */ + + /*** Operating system specific part ***/ +# if defined(DIRENT_WIN32_INTERFACE) + HANDLE search_handle; +# elif defined(DIRENT_MSDOS_INTERFACE) +# endif +} DIR; + +# ifdef __cplusplus +extern "C" { +# endif + +/* supply prototypes for dirent functions */ +static DIR *opendir(const char *dirname); +static struct dirent *readdir(DIR *dirp); +static int closedir(DIR *dirp); +#ifdef unused +static void rewinddir(DIR *dirp); +#endif + +/* + * Implement dirent interface as static functions so that the user does not + * need to change his project in any way to use dirent function. With this + * it is sufficient to include this very header from source modules using + * dirent functions and the functions will be pulled in automatically. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> + +/* use ffblk instead of _find_t if requested */ +#if defined(DIRENT_USE_FFBLK) +# define _A_ARCH (FA_ARCH) +# define _A_HIDDEN (FA_HIDDEN) +# define _A_NORMAL (0) +# define _A_RDONLY (FA_RDONLY) +# define _A_SUBDIR (FA_DIREC) +# define _A_SYSTEM (FA_SYSTEM) +# define _A_VOLID (FA_LABEL) +# define _dos_findnext(dest) findnext(dest) +# define _dos_findfirst(name,flags,dest) findfirst(name,dest,flags) +#endif + +static int _initdir(DIR *p); +static const char *_getdirname(const struct dirent *dp); +static void _setdirname(struct DIR *dirp); + +/* + * <function name="opendir"> + * <intro>open directory stream for reading + * <syntax>DIR *opendir (const char *dirname); + * + * <desc>Open named directory stream for read and return pointer to the + * internal working area that is used for retrieving individual directory + * entries. The internal working area has no fields of your interest. + * + * <ret>Returns a pointer to the internal working area or NULL in case the + * directory stream could not be opened. Global `errno' variable will set + * in case of error as follows: + * + * <table> + * [EACESS |Permission denied. + * [EMFILE |Too many open files used by the process. + * [ENFILE |Too many open files in system. + * [ENOENT |Directory does not exist. + * [ENOMEM |Insufficient memory. + * [ENOTDIR |dirname does not refer to directory. This value is not + * reliable on MS-DOS and MS-Windows platforms. Many + * implementations return ENOENT even when the name refers to a + * file.] + * </table> + * </function> + */ +static DIR *opendir(const char *dirname) +{ + DIR *dirp; + assert(dirname != NULL); + + dirp = (DIR*)malloc(sizeof(struct DIR)); + if (dirp != NULL) { + char *p; + + /* allocate room for directory name */ + dirp->dirname = (char*) malloc(strlen(dirname) + 1 + strlen("\\*.*")); + if (dirp->dirname == NULL) { + /* failed to duplicate directory name. errno set by malloc() */ + free(dirp); + return NULL; + } + /* Copy directory name while appending directory separator and "*.*". + * Directory separator is not appended if the name already ends with + * drive or directory separator. Directory separator is assumed to be + * '/' or '\' and drive separator is assumed to be ':'. */ + strcpy(dirp->dirname, dirname); + p = strchr(dirp->dirname, '\0'); + if (dirp->dirname < p && + *(p - 1) != '\\' && *(p - 1) != '/' && *(p - 1) != ':') { + strcpy(p++, "\\"); + } +# ifdef DIRENT_WIN32_INTERFACE + strcpy(p, "*"); /*scan files with and without extension in win32*/ +# else + strcpy(p, "*.*"); /*scan files with and without extension in DOS*/ +# endif + + /* open stream */ + if (_initdir(dirp) == 0) { + /* initialization failed */ + free(dirp->dirname); + free(dirp); + return NULL; + } + } + return dirp; +} + + +/* + * <function name="readdir"> + * <intro>read a directory entry + * <syntax>struct dirent *readdir (DIR *dirp); + * + * <desc>Read individual directory entry and return pointer to a structure + * containing the name of the entry. Individual directory entries returned + * include normal files, sub-directories, pseudo-directories "." and ".." + * and also volume labels, hidden files and system files in MS-DOS and + * MS-Windows. You might want to use stat(2) function to determinate which + * one are you dealing with. Many dirent implementations already contain + * equivalent information in dirent structure but you cannot depend on + * this. + * + * The dirent structure contains several system dependent fields that + * generally have no interest to you. The only interesting one is char + * d_name[] that is also portable across different systems. The d_name + * field contains the name of the directory entry without leading path. + * While d_name is portable across different systems the actual storage + * capacity of d_name varies from system to system and there is no portable + * way to find out it at compile time as different systems define the + * capacity of d_name with different macros and some systems do not define + * capacity at all (besides actual declaration of the field). If you really + * need to find out storage capacity of d_name then you might want to try + * NAME_MAX macro. The NAME_MAX is defined in POSIX standard although + * there are many MS-DOS and MS-Windows implementations those do not define + * it. There are also systems that declare d_name as "char d_name[1]" and + * then allocate suitable amount of memory at run-time. Thanks to Alain + * Decamps (Alain.Decamps@advalvas.be) for pointing it out to me. + * + * This all leads to the fact that it is difficult to allocate space + * for the directory names when the very same program is being compiled on + * number of operating systems. Therefore I suggest that you always + * allocate space for directory names dynamically. + * + * <ret> + * Returns a pointer to a structure containing name of the directory entry + * in `d_name' field or NULL if there was an error. In case of an error the + * global `errno' variable will set as follows: + * + * <table> + * [EBADF |dir parameter refers to an invalid directory stream. This value + * is not set reliably on all implementations.] + * </table> + * </function> + */ +static struct dirent * +readdir(DIR *dirp) +{ + assert(dirp != NULL); + if (dirp == NULL) { + errno = EBADF; + return NULL; + } + +#if defined(DIRENT_WIN32_INTERFACE) + if (dirp->search_handle == INVALID_HANDLE_VALUE) { + /* directory stream was opened/rewound incorrectly or it ended normally */ + errno = EBADF; + return NULL; + } +#endif + + if (dirp->dirent_filled != 0) { + /* + * Directory entry has already been retrieved and there is no need to + * retrieve a new one. Directory entry will be retrieved in advance + * when the user calls readdir function for the first time. This is so + * because real dirent has separate functions for opening and reading + * the stream whereas Win32 and DOS dirents open the stream + * automatically when we retrieve the first file. Therefore, we have to + * save the first file when opening the stream and later we have to + * return the saved entry when the user tries to read the first entry. + */ + dirp->dirent_filled = 0; + } else { + /* fill in entry and return that */ +#if defined(DIRENT_WIN32_INTERFACE) + if (FindNextFile(dirp->search_handle, &dirp->current.data) == FALSE) { + /* Last file has been processed or an error occurred */ + FindClose(dirp->search_handle); + dirp->search_handle = INVALID_HANDLE_VALUE; + errno = ENOENT; + return NULL; + } + +# elif defined(DIRENT_MSDOS_INTERFACE) + if (_dos_findnext(&dirp->current.data) != 0) { + /* _dos_findnext and findnext will set errno to ENOENT when no + * more entries could be retrieved. */ + return NULL; + } +# endif + + _setdirname(dirp); + assert(dirp->dirent_filled == 0); + } + return &dirp->current; +} + + +/* + * <function name="closedir"> + * <intro>close directory stream. + * <syntax>int closedir (DIR *dirp); + * + * <desc>Close directory stream opened by the `opendir' function. Close of + * directory stream invalidates the DIR structure as well as previously read + * dirent entry. + * + * <ret>The function typically returns 0 on success and -1 on failure but + * the function may be declared to return void on same systems. At least + * Borland C/C++ and some UNIX implementations use void as a return type. + * The dirent wrapper tries to define VOID_CLOSEDIR whenever closedir is + * known to return nothing. The very same definition is made by the GNU + * autoconf if you happen to use it. + * + * The global `errno' variable will set to EBADF in case of error. + * </function> + */ +static int +closedir(DIR *dirp) +{ + int retcode = 0; + + /* make sure that dirp points to legal structure */ + assert(dirp != NULL); + if (dirp == NULL) { + errno = EBADF; + return -1; + } + + /* free directory name and search handles */ + if (dirp->dirname != NULL) { + free(dirp->dirname); + } + +#if defined(DIRENT_WIN32_INTERFACE) + if (dirp->search_handle != INVALID_HANDLE_VALUE) { + if (FindClose(dirp->search_handle) == FALSE) { + /* Unknown error */ + retcode = -1; + errno = EBADF; + } + } +#endif + + /* clear dirp structure to make sure that it cannot be used anymore*/ + memset(dirp, 0, sizeof(*dirp)); +# if defined(DIRENT_WIN32_INTERFACE) + dirp->search_handle = INVALID_HANDLE_VALUE; +# endif + + free(dirp); + return retcode; +} + + +#ifdef unused +/* + * <function name="rewinddir"> + * <intro>rewind directory stream to the beginning + * <syntax>void rewinddir (DIR *dirp); + * + * <desc>Rewind directory stream to the beginning so that the next call of + * readdir() returns the very first directory entry again. However, note + * that next call of readdir() may not return the same directory entry as it + * did in first time. The directory stream may have been affected by newly + * created files. + * + * Almost every dirent implementation ensure that rewinddir will update + * the directory stream to reflect any changes made to the directory entries + * since the previous ``opendir'' or ``rewinddir'' call. Keep an eye on + * this if your program depends on the feature. I know at least one dirent + * implementation where you are required to close and re-open the stream to + * see the changes. + * + * <ret>Returns nothing. If something went wrong while rewinding, you will + * notice it later when you try to retrieve the first directory entry. + */ +static void +rewinddir(DIR *dirp) +{ + /* make sure that dirp is legal */ + assert(dirp != NULL); + if (dirp == NULL) { + errno = EBADF; + return; + } + assert(dirp->dirname != NULL); + + /* close previous stream */ +#if defined(DIRENT_WIN32_INTERFACE) + if (dirp->search_handle != INVALID_HANDLE_VALUE) { + if (FindClose(dirp->search_handle) == FALSE) { + /* Unknown error */ + errno = EBADF; + } + } +#endif + + /* re-open previous stream */ + if (_initdir(dirp) == 0) { + /* initialization failed but we cannot deal with error. User will notice + * error later when she tries to retrieve first directory enty. */ + /*EMPTY*/; + } +} +#endif + +/* + * Open native directory stream object and retrieve first file. + * Be sure to close previous stream before opening new one. + */ +static int +_initdir(DIR *dirp) +{ + assert(dirp != NULL); + assert(dirp->dirname != NULL); + dirp->dirent_filled = 0; + +# if defined(DIRENT_WIN32_INTERFACE) + /* Open stream and retrieve first file */ + dirp->search_handle = FindFirstFile(dirp->dirname, &dirp->current.data); + if (dirp->search_handle == INVALID_HANDLE_VALUE) { + /* something went wrong but we don't know what. GetLastError() could + * give us more information about the error, but then we should map + * the error code into errno. */ + errno = ENOENT; + return 0; + } + +# elif defined(DIRENT_MSDOS_INTERFACE) + if (_dos_findfirst(dirp->dirname, + _A_SUBDIR | _A_RDONLY | _A_ARCH | _A_SYSTEM | _A_HIDDEN, + &dirp->current.data) != 0) { + /* _dos_findfirst and findfirst will set errno to ENOENT when no + * more entries could be retrieved. */ + return 0; + } +# endif + + /* initialize DIR and it's first entry */ + _setdirname(dirp); + dirp->dirent_filled = 1; + return 1; +} + + +/* + * Return implementation dependent name of the current directory entry. + */ +static const char * +_getdirname(const struct dirent *dp) +{ +#if defined(DIRENT_WIN32_INTERFACE) + return dp->data.cFileName; + +#elif defined(DIRENT_USE_FFBLK) + return dp->data.ff_name; + +#else + return dp->data.name; +#endif +} + + +/* + * Copy name of implementation dependent directory entry to the d_name field. + */ +static void +_setdirname(struct DIR *dirp) +{ + /* make sure that d_name is long enough */ + assert(strlen(_getdirname(&dirp->current)) <= NAME_MAX); + + strncpy(dirp->current.d_name, + _getdirname(&dirp->current), + NAME_MAX); + dirp->current.d_name[NAME_MAX] = '\0'; /*char d_name[NAME_MAX+1]*/ +} + +# ifdef __cplusplus +} +# endif +# define NAMLEN(dp) ((int)(strlen((dp)->d_name))) + +#else +# error "missing dirent interface" +#endif + + +#endif /*DIRENT_H*/ diff --git a/openjpeg/src/bin/jp3d/CMakeLists.txt b/openjpeg/src/bin/jp3d/CMakeLists.txt new file mode 100644 index 000000000..3cac1a8fa --- /dev/null +++ b/openjpeg/src/bin/jp3d/CMakeLists.txt @@ -0,0 +1,41 @@ +# Build the demo app, small examples + +# First thing define the common source: +set(common_SRCS + convert.c + ${OPENJPEG_SOURCE_DIR}/src/bin/common/opj_getopt.c + ) + +# Headers file are located here: +include_directories( + ${OPENJPEG_BINARY_DIR}/src/lib/openjp2 # opj_config.h + ${OPENJPEG_SOURCE_DIR}/src/lib/openjp3d + ${LCMS_INCLUDE_DIRNAME} + ${OPENJPEG_SOURCE_DIR}/src/bin/common + ${Z_INCLUDE_DIRNAME} + ${PNG_INCLUDE_DIRNAME} + ${TIFF_INCLUDE_DIRNAME} + ) + +if(WIN32) + if(BUILD_SHARED_LIBS) + add_definitions(-DOPJ_EXPORTS) + else() + add_definitions(-DOPJ_STATIC) + endif() +endif() + +# Loop over all executables: +foreach(exe opj_jp3d_compress opj_jp3d_decompress) + add_executable(${exe} ${exe}.c ${common_SRCS}) + target_link_libraries(${exe} openjp3d) + # On unix you need to link to the math library: + if(UNIX) + target_link_libraries(${exe} m) + endif(UNIX) + # Install exe + install(TARGETS ${exe} + EXPORT OpenJP3DTargets + DESTINATION ${OPENJPEG_INSTALL_BIN_DIR} COMPONENT Applications + ) +endforeach() diff --git a/openjpeg/src/bin/jp3d/convert.c b/openjpeg/src/bin/jp3d/convert.c new file mode 100644 index 000000000..5d07bf19b --- /dev/null +++ b/openjpeg/src/bin/jp3d/convert.c @@ -0,0 +1,1050 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2006, Mónica Díez García, Image Processing Laboratory, University of Valladolid, Spain + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "openjp3d.h" +#ifdef _WIN32 +#include "windirent.h" +#else +#include <dirent.h> +#endif /* _WIN32 */ + + + +void dump_volume(FILE *fd, opj_volume_t * vol) +{ + int compno; + fprintf(fd, "volume {\n"); + fprintf(fd, " x0=%d, y0=%d, z0=%d, x1=%d, y1=%d, z1=%d\n", vol->x0, vol->y0, + vol->z0, vol->x1, vol->y1, vol->z1); + fprintf(fd, " numcomps=%d\n", vol->numcomps); + for (compno = 0; compno < vol->numcomps; compno++) { + opj_volume_comp_t *comp = &vol->comps[compno]; + fprintf(fd, " comp %d {\n", compno); + fprintf(fd, " dx=%d, dy=%d, dz=%d\n", comp->dx, comp->dy, comp->dz); + fprintf(fd, " prec=%d\n", comp->prec); + fprintf(fd, " sgnd=%d\n", comp->sgnd); + fprintf(fd, " }\n"); + } + fprintf(fd, "}\n"); +} + +/* + * Get logarithm of an integer and round downwards. + * + * log2(a) + */ +static int int_floorlog2(int a) +{ + int l; + for (l = 0; a > 1; l++) { + a >>= 1; + } + return l; +} + +/* + * Divide an integer by a power of 2 and round upwards. + * + * a divided by 2^b + */ +static int int_ceildivpow2(int a, int b) +{ + return (a + (1 << b) - 1) >> b; +} + +/* + * Divide an integer and round upwards. + * + * a divided by b + */ +static int int_ceildiv(int a, int b) +{ + return (a + b - 1) / b; +} + + +/* -->> -->> -->> -->> + +PGX IMAGE FORMAT + +<<-- <<-- <<-- <<-- */ + + +unsigned char readuchar(FILE * f) +{ + unsigned char c1; + fread(&c1, 1, 1, f); + return c1; +} + +unsigned short readushort(FILE * f, int bigendian) +{ + unsigned char c1, c2; + fread(&c1, 1, 1, f); + fread(&c2, 1, 1, f); + if (bigendian) { + return (c1 << 8) + c2; + } else { + return (c2 << 8) + c1; + } +} + +unsigned int readuint(FILE * f, int bigendian) +{ + unsigned char c1, c2, c3, c4; + fread(&c1, 1, 1, f); + fread(&c2, 1, 1, f); + fread(&c3, 1, 1, f); + fread(&c4, 1, 1, f); + if (bigendian) { + return (c1 << 24) + (c2 << 16) + (c3 << 8) + c4; + } else { + return (c4 << 24) + (c3 << 16) + (c2 << 8) + c1; + } +} +/*****************************************/ +static unsigned short ShortSwap(unsigned short v) +{ + unsigned char c1, c2; + c1 = v & 0xff; + c2 = (v >> 8) & 0xff; + return (c1 << 8) + c2; +} + +static unsigned int LongSwap(unsigned int i) +{ + unsigned char b1, b2, b3, b4; + b1 = i & 255; + b2 = (i >> 8) & 255; + b3 = (i >> 16) & 255; + b4 = (i >> 24) & 255; + return ((int)b1 << 24) + ((int)b2 << 16) + ((int)b3 << 8) + b4; +} +/*****************************************/ + +opj_volume_t* pgxtovolume(char *relpath, opj_cparameters_t *parameters) +{ + + FILE *f = NULL; + int w, h, prec; + unsigned long offset; + int i, s, numcomps, maxvalue, sliceno, slicepos, maxslice = 0; + + OPJ_COLOR_SPACE color_space; + opj_volume_cmptparm_t cmptparm; /* maximum of 1 component */ + opj_volume_t * volume = NULL; + + char endian1, endian2, sign; + char signtmp[32]; + char temp[32]; + opj_volume_comp_t *comp = NULL; + + DIR *dirp; + struct dirent *direntp; + + char *tmp = NULL, *tmp2 = NULL, + *point = NULL, *pgx = NULL; + char tmpdirpath[MAX_PATH]; + char dirpath[MAX_PATH]; + char pattern[MAX_PATH]; + char pgxfiles[MAX_SLICES][MAX_PATH]; + int pgxslicepos[MAX_SLICES]; + char tmpno[3]; + + numcomps = 1; + color_space = CLRSPC_GRAY; + sliceno = 0; + maxvalue = 0; + memset(pgxfiles, 0, MAX_SLICES * MAX_PATH * sizeof(char)); + memset(&cmptparm, 0, sizeof(opj_volume_cmptparm_t)); + + /* Separación del caso de un único slice frente al de muchos */ + if ((tmp = strrchr(relpath, '-')) == NULL) { + /*fprintf(stdout,"[INFO] A volume of only one slice....\n");*/ + sliceno = 1; + maxslice = 1; + strcpy(pgxfiles[0], relpath); + + } else { + /*Fetch only the path */ + strcpy(tmpdirpath, relpath); + if ((tmp = strrchr(tmpdirpath, '/')) != NULL) { + tmp++; + *tmp = '\0'; + strcpy(dirpath, tmpdirpath); + } else { + strcpy(dirpath, "./"); + } + + /*Fetch the pattern of the volume slices*/ + if ((tmp = strrchr(relpath, '/')) != NULL) { + tmp++; + } else { + tmp = relpath; + } + if ((tmp2 = strrchr(tmp, '-')) != NULL) { + *tmp2 = '\0'; + } else { + fprintf(stdout, "[ERROR] tmp2 ha dado null. no ha encontrado el * %s %s", tmp, + relpath); + return NULL; + } + strcpy(pattern, tmp); + + dirp = opendir(dirpath); + if (dirp == NULL) { + fprintf(stdout, + "[ERROR] Infile must be a .pgx file or a directory that contain pgx files"); + return NULL; + } + + /*Read all .pgx files of directory */ + while ((direntp = readdir(dirp)) != NULL) { + /* Found a directory, but ignore . and .. */ + if (strcmp(".", direntp->d_name) == 0 || strcmp("..", direntp->d_name) == 0) { + continue; + } + + if (((pgx = strstr(direntp->d_name, pattern)) != NULL) && + ((tmp2 = strstr(direntp->d_name, ".pgx")) != NULL)) { + + strcpy(tmp, dirpath); + tmp = strcat(tmp, direntp->d_name); + + /*Obtenemos el index de la secuencia de slices*/ + if ((tmp2 = strpbrk(direntp->d_name, "0123456789")) == NULL) { + continue; + } + i = 0; + while (tmp2 != NULL) { + tmpno[i++] = *tmp2; + point = tmp2; + tmp2 = strpbrk(tmp2 + 1, "0123456789"); + } + tmpno[i] = '\0'; + + /*Comprobamos que no estamos leyendo algo raro como pattern.jp3d*/ + if ((point = strpbrk(point, ".")) == NULL) { + break; + } + /*Slicepos --> index de slice; Sliceno --> no de slices hasta el momento*/ + slicepos = atoi(tmpno); + pgxslicepos[sliceno] = slicepos - 1; + sliceno++; + if (slicepos > maxslice) { + maxslice = slicepos; + } + + /*Colocamos el slices en su posicion correspondiente*/ + strcpy(pgxfiles[slicepos - 1], tmp); + } + } + + }/* else if pattern*.pgx */ + + if (!sliceno) { + fprintf(stdout, + "[ERROR] No slices with this pattern founded !! Please check input volume name\n"); + return NULL; + } + /*if ( maxslice != sliceno) { + fprintf(stdout,"[ERROR] Slices are not sequentially numbered !! Please rename them accordingly\n"); + return NULL; + }*/ + + for (s = 0; s < sliceno; s++) { + int pos = maxslice == sliceno ? s : pgxslicepos[s]; + f = fopen(pgxfiles[pos], "rb"); + if (!f) { + fprintf(stdout, "[ERROR] Failed to open %s for reading !\n", pgxfiles[s]); + return NULL; + } + fprintf(stdout, "[INFO] Loading %s \n", pgxfiles[pos]); + + fseek(f, 0, SEEK_SET); + fscanf(f, "PG%[ \t]%c%c%[ \t+-]%d%[ \t]%d%[ \t]%d", temp, &endian1, &endian2, + signtmp, &prec, temp, &w, temp, &h); + + i = 0; + sign = '+'; + while (signtmp[i] != '\0') { + if (signtmp[i] == '-') { + sign = '-'; + } + i++; + } + + fgetc(f); + if (endian1 == 'M' && endian2 == 'L') { + cmptparm.bigendian = 1; + } else if (endian2 == 'M' && endian1 == 'L') { + cmptparm.bigendian = 0; + } else { + fprintf(stdout, "[ERROR] Bad pgx header, please check input file\n"); + fclose(f); + return NULL; + } + + if (s == 0) { + /* initialize volume component */ + + cmptparm.x0 = parameters->volume_offset_x0; + cmptparm.y0 = parameters->volume_offset_y0; + cmptparm.z0 = parameters->volume_offset_z0; + cmptparm.w = !cmptparm.x0 ? (w - 1) * parameters->subsampling_dx + 1 : + cmptparm.x0 + (w - 1) * parameters->subsampling_dx + 1; + cmptparm.h = !cmptparm.y0 ? (h - 1) * parameters->subsampling_dy + 1 : + cmptparm.y0 + (h - 1) * parameters->subsampling_dy + 1; + cmptparm.l = !cmptparm.z0 ? (sliceno - 1) * parameters->subsampling_dz + 1 : + cmptparm.z0 + (sliceno - 1) * parameters->subsampling_dz + 1; + + if (sign == '-') { + cmptparm.sgnd = 1; + } else { + cmptparm.sgnd = 0; + } + cmptparm.prec = prec; + cmptparm.bpp = prec; + cmptparm.dcoffset = parameters->dcoffset; + cmptparm.dx = parameters->subsampling_dx; + cmptparm.dy = parameters->subsampling_dy; + cmptparm.dz = parameters->subsampling_dz; + + /* create the volume */ + volume = opj_volume_create(numcomps, &cmptparm, color_space); + if (!volume) { + fclose(f); + return NULL; + } + /* set volume offset and reference grid */ + volume->x0 = cmptparm.x0; + volume->y0 = cmptparm.y0; + volume->z0 = cmptparm.z0; + volume->x1 = cmptparm.w; + volume->y1 = cmptparm.h; + volume->z1 = cmptparm.l; + + /* set volume data :only one component, that is a volume*/ + comp = &volume->comps[0]; + + }/*if sliceno==1*/ + + offset = w * h * s; + + for (i = 0; i < w * h; i++) { + int v; + if (comp->prec <= 8) { + if (!comp->sgnd) { + v = readuchar(f); + } else { + v = (char) readuchar(f); + } + } else if (comp->prec <= 16) { + if (!comp->sgnd) { + v = readushort(f, cmptparm.bigendian); + } else { + v = (short) readushort(f, cmptparm.bigendian); + } + } else { + if (!comp->sgnd) { + v = readuint(f, cmptparm.bigendian); + } else { + v = (int) readuint(f, cmptparm.bigendian); + } + } + if (v > maxvalue) { + maxvalue = v; + } + comp->data[i + offset] = v; + + } + fclose(f); + } /* for s --> sliceno*/ + comp->bpp = int_floorlog2(maxvalue) + 1; + if (sliceno != 1) { + closedir(dirp); + } + /*dump_volume(stdout, volume);*/ + return volume; +} + + +int volumetopgx(opj_volume_t * volume, char *outfile) +{ + int w, wr, wrr, h, hr, hrr, l, lr, lrr; + int i, j, compno, offset, sliceno; + FILE *fdest = NULL; + + for (compno = 0; compno < volume->numcomps; compno++) { + opj_volume_comp_t *comp = &volume->comps[compno]; + char name[256]; + int nbytes = 0; + char *tmp = outfile; + while (*tmp) { + tmp++; + } + while (*tmp != '.') { + tmp--; + } + *tmp = '\0'; + for (sliceno = 0; sliceno < volume->z1 - volume->z0; sliceno++) { + + if (volume->numcomps > 1) { + sprintf(name, "%s%d-%d.pgx", outfile, sliceno + 1, compno); + } else if ((volume->z1 - volume->z0) > 1) { + sprintf(name, "%s%d.pgx", outfile, sliceno + 1); + } else { + sprintf(name, "%s.pgx", outfile); + } + + fdest = fopen(name, "wb"); + if (!fdest) { + fprintf(stdout, "[ERROR] Failed to open %s for writing \n", name); + return 1; + } + + fprintf(stdout, "[INFO] Writing in %s (%s)\n", name, + volume->comps[0].bigendian ? "Bigendian" : "Little-endian"); + + w = int_ceildiv(volume->x1 - volume->x0, volume->comps[compno].dx); + wr = volume->comps[compno].w; + wrr = int_ceildivpow2(volume->comps[compno].w, volume->comps[compno].factor[0]); + + h = int_ceildiv(volume->y1 - volume->y0, volume->comps[compno].dy); + hr = volume->comps[compno].h; + hrr = int_ceildivpow2(volume->comps[compno].h, volume->comps[compno].factor[1]); + + l = int_ceildiv(volume->z1 - volume->z0, volume->comps[compno].dz); + lr = volume->comps[compno].l; + lrr = int_ceildivpow2(volume->comps[compno].l, volume->comps[compno].factor[2]); + + fprintf(fdest, "PG %c%c %c%d %d %d\n", comp->bigendian ? 'M' : 'L', + comp->bigendian ? 'L' : 'M', comp->sgnd ? '-' : '+', comp->prec, wr, hr); + if (comp->prec <= 8) { + nbytes = 1; + } else if (comp->prec <= 16) { + nbytes = 2; + } else { + nbytes = 4; + } + + offset = (sliceno / lrr * l) + (sliceno % lrr); + offset = wrr * hrr * offset; + /*fprintf(stdout,"%d %d %d %d\n",offset,wrr*hrr,wrr,w);*/ + for (i = 0; i < wrr * hrr; i++) { + int v = volume->comps[0].data[(i / wrr * w) + (i % wrr) + offset]; + if (volume->comps[0].bigendian) { + for (j = nbytes - 1; j >= 0; j--) { + char byte = (char)((v >> (j * 8)) & 0xff); + fwrite(&byte, 1, 1, fdest); + } + } else { + for (j = 0; j <= nbytes - 1; j++) { + char byte = (char)((v >> (j * 8)) & 0xff); + fwrite(&byte, 1, 1, fdest); + } + } + } + + fclose(fdest); + }/*for sliceno*/ + }/*for compno*/ + + return 0; +} + +/* -->> -->> -->> -->> + +BIN IMAGE FORMAT + +<<-- <<-- <<-- <<-- */ + +opj_volume_t* bintovolume(char *filename, char *fileimg, + opj_cparameters_t *parameters) +{ + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + int subsampling_dz = parameters->subsampling_dz; + + int i, compno, w, h, l, numcomps = 1; + int prec, max = 0; + + /* char temp[32];*/ + char line[100]; + int bigendian; + + FILE *f = NULL; + FILE *fimg = NULL; + OPJ_COLOR_SPACE color_space; + opj_volume_cmptparm_t cmptparm; /* maximum of 1 component */ + opj_volume_t * volume = NULL; + opj_volume_comp_t *comp = NULL; + + bigendian = 0; + color_space = CLRSPC_GRAY; + + fimg = fopen(fileimg, "r"); + if (!fimg) { + fprintf(stdout, "[ERROR] Failed to open %s for reading !!\n", fileimg); + return 0; + } + + fseek(fimg, 0, SEEK_SET); + while (!feof(fimg)) { + fgets(line, 100, fimg); + /*fprintf(stdout,"%s %d \n",line,feof(fimg));*/ + if (strncmp(line, "Bpp", 3) == 0) { + sscanf(line, "%*s%*[ \t]%d", &prec); + } else if (strncmp(line, "Color", 5) == 0) { + sscanf(line, "%*s%*[ \t]%d", &color_space); + } else if (strncmp(line, "Dim", 3) == 0) { + sscanf(line, "%*s%*[ \t]%d%*[ \t]%d%*[ \t]%d", &w, &h, &l); + } + } + /*fscanf(fimg, "Bpp%[ \t]%d%[ \t\n]",temp,&prec,temp);*/ + /*fscanf(fimg, "Color Map%[ \t]%d%[ \n\t]Dimensions%[ \t]%d%[ \t]%d%[ \t]%d%[ \n\t]",temp,&color_space,temp,temp,&w,temp,&h,temp,&l,temp);*/ + /*fscanf(fimg, "Resolution(mm)%[ \t]%d%[ \t]%d%[ \t]%d%[ \n\t]",temp,&subsampling_dx,temp,&subsampling_dy,temp,&subsampling_dz,temp);*/ + +#ifdef VERBOSE + fprintf(stdout, "[INFO] %d \t %d %d %d \t %3.2f %2.2f %2.2f \t %d \n", + color_space, w, h, l, subsampling_dx, subsampling_dy, subsampling_dz, prec); +#endif + fclose(fimg); + + /* initialize volume components */ + memset(&cmptparm, 0, sizeof(opj_volume_cmptparm_t)); + + cmptparm.prec = prec; + cmptparm.bpp = prec; + cmptparm.sgnd = 0; + cmptparm.bigendian = bigendian; + cmptparm.dcoffset = parameters->dcoffset; + cmptparm.dx = subsampling_dx; + cmptparm.dy = subsampling_dy; + cmptparm.dz = subsampling_dz; + cmptparm.w = w; + cmptparm.h = h; + cmptparm.l = l; + + /* create the volume */ + volume = opj_volume_create(numcomps, &cmptparm, color_space); + if (!volume) { + fprintf(stdout, "[ERROR] Unable to create volume"); + fclose(f); + return NULL; + } + + /* set volume offset and reference grid */ + volume->x0 = parameters->volume_offset_x0; + volume->y0 = parameters->volume_offset_y0; + volume->z0 = parameters->volume_offset_z0; + volume->x1 = parameters->volume_offset_x0 + (w - 1) * subsampling_dx + 1; + volume->y1 = parameters->volume_offset_y0 + (h - 1) * subsampling_dy + 1; + volume->z1 = parameters->volume_offset_z0 + (l - 1) * subsampling_dz + 1; + + /* set volume data */ + f = fopen(filename, "rb"); + if (!f) { + fprintf(stdout, "[ERROR] Failed to open %s for reading !!\n", filename); + return 0; + } + + /* BINARY */ + for (compno = 0; compno < volume->numcomps; compno++) { + int whl = w * h * l; + /* set volume data */ + comp = &volume->comps[compno]; + + /*if (comp->prec <= 8) { + if (!comp->sgnd) { + unsigned char *data = (unsigned char *) malloc(whl * sizeof(unsigned char)); + fread(data, 1, whl, f); + for (i = 0; i < whl; i++) { + comp->data[i] = data[i]; + if (comp->data[i] > max) + max = comp->data[i]; + } + free(data); + } else { + char *data = (char *) malloc(whl); + fread(data, 1, whl, f); + for (i = 0; i < whl; i++) { + comp->data[i] = data[i]; + if (comp->data[i] > max) + max = comp->data[i]; + } + free(data); + } + } else if (comp->prec <= 16) { + if (!comp->sgnd) { + unsigned short *data = (unsigned short *) malloc(whl * sizeof(unsigned short)); + int leido = fread(data, 2, whl, f); + if (!leido) { + free(data); fclose(f); + return NULL; + } + + for (i = 0; i < whl; i++) { + if (bigendian) //(c1 << 8) + c2; + comp->data[i] = data[i]; + else{ //(c2 << 8) + c1; + comp->data[i] = ShortSwap(data[i]); + } + if (comp->data[i] > max) + max = comp->data[i]; + } + free(data); + } else { + short *data = (short *) malloc(whl); + int leido = fread(data, 2, whl, f); + if (!leido) { + free(data); fclose(f); + return NULL; + } + for (i = 0; i < whl; i++) { + if (bigendian){ //(c1 << 8) + c2; + comp->data[i] = data[i]; + }else{ //(c2 << 8) + c1; + comp->data[i] = (short) ShortSwap((unsigned short) data[i]); + } + if (comp->data[i] > max) + max = comp->data[i]; + } + free(data); + } + } else { + if (!comp->sgnd) { + unsigned int *data = (unsigned int *) malloc(whl * sizeof(unsigned int)); + int leido = fread(data, 4, whl, f); + if (!leido) { + free(data); fclose(f); + return NULL; + } for (i = 0; i < whl; i++) { + if (!bigendian) + comp->data[i] = LongSwap(data[i]); + else + comp->data[i] = data[i]; + if (comp->data[i] > max) + max = comp->data[i]; + } + free(data); + } else { + int leido = fread(comp->data, 4, whl, f); + if (!leido) { + fclose(f); + return NULL; + } + for (i = 0; i < whl; i++) { + if (!bigendian) + comp->data[i] = (int) LongSwap((unsigned int) comp->data[i]); + if (comp->data[i] > max) + max = comp->data[i]; + } + } + }*/ + + for (i = 0; i < whl; i++) { + int v; + if (comp->prec <= 8) { + if (!comp->sgnd) { + v = readuchar(f); + } else { + v = (char) readuchar(f); + } + } else if (comp->prec <= 16) { + if (!comp->sgnd) { + v = readushort(f, bigendian); + } else { + v = (short) readushort(f, bigendian); + } + } else { + if (!comp->sgnd) { + v = readuint(f, bigendian); + } else { + v = (int) readuint(f, bigendian); + } + } + if (v > max) { + max = v; + } + comp->data[i] = v; + } + comp->bpp = int_floorlog2(max) + 1; + } + fclose(f); + return volume; +} + +int volumetobin(opj_volume_t * volume, char *outfile) +{ + int w, wr, wrr, h, hr, hrr, l, lr, lrr, max; + int i, j, compno, nbytes; + int offset, sliceno; + FILE *fdest = NULL; + FILE *fimgdest = NULL; + /* char *imgtemp;*/ + char name[256]; + + for (compno = 0; compno < 1; compno++) { /*Only one component*/ + + fdest = fopen(outfile, "wb"); + if (!fdest) { + fprintf(stdout, "[ERROR] Failed to open %s for writing\n", outfile); + return 1; + } + fprintf(stdout, "[INFO] Writing outfile %s (%s) \n", outfile, + volume->comps[0].bigendian ? "Bigendian" : "Little-endian"); + + w = int_ceildiv(volume->x1 - volume->x0, volume->comps[compno].dx); + wr = volume->comps[compno].w; + wrr = int_ceildivpow2(volume->comps[compno].w, volume->comps[compno].factor[0]); + + h = int_ceildiv(volume->y1 - volume->y0, volume->comps[compno].dy); + hr = volume->comps[compno].h; + hrr = int_ceildivpow2(volume->comps[compno].h, volume->comps[compno].factor[1]); + + l = int_ceildiv(volume->z1 - volume->z0, volume->comps[compno].dz); + lr = volume->comps[compno].l; + lrr = int_ceildivpow2(volume->comps[compno].l, volume->comps[compno].factor[2]); + + max = (volume->comps[compno].prec <= 8) ? 255 : (1 << + volume->comps[compno].prec) - 1; + + volume->comps[compno].x0 = int_ceildivpow2(volume->comps[compno].x0 - + int_ceildiv(volume->x0, volume->comps[compno].dx), + volume->comps[compno].factor[0]); + volume->comps[compno].y0 = int_ceildivpow2(volume->comps[compno].y0 - + int_ceildiv(volume->y0, volume->comps[compno].dy), + volume->comps[compno].factor[1]); + volume->comps[compno].z0 = int_ceildivpow2(volume->comps[compno].z0 - + int_ceildiv(volume->z0, volume->comps[compno].dz), + volume->comps[compno].factor[2]); + + if (volume->comps[0].prec <= 8) { + nbytes = 1; + } else if (volume->comps[0].prec <= 16) { + nbytes = 2; + } else { + nbytes = 4; + } + + /*fprintf(stdout,"w %d wr %d wrr %d h %d hr %d hrr %d l %d lr %d lrr %d max %d nbytes %d\n Factor %d %d %d",w,wr,wrr,h,hr,hrr,l,lr,lrr,max,nbytes,volume->comps[compno].factor[0],volume->comps[compno].factor[1],volume->comps[compno].factor[2]);*/ + + for (sliceno = 0; sliceno < lrr; sliceno++) { + offset = (sliceno / lrr * l) + (sliceno % lrr); + offset = wrr * hrr * offset; + for (i = 0; i < wrr * hrr; i++) { + int v = volume->comps[0].data[(i / wrr * w) + (i % wrr) + offset]; + if (volume->comps[0].bigendian) { + for (j = nbytes - 1; j >= 0; j--) { + char byte = (char)((v >> (j * 8)) & 0xff); + fwrite(&byte, 1, 1, fdest); + } + } else { + for (j = 0; j <= nbytes - 1; j++) { + char byte = (char)((v >> (j * 8)) & 0xff); + fwrite(&byte, 1, 1, fdest); + } + } + } + } + + } + + fclose(fdest); + + sprintf(name, "%s.img", outfile); + fimgdest = fopen(name, "w"); + if (!fimgdest) { + fprintf(stdout, "[ERROR] Failed to open %s for writing\n", name); + return 1; + } + fprintf(fimgdest, + "Bpp\t%d\nColor Map\t2\nDimensions\t%d\t%d\t%d\nResolution(mm)\t%d\t%d\t%d\t\n", + volume->comps[0].prec, wrr, hrr, lrr, volume->comps[0].dx, volume->comps[0].dy, + volume->comps[0].dz); + + fclose(fimgdest); + return 0; +} +/* -->> -->> -->> -->> + +IMG IMAGE FORMAT + +<<-- <<-- <<-- <<-- */ +opj_volume_t* imgtovolume(char *fileimg, opj_cparameters_t *parameters) +{ + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + int subsampling_dz = parameters->subsampling_dz; + + int i, compno, w, h, l, numcomps = 1; + int prec, max = 0, min = 0; + float dx, dy, dz; + char filename[100], tmpdirpath[100], dirpath[100], *tmp; + char line[100], datatype[100]; + int bigendian; + + FILE *f = NULL; + FILE *fimg = NULL; + OPJ_COLOR_SPACE color_space; + opj_volume_cmptparm_t cmptparm; /* maximum of 1 component */ + opj_volume_t * volume = NULL; + opj_volume_comp_t *comp = NULL; + + bigendian = 0; + color_space = CLRSPC_GRAY; + + fimg = fopen(fileimg, "r"); + if (!fimg) { + fprintf(stderr, "[ERROR] Failed to open %s for reading !!\n", fileimg); + return 0; + } + + /*Fetch only the path */ + strcpy(tmpdirpath, fileimg); + if ((tmp = strrchr(tmpdirpath, '/')) != NULL) { + tmp++; + *tmp = '\0'; + strcpy(dirpath, tmpdirpath); + } else { + strcpy(dirpath, "./"); + } + + fseek(fimg, 0, SEEK_SET); + while (!feof(fimg)) { + fgets(line, 100, fimg); + /*fprintf(stdout,"%s %d \n",line,feof(fimg));*/ + if (strncmp(line, "Image", 5) == 0) { + sscanf(line, "%*s%*[ \t]%s", datatype); + } else if (strncmp(line, "File", 4) == 0) { + sscanf(line, "%*s %*s%*[ \t]%s", filename); + strcat(dirpath, filename); + strcpy(filename, dirpath); + } else if (strncmp(line, "Min", 3) == 0) { + sscanf(line, "%*s %*s%*[ \t]%d%*[ \t]%d", &min, &max); + prec = int_floorlog2(max - min + 1); + } else if (strncmp(line, "Bpp", 3) == 0) { + sscanf(line, "%*s%*[ \t]%d", &prec); + } else if (strncmp(line, "Color", 5) == 0) { + sscanf(line, "%*s %*s%*[ \t]%d", &color_space); + } else if (strncmp(line, "Dim", 3) == 0) { + sscanf(line, "%*s%*[ \t]%d%*[ \t]%d%*[ \t]%d", &w, &h, &l); + } else if (strncmp(line, "Res", 3) == 0) { + sscanf(line, "%*s%*[ \t]%f%*[ \t]%f%*[ \t]%f", &dx, &dy, &dz); + } + + } +#ifdef VERBOSE + fprintf(stdout, "[INFO] %s %d \t %d %d %d \t %f %f %f \t %d %d %d \n", filename, + color_space, w, h, l, dx, dy, dz, max, min, prec); +#endif + fclose(fimg); + + /* error control */ + if (!prec || !w || !h || !l) { + fprintf(stderr, + "[ERROR] Unable to read IMG file correctly. Found some null values."); + return NULL; + } + + /* initialize volume components */ + memset(&cmptparm, 0, sizeof(opj_volume_cmptparm_t)); + + cmptparm.prec = prec; + cmptparm.bpp = prec; + cmptparm.sgnd = 0; + cmptparm.bigendian = bigendian; + cmptparm.dcoffset = parameters->dcoffset; + cmptparm.dx = subsampling_dx; + cmptparm.dy = subsampling_dy; + cmptparm.dz = subsampling_dz; + cmptparm.w = w; + cmptparm.h = h; + cmptparm.l = l; + + /* create the volume */ + volume = opj_volume_create(numcomps, &cmptparm, color_space); + if (!volume) { + fprintf(stdout, "[ERROR] Unable to create volume"); + return NULL; + } + + /* set volume offset and reference grid */ + volume->x0 = parameters->volume_offset_x0; + volume->y0 = parameters->volume_offset_y0; + volume->z0 = parameters->volume_offset_z0; + volume->x1 = parameters->volume_offset_x0 + (w - 1) * subsampling_dx + 1; + volume->y1 = parameters->volume_offset_y0 + (h - 1) * subsampling_dy + 1; + volume->z1 = parameters->volume_offset_z0 + (l - 1) * subsampling_dz + 1; + + max = 0; + /* set volume data */ + f = fopen(filename, "rb"); + if (!f) { + fprintf(stderr, "[ERROR] Failed to open %s for reading !!\n", filename); + fclose(f); + return 0; + } + + /* BINARY */ + for (compno = 0; compno < volume->numcomps; compno++) { + int whl = w * h * l; + /* set volume data */ + comp = &volume->comps[compno]; + + /*if (comp->prec <= 8) { + if (!comp->sgnd) { + unsigned char *data = (unsigned char *) malloc(whl * sizeof(unsigned char)); + fread(data, 1, whl, f); + for (i = 0; i < whl; i++) { + comp->data[i] = data[i]; + if (comp->data[i] > max) + max = comp->data[i]; + } + free(data); + } else { + char *data = (char *) malloc(whl); + fread(data, 1, whl, f); + for (i = 0; i < whl; i++) { + comp->data[i] = data[i]; + if (comp->data[i] > max) + max = comp->data[i]; + } + free(data); + } + } else if (comp->prec <= 16) { + if (!comp->sgnd) { + unsigned short *data = (unsigned short *) malloc(whl * sizeof(unsigned short)); + int leido = fread(data, 2, whl, f); + if (!leido) { + free(data); fclose(f); + return NULL; + } + + for (i = 0; i < whl; i++) { + if (bigendian) //(c1 << 8) + c2; + comp->data[i] = data[i]; + else{ //(c2 << 8) + c1; + comp->data[i] = ShortSwap(data[i]); + } + if (comp->data[i] > max) + max = comp->data[i]; + } + free(data); + } else { + short *data = (short *) malloc(whl); + int leido = fread(data, 2, whl, f); + if (!leido) { + free(data); fclose(f); + return NULL; + } + for (i = 0; i < whl; i++) { + if (bigendian){ //(c1 << 8) + c2; + comp->data[i] = data[i]; + }else{ //(c2 << 8) + c1; + comp->data[i] = (short) ShortSwap((unsigned short) data[i]); + } + if (comp->data[i] > max) + max = comp->data[i]; + } + free(data); + } + } else { + if (!comp->sgnd) { + unsigned int *data = (unsigned int *) malloc(whl * sizeof(unsigned int)); + int leido = fread(data, 4, whl, f); + if (!leido) { + free(data); fclose(f); + return NULL; + } for (i = 0; i < whl; i++) { + if (!bigendian) + comp->data[i] = LongSwap(data[i]); + else + comp->data[i] = data[i]; + if (comp->data[i] > max) + max = comp->data[i]; + } + free(data); + } else { + int leido = fread(comp->data, 4, whl, f); + if (!leido) { + fclose(f); + return NULL; + } + for (i = 0; i < whl; i++) { + if (!bigendian) + comp->data[i] = (int) LongSwap((unsigned int) comp->data[i]); + if (comp->data[i] > max) + max = comp->data[i]; + } + } + }*/ + + for (i = 0; i < whl; i++) { + int v; + if (comp->prec <= 8) { + if (!comp->sgnd) { + v = readuchar(f); + } else { + v = (char) readuchar(f); + } + } else if (comp->prec <= 16) { + if (!comp->sgnd) { + v = readushort(f, bigendian); + } else { + v = (short) readushort(f, bigendian); + } + } else { + if (!comp->sgnd) { + v = readuint(f, bigendian); + } else { + v = (int) readuint(f, bigendian); + } + } + if (v > max) { + max = v; + } + comp->data[i] = v; + } + comp->bpp = int_floorlog2(max) + 1; + } + fclose(f); + return volume; +} + diff --git a/openjpeg/src/bin/jp3d/convert.h b/openjpeg/src/bin/jp3d/convert.h new file mode 100644 index 000000000..1df170eba --- /dev/null +++ b/openjpeg/src/bin/jp3d/convert.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2006, Mónica Díez García, Image Processing Laboratory, University of Valladolid, Spain + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __JP3D_CONVERT_H +#define __JP3D_CONVERT_H + +/** +Load a single volume component encoded in PGX file format +@param filename Name of the PGX file to load +@param parameters *List ?* +@return Returns a greyscale volume if successful, returns NULL otherwise +*/ +opj_volume_t* pgxtovolume(char *filename, opj_cparameters_t *parameters); + +int volumetopgx(opj_volume_t *volume, char *outfile); + +opj_volume_t* bintovolume(char *filename, char *fileimg, + opj_cparameters_t *parameters); + +int volumetobin(opj_volume_t *volume, char *outfile); + +opj_volume_t* imgtovolume(char *fileimg, opj_cparameters_t *parameters); + +#endif /* __J2K_CONVERT_H */ + diff --git a/openjpeg/src/bin/jp3d/getopt.c b/openjpeg/src/bin/jp3d/getopt.c new file mode 100644 index 000000000..855b9ae5c --- /dev/null +++ b/openjpeg/src/bin/jp3d/getopt.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* last review : october 29th, 2002 */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95"; +#endif /* LIBC_SCCS and not lint */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int getopt(int nargc, char *const *nargv, const char *ostr) +{ + +# define __progname nargv[0] /* program name */ + + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++optind; + place = EMSG; + return (-1); + } + } /* option letter okay? */ + + if ((optopt = (int) * place++) == (int) ':' || !(oli = strchr(ostr, optopt))) { + /* if the user didn't specify '-' as an option, assume it means -1. */ + if (optopt == (int) '-') { + return (-1); + } + if (!*place) { + ++optind; + } + if (opterr && *ostr != ':') { + (void) fprintf(stdout, "[ERROR] %s: illegal option -- %c\n", __progname, + optopt); + } + return (BADCH); + } + + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) { + ++optind; + } + } else { /* need an argument */ + if (*place) { /* no white space */ + optarg = place; + } else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') { + return (BADARG); + } + if (opterr) { + (void) fprintf(stdout, "[ERROR] %s: option requires an argument -- %c\n", + __progname, optopt); + } + return (BADCH); + } else { /* white space */ + optarg = nargv[optind]; + } + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} diff --git a/openjpeg/src/bin/jp3d/getopt.h b/openjpeg/src/bin/jp3d/getopt.h new file mode 100644 index 000000000..935171ba4 --- /dev/null +++ b/openjpeg/src/bin/jp3d/getopt.h @@ -0,0 +1,14 @@ +/* last review : october 29th, 2002 */ + +#ifndef _GETOPT_H_ +#define _GETOPT_H_ + +extern int opterr; +extern int optind; +extern int optopt; +extern int optreset; +extern char *optarg; + +extern int getopt(int nargc, char *const *nargv, const char *ostr); + +#endif /* _GETOPT_H_ */ diff --git a/openjpeg/src/bin/jp3d/opj_jp3d_compress.c b/openjpeg/src/bin/jp3d/opj_jp3d_compress.c new file mode 100644 index 000000000..ea7ee7fc9 --- /dev/null +++ b/openjpeg/src/bin/jp3d/opj_jp3d_compress.c @@ -0,0 +1,989 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2006, Mónica Díez García, Image Processing Laboratory, University of Valladolid, Spain + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "opj_config.h" +#include "openjp3d.h" +#include "opj_getopt.h" +#include "convert.h" + +#ifdef _WIN32 +#include <windows.h> +#else +#define stricmp strcasecmp +#define strnicmp strncasecmp +#endif /* _WIN32 */ + +/* ----------------------------------------------------------------------- */ + +void encode_help_display() +{ + fprintf(stdout, "List of parameters for the JPEG2000 Part 10 encoder:\n"); + fprintf(stdout, "------------\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "Required Parameters (except with -h):\n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "-i : source file (-i source.bin or source*.pgx) \n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "-m : source characteristics file (-m imgfile.img) \n"); + fprintf(stdout, "\n"); + fprintf(stdout, "-o : destination file (-o dest.jp3d) \n"); + fprintf(stdout, "\n"); + fprintf(stdout, "Optional Parameters:\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "-h : display the help information \n "); + fprintf(stdout, "\n"); + fprintf(stdout, "-n : number of resolutions (-n 3,3,3) \n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "-I : use the irreversible transforms: ICT + DWT 9-7 (-I) \n"); + fprintf(stdout, "\n"); + fprintf(stdout, "-C : coding algorithm (-C 2EB) [2EB, 3EB] \n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "-r : different compression ratios for successive layers (-r 20,10,5)\n "); + fprintf(stdout, + " - The rate specified for each quality level is the desired compression factor.\n"); + fprintf(stdout, " - Rate 1 means lossless compression\n"); + fprintf(stdout, + " (options -r and -q cannot be used together)\n "); + fprintf(stdout, "\n"); + fprintf(stdout, + "-q : different psnr for successive layers (-q 30,40,50) \n "); + fprintf(stdout, + " (options -r and -q cannot be used together)\n "); + fprintf(stdout, "\n"); + fprintf(stdout, "-b : size of code block (-b 32,32,32) \n"); + fprintf(stdout, "\n"); + fprintf(stdout, "-c : size of precinct (-c 128,128,128) \n"); + fprintf(stdout, "\n"); + fprintf(stdout, "-t : size of tile (-t 512,512,512) \n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "-p : progression order (-p LRCP) [LRCP, RLCP, RPCL, PCRL, CPRL] \n"); + fprintf(stdout, "\n"); + fprintf(stdout, "-s : subsampling factor (-s 2,2,2) [-s X,Y,Z] \n"); + fprintf(stdout, " - Remark: subsampling bigger than 2 can produce error\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "-SOP : write SOP marker before each packet \n"); + fprintf(stdout, "\n"); + fprintf(stdout, "-EPH : write EPH marker after each header packet \n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "-M : code-block style (-M 0) [1=BYPASS(LAZY) 2=RESET 4=RESTART(TERMALL)\n"); + fprintf(stdout, " 8=VSC 16=PTERM 32=SEGSYM 64=3DCTXT] \n"); + fprintf(stdout, + " Indicate multiple modes by adding their values. \n"); + fprintf(stdout, + " ex: RESTART(4) + RESET(2) + SEGMARK(32) = -M 38\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "-D : define DC offset (-D 12) \n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "-x : create an index file *.Idx (-x index_name.Idx) \n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "-ROI : c=%%d,U=%%d : quantization indices upshifted \n"); + fprintf(stdout, " for component c=%%d [%%d = 0,1,2]\n"); + fprintf(stdout, + " with a value of U=%%d [0 <= %%d <= 37] (i.e. -ROI:c=0,U=25) \n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "-d : offset of the origin of the volume (-d 150,300,100) \n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "-l : offset of the origin of the tiles (-l 100,75,25) \n"); + fprintf(stdout, "\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "DEFAULT CODING:\n"); + fprintf(stdout, "------------\n"); + fprintf(stdout, "\n"); + fprintf(stdout, " * Lossless\n"); + fprintf(stdout, " * 1 tile\n"); + fprintf(stdout, + " * Size of precinct : 2^15 x 2^15 x 2^15 (means 1 precinct)\n"); + fprintf(stdout, " * Size of code-block : 64 x 64 x 64\n"); + fprintf(stdout, " * Number of resolutions in x, y and z axis: 3\n"); + fprintf(stdout, " * No SOP marker in the codestream\n"); + fprintf(stdout, " * No EPH marker in the codestream\n"); + fprintf(stdout, " * No sub-sampling in x, y or z direction\n"); + fprintf(stdout, " * No mode switch activated\n"); + fprintf(stdout, " * Progression order: LRCP\n"); + fprintf(stdout, " * No index file\n"); + fprintf(stdout, " * No ROI upshifted\n"); + fprintf(stdout, " * No offset of the origin of the volume\n"); + fprintf(stdout, " * No offset of the origin of the tiles\n"); + fprintf(stdout, " * Reversible DWT 5-3 on each 2D slice\n"); + fprintf(stdout, " * Coding algorithm: 2D-EBCOT \n"); + fprintf(stdout, "\n"); + fprintf(stdout, "REMARKS:\n"); + fprintf(stdout, "---------\n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "- The markers written to the main_header are : SOC SIZ COD QCD COM.\n"); + fprintf(stdout, + "- COD and QCD markers will never appear in the tile_header.\n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "- You need enough disk space memory (twice the original) to encode \n"); + fprintf(stdout, + "the volume,i.e. for a 1.5 GB volume you need a minimum of 3GB of disk memory)\n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "- When loading *.pgx files, a relative path to directory is needed for input argument \n"); + fprintf(stdout, + " followed by the common prefix of the slices and a '*' character representing sequential numeration.\n"); + fprintf(stdout, "( -i relativepath/slices*.pgx )\n"); + fprintf(stdout, "\n"); + fprintf(stdout, " - The index file has the structure below:\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "\t Image_height Image_width Image_depth\n"); + fprintf(stdout, "\t Progression order: 0 (LRCP)\n"); + fprintf(stdout, "\t Tiles_size_X Tiles_size_Y Tiles_size_Z\n"); + fprintf(stdout, "\t Components_nb\n"); + fprintf(stdout, "\t Layers_nb\n"); + fprintf(stdout, "\t Decomposition_levels\n"); + fprintf(stdout, + "\t [Precincts_size_X_res_Nr Precincts_size_Y_res_Nr Precincts_size_Z_res_Nr]\n\t ...\n"); + fprintf(stdout, + "\t [Precincts_size_X_res_0 Precincts_size_Y_res_0 Precincts_size_Z_res_0]\n"); + fprintf(stdout, "\t Main_header_end_position\n"); + fprintf(stdout, "\t Codestream_size\n"); + fprintf(stdout, + "\t Tile_0 [start_pos end_header end_pos TotalDisto NumPix MaxMSE]\n"); + fprintf(stdout, "\t ...\n"); + fprintf(stdout, + "\t Tile_Nt [ '' '' '' '' '' '' ]\n"); + fprintf(stdout, + "\t Tpacket_0 [Tile layer res. comp. prec. start_pos end_pos disto]\n"); + fprintf(stdout, "\t ...\n"); + fprintf(stdout, + "\t Tpacket_Np ['' '' '' '' '' '' '' '' ]\n"); + fprintf(stdout, "\t MaxDisto\n"); + fprintf(stdout, "\t TotalDisto\n\n"); + fprintf(stdout, "\n"); + +} + +OPJ_PROG_ORDER give_progression(char progression[4]) +{ + if (strncmp(progression, "LRCP", 4) == 0) { + return LRCP; + } + if (strncmp(progression, "RLCP", 4) == 0) { + return RLCP; + } + if (strncmp(progression, "RPCL", 4) == 0) { + return RPCL; + } + if (strncmp(progression, "PCRL", 4) == 0) { + return PCRL; + } + if (strncmp(progression, "CPRL", 4) == 0) { + return CPRL; + } + + return PROG_UNKNOWN; +} + +OPJ_TRANSFORM give_transform(char transform[4]) +{ + if (strncmp(transform, "2DWT", 4) == 0) { + return TRF_2D_DWT; + } + if (strncmp(transform, "3DWT", 4) == 0) { + return TRF_3D_DWT; + } + return TRF_UNKNOWN; +} + +OPJ_ENTROPY_CODING give_coding(char coding[3]) +{ + + if (strncmp(coding, "2EB", 3) == 0) { + return ENCOD_2EB; + } + if (strncmp(coding, "3EB", 3) == 0) { + return ENCOD_3EB; + } + /*if(strncmp(coding, "2GR", 3) == 0) { + return ENCOD_2GR; + } + if(strncmp(coding, "3GR", 3) == 0) { + return ENCOD_3GR; + }*/ + + return ENCOD_UNKNOWN; +} + +int get_file_format(char *filename) +{ + int i; + static const char *extension[] = {"pgx", "bin", "img", "j3d", "jp3d", "j2k"}; + static const int format[] = { PGX_DFMT, BIN_DFMT, IMG_DFMT, J3D_CFMT, J3D_CFMT, J2K_CFMT}; + char * ext = strrchr(filename, '.'); + if (ext) { + ext++; + for (i = 0; i < sizeof(format) / sizeof(*format); i++) { + if (strnicmp(ext, extension[i], 3) == 0) { + return format[i]; + } + } + } + + return -1; +} + +/* ------------------------------------------------------------------------------------ */ + +int parse_cmdline_encoder(int argc, char **argv, opj_cparameters_t *parameters) +{ + int i, value; + + /* parse the command line */ + + while (1) { + int c = opj_getopt(argc, argv, + "i:m:o:r:q:f:t:n:c:b:x:p:s:d:hP:S:E:M:D:R:l:T:C:A:I"); + if (c == -1) { + break; + } + switch (c) { + case 'i': { /* input file */ + char *infile = opj_optarg; + parameters->decod_format = get_file_format(infile); + switch (parameters->decod_format) { + case PGX_DFMT: + case BIN_DFMT: + case IMG_DFMT: + break; + default: + fprintf(stdout, + "[ERROR] Unrecognized format for infile : %s [accept only *.pgx or *.bin] !!\n\n", + infile); + return 1; + break; + } + strncpy(parameters->infile, infile, MAX_PATH); + fprintf(stdout, "[INFO] Infile: %s \n", parameters->infile); + + } + break; + + /* ----------------------------------------------------- */ + case 'm': { /* input IMG file */ + char *imgfile = opj_optarg; + int imgformat = get_file_format(imgfile); + switch (imgformat) { + case IMG_DFMT: + break; + default: + fprintf(stdout, + "[ERROR] Unrecognized format for imgfile : %s [accept only *.img] !!\n\n", + imgfile); + return 1; + break; + } + strncpy(parameters->imgfile, imgfile, MAX_PATH); + fprintf(stdout, "[INFO] Imgfile: %s Format: %d\n", parameters->imgfile, + imgformat); + } + break; + + /* ----------------------------------------------------- */ + case 'o': { /* output file */ + char *outfile = opj_optarg; + parameters->cod_format = get_file_format(outfile); + switch (parameters->cod_format) { + case J3D_CFMT: + case J2K_CFMT: + case LSE_CFMT: + break; + default: + fprintf(stdout, + "[ERROR] Unknown output format volume %s [only *.j2k, *.lse3d or *.jp3d]!! \n", + outfile); + return 1; + break; + } + strncpy(parameters->outfile, outfile, MAX_PATH); + fprintf(stdout, "[INFO] Outfile: %s \n", parameters->outfile); + } + break; + + /* ----------------------------------------------------- */ + + case 'r': { /* define compression rates for each layer */ + char *s = opj_optarg; + while (sscanf(s, "%f", ¶meters->tcp_rates[parameters->tcp_numlayers]) == + 1) { + parameters->tcp_numlayers++; + while (*s && *s != ',') { + s++; + } + if (!*s) { + break; + } + s++; + } + parameters->cp_disto_alloc = 1; + } + break; + + /* ----------------------------------------------------- */ + + case 'q': { /* define distorsion (PSNR) for each layer */ + char *s = opj_optarg; + while (sscanf(s, "%f", ¶meters->tcp_distoratio[parameters->tcp_numlayers]) + == 1) { + parameters->tcp_numlayers++; + while (*s && *s != ',') { + s++; + } + if (!*s) { + break; + } + s++; + } + parameters->cp_fixed_quality = 1; + } + break; + + /* ----------------------------------------------------- */ + + case 'f': { + fprintf(stdout, "/---------------------------------------------------\\\n"); + fprintf(stdout, "| Fixed layer allocation option not implemented !! |\n"); + fprintf(stdout, "\\---------------------------------------------------/\n"); + /*int *row = NULL, *col = NULL; + int numlayers = 0, matrix_width = 0; + + char *s = opj_optarg; + sscanf(s, "%d", &numlayers); + s++; + if (numlayers > 9) + s++; + + parameters->tcp_numlayers = numlayers; + matrix_width = parameters->numresolution[0] + parameters->numresolution[1] + parameters->numresolution[2]; + parameters->cp_matrice = (int *) malloc(numlayers * matrix_width * sizeof(int)); + s = s + 2; + + for (i = 0; i < numlayers; i++) { + row = ¶meters->cp_matrice[i * matrix_width]; + col = row; + parameters->tcp_rates[i] = 1; + sscanf(s, "%d,", &col[0]); + s += 2; + if (col[0] > 9) + s++; + col[1] = 0; + col[2] = 0; + for (j = 1; j < matrix_width; j++) { + col += 3; j+=2; + sscanf(s, "%d,%d,%d", &col[0], &col[1], &col[2]); + s += 6; + if (col[0] > 9) + s++; + if (col[1] > 9) + s++; + if (col[2] > 9) + s++; + } + if (i < numlayers - 1) + s++; + } + parameters->cp_fixed_alloc = 1; */ + } + break; + + /* ----------------------------------------------------- */ + + case 't': { /* tiles */ + if (sscanf(opj_optarg, "%d,%d,%d", ¶meters->cp_tdx, ¶meters->cp_tdy, + ¶meters->cp_tdz) != 3) { + fprintf(stdout, + "[ERROR] '-t' 'dimensions of tiles' argument error ! [-t tdx,tdy,tdz]\n"); + return 1; + } + parameters->tile_size_on = true; + } + break; + + /* ----------------------------------------------------- */ + + case 'n': { /* resolution */ + int aux; + aux = sscanf(opj_optarg, "%d,%d,%d", ¶meters->numresolution[0], + ¶meters->numresolution[1], ¶meters->numresolution[2]); + if (aux == 2) { + parameters->numresolution[2] = 1; + } else if (aux == 1) { + parameters->numresolution[1] = parameters->numresolution[0]; + parameters->numresolution[2] = 1; + } else if (aux == 0) { + parameters->numresolution[0] = 1; + parameters->numresolution[1] = 1; + parameters->numresolution[2] = 1; + } + } + break; + + /* ----------------------------------------------------- */ + case 'c': { /* precinct dimension */ + char sep; + int res_spec = 0; + int aux; + char *s = opj_optarg; + do { + sep = 0; + aux = sscanf(s, "[%d,%d,%d]%c", ¶meters->prct_init[0][res_spec], + ¶meters->prct_init[1][res_spec], ¶meters->prct_init[2][res_spec], &sep); + if (sep == ',' && aux != 4) { + fprintf(stdout, + "[ERROR] '-c' 'dimensions of precincts' argument error ! [-c [prcx_res0,prcy_res0,prcz_res0],...,[prcx_resN,prcy_resN,prcz_resN]]\n"); + return 1; + } + parameters->csty |= 0x01; + res_spec++; + s = strpbrk(s, "]") + 2; + } while (sep == ','); + parameters->res_spec = res_spec; /* number of precinct size specifications */ + } + break; + + /* ----------------------------------------------------- */ + + case 'b': { /* code-block dimension */ + int cblockw_init = 0, cblockh_init = 0, cblockl_init = 0; + if (sscanf(opj_optarg, "%d,%d,%d", &cblockw_init, &cblockh_init, + &cblockl_init) != 3) { + fprintf(stdout, + "[ERROR] '-b' 'dimensions of codeblocks' argument error ! [-b cblkx,cblky,cblkz]\n"); + return 1; + } + if (cblockw_init * cblockh_init * cblockl_init > (1 << 18) || + cblockw_init > 1024 || cblockw_init < 4 || cblockh_init > 1024 || + cblockh_init < 4 || cblockl_init > 1024 || cblockl_init < 4) { + fprintf(stdout, + "[ERROR] Size of code_block error (option -b) !!\n\nRestriction :\n * width*height*length<=4096\n * 4<=width,height,length<= 1024\n\n"); + return 1; + } + parameters->cblock_init[0] = cblockw_init; + parameters->cblock_init[1] = cblockh_init; + parameters->cblock_init[2] = cblockl_init; + } + break; + + /* ----------------------------------------------------- */ + + case 'x': { /* creation of index file */ + char *index = opj_optarg; + strncpy(parameters->index, index, MAX_PATH); + parameters->index_on = 1; + } + break; + + /* ----------------------------------------------------- */ + + case 'p': { /* progression order */ + char progression[4]; + + strncpy(progression, opj_optarg, 4); + parameters->prog_order = give_progression(progression); + if (parameters->prog_order == -1) { + fprintf(stdout, + "[ERROR] Unrecognized progression order [LRCP, RLCP, RPCL, PCRL, CPRL] !!\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 's': { /* subsampling factor */ + if (sscanf(opj_optarg, "%d,%d,%d", ¶meters->subsampling_dx, + ¶meters->subsampling_dy, ¶meters->subsampling_dz) != 3) { + fprintf(stdout, "[ERROR] '-s' sub-sampling argument error ! [-s dx,dy,dz]\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 'd': { /* coordonnate of the reference grid */ + if (sscanf(opj_optarg, "%d,%d,%d", ¶meters->volume_offset_x0, + ¶meters->volume_offset_y0, ¶meters->volume_offset_z0) != 3) { + fprintf(stdout, + "[ERROR] -d 'coordonnate of the reference grid' argument error !! [-d x0,y0,z0]\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 'h': { /* display an help description */ + encode_help_display(); + return 1; + } + break; + + /* ----------------------------------------------------- */ + + case 'P': { /* POC */ + int numpocs = 0; /* number of progression order change (POC) default 0 */ + opj_poc_t *POC = NULL; /* POC : used in case of Progression order change */ + + char *s = opj_optarg; + POC = parameters->POC; + + fprintf(stdout, "/----------------------------------\\\n"); + fprintf(stdout, "| POC option not fully tested !! |\n"); + fprintf(stdout, "\\----------------------------------/\n"); + + while (sscanf(s, "T%d=%d,%d,%d,%d,%d,%s", &POC[numpocs].tile, + &POC[numpocs].resno0, &POC[numpocs].compno0, + &POC[numpocs].layno1, &POC[numpocs].resno1, + &POC[numpocs].compno1, POC[numpocs].progorder) == 7) { + POC[numpocs].prg = give_progression(POC[numpocs].progorder); + /* POC[numpocs].tile; */ + numpocs++; + while (*s && *s != '/') { + s++; + } + if (!*s) { + break; + } + s++; + } + parameters->numpocs = numpocs; + } + break; + + /* ------------------------------------------------------ */ + + case 'S': { /* SOP marker */ + parameters->csty |= 0x02; + } + break; + + /* ------------------------------------------------------ */ + + case 'E': { /* EPH marker */ + parameters->csty |= 0x04; + } + break; + + /* ------------------------------------------------------ */ + + case 'M': { /* Codification mode switch */ + fprintf(stdout, "[INFO] Mode switch option not fully tested !!\n"); + value = 0; + if (sscanf(opj_optarg, "%d", &value) == 1) { + for (i = 0; i <= 6; i++) { + int cache = value & (1 << i); + if (cache) { + parameters->mode |= (1 << i); + } + } + } + } + break; + + /* ------------------------------------------------------ */ + + case 'D': { /* DCO */ + if (sscanf(opj_optarg, "%d", ¶meters->dcoffset) != 1) { + fprintf(stdout, "[ERROR] DC offset error !! [-D %d]\n", parameters->dcoffset); + return 1; + } + } + break; + + /* ------------------------------------------------------ */ + + case 'R': { /* ROI */ + if (sscanf(opj_optarg, "OI:c=%d,U=%d", ¶meters->roi_compno, + ¶meters->roi_shift) != 2) { + fprintf(stdout, "[ERROR] ROI error !! [-ROI:c='compno',U='shift']\n"); + return 1; + } + } + break; + + /* ------------------------------------------------------ */ + + case 'l': { /* Tile offset */ + if (sscanf(opj_optarg, "%d,%d,%d", ¶meters->cp_tx0, ¶meters->cp_ty0, + ¶meters->cp_tz0) != 3) { + fprintf(stdout, "[ERROR] -l 'tile offset' argument error !! [-l X0,Y0,Z0]"); + return 1; + } + } + break; + + /* ------------------------------------------------------ + + case 'T': // Transformation of original data (2D-DWT/3D-DWT/3D-RLS/2D-DWT+1D-RLS) + { + char transform[4]; + + strncpy(transform, opj_optarg, 4); + parameters->transform_format = give_transform(transform); + if (parameters->transform_format == -1) { + fprintf(stdout, "[ERROR] -T 'Transform domain' argument error !! [-T 2DWT, 3DWT, 3RLS or 3LSE only]"); + return 1; + } + } + break; + + ------------------------------------------------------ */ + + case 'C': { /* Coding of transformed data */ + char coding[3]; + + strncpy(coding, opj_optarg, 3); + parameters->encoding_format = give_coding(coding); + if (parameters->encoding_format == -1) { + fprintf(stdout, + "[ERROR] -C 'Coding algorithm' argument error !! [-C 2EB, 3EB, 2GR, 3GR or GRI only]"); + return 1; + } + } + break; + + /* ------------------------------------------------------ */ + + case 'I': { /* reversible or not */ + parameters->irreversible = 1; + } + break; + + default: + fprintf(stdout, "[ERROR] This option is not valid \"-%c %s\"\n", c, opj_optarg); + return 1; + } + } + + /* check for possible errors */ + + if ((parameters->infile[0] == 0) || (parameters->outfile[0] == 0)) { + fprintf(stdout, "usage: jp3d_vm_enc -i volume-file -o jp3d-file (+ options)\n"); + return 1; + } + + if ((parameters->decod_format == BIN_DFMT) && (parameters->imgfile[0] == 0)) { + fprintf(stdout, + "usage: jp3d_vm_enc -i bin-volume-file -m img-file -o jp3d-file (+ options)\n"); + return 1; + } + + if ((parameters->decod_format != BIN_DFMT) && + (parameters->decod_format != PGX_DFMT) && + (parameters->decod_format != IMG_DFMT)) { + fprintf(stdout, + "usage: jp3d_vm_enc -i input-volume-file [*.bin,*.pgx,*.img] -o jp3d-file [*.jp3d,*.j2k] (+ options)\n"); + return 1; + } + if ((parameters->cod_format != J3D_CFMT) && + (parameters->cod_format != J2K_CFMT)) { + fprintf(stdout, + "usage: jp3d_vm_enc -i input-volume-file [*.bin,*.pgx,*.img] -o jp3d-file [*.jp3d,*.j2k] (+ options)\n"); + return 1; + } + + if ((parameters->encoding_format == ENCOD_2GR || + parameters->encoding_format == ENCOD_3GR) && + parameters->transform_format != TRF_3D_LSE && + parameters->transform_format != TRF_3D_RLS) { + fprintf(stdout, + "[ERROR] Entropy coding options -C [2GR,3GR] are only compatible with predictive-based transform algorithms: -T [3RLS,3LSE].\n"); + return 1; + } + if (parameters->encoding_format == ENCOD_3EB) { + parameters->mode |= (1 << 6); + } + + if ((parameters->mode >> 6) & 1) { + parameters->encoding_format = ENCOD_3EB; + } + + if ((parameters->numresolution[2] == 0 || (parameters->numresolution[1] == 0) || + (parameters->numresolution[0] == 0))) { + fprintf(stdout, + "[ERROR] -n 'resolution levels' argument error ! Resolutions must be greater than 1 in order to perform DWT.\n"); + return 1; + } + if (parameters->numresolution[1] != parameters->numresolution[0]) { + fprintf(stdout, + "[ERROR] -n 'resolution levels' argument error ! Resolutions in X and Y axis must be the same in this implementation.\n"); + return 1; + } + + if (parameters->numresolution[2] > parameters->numresolution[0]) { + fprintf(stdout, + "[ERROR] -n 'resolution levels' argument error ! Resolutions in Z axis must be lower than in X-Y axis.\n"); + return 1; + } + + if (parameters->dcoffset >= 128 && parameters->dcoffset <= -128) { + fprintf(stdout, + "[ERROR] -D 'DC offset' argument error ! Value must be -128<=DCO<=128.\n"); + return 1; + } + + if (parameters->numresolution[2] != 1) { + parameters->transform_format = TRF_3D_DWT; + /*fprintf(stdout, "[Warning] Resolution level in axial dim > 1 : 3D-DWT will be performed... \n");*/ + } else if (parameters->numresolution[2] == 1) { + parameters->transform_format = TRF_2D_DWT; + /*fprintf(stdout, "[Warning] Resolution level in axial dim == 1 : 2D-DWT will be performed... \n");*/ + } + + if ((parameters->cod_format == J2K_CFMT) && + (parameters->transform_format != TRF_2D_DWT || + parameters->encoding_format != ENCOD_2EB)) { + fprintf(stdout, + "[WARNING] Incompatible options -o *.j2k and defined transform or encoding algorithm. Latter will be ignored\n"); + parameters->transform_format = TRF_2D_DWT; + parameters->encoding_format = ENCOD_2EB; + } + + if ((parameters->cp_disto_alloc || parameters->cp_fixed_alloc || + parameters->cp_fixed_quality) && + (!(parameters->cp_disto_alloc ^ parameters->cp_fixed_quality))) { + fprintf(stdout, "[ERROR] Options -r and -q cannot be used together !!\n"); + return 1; + } /* mod fixed_quality */ + + /* if no rate entered, lossless by default */ + if (parameters->tcp_numlayers == 0) { + parameters->tcp_rates[0] = 0.0; /* MOD antonin : losslessbug */ + parameters->tcp_numlayers++; + parameters->cp_disto_alloc = 1; + } + + if ((parameters->cp_tx0 > parameters->volume_offset_x0) || + (parameters->cp_ty0 > parameters->volume_offset_y0) || + (parameters->cp_tz0 > parameters->volume_offset_z0)) { + fprintf(stdout, + "[ERROR] Tile offset dimension is unnappropriate --> TX0(%d)<=IMG_X0(%d) TYO(%d)<=IMG_Y0(%d) TZO(%d)<=IMG_Z0(%d)\n", + parameters->cp_tx0, parameters->volume_offset_x0, parameters->cp_ty0, + parameters->volume_offset_y0, + parameters->cp_tz0, parameters->volume_offset_z0); + return 1; + } + + for (i = 0; i < parameters->numpocs; i++) { + if (parameters->POC[i].prg == -1) { + fprintf(stdout, + "[ERROR] Unrecognized progression order in option -P (POC n %d) [LRCP, RLCP, RPCL, PCRL, CPRL] !!\n", + i + 1); + } + } + return 0; +} + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) +{ + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) +{ + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting a FILE* client object +*/ +void info_callback(const char *msg, void *client_data) +{ + FILE *stream = (FILE*)client_data; + fprintf(stream, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + +int main(int argc, char **argv) +{ + bool bSuccess; + bool delete_comment = true; + opj_cparameters_t parameters; /* compression parameters */ + opj_event_mgr_t event_mgr; /* event manager */ + opj_volume_t *volume = NULL; + + /* + configure the event callbacks (not required) + setting of each callback is optional + */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* set encoding parameters to default values */ + opj_set_default_encoder_parameters(¶meters); + + /* parse input and get user encoding parameters */ + if (parse_cmdline_encoder(argc, argv, ¶meters) == 1) { + return 0; + } + + if (parameters.cp_comment == NULL) { + parameters.cp_comment = "Created by OpenJPEG version JP3D"; + /* no need to delete parameters.cp_comment on exit */ + delete_comment = false; + } + + /* encode the destination volume */ + /* ---------------------------- */ + if (parameters.cod_format == J3D_CFMT || parameters.cod_format == J2K_CFMT) { + int codestream_length, pixels, bitsin; + opj_cio_t *cio = NULL; + FILE *f = NULL; + opj_cinfo_t* cinfo = NULL; + + /* decode the source volume */ + /* ----------------------- */ + switch (parameters.decod_format) { + case PGX_DFMT: + fprintf(stdout, "[INFO] Loading pgx file(s)\n"); + volume = pgxtovolume(parameters.infile, ¶meters); + if (!volume) { + fprintf(stdout, "[ERROR] Unable to load pgx files\n"); + return 1; + } + break; + + case BIN_DFMT: + fprintf(stdout, "[INFO] Loading bin file\n"); + volume = bintovolume(parameters.infile, parameters.imgfile, ¶meters); + if (!volume) { + fprintf(stdout, "[ERROR] Unable to load bin file\n"); + return 1; + } + break; + + case IMG_DFMT: + fprintf(stdout, "[INFO] Loading img file\n"); + volume = imgtovolume(parameters.infile, ¶meters); + if (!volume) { + fprintf(stderr, "[ERROR] Unable to load img file\n"); + return 1; + } + break; + } + + /* get a JP3D or J2K compressor handle */ + if (parameters.cod_format == J3D_CFMT) { + cinfo = opj_create_compress(CODEC_J3D); + } else if (parameters.cod_format == J2K_CFMT) { + cinfo = opj_create_compress(CODEC_J2K); + } + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stdout); + + /* setup the encoder parameters using the current volume and using user parameters */ + opj_setup_encoder(cinfo, ¶meters, volume); + + /* open a byte stream for writing */ + /* allocate memory for all tiles */ + cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0); + + /* encode the volume */ + /*fprintf(stdout, "[INFO] Encode the volume\n");*/ + bSuccess = opj_encode(cinfo, cio, volume, parameters.index); + if (!bSuccess) { + opj_cio_close(cio); + fprintf(stdout, "[ERROR] Failed to encode volume\n"); + return 1; + } + codestream_length = cio_tell(cio); + pixels = (volume->x1 - volume->x0) * (volume->y1 - volume->y0) * + (volume->z1 - volume->z0); + bitsin = pixels * volume->comps[0].prec; + fprintf(stdout, + "[RESULT] Volume: %d x %d x %d (x %d bpv)\n Codestream: %d B, Ratio: %5.3f bpv, (%5.3f : 1) \n", + (volume->x1 - volume->x0), (volume->y1 - volume->y0), (volume->z1 - volume->z0), + volume->comps[0].prec, + codestream_length, ((double)codestream_length * 8.0 / (double)pixels), + ((double)bitsin / (8.0 * (double)codestream_length))); + + /* write the buffer to disk */ + f = fopen(parameters.outfile, "wb"); + if (!f) { + fprintf(stdout, "[ERROR] Failed to open %s for writing\n", parameters.outfile); + return 1; + } + fwrite(cio->buffer, 1, codestream_length, f); + fclose(f); + + /* close and free the byte stream */ + opj_cio_close(cio); + + /* free remaining compression structures */ + opj_destroy_compress(cinfo); + } else { + fprintf(stdout, "[ERROR] Cod_format != JP3d !!! \n"); + return 1; + } + + /* free user parameters structure */ + if (delete_comment) { + if (parameters.cp_comment) { + free(parameters.cp_comment); + } + } + if (parameters.cp_matrice) { + free(parameters.cp_matrice); + } + + /* free volume data */ + opj_volume_destroy(volume); + + return 0; +} diff --git a/openjpeg/src/bin/jp3d/opj_jp3d_decompress.c b/openjpeg/src/bin/jp3d/opj_jp3d_decompress.c new file mode 100644 index 000000000..08d6ced2a --- /dev/null +++ b/openjpeg/src/bin/jp3d/opj_jp3d_decompress.c @@ -0,0 +1,601 @@ +/* + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2005, Francois Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2002-2005, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium + * Copyright (c) 2006, Mónica Díez García, Image Processing Laboratory, University of Valladolid, Spain + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <math.h> + +#include "opj_config.h" +#include "openjp3d.h" +#include "opj_getopt.h" +#include "convert.h" + +#ifdef _WIN32 +#include <windows.h> +#else +#define stricmp strcasecmp +#define strnicmp strncasecmp +#endif /* _WIN32 */ + +/* ----------------------------------------------------------------------- */ +static double calc_PSNR(opj_volume_t *original, opj_volume_t *decoded) +{ + int max, i, k, compno = 0, size; + double sum, total = 0; + int global = 1; + + max = (original->comps[compno].prec <= 8) ? 255 : (1 << + original->comps[compno].prec) - 1; + if (global) { + size = (original->x1 - original->x0) * (original->y1 - original->y0) * + (original->z1 - original->z0); + + for (compno = 0; compno < original->numcomps; compno++) { + for (sum = 0, i = 0; i < size; ++i) { + if ((decoded->comps[compno].data[i] < 0) || + (decoded->comps[compno].data[i] > max)) { + fprintf(stdout, "[WARNING] Data out of range during PSNR computing...\n"); + } else { + sum += (original->comps[compno].data[i] - decoded->comps[compno].data[i]) * + (original->comps[compno].data[i] - decoded->comps[compno].data[i]); + } + } + } + sum /= size; + total = ((sum == 0.0) ? 0.0 : 10 * log10(max * max / sum)); + } else { + size = (original->x1 - original->x0) * (original->y1 - original->y0); + + for (k = 0; k < original->z1 - original->z0; k++) { + int offset = k * size; + for (sum = 0, compno = 0; compno < original->numcomps; compno++) { + for (i = 0; i < size; ++i) { + if ((decoded->comps[compno].data[i + offset] < 0) || + (decoded->comps[compno].data[i + offset] > max)) { + fprintf(stdout, "[WARNING] Data out of range during PSNR computing...\n"); + } else { + sum += (original->comps[compno].data[i + offset] - decoded->comps[compno].data[i + + offset]) * (original->comps[compno].data[i + offset] - + decoded->comps[compno].data[i + offset]); + } + } + } + sum /= size; + total = total + ((sum == 0.0) ? 0.0 : 10 * log10(max * max / sum)); + } + + } + if (total == 0) { /* perfect reconstruction, PSNR should return infinity */ + return -1.0; + } + + return total; + /*return 20 * log10((max - 1) / sqrt(sum));*/ +} + +static double calc_SSIM(opj_volume_t *original, opj_volume_t *decoded) +{ + int max, i, compno = 0, size, sizeM; + double sum; + double mux = 0.0, muy = 0.0, sigmax = 0.0, sigmay = 0.0, + sigmaxy = 0.0/*, structx = 0.0, structy = 0.0*/; + double lcomp, ccomp, scomp; + double C1, C2, C3; + + max = (original->comps[compno].prec <= 8) ? 255 : (1 << + original->comps[compno].prec) - 1; + size = (original->x1 - original->x0) * (original->y1 - original->y0) * + (original->z1 - original->z0); + + /*MSSIM*/ + + /* sizeM = size / (original->z1 - original->z0);*/ + + sizeM = size; + for (sum = 0, i = 0; i < sizeM; ++i) { + /* First, the luminance of each signal is compared.*/ + mux += original->comps[compno].data[i]; + muy += decoded->comps[compno].data[i]; + } + mux /= sizeM; + muy /= sizeM; + + /*We use the standard deviation (the square root of variance) as an estimate of the signal contrast.*/ + for (sum = 0, i = 0; i < sizeM; ++i) { + /* First, the luminance of each signal is compared.*/ + sigmax += (original->comps[compno].data[i] - mux) * + (original->comps[compno].data[i] - mux); + sigmay += (decoded->comps[compno].data[i] - muy) * + (decoded->comps[compno].data[i] - muy); + sigmaxy += (original->comps[compno].data[i] - mux) * + (decoded->comps[compno].data[i] - muy); + } + sigmax /= sizeM - 1; + sigmay /= sizeM - 1; + sigmaxy /= sizeM - 1; + + sigmax = sqrt(sigmax); + sigmay = sqrt(sigmay); + sigmaxy = sqrt(sigmaxy); + + /*Third, the signal is normalized (divided) by its own standard deviation, */ + /*so that the two signals being compared have unit standard deviation.*/ + + /*Luminance comparison*/ + C1 = (0.01 * max) * (0.01 * max); + lcomp = ((2 * mux * muy) + C1) / ((mux * mux) + (muy * mux) + C1); + /*Constrast comparison*/ + C2 = (0.03 * max) * (0.03 * max); + ccomp = ((2 * sigmax * sigmay) + C2) / ((sigmax * sigmax) + + (sigmay * sigmay) + C2); + /*Structure comparison*/ + C3 = C2 / 2; + scomp = (sigmaxy + C3) / (sigmax * sigmay + C3); + /*Similarity measure*/ + + sum = lcomp * ccomp * scomp; + return sum; +} + +void decode_help_display() +{ + fprintf(stdout, "HELP\n----\n\n"); + fprintf(stdout, "- the -h option displays this help information on screen\n\n"); + + fprintf(stdout, "List of parameters for the JPEG 2000 encoder:\n"); + fprintf(stdout, "\n"); + fprintf(stdout, " Required arguments \n"); + fprintf(stdout, " ---------------------------- \n"); + fprintf(stdout, " -i <compressed file> ( *.jp3d, *.j3d )\n"); + fprintf(stdout, + " Currently accepts J3D-files. The file type is identified based on its suffix.\n"); + fprintf(stdout, " -o <decompressed file> ( *.pgx, *.bin )\n"); + fprintf(stdout, + " Currently accepts PGX-files and BIN-files. Binary data is written to the file (not ascii). \n"); + fprintf(stdout, + " If a PGX filename is given, there will be as many output files as slices; \n"); + fprintf(stdout, + " an indice starting from 0 will then be appended to the output filename,\n"); + fprintf(stdout, " just before the \"pgx\" extension.\n"); + fprintf(stdout, " -m <characteristics file> ( *.img ) \n"); + fprintf(stdout, + " Required only for BIN-files. Ascii data of volume characteristics is written. \n"); + fprintf(stdout, "\n"); + fprintf(stdout, " Optional \n"); + fprintf(stdout, " ---------------------------- \n"); + fprintf(stdout, " -h \n "); + fprintf(stdout, " Display the help information\n"); + fprintf(stdout, " -r <RFx,RFy,RFz>\n"); + fprintf(stdout, + " Set the number of highest resolution levels to be discarded on each dimension. \n"); + fprintf(stdout, + " The volume 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 <number of quality layers to decode>\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, " -O original-file \n"); + fprintf(stdout, + " This option offers the possibility to compute some quality results \n"); + fprintf(stdout, + " for the decompressed volume, like the PSNR value achieved or the global SSIM value. \n"); + fprintf(stdout, + " Needs the original file in order to compare with the new one.\n"); + fprintf(stdout, + " NOTE: Only valid when -r option is 0,0,0 (both original and decompressed volumes have same resolutions) \n"); + fprintf(stdout, + " NOTE: If original file is .BIN file, the volume characteristics file shall be defined with the -m option. \n"); + fprintf(stdout, " (i.e. -O original-BIN-file -m original-IMG-file) \n"); + fprintf(stdout, " -BE \n"); + fprintf(stdout, + " Define that the recovered volume data will be saved with big endian byte order.\n"); + fprintf(stdout, " By default, little endian byte order is used.\n"); + fprintf(stdout, "\n"); +} + +/* -------------------------------------------------------------------------- */ + +int get_file_format(char *filename) +{ + int i; + static const char *extension[] = {"pgx", "bin", "j3d", "jp3d", "j2k", "img"}; + static const int format[] = { PGX_DFMT, BIN_DFMT, J3D_CFMT, J3D_CFMT, J2K_CFMT, IMG_DFMT}; + char * ext = strrchr(filename, '.'); + if (ext) { + ext++; + for (i = 0; i < sizeof(format) / sizeof(format[0]); i++) { + if (strnicmp(ext, extension[i], 3) == 0) { + return format[i]; + } + } + } + + return -1; +} + +/* -------------------------------------------------------------------------- */ + +int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters) +{ + /* parse the command line */ + + while (1) { + int c = opj_getopt(argc, argv, "i:o:O:r:l:B:m:h"); + if (c == -1) { + break; + } + switch (c) { + case 'i': { /* input file */ + char *infile = opj_optarg; + parameters->decod_format = get_file_format(infile); + switch (parameters->decod_format) { + case J3D_CFMT: + case J2K_CFMT: + break; + default: + fprintf(stdout, "[ERROR] Unknown format for infile %s [only *.j3d]!! \n", + infile); + return 1; + break; + } + strncpy(parameters->infile, infile, MAX_PATH); + fprintf(stdout, "[INFO] Infile: %s \n", parameters->infile); + + } + break; + + case 'm': { /* img file */ + char *imgfile = opj_optarg; + int imgformat = get_file_format(imgfile); + switch (imgformat) { + case IMG_DFMT: + break; + default: + fprintf(stdout, + "[ERROR] Unrecognized format for imgfile : %s [accept only *.img] !!\n\n", + imgfile); + return 1; + break; + } + strncpy(parameters->imgfile, imgfile, MAX_PATH); + fprintf(stdout, "[INFO] Imgfile: %s Format: %d\n", parameters->imgfile, + imgformat); + } + break; + + /* ----------------------------------------------------- */ + + case 'o': { /* output file */ + char *outfile = opj_optarg; + parameters->cod_format = get_file_format(outfile); + switch (parameters->cod_format) { + case PGX_DFMT: + case BIN_DFMT: + break; + default: + fprintf(stdout, + "[ERROR] Unrecognized format for outfile : %s [accept only *.pgx or *.bin] !!\n\n", + outfile); + return 1; + break; + } + strncpy(parameters->outfile, outfile, MAX_PATH); + fprintf(stdout, "[INFO] Outfile: %s \n", parameters->outfile); + + } + break; + + /* ----------------------------------------------------- */ + + case 'O': { /* Original image for PSNR computing */ + char *original = opj_optarg; + parameters->orig_format = get_file_format(original); + switch (parameters->orig_format) { + case PGX_DFMT: + case BIN_DFMT: + break; + default: + fprintf(stdout, + "[ERROR] Unrecognized format for original file : %s [accept only *.pgx or *.bin] !!\n\n", + original); + return 1; + break; + } + strncpy(parameters->original, original, MAX_PATH); + fprintf(stdout, "[INFO] Original file: %s \n", parameters->original); + } + break; + + /* ----------------------------------------------------- */ + + case 'r': { /* reduce option */ + /*sscanf(opj_optarg, "%d, %d, %d", ¶meters->cp_reduce[0], ¶meters->cp_reduce[1], ¶meters->cp_reduce[2]);*/ + int aux; + aux = sscanf(opj_optarg, "%d,%d,%d", ¶meters->cp_reduce[0], + ¶meters->cp_reduce[1], ¶meters->cp_reduce[2]); + if (aux == 2) { + parameters->cp_reduce[2] = 0; + } else if (aux == 1) { + parameters->cp_reduce[1] = parameters->cp_reduce[0]; + parameters->cp_reduce[2] = 0; + } else if (aux == 0) { + parameters->cp_reduce[0] = 0; + parameters->cp_reduce[1] = 0; + parameters->cp_reduce[2] = 0; + } + } + break; + + /* ----------------------------------------------------- */ + + case 'l': { /* layering option */ + sscanf(opj_optarg, "%d", ¶meters->cp_layer); + } + break; + + /* ----------------------------------------------------- */ + + case 'B': { /* BIGENDIAN vs. LITTLEENDIAN */ + parameters->bigendian = 1; + } + break; + + /* ----------------------------------------------------- */ + + case 'L': { /* BIGENDIAN vs. LITTLEENDIAN */ + parameters->decod_format = LSE_CFMT; + } + break; + + /* ----------------------------------------------------- */ + + case 'h': { /* display an help description */ + decode_help_display(); + return 1; + } + break; + + /* ----------------------------------------------------- */ + + default: + fprintf(stdout, "[WARNING] This option is not valid \"-%c %s\"\n", c, + opj_optarg); + break; + } + } + + /* check for possible errors */ + + if ((parameters->infile[0] == 0) || (parameters->outfile[0] == 0)) { + fprintf(stdout, + "[ERROR] At least one required argument is missing\n Check jp3d_to_volume -help for usage information\n"); + return 1; + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) +{ + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) +{ + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting no client object +*/ +void info_callback(const char *msg, void *client_data) +{ + fprintf(stdout, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + +int main(int argc, char **argv) +{ + + opj_dparameters_t parameters; /* decompression parameters */ + opj_event_mgr_t event_mgr; /* event manager */ + opj_volume_t *volume = NULL; + + opj_volume_t *original = NULL; + opj_cparameters_t cparameters; /* original parameters */ + + FILE *fsrc = NULL; + unsigned char *src = NULL; + int file_length; + int decodeok; + double psnr, ssim; + + opj_dinfo_t* dinfo = NULL; /* handle to a decompressor */ + opj_cio_t *cio = NULL; + + /* configure the event callbacks (not required) */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* set decoding parameters to default values */ + opj_set_default_decoder_parameters(¶meters); + + /* parse input and get user decoding parameters */ + strcpy(parameters.original, "NULL"); + strcpy(parameters.imgfile, "NULL"); + if (parse_cmdline_decoder(argc, argv, ¶meters) == 1) { + return 0; + } + + /* read the input file and put it in memory */ + /* ---------------------------------------- */ + fprintf(stdout, "[INFO] Loading %s file \n", + parameters.decod_format == J3D_CFMT ? ".jp3d" : ".j2k"); + fsrc = fopen(parameters.infile, "rb"); + if (!fsrc) { + fprintf(stdout, "[ERROR] Failed to open %s for reading\n", parameters.infile); + return 1; + } + fseek(fsrc, 0, SEEK_END); + file_length = ftell(fsrc); + fseek(fsrc, 0, SEEK_SET); + src = (unsigned char *) malloc(file_length); + fread(src, 1, file_length, fsrc); + fclose(fsrc); + + /* decode the code-stream */ + /* ---------------------- */ + if (parameters.decod_format == J3D_CFMT || + parameters.decod_format == J2K_CFMT) { + /* get a JP3D or J2K decoder handle */ + if (parameters.decod_format == J3D_CFMT) { + dinfo = opj_create_decompress(CODEC_J3D); + } else if (parameters.decod_format == J2K_CFMT) { + dinfo = opj_create_decompress(CODEC_J2K); + } + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); + + /* decode the stream and fill the volume structure */ + volume = opj_decode(dinfo, cio); + if (!volume) { + fprintf(stdout, "[ERROR] jp3d_to_volume: failed to decode volume!\n"); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + return 1; + } + + /* close the byte stream */ + opj_cio_close(cio); + } + + /* free the memory containing the code-stream */ + free(src); + src = NULL; + + /* create output volume */ + /* ------------------- */ + + switch (parameters.cod_format) { + case PGX_DFMT: /* PGX */ + decodeok = volumetopgx(volume, parameters.outfile); + if (decodeok) { + fprintf(stdout, "[ERROR] Unable to write decoded volume into pgx files\n"); + } + break; + + case BIN_DFMT: /* BMP */ + decodeok = volumetobin(volume, parameters.outfile); + if (decodeok) { + fprintf(stdout, "[ERROR] Unable to write decoded volume into pgx files\n"); + } + break; + } + switch (parameters.orig_format) { + case PGX_DFMT: /* PGX */ + if (strcmp("NULL", parameters.original) != 0) { + fprintf(stdout, "Loading original file %s \n", parameters.original); + cparameters.subsampling_dx = 1; + cparameters.subsampling_dy = 1; + cparameters.subsampling_dz = 1; + cparameters.volume_offset_x0 = 0; + cparameters.volume_offset_y0 = 0; + cparameters.volume_offset_z0 = 0; + original = pgxtovolume(parameters.original, &cparameters); + } + break; + + case BIN_DFMT: /* BMP */ + if (strcmp("NULL", parameters.original) != 0 && + strcmp("NULL", parameters.imgfile) != 0) { + fprintf(stdout, "Loading original file %s %s\n", parameters.original, + parameters.imgfile); + cparameters.subsampling_dx = 1; + cparameters.subsampling_dy = 1; + cparameters.subsampling_dz = 1; + cparameters.volume_offset_x0 = 0; + cparameters.volume_offset_y0 = 0; + cparameters.volume_offset_z0 = 0; + original = bintovolume(parameters.original, parameters.imgfile, &cparameters); + } + break; + } + + fprintf(stdout, "[RESULT] Volume: %d x %d x %d (x %d bpv)\n ", + (volume->comps[0].w >> volume->comps[0].factor[0]), + (volume->comps[0].h >> volume->comps[0].factor[1]), + (volume->comps[0].l >> volume->comps[0].factor[2]), + volume->comps[0].prec); + + if (original) { + psnr = calc_PSNR(original, volume); + ssim = calc_SSIM(original, volume); + if (psnr < 0.0) { + fprintf(stdout, " PSNR: Inf , SSMI %f -- Perfect reconstruction!\n", ssim); + } else { + fprintf(stdout, " PSNR: %f , SSIM %f \n", psnr, ssim); + } + } + /* free remaining structures */ + if (dinfo) { + opj_destroy_decompress(dinfo); + } + + /* free volume data structure */ + opj_volume_destroy(volume); + + return 0; +} + diff --git a/openjpeg/src/bin/jp3d/tcltk/LPI_JP3D_VM.tcl b/openjpeg/src/bin/jp3d/tcltk/LPI_JP3D_VM.tcl new file mode 100755 index 000000000..37657b27c --- /dev/null +++ b/openjpeg/src/bin/jp3d/tcltk/LPI_JP3D_VM.tcl @@ -0,0 +1,115 @@ +#!/bin/sh +# The next line is executed by /bin/sh, but not tcl \ +exec wish "$0" ${1+"$@"} +lappend auto_path /usr/share/tcltk/bwidget1.9.2 + +namespace eval jp3dVM { + + variable _progress 0 + variable _afterid "" + variable _status "Compute in progress..." + variable notebook + variable mainframe + variable dataout "Process execution information" + variable status + variable prgtext + variable prgindic + + set pwd [pwd] + cd [file dirname [info script]] + variable VMDIR [pwd] + cd $pwd + + foreach script {encoder.tcl decoder.tcl} { + namespace inscope :: source $VMDIR/$script + } +} + + +proc jp3dVM::create { } { + variable notebook + variable mainframe + variable dataout + + bind all <F12> { catch {console show} } + + # Menu description + set descmenu { + "&File" {} {} 0 { + {command "E&xit" {} "Exit BWidget jp3dVM" {} -command exit} + } + "&Options" {} {} 0 { + {command "&Encode" {} "Show encoder" {} + -command {$jp3dVM::notebook raise [$jp3dVM::notebook page 0]} + } + {command "&Decode" {} "Show decoder" {} + -command {$jp3dVM::notebook raise [$jp3dVM::notebook page 1]} + } + } + "&Help" {} {} 0 { + {command "&About authors..." {} "Show info about authors" {} + -command {MessageDlg .msgdlg -parent . -title "About authors" -message " Copyright @ LPI-UVA 2006 " -type ok -icon info}} + } + } + + set mainframe [MainFrame .mainframe \ + -menu $descmenu \ + -textvariable jp3dVM::status \ + -progressvar jp3dVM::prgindic] + + $mainframe addindicator -text "JP3D Verification Model 1.0.0" + + # NoteBook creation + set frame [$mainframe getframe] + set notebook [NoteBook $frame.nb] + + set logo [frame $frame.logo] + #creo imagen logo + image create photo LPIimg -file logoLPI.gif + set logoimg [Label $logo.logoimg -image LPIimg] + + set f0 [VMEncoder::create $notebook] + set f1 [VMDecoder::create $notebook] + + set tfinfo [TitleFrame $frame.codinfo -text "Program Execution"] + set codinfo [$tfinfo getframe] + set sw [ScrolledWindow $codinfo.sw -relief sunken -borderwidth 2 -scrollbar both] + set sf [ScrollableFrame $codinfo.sf ] + $sw setwidget $sf + set subf [$sf getframe] + set labinfo [label $subf.labinfo -textvariable jp3dVM::dataout -justify left] + + pack $labinfo -side left + pack $sw + + $notebook compute_size + $notebook raise [$notebook page 0] + + pack $logoimg -side left -fill x -expand yes + pack $notebook -expand yes + pack $logo $tfinfo -side left -expand yes + pack $mainframe -fill both -expand yes + update idletasks +} + + +proc jp3dVM::main {} { + variable VMDIR + + lappend ::auto_path [file dirname $VMDIR] + namespace inscope :: package require BWidget + + option add *TitleFrame.l.font {helvetica 11 bold italic} + + wm withdraw . + wm title . "JP3D Verification Model @ LPI" + + jp3dVM::create + BWidget::place . 0 0 center + wm deiconify . + raise . + focus -force . +} + +jp3dVM::main +wm geom . [wm geom .] diff --git a/openjpeg/src/bin/jp3d/tcltk/README b/openjpeg/src/bin/jp3d/tcltk/README new file mode 100644 index 000000000..f4e2e3597 --- /dev/null +++ b/openjpeg/src/bin/jp3d/tcltk/README @@ -0,0 +1,13 @@ +HOWTO USE THE TCL/TK APP IN 'jp3d/tcltk' +---------------------------------------- +1. Download the 'BWidget-1.9.2' + http://www.sourceforge.net/projects/tcllib/ + +2. Install it e.g. in '/usr/local/BWidget-1.9.2/' +3. Add the lappend command in line 4 + to jp3d/tcltk/LPI_JP3D_VM.tcl: + +#!/bin/sh +# The next line is executed by /bin/sh, but not tcl \ +exec wish "$0" ${1+"$@"} +lappend auto_path /usr/local/BWidget-1.9.2 diff --git a/openjpeg/src/bin/jp3d/tcltk/Thumbs.db b/openjpeg/src/bin/jp3d/tcltk/Thumbs.db Binary files differnew file mode 100755 index 000000000..5d6ffdf99 --- /dev/null +++ b/openjpeg/src/bin/jp3d/tcltk/Thumbs.db diff --git a/openjpeg/src/bin/jp3d/tcltk/decoder.tcl b/openjpeg/src/bin/jp3d/tcltk/decoder.tcl new file mode 100755 index 000000000..21daba7d5 --- /dev/null +++ b/openjpeg/src/bin/jp3d/tcltk/decoder.tcl @@ -0,0 +1,272 @@ + +namespace eval VMDecoder { + variable var + variable JP3Ddecoder "../bin/jp3d_to_volume.exe" + #variable JP3Ddecoder "jp3d_to_volume.exe" +} + + +proc VMDecoder::create { nb } { + variable var + + set frameD [$nb insert end VMDecoder -text "Decoder"] + set topfD [frame $frameD.topfD] + set medfD [frame $frameD.medfD] + set bottomfD [frame $frameD.bottomfD] + set srcfD [TitleFrame $topfD.srcfD -text "Source"] + set dstfD [TitleFrame $topfD.dstfD -text "Destination"] + set paramfD [TitleFrame $medfD.paramfD -text "Decoding parameters"] + set infofD [TitleFrame $medfD.infofD -text "Distortion measures"] + + set frame1 [$srcfD getframe] + _sourceD $frame1 + set frame2 [$dstfD getframe] + _destinationD $frame2 + set frame3 [$infofD getframe] + _originalD $frame3 + set frame4 [$paramfD getframe] + _paramsD $frame4 + + set butD [Button $bottomfD.butD -text "Decode!" \ + -command "VMDecoder::_decode $frame1 $frame2 $frame3" \ + -helptext "Decoding trigger button"] + set butR [Button $bottomfD.butR -text "Save info" \ + -command "VMDecoder::_save $frame3" \ + -helptext "Save information"] + + pack $srcfD $dstfD -side left -fill both -padx 10 -ipadx 5 -expand yes + pack $topfD -pady 4 -fill x + + pack $paramfD $infofD -side left -fill both -padx 10 -pady 2 -ipadx 5 -expand yes + pack $medfD -pady 4 -fill x + + pack $butD $butR -side left -padx 4 -pady 5 -expand yes + pack $bottomfD -pady 4 -fill x + +return $frameD +} + + +proc fileDialogD {w ent operation} { + + variable file + + if {$operation == "open"} { + #-----Type names---------Extension(s)--- + set types { + {"JP3D Files" {.jp3d} } + {"All files" *} + } + set file [tk_getOpenFile -filetypes $types -parent $w ] + } elseif {$operation == "original"} { + #-----Type names---------Extension(s)--- + set types { + {"BIN Raw Image Files" {.bin} } + {"PGX Raw Image Files" {.pgx} } + {"All files" *} + } + set file [tk_getOpenFile -filetypes $types -parent $w ] + } else { + #-----Type names---------Extension(s)--- + set types { + {"BIN Raw Image Files" {.bin} } + {"PGX Raw Image Files" {.pgx} } + {"All files" *} + } + set file [tk_getSaveFile -filetypes $types -parent $w -initialfile Untitled -defaultextension "*.bin"] + } + if {[string compare $file ""]} { + $ent delete 0 end + $ent insert end $file + $ent xview moveto 1 + } +} + +proc VMDecoder::_sourceD { parent } { + + variable var + + set labsrcD [LabelFrame $parent.labsrcD -text "Select compressed file: " -side top \ + -anchor w -relief flat -borderwidth 0] + set subsrcD [$labsrcD getframe] + set listD [entry $subsrcD.entrysrcD -width 40 -textvariable VMDecoder::var(sourceD)] + + set labbrw [LabelFrame $parent.labbrw -side top -anchor w -relief flat -borderwidth 0] + set subbrw [$labbrw getframe] + set butbrw [button $subbrw.butbrw -image [Bitmap::get open] \ + -relief raised -borderwidth 1 -padx 1 -pady 1 \ + -command "fileDialogD . $subsrcD.entrysrcD open"] + + pack $listD -side top + pack $butbrw -side top + pack $labsrcD $labbrw -side left -fill both -expand yes + + +} + +proc VMDecoder::_destinationD { parent } { + + variable var + + set labdstD [LabelFrame $parent.labdstD -text "Save decompressed volume file(s) as: " -side top \ + -anchor w -relief flat -borderwidth 0] + set subdstD [$labdstD getframe] + set listD [entry $subdstD.entrydstD -width 40 -textvariable VMDecoder::var(destinationD)] + + set labbrw [LabelFrame $parent.labbrw -side top -anchor w -relief flat -borderwidth 0] + set subbrw [$labbrw getframe] + set butbrw [button $subbrw.butbrw -image [Bitmap::get save] \ + -relief raised -borderwidth 1 -padx 1 -pady 1 \ + -command "fileDialogD . $subdstD.entrydstD save"] + + pack $listD -side top + pack $butbrw -side top + pack $labdstD $labbrw -side left -fill both -expand yes +} + +proc VMDecoder::_originalD { parent } { + + variable var + + set laborgD [LabelFrame $parent.laborgD -text "Select original file: " -side top \ + -anchor w -relief flat -borderwidth 0] + set suborgD [$laborgD getframe] + set listorgD [entry $suborgD.entryorgD -width 30 -textvariable VMDecoder::var(originalD)] + + set labbrw2 [LabelFrame $parent.labbrw2 -side top -anchor w -relief flat -borderwidth 0] + set subbrw2 [$labbrw2 getframe] + set butbrw2 [button $subbrw2.butbrw2 -image [Bitmap::get open] \ + -relief raised -borderwidth 1 -padx 1 -pady 1 \ + -command "fileDialogD . $suborgD.entryorgD original"] + + set infoD [Label $parent.infoD -relief sunken -textvariable VMDecoder::var(decodinfo) -justify left] + + pack $listorgD -side left -anchor n + pack $butbrw2 -side left -anchor n + pack $infoD -side bottom -anchor nw -pady 4 -ipadx 150 -ipady 20 -expand yes + pack $laborgD $labbrw2 -side left -fill both + + +} + +proc VMDecoder::_paramsD { parent } { + + variable var + + ########### DECODING ############# + set labcod [LabelFrame $parent.labcod -side top -anchor w -relief sunken -borderwidth 1] + set subcod [$labcod getframe] + + set frameres [frame $subcod.frameres -borderwidth 1] + set labres [LabelEntry $frameres.labres -label "Resolutions to discard: " -labelwidth 20 -labelanchor w \ + -textvariable VMDecoder::var(resdiscard) -editable 1 \ + -helptext "Number of highest resolution levels to be discarded on each dimension" ] + set VMDecoder::var(resdiscard) "0,0,0" + + set framelayer [frame $subcod.framelayer -borderwidth 1] + set lablayer [LabelEntry $framelayer.lablayer -label "Layers to decode: " -labelwidth 20 -labelanchor w \ + -textvariable VMDecoder::var(layer) -editable 1 \ + -helptext "Maximum number of quality layers to decode" ] + set VMDecoder::var(layer) "All" + + set framebe [frame $subcod.framebe -borderwidth 1] + set chkbe [checkbutton $framebe.chkbe -text "Write decoded file with BigEndian byte order" \ + -variable VMDecoder::var(be) -onvalue 1 -offvalue 0 ] + + pack $labres -side left -padx 2 -anchor n + pack $lablayer -side left -padx 2 -anchor n + pack $chkbe -side left -padx 2 -anchor w + pack $frameres $framelayer $framebe -side top -anchor w + + pack $subcod -anchor n + pack $labcod -side left -fill both -padx 4 -expand yes +} + + +proc VMDecoder::_decode { framesrc framedst frameinfo} { + + variable var + + set sourceD [$framesrc.labsrcD.f.entrysrcD get ] + set destinationD [$framedst.labdstD.f.entrydstD get ] + set originD [$frameinfo.laborgD.f.entryorgD get ] + set cond1 [string match *.pgx [string tolower $destinationD]] + set cond2 [string match *\**.pgx [string tolower $destinationD]] + set cond3 [string match *.bin [string tolower $destinationD]] + + #comprobamos datos son correctos + if {($cond1 == 1) && ($cond2 == 0)} { + set pgx "*.pgx" + set pattern [string range $destinationD 0 [expr [string length $destinationD]-5]] + set destinationD $pattern$img + } elseif {$sourceD == ""} { + MessageDlg .msgdlg -parent . -message "Error : Source file is not defined !" -type ok -icon error + } elseif {$destinationD == ""} { + MessageDlg .msgdlg -parent . -message "Error : Destination file is not defined !" -type ok -icon error + } else { + + #creamos datain a partir de los parametros de entrada + #set dirJP3Ddecoder [mk_relativepath $VMDecoder::JP3Ddecoder] + set dirJP3Ddecoder $VMDecoder::JP3Ddecoder + set datain [concat " $dirJP3Ddecoder -i [mk_relativepath $sourceD] "] + set datain [concat " $datain -o [mk_relativepath $destinationD] "] + if {$originD != ""} { + set datain [concat " $datain -O [mk_relativepath $originD] "] + if {$cond3 == 1} { + set img ".img" + set pattern [string range $originD 0 [expr [string length $originD]-5]] + set pattern $pattern$img + if {[file exists $pattern]} { + set datain [concat " $datain -m [mk_relativepath $pattern] "] + } else { + MessageDlg .msgdlg -parent . -message "Error : IMG file associated to original BIN volume file not found in same directory !" -type ok -icon info + } + } + } + if {$VMDecoder::var(resdiscard) != "0,0,0"} { + set datain [concat " $datain -r $VMDecoder::var(resdiscard) "] + } + if {$VMDecoder::var(layer) != "All" && $VMDecoder::var(layer) > 0} { + set datain [concat " $datain -l $VMDecoder::var(layer) "] + } + if {$VMDecoder::var(be) == 1} { + set datain [concat " $datain -BE"] + } + + set VMDecoder::var(progval) 10 + ProgressDlg .progress -parent . -title "Wait..." \ + -type infinite \ + -width 20 \ + -textvariable "Compute in progress..."\ + -variable VMDecoder::progval \ + -stop "Stop" \ + -command {destroy .progress} + + after 200 set VMDecoder::var(progval) 2 + + set fp [open "| $datain " r+] + fconfigure $fp -buffering line + set jp3dVM::dataout [concat "EXECUTED PROGRAM:\n\t$datain"] + while {-1 != [gets $fp tmp]} { + set jp3dVM::dataout [concat "$jp3dVM::dataout\n$tmp"] + } + close $fp + destroy .progress + set cond [string first "ERROR" $jp3dVM::dataout] + set cond2 [string first "PSNR" $jp3dVM::dataout] + set cond3 [string first "RESULT" $jp3dVM::dataout] + if {$cond != -1} { + MessageDlg .msgdlg -parent . -message [string range $jp3dVM::dataout [expr $cond-1] end] -type ok -icon error + } elseif {$cond3 != -1} { + if {$cond2 != -1} { + set VMDecoder::var(decodinfo) [string range $jp3dVM::dataout [expr $cond2-1] end] + } + MessageDlg .msgdlg -parent . -message [string range $jp3dVM::dataout [expr $cond3-1] end] -type ok -icon info + } + } +} + +proc VMDecoder::_save { frameinfo } { + +} + diff --git a/openjpeg/src/bin/jp3d/tcltk/encoder.tcl b/openjpeg/src/bin/jp3d/tcltk/encoder.tcl new file mode 100755 index 000000000..6c4a50839 --- /dev/null +++ b/openjpeg/src/bin/jp3d/tcltk/encoder.tcl @@ -0,0 +1,470 @@ + +namespace eval VMEncoder { + variable var + variable JP3Dencoder "../bin/bin/volume_to_jp3d" +} + +proc VMEncoder::create { nb } { + + set frame [$nb insert end VMEncoder -text "Encoder"] + set topf [frame $frame.topf] + set midf [frame $frame.midf] + set bottomf [frame $frame.bottomf] + set srcf [TitleFrame $topf.srcf -text "Source"] + set dstf [TitleFrame $topf.dstf -text "Destination"] + set Tparf [TitleFrame $midf.parfT -text "Transform Parameters"] + set Cparf [TitleFrame $midf.parfC -text "Coding Parameters"] + + set frame1 [$srcf getframe] + VMEncoder::_sourceE $frame1 + + set frame2 [$dstf getframe] + VMEncoder::_destinationE $frame2 + + set frame3 [$Tparf getframe] + VMEncoder::_transformE $frame3 + + set frame4 [$Cparf getframe] + VMEncoder::_codingE $frame4 + + set butE [Button $bottomf.butE -text "Encode!" \ + -command "VMEncoder::_encode $frame1 $frame2" \ + -helptext "Encoding trigger button"] + set butR [Button $bottomf.butR -text "Restore defaults" \ + -command "VMEncoder::_reset $frame1 $frame2 $frame3 $frame4" \ + -helptext "Reset to default values"] + + pack $srcf $dstf -side left -fill y -padx 4 -expand yes + pack $topf -pady 2 -fill x + + pack $Tparf $Cparf -side left -fill both -padx 4 -expand yes + pack $midf -pady 2 -fill x + + pack $butE $butR -side left -padx 40 -pady 5 -fill y -expand yes + pack $bottomf -pady 2 -fill x + + return $frame +} + +proc VMEncoder::_sourceE { parent } { + + variable var + + set labsrc [LabelFrame $parent.labsrc -text "Select volume file to encode: " -side top \ + -anchor w -relief flat -borderwidth 0] + set subsrc [$labsrc getframe] + set list [entry $subsrc.entrysrc -width 30 -textvariable VMDecoder::var(source)] + + set labbrw [LabelFrame $parent.labbrw -side top -anchor w -relief flat -borderwidth 0] + set subbrw [$labbrw getframe] + set butbrw [button $subbrw.butbrw -image [Bitmap::get open] \ + -relief raised -borderwidth 1 -padx 1 -pady 1 \ + -command "fileDialogE . $subsrc.entrysrc open"] + + pack $list -side top + pack $butbrw -side top + pack $labsrc $labbrw -side left -fill both -expand yes +} + +proc VMEncoder::_destinationE { parent } { + + variable var + + set labdst [LabelFrame $parent.labdst -text "Save compressed volume as: " -side top \ + -anchor w -relief flat -borderwidth 0] + set subdst [$labdst getframe] + set list [entry $subdst.entrydst -width 30 -textvariable VMDecoder::var(destination)] + + set labbrw [LabelFrame $parent.labbrw -side top -anchor w -relief flat -borderwidth 0] + set subbrw [$labbrw getframe] + set butbrw [button $subbrw.butbrw -image [Bitmap::get save] \ + -relief raised -borderwidth 1 -padx 1 -pady 1 \ + -command "fileDialogE . $subdst.entrydst save"] + + pack $list -side top + pack $butbrw -side top + pack $labdst $labbrw -side left -fill both -expand yes +} + +proc VMEncoder::_codingE { parent } { + + + ########### CODING ############# + set labcod [LabelFrame $parent.labcod -side top -anchor w -relief sunken -borderwidth 1] + set subcod [$labcod getframe] + + set framerate [frame $subcod.framerate -borderwidth 1] + set labrate [LabelEntry $framerate.labrate -label "Rates: " -labelwidth 9 -labelanchor w \ + -textvariable VMEncoder::var(rate) -editable 1 \ + -helptext "Compression ratios for different layers (R1, R2, R3,...). If R=1, lossless coding" ] + set VMEncoder::var(rate) "1" + + set framecblk [frame $subcod.framecblk -borderwidth 1] + set labcblk [LabelEntry $framecblk.labcblk -label "Codeblock: " -labelwidth 9 -labelanchor w \ + -textvariable VMEncoder::var(cblksize) -editable 1 \ + -helptext "Codeblock size (X, Y, Z)" ] + set VMEncoder::var(cblksize) "64,64,64" + + set frametile [frame $subcod.frametile -borderwidth 1] + set labtile [LabelEntry $frametile.labtile -label "Tile size: " -labelwidth 9 -labelanchor w \ + -textvariable VMEncoder::var(tilesize) -editable 1 \ + -helptext "Tile size (X, Y, Z)" ] + set VMEncoder::var(tilesize) "512,512,512" + + set framesop [frame $subcod.framesop -borderwidth 1] + set chksop [checkbutton $framesop.chksop -text "Write SOP marker" \ + -variable VMEncoder::var(sop) -onvalue 1 -offvalue 0 ] + set frameeph [frame $subcod.frameeph -borderwidth 1] + set chkeph [checkbutton $frameeph.chkeph -text "Write EPH marker" \ + -variable VMEncoder::var(eph) -onvalue 1 -offvalue 0 ] + + set framepoc [frame $subcod.framepoc -borderwidth 1] + set labpoc [label $framepoc.labpoc -text "Progression order: " ] + set progorder [ComboBox $framepoc.progorder \ + -text {Choose a progression order} \ + -width 10 \ + -textvariable VMEncoder::var(progorder) \ + -values {"LRCP" "RLCP" "RPCL" "PCRL" "CPRL"} \ + -helptext "Progression order"] + set VMEncoder::var(progorder) "LRCP" + + pack $labrate -side left -padx 2 -anchor n + pack $labcblk -side left -padx 2 -anchor n + pack $labpoc $progorder -side left -padx 2 -anchor w + #pack $labtile -side left -padx 2 -anchor n + pack $chksop -side left -padx 2 -anchor w + pack $chkeph -side left -padx 2 -anchor w + ########### ENTROPY CODING ############# + set labent [LabelFrame $parent.labent -text "Entropy Coding" -side top -anchor w -relief sunken -borderwidth 1] + set subent [$labent getframe] + foreach entval {2EB 3EB} entropy {2D_EBCOT 3D_EBCOT} { + set rad [radiobutton $subent.$entval \ + -text $entropy \ + -variable VMEncoder::var(encoding) \ + -command "disableGR $entval $labcblk $progorder $labrate $chksop $chkeph" \ + -value $entval ] + pack $rad -anchor w + } + $subent.2EB select + + pack $subent -padx 2 -anchor n + + pack $framerate $framecblk $framepoc $framesop $frameeph -side top -anchor w + pack $subcod -anchor n + + pack $labent $labcod -side left -fill both -padx 4 -expand yes + + +} + +proc VMEncoder::_transformE { parent } { + + variable var + + ########### TRANSFORM ############# + set labtrf [LabelFrame $parent.labtrf -text "Transform" -side top -anchor w -relief sunken -borderwidth 1] + set subtrf [$labtrf getframe] + set labres [LabelFrame $parent.labres -side top -anchor w -relief sunken -borderwidth 1] + set subres [$labres getframe] + + ########### ATK ############# + set frameatk [frame $subres.frameatk -borderwidth 1] + set labatk [label $frameatk.labatk -text "Wavelet kernel: " -anchor w] + set atk [ComboBox $frameatk.atk \ + -textvariable VMEncoder::var(atk) \ + -width 20 \ + -text {Choose a wavelet kernel} \ + -editable false \ + -values {"R5.3" "I9.7"} ] + set VMEncoder::var(atk) "R5.3" + pack $labatk $atk -side left -anchor w + ########### RESOLUTIONS ############# + set frameres1 [frame $subres.frameres1 -borderwidth 1] + set labresolution [label $frameres1.labresol -text "Resolutions: " -anchor w ] + set frameres2 [frame $subres.frameres2 -borderwidth 1] + set labresX [label $frameres2.labresX -text " X" -anchor w ] + set labresY [label $frameres2.labresY -text " Y" -anchor w ] + set labresZ [label $frameres2.labresZ -text " Z" -anchor w ] + + + set resX [SpinBox $frameres2.spinresX \ + -range {1 6 1} -textvariable VMEncoder::var(resX) \ + -helptext "Number of resolutions in X" \ + -width 3 \ + -editable false ] + set resY [SpinBox $frameres2.spinresY \ + -range {1 6 1} -textvariable VMEncoder::var(resY) \ + -helptext "Number of resolutions in Y" \ + -width 3 \ + -editable false ] + set resZ [SpinBox $frameres2.spinresZ \ + -range {1 6 1} -textvariable VMEncoder::var(resZ) \ + -helptext "Number of resolutions in Z" \ + -width 3 \ + -editable false \ + -state disabled ] + set VMEncoder::var(resX) 3 + set VMEncoder::var(resY) 3 + set VMEncoder::var(resZ) 3 + + ########### TRF ############# + foreach trfval {2DWT 3DWT} trf {2D-DWT 3D-DWT} { + set rad [radiobutton $subtrf.$trfval -text $trf \ + -variable VMEncoder::var(transform) \ + -command "disable3RLS $trfval $atk $resX $resY $resZ"\ + -value $trfval ] + pack $rad -anchor w + } + $subtrf.2DWT select + + pack $subtrf -side left -padx 2 -pady 4 + + pack $labresolution -padx 2 -side left -anchor w + pack $labresX $resX -padx 2 -side left -anchor w + pack $labresY $resY -padx 2 -side left -anchor w + pack $labresZ $resZ -padx 2 -side left -anchor w + + pack $frameres1 -side top -fill x + pack $frameres2 $frameatk -side top -padx 2 -pady 4 -anchor n + + pack $subres -side left -padx 2 -pady 4 + pack $labtrf $labres -side left -fill both -padx 4 -expand yes +} + + +proc VMEncoder::_encode { framesrc framedst } { + + variable var + + set source [$framesrc.labsrc.f.entrysrc get ] + set destination [$framedst.labdst.f.entrydst get ] + set cond1 [string match *.pgx [string tolower $source]] + set cond2 [string match *-*.pgx [string tolower $source]] + set cond3 [string match *.bin [string tolower $source]] + + set img ".img" + set pattern [string range $source 0 [expr [string length $source]-5]] + set pattern $pattern$img + set exist [file exists $pattern] + + #comprobamos datos son correctos + if {($cond1 == 1) && ($cond2 == 0)} { + MessageDlg .msgdlg -parent . -message "Info : Really want to encode an slice instead of a volume?.\n For a group of .pgx slices, name must contain a - denoting a sequential index!" -type ok -icon info + } + + if {$source == ""} { + MessageDlg .msgdlg -parent . -message "Error : Source file is not defined !" -type ok -icon error + } elseif {$destination == ""} { + MessageDlg .msgdlg -parent . -message "Error : Destination file is not defined !" -type ok -icon error + } elseif { ($VMEncoder::var(transform) != "3RLS") && ($VMEncoder::var(atk) == "Choose a wavelet transformation kernel") } { + MessageDlg .msgdlg -parent . -title "Info" -message "Please choose a wavelet transformation kernel"\ + -type ok -icon warning + } elseif {($exist == 0) && ($cond1 == 0) && ($cond3 == 1)} { + MessageDlg .msgdlg -parent . -message "Error : IMG file associated to BIN volume file not found in same directory !" -type ok -icon info + } else { + + #creamos datain a partir de los parametros de entrada +# set dirJP3Dencoder [mk_relativepath $VMEncoder::JP3Dencoder] + set dirJP3Dencoder $VMEncoder::JP3Dencoder + set datain [concat " $dirJP3Dencoder -i [mk_relativepath $source] "] + if {$cond3 == 1} { + set datain [concat " $datain -m [mk_relativepath $pattern] "] + } + set datain [concat " $datain -o [mk_relativepath $destination] "] + if {$VMEncoder::var(encoding) != "2EB"} { + set datain [concat " $datain -C $VMEncoder::var(encoding) "] + } + if {$VMEncoder::var(transform) == "2DWT"} { + set datain [concat " $datain -n $VMEncoder::var(resX),$VMEncoder::var(resY) "] + } elseif {$VMEncoder::var(transform) == "3DWT"} { + set datain [concat " $datain -n $VMEncoder::var(resX),$VMEncoder::var(resY),$VMEncoder::var(resZ) "] + } + + set datain [concat " $datain -r $VMEncoder::var(rate) "] + + if {$VMEncoder::var(atk) == "I9.7"} { + set datain [concat " $datain -I "] + } + if {$VMEncoder::var(sop) == 1} { + set datain [concat " $datain -SOP "] + } + if {$VMEncoder::var(eph) == 1} { + set datain [concat " $datain -EPH "] + } + if {$VMEncoder::var(progorder) != "LRCP"} { + set datain [concat " $datain -p $VMEncoder::var(progorder) "] + } + if {$VMEncoder::var(cblksize) != "64,64,64"} { + set datain [concat " $datain -b $VMEncoder::var(cblksize) "] + } + + + #Making this work would be great !!! + set VMEncoder::var(progval) 10 + ProgressDlg .progress -parent . -title "Wait..." \ + -type infinite \ + -width 20 \ + -textvariable "Compute in progress..."\ + -variable VMEncoder::progval \ + -stop "Stop" \ + -command {destroy .progress} + after 200 set VMEncoder::var(progval) 2 + set fp [open "| $datain " r+] + fconfigure $fp -buffering line + set jp3dVM::dataout [concat "EXECUTED PROGRAM:\n\t$datain"] + while {-1 != [gets $fp tmp]} { + set jp3dVM::dataout [concat "$jp3dVM::dataout\n$tmp"] + } + destroy .progress + set cond [string first "ERROR" $jp3dVM::dataout] + set cond2 [string first "RESULT" $jp3dVM::dataout] + if {$cond != -1} { + MessageDlg .msgdlg -parent . -message [string range $jp3dVM::dataout [expr $cond-1] end] -type ok -icon error + } elseif {$cond2 != -1} { + MessageDlg .msgdlg -parent . -message [string range $jp3dVM::dataout [expr $cond2+7] end] -type ok -icon info + close $fp + } else { + #Must do something with this !!! [pid $fp] + close $fp + } + } +} + +proc VMEncoder::_reset { framesrc framedst frametrf framecod} { + + variable var + + #Restore defaults values + set VMEncoder::var(transform) 2DWT + set VMEncoder::var(encoding) 2EB + set VMEncoder::var(atk) "R5.3" + set VMEncoder::var(progorder) "LRCP" + set atk $frametrf.labres.f.frameatk.atk + set resX $frametrf.labres.f.frameres2.spinresX + set resY $frametrf.labres.f.frameres2.spinresY + set resZ $frametrf.labres.f.frameres2.spinresZ + disable3RLS 2DWT $atk $resX $resY $resZ + set labcblk $framecod.labcod.f.framecblk.labcblk + set progorder $framecod.labcod.f.framepoc.progorder + set labrate $framecod.labcod.f.framerate.labrate + set chksop $framecod.labcod.f.framesop.chksop + set chkeph $framecod.labcod.f.frameeph.chkeph + disableGR 3EB $labcblk $progorder $labrate $chksop $chkeph + + $framesrc.labsrc.f.entrysrc delete 0 end + $framedst.labdst.f.entrydst delete 0 end +} + +proc fileDialogE {w ent operation} { + + variable file + variable i j + + if {$operation == "open"} { + set types { + {"Source Image Files" {.pgx .bin} } + {"All files" *} + } + set file [tk_getOpenFile -filetypes $types -parent $w] + if {[string compare $file ""]} { + $ent delete 0 end + $ent insert end $file + $ent xview moveto 1 + } + } else { + set types { + {"JP3D Files" {.jp3d} } + {"JPEG2000 Files" {.j2k} } + {"All files" *} + } + set file [tk_getSaveFile -filetypes $types -parent $w \ + -initialfile Untitled -defaultextension .jp3d] + if {[string compare $file ""]} { + $ent delete 0 end + $ent insert end $file + $ent xview moveto 1 + } + } +} + +proc mk_relativepath {abspath} { + + set mydir [split [string trimleft [pwd] {/}] {/}] + set abspathcomps [split [string trimleft $abspath {/}] {/}] + + set i 0 + while {$i<[llength $mydir]} { + if {![string compare [lindex $abspathcomps $i] [lindex $mydir $i]]} { + incr i + } else { + break + } + } + set h [expr [llength $mydir]-$i] + set j [expr [llength $abspathcomps]-$i] + + if {!$h} { + set relpath "./" + } else { + set relpath "" + while { $h > 0 } { + set relpath "../$relpath" + incr h -1 + } + } + + set h [llength $abspathcomps] + while { $h > $i } { + set relpath [concat $relpath[lindex $abspathcomps [expr [llength $abspathcomps]-$j]]/] + incr h -1 + incr j -1 + } + return [string trim $relpath {/}] +} + +proc disable3RLS {flag atk resX resY resZ} { + + if {$flag == "3RLS"} { + $atk configure -state disabled + $resX configure -state disabled + $resY configure -state disabled + $resZ configure -state disabled + } elseif {$flag == "2DWT"} { + $atk configure -state normal + $resX configure -state normal + $resY configure -state normal + $resZ configure -state disabled + } elseif {$flag == "3DWT"} { + $atk configure -state normal + $resX configure -state normal + $resY configure -state normal + $resZ configure -state normal + } +} + +proc disableGR {flag labcblk progorder labrate chksop chkeph} { + + if {$flag == "2EB"} { + $labcblk configure -state normal + $progorder configure -state normal + $labrate configure -state normal + $chksop configure -state normal + $chkeph configure -state normal + set VMEncoder::var(cblksize) "64,64,64" + set VMEncoder::var(tilesize) "512,512,512" + } elseif {$flag == "3EB"} { + $labcblk configure -state normal + $progorder configure -state normal + $labrate configure -state normal + $chksop configure -state normal + $chkeph configure -state normal + set VMEncoder::var(cblksize) "64,64,64" + set VMEncoder::var(tilesize) "512,512,512" + } else { + $labcblk configure -state disabled + $progorder configure -state disabled + $labrate configure -state disabled + $chksop configure -state disabled + $chkeph configure -state disabled + } +} diff --git a/openjpeg/src/bin/jp3d/tcltk/logoLPI.gif b/openjpeg/src/bin/jp3d/tcltk/logoLPI.gif Binary files differnew file mode 100755 index 000000000..df7951505 --- /dev/null +++ b/openjpeg/src/bin/jp3d/tcltk/logoLPI.gif diff --git a/openjpeg/src/bin/jp3d/windirent.h b/openjpeg/src/bin/jp3d/windirent.h new file mode 100644 index 000000000..4b1d9ff1b --- /dev/null +++ b/openjpeg/src/bin/jp3d/windirent.h @@ -0,0 +1,679 @@ +/* + * uce-dirent.h - operating system independent dirent implementation + * + * Copyright (C) 1998-2002 Toni Ronkko + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * ``Software''), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * + * May 28 1998, Toni Ronkko <tronkko@messi.uku.fi> + * + * $Id: uce-dirent.h,v 1.7 2002/05/13 10:48:35 tr Exp $ + * + * $Log: uce-dirent.h,v $ + * Revision 1.7 2002/05/13 10:48:35 tr + * embedded some source code directly to the header so that no source + * modules need to be included in the MS Visual C project using the + * interface, removed all the dependencies to other headers of the `uce' + * library so that the header can be made public + * + * Revision 1.6 2002/04/12 16:22:04 tr + * Unified Compiling Environment (UCE) replaced `std' library + * + * Revision 1.5 2001/07/20 16:33:40 tr + * moved to `std' library and re-named defines accordingly + * + * Revision 1.4 2001/07/10 16:47:18 tronkko + * revised comments + * + * Revision 1.3 2001/01/11 13:16:43 tr + * using ``uce-machine.h'' for finding out defines such as `FREEBSD' + * + * Revision 1.2 2000/10/08 16:00:41 tr + * copy of FreeBSD man page + * + * Revision 1.1 2000/07/10 05:53:16 tr + * Initial revision + * + * Revision 1.2 1998/07/19 18:29:14 tr + * Added error reporting capabilities and some asserts. + * + * Revision 1.1 1998/07/04 16:27:51 tr + * Initial revision + * + * + * MSVC 1.0 scans automatic dependencies incorrectly when your project + * contains this very header. The problem is that MSVC cannot handle + * include directives inside #if..#endif block those are never entered. + * Since this header ought to compile in many different operating systems, + * there had to be several conditional blocks that are compiled only in + * operating systems for what they were designed for. MSVC 1.0 cannot + * handle inclusion of sys/dir.h in a part that is compiled only in Apollo + * operating system. To fix the problem you need to insert DIR.H into + * SYSINCL.DAT located in MSVC\BIN directory and restart visual C++. + * Consult manuals for more informaton about the problem. + * + * Since many UNIX systems have dirent.h we assume to have one also. + * However, if your UNIX system does not have dirent.h you can download one + * for example at: http://ftp.uni-mannheim.de/ftp/GNU/dirent/dirent.tar.gz. + * You can also see if you have one of dirent.h, direct.h, dir.h, ndir.h, + * sys/dir.h and sys/ndir.h somewhere. Try defining HAVE_DIRENT_H, + * HAVE_DIRECT_H, HAVE_DIR_H, HAVE_NDIR_H, HAVE_SYS_DIR_H and + * HAVE_SYS_NDIR_H according to the files found. + */ +#ifndef DIRENT_H +#define DIRENT_H +#define DIRENT_H_INCLUDED + +/* find out platform */ +#if defined(MSDOS) /* MS-DOS */ +#elif defined(__MSDOS__) /* Turbo C/Borland */ +# define MSDOS +#elif defined(__DOS__) /* Watcom */ +# define MSDOS +#endif + +#if defined(WIN32) /* MS-Windows */ +#elif defined(__NT__) /* Watcom */ +# define WIN32 +#elif defined(_WIN32) /* Microsoft */ +# define WIN32 +#elif defined(__WIN32__) /* Borland */ +# define WIN32 +#endif + +/* + * See what kind of dirent interface we have unless autoconf has already + * determinated that. + */ +#if !defined(HAVE_DIRENT_H) && !defined(HAVE_DIRECT_H) && !defined(HAVE_SYS_DIR_H) && !defined(HAVE_NDIR_H) && !defined(HAVE_SYS_NDIR_H) && !defined(HAVE_DIR_H) +# if defined(_MSC_VER) /* Microsoft C/C++ */ +/* no dirent.h */ +# elif defined(__MINGW32__) /* MinGW */ +/* no dirent.h */ +# elif defined(__BORLANDC__) /* Borland C/C++ */ +# define HAVE_DIRENT_H +# define VOID_CLOSEDIR +# elif defined(__TURBOC__) /* Borland Turbo C */ +/* no dirent.h */ +# elif defined(__WATCOMC__) /* Watcom C/C++ */ +# define HAVE_DIRECT_H +# elif defined(__apollo) /* Apollo */ +# define HAVE_SYS_DIR_H +# elif defined(__hpux) /* HP-UX */ +# define HAVE_DIRENT_H +# elif defined(__alpha) || defined(__alpha__) /* Alpha OSF1 */ +# error "not implemented" +# elif defined(__sgi) /* Silicon Graphics */ +# define HAVE_DIRENT_H +# elif defined(sun) || defined(_sun) /* Sun Solaris */ +# define HAVE_DIRENT_H +# elif defined(__FreeBSD__) /* FreeBSD */ +# define HAVE_DIRENT_H +# elif defined(__linux__) /* Linux */ +# define HAVE_DIRENT_H +# elif defined(__GNUC__) /* GNU C/C++ */ +# define HAVE_DIRENT_H +# else +# error "not implemented" +# endif +#endif + +/* include proper interface headers */ +#if defined(HAVE_DIRENT_H) +# include <dirent.h> +# ifdef FREEBSD +# define NAMLEN(dp) ((int)((dp)->d_namlen)) +# else +# define NAMLEN(dp) ((int)(strlen((dp)->d_name))) +# endif + +#elif defined(HAVE_NDIR_H) +# include <ndir.h> +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_SYS_NDIR_H) +# include <sys/ndir.h> +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_DIRECT_H) +# include <direct.h> +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_DIR_H) +# include <dir.h> +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_SYS_DIR_H) +# include <sys/types.h> +# include <sys/dir.h> +# ifndef dirent +# define dirent direct +# endif +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(MSDOS) || defined(WIN32) + +/* figure out type of underlaying directory interface to be used */ +# if defined(WIN32) +# define DIRENT_WIN32_INTERFACE +# elif defined(MSDOS) +# define DIRENT_MSDOS_INTERFACE +# else +# error "missing native dirent interface" +# endif + +/*** WIN32 specifics ***/ +# if defined(DIRENT_WIN32_INTERFACE) +# include <windows.h> +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN (MAX_PATH) +# endif + + +/*** MS-DOS specifics ***/ +# elif defined(DIRENT_MSDOS_INTERFACE) +# include <dos.h> + +/* Borland defines file length macros in dir.h */ +# if defined(__BORLANDC__) +# include <dir.h> +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN ((MAXFILE)+(MAXEXT)) +# endif +# if !defined(_find_t) +# define _find_t find_t +# endif + +/* Turbo C defines ffblk structure in dir.h */ +# elif defined(__TURBOC__) +# include <dir.h> +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN ((MAXFILE)+(MAXEXT)) +# endif +# define DIRENT_USE_FFBLK + +/* MSVC */ +# elif defined(_MSC_VER) +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN (12) +# endif + +/* Watcom */ +# elif defined(__WATCOMC__) +# if !defined(DIRENT_MAXNAMLEN) +# if defined(__OS2__) || defined(__NT__) +# define DIRENT_MAXNAMLEN (255) +# else +# define DIRENT_MAXNAMLEN (12) +# endif +# endif + +# endif +# endif + +/*** generic MS-DOS and MS-Windows stuff ***/ +# if !defined(NAME_MAX) && defined(DIRENT_MAXNAMLEN) +# define NAME_MAX DIRENT_MAXNAMLEN +# endif +# if NAME_MAX < DIRENT_MAXNAMLEN +# error "assertion failed: NAME_MAX >= DIRENT_MAXNAMLEN" +# endif + + +/* + * Substitute for real dirent structure. Note that `d_name' field is a + * true character array although we have it copied in the implementation + * dependent data. We could save some memory if we had declared `d_name' + * as a pointer referring the name within implementation dependent data. + * We have not done that since some code may rely on sizeof(d_name) to be + * something other than four. Besides, directory entries are typically so + * small that it takes virtually no time to copy them from place to place. + */ +typedef struct dirent { + char d_name[NAME_MAX + 1]; + + /*** Operating system specific part ***/ +# if defined(DIRENT_WIN32_INTERFACE) /*WIN32*/ + WIN32_FIND_DATA data; +# elif defined(DIRENT_MSDOS_INTERFACE) /*MSDOS*/ +# if defined(DIRENT_USE_FFBLK) + struct ffblk data; +# else + struct _find_t data; +# endif +# endif +} dirent; + +/* DIR substitute structure containing directory name. The name is + * essential for the operation of ``rewinndir'' function. */ +typedef struct DIR { + char *dirname; /* directory being scanned */ + dirent current; /* current entry */ + int dirent_filled; /* is current un-processed? */ + + /*** Operating system specific part ***/ +# if defined(DIRENT_WIN32_INTERFACE) + HANDLE search_handle; +# elif defined(DIRENT_MSDOS_INTERFACE) +# endif +} DIR; + +# ifdef __cplusplus +extern "C" { +# endif + +/* supply prototypes for dirent functions */ +static DIR *opendir(const char *dirname); +static struct dirent *readdir(DIR *dirp); +static int closedir(DIR *dirp); +static void rewinddir(DIR *dirp); + +/* + * Implement dirent interface as static functions so that the user does not + * need to change his project in any way to use dirent function. With this + * it is sufficient to include this very header from source modules using + * dirent functions and the functions will be pulled in automatically. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> + +/* use ffblk instead of _find_t if requested */ +#if defined(DIRENT_USE_FFBLK) +# define _A_ARCH (FA_ARCH) +# define _A_HIDDEN (FA_HIDDEN) +# define _A_NORMAL (0) +# define _A_RDONLY (FA_RDONLY) +# define _A_SUBDIR (FA_DIREC) +# define _A_SYSTEM (FA_SYSTEM) +# define _A_VOLID (FA_LABEL) +# define _dos_findnext(dest) findnext(dest) +# define _dos_findfirst(name,flags,dest) findfirst(name,dest,flags) +#endif + +static int _initdir(DIR *p); +static const char *_getdirname(const struct dirent *dp); +static void _setdirname(struct DIR *dirp); + +/* + * <function name="opendir"> + * <intro>open directory stream for reading + * <syntax>DIR *opendir (const char *dirname); + * + * <desc>Open named directory stream for read and return pointer to the + * internal working area that is used for retrieving individual directory + * entries. The internal working area has no fields of your interest. + * + * <ret>Returns a pointer to the internal working area or NULL in case the + * directory stream could not be opened. Global `errno' variable will set + * in case of error as follows: + * + * <table> + * [EACESS |Permission denied. + * [EMFILE |Too many open files used by the process. + * [ENFILE |Too many open files in system. + * [ENOENT |Directory does not exist. + * [ENOMEM |Insufficient memory. + * [ENOTDIR |dirname does not refer to directory. This value is not + * reliable on MS-DOS and MS-Windows platforms. Many + * implementations return ENOENT even when the name refers to a + * file.] + * </table> + * </function> + */ +static DIR *opendir(const char *dirname) +{ + DIR *dirp; + assert(dirname != NULL); + + dirp = (DIR*)malloc(sizeof(struct DIR)); + if (dirp != NULL) { + char *p; + + /* allocate room for directory name */ + dirp->dirname = (char*) malloc(strlen(dirname) + 1 + strlen("\\*.*")); + if (dirp->dirname == NULL) { + /* failed to duplicate directory name. errno set by malloc() */ + free(dirp); + return NULL; + } + /* Copy directory name while appending directory separator and "*.*". + * Directory separator is not appended if the name already ends with + * drive or directory separator. Directory separator is assumed to be + * '/' or '\' and drive separator is assumed to be ':'. */ + strcpy(dirp->dirname, dirname); + p = strchr(dirp->dirname, '\0'); + if (dirp->dirname < p && + *(p - 1) != '\\' && *(p - 1) != '/' && *(p - 1) != ':') { + strcpy(p++, "\\"); + } +# ifdef DIRENT_WIN32_INTERFACE + strcpy(p, "*"); /*scan files with and without extension in win32*/ +# else + strcpy(p, "*.*"); /*scan files with and without extension in DOS*/ +# endif + + /* open stream */ + if (_initdir(dirp) == 0) { + /* initialization failed */ + free(dirp->dirname); + free(dirp); + return NULL; + } + } + return dirp; +} + + +/* + * <function name="readdir"> + * <intro>read a directory entry + * <syntax>struct dirent *readdir (DIR *dirp); + * + * <desc>Read individual directory entry and return pointer to a structure + * containing the name of the entry. Individual directory entries returned + * include normal files, sub-directories, pseudo-directories "." and ".." + * and also volume labels, hidden files and system files in MS-DOS and + * MS-Windows. You might want to use stat(2) function to determinate which + * one are you dealing with. Many dirent implementations already contain + * equivalent information in dirent structure but you cannot depend on + * this. + * + * The dirent structure contains several system dependent fields that + * generally have no interest to you. The only interesting one is char + * d_name[] that is also portable across different systems. The d_name + * field contains the name of the directory entry without leading path. + * While d_name is portable across different systems the actual storage + * capacity of d_name varies from system to system and there is no portable + * way to find out it at compile time as different systems define the + * capacity of d_name with different macros and some systems do not define + * capacity at all (besides actual declaration of the field). If you really + * need to find out storage capacity of d_name then you might want to try + * NAME_MAX macro. The NAME_MAX is defined in POSIX standard although + * there are many MS-DOS and MS-Windows implementations those do not define + * it. There are also systems that declare d_name as "char d_name[1]" and + * then allocate suitable amount of memory at run-time. Thanks to Alain + * Decamps (Alain.Decamps@advalvas.be) for pointing it out to me. + * + * This all leads to the fact that it is difficult to allocate space + * for the directory names when the very same program is being compiled on + * number of operating systems. Therefore I suggest that you always + * allocate space for directory names dynamically. + * + * <ret> + * Returns a pointer to a structure containing name of the directory entry + * in `d_name' field or NULL if there was an error. In case of an error the + * global `errno' variable will set as follows: + * + * <table> + * [EBADF |dir parameter refers to an invalid directory stream. This value + * is not set reliably on all implementations.] + * </table> + * </function> + */ +static struct dirent * +readdir(DIR *dirp) +{ + assert(dirp != NULL); + if (dirp == NULL) { + errno = EBADF; + return NULL; + } + +#if defined(DIRENT_WIN32_INTERFACE) + if (dirp->search_handle == INVALID_HANDLE_VALUE) { + /* directory stream was opened/rewound incorrectly or it ended normally */ + errno = EBADF; + return NULL; + } +#endif + + if (dirp->dirent_filled != 0) { + /* + * Directory entry has already been retrieved and there is no need to + * retrieve a new one. Directory entry will be retrieved in advance + * when the user calls readdir function for the first time. This is so + * because real dirent has separate functions for opening and reading + * the stream whereas Win32 and DOS dirents open the stream + * automatically when we retrieve the first file. Therefore, we have to + * save the first file when opening the stream and later we have to + * return the saved entry when the user tries to read the first entry. + */ + dirp->dirent_filled = 0; + } else { + /* fill in entry and return that */ +#if defined(DIRENT_WIN32_INTERFACE) + if (FindNextFile(dirp->search_handle, &dirp->current.data) == FALSE) { + /* Last file has been processed or an error occurred */ + FindClose(dirp->search_handle); + dirp->search_handle = INVALID_HANDLE_VALUE; + errno = ENOENT; + return NULL; + } + +# elif defined(DIRENT_MSDOS_INTERFACE) + if (_dos_findnext(&dirp->current.data) != 0) { + /* _dos_findnext and findnext will set errno to ENOENT when no + * more entries could be retrieved. */ + return NULL; + } +# endif + + _setdirname(dirp); + assert(dirp->dirent_filled == 0); + } + return &dirp->current; +} + + +/* + * <function name="closedir"> + * <intro>close directory stream. + * <syntax>int closedir (DIR *dirp); + * + * <desc>Close directory stream opened by the `opendir' function. Close of + * directory stream invalidates the DIR structure as well as previously read + * dirent entry. + * + * <ret>The function typically returns 0 on success and -1 on failure but + * the function may be declared to return void on same systems. At least + * Borland C/C++ and some UNIX implementations use void as a return type. + * The dirent wrapper tries to define VOID_CLOSEDIR whenever closedir is + * known to return nothing. The very same definition is made by the GNU + * autoconf if you happen to use it. + * + * The global `errno' variable will set to EBADF in case of error. + * </function> + */ +static int +closedir(DIR *dirp) +{ + int retcode = 0; + + /* make sure that dirp points to legal structure */ + assert(dirp != NULL); + if (dirp == NULL) { + errno = EBADF; + return -1; + } + + /* free directory name and search handles */ + if (dirp->dirname != NULL) { + free(dirp->dirname); + } + +#if defined(DIRENT_WIN32_INTERFACE) + if (dirp->search_handle != INVALID_HANDLE_VALUE) { + if (FindClose(dirp->search_handle) == FALSE) { + /* Unknown error */ + retcode = -1; + errno = EBADF; + } + } +#endif + + /* clear dirp structure to make sure that it cannot be used anymore*/ + memset(dirp, 0, sizeof(*dirp)); +# if defined(DIRENT_WIN32_INTERFACE) + dirp->search_handle = INVALID_HANDLE_VALUE; +# endif + + free(dirp); + return retcode; +} + + +/* + * <function name="rewinddir"> + * <intro>rewind directory stream to the beginning + * <syntax>void rewinddir (DIR *dirp); + * + * <desc>Rewind directory stream to the beginning so that the next call of + * readdir() returns the very first directory entry again. However, note + * that next call of readdir() may not return the same directory entry as it + * did in first time. The directory stream may have been affected by newly + * created files. + * + * Almost every dirent implementation ensure that rewinddir will update + * the directory stream to reflect any changes made to the directory entries + * since the previous ``opendir'' or ``rewinddir'' call. Keep an eye on + * this if your program depends on the feature. I know at least one dirent + * implementation where you are required to close and re-open the stream to + * see the changes. + * + * <ret>Returns nothing. If something went wrong while rewinding, you will + * notice it later when you try to retrieve the first directory entry. + */ +static void +rewinddir(DIR *dirp) +{ + /* make sure that dirp is legal */ + assert(dirp != NULL); + if (dirp == NULL) { + errno = EBADF; + return; + } + assert(dirp->dirname != NULL); + + /* close previous stream */ +#if defined(DIRENT_WIN32_INTERFACE) + if (dirp->search_handle != INVALID_HANDLE_VALUE) { + if (FindClose(dirp->search_handle) == FALSE) { + /* Unknown error */ + errno = EBADF; + } + } +#endif + + /* re-open previous stream */ + if (_initdir(dirp) == 0) { + /* initialization failed but we cannot deal with error. User will notice + * error later when she tries to retrieve first directory enty. */ + /*EMPTY*/; + } +} + + +/* + * Open native directory stream object and retrieve first file. + * Be sure to close previous stream before opening new one. + */ +static int +_initdir(DIR *dirp) +{ + assert(dirp != NULL); + assert(dirp->dirname != NULL); + dirp->dirent_filled = 0; + +# if defined(DIRENT_WIN32_INTERFACE) + /* Open stream and retrieve first file */ + dirp->search_handle = FindFirstFile(dirp->dirname, &dirp->current.data); + if (dirp->search_handle == INVALID_HANDLE_VALUE) { + /* something went wrong but we don't know what. GetLastError() could + * give us more information about the error, but then we should map + * the error code into errno. */ + errno = ENOENT; + return 0; + } + +# elif defined(DIRENT_MSDOS_INTERFACE) + if (_dos_findfirst(dirp->dirname, + _A_SUBDIR | _A_RDONLY | _A_ARCH | _A_SYSTEM | _A_HIDDEN, + &dirp->current.data) != 0) { + /* _dos_findfirst and findfirst will set errno to ENOENT when no + * more entries could be retrieved. */ + return 0; + } +# endif + + /* initialize DIR and it's first entry */ + _setdirname(dirp); + dirp->dirent_filled = 1; + return 1; +} + + +/* + * Return implementation dependent name of the current directory entry. + */ +static const char * +_getdirname(const struct dirent *dp) +{ +#if defined(DIRENT_WIN32_INTERFACE) + return dp->data.cFileName; + +#elif defined(DIRENT_USE_FFBLK) + return dp->data.ff_name; + +#else + return dp->data.name; +#endif +} + + +/* + * Copy name of implementation dependent directory entry to the d_name field. + */ +static void +_setdirname(struct DIR *dirp) +{ + /* make sure that d_name is long enough */ + assert(strlen(_getdirname(&dirp->current)) <= NAME_MAX); + + strncpy(dirp->current.d_name, + _getdirname(&dirp->current), + NAME_MAX); + dirp->current.d_name[NAME_MAX] = '\0'; /*char d_name[NAME_MAX+1]*/ +} + +# ifdef __cplusplus +} +# endif +# define NAMLEN(dp) ((int)(strlen((dp)->d_name))) + +#else +# error "missing dirent interface" +#endif + + +#endif /*DIRENT_H*/ diff --git a/openjpeg/src/bin/jpip/CMakeLists.txt b/openjpeg/src/bin/jpip/CMakeLists.txt new file mode 100644 index 000000000..301d885ba --- /dev/null +++ b/openjpeg/src/bin/jpip/CMakeLists.txt @@ -0,0 +1,161 @@ +# Headers file are located here: +include_directories( + ${OPENJPEG_BINARY_DIR}/src/lib/openjp2 # opj_config.h + ${OPENJPEG_SOURCE_DIR}/src/lib/openjp2 + ${OPENJPEG_SOURCE_DIR}/src/bin/common # opj_getopt.h + ${OPENJPEG_SOURCE_DIR}/src/bin/jp2 # convert.h + ${OPENJPEG_SOURCE_DIR}/src/lib/openjpip + ${FCGI_INCLUDE_DIRS} +) + +# Tool to embed metadata into JP2 file +add_executable(opj_jpip_addxml opj_jpip_addxml.c) +# Install exe +install(TARGETS opj_jpip_addxml + EXPORT OpenJPEGTargets + DESTINATION ${OPENJPEG_INSTALL_BIN_DIR} COMPONENT Applications + ) + +if(BUILD_JPIP_SERVER) + set(OPJ_SERVER_SRCS + ${CMAKE_CURRENT_SOURCE_DIR}/opj_server.c + ) + + # Build executable + add_executable(opj_server ${OPJ_SERVER_SRCS}) + target_link_libraries(opj_server ${FCGI_LIBRARIES} openjpip_server) + set_property( + TARGET opj_server + APPEND PROPERTY + COMPILE_DEFINITIONS SERVER QUIT_SIGNAL="quitJPIP" + ) + + # On unix you need to link to the math library: + if(UNIX) + target_link_libraries(opj_server m) + endif() + + # Install exe + install(TARGETS opj_server + EXPORT OpenJPEGTargets + DESTINATION ${OPENJPEG_INSTALL_BIN_DIR} COMPONENT Applications + ) +endif() + +set(EXES + opj_dec_server + opj_jpip_transcode + opj_jpip_test + ) +foreach(exe ${EXES}) +add_executable(${exe} ${exe}.c) + target_link_libraries(${exe} openjpip) + install(TARGETS ${exe} + EXPORT OpenJPEGTargets + DESTINATION ${OPENJPEG_INSTALL_BIN_DIR} COMPONENT Applications + ) +endforeach() + +# Build the two java clients: +find_package(Java 1.5 COMPONENTS Development) # javac, jar + +# User can override this: +if(NOT DEFINED JAVA_SOURCE_VERSION) + set(JAVA_SOURCE_VERSION 1.5) +endif() +if(NOT DEFINED JAVA_TARGET_VERSION) + set(JAVA_TARGET_VERSION 1.5) +endif() + +# Only build the java viewer if dev is found: +if(Java_Development_FOUND AND Java_JAVAC_EXECUTABLE) + set(jflags $ENV{JFLAGS}) + # search for package org.apache.xerces.parsers + find_file(APACHE_XERCES_JAR + NAMES xerces-j2.jar xercesImpl.jar + PATHS /usr/share/java/ + NO_DEFAULT_PATH + ) + mark_as_advanced(APACHE_XERCES_JAR) + + # Decide to build the simple viewer or the xerces one: + if(EXISTS ${APACHE_XERCES_JAR}) + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/opj_viewer_xerces/dist/manifest.txt.in + ${CMAKE_CURRENT_BINARY_DIR}/opj_viewer_xerces/dist/manifest.txt + @ONLY + ) + # build dep list: + file(GLOB java2_srcs "opj_viewer_xerces/src/*.java") + + # Need some common files: + list(APPEND java2_srcs + ${CMAKE_CURRENT_SOURCE_DIR}/opj_viewer/src/ImageManager.java + ${CMAKE_CURRENT_SOURCE_DIR}/opj_viewer/src/ImgdecClient.java + ${CMAKE_CURRENT_SOURCE_DIR}/opj_viewer/src/JPIPHttpClient.java + ${CMAKE_CURRENT_SOURCE_DIR}/opj_viewer/src/MML.java + ${CMAKE_CURRENT_SOURCE_DIR}/opj_viewer/src/PnmImage.java + ${CMAKE_CURRENT_SOURCE_DIR}/opj_viewer/src/RegimViewer.java + ${CMAKE_CURRENT_SOURCE_DIR}/opj_viewer/src/ResizeListener.java + ) + + # make sure target javac dir exists: + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/classes2) + # Build java + add_custom_command( + OUTPUT ${LIBRARY_OUTPUT_PATH}/opj_jpip_viewer.jar + COMMAND ${Java_JAVAC_EXECUTABLE} ${jflags} + -source ${JAVA_SOURCE_VERSION} -target ${JAVA_TARGET_VERSION} + -classpath ${APACHE_XERCES_JAR} + ${java2_srcs} -d ${CMAKE_CURRENT_BINARY_DIR}/classes2 + COMMAND ${Java_JAR_EXECUTABLE} cfm ${LIBRARY_OUTPUT_PATH}/opj_jpip_viewer.jar + ${CMAKE_CURRENT_BINARY_DIR}/opj_viewer_xerces/dist/manifest.txt + -C ${CMAKE_CURRENT_BINARY_DIR}/classes2 . + DEPENDS ${java2_srcs} + ${CMAKE_CURRENT_SOURCE_DIR}/opj_viewer_xerces/dist/manifest.txt.in + COMMENT "javac *.java; jar cvf -> opj_viewer_xerces.jar" + ) + + # name the target + add_custom_target(OPJViewerXercesJar ALL + DEPENDS ${LIBRARY_OUTPUT_PATH}/opj_jpip_viewer.jar + COMMENT "building opj_jpip_viewer.jar (xerces)" + ) + + install(FILES ${LIBRARY_OUTPUT_PATH}/opj_jpip_viewer.jar + DESTINATION ${OPENJPEG_INSTALL_SHARE_DIR} COMPONENT JavaModule + ) + else() + # opj_viewer (simple, no xerces) + # build dep list: + file(GLOB java1_srcs "opj_viewer/src/*.java") + + # make sure target javac dir exists: + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/classes1) + # Build java + add_custom_command( + OUTPUT ${LIBRARY_OUTPUT_PATH}/opj_jpip_viewer.jar + COMMAND ${Java_JAVAC_EXECUTABLE} ${jflags} + -source ${JAVA_SOURCE_VERSION} -target ${JAVA_TARGET_VERSION} + ${java1_srcs} -d ${CMAKE_CURRENT_BINARY_DIR}/classes1 + COMMAND ${Java_JAR_EXECUTABLE} cfm ${LIBRARY_OUTPUT_PATH}/opj_jpip_viewer.jar + ${CMAKE_CURRENT_SOURCE_DIR}/opj_viewer/dist/manifest.txt -C + ${CMAKE_CURRENT_BINARY_DIR}/classes1 . + DEPENDS ${java1_srcs} + ${CMAKE_CURRENT_SOURCE_DIR}/opj_viewer/dist/manifest.txt + COMMENT "javac *.java; jar cvf -> opj_jpip_viewer.jar" + ) + + # name the target + add_custom_target(OPJViewerJar ALL + DEPENDS ${LIBRARY_OUTPUT_PATH}/opj_jpip_viewer.jar + COMMENT "building opj_jpip_viewer.jar (no xerces found)" + ) + + install(FILES ${LIBRARY_OUTPUT_PATH}/opj_jpip_viewer.jar + DESTINATION ${OPENJPEG_INSTALL_SHARE_DIR} COMPONENT JavaModule + ) + endif() +else() + message(WARNING "No java compiler found. Wont be able to build java viewer") +endif() diff --git a/openjpeg/src/bin/jpip/README b/openjpeg/src/bin/jpip/README new file mode 100644 index 000000000..5bcb01faa --- /dev/null +++ b/openjpeg/src/bin/jpip/README @@ -0,0 +1,149 @@ +======================================================================== + OpenJPIP software 2.1 ReadMe + +OpenJPEG: +http://www.openjpeg.org + +Written by: +Kaori Hagihara +UCL/SST/ICTM/ELEN +February 18 2011 +======================================================================== + +Contents: +1. Introduction +2. License +3. System requirements +4. Implementing instructions +5. JP2 encoding instructions + + +---------- +1. Introduction +---------- + +OpenJPIP software is an implementation of JPEG 2000 Part9: Interactivity tools, APIs and protocols (JPIP). +( For more info about JPIP, check the website: http://www.jpeg.org/jpeg2000/j2kpart9.html) +The current implementation uses some results from the 2KAN project (http://www.2kan.org). + +Version 2.1 covers: + - JPT-stream (Tile) and JPP-stream (Precinct) media types + - Session, channels, cache model managements + - JPIP over HTTP, HTTP requests and TCP return + - Indexing JPEG 2000 files + - Embedding XML formatted metadata + - Region Of Interest (ROI) requests + - Access to JP2 files with their URL + +---------- +2. License +---------- + +This software is released under the BSD license, anybody can use or modify the library, even for commercial applications. +The only restriction is to retain the copyright in the sources or the binaries documentation. +Neither the author, nor the university accept any responsibility for any kind of error or data loss which may occur during usage. + +---------- +3. System requirements +---------- + + - FastCGI development kit (C libraries) at server (http://www.fastcgi.com) + - libcURL library + - Java application launcher at client +<Optional> + - Xerces2 java XML parser on the client for accessing embedded image metadata (http://xerces.apache.org/xerces2-j) + +We tested this software with a virtual server running on the same Linux machine as the clients. + +---------- +4. Building instructions +---------- + +A Makefile is available in the same directory as this README file. Simply type 'make' and it will build all the required C-executables. +Concerning the java-based opj_viewer, simply type 'ant' in the corresponding directory (requires 'ant' utility of course) + +The documentation can be build this way (requires doxygen utility): + cd doc + doxygen Doxyfile + +---------- +5. Usage +---------- + +Preliminary notes : + * HTML documentation is available at http://www.openjpeg.org/jpip/doc/html + * Example image is available at http://www.openjpeg.org/jpip/data/copenhague1.zip (20 Mb !) + +Webserver: + You need a webserver running with the fastcgi module enabled and correctly configured. + For Apache, add the following line to your /etc/apache2/mods-available/fastcgi.conf configuration file: + + FastCGIExternalServer /var/www/myFCGI -host localhost:3000 + + where /var/www is your DocumentRoot. + Please refer to 'http://www.openjpeg.org/jpip/doc/ApacheFastCGITutorial.pdf' for more details. + +Server: + 1. Store JP2 files in the same directory as opj_server + + 2. Launch opj_server from the server terminal: + % spawn-fcgi -f ./opj_server -p 3000 -n + + For shutting down JPIP server: + %GET http://hostname/myFCGI?quitJPIP + Notice, http://hostname/myFCGI is the HTTP server URI (myFCGI refers to opj_server by the server setting) + Requst message "quitJPIP" can be changed in Makfile, modify -DQUIT_SIGNAL=\"quitJPIP\" + +Client: + 1. Launch image decoding server, and keep it alive as long as image viewers are open + % ./opj_dec_server [portnumber (50000 by default)] + + You might prefer to implement this program from another directory since cache files are saved in the working directory. + % mkdir cache + % cd cache + % ../opj_dec_server + + 2. Open image viewers (as many as needed) + % java -jar opj_viewer.jar http://hostname/myFCGI path/filename.jp2 [hostname] [portnumber] [stateless/session] [jptstream/jppstream] [tcp/udp] + ( The arguments + - http://hostname/myFCGI is the HTTP server URI (myFCGI refers to opj_server by the server setting) + - path/filename.jp2 is the server local path or URL of a JP2 file + - host name of opj_dec_server, localhost by default + - portnumber of opj_dec_server, 50000 by default + - request type stateless for no caching, session (default) for caching + - return media type, JPT-stream tile based stream, or JPP-stream (default) precinct based stream + - auxiliary return protocol, tcp or udp (udp is not implemented yet), if not given, return data is filled in http chunk + Image viewer GUI instructions: + Scale up request: Enlarge the window + ROI request: Select a region by mouse click and drag, then click inside the red frame of the selected region + <If Xerces2 is installed> + % java -jar opj_viewer_xerces.jar http://hostname/myFCGI JP2_filename.jp2 + Annotate image with ROI information in XML metadata: Click button "Region Of Interest" + Open a new window presenting an aligned image with a locally stored image: Click button "Image Registration" (Under Construction) + + 3. Quit the image decoding server through the telnet, be sure all image viewers are closed + % telnet localhost 50000 + quit + +---------- +5. JP2 encoding instructions +---------- + +An example to encode a TIF image "copenhague1.tif" at resolution 4780x4050, 8bit/pixel, grayscale. + % ./image_to_j2k -i copenhague1.tif -o copenhague1.jp2 -p RPCL -c [64,64] -t 640,480 -jpip -TP R + + options + -jpip : embed index table 'cidx' box into the output JP2 file (obligation for JPIP) + -TP R : partition a tile into tile parts of different resolution levels (obligation for JPT-stream) + +<Option> + 3. Embed metadata into JP2 file + % ./addXMLinJP2 copenhague1.jp2 copenhague1.xml + Input metadata file "copenhague1.xml" looks like: + <xmlbox> + <roi name="island" x="1890" y="1950" w="770" h="310"/> + <roi name="ship" x="750" y="330" w="100" h="60"/> + <roi name="airport" x="650" y="1800" w="650" h="800"/> + <roi name="harbor" x="4200" y="1650" w="130" h="130"/> + <irt refimg="name1.jp2" m1="0.50" m2="-0.50" m3="0" m4="0.80" m5="-0.80" m6="0" m7="500" m8="1000" m9="0"/> + </xmlbox> diff --git a/openjpeg/src/bin/jpip/opj_dec_server.c b/openjpeg/src/bin/jpip/opj_dec_server.c new file mode 100644 index 000000000..8a42b9821 --- /dev/null +++ b/openjpeg/src/bin/jpip/opj_dec_server.c @@ -0,0 +1,98 @@ +/* + * $Id: opj_dec_server.c 54 2011-05-10 13:22:47Z kaori $ + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/*! \file + * \brief opj_dec_server is a server to decode JPT-stream and communicate locally with JPIP client, which is coded in java. + * + * \section impinst Implementing instructions + * Launch opj_dec_server from a terminal in the same machine as JPIP client image viewers. \n + * % ./opj_dec_server [portnumber]\n + * ( portnumber=50000 by default)\n + * Keep it alive as long as image viewers are open.\n + * + * To quite the opj_dec_server, send a message "quit" through the telnet.\n + * % telnet localhost 50000\n + * quit\n + * Be sure all image viewers are closed.\n + * Cache file in JPT format is stored in the working directly before it quites. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include "opj_config.h" +#include "openjpip.h" + +#ifdef _WIN32 +WSADATA initialisation_win32; +#endif + +int main(int argc, char *argv[]) +{ + + dec_server_record_t *server_record; + client_t client; + int port = 50000; + int erreur; + (void)erreur; + + if (argc > 1) { + port = atoi(argv[1]); + } + +#ifdef _WIN32 + erreur = WSAStartup(MAKEWORD(2, 2), &initialisation_win32); + if (erreur != 0) { + fprintf(stderr, "Erreur initialisation Winsock error : %d %d\n", erreur, + WSAGetLastError()); + } else { + printf("Initialisation Winsock\n"); + } +#endif /*_WIN32*/ + + server_record = init_dec_server(port); + + while ((client = accept_connection(server_record)) != -1) + if (!handle_clientreq(client, server_record)) { + break; + } + + terminate_dec_server(&server_record); + +#ifdef _WIN32 + if (WSACleanup() != 0) { + printf("\nError in WSACleanup : %d %d", erreur, WSAGetLastError()); + } else { + printf("\nWSACleanup OK\n"); + } +#endif + + return 0; +} diff --git a/openjpeg/src/bin/jpip/opj_jpip_addxml.c b/openjpeg/src/bin/jpip/opj_jpip_addxml.c new file mode 100644 index 000000000..22fdd05b0 --- /dev/null +++ b/openjpeg/src/bin/jpip/opj_jpip_addxml.c @@ -0,0 +1,187 @@ +/* + * $Id: addXMLinJP2.c 46 2011-02-17 14:50:55Z kaori $ + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/*! \file + * \brief addXMLinJP2 is a program to embed metadata into JP2 file + * + * \section impinst Implementing instructions + * This program takes two arguments. \n + * -# Input/output image file in JP2 format, this JP2 file is being modified + * -# Input XML file with metadata contents\n + * % ./addXMLinJP2 image.jp2 metadata.xml\n + * + * Currently, this program does not parse XML file, and the XML file contents is directly embedded as a XML Box.\n + * The following is an example of XML file contents specifying Region Of Interests with target names.\n + * <xmlbox>\n + * <roi name="island" x="1890" y="1950" w="770" h="310"/>\n + * <roi name="ship" x="750" y="330" w="100" h="60"/>\n + * <roi name="airport" x="650" y="1800" w="650" h="800"/>\n + * <roi name="harbor" x="4200" y="1650" w="130" h="130"/>\n + * </xmlbox> + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + + +/** + * Open JP2 file with the check of JP2 header + * + * @param[in] filename file name string + * @return file descriptor + */ +FILE * open_jp2file(const char filename[]); + + +/** + * read xml file without any format check for the moment + * + * @param[in] filename file name string + * @param[out] fsize file byte size + * @return pointer to the xml file content buffer + */ +char * read_xmlfile(const char filename[], long *fsize); + +int main(int argc, char *argv[]) +{ + FILE *fp; + char *xmldata, type[] = "xml "; + long fsize, boxsize; + + if (argc < 3) { + fprintf(stderr, "USAGE: %s modifing.jp2 adding.xml\n", argv[0]); + return -1; + } + + fp = open_jp2file(argv[1]); + if (!fp) { + return -1; + } + + xmldata = read_xmlfile(argv[2], &fsize); + if (fsize < 0) { + return -1; + } + boxsize = fsize + 8; + + fputc((boxsize >> 24) & 0xff, fp); + fputc((boxsize >> 16) & 0xff, fp); + fputc((boxsize >> 8) & 0xff, fp); + fputc(boxsize & 0xff, fp); + fwrite(type, 4, 1, fp); + fwrite(xmldata, (size_t)fsize, 1, fp); + + free(xmldata); + fclose(fp); + + return 0; +} + +FILE * open_jp2file(const char filename[]) +{ + FILE *fp; + char *data; + + if (!(fp = fopen(filename, "a+b"))) { + fprintf(stderr, "Original JP2 %s not found\n", filename); + return NULL; + } + /* Check resource is a JP family file. */ + if (fseek(fp, 0, SEEK_SET) == -1) { + fclose(fp); + fprintf(stderr, "Original JP2 %s broken (fseek error)\n", filename); + return NULL; + } + + data = (char *)malloc(12); /* size of header */ + if (fread(data, 12, 1, fp) != 1) { + free(data); + fclose(fp); + fprintf(stderr, "Original JP2 %s broken (read error)\n", filename); + return NULL; + } + + if (*data || *(data + 1) || *(data + 2) || + *(data + 3) != 12 || strncmp(data + 4, "jP \r\n\x87\n", 8)) { + free(data); + fclose(fp); + fprintf(stderr, "No JPEG 2000 Signature box in target %s\n", filename); + return NULL; + } + free(data); + return fp; +} + +char * read_xmlfile(const char filename[], long *fsize) +{ + FILE *fp; + char *data; + + /* fprintf( stderr, "open %s\n", filename);*/ + if (!(fp = fopen(filename, "r"))) { + fprintf(stderr, "XML file %s not found\n", filename); + return NULL; + } + + if (fseek(fp, 0, SEEK_END) == -1) { + fprintf(stderr, "XML file %s broken (seek error)\n", filename); + fclose(fp); + return NULL; + } + + if ((*fsize = ftell(fp)) == -1) { + fprintf(stderr, "XML file %s broken (seek error)\n", filename); + fclose(fp); + return NULL; + } + assert(*fsize >= 0); + + if (fseek(fp, 0, SEEK_SET) == -1) { + fprintf(stderr, "XML file %s broken (seek error)\n", filename); + fclose(fp); + return NULL; + } + + data = (char *)malloc((size_t) * fsize); + + if (fread(data, (size_t)*fsize, 1, fp) != 1) { + fprintf(stderr, "XML file %s broken (read error)\n", filename); + free(data); + fclose(fp); + return NULL; + } + + fclose(fp); + + return data; +} diff --git a/openjpeg/src/bin/jpip/opj_jpip_test.c b/openjpeg/src/bin/jpip/opj_jpip_test.c new file mode 100644 index 000000000..f86ec4a63 --- /dev/null +++ b/openjpeg/src/bin/jpip/opj_jpip_test.c @@ -0,0 +1,75 @@ +/* + * $Id: test_index.c 46 2011-02-17 14:50:55Z kaori $ + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/*! \file + * \brief test_index is a program to test the index code format of a JP2 file + * + * \section impinst Implementing instructions + * This program takes one argument, and print out text type index information to the terminal. \n + * -# Input JP2 file\n + * % ./test_index input.jp2\n + */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#ifdef _WIN32 +#include <io.h> +#else +#include <unistd.h> +#endif +#include "openjpip.h" + +int +main(int argc, char *argv[]) +{ + int fd; + index_t *jp2idx; + if (argc < 2) { + return 1; + } + + if ((fd = open(argv[1], O_RDONLY)) == -1) { + fprintf(stderr, "Error: Target %s not found\n", argv[1]); + return -1; + } + + if (!(jp2idx = get_index_from_JP2file(fd))) { + fprintf(stderr, "JP2 file broken\n"); + return -1; + } + + output_index(jp2idx); + destroy_index(&jp2idx); + close(fd); + + return 0; +} /* main */ diff --git a/openjpeg/src/bin/jpip/opj_jpip_transcode.c b/openjpeg/src/bin/jpip/opj_jpip_transcode.c new file mode 100644 index 000000000..6cd2604d6 --- /dev/null +++ b/openjpeg/src/bin/jpip/opj_jpip_transcode.c @@ -0,0 +1,125 @@ +/* + * $Id$ + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include "openjpip.h" + +/*! \file + * \brief jpip_to_jp2 is a program to convert JPT- JPP- stream to JP2 file + * + * \section impinst Implementing instructions + * This program takes two arguments. \n + * -# Input JPT or JPP file + * -# Output JP2 file\n + * % ./jpip_to_jp2 input.jpt output.jp2 + * or + * % ./jpip_to_jp2 input.jpp output.jp2 + */ +static int jpip_to_jp2(char *argv[]) +{ + jpip_dec_param_t *dec; + + dec = init_jpipdecoder(OPJ_TRUE); + + if (!(fread_jpip(argv[1], dec))) { + return 1; + } + + decode_jpip(dec); + + if (!(fwrite_jp2k(argv[2], dec))) { + return 1; + } + + /* output_log( OPJ_TRUE, OPJ_FALSE, OPJ_TRUE, dec); */ + + destroy_jpipdecoder(&dec); + + return 0; +} + +/*! \file + * \brief jpip_to_j2k is a program to convert JPT- JPP- stream to J2K file + * + * \section impinst Implementing instructions + * This program takes two arguments. \n + * -# Input JPT or JPP file + * -# Output J2K file\n + * % ./jpip_to_j2k input.jpt output.j2k + * or + * % ./jpip_to_j2k input.jpp output.j2k + */ +static int jpip_to_j2k(char *argv[]) +{ + jpip_dec_param_t *dec; + + dec = init_jpipdecoder(OPJ_FALSE); + + if (!(fread_jpip(argv[1], dec))) { + return 1; + } + + decode_jpip(dec); + + if (!(fwrite_jp2k(argv[2], dec))) { + return 1; + } + + /* output_log( OPJ_TRUE, OPJ_FALSE, OPJ_FALSE, dec); */ + + destroy_jpipdecoder(&dec); + + return 0; +} + +int main(int argc, char *argv[]) +{ + char *ext; + if (argc < 3) { + fprintf(stderr, "Too few arguments:\n"); + fprintf(stderr, " - input jpt or jpp file\n"); + fprintf(stderr, " - output j2k file\n"); + return 1; + } + + ext = strrchr(argv[2], '.'); + if (ext) { + /* strcasecmp ? */ + if (strcmp(ext, ".jp2") == 0) { + return jpip_to_jp2(argv); + } + if (strcmp(ext, ".j2k") == 0) { + return jpip_to_j2k(argv); + } + } + + fprintf(stderr, "Invalid file extension for output file: %s\n", argv[2]); + return 1; +} diff --git a/openjpeg/src/bin/jpip/opj_server.c b/openjpeg/src/bin/jpip/opj_server.c new file mode 100644 index 000000000..ad0b16a9d --- /dev/null +++ b/openjpeg/src/bin/jpip/opj_server.c @@ -0,0 +1,131 @@ +/* + * $Id: opj_server.c 53 2011-05-09 16:55:39Z kaori $ + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2010-2011, Kaori Hagihara + * Copyright (c) 2011, Lucian Corlaciu, GSoC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/*! \file + * \brief opj_server is a JPIP server program, which supports HTTP connection, JPT-stream, session, channels, and cache model managements. + * + * \section req Requirements + * FastCGI development kit (http://www.fastcgi.com). + * + * \section impinst Implementing instructions + * Launch opj_server from the server terminal:\n + * % spawn-fcgi -f ./opj_server -p 3000 -n + * + * Note: JP2 files are stored in the working directory of opj_server\n + * Check README for the JP2 Encoding\n + * + * We tested this software with a virtual server running on the same Linux machine as the clients. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "fcgi_stdio.h" +#include "openjpip.h" + +#ifndef QUIT_SIGNAL +#define QUIT_SIGNAL "quitJPIP" +#endif + +#ifdef _WIN32 +WSADATA initialisation_win32; +#endif /*_WIN32*/ + +int main(void) +{ + server_record_t *server_record; +#ifdef SERVER + char *query_string; +#endif + +#ifdef _WIN32 + int erreur = WSAStartup(MAKEWORD(2, 2), &initialisation_win32); + if (erreur != 0) { + fprintf(stderr, "Erreur initialisation Winsock error : %d %d\n", erreur, + WSAGetLastError()); + } else { + fprintf(stderr, "Initialisation Winsock\n"); + } +#endif /*_WIN32*/ + + server_record = init_JPIPserver(60000, 0); + +#ifdef SERVER + while (FCGI_Accept() >= 0) +#else + + char query_string[128]; + while (fgets(query_string, 128, stdin) && query_string[0] != '\n') +#endif + { + QR_t *qr; + OPJ_BOOL parse_status; + +#ifdef SERVER + query_string = getenv("QUERY_STRING"); +#endif /*SERVER*/ + + if (strcmp(query_string, QUIT_SIGNAL) == 0) { + break; + } + + qr = parse_querystring(query_string); + + parse_status = process_JPIPrequest(server_record, qr); + +#ifndef SERVER + local_log(OPJ_TRUE, OPJ_TRUE, parse_status, OPJ_FALSE, qr, server_record); +#endif + + if (parse_status) { + send_responsedata(server_record, qr); + } else { + fprintf(FCGI_stderr, "Error: JPIP request failed\n"); + fprintf(FCGI_stdout, "\r\n"); + } + + end_QRprocess(server_record, &qr); + } + + fprintf(FCGI_stderr, "JPIP server terminated by a client request\n"); + + terminate_JPIPserver(&server_record); + +#ifdef _WIN32 + if (WSACleanup() != 0) { + fprintf(stderr, "\nError in WSACleanup : %d %d", erreur, WSAGetLastError()); + } else { + fprintf(stderr, "\nWSACleanup OK\n"); + } +#endif + + return 0; +} diff --git a/openjpeg/src/bin/jpip/opj_viewer/dist/manifest.txt b/openjpeg/src/bin/jpip/opj_viewer/dist/manifest.txt new file mode 100644 index 000000000..537c33dd8 --- /dev/null +++ b/openjpeg/src/bin/jpip/opj_viewer/dist/manifest.txt @@ -0,0 +1,4 @@ +Manifest-Version: 1.0 +Ant-Version: Apache Ant 1.7.0 +Created-By: Kaori Hagihara +Main-Class: ImageWindow diff --git a/openjpeg/src/bin/jpip/opj_viewer/src/ImageManager.java b/openjpeg/src/bin/jpip/opj_viewer/src/ImageManager.java new file mode 100644 index 000000000..2885e92f4 --- /dev/null +++ b/openjpeg/src/bin/jpip/opj_viewer/src/ImageManager.java @@ -0,0 +1,136 @@ +/* + * $Id$ + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import java.awt.Image; + +public class ImageManager extends JPIPHttpClient +{ + private PnmImage pnmimage; + private int origwidth; + private int origheight; + private ImgdecClient imgdecoder; + + public ImageManager( String uri, String host, int port) + { + super( uri); + imgdecoder = new ImgdecClient( host, port); + pnmimage = null; + origwidth = 0; + origheight = 0; + } + + public int getOrigWidth(){ + if( origwidth == 0){ + if( cid != null || tid != null){ + java.awt.Dimension dim = imgdecoder.query_imagesize( cid, tid); + if( dim != null){ + origwidth = dim.width; + origheight = dim.height; + } + } + else + System.err.println("Neither cid or tid obtained before to get Original Image Dimension"); + } + return origwidth; + } + public int getOrigHeight(){ return origheight;} + + public Image getImage( String j2kfilename, int reqfw, int reqfh, boolean reqcnew, int reqaux, boolean reqJPP, boolean reqJPT) + { + System.err.println(); + + String refcid = null; + byte[] jpipstream; + + // Todo: check if the cid is for the same stream type + if( reqcnew) + refcid = imgdecoder.query_cid( j2kfilename); + + if( refcid == null){ + String reftid = imgdecoder.query_tid( j2kfilename); + if( reftid == null) + jpipstream = super.requestViewWindow( j2kfilename, reqfw, reqfh, reqcnew, reqaux, reqJPP, reqJPT); + else + jpipstream = super.requestViewWindow( j2kfilename, reftid, reqfw, reqfh, reqcnew, reqaux, reqJPP, reqJPT); + } + else + jpipstream = super.requestViewWindow( reqfw, reqfh, refcid, reqcnew, reqaux, reqJPP, reqJPT); + + System.err.println( "decoding to PNM image"); + if((pnmimage = imgdecoder.decode_jpipstream( jpipstream, j2kfilename, tid, cid, fw, fh))!=null){ + System.err.println( " done"); + return pnmimage.createROIImage( rx, ry, rw, rh); + } + else{ + System.err.println( " failed"); + return null; + } + } + + public Image getImage( int reqfw, int reqfh, int reqrx, int reqry, int reqrw, int reqrh) + { + System.err.println(); + + byte[] jpipstream = super.requestViewWindow( reqfw, reqfh, reqrx, reqry, reqrw, reqrh); + + System.err.println( "decoding to PNM image"); + if((pnmimage = imgdecoder.decode_jpipstream( jpipstream, tid, cid, fw, fh)) != null){ + System.err.println( " done"); + return pnmimage.createROIImage( rx, ry, rw, rh); + } + else{ + System.err.println( " failed"); + return null; + } + } + + public byte[] getXML() + { + System.err.println(); + + byte []xmldata = null; + byte[] jpipstream = super.requestXML(); + + if( jpipstream != null){ + imgdecoder.send_JPIPstream( jpipstream); + + xmldata = imgdecoder.get_XMLstream( cid); + } + return xmldata; + } + + public void closeChannel() + { + if( cid != null){ + imgdecoder.destroy_cid( cid); + super.closeChannel(); + } + } +} diff --git a/openjpeg/src/bin/jpip/opj_viewer/src/ImageViewer.java b/openjpeg/src/bin/jpip/opj_viewer/src/ImageViewer.java new file mode 100644 index 000000000..c43a59148 --- /dev/null +++ b/openjpeg/src/bin/jpip/opj_viewer/src/ImageViewer.java @@ -0,0 +1,266 @@ +/* + * $Id$ + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import java.awt.image.*; +import java.awt.geom.*; +import java.net.URL; +import javax.swing.border.*; +import java.util.*; +import java.io.*; + +public class ImageViewer extends JPanel +{ + private ImageManager imgmanager; + private int vw, vh; + private int iw, ih; + private int selected = 0; + private Image img; + + private String cmdline = new String(); + private boolean fullRefresh = false; + private Point offset = new Point(0,0); + private Rectangle rect = new Rectangle(); + private Rectangle roirect[] = null; + private String roiname[] = null; + + public ImageViewer( String j2kfilename, ImageManager manager, boolean session, boolean jppstream, int aux) + { + String str; + MML myMML; + + this.setSize( 170, 170); + Dimension asz = this.getSize(); + + vw = asz.width; + vh = asz.height; + + setBackground(Color.black); + myMML = new MML(this); + + imgmanager = manager; + + img = imgmanager.getImage( j2kfilename, vw, vh, session, aux, jppstream, !jppstream); + + addMouseListener(myMML); + addMouseMotionListener(myMML); + addComponentListener( new ResizeListener(this)); + } + + public Image getImage() + { + return img; + } + + public void zoomIn() + { + roirect = null; + roiname = null; + + double scalex = (double)vw/(double)rect.width; + double scaley = (double)vh/(double)rect.height; + + int fw = (int)(imgmanager.getFw()*scalex); + int fh = (int)(imgmanager.getFh()*scaley); + int rx = (int)((imgmanager.getRx()+rect.x)*scalex); + int ry = (int)((imgmanager.getRy()+rect.y)*scaley); + + img = imgmanager.getImage( fw, fh, rx, ry, vw, vh); + + rect.x = rect.y = rect.width = rect.height = 0; + + selected = 0; + fullRefresh = true; + repaint(); + } + + public void enlarge() + { + roirect = null; + roiname = null; + + Dimension asz = this.getSize(); + + vw = asz.width; + vh = asz.height; + + double scalex = vw/(double)imgmanager.getRw(); + double scaley = vh/(double)imgmanager.getRh(); + + int fw = (int)(imgmanager.getFw()*scalex); + int fh = (int)(imgmanager.getFh()*scaley); + int rx = (int)(imgmanager.getRx()*scalex); + int ry = (int)(imgmanager.getRy()*scaley); + + img = imgmanager.getImage( fw, fh, rx, ry, vw, vh); + + fullRefresh = true; + repaint(); + } + + public void setSelected(int state) + { + roirect = null; + roiname = null; + + if (state != selected) { + + selected = state; + repaint(); + } + } + + public boolean isInsideRect(int x, int y) + { + return rect.contains(x - offset.x, y - offset.y); + } + + public void setRGeom(int x1, int y1, int x2, int y2) + { + rect.x = Math.min(x1,x2) - offset.x; + rect.y = Math.min(y1,y2) - offset.y; + rect.width = Math.abs(x2-x1); + rect.height = Math.abs(y2-y1); + } + + // public void annotate( JP2XMLparser.ROIparams roi[]) + // { + // int numofroi = roi.length; + + // roirect = new Rectangle [numofroi]; + // roiname = new String [numofroi]; + + // double scale_x = imgmanager.getFw()/(double)imgmanager.getOrigWidth(); + // double scale_y = imgmanager.getFh()/(double)imgmanager.getOrigHeight(); + // int rx = imgmanager.getRx(); + // int ry = imgmanager.getRy(); + // int rw = imgmanager.getRw(); + // int rh = imgmanager.getRh(); + + // for( int i=0; i<numofroi ; i++){ + // int x = (int)(roi[i].x*scale_x) - rx; + // int y = (int)(roi[i].y*scale_y) - ry; + // int w = (int)(roi[i].w*scale_x); + // int h = (int)(roi[i].h*scale_y); + // if( 0<=x && 0<=y && x+w<=rw && y+h<=rh){ // can be optimized + // roirect[i] = new Rectangle( x, y, w, h); + // roiname[i] = new String( roi[i].name); + // } + // else{ + // roirect[i] = null; + // roiname[i] = null; + // } + // } + // repaint(); + // } + + public boolean hasAnnotation() + { + if( roirect == null) + return false; + else + return true; + } + + public boolean isInsideROIRect(int x, int y) + { + for( int i=0; i<roirect.length; i++) + if( roirect[i] != null) + if( roirect[i].contains(x - offset.x, y - offset.y)){ + rect = roirect[i]; + return true; + } + return false; + } + + public void paint(Graphics g) + { + BufferedImage bi; + Graphics2D big; + Graphics2D g2 = (Graphics2D) g; + + if (fullRefresh) { + g2.clearRect(0, 0, vw, vh); + fullRefresh = false; + } + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g2.setRenderingHint(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_QUALITY); + + offset.x = 0; + offset.y = 0; + + iw = img.getWidth(this); + ih = img.getHeight(this); + + bi = new BufferedImage( iw, ih, BufferedImage.TYPE_INT_RGB); + big = bi.createGraphics(); + + big.drawImage(img, 0, 0, this); + big.setPaint(Color.red); + if ((rect.width > 0) && (rect.height > 0)) + big.draw(rect); + + if( roirect != null){ + for( int i=0; i<roirect.length; i++) + if( roirect[i] != null){ + big.draw( roirect[i]); + big.drawString( roiname[i], roirect[i].x+3, roirect[i].y+roirect[i].height*2/3); + } + } + if (selected == 1) + shadeExt(big, 0, 0, 0, 64); + else if (selected == 2) { + shadeExt(big, 0, 0, 0, 255); + selected = 1; + } + g2.drawImage(bi, offset.x, offset.y, this); + } + + private void shadeRect(Graphics2D g2, int r, int g, int b, int a) + { + g2.setPaint(new Color(r, g, b, a)); + g2.fillRect(rect.x + 1, rect.y + 1, rect.width - 1, rect.height - 1); + } + + private void shadeExt(Graphics2D g2, int r, int g, int b, int a) + { + g2.setPaint(new Color(r, g, b, a)); + g2.fillRect(0, 0, iw, rect.y); /* _N_ */ + g2.fillRect(rect.x + rect.width + 1, rect.y, + iw - rect.x - rect.width - 1, rect.height + 1); /* E */ + g2.fillRect(0, rect.y, rect.x, rect.height + 1); /* W */ + g2.fillRect(0, rect.y + rect.height + 1, + iw, ih - rect.y - rect.height - 1); /* _S_ */ + } +} diff --git a/openjpeg/src/bin/jpip/opj_viewer/src/ImageWindow.java b/openjpeg/src/bin/jpip/opj_viewer/src/ImageWindow.java new file mode 100644 index 000000000..fbf02ea67 --- /dev/null +++ b/openjpeg/src/bin/jpip/opj_viewer/src/ImageWindow.java @@ -0,0 +1,120 @@ +/* + * $Id$ + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import javax.swing.*; +import java.awt.event.*; +import java.awt.*; + +public class ImageWindow extends JFrame +{ + private ImageViewer imgviewer; + private ImageManager imgmanager; + + public ImageWindow( String uri, String j2kfilename, String host, int port, boolean session, boolean jppstream, int aux) + { + super( j2kfilename); + + imgmanager = new ImageManager( uri, host, port); + + imgviewer = new ImageViewer( j2kfilename, imgmanager, session, jppstream, aux); + imgviewer.setOpaque(true); //content panes must be opaque + + JPanel panel = new JPanel(); + panel.setLayout(new BorderLayout()); + panel.add( imgviewer, BorderLayout.CENTER); + + setContentPane( panel); + + addWindowListener(new WindowMyAdapter()); + } + + class WindowMyAdapter extends WindowAdapter + { + public void windowClosing(WindowEvent arg) + { + imgmanager.closeChannel(); + System.exit(0); + } + } + + public static void main(String s[]) + { + String j2kfilename, uri, host; + boolean session, jppstream; + int port, aux; // 0: none, 1: tcp, 2: udp + + if(s.length >= 2){ + uri = s[0]; + j2kfilename = s[1]; + + if( s.length > 2) + host = s[2]; + else + host = "localhost"; + + if( s.length > 3) + port = Integer.valueOf( s[3]).intValue(); + else + port = 50000; + + if( s.length > 4) + session = !s[4].equalsIgnoreCase( "stateless"); + else + session = true; + + if( s.length > 5) + jppstream = !s[5].equalsIgnoreCase( "JPT"); + else + jppstream = true; + + if( s.length > 6){ + if( s[6].equalsIgnoreCase("udp")) + aux = 2; + else + aux = 1; + } + else + aux = 0; + } + else{ + System.out.println("Usage: java -jar opj_viewer.jar HTTP_server_URI imagefile.jp2 [hostname] [portnumber] [stateless/session] [JPT/JPP] [tcp/udp]"); + return; + } + ImageWindow frame = new ImageWindow( uri, j2kfilename, host, port, session, jppstream, aux); + + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + //Display the window. + frame.pack(); + frame.setSize(new Dimension(400,200)); + frame.setLocation( 0, 50); + frame.setVisible(true); + } +} diff --git a/openjpeg/src/bin/jpip/opj_viewer/src/ImgdecClient.java b/openjpeg/src/bin/jpip/opj_viewer/src/ImgdecClient.java new file mode 100644 index 000000000..f7ad8b87e --- /dev/null +++ b/openjpeg/src/bin/jpip/opj_viewer/src/ImgdecClient.java @@ -0,0 +1,350 @@ +/* + * $Id$ + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import java.io.*; +import java.net.*; + +public class ImgdecClient{ + + private String hostname; + private int portNo; + + public ImgdecClient( String host, int port) + { + hostname = host; + portNo = port; + } + + public PnmImage decode_jpipstream( byte[] jpipstream, String tid, String cid, int fw, int fh) + { + if( jpipstream != null) + send_JPIPstream( jpipstream); + return get_PNMstream( cid, tid, fw, fh); + } + + public PnmImage decode_jpipstream( byte[] jpipstream, String j2kfilename, String tid, String cid, int fw, int fh) + { + send_JPIPstream( jpipstream, j2kfilename, tid, cid); + return get_PNMstream( cid, tid, fw, fh); + } + + public void send_JPIPstream( byte[] jpipstream) + { + try{ + Socket imgdecSocket = new Socket( hostname, portNo); + DataOutputStream os = new DataOutputStream( imgdecSocket.getOutputStream()); + DataInputStream is = new DataInputStream( imgdecSocket.getInputStream()); + + System.err.println("Sending " + jpipstream.length + "Data Bytes to decodingServer"); + + os.writeBytes("JPIP-stream\n"); + os.writeBytes("version 1.2\n"); + os.writeBytes( jpipstream.length + "\n"); + os.write( jpipstream, 0, jpipstream.length); + + byte signal = is.readByte(); + + if( signal == 0) + System.err.println(" failed"); + } catch (UnknownHostException e) { + System.err.println("Trying to connect to unknown host: " + e); + } catch (IOException e) { + System.err.println("IOException: " + e); + } + } + + public void send_JPIPstream( byte[] jpipstream, String j2kfilename, String tid, String cid) + { + try{ + Socket imgdecSocket = new Socket( hostname, portNo); + DataOutputStream os = new DataOutputStream( imgdecSocket.getOutputStream()); + DataInputStream is = new DataInputStream( imgdecSocket.getInputStream()); + int length = 0; + + if( jpipstream != null) + length = jpipstream.length; + + System.err.println("Sending " + length + "Data Bytes to decodingServer"); + + os.writeBytes("JPIP-stream\n"); + os.writeBytes("version 1.2\n"); + os.writeBytes( j2kfilename + "\n"); + if( tid == null) + os.writeBytes( "0\n"); + else + os.writeBytes( tid + "\n"); + if( cid == null) + os.writeBytes( "0\n"); + else + os.writeBytes( cid + "\n"); + os.writeBytes( length + "\n"); + os.write( jpipstream, 0, length); + + byte signal = is.readByte(); + + if( signal == 0) + System.err.println(" failed"); + } catch (UnknownHostException e) { + System.err.println("Trying to connect to unknown host: " + e); + } catch (IOException e) { + System.err.println("IOException: " + e); + } + } + + public PnmImage get_PNMstream( String cid, String tid, int fw, int fh) + { + PnmImage pnmstream = null; + + try { + Socket imgdecSocket = new Socket( hostname, portNo); + DataOutputStream os = new DataOutputStream( imgdecSocket.getOutputStream()); + DataInputStream is = new DataInputStream( imgdecSocket.getInputStream()); + byte []header = new byte[7]; + + os.writeBytes("PNM request\n"); + if( cid != null) + os.writeBytes( cid + "\n"); + else + if( tid != null) + os.writeBytes( tid + "\n"); + else + os.writeBytes( "0\n"); + os.writeBytes( fw + "\n"); + os.writeBytes( fh + "\n"); + + read_stream( is, header, 7); + + if( header[0] == 80){ + // P5: gray, P6: color + byte magicknum = header[1]; + if( magicknum == 5 || magicknum == 6){ + int c = magicknum==6 ? 3: 1; + int w = (header[2]&0xff)<<8 | (header[3]&0xff); + int h = (header[4]&0xff)<<8 | (header[5]&0xff); + int maxval = header[6]&0xff; + int length = w*h*c; + + if( maxval == 255 && length != 0){ + pnmstream = new PnmImage( c, w, h); + read_stream( is, pnmstream.get_data(), length); + } + else + System.err.println("Error in get_PNMstream(), only 255 is accepted"); + } + else + System.err.println("Error in get_PNMstream(), wrong magick number" + header[1]); + } + else + System.err.println("Error in get_PNMstream(), Not starting with P"); + + os.close(); + is.close(); + imgdecSocket.close(); + } catch (UnknownHostException e) { + System.err.println("Trying to connect to unknown host: " + e); + } catch (IOException e) { + System.err.println("IOException: " + e); + } + return pnmstream; + } + + public byte [] get_XMLstream( String cid) + { + byte []xmldata = null; + + try{ + Socket imgdecSocket = new Socket( hostname, portNo); + DataOutputStream os = new DataOutputStream( imgdecSocket.getOutputStream()); + DataInputStream is = new DataInputStream( imgdecSocket.getInputStream()); + byte []header = new byte[5]; + + os.writeBytes("XML request\n"); + os.writeBytes( cid + "\n"); + + read_stream( is, header, 5); + + if( header[0] == 88 && header[1] == 77 && header[2] == 76){ + int length = (header[3]&0xff)<<8 | (header[4]&0xff); + + xmldata = new byte[ length]; + read_stream( is, xmldata, length); + } + else + System.err.println("Error in get_XMLstream(), not starting with XML"); + } catch (UnknownHostException e) { + System.err.println("Trying to connect to unknown host: " + e); + } catch (IOException e) { + System.err.println("IOException: " + e); + } + return xmldata; + } + + public String query_cid( String j2kfilename) + { + int []retmsglabel = new int[3]; + retmsglabel[0] = 67; + retmsglabel[1] = 73; + retmsglabel[2] = 68; + + return query_id( "CID request", j2kfilename, retmsglabel); + } + + public String query_tid( String j2kfilename) + { + int []retmsglabel = new int[3]; + retmsglabel[0] = 84; + retmsglabel[1] = 73; + retmsglabel[2] = 68; + + return query_id( "TID request", j2kfilename, retmsglabel); + } + + public String query_id( String reqmsghead, String j2kfilename, int[] retmsglabel) + { + String id = null; + + try{ + Socket imgdecSocket = new Socket( hostname, portNo); + DataOutputStream os = new DataOutputStream( imgdecSocket.getOutputStream()); + DataInputStream is = new DataInputStream( imgdecSocket.getInputStream()); + byte []header = new byte[4]; + + os.writeBytes( reqmsghead + "\n"); + os.writeBytes( j2kfilename + "\n"); + + read_stream( is, header, 4); + + if( header[0] == retmsglabel[0] && header[1] == retmsglabel[1] && header[2] == retmsglabel[2]){ + int length = header[3]&0xff; + + if( length > 0){ + + byte []iddata = new byte[ length]; + read_stream( is, iddata, length); + id = new String( iddata); + } + } + else + System.err.println("Error in query_id("+ reqmsghead + "), wrong to start with " + header); + } + catch (UnknownHostException e) { + System.err.println("Trying to connect to unknown host: " + e); + } catch (IOException e) { + System.err.println("IOException: " + e); + } + + return id; + } + + public java.awt.Dimension query_imagesize( String cid, String tid) + { + java.awt.Dimension dim = null; + + try{ + Socket imgdecSocket = new Socket( hostname, portNo); + DataOutputStream os = new DataOutputStream( imgdecSocket.getOutputStream()); + DataInputStream is = new DataInputStream( imgdecSocket.getInputStream()); + byte []header = new byte[3]; + + os.writeBytes( "SIZ request\n"); + if( tid == null) + os.writeBytes( "0\n"); + else + os.writeBytes( tid + "\n"); + if( cid == null) + os.writeBytes( "0\n"); + else + os.writeBytes( cid + "\n"); + + read_stream( is, header, 3); + + if( header[0] == 83 && header[1] == 73 && header[2] == 90){ + + byte []data = new byte[ 3]; + read_stream( is, data, 3); + int w = (data[0]&0xff)<<16 | (data[1]&0xff)<<8 | (data[2]&0xff); + read_stream( is, data, 3); + int h = (data[0]&0xff)<<16 | (data[1]&0xff)<<8 | (data[2]&0xff); + dim = new java.awt.Dimension( w, h); + } + else + System.err.println("Error in query_imagesize("+ cid + ", " + tid + "), wrong to start with " + header); + } + catch (UnknownHostException e) { + System.err.println("Trying to connect to unknown host: " + e); + } catch (IOException e) { + System.err.println("IOException: " + e); + } + + return dim; + } + + private static void read_stream( DataInputStream is, byte []stream, int length) + { + int remlen = length; + int off = 0; + + try{ + while( remlen > 0){ + int redlen = is.read( stream, off, remlen); + + if( redlen == -1){ + System.err.println(" failed to read_stream()"); + break; + } + off += redlen; + remlen -= redlen; + } + } catch (IOException e) { + System.err.println("IOException: " + e); + } + } + + public void destroy_cid( String cid) + { + try{ + Socket imgdecSocket = new Socket( hostname, portNo); + DataOutputStream os = new DataOutputStream( imgdecSocket.getOutputStream()); + DataInputStream is = new DataInputStream( imgdecSocket.getInputStream()); + + os.writeBytes("CID destroy\n"); + os.writeBytes( cid + "\n"); + + byte signal = is.readByte(); + + if( signal == 0) + System.err.println(" failed"); + } catch (UnknownHostException e) { + System.err.println("Trying to connect to unknown host: " + e); + } catch (IOException e) { + System.err.println("IOException: " + e); + } + } +} diff --git a/openjpeg/src/bin/jpip/opj_viewer/src/JPIPHttpClient.java b/openjpeg/src/bin/jpip/opj_viewer/src/JPIPHttpClient.java new file mode 100644 index 000000000..3c71c5da1 --- /dev/null +++ b/openjpeg/src/bin/jpip/opj_viewer/src/JPIPHttpClient.java @@ -0,0 +1,503 @@ +/* + * $Id$ + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import java.net.*; +import java.io.*; +import java.util.*; + + +public class JPIPHttpClient +{ + private String comURL; + protected int fw, fh; + protected int rx, ry; + protected int rw, rh; + protected String cid; + protected String tid; + private boolean JPTstream; + private boolean JPPstream; + private boolean aux; + private boolean tcp; // true: tcp, false: udp + private int port; + + public JPIPHttpClient( String URI) + { + comURL = URI + "?"; + fw = fh = -1; + rx = ry = -1; + rw = rh = -1; + cid = null; + tid = null; + JPTstream = JPPstream = aux = false; + port = 0; + } + + public int getFw(){ return fw;} + public int getFh(){ return fh;} + public int getRx(){ return rx;} + public int getRy(){ return ry;} + public int getRw(){ return rw;} + public int getRh(){ return rh;} + + public byte[] requestViewWindow( int reqfw, int reqfh) + { + if( cid != null) + return requestViewWindow( reqfw, reqfh, cid); + else + return null; + } + + public byte[] requestViewWindow( int reqfw, int reqfh, int reqrx, int reqry, int reqrw, int reqrh) + { + if( cid != null) + return requestViewWindow( reqfw, reqfh, reqrx, reqry, reqrw, reqrh, cid); + else + if( tid != null) + return requestViewWindow( null, tid, reqfw, reqfh, reqrx, reqry, reqrw, reqrh, null, false, 0, false, false); + else + return null; + } + + public byte[] requestViewWindow( int reqfw, int reqfh, String reqcid) + { + return requestViewWindow( null, null, reqfw, reqfh, -1, -1, -1, -1, reqcid, false, 0, false, false); + } + + public byte[] requestViewWindow( int reqfw, int reqfh, int reqrx, int reqry, int reqrw, int reqrh, String reqcid) + { + return requestViewWindow( null, null, reqfw, reqfh, reqrx, reqry, reqrw, reqrh, reqcid, false, 0, false, false); + } + + public byte[] requestViewWindow( String target, int reqfw, int reqfh) + { + return requestViewWindow( target, null, reqfw, reqfh, -1, -1, -1, -1, null, false, 0, false, false); + } + + public byte[] requestViewWindow( String target, int reqfw, int reqfh, boolean reqcnew, int reqaux, boolean reqJPP, boolean reqJPT) + { + if( cid == null) // 1 channel allocation only + return requestViewWindow( target, null, reqfw, reqfh, -1, -1, -1, -1, null, reqcnew, reqaux, reqJPP, reqJPT); + else + return null; + } + + public byte[] requestViewWindow( String target, String reqtid, int reqfw, int reqfh, boolean reqcnew, int reqaux, boolean reqJPP, boolean reqJPT) + { + if( cid == null) // 1 channel allocation only + return requestViewWindow( target, reqtid, reqfw, reqfh, -1, -1, -1, -1, null, reqcnew, reqaux, reqJPP, reqJPT); + else + return null; + } + + public byte[] requestViewWindow( String target, int reqfw, int reqfh, int reqrx, int reqry, int reqrw, int reqrh) + { + return requestViewWindow( target, null, reqfw, reqfh, reqrx, reqry, reqrw, reqrh, null, false, 0, false, false); + } + + public byte[] requestViewWindow( int reqfw, int reqfh, String reqcid, boolean reqcnew, int reqaux, boolean reqJPP, boolean reqJPT) + { + return requestViewWindow( null, null, reqfw, reqfh, -1, -1, -1, -1, reqcid, reqcnew, reqaux, reqJPP, reqJPT); + } + + public byte[] requestViewWindow( String target, + String reqtid, + int reqfw, int reqfh, + int reqrx, int reqry, + int reqrw, int reqrh, + String reqcid, boolean reqcnew, int reqaux, boolean reqJPP, boolean reqJPT) + { + if( reqtid != null) + tid = reqtid; + + String urlstring = const_urlstring( target, reqtid, reqfw, reqfh, reqrx, reqry, reqrw, reqrh, reqcid, reqcnew, reqaux, reqJPP, reqJPT); + return GETrequest( urlstring); + } + + public byte[] requestXML() + { + String urlstring = comURL; + + if( cid == null) + return null; + + urlstring = urlstring.concat( "cid=" + cid); + urlstring = urlstring.concat( "&metareq=[xml_]"); + + return GETrequest( urlstring); + } + + private byte[] GETrequest( String urlstring) + { + URL url = null; + HttpURLConnection urlconn = null; + byte[] jpipstream = null; + + try{ + url = new URL( urlstring); + + System.err.println("Requesting: " + url); + + urlconn = (HttpURLConnection)url.openConnection(); + urlconn.setRequestMethod("GET"); + urlconn.setInstanceFollowRedirects(false); + urlconn.connect(); + + set_responseheader( urlconn); + + if( !aux){ + jpipstream = receive_httpchunk( urlconn); + urlconn.disconnect(); + } + else{ + urlconn.disconnect(); + jpipstream = receive_tcpaux( comURL.substring( 7, comURL.indexOf('/', 7)), port, cid); + } + } + catch ( MalformedURLException e){ + e.printStackTrace(); + } + catch ( ProtocolException e){ + e.printStackTrace(); + } + catch( ClassCastException e){ + e.printStackTrace(); + } + catch( NullPointerException e){ + e.printStackTrace(); + } + catch( UnknownServiceException e){ + e.printStackTrace(); + } + catch ( IOException e){ + e.printStackTrace(); + } + + return jpipstream; + } + + private void set_responseheader( HttpURLConnection urlconn) + { + Map<String,java.util.List<String>> headers = urlconn.getHeaderFields(); + java.util.List<String> hvaluelist; + String hvalueline; + + String status = headers.get(null).get(0); + + System.err.println( status); + if( !status.contains("OK")) + System.err.println( headers.get("Reason")); + + if(( hvaluelist = headers.get("Content-type")) == null) + hvaluelist = headers.get("Content-Type"); + hvalueline = hvaluelist.get(0); + System.err.println( hvalueline); + + if( hvalueline.endsWith("jpt-stream")) + JPTstream = true; + else if( hvalueline.endsWith("jpp-stream")) + JPPstream = true; + + if(( hvaluelist = headers.get("JPIP-fsiz")) != null){ + hvalueline = hvaluelist.get(0); + fw = Integer.valueOf( hvalueline.substring( 0, hvalueline.indexOf(','))).intValue(); + fh = Integer.valueOf( hvalueline.substring( hvalueline.indexOf(',')+1 )).intValue(); + + System.err.println("fw,fh: " + fw + "," + fh); + } + + if(( hvaluelist = headers.get("JPIP-roff")) != null){ + hvalueline = hvaluelist.get(0); + rx = Integer.valueOf( hvalueline.substring( 0, hvalueline.indexOf(','))).intValue(); + ry = Integer.valueOf( hvalueline.substring( hvalueline.indexOf(',')+1 )).intValue(); + System.err.println("rx,ry: " + rx + "," + ry); + } + + if(( hvaluelist = headers.get("JPIP-rsiz")) != null){ + hvalueline = hvaluelist.get(0); + rw = Integer.valueOf( hvalueline.substring( 0, hvalueline.indexOf(','))).intValue(); + rh = Integer.valueOf( hvalueline.substring( hvalueline.indexOf(',')+1 )).intValue(); + System.err.println("rw,rh: " + rw + "," + rh); + } + + if(( hvaluelist = headers.get("JPIP-cnew")) != null){ + hvalueline = hvaluelist.get(0); + cid = hvalueline.substring( hvalueline.indexOf('=')+1, hvalueline.indexOf(',')); + + int idxOfcid = hvalueline.indexOf("transport")+10; + int idxOfcid2 = hvalueline.indexOf(',', idxOfcid); + String transport; + if( idxOfcid2 != -1) + transport = hvalueline.substring( idxOfcid, idxOfcid2); + else + transport = hvalueline.substring( idxOfcid); + + if( transport.matches("http-tcp")){ + aux = true; + tcp = true; + } + else if( transport.matches("http-udp")){ + aux = true; + tcp = false; + } + else + aux = false; + + if( aux){ + idxOfcid = hvalueline.indexOf("auxport")+8; + port = Integer.valueOf( hvalueline.substring( idxOfcid)).intValue(); + System.err.println("cid: " + cid + ", transport: " + transport + ", auxport: " + port); + } + else + System.err.println("cid: " + cid + ", transport: " + transport); + } + + if(( hvaluelist = headers.get("JPIP-tid")) != null){ + hvalueline = hvaluelist.get(0); + tid = hvalueline.substring( hvalueline.indexOf('=')+1); + System.err.println("tid: " + tid); + } + } + + private static byte[] receive_httpchunk( HttpURLConnection urlconn) + { + byte[] chunk = null; + InputStream input; + + try{ + input = urlconn.getInputStream(); + + if( input.available() > 0){ + ByteArrayOutputStream tmpstream = new ByteArrayOutputStream(); + byte[] buf = new byte[ 1024]; + int redlen, buflen; + + System.err.println("reading jpipstream..."); + + do{ + redlen = input.read( buf); + + if( redlen == -1) + break; + tmpstream.write( buf, 0, redlen); + }while( redlen > 0); + + buflen = tmpstream.size(); + chunk = tmpstream.toByteArray(); + + buf = null; + tmpstream = null; + + System.err.println("jpiplen: " + buflen); + System.err.println(" succeeded"); + } + else{ + System.err.println("No new jpipstream"); + } + input.close(); + } + catch ( IOException e){ + e.printStackTrace(); + } + + return chunk; + } + + private static byte[] receive_tcpaux( String host, int port, String cid) + { + Socket jpipsocket; + DataOutputStream os; + DataInputStream is; + byte []auxheader; + byte []chunkbody = null; + byte []stream = null; + int chunkbodylen, streamlen, headlen = 8; + ByteArrayOutputStream tmpstream; + + try{ + jpipsocket = new Socket( host, port); + os = new DataOutputStream( jpipsocket.getOutputStream()); + is = new DataInputStream( jpipsocket.getInputStream()); + auxheader = new byte[headlen]; + tmpstream = new ByteArrayOutputStream(); + + os.writeBytes( cid + "\r\n"); + + do{ + read_stream( is, auxheader, headlen); + + chunkbodylen = ((auxheader[0]&0xff)<<8 | (auxheader[1]&0xff)) - headlen; + + chunkbody = new byte [ chunkbodylen]; + read_stream( is, chunkbody, chunkbodylen); + tmpstream.write( chunkbody, 0, chunkbodylen); + + os.write( auxheader, 0, headlen); + }while( !(chunkbody[chunkbodylen-3]==0x00 && ( chunkbody[chunkbodylen-2]==0x01 || chunkbody[chunkbodylen-2]== 0x02))); + + streamlen = tmpstream.size(); + stream = tmpstream.toByteArray(); + + System.err.println("jpiplen: " + streamlen); + System.err.println(" succeeded"); + + chunkbody = null; + tmpstream = null; + + os.close(); + is.close(); + + jpipsocket.close(); + } + catch ( IOException e){ + e.printStackTrace(); + } + + return stream; + } + + private static void read_stream( InputStream is, byte []stream, int length) + { + int remlen = length; + int off = 0; + + try{ + while( remlen > 0){ + int redlen = is.read( stream, off, remlen); + + if( redlen == -1){ + System.err.println(" failed to read_stream()"); + break; + } + off += redlen; + remlen -= redlen; + } + } catch (IOException e) { + System.err.println("IOException: " + e); + } + } + + private String const_urlstring( String target, + String reqtid, + int reqfw, int reqfh, + int reqrx, int reqry, + int reqrw, int reqrh, + String reqcid, boolean reqcnew, int reqaux, boolean reqJPP, boolean reqJPT) + { + String urlstring = comURL; + + // C.7.3 Image Return Type + // add type=jpp-stream(;ptype=ext) or type=jpt-stream;ttype=ext + + if( target != null){ + if( !urlstring.endsWith("?")) + urlstring = urlstring.concat( "&"); + urlstring = urlstring.concat( "target=" + target); + } + if( reqtid != null){ + if( !urlstring.endsWith("?")) + urlstring = urlstring.concat( "&"); + urlstring = urlstring.concat( "tid=" + reqtid); + } + if( reqfw != -1 && reqfh != -1){ + if( !urlstring.endsWith("?")) + urlstring = urlstring.concat( "&"); + urlstring = urlstring.concat( "fsiz=" + reqfw + "," + reqfh); + } + if( reqrx != -1 && reqry != -1){ + if( !urlstring.endsWith("?")) + urlstring = urlstring.concat( "&"); + urlstring = urlstring.concat( "roff=" + reqrx + "," + reqry); + } + if( reqrw != -1 && reqrh != -1){ + if( !urlstring.endsWith("?")) + urlstring = urlstring.concat( "&"); + urlstring = urlstring.concat( "rsiz=" + reqrw + "," + reqrh); + } + if( reqcid != null){ + if( !urlstring.endsWith("?")) + urlstring = urlstring.concat( "&"); + urlstring = urlstring.concat( "cid=" + reqcid); + } + if( reqcnew){ + if( !urlstring.endsWith("?")) + urlstring = urlstring.concat( "&"); + if( reqaux == 1) + urlstring = urlstring.concat( "cnew=http-tcp"); + else if( reqaux == 2) + urlstring = urlstring.concat( "cnew=http-udp"); + else + urlstring = urlstring.concat( "cnew=http"); + } + if( reqJPP && !JPTstream){ + if( !urlstring.endsWith("?")) + urlstring = urlstring.concat( "&"); + urlstring = urlstring.concat( "type=jpp-stream"); + } + else if( reqJPT && !JPPstream){ + if( !urlstring.endsWith("?")) + urlstring = urlstring.concat( "&"); + urlstring = urlstring.concat( "type=jpt-stream"); + } + else{ // remove this option later + if( !urlstring.endsWith("?")) + urlstring = urlstring.concat( "&"); + if( JPTstream) + urlstring = urlstring.concat( "type=jpt-stream"); + else if( JPPstream) + urlstring = urlstring.concat( "type=jpp-stream"); + } + + return urlstring; + } + + public void closeChannel() + { + if( cid == null) + return; + + try{ + URL url = new URL( comURL + "cclose=" + cid); + System.err.println( "closing cid: " + cid); + + HttpURLConnection urlconn = (HttpURLConnection)url.openConnection(); + urlconn.setRequestMethod("GET"); + urlconn.setInstanceFollowRedirects(false); + urlconn.connect(); + + Map headers = urlconn.getHeaderFields(); + + urlconn.disconnect(); + } catch ( MalformedURLException e){ + e.printStackTrace(); + } catch ( IOException e){ + e.printStackTrace(); + } + } +} diff --git a/openjpeg/src/bin/jpip/opj_viewer/src/MML.java b/openjpeg/src/bin/jpip/opj_viewer/src/MML.java new file mode 100644 index 000000000..45c495e22 --- /dev/null +++ b/openjpeg/src/bin/jpip/opj_viewer/src/MML.java @@ -0,0 +1,116 @@ +/* + * $Id$ + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import java.awt.event.*; + +class MML implements MouseMotionListener, MouseListener +{ + public void mouseExited(MouseEvent e) {} + public void mouseEntered(MouseEvent e) {} + public void mouseClicked(MouseEvent e) {} + + private ImageViewer iv; + private int x1, y1, x2, y2, zf, btn; + private boolean zoomrq; + + public MML(ImageViewer imageviewer) + { + x1 = y1 = -1; + iv = imageviewer; + zoomrq = false; + zf = 0; + } + + private boolean isInside(int x, int y) + { + x -= iv.getX(); + y -= iv.getY(); + return (x >= 0) && (x < iv.getWidth()) + && (y >= 0) && (y < iv.getHeight()); + } + + public void mousePressed(MouseEvent e) + { + btn = e.getButton(); + + if( iv.hasAnnotation()){ + if( iv.isInsideROIRect(e.getX(), e.getY())){ + iv.zoomIn(); + System.out.println("annotation click"); + return; + } + } + if (iv.isInsideRect(e.getX(), e.getY())) { + iv.setSelected(2); + iv.repaint(); + zoomrq = true; + } else { + iv.setRGeom(0, 0, 0, 0); + iv.setSelected(0); + iv.repaint(); + x1 = y1 = -1; + } + } + + public void mouseReleased(MouseEvent e) + { + if(e.getButton() == 1) { + if (zoomrq) { + iv.zoomIn(); + zoomrq = false; + } + } + } + + public void mouseMoved(MouseEvent e) + { + } + + public void mouseDragged(MouseEvent e) + { + if (btn == 1) { + x2 = e.getX(); + y2 = e.getY(); + + iv.setSelected(0); + zoomrq = false; + + if (isInside(x2, y2)) { + if (x1 == -1) { + x1 = x2; + y1 = y2; + } else { + iv.setRGeom(x1, y1, x2, y2); + iv.repaint(); + } + } + } + } +} diff --git a/openjpeg/src/bin/jpip/opj_viewer/src/PnmImage.java b/openjpeg/src/bin/jpip/opj_viewer/src/PnmImage.java new file mode 100644 index 000000000..9b225386e --- /dev/null +++ b/openjpeg/src/bin/jpip/opj_viewer/src/PnmImage.java @@ -0,0 +1,154 @@ +/* + * $Id$ + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import java.awt.*; +import java.awt.image.*; +import java.io.*; +import java.util.regex.*; + +public class PnmImage extends Component +{ + private byte[] data = null; + private int width = 0; + private int height = 0; + private int channel = 0; + + public PnmImage( int c, int w, int h) + { + channel = c; + width = w; + height = h; + data = new byte [ w*h*c]; + } + + public PnmImage( String filename) + { + String str; + Pattern pat; + Matcher mat; + int bytes; + int r, offset = 0; + + try { + FileInputStream fis = new FileInputStream( new File(filename)); + DataInputStream is = new DataInputStream( fis); + + pat = Pattern.compile("^P([56])$"); + mat = pat.matcher(str = is.readLine()); + if( !mat.matches()){ + System.out.println("PNM header format error"); + return; + } + + if( (mat.group(1)).compareTo("5") == 0) + channel = 1; + else + channel = 3; + + pat = Pattern.compile("^(\\d+) (\\d+)$"); + mat = pat.matcher(str = is.readLine()); + if( !mat.matches()){ + System.out.println("PNM header format error"); + return; + } + width = Integer.parseInt( mat.group(1)); + height = Integer.parseInt( mat.group(2)); + + str = is.readLine(); // 255 + + bytes = width*height*channel; + data = new byte[bytes]; + + while( bytes > 0){ + try { + r = is.read(data, offset, bytes); + if( r == -1){ + System.err.println(" failed to read()"); + break; + } + offset += r; + bytes -= r; + } + catch (IOException e) { e.printStackTrace(); } + } + fis.close(); + } catch (IOException e) { e.printStackTrace(); } + } + + public byte [] get_data(){ return data;} + public int get_width() { return width;} + public int get_height(){ return height;} + + public Image createROIImage( int rx, int ry, int rw, int rh) + { + int []pix = new int[ rw*rh]; + + for( int i=0; i<rh; i++) + for( int j=0; j<rw; j++){ + pix[i*rw+j] = 0xFF << 24; // transparency + if( channel == 1){ + Byte lum = data[(ry+i)*width+rx+j]; + short slum; + + if( lum < 0) + slum = (short)(2*128+lum); + else + slum = (short)lum; + + for( int c=0; c<3; c++){ + pix[i*rw+j] = pix[i*rw+j] | slum << (8*c); + } + } + else + for( int c=0; c<3; c++){ + Byte lum = data[ ((ry+i)*width+rx+j)*channel+(2-c)]; + short slum; + + if( lum < 0) + slum = (short)(2*128+lum); + else + slum = (short)lum; + + pix[i*rw+j] = pix[i*rw+j] | slum << (8*c); + } + } + + return createImage(new MemoryImageSource( rw, rh, pix, 0, rw)); + } + + public Image createScaleImage( double scale) + { + Image src = createROIImage( 0, 0, width, height); + ImageFilter replicate = new ReplicateScaleFilter( (int)(width*scale), (int)(height*scale)); + ImageProducer prod = new FilteredImageSource( src.getSource(), replicate); + + return createImage(prod); + } +} diff --git a/openjpeg/src/bin/jpip/opj_viewer/src/RegimViewer.java b/openjpeg/src/bin/jpip/opj_viewer/src/RegimViewer.java new file mode 100644 index 000000000..9bc898a18 --- /dev/null +++ b/openjpeg/src/bin/jpip/opj_viewer/src/RegimViewer.java @@ -0,0 +1,114 @@ +/* + * $Id$ + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import javax.swing.*; +import java.awt.*; +import java.awt.image.*; +import java.awt.geom.AffineTransform; + +public class RegimViewer extends JPanel +{ + private PnmImage refpnm; + private int vw, vh; + private Image refimg; + private Image jpipImg; + private double[] affine_matrix; + private AffineTransform affine; + + public RegimViewer( String refname, double[] mat) + { + refpnm = new PnmImage( refname.replaceFirst("jp2", "pgm")); // decoding not realized + affine_matrix = new double[6]; + + affine_matrix[0] = mat[0]; + affine_matrix[1] = mat[3]; + affine_matrix[2] = mat[1]; + affine_matrix[3] = mat[4]; + affine_matrix[4] = mat[2]; + affine_matrix[5] = mat[5]; + + affine = new AffineTransform(); + + for( int i=0; i<3; i++){ + for( int j=0; j<3; j++) + System.out.print( mat[i*3+j] + " "); + System.out.println(); + } + } + + public void projection( Image jpipimg, double scale) + { + jpipImg = jpipimg; + refimg = refpnm.createScaleImage( scale); + vw = refimg.getWidth(this); + vh = refimg.getHeight(this); + this.setSize( vw, vh); + + affine.setTransform( affine_matrix[0], affine_matrix[1], affine_matrix[2], affine_matrix[3], affine_matrix[4], affine_matrix[5]); + repaint(); + } + + public void paint(Graphics g) + { + int iw, ih; + BufferedImage bi, bi2; + Graphics2D big, big2; + Graphics2D g2 = (Graphics2D) g; + + g2.clearRect(0, 0, vw, vh); + + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g2.setRenderingHint(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_QUALITY); + + iw = refimg.getWidth(this); + ih = refimg.getHeight(this); + + bi = new BufferedImage( iw, ih, BufferedImage.TYPE_INT_RGB); + big = bi.createGraphics(); + big.drawImage(refimg, 0, 0, this); + + g2.drawImage(bi, 0, 0, this); + + bi2 = new BufferedImage( jpipImg.getWidth(this), jpipImg.getHeight(this), BufferedImage.TYPE_INT_RGB); + big2 = bi2.createGraphics(); + big2.drawImage( jpipImg, 0, 0, this); + + g2.setTransform(affine); + + g2.drawImage(bi2, 0, 0, this); + } + + public Dimension get_imsize() + { + return (new Dimension( vw, vh)); + } +} diff --git a/openjpeg/src/bin/jpip/opj_viewer/src/ResizeListener.java b/openjpeg/src/bin/jpip/opj_viewer/src/ResizeListener.java new file mode 100644 index 000000000..150ec46aa --- /dev/null +++ b/openjpeg/src/bin/jpip/opj_viewer/src/ResizeListener.java @@ -0,0 +1,67 @@ +/* + * $Id$ + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; + +class ResizeListener implements ComponentListener +{ + private ImageViewer iv; + private Dimension largest; + + public ResizeListener( ImageViewer _iv) + { + iv = _iv; + largest = iv.getSize(); + } + + public void componentHidden(ComponentEvent e) {} + + public void componentMoved(ComponentEvent e) {} + + public void componentResized(ComponentEvent e) { + Dimension cursize = iv.getSize(); + if( largest.getWidth() < cursize.getWidth() || largest.getHeight() < cursize.getHeight()){ + update_largest( cursize); + iv.enlarge(); + } + } + + private void update_largest( Dimension cursize) + { + if( largest.getWidth() < cursize.getWidth()) + largest.setSize( cursize.getWidth(), largest.getHeight()); + if( largest.getHeight() < cursize.getHeight()) + largest.setSize( largest.getWidth(), cursize.getHeight()); + } + + public void componentShown(ComponentEvent e) {} +} diff --git a/openjpeg/src/bin/jpip/opj_viewer_xerces/dist/manifest.txt.in b/openjpeg/src/bin/jpip/opj_viewer_xerces/dist/manifest.txt.in new file mode 100644 index 000000000..c7ba9f368 --- /dev/null +++ b/openjpeg/src/bin/jpip/opj_viewer_xerces/dist/manifest.txt.in @@ -0,0 +1,5 @@ +Manifest-Version: 1.0 +Ant-Version: Apache Ant 1.7.0 +Created-By: Kaori Hagihara +Main-Class: ImageWindow +Class-Path: @APACHE_XERCES_JAR@ diff --git a/openjpeg/src/bin/jpip/opj_viewer_xerces/src/ImageViewer.java b/openjpeg/src/bin/jpip/opj_viewer_xerces/src/ImageViewer.java new file mode 100644 index 000000000..827372a8f --- /dev/null +++ b/openjpeg/src/bin/jpip/opj_viewer_xerces/src/ImageViewer.java @@ -0,0 +1,266 @@ +/* + * $Id$ + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import java.awt.image.*; +import java.awt.geom.*; +import java.net.URL; +import javax.swing.border.*; +import java.util.*; +import java.io.*; + +public class ImageViewer extends JPanel +{ + private ImageManager imgmanager; + private int vw, vh; + private int iw, ih; + private int selected = 0; + private Image img; + + private String cmdline = new String(); + private boolean fullRefresh = false; + private Point offset = new Point(0,0); + private Rectangle rect = new Rectangle(); + private Rectangle roirect[] = null; + private String roiname[] = null; + + public ImageViewer( String j2kfilename, ImageManager manager, boolean session, boolean jppstream, int aux) + { + String str; + MML myMML; + + this.setSize( 170, 170); + Dimension asz = this.getSize(); + + vw = asz.width; + vh = asz.height; + + setBackground(Color.black); + myMML = new MML(this); + + imgmanager = manager; + + img = imgmanager.getImage( j2kfilename, vw, vh, session, aux, jppstream, !jppstream); + + addMouseListener(myMML); + addMouseMotionListener(myMML); + addComponentListener( new ResizeListener(this)); + } + + public Image getImage() + { + return img; + } + + public void zoomIn() + { + roirect = null; + roiname = null; + + double scalex = (double)vw/(double)rect.width; + double scaley = (double)vh/(double)rect.height; + + int fw = (int)(imgmanager.getFw()*scalex); + int fh = (int)(imgmanager.getFh()*scaley); + int rx = (int)((imgmanager.getRx()+rect.x)*scalex); + int ry = (int)((imgmanager.getRy()+rect.y)*scaley); + + img = imgmanager.getImage( fw, fh, rx, ry, vw, vh); + + rect.x = rect.y = rect.width = rect.height = 0; + + selected = 0; + fullRefresh = true; + repaint(); + } + + public void enlarge() + { + roirect = null; + roiname = null; + + Dimension asz = this.getSize(); + + vw = asz.width; + vh = asz.height; + + double scalex = vw/(double)imgmanager.getRw(); + double scaley = vh/(double)imgmanager.getRh(); + + int fw = (int)(imgmanager.getFw()*scalex); + int fh = (int)(imgmanager.getFh()*scaley); + int rx = (int)(imgmanager.getRx()*scalex); + int ry = (int)(imgmanager.getRy()*scaley); + + img = imgmanager.getImage( fw, fh, rx, ry, vw, vh); + + fullRefresh = true; + repaint(); + } + + public void setSelected(int state) + { + roirect = null; + roiname = null; + + if (state != selected) { + + selected = state; + repaint(); + } + } + + public boolean isInsideRect(int x, int y) + { + return rect.contains(x - offset.x, y - offset.y); + } + + public void setRGeom(int x1, int y1, int x2, int y2) + { + rect.x = Math.min(x1,x2) - offset.x; + rect.y = Math.min(y1,y2) - offset.y; + rect.width = Math.abs(x2-x1); + rect.height = Math.abs(y2-y1); + } + + public void annotate( JP2XMLparser.ROIparams roi[]) + { + int numofroi = roi.length; + + roirect = new Rectangle [numofroi]; + roiname = new String [numofroi]; + + double scale_x = imgmanager.getFw()/(double)imgmanager.getOrigWidth(); + double scale_y = imgmanager.getFh()/(double)imgmanager.getOrigHeight(); + int rx = imgmanager.getRx(); + int ry = imgmanager.getRy(); + int rw = imgmanager.getRw(); + int rh = imgmanager.getRh(); + + for( int i=0; i<numofroi ; i++){ + int x = (int)(roi[i].x*scale_x) - rx; + int y = (int)(roi[i].y*scale_y) - ry; + int w = (int)(roi[i].w*scale_x); + int h = (int)(roi[i].h*scale_y); + if( 0<=x && 0<=y && x+w<=rw && y+h<=rh){ // can be optimized + roirect[i] = new Rectangle( x, y, w, h); + roiname[i] = new String( roi[i].name); + } + else{ + roirect[i] = null; + roiname[i] = null; + } + } + repaint(); + } + + public boolean hasAnnotation() + { + if( roirect == null) + return false; + else + return true; + } + + public boolean isInsideROIRect(int x, int y) + { + for( int i=0; i<roirect.length; i++) + if( roirect[i] != null) + if( roirect[i].contains(x - offset.x, y - offset.y)){ + rect = roirect[i]; + return true; + } + return false; + } + + public void paint(Graphics g) + { + BufferedImage bi; + Graphics2D big; + Graphics2D g2 = (Graphics2D) g; + + if (fullRefresh) { + g2.clearRect(0, 0, vw, vh); + fullRefresh = false; + } + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g2.setRenderingHint(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_QUALITY); + + offset.x = 0; + offset.y = 0; + + iw = img.getWidth(this); + ih = img.getHeight(this); + + bi = new BufferedImage( iw, ih, BufferedImage.TYPE_INT_RGB); + big = bi.createGraphics(); + + big.drawImage(img, 0, 0, this); + big.setPaint(Color.red); + if ((rect.width > 0) && (rect.height > 0)) + big.draw(rect); + + if( roirect != null){ + for( int i=0; i<roirect.length; i++) + if( roirect[i] != null){ + big.draw( roirect[i]); + big.drawString( roiname[i], roirect[i].x+3, roirect[i].y+roirect[i].height*2/3); + } + } + if (selected == 1) + shadeExt(big, 0, 0, 0, 64); + else if (selected == 2) { + shadeExt(big, 0, 0, 0, 255); + selected = 1; + } + g2.drawImage(bi, offset.x, offset.y, this); + } + + private void shadeRect(Graphics2D g2, int r, int g, int b, int a) + { + g2.setPaint(new Color(r, g, b, a)); + g2.fillRect(rect.x + 1, rect.y + 1, rect.width - 1, rect.height - 1); + } + + private void shadeExt(Graphics2D g2, int r, int g, int b, int a) + { + g2.setPaint(new Color(r, g, b, a)); + g2.fillRect(0, 0, iw, rect.y); /* _N_ */ + g2.fillRect(rect.x + rect.width + 1, rect.y, + iw - rect.x - rect.width - 1, rect.height + 1); /* E */ + g2.fillRect(0, rect.y, rect.x, rect.height + 1); /* W */ + g2.fillRect(0, rect.y + rect.height + 1, + iw, ih - rect.y - rect.height - 1); /* _S_ */ + } +} diff --git a/openjpeg/src/bin/jpip/opj_viewer_xerces/src/ImageWindow.java b/openjpeg/src/bin/jpip/opj_viewer_xerces/src/ImageWindow.java new file mode 100644 index 000000000..fa12ddd24 --- /dev/null +++ b/openjpeg/src/bin/jpip/opj_viewer_xerces/src/ImageWindow.java @@ -0,0 +1,124 @@ +/* + * $Id$ + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import javax.swing.*; +import java.awt.event.*; +import java.awt.*; + +public class ImageWindow extends JFrame +{ + private ImageViewer imgviewer; + private OptionPanel optpanel; + private ImageManager imgmanager; + + public ImageWindow( String uri, String j2kfilename, String host, int port, boolean session, boolean jppstream, int aux) + { + super( j2kfilename); + + imgmanager = new ImageManager( uri, host, port); + + imgviewer = new ImageViewer( j2kfilename, imgmanager, session, jppstream, aux); + imgviewer.setOpaque(true); //content panes must be opaque + + optpanel = new OptionPanel( imgmanager, imgviewer); + + JPanel panel = new JPanel(); + panel.setLayout(new BorderLayout()); + panel.add( imgviewer, BorderLayout.CENTER); + panel.add( optpanel, BorderLayout.EAST); + + setContentPane( panel); + + addWindowListener(new WindowMyAdapter()); + } + + class WindowMyAdapter extends WindowAdapter + { + public void windowClosing(WindowEvent arg) + { + imgmanager.closeChannel(); + System.exit(0); + } + } + + public static void main(String s[]) + { + String j2kfilename, uri, host; + boolean session, jppstream; + int port, aux; // 0: none, 1: tcp, 2: udp + + if(s.length >= 2){ + uri = s[0]; + j2kfilename = s[1]; + + if( s.length > 2) + host = s[2]; + else + host = "localhost"; + + if( s.length > 3) + port = Integer.valueOf( s[3]).intValue(); + else + port = 50000; + + if( s.length > 4) + session = !s[4].equalsIgnoreCase( "stateless"); + else + session = true; + + if( s.length > 5) + jppstream = !s[5].equalsIgnoreCase( "JPT"); + else + jppstream = true; + + if( s.length > 6){ + if( s[6].equalsIgnoreCase("udp")) + aux = 2; + else + aux = 1; + } + else + aux = 0; + } + else{ + System.out.println("Usage: java -jar opj_viewer.jar HTTP_server_URI imagefile.jp2 [hostname] [portnumber] [stateless/session] [JPT/JPP] [tcp/udp]"); + return; + } + ImageWindow frame = new ImageWindow( uri, j2kfilename, host, port, session, jppstream, aux); + + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + //Display the window. + frame.pack(); + frame.setSize(new Dimension(400,200)); + frame.setLocation( 0, 50); + frame.setVisible(true); + } +} diff --git a/openjpeg/src/bin/jpip/opj_viewer_xerces/src/JP2XMLparser.java b/openjpeg/src/bin/jpip/opj_viewer_xerces/src/JP2XMLparser.java new file mode 100644 index 000000000..e844eaa86 --- /dev/null +++ b/openjpeg/src/bin/jpip/opj_viewer_xerces/src/JP2XMLparser.java @@ -0,0 +1,122 @@ +/* + * $Id$ + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXParseException; +import org.xml.sax.ErrorHandler; +import org.apache.xerces.parsers.DOMParser; +import org.xml.sax.InputSource; +import java.io.*; +import java.lang.Integer; + +public class JP2XMLparser +{ + Document document; + + public static class ROIparams{ + public String name = null; + public int x = 0; + public int y = 0; + public int w = 0; + public int h = 0; + } + + public static class IRTparams{ + public String refimg = null; + public double []mat = { 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0}; + } + + public JP2XMLparser( byte[] buf) + { + try{ + InputSource source = new InputSource( new ByteArrayInputStream( buf)); + DOMParser parser = new DOMParser(); + parser.setErrorHandler(new MyHandler()); + parser.parse( source); + document = parser.getDocument(); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + public ROIparams [] getROIparams() + { + ROIparams roi[]; + NodeList elements = document.getElementsByTagName("roi"); + int elementCount = elements.getLength(); + + roi = new ROIparams [elementCount]; + + for( int i = 0; i < elementCount; i++) { + Element element = (Element)elements.item(i); + + roi[i] = new ROIparams(); + roi[i].name = element.getAttribute( "name"); + roi[i].x = Integer.parseInt( element.getAttribute( "x")) ; + roi[i].y = Integer.parseInt( element.getAttribute( "y")) ; + roi[i].w = Integer.parseInt( element.getAttribute( "w")) ; + roi[i].h = Integer.parseInt( element.getAttribute( "h")) ; + } + return roi; + } + + public IRTparams getIRTparams() + { + IRTparams irt = new IRTparams(); + NodeList elements = document.getElementsByTagName("irt"); + int elementCount = elements.getLength(); + + Element element = (Element)elements.item(0); + irt.refimg = element.getAttribute( "refimg"); + for( int i=1; i<=9; i++) + irt.mat[i-1] = Double.parseDouble( element.getAttribute("m" + i)); + + return irt; + } +} + +class MyHandler implements ErrorHandler { + public void warning(SAXParseException e) { + System.out.println("Warning: line" + e.getLineNumber()); + System.out.println(e.getMessage()); + } + public void error(SAXParseException e) { + System.out.println("Error: line" + e.getLineNumber()); + System.out.println(e.getMessage()); + } + public void fatalError(SAXParseException e) { + System.out.println("Critical error: line" + e.getLineNumber()); + System.out.println(e.getMessage()); + } +}
\ No newline at end of file diff --git a/openjpeg/src/bin/jpip/opj_viewer_xerces/src/OptionPanel.java b/openjpeg/src/bin/jpip/opj_viewer_xerces/src/OptionPanel.java new file mode 100644 index 000000000..23a270143 --- /dev/null +++ b/openjpeg/src/bin/jpip/opj_viewer_xerces/src/OptionPanel.java @@ -0,0 +1,98 @@ +/* + * $Id$ + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2010-2011, Kaori Hagihara + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; + +public class OptionPanel extends JPanel implements ActionListener +{ + private JButton roibutton; + private JButton imregbutton; + private ImageManager imgmanager; + private ImageViewer iv; + private JP2XMLparser xmlparser; + private JFrame regimwindow; + private RegimViewer regimgviewer; + + public OptionPanel( ImageManager manager, ImageViewer imgviewer) + { + this.setLayout(new BoxLayout( this, BoxLayout.Y_AXIS)); + + roibutton = new JButton("Region Of Interest"); + imregbutton = new JButton("Image Registration"); + + roibutton.setAlignmentX( Component.CENTER_ALIGNMENT); + imregbutton.setAlignmentX( Component.CENTER_ALIGNMENT); + + add( roibutton); + add( imregbutton); + roibutton.addActionListener(this); + imregbutton.addActionListener(this); + + imgmanager = manager; + iv = imgviewer; + xmlparser = null; + } + + public void actionPerformed(ActionEvent e) + { + if( xmlparser == null){ + byte []xmldata = imgmanager.getXML(); + if( xmldata != null) + xmlparser = new JP2XMLparser( xmldata); + } + if( e.getSource() == roibutton){ + if( xmlparser != null){ + JP2XMLparser.ROIparams roi[] = xmlparser.getROIparams(); + iv.annotate( roi); + } + } + if( e.getSource() == imregbutton){ + if( xmlparser != null){ + if( regimwindow == null){ + JP2XMLparser.IRTparams irt = xmlparser.getIRTparams(); + + regimgviewer = new RegimViewer( irt.refimg, irt.mat); + regimgviewer.setOpaque(false); + + regimwindow = new JFrame("Registered Image"); + regimwindow.getContentPane().add("Center", regimgviewer); + regimwindow.pack(); + regimwindow.setLocation( 500, 50); + regimwindow.setVisible(true); + } + regimgviewer.projection( iv.getImage(), (double)imgmanager.getRw()/(double)imgmanager.getOrigWidth()); + regimwindow.setSize( regimgviewer.get_imsize()); + regimwindow.show(); + } + } + } +}
\ No newline at end of file diff --git a/openjpeg/src/bin/jpwl/CMakeLists.txt b/openjpeg/src/bin/jpwl/CMakeLists.txt new file mode 100644 index 000000000..5df225def --- /dev/null +++ b/openjpeg/src/bin/jpwl/CMakeLists.txt @@ -0,0 +1,62 @@ +# jpwl apps + +# First thing define the common source: +set(common_SRCS + convert.c + index.c + ${OPENJPEG_SOURCE_DIR}/src/bin/common/color.c + ${OPENJPEG_SOURCE_DIR}/src/bin/common/opj_getopt.c + ) + +# Headers file are located here: +include_directories( + ${OPENJPEG_BINARY_DIR}/src/lib/openjp2 # opj_config.h + ${OPENJPEG_BINARY_DIR}/src/bin/common # opj_apps_config.h + ${OPENJPEG_SOURCE_DIR}/src/lib/openmj2 + ${OPENJPEG_SOURCE_DIR}/src/bin/common + ${LCMS_INCLUDE_DIRNAME} + ${Z_INCLUDE_DIRNAME} + ${PNG_INCLUDE_DIRNAME} + ${TIFF_INCLUDE_DIRNAME} + ) + +if(WIN32) + if(BUILD_SHARED_LIBS) + add_definitions(-DOPJ_EXPORTS) + else() + add_definitions(-DOPJ_STATIC) + endif() +endif() + +add_definitions(-DOPJ_USE_LEGACY) +foreach(exe decompress compress) + set(jpwl_exe opj_jpwl_${exe}) + set(jp2_exe opj_${exe}) + add_executable(${jpwl_exe} + #../jp2/${jp2_exe}.c + ${jpwl_exe}.c + ${common_SRCS} + ) + set_property( + TARGET ${jpwl_exe} + APPEND PROPERTY COMPILE_DEFINITIONS USE_JPWL + ) + + target_link_libraries(${jpwl_exe} openjpwl + ${LCMS_LIBNAME} ${PNG_LIBNAME} ${TIFF_LIBNAME}) + + # To support universal exe: + if(ZLIB_FOUND AND APPLE) + target_link_libraries(${jpwl_exe} z) + else(ZLIB_FOUND AND APPLE) + target_link_libraries(${jpwl_exe} ${Z_LIBNAME}) + endif() + + if(UNIX) + target_link_libraries(${jpwl_exe} m) + endif() + + install(TARGETS ${jpwl_exe} + DESTINATION ${OPENJPEG_INSTALL_BIN_DIR} COMPONENT Applications + ) +endforeach() diff --git a/openjpeg/src/bin/jpwl/convert.c b/openjpeg/src/bin/jpwl/convert.c new file mode 100644 index 000000000..d0ec4bd05 --- /dev/null +++ b/openjpeg/src/bin/jpwl/convert.c @@ -0,0 +1,3748 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * Copyright (c) 2003-2014, Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "opj_apps_config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#ifdef OPJ_HAVE_LIBTIFF +#include <tiffio.h> +#endif /* OPJ_HAVE_LIBTIFF */ + +#ifdef OPJ_HAVE_LIBPNG +#include <zlib.h> +#include <png.h> +#endif /* OPJ_HAVE_LIBPNG */ + +#include "openjpeg.h" +#include "convert.h" + +/* + * Get logarithm of an integer and round downwards. + * + * log2(a) + */ +static int int_floorlog2(int a) +{ + int l; + for (l = 0; a > 1; l++) { + a >>= 1; + } + return l; +} + +/* -->> -->> -->> -->> + + TGA IMAGE FORMAT + + <<-- <<-- <<-- <<-- */ + +#ifdef INFORMATION_ONLY +/* TGA header definition. */ +struct tga_header { + unsigned char id_length; /* Image id field length */ + unsigned char colour_map_type; /* Colour map type */ + unsigned char image_type; /* Image type */ + /* + ** Colour map specification + */ + unsigned short colour_map_index; /* First entry index */ + unsigned short colour_map_length; /* Colour map length */ + unsigned char colour_map_entry_size; /* Colour map entry size */ + /* + ** Image specification + */ + unsigned short x_origin; /* x origin of image */ + unsigned short y_origin; /* u origin of image */ + unsigned short image_width; /* Image width */ + unsigned short image_height; /* Image height */ + unsigned char pixel_depth; /* Pixel depth */ + unsigned char image_desc; /* Image descriptor */ +}; +#endif /* INFORMATION_ONLY */ + +static unsigned short get_ushort(unsigned short val) +{ + +#ifdef OPJ_BIG_ENDIAN + return (((val & 0xff) << 8) + (val >> 8)); +#else + return (val); +#endif + +} + +#define TGA_HEADER_SIZE 18 + +static int tga_readheader(FILE *fp, unsigned int *bits_per_pixel, + unsigned int *width, unsigned int *height, int *flip_image) +{ + int palette_size; + unsigned char *tga ; + unsigned char id_len, cmap_type, image_type; + unsigned char pixel_depth, image_desc; + unsigned short cmap_index, cmap_len, cmap_entry_size; + unsigned short x_origin, y_origin, image_w, image_h; + + if (!bits_per_pixel || !width || !height || !flip_image) { + return 0; + } + tga = (unsigned char*)malloc(18); + + if (fread(tga, TGA_HEADER_SIZE, 1, fp) != 1) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + free(tga); + return 0 ; + } + id_len = (unsigned char)tga[0]; + cmap_type = (unsigned char)tga[1]; + image_type = (unsigned char)tga[2]; + cmap_index = get_ushort(*(unsigned short*)(&tga[3])); + cmap_len = get_ushort(*(unsigned short*)(&tga[5])); + cmap_entry_size = (unsigned char)tga[7]; + + + x_origin = get_ushort(*(unsigned short*)(&tga[8])); + y_origin = get_ushort(*(unsigned short*)(&tga[10])); + image_w = get_ushort(*(unsigned short*)(&tga[12])); + image_h = get_ushort(*(unsigned short*)(&tga[14])); + pixel_depth = (unsigned char)tga[16]; + image_desc = (unsigned char)tga[17]; + + free(tga); + + *bits_per_pixel = (unsigned int)pixel_depth; + *width = (unsigned int)image_w; + *height = (unsigned int)image_h; + + /* Ignore tga identifier, if present ... */ + if (id_len) { + unsigned char *id = (unsigned char *) malloc(id_len); + if (!fread(id, id_len, 1, fp)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + free(id); + return 0 ; + } + free(id); + } + + /* Test for compressed formats ... not yet supported ... + // Note :- 9 - RLE encoded palettized. + // 10 - RLE encoded RGB. */ + if (image_type > 8) { + fprintf(stderr, "Sorry, compressed tga files are not currently supported.\n"); + return 0 ; + } + + *flip_image = !(image_desc & 32); + + /* Palettized formats are not yet supported, skip over the palette, if present ... */ + palette_size = cmap_len * (cmap_entry_size / 8); + + if (palette_size > 0) { + fprintf(stderr, "File contains a palette - not yet supported."); + fseek(fp, palette_size, SEEK_CUR); + } + return 1; +} + +#ifdef OPJ_BIG_ENDIAN + +static inline uint16_t swap16(uint16_t x) +{ + return (((x & 0x00ffU) << 8) | ((x & 0xff00U) >> 8)); +} + +#endif + +static int tga_writeheader(FILE *fp, int bits_per_pixel, int width, int height, + opj_bool flip_image) +{ + unsigned short image_w, image_h, us0; + unsigned char uc0, image_type; + unsigned char pixel_depth, image_desc; + + if (!bits_per_pixel || !width || !height) { + return 0; + } + + pixel_depth = 0; + + if (bits_per_pixel < 256) { + pixel_depth = (unsigned char)bits_per_pixel; + } else { + fprintf(stderr, "ERROR: Wrong bits per pixel inside tga_header"); + return 0; + } + uc0 = 0; + + if (fwrite(&uc0, 1, 1, fp) != 1) { + goto fails; /* id_length */ + } + if (fwrite(&uc0, 1, 1, fp) != 1) { + goto fails; /* colour_map_type */ + } + + image_type = 2; /* Uncompressed. */ + if (fwrite(&image_type, 1, 1, fp) != 1) { + goto fails; + } + + us0 = 0; + if (fwrite(&us0, 2, 1, fp) != 1) { + goto fails; /* colour_map_index */ + } + if (fwrite(&us0, 2, 1, fp) != 1) { + goto fails; /* colour_map_length */ + } + if (fwrite(&uc0, 1, 1, fp) != 1) { + goto fails; /* colour_map_entry_size */ + } + + if (fwrite(&us0, 2, 1, fp) != 1) { + goto fails; /* x_origin */ + } + if (fwrite(&us0, 2, 1, fp) != 1) { + goto fails; /* y_origin */ + } + + image_w = (unsigned short)width; + image_h = (unsigned short) height; + +#ifndef OPJ_BIG_ENDIAN + if (fwrite(&image_w, 2, 1, fp) != 1) { + goto fails; + } + if (fwrite(&image_h, 2, 1, fp) != 1) { + goto fails; + } +#else + image_w = swap16(image_w); + image_h = swap16(image_h); + if (fwrite(&image_w, 2, 1, fp) != 1) { + goto fails; + } + if (fwrite(&image_h, 2, 1, fp) != 1) { + goto fails; + } +#endif + + if (fwrite(&pixel_depth, 1, 1, fp) != 1) { + goto fails; + } + + image_desc = 8; /* 8 bits per component. */ + + if (flip_image) { + image_desc |= 32; + } + if (fwrite(&image_desc, 1, 1, fp) != 1) { + goto fails; + } + + return 1; + +fails: + fputs("\nwrite_tgaheader: write ERROR\n", stderr); + return 0; +} + +opj_image_t* tgatoimage(const char *filename, opj_cparameters_t *parameters) +{ + FILE *f; + opj_image_t *image; + unsigned int image_width, image_height, pixel_bit_depth; + unsigned int x, y; + int flip_image = 0; + opj_image_cmptparm_t cmptparm[4]; /* maximum 4 components */ + int numcomps; + OPJ_COLOR_SPACE color_space; + opj_bool mono ; + opj_bool save_alpha; + int subsampling_dx, subsampling_dy; + int i; + + f = fopen(filename, "rb"); + if (!f) { + fprintf(stderr, "Failed to open %s for reading !!\n", filename); + return 0; + } + + if (!tga_readheader(f, &pixel_bit_depth, &image_width, &image_height, + &flip_image)) { + return NULL; + } + + /* We currently only support 24 & 32 bit tga's ... */ + if (!((pixel_bit_depth == 24) || (pixel_bit_depth == 32))) { + return NULL; + } + + /* initialize image components */ + memset(&cmptparm[0], 0, 4 * sizeof(opj_image_cmptparm_t)); + + mono = (pixel_bit_depth == 8) || + (pixel_bit_depth == 16); /* Mono with & without alpha. */ + save_alpha = (pixel_bit_depth == 16) || + (pixel_bit_depth == 32); /* Mono with alpha, or RGB with alpha */ + + if (mono) { + color_space = CLRSPC_GRAY; + numcomps = save_alpha ? 2 : 1; + } else { + numcomps = save_alpha ? 4 : 3; + color_space = CLRSPC_SRGB; + } + + subsampling_dx = parameters->subsampling_dx; + subsampling_dy = parameters->subsampling_dy; + + for (i = 0; i < numcomps; i++) { + cmptparm[i].prec = 8; + cmptparm[i].bpp = 8; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = subsampling_dx; + cmptparm[i].dy = subsampling_dy; + cmptparm[i].w = image_width; + cmptparm[i].h = image_height; + } + + /* create the image */ + image = opj_image_create(numcomps, &cmptparm[0], color_space); + + if (!image) { + return NULL; + } + + /* set image offset and reference grid */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = !image->x0 ? (image_width - 1) * subsampling_dx + 1 : image->x0 + + (image_width - 1) * subsampling_dx + 1; + image->y1 = !image->y0 ? (image_height - 1) * subsampling_dy + 1 : image->y0 + + (image_height - 1) * subsampling_dy + 1; + + /* set image data */ + for (y = 0; y < image_height; y++) { + int index; + + if (flip_image) { + index = (image_height - y - 1) * image_width; + } else { + index = y * image_width; + } + + if (numcomps == 3) { + for (x = 0; x < image_width; x++) { + unsigned char r, g, b; + + if (!fread(&b, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + opj_image_destroy(image); + return NULL; + } + if (!fread(&g, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + opj_image_destroy(image); + return NULL; + } + if (!fread(&r, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + opj_image_destroy(image); + return NULL; + } + + image->comps[0].data[index] = r; + image->comps[1].data[index] = g; + image->comps[2].data[index] = b; + index++; + } + } else if (numcomps == 4) { + for (x = 0; x < image_width; x++) { + unsigned char r, g, b, a; + if (!fread(&b, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + opj_image_destroy(image); + return NULL; + } + if (!fread(&g, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + opj_image_destroy(image); + return NULL; + } + if (!fread(&r, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + opj_image_destroy(image); + return NULL; + } + if (!fread(&a, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + opj_image_destroy(image); + return NULL; + } + + image->comps[0].data[index] = r; + image->comps[1].data[index] = g; + image->comps[2].data[index] = b; + image->comps[3].data[index] = a; + index++; + } + } else { + fprintf(stderr, "Currently unsupported bit depth : %s\n", filename); + } + } + return image; +} + +int imagetotga(opj_image_t * image, const char *outfile) +{ + int width, height, bpp, x, y; + opj_bool write_alpha; + int i, adjustR, adjustG, adjustB; + unsigned int alpha_channel; + float r, g, b, a; + unsigned char value; + float scale; + FILE *fdest; + size_t res; + + fdest = fopen(outfile, "wb"); + if (!fdest) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", outfile); + return 1; + } + + for (i = 0; i < image->numcomps - 1; i++) { + if ((image->comps[0].dx != image->comps[i + 1].dx) + || (image->comps[0].dy != image->comps[i + 1].dy) + || (image->comps[0].prec != image->comps[i + 1].prec)) { + fprintf(stderr, + "Unable to create a tga file with such J2K image charateristics."); + return 1; + } + } + + width = image->comps[0].w; + height = image->comps[0].h; + + /* Mono with alpha, or RGB with alpha. */ + write_alpha = (image->numcomps == 2) || (image->numcomps == 4); + + /* Write TGA header */ + bpp = write_alpha ? 32 : 24; + if (!tga_writeheader(fdest, bpp, width, height, OPJ_TRUE)) { + return 1; + } + + alpha_channel = image->numcomps - 1; + + scale = 255.0f / (float)((1 << image->comps[0].prec) - 1); + + adjustR = (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + adjustG = (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); + adjustB = (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); + + for (y = 0; y < height; y++) { + unsigned int index = y * width; + + for (x = 0; x < width; x++, index++) { + r = (float)(image->comps[0].data[index] + adjustR); + + if (image->numcomps > 2) { + g = (float)(image->comps[1].data[index] + adjustG); + b = (float)(image->comps[2].data[index] + adjustB); + } else { /* Greyscale ... */ + g = r; + b = r; + } + + /* TGA format writes BGR ... */ + value = (unsigned char)(b * scale); + res = fwrite(&value, 1, 1, fdest); + if (res < 1) { + fprintf(stderr, "failed to write 1 byte for %s\n", outfile); + return 1; + } + + value = (unsigned char)(g * scale); + res = fwrite(&value, 1, 1, fdest); + if (res < 1) { + fprintf(stderr, "failed to write 1 byte for %s\n", outfile); + return 1; + } + + value = (unsigned char)(r * scale); + res = fwrite(&value, 1, 1, fdest); + if (res < 1) { + fprintf(stderr, "failed to write 1 byte for %s\n", outfile); + return 1; + } + + if (write_alpha) { + a = (float)(image->comps[alpha_channel].data[index]); + value = (unsigned char)(a * scale); + res = fwrite(&value, 1, 1, fdest); + if (res < 1) { + fprintf(stderr, "failed to write 1 byte for %s\n", outfile); + return 1; + } + } + } + } + + return 0; +} + +/* -->> -->> -->> -->> + + BMP IMAGE FORMAT + + <<-- <<-- <<-- <<-- */ + +/* WORD defines a two byte word */ +typedef unsigned short int WORD; + +/* DWORD defines a four byte word */ +typedef unsigned int DWORD; + +typedef struct { + WORD bfType; /* 'BM' for Bitmap (19776) */ + DWORD bfSize; /* Size of the file */ + WORD bfReserved1; /* Reserved : 0 */ + WORD bfReserved2; /* Reserved : 0 */ + DWORD bfOffBits; /* Offset */ +} BITMAPFILEHEADER_t; + +typedef struct { + DWORD biSize; /* Size of the structure in bytes */ + DWORD biWidth; /* Width of the image in pixels */ + DWORD biHeight; /* Height of the image in pixels */ + WORD biPlanes; /* 1 */ + WORD biBitCount; /* Number of color bits by pixels */ + DWORD biCompression; /* Type of encoding 0: none 1: RLE8 2: RLE4 */ + DWORD biSizeImage; /* Size of the image in bytes */ + DWORD biXpelsPerMeter; /* Horizontal (X) resolution in pixels/meter */ + DWORD biYpelsPerMeter; /* Vertical (Y) resolution in pixels/meter */ + DWORD biClrUsed; /* Number of color used in the image (0: ALL) */ + DWORD biClrImportant; /* Number of important color (0: ALL) */ +} BITMAPINFOHEADER_t; + +opj_image_t* bmptoimage(const char *filename, opj_cparameters_t *parameters) +{ + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + + int i, numcomps, w, h; + OPJ_COLOR_SPACE color_space; + opj_image_cmptparm_t cmptparm[3]; /* maximum of 3 components */ + opj_image_t * image = NULL; + + FILE *IN; + BITMAPFILEHEADER_t File_h; + BITMAPINFOHEADER_t Info_h; + unsigned char *RGB; + unsigned char *table_R, *table_G, *table_B; + unsigned int j, PAD = 0; + + int x, y, index; + int gray_scale = 1; + int has_color; + DWORD W, H; + + IN = fopen(filename, "rb"); + if (!IN) { + fprintf(stderr, "Failed to open %s for reading !!\n", filename); + return NULL; + } + + File_h.bfType = getc(IN); + File_h.bfType = (getc(IN) << 8) + File_h.bfType; + + if (File_h.bfType != 19778) { + fprintf(stderr, "Error, not a BMP file!\n"); + fclose(IN); + return NULL; + } + /* FILE HEADER */ + /* ------------- */ + File_h.bfSize = getc(IN); + File_h.bfSize = (getc(IN) << 8) + File_h.bfSize; + File_h.bfSize = (getc(IN) << 16) + File_h.bfSize; + File_h.bfSize = (getc(IN) << 24) + File_h.bfSize; + + File_h.bfReserved1 = getc(IN); + File_h.bfReserved1 = (getc(IN) << 8) + File_h.bfReserved1; + + File_h.bfReserved2 = getc(IN); + File_h.bfReserved2 = (getc(IN) << 8) + File_h.bfReserved2; + + File_h.bfOffBits = getc(IN); + File_h.bfOffBits = (getc(IN) << 8) + File_h.bfOffBits; + File_h.bfOffBits = (getc(IN) << 16) + File_h.bfOffBits; + File_h.bfOffBits = (getc(IN) << 24) + File_h.bfOffBits; + + /* INFO HEADER */ + /* ------------- */ + + Info_h.biSize = getc(IN); + Info_h.biSize = (getc(IN) << 8) + Info_h.biSize; + Info_h.biSize = (getc(IN) << 16) + Info_h.biSize; + Info_h.biSize = (getc(IN) << 24) + Info_h.biSize; + + if (Info_h.biSize != 40) { + fprintf(stderr, "Error, unknown BMP header size %d\n", Info_h.biSize); + fclose(IN); + return NULL; + } + Info_h.biWidth = getc(IN); + Info_h.biWidth = (getc(IN) << 8) + Info_h.biWidth; + Info_h.biWidth = (getc(IN) << 16) + Info_h.biWidth; + Info_h.biWidth = (getc(IN) << 24) + Info_h.biWidth; + w = Info_h.biWidth; + + Info_h.biHeight = getc(IN); + Info_h.biHeight = (getc(IN) << 8) + Info_h.biHeight; + Info_h.biHeight = (getc(IN) << 16) + Info_h.biHeight; + Info_h.biHeight = (getc(IN) << 24) + Info_h.biHeight; + h = Info_h.biHeight; + + Info_h.biPlanes = getc(IN); + Info_h.biPlanes = (getc(IN) << 8) + Info_h.biPlanes; + + Info_h.biBitCount = getc(IN); + Info_h.biBitCount = (getc(IN) << 8) + Info_h.biBitCount; + + Info_h.biCompression = getc(IN); + Info_h.biCompression = (getc(IN) << 8) + Info_h.biCompression; + Info_h.biCompression = (getc(IN) << 16) + Info_h.biCompression; + Info_h.biCompression = (getc(IN) << 24) + Info_h.biCompression; + + Info_h.biSizeImage = getc(IN); + Info_h.biSizeImage = (getc(IN) << 8) + Info_h.biSizeImage; + Info_h.biSizeImage = (getc(IN) << 16) + Info_h.biSizeImage; + Info_h.biSizeImage = (getc(IN) << 24) + Info_h.biSizeImage; + + Info_h.biXpelsPerMeter = getc(IN); + Info_h.biXpelsPerMeter = (getc(IN) << 8) + Info_h.biXpelsPerMeter; + Info_h.biXpelsPerMeter = (getc(IN) << 16) + Info_h.biXpelsPerMeter; + Info_h.biXpelsPerMeter = (getc(IN) << 24) + Info_h.biXpelsPerMeter; + + Info_h.biYpelsPerMeter = getc(IN); + Info_h.biYpelsPerMeter = (getc(IN) << 8) + Info_h.biYpelsPerMeter; + Info_h.biYpelsPerMeter = (getc(IN) << 16) + Info_h.biYpelsPerMeter; + Info_h.biYpelsPerMeter = (getc(IN) << 24) + Info_h.biYpelsPerMeter; + + Info_h.biClrUsed = getc(IN); + Info_h.biClrUsed = (getc(IN) << 8) + Info_h.biClrUsed; + Info_h.biClrUsed = (getc(IN) << 16) + Info_h.biClrUsed; + Info_h.biClrUsed = (getc(IN) << 24) + Info_h.biClrUsed; + + Info_h.biClrImportant = getc(IN); + Info_h.biClrImportant = (getc(IN) << 8) + Info_h.biClrImportant; + Info_h.biClrImportant = (getc(IN) << 16) + Info_h.biClrImportant; + Info_h.biClrImportant = (getc(IN) << 24) + Info_h.biClrImportant; + + /* Read the data and store them in the OUT file */ + + if (Info_h.biBitCount == 24) { + numcomps = 3; + color_space = CLRSPC_SRGB; + /* initialize image components */ + memset(&cmptparm[0], 0, 3 * sizeof(opj_image_cmptparm_t)); + for (i = 0; i < numcomps; i++) { + cmptparm[i].prec = 8; + cmptparm[i].bpp = 8; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = subsampling_dx; + cmptparm[i].dy = subsampling_dy; + cmptparm[i].w = w; + cmptparm[i].h = h; + } + /* create the image */ + image = opj_image_create(numcomps, &cmptparm[0], color_space); + if (!image) { + fclose(IN); + return NULL; + } + + /* set image offset and reference grid */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = !image->x0 ? (w - 1) * subsampling_dx + 1 : image->x0 + + (w - 1) * subsampling_dx + 1; + image->y1 = !image->y0 ? (h - 1) * subsampling_dy + 1 : image->y0 + + (h - 1) * subsampling_dy + 1; + + /* set image data */ + + /* Place the cursor at the beginning of the image information */ + fseek(IN, 0, SEEK_SET); + fseek(IN, File_h.bfOffBits, SEEK_SET); + + W = Info_h.biWidth; + H = Info_h.biHeight; + + /* PAD = 4 - (3 * W) % 4; */ + /* PAD = (PAD == 4) ? 0 : PAD; */ + PAD = (3 * W) % 4 ? 4 - (3 * W) % 4 : 0; + + RGB = (unsigned char *) + malloc((3 * W + PAD) * H * sizeof(unsigned char)); + + if (fread(RGB, sizeof(unsigned char), (3 * W + PAD) * H, + IN) != (3 * W + PAD) * H) { + free(RGB); + opj_image_destroy(image); + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + return NULL; + } + + index = 0; + + for (y = 0; y < (int)H; y++) { + unsigned char *scanline = RGB + (3 * W + PAD) * (H - 1 - y); + for (x = 0; x < (int)W; x++) { + unsigned char *pixel = &scanline[3 * x]; + image->comps[0].data[index] = pixel[2]; /* R */ + image->comps[1].data[index] = pixel[1]; /* G */ + image->comps[2].data[index] = pixel[0]; /* B */ + index++; + } + } + free(RGB); + }/* if (Info_h.biBitCount == 24) */ + else if (Info_h.biBitCount == 8 && Info_h.biCompression == 0) { /*RGB */ + if (Info_h.biClrUsed == 0) { + Info_h.biClrUsed = 256; + } else if (Info_h.biClrUsed > 256) { + Info_h.biClrUsed = 256; + } + + table_R = (unsigned char *) malloc(256 * sizeof(unsigned char)); + table_G = (unsigned char *) malloc(256 * sizeof(unsigned char)); + table_B = (unsigned char *) malloc(256 * sizeof(unsigned char)); + + has_color = 0; + for (j = 0; j < Info_h.biClrUsed; j++) { + table_B[j] = (unsigned char)getc(IN); + table_G[j] = (unsigned char)getc(IN); + table_R[j] = (unsigned char)getc(IN); + getc(IN); + has_color += + !(table_R[j] == table_G[j] && table_R[j] == table_B[j]); + } + if (has_color) { + gray_scale = 0; + } + + /* Place the cursor at the beginning of the image information */ + fseek(IN, 0, SEEK_SET); + fseek(IN, File_h.bfOffBits, SEEK_SET); + + W = Info_h.biWidth; + H = Info_h.biHeight; + if (Info_h.biWidth % 2) { + W++; + } + + numcomps = gray_scale ? 1 : 3; + color_space = gray_scale ? CLRSPC_GRAY : CLRSPC_SRGB; + /* initialize image components */ + memset(&cmptparm[0], 0, 3 * sizeof(opj_image_cmptparm_t)); + for (i = 0; i < numcomps; i++) { + cmptparm[i].prec = 8; + cmptparm[i].bpp = 8; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = subsampling_dx; + cmptparm[i].dy = subsampling_dy; + cmptparm[i].w = w; + cmptparm[i].h = h; + } + /* create the image */ + image = opj_image_create(numcomps, &cmptparm[0], color_space); + if (!image) { + fclose(IN); + free(table_R); + free(table_G); + free(table_B); + return NULL; + } + + /* set image offset and reference grid */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = !image->x0 ? (w - 1) * subsampling_dx + 1 : image->x0 + + (w - 1) * subsampling_dx + 1; + image->y1 = !image->y0 ? (h - 1) * subsampling_dy + 1 : image->y0 + + (h - 1) * subsampling_dy + 1; + + /* set image data */ + + RGB = (unsigned char *) malloc(W * H * sizeof(unsigned char)); + + if (fread(RGB, sizeof(unsigned char), W * H, IN) != W * H) { + free(table_R); + free(table_G); + free(table_B); + free(RGB); + opj_image_destroy(image); + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + return NULL; + } + if (gray_scale) { + index = 0; + for (j = 0; j < W * H; j++) { + if ((j % W < W - 1 && Info_h.biWidth % 2) || !(Info_h.biWidth % 2)) { + image->comps[0].data[index] = + table_R[RGB[W * H - ((j) / (W) + 1) * W + (j) % (W)]]; + index++; + } + } + + } else { + index = 0; + for (j = 0; j < W * H; j++) { + if ((j % W < W - 1 && Info_h.biWidth % 2) + || !(Info_h.biWidth % 2)) { + unsigned char pixel_index = + RGB[W * H - ((j) / (W) + 1) * W + (j) % (W)]; + image->comps[0].data[index] = table_R[pixel_index]; + image->comps[1].data[index] = table_G[pixel_index]; + image->comps[2].data[index] = table_B[pixel_index]; + index++; + } + } + } + free(RGB); + free(table_R); + free(table_G); + free(table_B); + }/* RGB8 */ + else if (Info_h.biBitCount == 8 && Info_h.biCompression == 1) { /*RLE8*/ + unsigned char *pix, *beyond; + int *gray, *red, *green, *blue; + unsigned int x, y, max; + int i, c, c1; + unsigned char uc; + + if (Info_h.biClrUsed == 0) { + Info_h.biClrUsed = 256; + } else if (Info_h.biClrUsed > 256) { + Info_h.biClrUsed = 256; + } + + table_R = (unsigned char *) malloc(256 * sizeof(unsigned char)); + table_G = (unsigned char *) malloc(256 * sizeof(unsigned char)); + table_B = (unsigned char *) malloc(256 * sizeof(unsigned char)); + + has_color = 0; + for (j = 0; j < Info_h.biClrUsed; j++) { + table_B[j] = (unsigned char)getc(IN); + table_G[j] = (unsigned char)getc(IN); + table_R[j] = (unsigned char)getc(IN); + getc(IN); + has_color += !(table_R[j] == table_G[j] && table_R[j] == table_B[j]); + } + + if (has_color) { + gray_scale = 0; + } + + numcomps = gray_scale ? 1 : 3; + color_space = gray_scale ? CLRSPC_GRAY : CLRSPC_SRGB; + /* initialize image components */ + memset(&cmptparm[0], 0, 3 * sizeof(opj_image_cmptparm_t)); + for (i = 0; i < numcomps; i++) { + cmptparm[i].prec = 8; + cmptparm[i].bpp = 8; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = subsampling_dx; + cmptparm[i].dy = subsampling_dy; + cmptparm[i].w = w; + cmptparm[i].h = h; + } + /* create the image */ + image = opj_image_create(numcomps, &cmptparm[0], color_space); + if (!image) { + fclose(IN); + free(table_R); + free(table_G); + free(table_B); + return NULL; + } + + /* set image offset and reference grid */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = !image->x0 ? (w - 1) * subsampling_dx + 1 : image->x0 + (w + - 1) * subsampling_dx + 1; + image->y1 = !image->y0 ? (h - 1) * subsampling_dy + 1 : image->y0 + (h + - 1) * subsampling_dy + 1; + + /* set image data */ + + /* Place the cursor at the beginning of the image information */ + fseek(IN, 0, SEEK_SET); + fseek(IN, File_h.bfOffBits, SEEK_SET); + + W = Info_h.biWidth; + H = Info_h.biHeight; + RGB = (unsigned char *) calloc(1, W * H * sizeof(unsigned char)); + beyond = RGB + W * H; + pix = beyond - W; + x = y = 0; + + while (y < H) { + c = getc(IN); + + if (c) { + c1 = getc(IN); + + for (i = 0; i < c && x < W && pix < beyond; i++, x++, pix++) { + *pix = (unsigned char)c1; + } + } else { + c = getc(IN); + + if (c == 0x00) { /* EOL */ + x = 0; + ++y; + pix = RGB + x + (H - y - 1) * W; + } else if (c == 0x01) { /* EOP */ + break; + } else if (c == 0x02) { /* MOVE by dxdy */ + c = getc(IN); + x += c; + c = getc(IN); + y += c; + pix = RGB + (H - y - 1) * W + x; + } else { /* 03 .. 255 */ + i = 0; + for (; i < c && x < W && pix < beyond; i++, x++, pix++) { + c1 = getc(IN); + *pix = (unsigned char)c1; + } + if (c & 1) { /* skip padding byte */ + getc(IN); + } + } + } + }/* while() */ + + if (gray_scale) { + gray = image->comps[0].data; + pix = RGB; + max = W * H; + + while (max--) { + uc = *pix++; + + *gray++ = table_R[uc]; + } + } else { + /*int *red, *green, *blue;*/ + + red = image->comps[0].data; + green = image->comps[1].data; + blue = image->comps[2].data; + pix = RGB; + max = W * H; + + while (max--) { + uc = *pix++; + + *red++ = table_R[uc]; + *green++ = table_G[uc]; + *blue++ = table_B[uc]; + } + } + free(RGB); + free(table_R); + free(table_G); + free(table_B); + }/* RLE8 */ + else { + fprintf(stderr, + "Other system than 24 bits/pixels or 8 bits (no RLE coding) " + "is not yet implemented [%d]\n", Info_h.biBitCount); + } + fclose(IN); + return image; +} + +int imagetobmp(opj_image_t * image, const char *outfile) +{ + int w, h; + int i, pad; + FILE *fdest = NULL; + int adjustR, adjustG, adjustB; + + if (image->comps[0].prec < 8) { + fprintf(stderr, "Unsupported precision: %d\n", image->comps[0].prec); + return 1; + } + if (image->numcomps >= 3 && image->comps[0].dx == image->comps[1].dx + && image->comps[1].dx == image->comps[2].dx + && image->comps[0].dy == image->comps[1].dy + && image->comps[1].dy == image->comps[2].dy + && image->comps[0].prec == image->comps[1].prec + && image->comps[1].prec == image->comps[2].prec) { + + /* -->> -->> -->> -->> + 24 bits color + <<-- <<-- <<-- <<-- */ + + fdest = fopen(outfile, "wb"); + if (!fdest) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", outfile); + return 1; + } + + w = image->comps[0].w; + h = image->comps[0].h; + + fprintf(fdest, "BM"); + + /* FILE HEADER */ + /* ------------- */ + fprintf(fdest, "%c%c%c%c", + (unsigned char)(h * w * 3 + 3 * h * (w % 2) + 54) & 0xff, + (unsigned char)((h * w * 3 + 3 * h * (w % 2) + 54) >> 8) & 0xff, + (unsigned char)((h * w * 3 + 3 * h * (w % 2) + 54) >> 16) & 0xff, + (unsigned char)((h * w * 3 + 3 * h * (w % 2) + 54) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, + ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (54) & 0xff, ((54) >> 8) & 0xff, ((54) >> 16) & 0xff, + ((54) >> 24) & 0xff); + + /* INFO HEADER */ + /* ------------- */ + fprintf(fdest, "%c%c%c%c", (40) & 0xff, ((40) >> 8) & 0xff, ((40) >> 16) & 0xff, + ((40) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (unsigned char)((w) & 0xff), + (unsigned char)((w) >> 8) & 0xff, + (unsigned char)((w) >> 16) & 0xff, + (unsigned char)((w) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (unsigned char)((h) & 0xff), + (unsigned char)((h) >> 8) & 0xff, + (unsigned char)((h) >> 16) & 0xff, + (unsigned char)((h) >> 24) & 0xff); + fprintf(fdest, "%c%c", (1) & 0xff, ((1) >> 8) & 0xff); + fprintf(fdest, "%c%c", (24) & 0xff, ((24) >> 8) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, + ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (unsigned char)(3 * h * w + 3 * h * (w % 2)) & 0xff, + (unsigned char)((h * w * 3 + 3 * h * (w % 2)) >> 8) & 0xff, + (unsigned char)((h * w * 3 + 3 * h * (w % 2)) >> 16) & 0xff, + (unsigned char)((h * w * 3 + 3 * h * (w % 2)) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, + ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, + ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, + ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, + ((0) >> 24) & 0xff); + + if (image->comps[0].prec > 8) { + adjustR = image->comps[0].prec - 8; + printf("BMP CONVERSION: Truncating component 0 from %d bits to 8 bits\n", + image->comps[0].prec); + } else { + adjustR = 0; + } + if (image->comps[1].prec > 8) { + adjustG = image->comps[1].prec - 8; + printf("BMP CONVERSION: Truncating component 1 from %d bits to 8 bits\n", + image->comps[1].prec); + } else { + adjustG = 0; + } + if (image->comps[2].prec > 8) { + adjustB = image->comps[2].prec - 8; + printf("BMP CONVERSION: Truncating component 2 from %d bits to 8 bits\n", + image->comps[2].prec); + } else { + adjustB = 0; + } + + for (i = 0; i < w * h; i++) { + unsigned char rc, gc, bc; + int r, g, b; + + r = image->comps[0].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + r = ((r >> adjustR) + ((r >> (adjustR - 1)) % 2)); + if (r > 255) { + r = 255; + } else if (r < 0) { + r = 0; + } + rc = (unsigned char)r; + + g = image->comps[1].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); + g = ((g >> adjustG) + ((g >> (adjustG - 1)) % 2)); + if (g > 255) { + g = 255; + } else if (g < 0) { + g = 0; + } + gc = (unsigned char)g; + + b = image->comps[2].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); + b = ((b >> adjustB) + ((b >> (adjustB - 1)) % 2)); + if (b > 255) { + b = 255; + } else if (b < 0) { + b = 0; + } + bc = (unsigned char)b; + + fprintf(fdest, "%c%c%c", bc, gc, rc); + + if ((i + 1) % w == 0) { + for (pad = (3 * w) % 4 ? 4 - (3 * w) % 4 : 0; pad > 0; pad--) { /* ADD */ + fprintf(fdest, "%c", 0); + } + } + } + fclose(fdest); + } else { /* Gray-scale */ + + /* -->> -->> -->> -->> + 8 bits non code (Gray scale) + <<-- <<-- <<-- <<-- */ + + fdest = fopen(outfile, "wb"); + w = image->comps[0].w; + h = image->comps[0].h; + + fprintf(fdest, "BM"); + + /* FILE HEADER */ + /* ------------- */ + fprintf(fdest, "%c%c%c%c", + (unsigned char)(h * w + 54 + 1024 + h * (w % 2)) & 0xff, + (unsigned char)((h * w + 54 + 1024 + h * (w % 2)) >> 8) & 0xff, + (unsigned char)((h * w + 54 + 1024 + h * (w % 2)) >> 16) & 0xff, + (unsigned char)((h * w + 54 + 1024 + w * (w % 2)) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, + ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (54 + 1024) & 0xff, ((54 + 1024) >> 8) & 0xff, + ((54 + 1024) >> 16) & 0xff, + ((54 + 1024) >> 24) & 0xff); + + /* INFO HEADER */ + /* ------------- */ + fprintf(fdest, "%c%c%c%c", (40) & 0xff, ((40) >> 8) & 0xff, ((40) >> 16) & 0xff, + ((40) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (unsigned char)((w) & 0xff), + (unsigned char)((w) >> 8) & 0xff, + (unsigned char)((w) >> 16) & 0xff, + (unsigned char)((w) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (unsigned char)((h) & 0xff), + (unsigned char)((h) >> 8) & 0xff, + (unsigned char)((h) >> 16) & 0xff, + (unsigned char)((h) >> 24) & 0xff); + fprintf(fdest, "%c%c", (1) & 0xff, ((1) >> 8) & 0xff); + fprintf(fdest, "%c%c", (8) & 0xff, ((8) >> 8) & 0xff); + fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, + ((0) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (unsigned char)(h * w + h * (w % 2)) & 0xff, + (unsigned char)((h * w + h * (w % 2)) >> 8) & 0xff, + (unsigned char)((h * w + h * (w % 2)) >> 16) & 0xff, + (unsigned char)((h * w + h * (w % 2)) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, + ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, + ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (256) & 0xff, ((256) >> 8) & 0xff, + ((256) >> 16) & 0xff, ((256) >> 24) & 0xff); + fprintf(fdest, "%c%c%c%c", (256) & 0xff, ((256) >> 8) & 0xff, + ((256) >> 16) & 0xff, ((256) >> 24) & 0xff); + + if (image->comps[0].prec > 8) { + adjustR = image->comps[0].prec - 8; + printf("BMP CONVERSION: Truncating component 0 from %d bits to 8 bits\n", + image->comps[0].prec); + } else { + adjustR = 0; + } + + for (i = 0; i < 256; i++) { + fprintf(fdest, "%c%c%c%c", i, i, i, 0); + } + + for (i = 0; i < w * h; i++) { + int r; + + r = image->comps[0].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; + r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + r = ((r >> adjustR) + ((r >> (adjustR - 1)) % 2)); + if (r > 255) { + r = 255; + } else if (r < 0) { + r = 0; + } + + fprintf(fdest, "%c", (unsigned char)r); + + if ((i + 1) % w == 0) { + for (pad = w % 4 ? 4 - w % 4 : 0; pad > 0; pad--) { /* ADD */ + fprintf(fdest, "%c", 0); + } + } + } + fclose(fdest); + } + + return 0; +} + +/* -->> -->> -->> -->> + +PGX IMAGE FORMAT + +<<-- <<-- <<-- <<-- */ + + +static unsigned char readuchar(FILE * f) +{ + unsigned char c1; + if (!fread(&c1, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + return 0; + } + return c1; +} + +static unsigned short readushort(FILE * f, int bigendian) +{ + unsigned char c1, c2; + if (!fread(&c1, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + return 0; + } + if (!fread(&c2, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + return 0; + } + if (bigendian) { + return (c1 << 8) + c2; + } else { + return (c2 << 8) + c1; + } +} + +static unsigned int readuint(FILE * f, int bigendian) +{ + unsigned char c1, c2, c3, c4; + if (!fread(&c1, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + return 0; + } + if (!fread(&c2, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + return 0; + } + if (!fread(&c3, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + return 0; + } + if (!fread(&c4, 1, 1, f)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + return 0; + } + if (bigendian) { + return (c1 << 24) + (c2 << 16) + (c3 << 8) + c4; + } else { + return (c4 << 24) + (c3 << 16) + (c2 << 8) + c1; + } +} + +opj_image_t* pgxtoimage(const char *filename, opj_cparameters_t *parameters) +{ + FILE *f = NULL; + int w, h, prec; + int i, numcomps, max; + OPJ_COLOR_SPACE color_space; + opj_image_cmptparm_t cmptparm; /* maximum of 1 component */ + opj_image_t * image = NULL; + int adjustS, ushift, dshift, force8; + + char endian1, endian2, sign; + char signtmp[32]; + + char temp[32]; + int bigendian; + opj_image_comp_t *comp = NULL; + + numcomps = 1; + color_space = CLRSPC_GRAY; + + memset(&cmptparm, 0, sizeof(opj_image_cmptparm_t)); + + max = 0; + + f = fopen(filename, "rb"); + if (!f) { + fprintf(stderr, "Failed to open %s for reading !\n", filename); + return NULL; + } + + fseek(f, 0, SEEK_SET); + if (fscanf(f, "PG%[ \t]%c%c%[ \t+-]%d%[ \t]%d%[ \t]%d", temp, &endian1, + &endian2, signtmp, &prec, temp, &w, temp, &h) != 9) { + fprintf(stderr, + "ERROR: Failed to read the right number of element from the fscanf() function!\n"); + fclose(f); + return NULL; + } + + i = 0; + sign = '+'; + while (signtmp[i] != '\0') { + if (signtmp[i] == '-') { + sign = '-'; + } + i++; + } + + fgetc(f); + if (endian1 == 'M' && endian2 == 'L') { + bigendian = 1; + } else if (endian2 == 'M' && endian1 == 'L') { + bigendian = 0; + } else { + fprintf(stderr, "Bad pgx header, please check input file\n"); + fclose(f); + return NULL; + } + + /* initialize image component */ + + cmptparm.x0 = parameters->image_offset_x0; + cmptparm.y0 = parameters->image_offset_y0; + cmptparm.w = !cmptparm.x0 ? (w - 1) * parameters->subsampling_dx + 1 : + cmptparm.x0 + (w - 1) * parameters->subsampling_dx + 1; + cmptparm.h = !cmptparm.y0 ? (h - 1) * parameters->subsampling_dy + 1 : + cmptparm.y0 + (h - 1) * parameters->subsampling_dy + 1; + + if (sign == '-') { + cmptparm.sgnd = 1; + } else { + cmptparm.sgnd = 0; + } + if (prec < 8) { + force8 = 1; + ushift = 8 - prec; + dshift = prec - ushift; + if (cmptparm.sgnd) { + adjustS = (1 << (prec - 1)); + } else { + adjustS = 0; + } + cmptparm.sgnd = 0; + prec = 8; + } else { + ushift = dshift = force8 = adjustS = 0; + } + + cmptparm.prec = prec; + cmptparm.bpp = prec; + cmptparm.dx = parameters->subsampling_dx; + cmptparm.dy = parameters->subsampling_dy; + + /* create the image */ + image = opj_image_create(numcomps, &cmptparm, color_space); + if (!image) { + fclose(f); + return NULL; + } + /* set image offset and reference grid */ + image->x0 = cmptparm.x0; + image->y0 = cmptparm.x0; + image->x1 = cmptparm.w; + image->y1 = cmptparm.h; + + /* set image data */ + + comp = &image->comps[0]; + + for (i = 0; i < w * h; i++) { + int v; + if (force8) { + v = readuchar(f) + adjustS; + v = (v << ushift) + (v >> dshift); + comp->data[i] = (unsigned char)v; + + if (v > max) { + max = v; + } + + continue; + } + if (comp->prec == 8) { + if (!comp->sgnd) { + v = readuchar(f); + } else { + v = (char) readuchar(f); + } + } else if (comp->prec <= 16) { + if (!comp->sgnd) { + v = readushort(f, bigendian); + } else { + v = (short) readushort(f, bigendian); + } + } else { + if (!comp->sgnd) { + v = readuint(f, bigendian); + } else { + v = (int) readuint(f, bigendian); + } + } + if (v > max) { + max = v; + } + comp->data[i] = v; + } + fclose(f); + comp->bpp = int_floorlog2(max) + 1; + + return image; +} + +int imagetopgx(opj_image_t * image, const char *outfile) +{ + int w, h; + int i, j, compno; + FILE *fdest = NULL; + + for (compno = 0; compno < image->numcomps; compno++) { + opj_image_comp_t *comp = &image->comps[compno]; + char bname[256]; /* buffer for name */ + char *name = bname; /* pointer */ + int nbytes = 0; + size_t res; + const size_t olen = strlen(outfile); + const size_t dotpos = olen - 4; + const size_t total = dotpos + 1 + 1 + 4; /* '-' + '[1-3]' + '.pgx' */ + if (outfile[dotpos] != '.') { + /* `pgx` was recognized but there is no dot at expected position */ + fprintf(stderr, "ERROR -> Impossible happen."); + return 1; + } + if (total > 256) { + name = (char*)malloc(total + 1); + } + strncpy(name, outfile, dotpos); + /*if (image->numcomps > 1) {*/ + sprintf(name + dotpos, "_%d.pgx", compno); + /*} else { + strcpy(name+dotpos, ".pgx"); + }*/ + fdest = fopen(name, "wb"); + if (!fdest) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", name); + return 1; + } + /* don't need name anymore */ + if (total > 256) { + free(name); + } + + w = image->comps[compno].w; + h = image->comps[compno].h; + + fprintf(fdest, "PG ML %c %d %d %d\n", comp->sgnd ? '-' : '+', comp->prec, w, h); + if (comp->prec <= 8) { + nbytes = 1; + } else if (comp->prec <= 16) { + nbytes = 2; + } else { + nbytes = 4; + } + for (i = 0; i < w * h; i++) { + int v = image->comps[compno].data[i]; + for (j = nbytes - 1; j >= 0; j--) { + char byte = (char)(v >> (j * 8)); + res = fwrite(&byte, 1, 1, fdest); + if (res < 1) { + fprintf(stderr, "failed to write 1 byte for %s\n", name); + fclose(fdest); + return 1; + } + } + } + fclose(fdest); + } + + return 0; +} + +/* -->> -->> -->> -->> + +PNM IMAGE FORMAT + +<<-- <<-- <<-- <<-- */ + +struct pnm_header { + int width, height, maxval, depth, format; + char rgb, rgba, gray, graya, bw; + char ok; +}; + +static char *skip_white(char *s) +{ + while (*s) { + if (*s == '\n' || *s == '\r') { + return NULL; + } + if (isspace(*s)) { + ++s; + continue; + } + return s; + } + return NULL; +} + +static char *skip_int(char *start, int *out_n) +{ + char *s; + char c; + + *out_n = 0; + s = start; + + s = skip_white(start); + if (s == NULL) { + return NULL; + } + start = s; + + while (*s) { + if (!isdigit(*s)) { + break; + } + ++s; + } + c = *s; + *s = 0; + *out_n = atoi(start); + *s = c; + return s; +} + +static char *skip_idf(char *start, char out_idf[256]) +{ + char *s; + char c; + + s = skip_white(start); + if (s == NULL) { + return NULL; + } + start = s; + + while (*s) { + if (isalpha(*s) || *s == '_') { + ++s; + continue; + } + break; + } + c = *s; + *s = 0; + strncpy(out_idf, start, 255); + *s = c; + return s; +} + +static void read_pnm_header(FILE *reader, struct pnm_header *ph) +{ + char *s; + int format, have_wh, end, ttype; + char idf[256], type[256]; + char line[256]; + + if (fgets(line, 250, reader) == NULL) { + fprintf(stderr, "\nWARNING: fgets return a NULL value"); + return; + } + + if (line[0] != 'P') { + fprintf(stderr, "read_pnm_header:PNM:magic P missing\n"); + return; + } + format = atoi(line + 1); + if (format < 1 || format > 7) { + fprintf(stderr, "read_pnm_header:magic format %d invalid\n", format); + return; + } + ph->format = format; + ttype = end = have_wh = 0; + + while (fgets(line, 250, reader)) { + if (*line == '#') { + continue; + } + + s = line; + + if (format == 7) { + s = skip_idf(s, idf); + + if (s == NULL || *s == 0) { + return; + } + + if (strcmp(idf, "ENDHDR") == 0) { + end = 1; + break; + } + if (strcmp(idf, "WIDTH") == 0) { + s = skip_int(s, &ph->width); + if (s == NULL || *s == 0) { + return; + } + + continue; + } + if (strcmp(idf, "HEIGHT") == 0) { + s = skip_int(s, &ph->height); + if (s == NULL || *s == 0) { + return; + } + + continue; + } + if (strcmp(idf, "DEPTH") == 0) { + s = skip_int(s, &ph->depth); + if (s == NULL || *s == 0) { + return; + } + + continue; + } + if (strcmp(idf, "MAXVAL") == 0) { + s = skip_int(s, &ph->maxval); + if (s == NULL || *s == 0) { + return; + } + + continue; + } + if (strcmp(idf, "TUPLTYPE") == 0) { + s = skip_idf(s, type); + if (s == NULL || *s == 0) { + return; + } + + if (strcmp(type, "BLACKANDWHITE") == 0) { + ph->bw = 1; + ttype = 1; + continue; + } + if (strcmp(type, "GRAYSCALE") == 0) { + ph->gray = 1; + ttype = 1; + continue; + } + if (strcmp(type, "GRAYSCALE_ALPHA") == 0) { + ph->graya = 1; + ttype = 1; + continue; + } + if (strcmp(type, "RGB") == 0) { + ph->rgb = 1; + ttype = 1; + continue; + } + if (strcmp(type, "RGB_ALPHA") == 0) { + ph->rgba = 1; + ttype = 1; + continue; + } + fprintf(stderr, "read_pnm_header:unknown P7 TUPLTYPE %s\n", type); + return; + } + fprintf(stderr, "read_pnm_header:unknown P7 idf %s\n", idf); + return; + } /* if(format == 7) */ + + if (!have_wh) { + s = skip_int(s, &ph->width); + + s = skip_int(s, &ph->height); + + have_wh = 1; + + if (format == 1 || format == 4) { + break; + } + + continue; + } + if (format == 2 || format == 3 || format == 5 || format == 6) { + /* P2, P3, P5, P6: */ + s = skip_int(s, &ph->maxval); + + if (ph->maxval > 65535) { + return; + } + } + break; + }/* while(fgets( ) */ + if (format == 2 || format == 3 || format > 4) { + if (ph->maxval < 1 || ph->maxval > 65535) { + return; + } + } + if (ph->width < 1 || ph->height < 1) { + return; + } + + if (format == 7) { + if (!end) { + fprintf(stderr, "read_pnm_header:P7 without ENDHDR\n"); + return; + } + if (ph->depth < 1 || ph->depth > 4) { + return; + } + + if (ph->width && ph->height && ph->depth & ph->maxval && ttype) { + ph->ok = 1; + } + } else { + if (format != 1 && format != 4) { + if (ph->width && ph->height && ph->maxval) { + ph->ok = 1; + } + } else { + if (ph->width && ph->height) { + ph->ok = 1; + } + ph->maxval = 255; + } + } +} + +static int has_prec(int val) +{ + if (val < 2) { + return 1; + } + if (val < 4) { + return 2; + } + if (val < 8) { + return 3; + } + if (val < 16) { + return 4; + } + if (val < 32) { + return 5; + } + if (val < 64) { + return 6; + } + if (val < 128) { + return 7; + } + if (val < 256) { + return 8; + } + if (val < 512) { + return 9; + } + if (val < 1024) { + return 10; + } + if (val < 2048) { + return 11; + } + if (val < 4096) { + return 12; + } + if (val < 8192) { + return 13; + } + if (val < 16384) { + return 14; + } + if (val < 32768) { + return 15; + } + return 16; +} + +opj_image_t* pnmtoimage(const char *filename, opj_cparameters_t *parameters) +{ + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + + FILE *fp = NULL; + int i, compno, numcomps, w, h, prec, format; + OPJ_COLOR_SPACE color_space; + opj_image_cmptparm_t cmptparm[4]; /* RGBA: max. 4 components */ + opj_image_t * image = NULL; + struct pnm_header header_info; + + if ((fp = fopen(filename, "rb")) == NULL) { + fprintf(stderr, "pnmtoimage:Failed to open %s for reading!\n", filename); + return NULL; + } + memset(&header_info, 0, sizeof(struct pnm_header)); + + read_pnm_header(fp, &header_info); + + if (!header_info.ok) { + fclose(fp); + return NULL; + } + + format = header_info.format; + + switch (format) { + case 1: /* ascii bitmap */ + case 4: /* raw bitmap */ + numcomps = 1; + break; + + case 2: /* ascii greymap */ + case 5: /* raw greymap */ + numcomps = 1; + break; + + case 3: /* ascii pixmap */ + case 6: /* raw pixmap */ + numcomps = 3; + break; + + case 7: /* arbitrary map */ + numcomps = header_info.depth; + break; + + default: + fclose(fp); + return NULL; + } + if (numcomps < 3) { + color_space = CLRSPC_GRAY; /* GRAY, GRAYA */ + } else { + color_space = CLRSPC_SRGB; /* RGB, RGBA */ + } + + prec = has_prec(header_info.maxval); + + if (prec < 8) { + prec = 8; + } + + w = header_info.width; + h = header_info.height; + subsampling_dx = parameters->subsampling_dx; + subsampling_dy = parameters->subsampling_dy; + + memset(&cmptparm[0], 0, numcomps * sizeof(opj_image_cmptparm_t)); + + for (i = 0; i < numcomps; i++) { + cmptparm[i].prec = prec; + cmptparm[i].bpp = prec; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = subsampling_dx; + cmptparm[i].dy = subsampling_dy; + cmptparm[i].w = w; + cmptparm[i].h = h; + } + image = opj_image_create(numcomps, &cmptparm[0], color_space); + + if (!image) { + fclose(fp); + return NULL; + } + + /* set image offset and reference grid */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = parameters->image_offset_x0 + (w - 1) * subsampling_dx + 1; + image->y1 = parameters->image_offset_y0 + (h - 1) * subsampling_dy + 1; + + if ((format == 2) || (format == 3)) { /* ascii pixmap */ + unsigned int index; + + for (i = 0; i < w * h; i++) { + for (compno = 0; compno < numcomps; compno++) { + index = 0; + if (fscanf(fp, "%u", &index) != 1) { + fprintf(stderr, + "\nWARNING: fscanf return a number of element different from the expected.\n"); + } + + image->comps[compno].data[i] = (index * 255) / header_info.maxval; + } + } + } else if ((format == 5) + || (format == 6) + || ((format == 7) + && (header_info.gray || header_info.graya + || header_info.rgb || header_info.rgba))) { /* binary pixmap */ + unsigned char c0, c1, one; + + one = (prec < 9); + + for (i = 0; i < w * h; i++) { + for (compno = 0; compno < numcomps; compno++) { + if (!fread(&c0, 1, 1, fp)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + } + if (one) { + image->comps[compno].data[i] = c0; + } else { + if (!fread(&c1, 1, 1, fp)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + } + /* netpbm: */ + image->comps[compno].data[i] = ((c0 << 8) | c1); + } + } + } + } else if (format == 1) { /* ascii bitmap */ + for (i = 0; i < w * h; i++) { + unsigned int index; + + if (fscanf(fp, "%u", &index) != 1) { + fprintf(stderr, + "\nWARNING: fscanf return a number of element different from the expected.\n"); + } + + image->comps[0].data[i] = (index ? 0 : 255); + } + } else if (format == 4) { + int x, y, bit; + unsigned char uc; + + i = 0; + for (y = 0; y < h; ++y) { + bit = -1; + uc = 0; + + for (x = 0; x < w; ++x) { + if (bit == -1) { + bit = 7; + uc = (unsigned char)getc(fp); + } + image->comps[0].data[i] = (((uc >> bit) & 1) ? 0 : 255); + --bit; + ++i; + } + } + } else if ((format == 7 && header_info.bw)) { /*MONO*/ + unsigned char uc; + + for (i = 0; i < w * h; ++i) { + if (!fread(&uc, 1, 1, fp)) { + fprintf(stderr, + "\nError: fread return a number of element different from the expected.\n"); + } + image->comps[0].data[i] = (uc & 1) ? 0 : 255; + } + } + fclose(fp); + + return image; +}/* pnmtoimage() */ + +int imagetopnm(opj_image_t * image, const char *outfile) +{ + int *red, *green, *blue, *alpha; + int wr, hr, max; + int i, compno, ncomp; + int adjustR, adjustG, adjustB, adjustA; + int fails, two, want_gray, has_alpha, triple; + int prec, v; + FILE *fdest = NULL; + const char *tmp = outfile; + char *destname; + alpha = NULL; + if ((prec = image->comps[0].prec) > 16) { + fprintf(stderr, "%s:%d:imagetopnm\n\tprecision %d is larger than 16" + "\n\t: refused.\n", __FILE__, __LINE__, prec); + return 1; + } + two = has_alpha = 0; + fails = 1; + ncomp = image->numcomps; + + while (*tmp) { + ++tmp; + } + tmp -= 2; + want_gray = (*tmp == 'g' || *tmp == 'G'); + ncomp = image->numcomps; + + if (want_gray) { + ncomp = 1; + } + + if (ncomp == 2 /* GRAYA */ + || (ncomp > 2 /* RGB, RGBA */ + && image->comps[0].dx == image->comps[1].dx + && image->comps[1].dx == image->comps[2].dx + && image->comps[0].dy == image->comps[1].dy + && image->comps[1].dy == image->comps[2].dy + && image->comps[0].prec == image->comps[1].prec + && image->comps[1].prec == image->comps[2].prec + )) { + fdest = fopen(outfile, "wb"); + + if (!fdest) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", outfile); + return fails; + } + two = (prec > 8); + triple = (ncomp > 2); + wr = image->comps[0].w; + hr = image->comps[0].h; + max = (1 << prec) - 1; + has_alpha = (ncomp == 4 || ncomp == 2); + + red = image->comps[0].data; + + if (triple) { + green = image->comps[1].data; + blue = image->comps[2].data; + } else { + green = blue = NULL; + } + + if (has_alpha) { + const char *tt = (triple ? "RGB_ALPHA" : "GRAYSCALE_ALPHA"); + + fprintf(fdest, "P7\n# OpenJPEG-%s\nWIDTH %d\nHEIGHT %d\nDEPTH %d\n" + "MAXVAL %d\nTUPLTYPE %s\nENDHDR\n", opj_version(), + wr, hr, ncomp, max, tt); + alpha = image->comps[ncomp - 1].data; + adjustA = (image->comps[ncomp - 1].sgnd ? + 1 << (image->comps[ncomp - 1].prec - 1) : 0); + } else { + fprintf(fdest, "P6\n# OpenJPEG-%s\n%d %d\n%d\n", + opj_version(), wr, hr, max); + adjustA = 0; + } + adjustR = (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + + if (triple) { + adjustG = (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); + adjustB = (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); + } else { + adjustG = adjustB = 0; + } + + for (i = 0; i < wr * hr; ++i) { + if (two) { + v = *red + adjustR; + ++red; + /* netpbm: */ + fprintf(fdest, "%c%c", (unsigned char)(v >> 8), (unsigned char)v); + + if (triple) { + v = *green + adjustG; + ++green; + /* netpbm: */ + fprintf(fdest, "%c%c", (unsigned char)(v >> 8), (unsigned char)v); + + v = *blue + adjustB; + ++blue; + /* netpbm: */ + fprintf(fdest, "%c%c", (unsigned char)(v >> 8), (unsigned char)v); + + }/* if(triple) */ + + if (has_alpha) { + v = *alpha + adjustA; + ++alpha; + /* netpbm: */ + fprintf(fdest, "%c%c", (unsigned char)(v >> 8), (unsigned char)v); + } + continue; + + } /* if(two) */ + + /* prec <= 8: */ + + fprintf(fdest, "%c", (unsigned char)*red++); + if (triple) { + fprintf(fdest, "%c%c", (unsigned char)*green++, (unsigned char)*blue++); + } + + if (has_alpha) { + fprintf(fdest, "%c", (unsigned char)*alpha++); + } + + } /* for(i */ + + fclose(fdest); + return 0; + } + + /* YUV or MONO: */ + + if (image->numcomps > ncomp) { + fprintf(stderr, "WARNING -> [PGM file] Only the first component\n"); + fprintf(stderr, " is written to the file\n"); + } + destname = (char*)malloc(strlen(outfile) + 8); + + for (compno = 0; compno < ncomp; compno++) { + if (ncomp > 1) { + sprintf(destname, "%d.%s", compno, outfile); + } else { + sprintf(destname, "%s", outfile); + } + + fdest = fopen(destname, "wb"); + if (!fdest) { + fprintf(stderr, "ERROR -> failed to open %s for writing\n", destname); + free(destname); + return 1; + } + wr = image->comps[compno].w; + hr = image->comps[compno].h; + prec = image->comps[compno].prec; + max = (1 << prec) - 1; + + fprintf(fdest, "P5\n#OpenJPEG-%s\n%d %d\n%d\n", + opj_version(), wr, hr, max); + + red = image->comps[compno].data; + adjustR = + (image->comps[compno].sgnd ? 1 << (image->comps[compno].prec - 1) : 0); + + if (prec > 8) { + for (i = 0; i < wr * hr; i++) { + v = *red + adjustR; + ++red; + /* netpbm: */ + fprintf(fdest, "%c%c", (unsigned char)(v >> 8), (unsigned char)v); + + if (has_alpha) { + v = *alpha++; + /* netpbm: */ + fprintf(fdest, "%c%c", (unsigned char)(v >> 8), (unsigned char)v); + } + }/* for(i */ + } else { /* prec <= 8 */ + for (i = 0; i < wr * hr; ++i) { + fprintf(fdest, "%c", (unsigned char)(*red + adjustR)); + ++red; + } + } + fclose(fdest); + } /* for (compno */ + free(destname); + + return 0; +}/* imagetopnm() */ + +#ifdef OPJ_HAVE_LIBTIFF +/* -->> -->> -->> -->> + + TIFF IMAGE FORMAT + + <<-- <<-- <<-- <<-- */ + +int imagetotif(opj_image_t * image, const char *outfile) +{ + int width, height, imgsize; + int bps, index, adjust, sgnd; + int ushift, dshift, has_alpha, force16; + TIFF *tif; + tdata_t buf; + tstrip_t strip; + tsize_t strip_size; + + ushift = dshift = force16 = has_alpha = 0; + bps = image->comps[0].prec; + + if (bps > 8 && bps < 16) { + ushift = 16 - bps; + dshift = bps - ushift; + bps = 16; + force16 = 1; + } + + if (bps != 8 && bps != 16) { + fprintf(stderr, "imagetotif: Bits=%d, Only 8 and 16 bits implemented\n", + bps); + fprintf(stderr, "\tAborting\n"); + return 1; + } + tif = TIFFOpen(outfile, "wb"); + + if (!tif) { + fprintf(stderr, "imagetotif:failed to open %s for writing\n", outfile); + return 1; + } + sgnd = image->comps[0].sgnd; + adjust = sgnd ? 1 << (image->comps[0].prec - 1) : 0; + + if (image->numcomps >= 3 + && image->comps[0].dx == image->comps[1].dx + && image->comps[1].dx == image->comps[2].dx + && image->comps[0].dy == image->comps[1].dy + && image->comps[1].dy == image->comps[2].dy + && image->comps[0].prec == image->comps[1].prec + && image->comps[1].prec == image->comps[2].prec) { + has_alpha = (image->numcomps == 4); + + width = image->comps[0].w; + height = image->comps[0].h; + imgsize = width * height ; + + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3 + has_alpha); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps); + TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1); + strip_size = TIFFStripSize(tif); + buf = _TIFFmalloc(strip_size); + index = 0; + + for (strip = 0; strip < TIFFNumberOfStrips(tif); strip++) { + unsigned char *dat8; + tsize_t i, ssize, last_i = 0; + int step, restx; + ssize = TIFFStripSize(tif); + dat8 = (unsigned char*)buf; + + if (bps == 8) { + step = 3 + has_alpha; + restx = step - 1; + + for (i = 0; i < ssize - restx; i += step) { + int r, g, b, a = 0; + + if (index < imgsize) { + r = image->comps[0].data[index]; + g = image->comps[1].data[index]; + b = image->comps[2].data[index]; + if (has_alpha) { + a = image->comps[3].data[index]; + } + + if (sgnd) { + r += adjust; + g += adjust; + b += adjust; + if (has_alpha) { + a += adjust; + } + } + dat8[i + 0] = r ; + dat8[i + 1] = g ; + dat8[i + 2] = b ; + if (has_alpha) { + dat8[i + 3] = a; + } + + index++; + last_i = i + step; + } else { + break; + } + }/*for(i = 0;)*/ + + if (last_i < ssize) { + for (i = last_i; i < ssize; i += step) { + int r, g, b, a = 0; + + if (index < imgsize) { + r = image->comps[0].data[index]; + g = image->comps[1].data[index]; + b = image->comps[2].data[index]; + if (has_alpha) { + a = image->comps[3].data[index]; + } + + if (sgnd) { + r += adjust; + g += adjust; + b += adjust; + if (has_alpha) { + a += adjust; + } + } + dat8[i + 0] = r ; + if (i + 1 < ssize) { + dat8[i + 1] = g ; + } else { + break; + } + if (i + 2 < ssize) { + dat8[i + 2] = b ; + } else { + break; + } + if (has_alpha) { + if (i + 3 < ssize) { + dat8[i + 3] = a ; + } else { + break; + } + } + index++; + } else { + break; + } + }/*for(i)*/ + }/*if(last_i < ssize)*/ + + } /*if(bps == 8)*/ + else if (bps == 16) { + step = 6 + has_alpha + has_alpha; + restx = step - 1; + + for (i = 0; i < ssize - restx ; i += step) { + int r, g, b, a = 0; + + if (index < imgsize) { + r = image->comps[0].data[index]; + g = image->comps[1].data[index]; + b = image->comps[2].data[index]; + if (has_alpha) { + a = image->comps[3].data[index]; + } + + if (sgnd) { + r += adjust; + g += adjust; + b += adjust; + if (has_alpha) { + a += adjust; + } + } + if (force16) { + r = (r << ushift) + (r >> dshift); + g = (g << ushift) + (g >> dshift); + b = (b << ushift) + (b >> dshift); + if (has_alpha) { + a = (a << ushift) + (a >> dshift); + } + } + dat8[i + 0] = r; /*LSB*/ + dat8[i + 1] = (r >> 8); /*MSB*/ + dat8[i + 2] = g; + dat8[i + 3] = (g >> 8); + dat8[i + 4] = b; + dat8[i + 5] = (b >> 8); + if (has_alpha) { + dat8[i + 6] = a; + dat8[i + 7] = (a >> 8); + } + index++; + last_i = i + step; + } else { + break; + } + }/*for(i = 0;)*/ + + if (last_i < ssize) { + for (i = last_i ; i < ssize ; i += step) { + int r, g, b, a = 0; + + if (index < imgsize) { + r = image->comps[0].data[index]; + g = image->comps[1].data[index]; + b = image->comps[2].data[index]; + if (has_alpha) { + a = image->comps[3].data[index]; + } + + if (sgnd) { + r += adjust; + g += adjust; + b += adjust; + if (has_alpha) { + a += adjust; + } + } + if (force16) { + r = (r << ushift) + (r >> dshift); + g = (g << ushift) + (g >> dshift); + b = (b << ushift) + (b >> dshift); + if (has_alpha) { + a = (a << ushift) + (a >> dshift); + } + } + dat8[i + 0] = r; /*LSB*/ + if (i + 1 < ssize) { + dat8[i + 1] = (r >> 8); + } else { + break; /*MSB*/ + } + if (i + 2 < ssize) { + dat8[i + 2] = g; + } else { + break; + } + if (i + 3 < ssize) { + dat8[i + 3] = (g >> 8); + } else { + break; + } + if (i + 4 < ssize) { + dat8[i + 4] = b; + } else { + break; + } + if (i + 5 < ssize) { + dat8[i + 5] = (b >> 8); + } else { + break; + } + + if (has_alpha) { + if (i + 6 < ssize) { + dat8[i + 6] = a; + } else { + break; + } + if (i + 7 < ssize) { + dat8[i + 7] = (a >> 8); + } else { + break; + } + } + index++; + } else { + break; + } + }/*for(i)*/ + }/*if(last_i < ssize)*/ + + }/*if(bps == 16)*/ + (void)TIFFWriteEncodedStrip(tif, strip, (void*)buf, strip_size); + }/*for(strip = 0; )*/ + + _TIFFfree((void*)buf); + TIFFClose(tif); + + return 0; + }/*RGB(A)*/ + + if (image->numcomps == 1 /* GRAY */ + || (image->numcomps == 2 /* GRAY_ALPHA */ + && image->comps[0].dx == image->comps[1].dx + && image->comps[0].dy == image->comps[1].dy + && image->comps[0].prec == image->comps[1].prec)) { + int step; + + has_alpha = (image->numcomps == 2); + + width = image->comps[0].w; + height = image->comps[0].h; + imgsize = width * height; + + /* Set tags */ + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1 + has_alpha); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps); + TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1); + + /* Get a buffer for the data */ + strip_size = TIFFStripSize(tif); + buf = _TIFFmalloc(strip_size); + index = 0; + + for (strip = 0; strip < TIFFNumberOfStrips(tif); strip++) { + unsigned char *dat8; + tsize_t i, ssize = TIFFStripSize(tif); + dat8 = (unsigned char*)buf; + + if (bps == 8) { + step = 1 + has_alpha; + + for (i = 0; i < ssize; i += step) { + if (index < imgsize) { + int r, a = 0; + + r = image->comps[0].data[index]; + if (has_alpha) { + a = image->comps[1].data[index]; + } + + if (sgnd) { + r += adjust; + if (has_alpha) { + a += adjust; + } + } + dat8[i + 0] = r; + if (has_alpha) { + dat8[i + 1] = a; + } + index++; + } else { + break; + } + }/*for(i )*/ + }/*if(bps == 8*/ + else if (bps == 16) { + step = 2 + has_alpha + has_alpha; + + for (i = 0; i < ssize; i += step) { + if (index < imgsize) { + int r, a = 0; + + r = image->comps[0].data[index]; + if (has_alpha) { + a = image->comps[1].data[index]; + } + + if (sgnd) { + r += adjust; + if (has_alpha) { + a += adjust; + } + } + if (force16) { + r = (r << ushift) + (r >> dshift); + if (has_alpha) { + a = (a << ushift) + (a >> dshift); + } + } + dat8[i + 0] = r; /*LSB*/ + dat8[i + 1] = r >> 8; /*MSB*/ + if (has_alpha) { + dat8[i + 2] = a; + dat8[i + 3] = a >> 8; + } + index++; + }/*if(index < imgsize)*/ + else { + break; + } + }/*for(i )*/ + } + (void)TIFFWriteEncodedStrip(tif, strip, (void*)buf, strip_size); + }/*for(strip*/ + + _TIFFfree(buf); + TIFFClose(tif); + + return 0; + } + + TIFFClose(tif); + + fprintf(stderr, "imagetotif: Bad color format.\n" + "\tOnly RGB(A) and GRAY(A) has been implemented\n"); + fprintf(stderr, "\tFOUND: numcomps(%d)\n\tAborting\n", + image->numcomps); + + return 1; +}/* imagetotif() */ + +/* + * libtiff/tif_getimage.c : 1,2,4,8,16 bitspersample accepted + * CINEMA : 12 bit precision +*/ +opj_image_t* tiftoimage(const char *filename, opj_cparameters_t *parameters) +{ + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + TIFF *tif; + tdata_t buf; + tstrip_t strip; + tsize_t strip_size; + int j, numcomps, w, h, index; + OPJ_COLOR_SPACE color_space; + opj_image_cmptparm_t cmptparm[4]; /* RGBA */ + opj_image_t *image = NULL; + int imgsize = 0; + int has_alpha = 0; + unsigned short tiBps, tiPhoto, tiSf, tiSpp, tiPC; + unsigned int tiWidth, tiHeight; + + tif = TIFFOpen(filename, "r"); + + if (!tif) { + fprintf(stderr, "tiftoimage:Failed to open %s for reading\n", filename); + return 0; + } + tiBps = tiPhoto = tiSf = tiSpp = tiPC = 0; + tiWidth = tiHeight = 0; + + TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &tiWidth); + TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &tiHeight); + TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &tiBps); + TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &tiSf); + TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &tiSpp); + TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &tiPhoto); + TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &tiPC); + w = tiWidth; + h = tiHeight; + + { + unsigned short b = tiBps, p = tiPhoto; + + if (tiBps != 8 && tiBps != 16 && tiBps != 12) { + b = 0; + } + if (tiPhoto != 1 && tiPhoto != 2) { + p = 0; + } + + if (!b || !p) { + if (!b) + fprintf(stderr, "imagetotif: Bits=%d, Only 8 and 16 bits" + " implemented\n", tiBps); + else if (!p) + fprintf(stderr, "tiftoimage: Bad color format %d.\n\tOnly RGB(A)" + " and GRAY(A) has been implemented\n", (int) tiPhoto); + + fprintf(stderr, "\tAborting\n"); + TIFFClose(tif); + + return NULL; + } + } + {/* From: tiff-4.0.x/libtiff/tif_getimage.c : */ + uint16* sampleinfo; + uint16 extrasamples; + + TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, + &extrasamples, &sampleinfo); + + if (extrasamples >= 1) { + switch (sampleinfo[0]) { + case EXTRASAMPLE_UNSPECIFIED: + /* Workaround for some images without correct info about alpha channel + */ + if (tiSpp > 3) { + has_alpha = 1; + } + break; + + case EXTRASAMPLE_ASSOCALPHA: /* data pre-multiplied */ + case EXTRASAMPLE_UNASSALPHA: /* data not pre-multiplied */ + has_alpha = 1; + break; + } + } else /* extrasamples == 0 */ + if (tiSpp == 4 || tiSpp == 2) { + has_alpha = 1; + } + } + + /* initialize image components + */ + memset(&cmptparm[0], 0, 4 * sizeof(opj_image_cmptparm_t)); + + if (tiPhoto == PHOTOMETRIC_RGB) { /* RGB(A) */ + numcomps = 3 + has_alpha; + color_space = CLRSPC_SRGB; + + for (j = 0; j < numcomps; j++) { + if (parameters->cp_cinema) { + cmptparm[j].prec = 12; + cmptparm[j].bpp = 12; + } else { + cmptparm[j].prec = tiBps; + cmptparm[j].bpp = tiBps; + } + cmptparm[j].dx = subsampling_dx; + cmptparm[j].dy = subsampling_dy; + cmptparm[j].w = w; + cmptparm[j].h = h; + } + + image = opj_image_create(numcomps, &cmptparm[0], color_space); + + if (!image) { + TIFFClose(tif); + return NULL; + } + /* set image offset and reference grid + */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = !image->x0 ? (w - 1) * subsampling_dx + 1 : + image->x0 + (w - 1) * subsampling_dx + 1; + image->y1 = !image->y0 ? (h - 1) * subsampling_dy + 1 : + image->y0 + (h - 1) * subsampling_dy + 1; + + buf = _TIFFmalloc(TIFFStripSize(tif)); + + strip_size = TIFFStripSize(tif); + index = 0; + imgsize = image->comps[0].w * image->comps[0].h ; + /* Read the Image components + */ + for (strip = 0; strip < TIFFNumberOfStrips(tif); strip++) { + unsigned char *dat8; + int step; + tsize_t i, ssize; + ssize = TIFFReadEncodedStrip(tif, strip, buf, strip_size); + dat8 = (unsigned char*)buf; + + if (tiBps == 16) { + step = 6 + has_alpha + has_alpha; + + for (i = 0; i < ssize; i += step) { + if (index < imgsize) { + image->comps[0].data[index] = (dat8[i + 1] << 8) | dat8[i + 0]; /* R */ + image->comps[1].data[index] = (dat8[i + 3] << 8) | dat8[i + 2]; /* G */ + image->comps[2].data[index] = (dat8[i + 5] << 8) | dat8[i + 4]; /* B */ + if (has_alpha) { + image->comps[3].data[index] = (dat8[i + 7] << 8) | dat8[i + 6]; + } + + if (parameters->cp_cinema) { + /* Rounding 16 to 12 bits + */ + image->comps[0].data[index] = + (image->comps[0].data[index] + 0x08) >> 4 ; + image->comps[1].data[index] = + (image->comps[1].data[index] + 0x08) >> 4 ; + image->comps[2].data[index] = + (image->comps[2].data[index] + 0x08) >> 4 ; + if (has_alpha) + image->comps[3].data[index] = + (image->comps[3].data[index] + 0x08) >> 4 ; + } + index++; + } else { + break; + } + }/*for(i = 0)*/ + }/*if(tiBps == 16)*/ + else if (tiBps == 8) { + step = 3 + has_alpha; + + for (i = 0; i < ssize; i += step) { + if (index < imgsize) { + image->comps[0].data[index] = dat8[i + 0]; /* R */ + image->comps[1].data[index] = dat8[i + 1]; /* G */ + image->comps[2].data[index] = dat8[i + 2]; /* B */ + if (has_alpha) { + image->comps[3].data[index] = dat8[i + 3]; + } + + if (parameters->cp_cinema) { + /* Rounding 8 to 12 bits + */ + image->comps[0].data[index] = image->comps[0].data[index] << 4 ; + image->comps[1].data[index] = image->comps[1].data[index] << 4 ; + image->comps[2].data[index] = image->comps[2].data[index] << 4 ; + if (has_alpha) { + image->comps[3].data[index] = image->comps[3].data[index] << 4 ; + } + } + index++; + }/*if(index*/ + else { + break; + } + }/*for(i )*/ + }/*if( tiBps == 8)*/ + else if (tiBps == 12) { /* CINEMA file */ + step = 9; + + for (i = 0; i < ssize; i += step) { + if ((index < imgsize) & (index + 1 < imgsize)) { + image->comps[0].data[index] = (dat8[i + 0] << 4) | (dat8[i + 1] >> 4); + image->comps[1].data[index] = ((dat8[i + 1] & 0x0f) << 8) | dat8[i + 2]; + + image->comps[2].data[index] = (dat8[i + 3] << 4) | (dat8[i + 4] >> 4); + image->comps[0].data[index + 1] = ((dat8[i + 4] & 0x0f) << 8) | dat8[i + 5]; + + image->comps[1].data[index + 1] = (dat8[i + 6] << 4) | + (dat8[i + 7] >> 4); + image->comps[2].data[index + 1] = ((dat8[i + 7] & 0x0f) << 8) | dat8[i + 8]; + + index += 2; + } else { + break; + } + }/*for(i )*/ + } + }/*for(strip = 0; )*/ + + _TIFFfree(buf); + TIFFClose(tif); + + return image; + }/*RGB(A)*/ + + if (tiPhoto == PHOTOMETRIC_MINISBLACK) { /* GRAY(A) */ + numcomps = 1 + has_alpha; + color_space = CLRSPC_GRAY; + + for (j = 0; j < numcomps; ++j) { + cmptparm[j].prec = tiBps; + cmptparm[j].bpp = tiBps; + cmptparm[j].dx = subsampling_dx; + cmptparm[j].dy = subsampling_dy; + cmptparm[j].w = w; + cmptparm[j].h = h; + } + image = opj_image_create(numcomps, &cmptparm[0], color_space); + + if (!image) { + TIFFClose(tif); + return NULL; + } + /* set image offset and reference grid + */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = !image->x0 ? (w - 1) * subsampling_dx + 1 : + image->x0 + (w - 1) * subsampling_dx + 1; + image->y1 = !image->y0 ? (h - 1) * subsampling_dy + 1 : + image->y0 + (h - 1) * subsampling_dy + 1; + + buf = _TIFFmalloc(TIFFStripSize(tif)); + + strip_size = TIFFStripSize(tif); + index = 0; + imgsize = image->comps[0].w * image->comps[0].h ; + /* Read the Image components + */ + for (strip = 0; strip < TIFFNumberOfStrips(tif); strip++) { + unsigned char *dat8; + tsize_t i, ssize; + int step; + + ssize = TIFFReadEncodedStrip(tif, strip, buf, strip_size); + dat8 = (unsigned char*)buf; + + if (tiBps == 16) { + step = 2 + has_alpha + has_alpha; + + for (i = 0; i < ssize; i += step) { + if (index < imgsize) { + image->comps[0].data[index] = (dat8[i + 1] << 8) | dat8[i + 0]; + if (has_alpha) { + image->comps[1].data[index] = (dat8[i + 3] << 8) | dat8[i + 2]; + } + index++; + } else { + break; + } + }/*for(i )*/ + } else if (tiBps == 8) { + step = 1 + has_alpha; + + for (i = 0; i < ssize; i += step) { + if (index < imgsize) { + image->comps[0].data[index] = dat8[i + 0]; + if (has_alpha) { + image->comps[1].data[index] = dat8[i + 1]; + } + index++; + } else { + break; + } + }/*for(i )*/ + } + }/*for(strip = 0;*/ + + _TIFFfree(buf); + TIFFClose(tif); + + }/*GRAY(A)*/ + + return image; + +}/* tiftoimage() */ + +#endif /* OPJ_HAVE_LIBTIFF */ + +/* -->> -->> -->> -->> + + RAW IMAGE FORMAT + + <<-- <<-- <<-- <<-- */ + +opj_image_t* rawtoimage(const char *filename, opj_cparameters_t *parameters, + raw_cparameters_t *raw_cp) +{ + int subsampling_dx = parameters->subsampling_dx; + int subsampling_dy = parameters->subsampling_dy; + + FILE *f = NULL; + int i, compno, numcomps, w, h; + OPJ_COLOR_SPACE color_space; + opj_image_cmptparm_t *cmptparm; + opj_image_t * image = NULL; + unsigned short ch; + + if ((!(raw_cp->rawWidth & raw_cp->rawHeight & raw_cp->rawComp & + raw_cp->rawBitDepth)) == 0) { + fprintf(stderr, "\nError: invalid raw image parameters\n"); + fprintf(stderr, "Please use the Format option -F:\n"); + fprintf(stderr, + "-F rawWidth,rawHeight,rawComp,rawBitDepth,s/u (Signed/Unsigned)\n"); + fprintf(stderr, "Example: -i lena.raw -o lena.j2k -F 512,512,3,8,u\n"); + fprintf(stderr, "Aborting\n"); + return NULL; + } + + f = fopen(filename, "rb"); + if (!f) { + fprintf(stderr, "Failed to open %s for reading !!\n", filename); + fprintf(stderr, "Aborting\n"); + return NULL; + } + numcomps = raw_cp->rawComp; + color_space = CLRSPC_SRGB; + w = raw_cp->rawWidth; + h = raw_cp->rawHeight; + cmptparm = (opj_image_cmptparm_t*) malloc(numcomps * sizeof( + opj_image_cmptparm_t)); + + /* initialize image components */ + memset(&cmptparm[0], 0, numcomps * sizeof(opj_image_cmptparm_t)); + for (i = 0; i < numcomps; i++) { + cmptparm[i].prec = raw_cp->rawBitDepth; + cmptparm[i].bpp = raw_cp->rawBitDepth; + cmptparm[i].sgnd = raw_cp->rawSigned; + cmptparm[i].dx = subsampling_dx; + cmptparm[i].dy = subsampling_dy; + cmptparm[i].w = w; + cmptparm[i].h = h; + } + /* create the image */ + image = opj_image_create(numcomps, &cmptparm[0], color_space); + if (!image) { + fclose(f); + return NULL; + } + /* set image offset and reference grid */ + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = parameters->image_offset_x0 + (w - 1) * subsampling_dx + 1; + image->y1 = parameters->image_offset_y0 + (h - 1) * subsampling_dy + 1; + + if (raw_cp->rawBitDepth <= 8) { + unsigned char value = 0; + for (compno = 0; compno < numcomps; compno++) { + for (i = 0; i < w * h; i++) { + if (!fread(&value, 1, 1, f)) { + fprintf(stderr, "Error reading raw file. End of file probably reached.\n"); + fclose(f); + return NULL; + } + image->comps[compno].data[i] = raw_cp->rawSigned ? (char)value : value; + } + } + } else if (raw_cp->rawBitDepth <= 16) { + unsigned short value; + for (compno = 0; compno < numcomps; compno++) { + for (i = 0; i < w * h; i++) { + unsigned char temp; + if (!fread(&temp, 1, 1, f)) { + fprintf(stderr, "Error reading raw file. End of file probably reached.\n"); + fclose(f); + return NULL; + } + value = temp << 8; + if (!fread(&temp, 1, 1, f)) { + fprintf(stderr, "Error reading raw file. End of file probably reached.\n"); + fclose(f); + return NULL; + } + value += temp; + image->comps[compno].data[i] = raw_cp->rawSigned ? (short)value : value; + } + } + } else { + fprintf(stderr, + "OpenJPEG cannot encode raw components with bit depth higher than 16 bits.\n"); + fclose(f); + return NULL; + } + + if (fread(&ch, 1, 1, f)) { + fprintf(stderr, "Warning. End of raw file not reached... processing anyway\n"); + } + fclose(f); + + return image; +} + +int imagetoraw(opj_image_t * image, const char *outfile) +{ + FILE *rawFile = NULL; + size_t res; + int compno; + int w, h; + int line, row; + int *ptr; + + if ((image->numcomps * image->x1 * image->y1) == 0) { + fprintf(stderr, "\nError: invalid raw image parameters\n"); + return 1; + } + + rawFile = fopen(outfile, "wb"); + if (!rawFile) { + fprintf(stderr, "Failed to open %s for writing !!\n", outfile); + return 1; + } + + fprintf(stdout, "Raw image characteristics: %d components\n", image->numcomps); + + for (compno = 0; compno < image->numcomps; compno++) { + fprintf(stdout, "Component %d characteristics: %dx%dx%d %s\n", compno, + image->comps[compno].w, + image->comps[compno].h, image->comps[compno].prec, + image->comps[compno].sgnd == 1 ? "signed" : "unsigned"); + + w = image->comps[compno].w; + h = image->comps[compno].h; + + if (image->comps[compno].prec <= 8) { + if (image->comps[compno].sgnd == 1) { + signed char curr; + int mask = (1 << image->comps[compno].prec) - 1; + ptr = image->comps[compno].data; + for (line = 0; line < h; line++) { + for (row = 0; row < w; row++) { + curr = (signed char)(*ptr & mask); + res = fwrite(&curr, sizeof(signed char), 1, rawFile); + if (res < 1) { + fprintf(stderr, "failed to write 1 byte for %s\n", outfile); + return 1; + } + ptr++; + } + } + } else if (image->comps[compno].sgnd == 0) { + unsigned char curr; + int mask = (1 << image->comps[compno].prec) - 1; + ptr = image->comps[compno].data; + for (line = 0; line < h; line++) { + for (row = 0; row < w; row++) { + curr = (unsigned char)(*ptr & mask); + res = fwrite(&curr, sizeof(unsigned char), 1, rawFile); + if (res < 1) { + fprintf(stderr, "failed to write 1 byte for %s\n", outfile); + return 1; + } + ptr++; + } + } + } + } else if (image->comps[compno].prec <= 16) { + if (image->comps[compno].sgnd == 1) { + signed short int curr; + int mask = (1 << image->comps[compno].prec) - 1; + ptr = image->comps[compno].data; + for (line = 0; line < h; line++) { + for (row = 0; row < w; row++) { + unsigned char temp; + curr = (signed short int)(*ptr & mask); + temp = (unsigned char)(curr >> 8); + res = fwrite(&temp, 1, 1, rawFile); + if (res < 1) { + fprintf(stderr, "failed to write 1 byte for %s\n", outfile); + return 1; + } + temp = (unsigned char) curr; + res = fwrite(&temp, 1, 1, rawFile); + if (res < 1) { + fprintf(stderr, "failed to write 1 byte for %s\n", outfile); + return 1; + } + ptr++; + } + } + } else if (image->comps[compno].sgnd == 0) { + unsigned short int curr; + int mask = (1 << image->comps[compno].prec) - 1; + ptr = image->comps[compno].data; + for (line = 0; line < h; line++) { + for (row = 0; row < w; row++) { + unsigned char temp; + curr = (unsigned short int)(*ptr & mask); + temp = (unsigned char)(curr >> 8); + res = fwrite(&temp, 1, 1, rawFile); + if (res < 1) { + fprintf(stderr, "failed to write 1 byte for %s\n", outfile); + return 1; + } + temp = (unsigned char) curr; + res = fwrite(&temp, 1, 1, rawFile); + if (res < 1) { + fprintf(stderr, "failed to write 1 byte for %s\n", outfile); + return 1; + } + ptr++; + } + } + } + } else if (image->comps[compno].prec <= 32) { + fprintf(stderr, "More than 16 bits per component no handled yet\n"); + return 1; + } else { + fprintf(stderr, "Error: invalid precision: %d\n", image->comps[compno].prec); + return 1; + } + } + fclose(rawFile); + return 0; +} + +#ifdef OPJ_HAVE_LIBPNG + +#define PNG_MAGIC "\x89PNG\x0d\x0a\x1a\x0a" +#define MAGIC_SIZE 8 +/* PNG allows bits per sample: 1, 2, 4, 8, 16 */ + +opj_image_t *pngtoimage(const char *read_idf, opj_cparameters_t * params) +{ + png_structp png; + png_infop info; + double gamma, display_exponent; + int bit_depth, interlace_type, compression_type, filter_type; + int unit; + png_uint_32 resx, resy; + unsigned int i, j; + png_uint_32 width, height; + int color_type, has_alpha, is16; + unsigned char *s; + FILE *reader; + unsigned char **rows; + /* j2k: */ + opj_image_t *image; + opj_image_cmptparm_t cmptparm[4]; + int sub_dx, sub_dy; + unsigned int nr_comp; + int *r, *g, *b, *a; + unsigned char sigbuf[8]; + + if ((reader = fopen(read_idf, "rb")) == NULL) { + fprintf(stderr, "pngtoimage: can not open %s\n", read_idf); + return NULL; + } + image = NULL; + png = NULL; + rows = NULL; + + if (fread(sigbuf, 1, MAGIC_SIZE, reader) != MAGIC_SIZE + || memcmp(sigbuf, PNG_MAGIC, MAGIC_SIZE) != 0) { + fprintf(stderr, "pngtoimage: %s is no valid PNG file\n", read_idf); + goto fin; + } + /* libpng-VERSION/example.c: + * PC : screen_gamma = 2.2; + * Mac: screen_gamma = 1.7 or 1.0; + */ + display_exponent = 2.2; + + if ((png = png_create_read_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL)) == NULL) { + goto fin; + } + if ((info = png_create_info_struct(png)) == NULL) { + goto fin; + } + + if (setjmp(png_jmpbuf(png))) { + goto fin; + } + + png_init_io(png, reader); + png_set_sig_bytes(png, MAGIC_SIZE); + + png_read_info(png, info); + + if (png_get_IHDR(png, info, &width, &height, + &bit_depth, &color_type, &interlace_type, + &compression_type, &filter_type) == 0) { + goto fin; + } + + /* png_set_expand(): + * expand paletted images to RGB, expand grayscale images of + * less than 8-bit depth to 8-bit depth, and expand tRNS chunks + * to alpha channels. + */ + if (color_type == PNG_COLOR_TYPE_PALETTE) { + png_set_expand(png); + } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { + png_set_expand(png); + } + + if (png_get_valid(png, info, PNG_INFO_tRNS)) { + png_set_expand(png); + } + + is16 = (bit_depth == 16); + + /* GRAY => RGB; GRAY_ALPHA => RGBA + */ + if (color_type == PNG_COLOR_TYPE_GRAY + || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { + png_set_gray_to_rgb(png); + color_type = + (color_type == PNG_COLOR_TYPE_GRAY ? PNG_COLOR_TYPE_RGB : + PNG_COLOR_TYPE_RGB_ALPHA); + } + if (!png_get_gAMA(png, info, &gamma)) { + gamma = 0.45455; + } + + png_set_gamma(png, display_exponent, gamma); + + png_read_update_info(png, info); + + png_get_pHYs(png, info, &resx, &resy, &unit); + + color_type = png_get_color_type(png, info); + + has_alpha = (color_type == PNG_COLOR_TYPE_RGB_ALPHA); + + nr_comp = 3 + has_alpha; + + bit_depth = png_get_bit_depth(png, info); + + rows = (unsigned char**)calloc(height + 1, sizeof(unsigned char*)); + for (i = 0; i < height; ++i) { + rows[i] = (unsigned char*)malloc(png_get_rowbytes(png, info)); + } + + png_read_image(png, rows); + + memset(&cmptparm, 0, 4 * sizeof(opj_image_cmptparm_t)); + + sub_dx = params->subsampling_dx; + sub_dy = params->subsampling_dy; + + for (i = 0; i < nr_comp; ++i) { + cmptparm[i].prec = bit_depth; + /* bits_per_pixel: 8 or 16 */ + cmptparm[i].bpp = bit_depth; + cmptparm[i].sgnd = 0; + cmptparm[i].dx = sub_dx; + cmptparm[i].dy = sub_dy; + cmptparm[i].w = width; + cmptparm[i].h = height; + } + + image = opj_image_create(nr_comp, &cmptparm[0], CLRSPC_SRGB); + + if (image == NULL) { + goto fin; + } + + image->x0 = params->image_offset_x0; + image->y0 = params->image_offset_y0; + image->x1 = image->x0 + (width - 1) * sub_dx + 1 + image->x0; + image->y1 = image->y0 + (height - 1) * sub_dy + 1 + image->y0; + + r = image->comps[0].data; + g = image->comps[1].data; + b = image->comps[2].data; + a = image->comps[3].data; + + for (i = 0; i < height; ++i) { + s = rows[i]; + + for (j = 0; j < width; ++j) { + if (is16) { + *r++ = s[0] << 8 | s[1]; + s += 2; + + *g++ = s[0] << 8 | s[1]; + s += 2; + + *b++ = s[0] << 8 | s[1]; + s += 2; + + if (has_alpha) { + *a++ = s[0] << 8 | s[1]; + s += 2; + } + + continue; + } + *r++ = *s++; + *g++ = *s++; + *b++ = *s++; + + if (has_alpha) { + *a++ = *s++; + } + } + } +fin: + if (rows) { + for (i = 0; i < height; ++i) { + free(rows[i]); + } + free(rows); + } + if (png) { + png_destroy_read_struct(&png, &info, NULL); + } + + fclose(reader); + + return image; + +}/* pngtoimage() */ + +int imagetopng(opj_image_t * image, const char *write_idf) +{ + FILE *writer; + png_structp png; + png_infop info; + int *red, *green, *blue, *alpha; + unsigned char *row_buf, *d; + int has_alpha, width, height, nr_comp, color_type; + int adjustR, adjustG, adjustB, adjustA, x, y, fails; + int prec, ushift, dshift, is16, force16, force8; + unsigned short mask = 0xffff; + png_color_8 sig_bit; + + is16 = force16 = force8 = ushift = dshift = 0; + fails = 1; + prec = image->comps[0].prec; + nr_comp = image->numcomps; + + if (prec > 8 && prec < 16) { + ushift = 16 - prec; + dshift = prec - ushift; + prec = 16; + force16 = 1; + } else if (prec < 8 && nr_comp > 1) { /* GRAY_ALPHA, RGB, RGB_ALPHA */ + ushift = 8 - prec; + dshift = 8 - ushift; + prec = 8; + force8 = 1; + } + + if (prec != 1 && prec != 2 && prec != 4 && prec != 8 && prec != 16) { + fprintf(stderr, "imagetopng: can not create %s" + "\n\twrong bit_depth %d\n", write_idf, prec); + return fails; + } + writer = fopen(write_idf, "wb"); + + if (writer == NULL) { + return fails; + } + + info = NULL; + has_alpha = 0; + + /* Create and initialize the png_struct with the desired error handler + * functions. If you want to use the default stderr and longjump method, + * you can supply NULL for the last three parameters. We also check that + * the library version is compatible with the one used at compile time, + * in case we are using dynamically linked libraries. REQUIRED. + */ + png = png_create_write_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + /*png_voidp user_error_ptr, user_error_fn, user_warning_fn); */ + + if (png == NULL) { + goto fin; + } + + /* Allocate/initialize the image information data. REQUIRED + */ + info = png_create_info_struct(png); + + if (info == NULL) { + goto fin; + } + + /* Set error handling. REQUIRED if you are not supplying your own + * error handling functions in the png_create_write_struct() call. + */ + if (setjmp(png_jmpbuf(png))) { + goto fin; + } + + /* I/O initialization functions is REQUIRED + */ + png_init_io(png, writer); + + /* Set the image information here. Width and height are up to 2^31, + * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on + * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, + * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, + * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or + * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST + * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. + * REQUIRED + * + * ERRORS: + * + * color_type == PNG_COLOR_TYPE_PALETTE && bit_depth > 8 + * color_type == PNG_COLOR_TYPE_RGB && bit_depth < 8 + * color_type == PNG_COLOR_TYPE_GRAY_ALPHA && bit_depth < 8 + * color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8 + * + */ + png_set_compression_level(png, Z_BEST_COMPRESSION); + + if (prec == 16) { + mask = 0xffff; + } else if (prec == 8) { + mask = 0x00ff; + } else if (prec == 4) { + mask = 0x000f; + } else if (prec == 2) { + mask = 0x0003; + } else if (prec == 1) { + mask = 0x0001; + } + + if (nr_comp >= 3 + && image->comps[0].dx == image->comps[1].dx + && image->comps[1].dx == image->comps[2].dx + && image->comps[0].dy == image->comps[1].dy + && image->comps[1].dy == image->comps[2].dy + && image->comps[0].prec == image->comps[1].prec + && image->comps[1].prec == image->comps[2].prec) { + int v; + + has_alpha = (nr_comp > 3); + + is16 = (prec == 16); + + width = image->comps[0].w; + height = image->comps[0].h; + + red = image->comps[0].data; + green = image->comps[1].data; + blue = image->comps[2].data; + + sig_bit.red = sig_bit.green = sig_bit.blue = prec; + + if (has_alpha) { + sig_bit.alpha = prec; + alpha = image->comps[3].data; + color_type = PNG_COLOR_TYPE_RGB_ALPHA; + adjustA = (image->comps[3].sgnd ? 1 << (image->comps[3].prec - 1) : 0); + } else { + sig_bit.alpha = 0; + alpha = NULL; + color_type = PNG_COLOR_TYPE_RGB; + adjustA = 0; + } + png_set_sBIT(png, info, &sig_bit); + + png_set_IHDR(png, info, width, height, prec, + color_type, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + /*=============================*/ + png_write_info(png, info); + /*=============================*/ + if (prec < 8) { + png_set_packing(png); + } + adjustR = (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + adjustG = (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); + adjustB = (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); + + row_buf = (unsigned char*)malloc(width * nr_comp * 2); + + for (y = 0; y < height; ++y) { + d = row_buf; + + for (x = 0; x < width; ++x) { + if (is16) { + v = *red + adjustR; + ++red; + + if (force16) { + v = (v << ushift) + (v >> dshift); + } + + *d++ = (unsigned char)(v >> 8); + *d++ = (unsigned char)v; + + v = *green + adjustG; + ++green; + + if (force16) { + v = (v << ushift) + (v >> dshift); + } + + *d++ = (unsigned char)(v >> 8); + *d++ = (unsigned char)v; + + v = *blue + adjustB; + ++blue; + + if (force16) { + v = (v << ushift) + (v >> dshift); + } + + *d++ = (unsigned char)(v >> 8); + *d++ = (unsigned char)v; + + if (has_alpha) { + v = *alpha + adjustA; + ++alpha; + + if (force16) { + v = (v << ushift) + (v >> dshift); + } + + *d++ = (unsigned char)(v >> 8); + *d++ = (unsigned char)v; + } + continue; + }/* if(is16) */ + + v = *red + adjustR; + ++red; + + if (force8) { + v = (v << ushift) + (v >> dshift); + } + + *d++ = (unsigned char)(v & mask); + + v = *green + adjustG; + ++green; + + if (force8) { + v = (v << ushift) + (v >> dshift); + } + + *d++ = (unsigned char)(v & mask); + + v = *blue + adjustB; + ++blue; + + if (force8) { + v = (v << ushift) + (v >> dshift); + } + + *d++ = (unsigned char)(v & mask); + + if (has_alpha) { + v = *alpha + adjustA; + ++alpha; + + if (force8) { + v = (v << ushift) + (v >> dshift); + } + + *d++ = (unsigned char)(v & mask); + } + } /* for(x) */ + + png_write_row(png, row_buf); + + } /* for(y) */ + free(row_buf); + + }/* nr_comp >= 3 */ + else if (nr_comp == 1 /* GRAY */ + || (nr_comp == 2 /* GRAY_ALPHA */ + && image->comps[0].dx == image->comps[1].dx + && image->comps[0].dy == image->comps[1].dy + && image->comps[0].prec == image->comps[1].prec)) { + int v; + + red = image->comps[0].data; + + sig_bit.gray = prec; + sig_bit.red = sig_bit.green = sig_bit.blue = sig_bit.alpha = 0; + alpha = NULL; + adjustA = 0; + color_type = PNG_COLOR_TYPE_GRAY; + + if (nr_comp == 2) { + has_alpha = 1; + sig_bit.alpha = prec; + alpha = image->comps[1].data; + color_type = PNG_COLOR_TYPE_GRAY_ALPHA; + adjustA = (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); + } + width = image->comps[0].w; + height = image->comps[0].h; + + png_set_IHDR(png, info, width, height, sig_bit.gray, + color_type, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + png_set_sBIT(png, info, &sig_bit); + /*=============================*/ + png_write_info(png, info); + /*=============================*/ + adjustR = (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + + if (prec < 8) { + png_set_packing(png); + } + + if (prec > 8) { + row_buf = (unsigned char*) + malloc(width * nr_comp * sizeof(unsigned short)); + + for (y = 0; y < height; ++y) { + d = row_buf; + + for (x = 0; x < width; ++x) { + v = *red + adjustR; + ++red; + + if (force16) { + v = (v << ushift) + (v >> dshift); + } + + *d++ = (unsigned char)(v >> 8); + *d++ = (unsigned char)v; + + if (has_alpha) { + v = *alpha++; + + if (force16) { + v = (v << ushift) + (v >> dshift); + } + + *d++ = (unsigned char)(v >> 8); + *d++ = (unsigned char)v; + } + }/* for(x) */ + png_write_row(png, row_buf); + + } /* for(y) */ + free(row_buf); + } else { /* prec <= 8 */ + row_buf = (unsigned char*)calloc(width, nr_comp * 2); + + for (y = 0; y < height; ++y) { + d = row_buf; + + for (x = 0; x < width; ++x) { + v = *red + adjustR; + ++red; + + if (force8) { + v = (v << ushift) + (v >> dshift); + } + + *d++ = (unsigned char)(v & mask); + + if (has_alpha) { + v = *alpha + adjustA; + ++alpha; + + if (force8) { + v = (v << ushift) + (v >> dshift); + } + + *d++ = (unsigned char)(v & mask); + } + }/* for(x) */ + + png_write_row(png, row_buf); + + } /* for(y) */ + free(row_buf); + } + } else { + fprintf(stderr, "imagetopng: can not create %s\n", write_idf); + goto fin; + } + png_write_end(png, info); + + fails = 0; + +fin: + + if (png) { + png_destroy_write_struct(&png, &info); + } + fclose(writer); + + if (fails) { + remove(write_idf); + } + + return fails; +}/* imagetopng() */ +#endif /* OPJ_HAVE_LIBPNG */ diff --git a/openjpeg/src/bin/jpwl/convert.h b/openjpeg/src/bin/jpwl/convert.h new file mode 100644 index 000000000..7f1a5bc89 --- /dev/null +++ b/openjpeg/src/bin/jpwl/convert.h @@ -0,0 +1,90 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * Copyright (c) 2003-2014, Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __J2K_CONVERT_H +#define __J2K_CONVERT_H + +/**@name RAW image encoding parameters */ +/*@{*/ +typedef struct raw_cparameters { + /** width of the raw image */ + int rawWidth; + /** height of the raw image */ + int rawHeight; + /** components of the raw image */ + int rawComp; + /** bit depth of the raw image */ + int rawBitDepth; + /** signed/unsigned raw image */ + opj_bool rawSigned; + /*@}*/ +} raw_cparameters_t; + +/* TGA conversion */ +opj_image_t* tgatoimage(const char *filename, opj_cparameters_t *parameters); +int imagetotga(opj_image_t * image, const char *outfile); + +/* BMP conversion */ +opj_image_t* bmptoimage(const char *filename, opj_cparameters_t *parameters); +int imagetobmp(opj_image_t *image, const char *outfile); + +/* TIFF conversion*/ +opj_image_t* tiftoimage(const char *filename, opj_cparameters_t *parameters); +int imagetotif(opj_image_t *image, const char *outfile); +/** +Load a single image component encoded in PGX file format +@param filename Name of the PGX file to load +@param parameters *List ?* +@return Returns a greyscale image if successful, returns NULL otherwise +*/ +opj_image_t* pgxtoimage(const char *filename, opj_cparameters_t *parameters); +int imagetopgx(opj_image_t *image, const char *outfile); + +opj_image_t* pnmtoimage(const char *filename, opj_cparameters_t *parameters); +int imagetopnm(opj_image_t *image, const char *outfile); + +/* RAW conversion */ +int imagetoraw(opj_image_t * image, const char *outfile); +opj_image_t* rawtoimage(const char *filename, opj_cparameters_t *parameters, + raw_cparameters_t *raw_cp); + +/* PNG conversion*/ +extern int imagetopng(opj_image_t *image, const char *write_idf); +extern opj_image_t* pngtoimage(const char *filename, + opj_cparameters_t *parameters); + +#endif /* __J2K_CONVERT_H */ + diff --git a/openjpeg/src/bin/jpwl/index.c b/openjpeg/src/bin/jpwl/index.c new file mode 100644 index 000000000..6c6c8fc02 --- /dev/null +++ b/openjpeg/src/bin/jpwl/index.c @@ -0,0 +1,454 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <math.h> +#include <string.h> +#include "openjpeg.h" +#include "index.h" + +/* ------------------------------------------------------------------------------------ */ + +/** +Write a structured index to a file +@param cstr_info Codestream information +@param index Index filename +@return Returns 0 if successful, returns 1 otherwise +*/ +int write_index_file(opj_codestream_info_t *cstr_info, char *index) +{ + int tileno, compno, layno, resno, precno, pack_nb, x, y; + FILE *stream = NULL; + double total_disto = 0; + /* UniPG>> */ + int tilepartno; + char disto_on, numpix_on; + +#ifdef USE_JPWL + if (!strcmp(index, JPWL_PRIVATEINDEX_NAME)) { + return 0; + } +#endif /* USE_JPWL */ + /* <<UniPG */ + + if (!cstr_info) { + return 1; + } + + stream = fopen(index, "w"); + if (!stream) { + fprintf(stderr, "failed to open index file [%s] for writing\n", index); + return 1; + } + + if (cstr_info->tile[0].distotile) { + disto_on = 1; + } else { + disto_on = 0; + } + + if (cstr_info->tile[0].numpix) { + numpix_on = 1; + } else { + numpix_on = 0; + } + + fprintf(stream, "%d %d\n", cstr_info->image_w, cstr_info->image_h); + fprintf(stream, "%d\n", cstr_info->prog); + fprintf(stream, "%d %d\n", cstr_info->tile_x, cstr_info->tile_y); + fprintf(stream, "%d %d\n", cstr_info->tw, cstr_info->th); + fprintf(stream, "%d\n", cstr_info->numcomps); + fprintf(stream, "%d\n", cstr_info->numlayers); + fprintf(stream, "%d\n", cstr_info->numdecompos[0]); /* based on component 0 */ + + for (resno = cstr_info->numdecompos[0]; resno >= 0; resno--) { + fprintf(stream, "[%d,%d] ", + (1 << cstr_info->tile[0].pdx[resno]), + (1 << cstr_info->tile[0].pdx[resno])); /* based on tile 0 and component 0 */ + } + + fprintf(stream, "\n"); + /* UniPG>> */ + fprintf(stream, "%d\n", cstr_info->main_head_start); + /* <<UniPG */ + fprintf(stream, "%d\n", cstr_info->main_head_end); + fprintf(stream, "%d\n", cstr_info->codestream_size); + + fprintf(stream, "\nINFO ON TILES\n"); + fprintf(stream, "tileno start_pos end_hd end_tile nbparts"); + if (disto_on) { + fprintf(stream, " disto"); + } + if (numpix_on) { + fprintf(stream, " nbpix"); + } + if (disto_on && numpix_on) { + fprintf(stream, " disto/nbpix"); + } + fprintf(stream, "\n"); + + for (tileno = 0; tileno < cstr_info->tw * cstr_info->th; tileno++) { + fprintf(stream, "%4d %9d %9d %9d %9d", + cstr_info->tile[tileno].tileno, + cstr_info->tile[tileno].start_pos, + cstr_info->tile[tileno].end_header, + cstr_info->tile[tileno].end_pos, + cstr_info->tile[tileno].num_tps); + if (disto_on) { + fprintf(stream, " %9e", cstr_info->tile[tileno].distotile); + } + if (numpix_on) { + fprintf(stream, " %9d", cstr_info->tile[tileno].numpix); + } + if (disto_on && numpix_on) { + fprintf(stream, " %9e", cstr_info->tile[tileno].distotile / + cstr_info->tile[tileno].numpix); + } + fprintf(stream, "\n"); + } + + for (tileno = 0; tileno < cstr_info->tw * cstr_info->th; tileno++) { + int start_pos, end_ph_pos, end_pos; + double disto = 0; + int max_numdecompos = 0; + pack_nb = 0; + + for (compno = 0; compno < cstr_info->numcomps; compno++) { + if (max_numdecompos < cstr_info->numdecompos[compno]) { + max_numdecompos = cstr_info->numdecompos[compno]; + } + } + + fprintf(stream, "\nTILE %d DETAILS\n", tileno); + fprintf(stream, + "part_nb tileno start_pack num_packs start_pos end_tph_pos end_pos\n"); + for (tilepartno = 0; tilepartno < cstr_info->tile[tileno].num_tps; tilepartno++) + fprintf(stream, "%4d %9d %9d %9d %9d %11d %9d\n", + tilepartno, tileno, + cstr_info->tile[tileno].tp[tilepartno].tp_start_pack, + cstr_info->tile[tileno].tp[tilepartno].tp_numpacks, + cstr_info->tile[tileno].tp[tilepartno].tp_start_pos, + cstr_info->tile[tileno].tp[tilepartno].tp_end_header, + cstr_info->tile[tileno].tp[tilepartno].tp_end_pos + ); + + if (cstr_info->prog == LRCP) { /* LRCP */ + fprintf(stream, + "LRCP\npack_nb tileno layno resno compno precno start_pos end_ph_pos end_pos"); + if (disto_on) { + fprintf(stream, " disto"); + } + fprintf(stream, "\n"); + + for (layno = 0; layno < cstr_info->numlayers; layno++) { + for (resno = 0; resno < max_numdecompos + 1; resno++) { + for (compno = 0; compno < cstr_info->numcomps; compno++) { + int prec_max; + if (resno > cstr_info->numdecompos[compno]) { + break; + } + prec_max = cstr_info->tile[tileno].pw[resno] * + cstr_info->tile[tileno].ph[resno]; + for (precno = 0; precno < prec_max; precno++) { + start_pos = cstr_info->tile[tileno].packet[pack_nb].start_pos; + end_ph_pos = cstr_info->tile[tileno].packet[pack_nb].end_ph_pos; + end_pos = cstr_info->tile[tileno].packet[pack_nb].end_pos; + disto = cstr_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %7d %5d %6d %6d %6d %6d %7d", + pack_nb, tileno, layno, resno, compno, precno, start_pos, end_ph_pos, end_pos); + if (disto_on) { + fprintf(stream, " %8e", disto); + } + fprintf(stream, "\n"); + total_disto += disto; + pack_nb++; + } + } + } + } + } /* LRCP */ + + else if (cstr_info->prog == RLCP) { /* RLCP */ + fprintf(stream, + "RLCP\npack_nb tileno resno layno compno precno start_pos end_ph_pos end_pos\n"); + if (disto_on) { + fprintf(stream, " disto"); + } + fprintf(stream, "\n"); + + for (resno = 0; resno < max_numdecompos + 1; resno++) { + for (layno = 0; layno < cstr_info->numlayers; layno++) { + for (compno = 0; compno < cstr_info->numcomps; compno++) { + int prec_max; + if (resno > cstr_info->numdecompos[compno]) { + break; + } + prec_max = cstr_info->tile[tileno].pw[resno] * + cstr_info->tile[tileno].ph[resno]; + for (precno = 0; precno < prec_max; precno++) { + start_pos = cstr_info->tile[tileno].packet[pack_nb].start_pos; + end_ph_pos = cstr_info->tile[tileno].packet[pack_nb].end_ph_pos; + end_pos = cstr_info->tile[tileno].packet[pack_nb].end_pos; + disto = cstr_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %5d %7d %6d %6d %9d %9d %7d", + pack_nb, tileno, resno, layno, compno, precno, start_pos, end_ph_pos, end_pos); + if (disto_on) { + fprintf(stream, " %8e", disto); + } + fprintf(stream, "\n"); + total_disto += disto; + pack_nb++; + } + } + } + } + } /* RLCP */ + + else if (cstr_info->prog == RPCL) { /* RPCL */ + + fprintf(stream, + "RPCL\npack_nb tileno resno precno compno layno start_pos end_ph_pos end_pos"); + if (disto_on) { + fprintf(stream, " disto"); + } + fprintf(stream, "\n"); + + for (resno = 0; resno < max_numdecompos + 1; resno++) { + int numprec = cstr_info->tile[tileno].pw[resno] * + cstr_info->tile[tileno].ph[resno]; + for (precno = 0; precno < numprec; precno++) { + /* I suppose components have same XRsiz, YRsiz */ + int x0 = cstr_info->tile_Ox + tileno - (int)floor((float)tileno / + (float)cstr_info->tw) * cstr_info->tw * cstr_info->tile_x; + int y0 = cstr_info->tile_Ox + (int)floor((float)tileno / + (float)cstr_info->tw) * cstr_info->tile_y; + int x1 = x0 + cstr_info->tile_x; + int y1 = y0 + cstr_info->tile_y; + for (compno = 0; compno < cstr_info->numcomps; compno++) { + int pcnx = cstr_info->tile[tileno].pw[resno]; + int pcx = (int) pow(2, cstr_info->tile[tileno].pdx[resno] + + cstr_info->numdecompos[compno] - resno); + int pcy = (int) pow(2, cstr_info->tile[tileno].pdy[resno] + + cstr_info->numdecompos[compno] - resno); + int precno_x = precno - (int) floor((float)precno / (float)pcnx) * pcnx; + int precno_y = (int) floor((float)precno / (float)pcnx); + if (resno > cstr_info->numdecompos[compno]) { + break; + } + for (y = y0; y < y1; y++) { + if (precno_y * pcy == y) { + for (x = x0; x < x1; x++) { + if (precno_x * pcx == x) { + for (layno = 0; layno < cstr_info->numlayers; layno++) { + start_pos = cstr_info->tile[tileno].packet[pack_nb].start_pos; + end_ph_pos = cstr_info->tile[tileno].packet[pack_nb].end_ph_pos; + end_pos = cstr_info->tile[tileno].packet[pack_nb].end_pos; + disto = cstr_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %5d %6d %6d %7d %9d %9d %7d", + pack_nb, tileno, resno, precno, compno, layno, start_pos, end_ph_pos, end_pos); + if (disto_on) { + fprintf(stream, " %8e", disto); + } + fprintf(stream, "\n"); + total_disto += disto; + pack_nb++; + } + } + }/* x = x0..x1 */ + } + } /* y = y0..y1 */ + } /* precno */ + } /* compno */ + } /* resno */ + } /* RPCL */ + + else if (cstr_info->prog == PCRL) { /* PCRL */ + /* I suppose components have same XRsiz, YRsiz */ + int x0 = cstr_info->tile_Ox + tileno - (int)floor((float)tileno / + (float)cstr_info->tw) * cstr_info->tw * cstr_info->tile_x; + int y0 = cstr_info->tile_Ox + (int)floor((float)tileno / + (float)cstr_info->tw) * cstr_info->tile_y; + int x1 = x0 + cstr_info->tile_x; + int y1 = y0 + cstr_info->tile_y; + + /* Count the maximum number of precincts */ + int max_numprec = 0; + for (resno = 0; resno < max_numdecompos + 1; resno++) { + int numprec = cstr_info->tile[tileno].pw[resno] * + cstr_info->tile[tileno].ph[resno]; + if (numprec > max_numprec) { + max_numprec = numprec; + } + } + + fprintf(stream, + "PCRL\npack_nb tileno precno compno resno layno start_pos end_ph_pos end_pos"); + if (disto_on) { + fprintf(stream, " disto"); + } + fprintf(stream, "\n"); + + for (precno = 0; precno < max_numprec; precno++) { + for (compno = 0; compno < cstr_info->numcomps; compno++) { + for (resno = 0; resno < cstr_info->numdecompos[compno] + 1; resno++) { + int numprec = cstr_info->tile[tileno].pw[resno] * + cstr_info->tile[tileno].ph[resno]; + int pcnx = cstr_info->tile[tileno].pw[resno]; + int pcx = (int) pow(2, cstr_info->tile[tileno].pdx[resno] + + cstr_info->numdecompos[compno] - resno); + int pcy = (int) pow(2, cstr_info->tile[tileno].pdy[resno] + + cstr_info->numdecompos[compno] - resno); + int precno_x = precno - (int) floor((float)precno / (float)pcnx) * pcnx; + int precno_y = (int) floor((float)precno / (float)pcnx); + if (precno >= numprec) { + continue; + } + for (y = y0; y < y1; y++) { + if (precno_y * pcy == y) { + for (x = x0; x < x1; x++) { + if (precno_x * pcx == x) { + for (layno = 0; layno < cstr_info->numlayers; layno++) { + start_pos = cstr_info->tile[tileno].packet[pack_nb].start_pos; + end_ph_pos = cstr_info->tile[tileno].packet[pack_nb].end_ph_pos; + end_pos = cstr_info->tile[tileno].packet[pack_nb].end_pos; + disto = cstr_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %6d %6d %5d %7d %9d %9d %7d", + pack_nb, tileno, precno, compno, resno, layno, start_pos, end_ph_pos, end_pos); + if (disto_on) { + fprintf(stream, " %8e", disto); + } + fprintf(stream, "\n"); + total_disto += disto; + pack_nb++; + } + } + }/* x = x0..x1 */ + } + } /* y = y0..y1 */ + } /* resno */ + } /* compno */ + } /* precno */ + } /* PCRL */ + + else { /* CPRL */ + /* Count the maximum number of precincts */ + int max_numprec = 0; + for (resno = 0; resno < max_numdecompos + 1; resno++) { + int numprec = cstr_info->tile[tileno].pw[resno] * + cstr_info->tile[tileno].ph[resno]; + if (numprec > max_numprec) { + max_numprec = numprec; + } + } + + fprintf(stream, + "CPRL\npack_nb tileno compno precno resno layno start_pos end_ph_pos end_pos"); + if (disto_on) { + fprintf(stream, " disto"); + } + fprintf(stream, "\n"); + + for (compno = 0; compno < cstr_info->numcomps; compno++) { + /* I suppose components have same XRsiz, YRsiz */ + int x0 = cstr_info->tile_Ox + tileno - (int)floor((float)tileno / + (float)cstr_info->tw) * cstr_info->tw * cstr_info->tile_x; + int y0 = cstr_info->tile_Ox + (int)floor((float)tileno / + (float)cstr_info->tw) * cstr_info->tile_y; + int x1 = x0 + cstr_info->tile_x; + int y1 = y0 + cstr_info->tile_y; + + for (precno = 0; precno < max_numprec; precno++) { + for (resno = 0; resno < cstr_info->numdecompos[compno] + 1; resno++) { + int numprec = cstr_info->tile[tileno].pw[resno] * + cstr_info->tile[tileno].ph[resno]; + int pcnx = cstr_info->tile[tileno].pw[resno]; + int pcx = (int) pow(2, cstr_info->tile[tileno].pdx[resno] + + cstr_info->numdecompos[compno] - resno); + int pcy = (int) pow(2, cstr_info->tile[tileno].pdy[resno] + + cstr_info->numdecompos[compno] - resno); + int precno_x = precno - (int) floor((float)precno / (float)pcnx) * pcnx; + int precno_y = (int) floor((float)precno / (float)pcnx); + if (precno >= numprec) { + continue; + } + + for (y = y0; y < y1; y++) { + if (precno_y * pcy == y) { + for (x = x0; x < x1; x++) { + if (precno_x * pcx == x) { + for (layno = 0; layno < cstr_info->numlayers; layno++) { + start_pos = cstr_info->tile[tileno].packet[pack_nb].start_pos; + end_ph_pos = cstr_info->tile[tileno].packet[pack_nb].end_ph_pos; + end_pos = cstr_info->tile[tileno].packet[pack_nb].end_pos; + disto = cstr_info->tile[tileno].packet[pack_nb].disto; + fprintf(stream, "%4d %6d %6d %6d %5d %7d %9d %9d %7d", + pack_nb, tileno, compno, precno, resno, layno, start_pos, end_ph_pos, end_pos); + if (disto_on) { + fprintf(stream, " %8e", disto); + } + fprintf(stream, "\n"); + total_disto += disto; + pack_nb++; + } + } + }/* x = x0..x1 */ + } + } /* y = y0..y1 */ + } /* resno */ + } /* precno */ + } /* compno */ + } /* CPRL */ + } /* tileno */ + + if (disto_on) { + fprintf(stream, "%8e\n", cstr_info->D_max); /* SE max */ + fprintf(stream, "%.8e\n", total_disto); /* SE totale */ + } + /* UniPG>> */ + /* print the markers' list */ + if (cstr_info->marknum) { + fprintf(stream, "\nMARKER LIST\n"); + fprintf(stream, "%d\n", cstr_info->marknum); + fprintf(stream, "type\tstart_pos length\n"); + for (x = 0; x < cstr_info->marknum; x++) { + fprintf(stream, "%X\t%9d %9d\n", cstr_info->marker[x].type, + cstr_info->marker[x].pos, cstr_info->marker[x].len); + } + } + /* <<UniPG */ + fclose(stream); + + fprintf(stderr, "Generated index file %s\n", index); + + return 0; +} diff --git a/openjpeg/src/bin/jpwl/index.h b/openjpeg/src/bin/jpwl/index.h new file mode 100644 index 000000000..b461e91b1 --- /dev/null +++ b/openjpeg/src/bin/jpwl/index.h @@ -0,0 +1,54 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __J2K_INDEX_H +#define __J2K_INDEX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** +Write a structured index to a file +@param cstr_info Codestream information +@param index Index filename +@return Returns 0 if successful, returns 1 otherwise +*/ +int write_index_file(opj_codestream_info_t *cstr_info, char *index); + +#ifdef __cplusplus +} +#endif + +#endif /* __J2K_INDEX_H */ + diff --git a/openjpeg/src/bin/jpwl/opj_jpwl_compress.c b/openjpeg/src/bin/jpwl/opj_jpwl_compress.c new file mode 100644 index 000000000..28f0670c0 --- /dev/null +++ b/openjpeg/src/bin/jpwl/opj_jpwl_compress.c @@ -0,0 +1,1951 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * Copyright (c) 2003-2014, Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <math.h> + +#ifdef _WIN32 +#include "windirent.h" +#else +#include <dirent.h> +#endif /* _WIN32 */ + +#ifdef _WIN32 +#include <windows.h> +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#else +#include <strings.h> +#endif /* _WIN32 */ + +#include "opj_apps_config.h" +#include "openjpeg.h" +#include "opj_getopt.h" +#include "convert.h" +#include "index.h" + +#include "format_defs.h" + +#define CINEMA_24_CS 1302083 /*Codestream length for 24fps*/ +#define CINEMA_48_CS 651041 /*Codestream length for 48fps*/ +#define COMP_24_CS 1041666 /*Maximum size per color component for 2K & 4K @ 24fps*/ +#define COMP_48_CS 520833 /*Maximum size per color component for 2K @ 48fps*/ + +typedef struct dircnt { + /** Buffer for holding images read from Directory*/ + char *filename_buf; + /** Pointer to the buffer*/ + char **filename; +} dircnt_t; + +typedef struct img_folder { + /** The directory path of the folder containing input images*/ + char *imgdirpath; + /** Output format*/ + char *out_format; + /** Enable option*/ + char set_imgdir; + /** Enable Cod Format for output*/ + char set_out_format; + /** User specified rate stored in case of cinema option*/ + float *rates; +} img_fol_t; + +static void encode_help_display(void) +{ + fprintf(stdout, "HELP for opj_jpwl_compress\n----\n\n"); + fprintf(stdout, "- the -h option displays this help information on screen\n\n"); + + /* UniPG>> */ + fprintf(stdout, "List of parameters for the JPEG 2000 " +#ifdef USE_JPWL + "+ JPWL " +#endif /* USE_JPWL */ + "encoder:\n"); + /* <<UniPG */ + fprintf(stdout, "\n"); + fprintf(stdout, "REMARKS:\n"); + fprintf(stdout, "---------\n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "The markers written to the main_header are : SOC SIZ COD QCD COM.\n"); + fprintf(stdout, "COD and QCD never appear in the tile_header.\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "By default:\n"); + fprintf(stdout, "------------\n"); + fprintf(stdout, "\n"); + fprintf(stdout, " * Lossless\n"); + fprintf(stdout, " * 1 tile\n"); + fprintf(stdout, " * Size of precinct : 2^15 x 2^15 (means 1 precinct)\n"); + fprintf(stdout, " * Size of code-block : 64 x 64\n"); + fprintf(stdout, " * Number of resolutions: 6\n"); + fprintf(stdout, " * No SOP marker in the codestream\n"); + fprintf(stdout, " * No EPH marker in the codestream\n"); + fprintf(stdout, " * No sub-sampling in x or y direction\n"); + fprintf(stdout, " * No mode switch activated\n"); + fprintf(stdout, " * Progression order: LRCP\n"); + fprintf(stdout, " * No index file\n"); + fprintf(stdout, " * No ROI upshifted\n"); + fprintf(stdout, " * No offset of the origin of the image\n"); + fprintf(stdout, " * No offset of the origin of the tiles\n"); + fprintf(stdout, " * Reversible DWT 5-3\n"); + /* UniPG>> */ +#ifdef USE_JPWL + fprintf(stdout, " * No JPWL protection\n"); +#endif /* USE_JPWL */ + /* <<UniPG */ + fprintf(stdout, "\n"); + fprintf(stdout, "Parameters:\n"); + fprintf(stdout, "------------\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "Required Parameters (except with -h):\n"); + fprintf(stdout, "One of the two options -ImgDir or -i must be used\n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "-ImgDir : Image file Directory path (example ../Images) \n"); + fprintf(stdout, " When using this option -OutFor must be used\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "-OutFor \n"); + fprintf(stdout, " REQUIRED only if -ImgDir is used\n"); + fprintf(stdout, " Need to specify only format without filename <BMP> \n"); + fprintf(stdout, + " Currently accepts PBM, PGM, PPM, PNM, PAM, PGX, PNG, BMP, TIF, RAW and TGA formats\n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "-i : source file (-i source.pnm also *pbm, *.pgm, *.ppm, *.pam, *.pgx, *png, *.bmp, *.tif, *.raw, *.tga) \n"); + fprintf(stdout, " When using this option -o must be used\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "-o : destination file (-o dest.j2k or .jp2) \n"); + fprintf(stdout, "\n"); + fprintf(stdout, "Optional Parameters:\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "-h : display the help information \n "); + fprintf(stdout, "\n"); + fprintf(stdout, + "-cinema2K : Digital Cinema 2K profile compliant codestream for 2K resolution.(-cinema2k 24 or 48) \n"); + fprintf(stdout, + " Need to specify the frames per second for a 2K resolution. Only 24 or 48 fps is allowed\n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "-cinema4K : Digital Cinema 4K profile compliant codestream for 4K resolution \n"); + fprintf(stdout, " Frames per second not required. Default value is 24fps\n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "-r : different compression ratios for successive layers (-r 20,10,5)\n "); + fprintf(stdout, + " - The rate specified for each quality level is the desired \n"); + fprintf(stdout, " compression factor.\n"); + fprintf(stdout, " Example: -r 20,10,1 means quality 1: compress 20x, \n"); + fprintf(stdout, + " quality 2: compress 10x and quality 3: compress lossless\n"); + fprintf(stdout, "\n"); + fprintf(stdout, + " (options -r and -q cannot be used together)\n "); + fprintf(stdout, "\n"); + + fprintf(stdout, + "-q : different psnr for successive layers (-q 30,40,50) \n "); + + fprintf(stdout, + " (options -r and -q cannot be used together)\n "); + + fprintf(stdout, "\n"); + fprintf(stdout, "-n : number of resolutions (-n 3) \n"); + fprintf(stdout, "\n"); + fprintf(stdout, "-b : size of code block (-b 32,32) \n"); + fprintf(stdout, "\n"); + fprintf(stdout, "-c : size of precinct (-c 128,128) \n"); + fprintf(stdout, "\n"); + fprintf(stdout, "-t : size of tile (-t 512,512) \n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "-p : progression order (-p LRCP) [LRCP, RLCP, RPCL, PCRL, CPRL] \n"); + fprintf(stdout, "\n"); + fprintf(stdout, "-s : subsampling factor (-s 2,2) [-s X,Y] \n"); + fprintf(stdout, " Remark: subsampling bigger than 2 can produce error\n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "-POC : Progression order change (-POC T1=0,0,1,5,3,CPRL/T1=5,0,1,6,3,CPRL) \n"); + fprintf(stdout, " Example: T1=0,0,1,5,3,CPRL \n"); + fprintf(stdout, + " : Ttilenumber=Resolution num start,Component num start,Layer num end,Resolution num end,Component num end,Progression order\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "-SOP : write SOP marker before each packet \n"); + fprintf(stdout, "\n"); + fprintf(stdout, "-EPH : write EPH marker after each header packet \n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "-M : mode switch (-M 3) [1=BYPASS(LAZY) 2=RESET 4=RESTART(TERMALL)\n"); + fprintf(stdout, + " 8=VSC 16=ERTERM(SEGTERM) 32=SEGMARK(SEGSYM)] \n"); + fprintf(stdout, + " Indicate multiple modes by adding their values. \n"); + fprintf(stdout, + " ex: RESTART(4) + RESET(2) + SEGMARK(32) = -M 38\n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "-TP : divide packets of every tile into tile-parts (-TP R) [R, L, C]\n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "-x : create an index file *.Idx (-x index_name.Idx) \n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "-ROI : c=%%d,U=%%d : quantization indices upshifted \n"); + fprintf(stdout, " for component c=%%d [%%d = 0,1,2]\n"); + fprintf(stdout, + " with a value of U=%%d [0 <= %%d <= 37] (i.e. -ROI c=0,U=25) \n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "-d : offset of the origin of the image (-d 150,300) \n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "-T : offset of the origin of the tiles (-T 100,75) \n"); + fprintf(stdout, "\n"); + fprintf(stdout, "-I : use the irreversible DWT 9-7 (-I) \n"); + fprintf(stdout, "\n"); + fprintf(stdout, "-F : characteristics of the raw input image\n"); + fprintf(stdout, + " -F rawWidth,rawHeight,rawComp,rawBitDepth,s/u (Signed/Unsigned)\n"); + fprintf(stdout, + " Example: -i lena.raw -o lena.j2k -F 512,512,3,8,u\n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "-jpip : write jpip codestream index box in JP2 output file\n"); + fprintf(stdout, " NOTICE: currently supports only RPCL order\n"); + fprintf(stdout, "\n"); + /* UniPG>> */ +#ifdef USE_JPWL + fprintf(stdout, + "-W : adoption of JPWL (Part 11) capabilities (-W params)\n"); + fprintf(stdout, + " The parameters can be written and repeated in any order:\n"); + fprintf(stdout, + " [h<tilepart><=type>,s<tilepart><=method>,a=<addr>,...\n"); + fprintf(stdout, + " ...,z=<size>,g=<range>,p<tilepart:pack><=type>]\n"); + fprintf(stdout, "\n"); + fprintf(stdout, + " h selects the header error protection (EPB): 'type' can be\n"); + fprintf(stdout, + " [0=none 1,absent=predefined 16=CRC-16 32=CRC-32 37-128=RS]\n"); + fprintf(stdout, + " if 'tilepart' is absent, it is for main and tile headers\n"); + fprintf(stdout, + " if 'tilepart' is present, it applies from that tile\n"); + fprintf(stdout, + " onwards, up to the next h<> spec, or to the last tilepart\n"); + fprintf(stdout, " in the codestream (max. %d specs)\n", + JPWL_MAX_NO_TILESPECS); + fprintf(stdout, "\n"); + fprintf(stdout, + " p selects the packet error protection (EEP/UEP with EPBs)\n"); + fprintf(stdout, " to be applied to raw data: 'type' can be\n"); + fprintf(stdout, + " [0=none 1,absent=predefined 16=CRC-16 32=CRC-32 37-128=RS]\n"); + fprintf(stdout, + " if 'tilepart:pack' is absent, it is from tile 0, packet 0\n"); + fprintf(stdout, + " if 'tilepart:pack' is present, it applies from that tile\n"); + fprintf(stdout, + " and that packet onwards, up to the next packet spec\n"); + fprintf(stdout, + " or to the last packet in the last tilepart in the stream\n"); + fprintf(stdout, " (max. %d specs)\n", + JPWL_MAX_NO_PACKSPECS); + fprintf(stdout, "\n"); + fprintf(stdout, + " s enables sensitivity data insertion (ESD): 'method' can be\n"); + fprintf(stdout, + " [-1=NO ESD 0=RELATIVE ERROR 1=MSE 2=MSE REDUCTION 3=PSNR\n"); + fprintf(stdout, + " 4=PSNR INCREMENT 5=MAXERR 6=TSE 7=RESERVED]\n"); + fprintf(stdout, + " if 'tilepart' is absent, it is for main header only\n"); + fprintf(stdout, + " if 'tilepart' is present, it applies from that tile\n"); + fprintf(stdout, + " onwards, up to the next s<> spec, or to the last tilepart\n"); + fprintf(stdout, " in the codestream (max. %d specs)\n", + JPWL_MAX_NO_TILESPECS); + fprintf(stdout, "\n"); + fprintf(stdout, + " g determines the addressing mode: <range> can be\n"); + fprintf(stdout, " [0=PACKET 1=BYTE RANGE 2=PACKET RANGE]\n"); + fprintf(stdout, "\n"); + fprintf(stdout, + " a determines the size of data addressing: <addr> can be\n"); + fprintf(stdout, + " 2/4 bytes (small/large codestreams). If not set, auto-mode\n"); + fprintf(stdout, "\n"); + fprintf(stdout, + " z determines the size of sensitivity values: <size> can be\n"); + fprintf(stdout, + " 1/2 bytes, for the transformed pseudo-floating point value\n"); + fprintf(stdout, "\n"); + fprintf(stdout, " ex.:\n"); + fprintf(stdout, + " h,h0=64,h3=16,h5=32,p0=78,p0:24=56,p1,p3:0=0,p3:20=32,s=0,\n"); + fprintf(stdout, " s0=6,s3=-1,a=0,g=1,z=1\n"); + fprintf(stdout, " means\n"); + fprintf(stdout, + " predefined EPB in MH, rs(64,32) from TPH 0 to TPH 2,\n"); + fprintf(stdout, + " CRC-16 in TPH 3 and TPH 4, CRC-32 in remaining TPHs,\n"); + fprintf(stdout, + " UEP rs(78,32) for packets 0 to 23 of tile 0,\n"); + fprintf(stdout, + " UEP rs(56,32) for packs. 24 to the last of tilepart 0,\n"); + fprintf(stdout, + " UEP rs default for packets of tilepart 1,\n"); + fprintf(stdout, + " no UEP for packets 0 to 19 of tilepart 3,\n"); + fprintf(stdout, + " UEP CRC-32 for packs. 20 of tilepart 3 to last tilepart,\n"); + fprintf(stdout, " relative sensitivity ESD for MH,\n"); + fprintf(stdout, + " TSE ESD from TPH 0 to TPH 2, byte range with automatic\n"); + fprintf(stdout, + " size of addresses and 1 byte for each sensitivity value\n"); + fprintf(stdout, "\n"); + fprintf(stdout, " ex.:\n"); + fprintf(stdout, " h,s,p\n"); + fprintf(stdout, " means\n"); + fprintf(stdout, + " default protection to headers (MH and TPHs) as well as\n"); + fprintf(stdout, " data packets, one ESD in MH\n"); + fprintf(stdout, "\n"); + fprintf(stdout, + " N.B.: use the following recommendations when specifying\n"); + fprintf(stdout, " the JPWL parameters list\n"); + fprintf(stdout, + " - when you use UEP, always pair the 'p' option with 'h'\n"); + fprintf(stdout, " \n"); +#endif /* USE_JPWL */ + /* <<UniPG */ + fprintf(stdout, "IMPORTANT:\n"); + fprintf(stdout, "-----------\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "The index file has the structure below:\n"); + fprintf(stdout, "---------------------------------------\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "Image_height Image_width\n"); + fprintf(stdout, "progression order\n"); + fprintf(stdout, "Tiles_size_X Tiles_size_Y\n"); + fprintf(stdout, "Tiles_nb_X Tiles_nb_Y\n"); + fprintf(stdout, "Components_nb\n"); + fprintf(stdout, "Layers_nb\n"); + fprintf(stdout, "decomposition_levels\n"); + fprintf(stdout, "[Precincts_size_X_res_Nr Precincts_size_Y_res_Nr]...\n"); + fprintf(stdout, " [Precincts_size_X_res_0 Precincts_size_Y_res_0]\n"); + fprintf(stdout, "Main_header_start_position\n"); + fprintf(stdout, "Main_header_end_position\n"); + fprintf(stdout, "Codestream_size\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "INFO ON TILES\n"); + fprintf(stdout, + "tileno start_pos end_hd end_tile nbparts disto nbpix disto/nbpix\n"); + fprintf(stdout, + "Tile_0 start_pos end_Theader end_pos NumParts TotalDisto NumPix MaxMSE\n"); + fprintf(stdout, + "Tile_1 '' '' '' '' '' '' ''\n"); + fprintf(stdout, "...\n"); + fprintf(stdout, + "Tile_Nt '' '' '' '' '' '' ''\n"); + fprintf(stdout, "...\n"); + fprintf(stdout, "TILE 0 DETAILS\n"); + fprintf(stdout, "part_nb tileno num_packs start_pos end_tph_pos end_pos\n"); + fprintf(stdout, "...\n"); + fprintf(stdout, "Progression_string\n"); + fprintf(stdout, + "pack_nb tileno layno resno compno precno start_pos end_ph_pos end_pos disto\n"); + fprintf(stdout, + "Tpacket_0 Tile layer res. comp. prec. start_pos end_pos disto\n"); + fprintf(stdout, "...\n"); + fprintf(stdout, + "Tpacket_Np '' '' '' '' '' '' '' ''\n"); + + fprintf(stdout, "MaxDisto\n"); + + fprintf(stdout, "TotalDisto\n\n"); +} + +static OPJ_PROG_ORDER give_progression(const char progression[4]) +{ + if (strncmp(progression, "LRCP", 4) == 0) { + return LRCP; + } + if (strncmp(progression, "RLCP", 4) == 0) { + return RLCP; + } + if (strncmp(progression, "RPCL", 4) == 0) { + return RPCL; + } + if (strncmp(progression, "PCRL", 4) == 0) { + return PCRL; + } + if (strncmp(progression, "CPRL", 4) == 0) { + return CPRL; + } + + return PROG_UNKNOWN; +} + +static unsigned int get_num_images(char *imgdirpath) +{ + DIR *dir; + struct dirent* content; + unsigned int num_images = 0; + + /*Reading the input images from given input directory*/ + + dir = opendir(imgdirpath); + if (!dir) { + fprintf(stderr, "Could not open Folder %s\n", imgdirpath); + return 0; + } + + num_images = 0; + while ((content = readdir(dir)) != NULL) { + if (strcmp(".", content->d_name) == 0 || strcmp("..", content->d_name) == 0) { + continue; + } + num_images++; + } + return num_images; +} + +static int load_images(dircnt_t *dirptr, char *imgdirpath) +{ + DIR *dir; + struct dirent* content; + int i = 0; + + /*Reading the input images from given input directory*/ + + dir = opendir(imgdirpath); + if (!dir) { + fprintf(stderr, "Could not open Folder %s\n", imgdirpath); + return 1; + } else { + fprintf(stderr, "Folder opened successfully\n"); + } + + while ((content = readdir(dir)) != NULL) { + if (strcmp(".", content->d_name) == 0 || strcmp("..", content->d_name) == 0) { + continue; + } + + strcpy(dirptr->filename[i], content->d_name); + i++; + } + return 0; +} + +static int get_file_format(char *filename) +{ + unsigned int i; + static const char *extension[] = { + "pgx", "pnm", "pgm", "ppm", "pbm", "pam", "bmp", "tif", "raw", "tga", "png", "j2k", "jp2", "j2c", "jpc" + }; + static const int format[] = { + PGX_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, BMP_DFMT, TIF_DFMT, RAW_DFMT, TGA_DFMT, PNG_DFMT, J2K_CFMT, JP2_CFMT, J2K_CFMT, J2K_CFMT + }; + char * ext = strrchr(filename, '.'); + if (ext == NULL) { + return -1; + } + ext++; + for (i = 0; i < sizeof(format) / sizeof(*format); i++) { + if (strcasecmp(ext, extension[i]) == 0) { + return format[i]; + } + } + return -1; +} + +static char * get_file_name(char *name) +{ + char *fname; + fname = (char*)malloc(OPJ_PATH_LEN * sizeof(char)); + fname = strtok(name, "."); + return fname; +} + +static char get_next_file(int imageno, dircnt_t *dirptr, img_fol_t *img_fol, + opj_cparameters_t *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 = get_file_format(image_filename); + if (parameters->decod_format == -1) { + return 1; + } + sprintf(infilename, "%s/%s", img_fol->imgdirpath, image_filename); + strncpy(parameters->infile, infilename, sizeof(infilename)); + + /*Set output file*/ + strcpy(temp_ofname, get_file_name(image_filename)); + while ((temp_p = strtok(NULL, ".")) != NULL) { + strcat(temp_ofname, temp1); + sprintf(temp1, ".%s", temp_p); + } + 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)); + } + return 0; +} + +static int initialise_4K_poc(opj_poc_t *POC, int numres) +{ + POC[0].tile = 1; + POC[0].resno0 = 0; + POC[0].compno0 = 0; + POC[0].layno1 = 1; + POC[0].resno1 = numres - 1; + POC[0].compno1 = 3; + POC[0].prg1 = CPRL; + POC[1].tile = 1; + POC[1].resno0 = numres - 1; + POC[1].compno0 = 0; + POC[1].layno1 = 1; + POC[1].resno1 = numres; + POC[1].compno1 = 3; + POC[1].prg1 = CPRL; + return 2; +} + +static void cinema_parameters(opj_cparameters_t *parameters) +{ + parameters->tile_size_on = OPJ_FALSE; + parameters->cp_tdx = 1; + parameters->cp_tdy = 1; + + /*Tile part*/ + parameters->tp_flag = 'C'; + parameters->tp_on = 1; + + /*Tile and Image shall be at (0,0)*/ + parameters->cp_tx0 = 0; + parameters->cp_ty0 = 0; + parameters->image_offset_x0 = 0; + parameters->image_offset_y0 = 0; + + /*Codeblock size= 32*32*/ + parameters->cblockw_init = 32; + parameters->cblockh_init = 32; + parameters->csty |= 0x01; + + /*The progression order shall be CPRL*/ + parameters->prog_order = CPRL; + + /* No ROI */ + parameters->roi_compno = -1; + + parameters->subsampling_dx = 1; + parameters->subsampling_dy = 1; + + /* 9-7 transform */ + parameters->irreversible = 1; + +} + +static void cinema_setup_encoder(opj_cparameters_t *parameters, + opj_image_t *image, img_fol_t *img_fol) +{ + int i; + float temp_rate; + + switch (parameters->cp_cinema) { + case CINEMA2K_24: + case CINEMA2K_48: + if (parameters->numresolution > 6) { + parameters->numresolution = 6; + } + if (!((image->comps[0].w == 2048) | (image->comps[0].h == 1080))) { + fprintf(stdout, + "Image coordinates %d x %d is not 2K compliant.\nJPEG Digital Cinema Profile-3 " + "(2K profile) compliance requires that at least one of coordinates match 2048 x 1080\n", + image->comps[0].w, image->comps[0].h); + parameters->cp_rsiz = STD_RSIZ; + } + break; + + case CINEMA4K_24: + if (parameters->numresolution < 1) { + parameters->numresolution = 1; + } else if (parameters->numresolution > 7) { + parameters->numresolution = 7; + } + if (!((image->comps[0].w == 4096) | (image->comps[0].h == 2160))) { + fprintf(stdout, + "Image coordinates %d x %d is not 4K compliant.\nJPEG Digital Cinema Profile-4" + "(4K profile) compliance requires that at least one of coordinates match 4096 x 2160\n", + image->comps[0].w, image->comps[0].h); + parameters->cp_rsiz = STD_RSIZ; + } + parameters->numpocs = initialise_4K_poc(parameters->POC, + parameters->numresolution); + break; + default : + break; + } + + switch (parameters->cp_cinema) { + case CINEMA2K_24: + case CINEMA4K_24: + for (i = 0 ; i < parameters->tcp_numlayers ; i++) { + temp_rate = 0 ; + if (img_fol->rates[i] == 0) { + parameters->tcp_rates[0] = ((float)(image->numcomps * image->comps[0].w * + image->comps[0].h * image->comps[0].prec)) / + (CINEMA_24_CS * 8 * image->comps[0].dx * image->comps[0].dy); + } else { + temp_rate = ((float)(image->numcomps * image->comps[0].w * image->comps[0].h * + image->comps[0].prec)) / + (img_fol->rates[i] * 8 * image->comps[0].dx * image->comps[0].dy); + if (temp_rate > CINEMA_24_CS) { + parameters->tcp_rates[i] = ((float)(image->numcomps * image->comps[0].w * + image->comps[0].h * image->comps[0].prec)) / + (CINEMA_24_CS * 8 * image->comps[0].dx * image->comps[0].dy); + } else { + parameters->tcp_rates[i] = img_fol->rates[i]; + } + } + } + parameters->max_comp_size = COMP_24_CS; + break; + + case CINEMA2K_48: + for (i = 0 ; i < parameters->tcp_numlayers ; i++) { + temp_rate = 0 ; + if (img_fol->rates[i] == 0) { + parameters->tcp_rates[0] = ((float)(image->numcomps * image->comps[0].w * + image->comps[0].h * image->comps[0].prec)) / + (CINEMA_48_CS * 8 * image->comps[0].dx * image->comps[0].dy); + } else { + temp_rate = ((float)(image->numcomps * image->comps[0].w * image->comps[0].h * + image->comps[0].prec)) / + (img_fol->rates[i] * 8 * image->comps[0].dx * image->comps[0].dy); + if (temp_rate > CINEMA_48_CS) { + parameters->tcp_rates[0] = ((float)(image->numcomps * image->comps[0].w * + image->comps[0].h * image->comps[0].prec)) / + (CINEMA_48_CS * 8 * image->comps[0].dx * image->comps[0].dy); + } else { + parameters->tcp_rates[i] = img_fol->rates[i]; + } + } + } + parameters->max_comp_size = COMP_48_CS; + break; + default: + break; + } + parameters->cp_disto_alloc = 1; +} + +/* ------------------------------------------------------------------------------------ */ + +static int parse_cmdline_encoder(int argc, char **argv, + opj_cparameters_t *parameters, + img_fol_t *img_fol, raw_cparameters_t *raw_cp, char *indexfilename) +{ + int i, j, totlen, c; + opj_option_t long_option[] = { + {"cinema2K", REQ_ARG, NULL, 'w'}, + {"cinema4K", NO_ARG, NULL, 'y'}, + {"ImgDir", REQ_ARG, NULL, 'z'}, + {"TP", REQ_ARG, NULL, 'u'}, + {"SOP", NO_ARG, NULL, 'S'}, + {"EPH", NO_ARG, NULL, 'E'}, + {"OutFor", REQ_ARG, NULL, 'O'}, + {"POC", REQ_ARG, NULL, 'P'}, + {"ROI", REQ_ARG, NULL, 'R'}, + {"jpip", NO_ARG, NULL, 'J'} + }; + + /* parse the command line */ + const char optlist[] = "i:o:r:q:n:b:c:t:p:s:SEM:x:R:d:T:If:P:C:F:u:J" +#ifdef USE_JPWL + "W:" +#endif /* USE_JPWL */ + "h"; + + totlen = sizeof(long_option); + img_fol->set_out_format = 0; + raw_cp->rawWidth = 0; + + do { + c = opj_getopt_long(argc, argv, optlist, long_option, totlen); + if (c == -1) { + break; + } + switch (c) { + case 'i': { /* input file */ + char *infile = opj_optarg; + parameters->decod_format = get_file_format(infile); + switch (parameters->decod_format) { + case PGX_DFMT: + case PXM_DFMT: + case BMP_DFMT: + case TIF_DFMT: + case RAW_DFMT: + case TGA_DFMT: + case PNG_DFMT: + break; + default: + fprintf(stderr, + "!! Unrecognized format for infile : %s " + "[accept only *.pnm, *.pgm, *.ppm, *.pgx, *png, *.bmp, *.tif, *.raw or *.tga] !!\n\n", + infile); + return 1; + } + strncpy(parameters->infile, infile, sizeof(parameters->infile) - 1); + } + break; + + /* ----------------------------------------------------- */ + + case 'o': { /* output file */ + char *outfile = opj_optarg; + parameters->cod_format = get_file_format(outfile); + switch (parameters->cod_format) { + case J2K_CFMT: + case JP2_CFMT: + break; + default: + fprintf(stderr, + "Unknown output format image %s [only *.j2k, *.j2c or *.jp2]!! \n", outfile); + return 1; + } + strncpy(parameters->outfile, outfile, sizeof(parameters->outfile) - 1); + } + break; + + /* ----------------------------------------------------- */ + case 'O': { /* output format */ + char outformat[50]; + char *of = opj_optarg; + sprintf(outformat, ".%s", of); + img_fol->set_out_format = 1; + parameters->cod_format = get_file_format(outformat); + switch (parameters->cod_format) { + case J2K_CFMT: + case JP2_CFMT: + img_fol->out_format = opj_optarg; + break; + default: + fprintf(stderr, "Unknown output format image [only j2k, j2c, jp2]!! \n"); + return 1; + } + } + break; + + + /* ----------------------------------------------------- */ + + + case 'r': { /* rates rates/distorsion */ + char *s = opj_optarg; + parameters->tcp_numlayers = 0; + while (sscanf(s, "%f", ¶meters->tcp_rates[parameters->tcp_numlayers]) == + 1) { + parameters->tcp_numlayers++; + while (*s && *s != ',') { + s++; + } + if (!*s) { + break; + } + s++; + } + parameters->cp_disto_alloc = 1; + } + break; + + /* ----------------------------------------------------- */ + + + case 'F': { /* Raw image format parameters */ + char signo; + char *s = opj_optarg; + if (sscanf(s, "%d,%d,%d,%d,%c", &raw_cp->rawWidth, &raw_cp->rawHeight, + &raw_cp->rawComp, &raw_cp->rawBitDepth, &signo) == 5) { + if (signo == 's') { + raw_cp->rawSigned = OPJ_TRUE; + fprintf(stdout, "\nRaw file parameters: %d,%d,%d,%d Signed\n", raw_cp->rawWidth, + raw_cp->rawHeight, raw_cp->rawComp, raw_cp->rawBitDepth); + } else if (signo == 'u') { + raw_cp->rawSigned = OPJ_FALSE; + fprintf(stdout, "\nRaw file parameters: %d,%d,%d,%d Unsigned\n", + raw_cp->rawWidth, raw_cp->rawHeight, raw_cp->rawComp, raw_cp->rawBitDepth); + } else { + fprintf(stderr, + "\nError: invalid raw image parameters: Unknown sign of raw file\n"); + fprintf(stderr, "Please use the Format option -F:\n"); + fprintf(stderr, + "-F rawWidth,rawHeight,rawComp,rawBitDepth,s/u (Signed/Unsigned)\n"); + fprintf(stderr, "Example: -i lena.raw -o lena.j2k -F 512,512,3,8,u\n"); + fprintf(stderr, "Aborting\n"); + } + } else { + fprintf(stderr, "\nError: invalid raw image parameters\n"); + fprintf(stderr, "Please use the Format option -F:\n"); + fprintf(stderr, + "-F rawWidth,rawHeight,rawComp,rawBitDepth,s/u (Signed/Unsigned)\n"); + fprintf(stderr, "Example: -i lena.raw -o lena.j2k -F 512,512,3,8,u\n"); + fprintf(stderr, "Aborting\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 'q': { /* add fixed_quality */ + char *s = opj_optarg; + while (sscanf(s, "%f", ¶meters->tcp_distoratio[parameters->tcp_numlayers]) + == 1) { + parameters->tcp_numlayers++; + while (*s && *s != ',') { + s++; + } + if (!*s) { + break; + } + s++; + } + parameters->cp_fixed_quality = 1; + } + break; + + /* dda */ + /* ----------------------------------------------------- */ + + case 'f': { /* mod fixed_quality (before : -q) */ + int *row = NULL, *col = NULL; + int numlayers = 0, numresolution = 0, matrix_width = 0; + + char *s = opj_optarg; + sscanf(s, "%d", &numlayers); + s++; + if (numlayers > 9) { + s++; + } + + parameters->tcp_numlayers = numlayers; + numresolution = parameters->numresolution; + matrix_width = numresolution * 3; + parameters->cp_matrice = (int *) malloc(numlayers * matrix_width * sizeof(int)); + s = s + 2; + + for (i = 0; i < numlayers; i++) { + row = ¶meters->cp_matrice[i * matrix_width]; + col = row; + parameters->tcp_rates[i] = 1; + sscanf(s, "%d,", &col[0]); + s += 2; + if (col[0] > 9) { + s++; + } + col[1] = 0; + col[2] = 0; + for (j = 1; j < numresolution; j++) { + col += 3; + sscanf(s, "%d,%d,%d", &col[0], &col[1], &col[2]); + s += 6; + if (col[0] > 9) { + s++; + } + if (col[1] > 9) { + s++; + } + if (col[2] > 9) { + s++; + } + } + if (i < numlayers - 1) { + s++; + } + } + parameters->cp_fixed_alloc = 1; + } + break; + + /* ----------------------------------------------------- */ + + case 't': { /* tiles */ + sscanf(opj_optarg, "%d,%d", ¶meters->cp_tdx, ¶meters->cp_tdy); + parameters->tile_size_on = OPJ_TRUE; + } + break; + + /* ----------------------------------------------------- */ + + case 'n': { /* resolution */ + sscanf(opj_optarg, "%d", ¶meters->numresolution); + } + break; + + /* ----------------------------------------------------- */ + case 'c': { /* precinct dimension */ + char sep; + int res_spec = 0; + + char *s = opj_optarg; + do { + sep = 0; + sscanf(s, "[%d,%d]%c", ¶meters->prcw_init[res_spec], + ¶meters->prch_init[res_spec], &sep); + parameters->csty |= 0x01; + res_spec++; + s = strpbrk(s, "]") + 2; + } while (sep == ','); + parameters->res_spec = res_spec; + } + break; + + /* ----------------------------------------------------- */ + + case 'b': { /* code-block dimension */ + int cblockw_init = 0, cblockh_init = 0; + sscanf(opj_optarg, "%d,%d", &cblockw_init, &cblockh_init); + if (cblockw_init * cblockh_init > 4096 || cblockw_init > 1024 + || cblockw_init < 4 || cblockh_init > 1024 || cblockh_init < 4) { + fprintf(stderr, + "!! Size of code_block error (option -b) !!\n\nRestriction :\n" + " * width*height<=4096\n * 4<=width,height<= 1024\n\n"); + return 1; + } + parameters->cblockw_init = cblockw_init; + parameters->cblockh_init = cblockh_init; + } + break; + + /* ----------------------------------------------------- */ + + case 'x': { /* creation of index file */ + char *index = opj_optarg; + strncpy(indexfilename, index, OPJ_PATH_LEN); + } + break; + + /* ----------------------------------------------------- */ + + case 'p': { /* progression order */ + char progression[4]; + + strncpy(progression, opj_optarg, 4); + parameters->prog_order = give_progression(progression); + if (parameters->prog_order == -1) { + fprintf(stderr, "Unrecognized progression order " + "[LRCP, RLCP, RPCL, PCRL, CPRL] !!\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 's': { /* subsampling factor */ + if (sscanf(opj_optarg, "%d,%d", ¶meters->subsampling_dx, + ¶meters->subsampling_dy) != 2) { + fprintf(stderr, "'-s' sub-sampling argument error ! [-s dx,dy]\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 'd': { /* coordonnate of the reference grid */ + if (sscanf(opj_optarg, "%d,%d", ¶meters->image_offset_x0, + ¶meters->image_offset_y0) != 2) { + fprintf(stderr, "-d 'coordonnate of the reference grid' argument " + "error !! [-d x0,y0]\n"); + return 1; + } + } + break; + + /* ----------------------------------------------------- */ + + case 'h': /* display an help description */ + encode_help_display(); + return 1; + + /* ----------------------------------------------------- */ + + case 'P': { /* POC */ + int numpocs = 0; /* number of progression order change (POC) default 0 */ + opj_poc_t *POC = NULL; /* POC : used in case of Progression order change */ + + char *s = opj_optarg; + POC = parameters->POC; + + while (sscanf(s, "T%d=%d,%d,%d,%d,%d,%4s", &POC[numpocs].tile, + &POC[numpocs].resno0, &POC[numpocs].compno0, + &POC[numpocs].layno1, &POC[numpocs].resno1, + &POC[numpocs].compno1, POC[numpocs].progorder) == 7) { + POC[numpocs].prg1 = give_progression(POC[numpocs].progorder); + numpocs++; + while (*s && *s != '/') { + s++; + } + if (!*s) { + break; + } + s++; + } + parameters->numpocs = numpocs; + } + break; + + /* ------------------------------------------------------ */ + + case 'S': { /* SOP marker */ + parameters->csty |= 0x02; + } + break; + + /* ------------------------------------------------------ */ + + case 'E': { /* EPH marker */ + parameters->csty |= 0x04; + } + break; + + /* ------------------------------------------------------ */ + + case 'M': { /* Mode switch pas tous au point !! */ + int value = 0; + if (sscanf(opj_optarg, "%d", &value) == 1) { + for (i = 0; i <= 5; i++) { + int cache = value & (1 << i); + if (cache) { + parameters->mode |= (1 << i); + } + } + } + } + break; + + /* ------------------------------------------------------ */ + + case 'R': { /* ROI */ + if (sscanf(opj_optarg, "c=%d,U=%d", ¶meters->roi_compno, + ¶meters->roi_shift) != 2) { + fprintf(stderr, "ROI error !! [-ROI c='compno',U='shift']\n"); + return 1; + } + } + break; + + /* ------------------------------------------------------ */ + + case 'T': { /* Tile offset */ + if (sscanf(opj_optarg, "%d,%d", ¶meters->cp_tx0, + ¶meters->cp_ty0) != 2) { + fprintf(stderr, "-T 'tile offset' argument error !! [-T X0,Y0]"); + return 1; + } + } + break; + + /* ------------------------------------------------------ */ + + case 'C': { /* add a comment */ + parameters->cp_comment = (char*)malloc(strlen(opj_optarg) + 1); + if (parameters->cp_comment) { + strcpy(parameters->cp_comment, opj_optarg); + } + } + break; + + + /* ------------------------------------------------------ */ + + case 'I': { /* reversible or not */ + parameters->irreversible = 1; + } + break; + + /* ------------------------------------------------------ */ + + case 'u': { /* Tile part generation*/ + parameters->tp_flag = opj_optarg[0]; + parameters->tp_on = 1; + } + break; + + /* ------------------------------------------------------ */ + + case 'z': { /* Image Directory path */ + img_fol->imgdirpath = (char*)malloc(strlen(opj_optarg) + 1); + strcpy(img_fol->imgdirpath, opj_optarg); + img_fol->set_imgdir = 1; + } + break; + + /* ------------------------------------------------------ */ + + case 'w': { /* Digital Cinema 2K profile compliance*/ + int fps = 0; + sscanf(opj_optarg, "%d", &fps); + if (fps == 24) { + parameters->cp_cinema = CINEMA2K_24; + } else if (fps == 48) { + parameters->cp_cinema = CINEMA2K_48; + } else { + fprintf(stderr, "Incorrect value!! must be 24 or 48\n"); + return 1; + } + fprintf(stdout, "CINEMA 2K compliant codestream\n"); + parameters->cp_rsiz = CINEMA2K; + + } + break; + + /* ------------------------------------------------------ */ + + case 'y': { /* Digital Cinema 4K profile compliance*/ + parameters->cp_cinema = CINEMA4K_24; + fprintf(stdout, "CINEMA 4K compliant codestream\n"); + parameters->cp_rsiz = CINEMA4K; + } + break; + + /* ------------------------------------------------------ */ + + /* UniPG>> */ +#ifdef USE_JPWL + /* ------------------------------------------------------ */ + + case 'W': { /* JPWL capabilities switched on */ + char *token = NULL; + int hprot, pprot, sens, addr, size, range; + + /* we need to enable indexing */ + if (!indexfilename || !*indexfilename) { + strncpy(indexfilename, JPWL_PRIVATEINDEX_NAME, OPJ_PATH_LEN); + } + + /* search for different protection methods */ + + /* break the option in comma points and parse the result */ + token = strtok(opj_optarg, ","); + while (token != NULL) { + + /* search header error protection method */ + if (*token == 'h') { + + static int tile = 0, tilespec = 0, lasttileno = 0; + + hprot = 1; /* predefined method */ + + if (sscanf(token, "h=%d", &hprot) == 1) { + /* Main header, specified */ + if (!((hprot == 0) || (hprot == 1) || (hprot == 16) || (hprot == 32) || + ((hprot >= 37) && (hprot <= 128)))) { + fprintf(stderr, "ERROR -> invalid main header protection method h = %d\n", + hprot); + return 1; + } + parameters->jpwl_hprot_MH = hprot; + + } else if (sscanf(token, "h%d=%d", &tile, &hprot) == 2) { + /* Tile part header, specified */ + if (!((hprot == 0) || (hprot == 1) || (hprot == 16) || (hprot == 32) || + ((hprot >= 37) && (hprot <= 128)))) { + fprintf(stderr, "ERROR -> invalid tile part header protection method h = %d\n", + hprot); + return 1; + } + if (tile < 0) { + fprintf(stderr, + "ERROR -> invalid tile part number on protection method t = %d\n", tile); + return 1; + } + if (tilespec < JPWL_MAX_NO_TILESPECS) { + parameters->jpwl_hprot_TPH_tileno[tilespec] = lasttileno = tile; + parameters->jpwl_hprot_TPH[tilespec++] = hprot; + } + + } else if (sscanf(token, "h%d", &tile) == 1) { + /* Tile part header, unspecified */ + if (tile < 0) { + fprintf(stderr, + "ERROR -> invalid tile part number on protection method t = %d\n", tile); + return 1; + } + if (tilespec < JPWL_MAX_NO_TILESPECS) { + parameters->jpwl_hprot_TPH_tileno[tilespec] = lasttileno = tile; + parameters->jpwl_hprot_TPH[tilespec++] = hprot; + } + + + } else if (!strcmp(token, "h")) { + /* Main header, unspecified */ + parameters->jpwl_hprot_MH = hprot; + + } else { + fprintf(stderr, "ERROR -> invalid protection method selection = %s\n", token); + return 1; + }; + + } + + /* search packet error protection method */ + if (*token == 'p') { + + static int pack = 0, tile = 0, packspec = 0; + + pprot = 1; /* predefined method */ + + if (sscanf(token, "p=%d", &pprot) == 1) { + /* Method for all tiles and all packets */ + if (!((pprot == 0) || (pprot == 1) || (pprot == 16) || (pprot == 32) || + ((pprot >= 37) && (pprot <= 128)))) { + fprintf(stderr, "ERROR -> invalid default packet protection method p = %d\n", + pprot); + return 1; + } + parameters->jpwl_pprot_tileno[0] = 0; + parameters->jpwl_pprot_packno[0] = 0; + parameters->jpwl_pprot[0] = pprot; + + } else if (sscanf(token, "p%d=%d", &tile, &pprot) == 2) { + /* method specified from that tile on */ + if (!((pprot == 0) || (pprot == 1) || (pprot == 16) || (pprot == 32) || + ((pprot >= 37) && (pprot <= 128)))) { + fprintf(stderr, "ERROR -> invalid packet protection method p = %d\n", pprot); + return 1; + } + if (tile < 0) { + fprintf(stderr, + "ERROR -> invalid tile part number on protection method p = %d\n", tile); + return 1; + } + if (packspec < JPWL_MAX_NO_PACKSPECS) { + parameters->jpwl_pprot_tileno[packspec] = tile; + parameters->jpwl_pprot_packno[packspec] = 0; + parameters->jpwl_pprot[packspec++] = pprot; + } + + } else if (sscanf(token, "p%d:%d=%d", &tile, &pack, &pprot) == 3) { + /* method fully specified from that tile and that packet on */ + if (!((pprot == 0) || (pprot == 1) || (pprot == 16) || (pprot == 32) || + ((pprot >= 37) && (pprot <= 128)))) { + fprintf(stderr, "ERROR -> invalid packet protection method p = %d\n", pprot); + return 1; + } + if (tile < 0) { + fprintf(stderr, + "ERROR -> invalid tile part number on protection method p = %d\n", tile); + return 1; + } + if (pack < 0) { + fprintf(stderr, "ERROR -> invalid packet number on protection method p = %d\n", + pack); + return 1; + } + if (packspec < JPWL_MAX_NO_PACKSPECS) { + parameters->jpwl_pprot_tileno[packspec] = tile; + parameters->jpwl_pprot_packno[packspec] = pack; + parameters->jpwl_pprot[packspec++] = pprot; + } + + } else if (sscanf(token, "p%d:%d", &tile, &pack) == 2) { + /* default method from that tile and that packet on */ + if (!((pprot == 0) || (pprot == 1) || (pprot == 16) || (pprot == 32) || + ((pprot >= 37) && (pprot <= 128)))) { + fprintf(stderr, "ERROR -> invalid packet protection method p = %d\n", pprot); + return 1; + } + if (tile < 0) { + fprintf(stderr, + "ERROR -> invalid tile part number on protection method p = %d\n", tile); + return 1; + } + if (pack < 0) { + fprintf(stderr, "ERROR -> invalid packet number on protection method p = %d\n", + pack); + return 1; + } + if (packspec < JPWL_MAX_NO_PACKSPECS) { + parameters->jpwl_pprot_tileno[packspec] = tile; + parameters->jpwl_pprot_packno[packspec] = pack; + parameters->jpwl_pprot[packspec++] = pprot; + } + + } else if (sscanf(token, "p%d", &tile) == 1) { + /* default from a tile on */ + if (tile < 0) { + fprintf(stderr, + "ERROR -> invalid tile part number on protection method p = %d\n", tile); + return 1; + } + if (packspec < JPWL_MAX_NO_PACKSPECS) { + parameters->jpwl_pprot_tileno[packspec] = tile; + parameters->jpwl_pprot_packno[packspec] = 0; + parameters->jpwl_pprot[packspec++] = pprot; + } + + + } else if (!strcmp(token, "p")) { + /* all default */ + parameters->jpwl_pprot_tileno[0] = 0; + parameters->jpwl_pprot_packno[0] = 0; + parameters->jpwl_pprot[0] = pprot; + + } else { + fprintf(stderr, "ERROR -> invalid protection method selection = %s\n", token); + return 1; + }; + + } + + /* search sensitivity method */ + if (*token == 's') { + + static int tile = 0, tilespec = 0, lasttileno = 0; + + sens = 0; /* predefined: relative error */ + + if (sscanf(token, "s=%d", &sens) == 1) { + /* Main header, specified */ + if ((sens < -1) || (sens > 7)) { + fprintf(stderr, "ERROR -> invalid main header sensitivity method s = %d\n", + sens); + return 1; + } + parameters->jpwl_sens_MH = sens; + + } else if (sscanf(token, "s%d=%d", &tile, &sens) == 2) { + /* Tile part header, specified */ + if ((sens < -1) || (sens > 7)) { + fprintf(stderr, "ERROR -> invalid tile part header sensitivity method s = %d\n", + sens); + return 1; + } + if (tile < 0) { + fprintf(stderr, + "ERROR -> invalid tile part number on sensitivity method t = %d\n", tile); + return 1; + } + if (tilespec < JPWL_MAX_NO_TILESPECS) { + parameters->jpwl_sens_TPH_tileno[tilespec] = lasttileno = tile; + parameters->jpwl_sens_TPH[tilespec++] = sens; + } + + } else if (sscanf(token, "s%d", &tile) == 1) { + /* Tile part header, unspecified */ + if (tile < 0) { + fprintf(stderr, + "ERROR -> invalid tile part number on sensitivity method t = %d\n", tile); + return 1; + } + if (tilespec < JPWL_MAX_NO_TILESPECS) { + parameters->jpwl_sens_TPH_tileno[tilespec] = lasttileno = tile; + parameters->jpwl_sens_TPH[tilespec++] = hprot; + } + + } else if (!strcmp(token, "s")) { + /* Main header, unspecified */ + parameters->jpwl_sens_MH = sens; + + } else { + fprintf(stderr, "ERROR -> invalid sensitivity method selection = %s\n", token); + return 1; + }; + + parameters->jpwl_sens_size = 2; /* 2 bytes for default size */ + } + + /* search addressing size */ + if (*token == 'a') { + + + addr = 0; /* predefined: auto */ + + if (sscanf(token, "a=%d", &addr) == 1) { + /* Specified */ + if ((addr != 0) && (addr != 2) && (addr != 4)) { + fprintf(stderr, "ERROR -> invalid addressing size a = %d\n", addr); + return 1; + } + parameters->jpwl_sens_addr = addr; + + } else if (!strcmp(token, "a")) { + /* default */ + parameters->jpwl_sens_addr = addr; /* auto for default size */ + + } else { + fprintf(stderr, "ERROR -> invalid addressing selection = %s\n", token); + return 1; + }; + + } + + /* search sensitivity size */ + if (*token == 'z') { + + + size = 1; /* predefined: 1 byte */ + + if (sscanf(token, "z=%d", &size) == 1) { + /* Specified */ + if ((size != 0) && (size != 1) && (size != 2)) { + fprintf(stderr, "ERROR -> invalid sensitivity size z = %d\n", size); + return 1; + } + parameters->jpwl_sens_size = size; + + } else if (!strcmp(token, "a")) { + /* default */ + parameters->jpwl_sens_size = size; /* 1 for default size */ + + } else { + fprintf(stderr, "ERROR -> invalid size selection = %s\n", token); + return 1; + }; + + } + + /* search range method */ + if (*token == 'g') { + + + range = 0; /* predefined: 0 (packet) */ + + if (sscanf(token, "g=%d", &range) == 1) { + /* Specified */ + if ((range < 0) || (range > 3)) { + fprintf(stderr, "ERROR -> invalid sensitivity range method g = %d\n", range); + return 1; + } + parameters->jpwl_sens_range = range; + + } else if (!strcmp(token, "g")) { + /* default */ + parameters->jpwl_sens_range = range; + + } else { + fprintf(stderr, "ERROR -> invalid range selection = %s\n", token); + return 1; + }; + + } + + /* next token or bust */ + token = strtok(NULL, ","); + }; + + + /* some info */ + fprintf(stdout, "Info: JPWL capabilities enabled\n"); + parameters->jpwl_epc_on = OPJ_TRUE; + + } + break; +#endif /* USE_JPWL */ + /* <<UniPG */ + /* ------------------------------------------------------ */ + + case 'J': { /* jpip on */ + /*parameters->jpip_on = OPJ_TRUE;*/ + } + break; + /* ------------------------------------------------------ */ + + + default: + fprintf(stderr, "ERROR -> Command line not valid\n"); + return 1; + } + } while (c != -1); + + /* check for possible errors */ + if (parameters->cp_cinema) { + if (parameters->tcp_numlayers > 1) { + parameters->cp_rsiz = STD_RSIZ; + fprintf(stdout, + "Warning: DC profiles do not allow more than one quality layer. The codestream created will not be compliant with the DC profile\n"); + } + } + if (img_fol->set_imgdir == 1) { + if (!(parameters->infile[0] == 0)) { + 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 <FORMAT> must be used !!\n"); + fprintf(stderr, "Only one format allowed! Valid formats are j2k and jp2!!\n"); + return 1; + } + if (!((parameters->outfile[0] == 0))) { + fprintf(stderr, "Error: options -ImgDir and -o cannot be used together !!\n"); + fprintf(stderr, "Specify OutputFormat using -OutFor<FORMAT> !!\n"); + return 1; + } + } else { + if ((parameters->infile[0] == 0) || (parameters->outfile[0] == 0)) { + fprintf(stderr, "Example: %s -i image.ppm -o image.j2k\n", argv[0]); + fprintf(stderr, " Try: %s -h\n", argv[0]); + return 1; + } + } + + if (parameters->decod_format == RAW_DFMT && raw_cp->rawWidth == 0) { + fprintf(stderr, "\nError: invalid raw image parameters\n"); + fprintf(stderr, "Please use the Format option -F:\n"); + fprintf(stderr, + "-F rawWidth,rawHeight,rawComp,rawBitDepth,s/u (Signed/Unsigned)\n"); + fprintf(stderr, "Example: -i lena.raw -o lena.j2k -F 512,512,3,8,u\n"); + fprintf(stderr, "Aborting\n"); + return 1; + } + + if ((parameters->cp_disto_alloc || parameters->cp_fixed_alloc || + parameters->cp_fixed_quality) + && (!(parameters->cp_disto_alloc ^ parameters->cp_fixed_alloc ^ + parameters->cp_fixed_quality))) { + fprintf(stderr, "Error: options -r -q and -f cannot be used together !!\n"); + return 1; + } /* mod fixed_quality */ + + /* if no rate entered, lossless by default */ + if (parameters->tcp_numlayers == 0) { + parameters->tcp_rates[0] = 0; /* MOD antonin : losslessbug */ + parameters->tcp_numlayers++; + parameters->cp_disto_alloc = 1; + } + + if ((parameters->cp_tx0 > parameters->image_offset_x0) || + (parameters->cp_ty0 > parameters->image_offset_y0)) { + fprintf(stderr, + "Error: Tile offset dimension is unnappropriate --> TX0(%d)<=IMG_X0(%d) TYO(%d)<=IMG_Y0(%d) \n", + parameters->cp_tx0, parameters->image_offset_x0, parameters->cp_ty0, + parameters->image_offset_y0); + return 1; + } + + for (i = 0; i < parameters->numpocs; i++) { + if (parameters->POC[i].prg == -1) { + fprintf(stderr, + "Unrecognized progression order in option -P (POC n %d) [LRCP, RLCP, RPCL, PCRL, CPRL] !!\n", + i + 1); + } + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +static void error_callback(const char *msg, void *client_data) +{ + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +static void warning_callback(const char *msg, void *client_data) +{ + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting a FILE* client object +*/ +static void info_callback(const char *msg, void *client_data) +{ + FILE *stream = (FILE*)client_data; + fprintf(stream, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + +int main(int argc, char **argv) +{ + opj_bool bSuccess; + opj_cparameters_t parameters; /* compression parameters */ + img_fol_t img_fol; + opj_event_mgr_t event_mgr; /* event manager */ + opj_image_t *image = NULL; + int i, num_images; + int imageno; + dircnt_t *dirptr = NULL; + raw_cparameters_t raw_cp; + opj_codestream_info_t cstr_info; /* Codestream information structure */ + char indexfilename[OPJ_PATH_LEN]; /* index file name */ + + /* + configure the event callbacks (not required) + setting of each callback is optional + */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* set encoding parameters to default values */ + opj_set_default_encoder_parameters(¶meters); + + /* Initialize indexfilename and img_fol */ + *indexfilename = 0; + memset(&img_fol, 0, sizeof(img_fol_t)); + + /* parse input and get user encoding parameters */ + if (parse_cmdline_encoder(argc, argv, ¶meters, &img_fol, &raw_cp, + indexfilename) == 1) { + return 1; + } + + if (parameters.cp_cinema) { + img_fol.rates = (float*)malloc(parameters.tcp_numlayers * sizeof(float)); + for (i = 0; i < parameters.tcp_numlayers; i++) { + img_fol.rates[i] = parameters.tcp_rates[i]; + } + cinema_parameters(¶meters); + } + + /* Create comment for codestream */ + if (parameters.cp_comment == NULL) { + const char comment[] = "Created by OpenJPEG version "; + const size_t clen = strlen(comment); + const char *version = opj_version(); + /* UniPG>> */ +#ifdef USE_JPWL + parameters.cp_comment = (char*)malloc(clen + strlen(version) + 11); + sprintf(parameters.cp_comment, "%s%s with JPWL", comment, version); +#else + parameters.cp_comment = (char*)malloc(clen + strlen(version) + 1); + sprintf(parameters.cp_comment, "%s%s", comment, version); +#endif + /* <<UniPG */ + } + + /* Read directory if necessary */ + if (img_fol.set_imgdir == 1) { + num_images = get_num_images(img_fol.imgdirpath); + dirptr = (dircnt_t*)malloc(sizeof(dircnt_t)); + if (dirptr) { + dirptr->filename_buf = (char*)malloc(num_images * OPJ_PATH_LEN * sizeof( + char)); /* Stores at max 10 image file names*/ + dirptr->filename = (char**) malloc(num_images * sizeof(char*)); + if (!dirptr->filename_buf) { + return 0; + } + for (i = 0; i < num_images; i++) { + dirptr->filename[i] = dirptr->filename_buf + i * OPJ_PATH_LEN; + } + } + if (load_images(dirptr, img_fol.imgdirpath) == 1) { + return 0; + } + if (num_images == 0) { + fprintf(stdout, "Folder is empty\n"); + return 0; + } + } else { + num_images = 1; + } + /*Encoding image one by one*/ + for (imageno = 0; imageno < num_images; imageno++) { + image = NULL; + fprintf(stderr, "\n"); + + if (img_fol.set_imgdir == 1) { + if (get_next_file(imageno, dirptr, &img_fol, ¶meters)) { + fprintf(stderr, "skipping file...\n"); + continue; + } + } + switch (parameters.decod_format) { + case PGX_DFMT: + break; + case PXM_DFMT: + break; + case BMP_DFMT: + break; + case TIF_DFMT: + break; + case RAW_DFMT: + break; + case TGA_DFMT: + break; + case PNG_DFMT: + break; + default: + fprintf(stderr, "skipping file...\n"); + continue; + } + + /* decode the source image */ + /* ----------------------- */ + + switch (parameters.decod_format) { + case PGX_DFMT: + image = pgxtoimage(parameters.infile, ¶meters); + if (!image) { + fprintf(stderr, "Unable to load pgx file\n"); + return 1; + } + break; + + case PXM_DFMT: + image = pnmtoimage(parameters.infile, ¶meters); + if (!image) { + fprintf(stderr, "Unable to load pnm file\n"); + return 1; + } + break; + + case BMP_DFMT: + image = bmptoimage(parameters.infile, ¶meters); + if (!image) { + fprintf(stderr, "Unable to load bmp file\n"); + return 1; + } + break; +#ifdef OPJ_HAVE_LIBTIFF + case TIF_DFMT: + image = tiftoimage(parameters.infile, ¶meters); + if (!image) { + fprintf(stderr, "Unable to load tiff file\n"); + return 1; + } + break; +#endif /* OPJ_HAVE_LIBTIFF */ + case RAW_DFMT: + image = rawtoimage(parameters.infile, ¶meters, &raw_cp); + if (!image) { + fprintf(stderr, "Unable to load raw file\n"); + return 1; + } + break; + + case TGA_DFMT: + image = tgatoimage(parameters.infile, ¶meters); + if (!image) { + fprintf(stderr, "Unable to load tga file\n"); + return 1; + } + break; +#ifdef OPJ_HAVE_LIBPNG + case PNG_DFMT: + image = pngtoimage(parameters.infile, ¶meters); + if (!image) { + fprintf(stderr, "Unable to load png file\n"); + return 1; + } + break; +#endif /* OPJ_HAVE_LIBPNG */ + } + /* Can happen if input file is TIFF or PNG + * and OPJ_HAVE_LIBTIF or OPJ_HAVE_LIBPNG is undefined + */ + if (!image) { + fprintf(stderr, "Unable to load file: got no image\n"); + return 1; + } + /* Decide if MCT should be used */ + parameters.tcp_mct = image->numcomps == 3 ? 1 : 0; + + if (parameters.cp_cinema) { + cinema_setup_encoder(¶meters, image, &img_fol); + } + + /* encode the destination image */ + /* ---------------------------- */ + + if (parameters.cod_format == J2K_CFMT) { /* J2K format output */ + int codestream_length; + size_t res; + opj_cio_t *cio = NULL; + FILE *f = NULL; + + /* get a J2K compressor handle */ + opj_cinfo_t* cinfo = opj_create_compress(CODEC_J2K); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr); + + /* setup the encoder parameters using the current image and user parameters */ + opj_setup_encoder(cinfo, ¶meters, image); + + /* open a byte stream for writing */ + /* allocate memory for all tiles */ + cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0); + + /* encode the image */ + if (*indexfilename) { /* If need to extract codestream information*/ + bSuccess = opj_encode_with_info(cinfo, cio, image, &cstr_info); + } else { + bSuccess = opj_encode(cinfo, cio, image, NULL); + } + if (!bSuccess) { + opj_cio_close(cio); + fprintf(stderr, "failed to encode image\n"); + return 1; + } + codestream_length = cio_tell(cio); + + /* write the buffer to disk */ + f = fopen(parameters.outfile, "wb"); + if (!f) { + fprintf(stderr, "failed to open %s for writing\n", parameters.outfile); + return 1; + } + res = fwrite(cio->buffer, 1, codestream_length, f); + if (res < (size_t)codestream_length) { /* FIXME */ + fprintf(stderr, "failed to write %d (%s)\n", codestream_length, + parameters.outfile); + return 1; + } + fclose(f); + + fprintf(stderr, "Generated outfile %s\n", parameters.outfile); + /* close and free the byte stream */ + opj_cio_close(cio); + + /* Write the index to disk */ + if (*indexfilename) { + bSuccess = write_index_file(&cstr_info, indexfilename); + if (bSuccess) { + fprintf(stderr, "Failed to output index file into [%s]\n", indexfilename); + } + } + + /* free remaining compression structures */ + opj_destroy_compress(cinfo); + if (*indexfilename) { + opj_destroy_cstr_info(&cstr_info); + } + } else { /* JP2 format output */ + int codestream_length; + size_t res; + opj_cio_t *cio = NULL; + FILE *f = NULL; + opj_cinfo_t *cinfo = NULL; + + /* get a JP2 compressor handle */ + cinfo = opj_create_compress(CODEC_JP2); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr); + + /* setup the encoder parameters using the current image and using user parameters */ + opj_setup_encoder(cinfo, ¶meters, image); + + /* open a byte stream for writing */ + /* allocate memory for all tiles */ + cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0); + + /* encode the image */ + if (*indexfilename /*|| parameters.jpip_on*/) { /* If need to extract codestream information*/ + bSuccess = opj_encode_with_info(cinfo, cio, image, &cstr_info); + } else { + bSuccess = opj_encode(cinfo, cio, image, NULL); + } + if (!bSuccess) { + opj_cio_close(cio); + fprintf(stderr, "failed to encode image\n"); + return 1; + } + codestream_length = cio_tell(cio); + + /* write the buffer to disk */ + f = fopen(parameters.outfile, "wb"); + if (!f) { + fprintf(stderr, "failed to open %s for writing\n", parameters.outfile); + return 1; + } + res = fwrite(cio->buffer, 1, codestream_length, f); + if (res < (size_t)codestream_length) { /* FIXME */ + fprintf(stderr, "failed to write %d (%s)\n", codestream_length, + parameters.outfile); + return 1; + } + fclose(f); + fprintf(stderr, "Generated outfile %s\n", parameters.outfile); + /* close and free the byte stream */ + opj_cio_close(cio); + + /* Write the index to disk */ + if (*indexfilename) { + bSuccess = write_index_file(&cstr_info, indexfilename); + if (bSuccess) { + fprintf(stderr, "Failed to output index file\n"); + } + } + + /* free remaining compression structures */ + opj_destroy_compress(cinfo); + if (*indexfilename) { + opj_destroy_cstr_info(&cstr_info); + } + } + + /* free image data */ + opj_image_destroy(image); + } + + /* free user parameters structure */ + if (parameters.cp_comment) { + free(parameters.cp_comment); + } + if (parameters.cp_matrice) { + free(parameters.cp_matrice); + } + + return 0; +} diff --git a/openjpeg/src/bin/jpwl/opj_jpwl_decompress.c b/openjpeg/src/bin/jpwl/opj_jpwl_decompress.c new file mode 100644 index 000000000..ffe84e54e --- /dev/null +++ b/openjpeg/src/bin/jpwl/opj_jpwl_decompress.c @@ -0,0 +1,895 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * Copyright (c) 2003-2014, Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <math.h> + +#ifdef _WIN32 +#include "windirent.h" +#else +#include <dirent.h> +#endif /* _WIN32 */ + +#ifdef _WIN32 +#include <windows.h> +#else +#include <strings.h> +#define _stricmp strcasecmp +#define _strnicmp strncasecmp +#endif /* _WIN32 */ + +#include "opj_apps_config.h" +#include "openjpeg.h" +#include "opj_getopt.h" +#include "convert.h" +#include "index.h" + +#ifdef OPJ_HAVE_LIBLCMS2 +#include <lcms2.h> +#endif +#ifdef OPJ_HAVE_LIBLCMS1 +#include <lcms.h> +#endif +#include "color.h" + +#include "format_defs.h" + +typedef struct dircnt { + /** Buffer for holding images read from Directory*/ + char *filename_buf; + /** Pointer to the buffer*/ + char **filename; +} dircnt_t; + + +typedef struct img_folder { + /** The directory path of the folder containing input images*/ + char *imgdirpath; + /** Output format*/ + const char *out_format; + /** Enable option*/ + char set_imgdir; + /** Enable Cod Format for output*/ + char set_out_format; + +} img_fol_t; + +void decode_help_display(void) +{ + fprintf(stdout, "HELP for j2k_to_image\n----\n\n"); + fprintf(stdout, "- the -h option displays this help information on screen\n\n"); + + /* UniPG>> */ + fprintf(stdout, "List of parameters for the JPEG 2000 " +#ifdef USE_JPWL + "+ JPWL " +#endif /* USE_JPWL */ + "decoder:\n"); + /* <<UniPG */ + fprintf(stdout, "\n"); + fprintf(stdout, "\n"); + fprintf(stdout, " -ImgDir \n"); + fprintf(stdout, " Image file Directory path \n"); + fprintf(stdout, " -OutFor \n"); + fprintf(stdout, " REQUIRED only if -ImgDir is used\n"); + fprintf(stdout, " Need to specify only format without filename <BMP> \n"); + fprintf(stdout, + " Currently accepts PGM, PPM, PNM, PGX, PNG, BMP, TIF, RAW and TGA formats\n"); + fprintf(stdout, " -i <compressed file>\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 <decompressed file>\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 <reduce factor>\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 <number of quality layers to decode>\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, "\n"); + /* UniPG>> */ +#ifdef USE_JPWL + fprintf(stdout, " -W <options>\n"); + fprintf(stdout, + " Activates the JPWL correction capability, if the codestream complies.\n"); + fprintf(stdout, + " Options can be a comma separated list of <param=val> 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); +#endif /* USE_JPWL */ + /* <<UniPG */ + fprintf(stdout, "\n"); +} + +/* -------------------------------------------------------------------------- */ + +int get_num_images(char *imgdirpath) +{ + DIR *dir; + struct dirent* content; + int num_images = 0; + + /*Reading the input images from given input directory*/ + + dir = opendir(imgdirpath); + if (!dir) { + fprintf(stderr, "Could not open Folder %s\n", imgdirpath); + return 0; + } + + while ((content = readdir(dir)) != NULL) { + if (strcmp(".", content->d_name) == 0 || strcmp("..", content->d_name) == 0) { + continue; + } + num_images++; + } + return num_images; +} + +int load_images(dircnt_t *dirptr, char *imgdirpath) +{ + DIR *dir; + struct dirent* content; + int i = 0; + + /*Reading the input images from given input directory*/ + + dir = opendir(imgdirpath); + if (!dir) { + fprintf(stderr, "Could not open Folder %s\n", imgdirpath); + return 1; + } else { + fprintf(stderr, "Folder opened successfully\n"); + } + + while ((content = readdir(dir)) != NULL) { + if (strcmp(".", content->d_name) == 0 || strcmp("..", content->d_name) == 0) { + continue; + } + + strcpy(dirptr->filename[i], content->d_name); + i++; + } + return 0; +} + +int get_file_format(char *filename) +{ + unsigned int i; + static const char *extension[] = {"pgx", "pnm", "pgm", "ppm", "bmp", "tif", "raw", "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, TGA_DFMT, PNG_DFMT, J2K_CFMT, JP2_CFMT, JPT_CFMT, J2K_CFMT, J2K_CFMT }; + char * ext = strrchr(filename, '.'); + if (ext == NULL) { + return -1; + } + ext++; + if (ext) { + for (i = 0; i < sizeof(format) / sizeof(*format); i++) { + if (_strnicmp(ext, extension[i], 3) == 0) { + return format[i]; + } + } + } + + return -1; +} + +char get_next_file(int imageno, dircnt_t *dirptr, img_fol_t *img_fol, + opj_dparameters_t *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 = get_file_format(image_filename); + if (parameters->decod_format == -1) { + return 1; + } + sprintf(infilename, "%s/%s", img_fol->imgdirpath, image_filename); + strncpy(parameters->infile, infilename, sizeof(infilename)); + + /*Set output file*/ + strcpy(temp_ofname, strtok(image_filename, ".")); + while ((temp_p = strtok(NULL, ".")) != NULL) { + strcat(temp_ofname, temp1); + sprintf(temp1, ".%s", temp_p); + } + 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)); + } + return 0; +} + +/* -------------------------------------------------------------------------- */ +int parse_cmdline_decoder(int argc, char **argv, opj_dparameters_t *parameters, + img_fol_t *img_fol, char *indexfilename) +{ + /* parse the command line */ + int totlen, c; + opj_option_t long_option[] = { + {"ImgDir", REQ_ARG, NULL, 'y'}, + {"OutFor", REQ_ARG, NULL, 'O'}, + }; + + const char optlist[] = "i:o:r:l:x:" + + /* UniPG>> */ +#ifdef USE_JPWL + "W:" +#endif /* USE_JPWL */ + /* <<UniPG */ + "h" ; + totlen = sizeof(long_option); + img_fol->set_out_format = 0; + do { + c = opj_getopt_long(argc, argv, optlist, long_option, totlen); + if (c == -1) { + break; + } + switch (c) { + case 'i': { /* input file */ + char *infile = opj_optarg; + parameters->decod_format = get_file_format(infile); + switch (parameters->decod_format) { + case J2K_CFMT: + case JP2_CFMT: + case JPT_CFMT: + break; + default: + fprintf(stderr, + "!! Unrecognized format for infile : %s [accept only *.j2k, *.jp2, *.jpc or *.jpt] !!\n\n", + infile); + return 1; + } + strncpy(parameters->infile, infile, sizeof(parameters->infile) - 1); + } + break; + + /* ----------------------------------------------------- */ + + case 'o': { /* output file */ + char *outfile = opj_optarg; + parameters->cod_format = get_file_format(outfile); + switch (parameters->cod_format) { + case PGX_DFMT: + case PXM_DFMT: + case BMP_DFMT: + case TIF_DFMT: + case RAW_DFMT: + case TGA_DFMT: + case PNG_DFMT: + break; + default: + fprintf(stderr, + "Unknown output format image %s [only *.pnm, *.pgm, *.ppm, *.pgx, *.bmp, *.tif, *.raw or *.tga]!! \n", + outfile); + return 1; + } + strncpy(parameters->outfile, outfile, sizeof(parameters->outfile) - 1); + } + break; + + /* ----------------------------------------------------- */ + + case 'O': { /* output format */ + char outformat[50]; + char *of = opj_optarg; + sprintf(outformat, ".%s", of); + img_fol->set_out_format = 1; + parameters->cod_format = get_file_format(outformat); + switch (parameters->cod_format) { + case PGX_DFMT: + img_fol->out_format = "pgx"; + break; + case PXM_DFMT: + img_fol->out_format = "ppm"; + break; + case BMP_DFMT: + img_fol->out_format = "bmp"; + break; + case TIF_DFMT: + img_fol->out_format = "tif"; + break; + case RAW_DFMT: + img_fol->out_format = "raw"; + break; + case TGA_DFMT: + img_fol->out_format = "raw"; + break; + case PNG_DFMT: + 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); + return 1; + break; + } + } + break; + + /* ----------------------------------------------------- */ + + + case 'r': { /* reduce option */ + sscanf(opj_optarg, "%d", ¶meters->cp_reduce); + } + break; + + /* ----------------------------------------------------- */ + + + case 'l': { /* layering option */ + sscanf(opj_optarg, "%d", ¶meters->cp_layer); + } + break; + + /* ----------------------------------------------------- */ + + case 'h': /* display an help description */ + decode_help_display(); + return 1; + + /* ------------------------------------------------------ */ + + case 'y': { /* Image Directory path */ + img_fol->imgdirpath = (char*)malloc(strlen(opj_optarg) + 1); + strcpy(img_fol->imgdirpath, opj_optarg); + img_fol->set_imgdir = 1; + } + break; + /* ----------------------------------------------------- */ + case 'x': { /* Creation of index file */ + char *index = opj_optarg; + strncpy(indexfilename, index, OPJ_PATH_LEN); + } + break; + /* ----------------------------------------------------- */ + /* UniPG>> */ +#ifdef USE_JPWL + + case 'W': { /* activate JPWL correction */ + char *token = NULL; + + token = strtok(opj_optarg, ","); + while (token != NULL) { + + /* search expected number of components */ + if (*token == 'c') { + + static int compno; + + compno = JPWL_EXPECTED_COMPONENTS; /* predefined no. of components */ + + if (sscanf(token, "c=%d", &compno) == 1) { + /* Specified */ + if ((compno < 1) || (compno > 256)) { + fprintf(stderr, "ERROR -> invalid number of components c = %d\n", compno); + return 1; + } + parameters->jpwl_exp_comps = compno; + + } else if (!strcmp(token, "c")) { + /* default */ + parameters->jpwl_exp_comps = compno; /* auto for default size */ + + } else { + fprintf(stderr, "ERROR -> invalid components specified = %s\n", token); + return 1; + }; + } + + /* search maximum number of tiles */ + if (*token == 't') { + + static int tileno; + + tileno = JPWL_MAXIMUM_TILES; /* maximum no. of tiles */ + + if (sscanf(token, "t=%d", &tileno) == 1) { + /* Specified */ + if ((tileno < 1) || (tileno > JPWL_MAXIMUM_TILES)) { + fprintf(stderr, "ERROR -> invalid number of tiles t = %d\n", tileno); + return 1; + } + parameters->jpwl_max_tiles = tileno; + + } else if (!strcmp(token, "t")) { + /* default */ + parameters->jpwl_max_tiles = tileno; /* auto for default size */ + + } else { + fprintf(stderr, "ERROR -> invalid tiles specified = %s\n", token); + return 1; + }; + } + + /* next token or bust */ + token = strtok(NULL, ","); + }; + parameters->jpwl_correct = OPJ_TRUE; + fprintf(stdout, "JPWL correction capability activated\n"); + fprintf(stdout, "- expecting %d components\n", parameters->jpwl_exp_comps); + } + break; +#endif /* USE_JPWL */ + /* <<UniPG */ + + /* ----------------------------------------------------- */ + + default: + fprintf(stderr, "WARNING -> this option is not valid \"-%c %s\"\n", c, + opj_optarg); + break; + } + } while (c != -1); + + /* 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"); + return 1; + } + if (img_fol->set_out_format == 0) { + fprintf(stderr, + "Error: When -ImgDir is used, -OutFor <FORMAT> must be used !!\n"); + fprintf(stderr, + "Only one format allowed! Valid format 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"); + return 1; + } + } else { + if ((parameters->infile[0] == 0) || (parameters->outfile[0] == 0)) { + fprintf(stderr, "Example: %s -i image.j2k -o image.pgm\n", argv[0]); + fprintf(stderr, " Try: %s -h\n", argv[0]); + return 1; + } + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) +{ + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) +{ + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting no client object +*/ +void info_callback(const char *msg, void *client_data) +{ + (void)client_data; + fprintf(stdout, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + +int main(int argc, char **argv) +{ + opj_dparameters_t parameters; /* decompression parameters */ + img_fol_t img_fol; + opj_event_mgr_t event_mgr; /* event manager */ + opj_image_t *image = NULL; + FILE *fsrc = NULL; + unsigned char *src = NULL; + int file_length; + int num_images; + int i, imageno; + dircnt_t *dirptr = NULL; + opj_dinfo_t* dinfo = NULL; /* handle to a decompressor */ + opj_cio_t *cio = NULL; + opj_codestream_info_t cstr_info; /* Codestream information structure */ + char indexfilename[OPJ_PATH_LEN]; /* index file name */ + + /* configure the event callbacks (not required) */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* set decoding parameters to default values */ + opj_set_default_decoder_parameters(¶meters); + + /* Initialize indexfilename and img_fol */ + *indexfilename = 0; + 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) { + return 1; + } + + /* Initialize reading of directory */ + if (img_fol.set_imgdir == 1) { + num_images = get_num_images(img_fol.imgdirpath); + + dirptr = (dircnt_t*)malloc(sizeof(dircnt_t)); + if (dirptr) { + dirptr->filename_buf = (char*)malloc(num_images * OPJ_PATH_LEN * sizeof( + char)); /* Stores at max 10 image file names*/ + dirptr->filename = (char**) malloc(num_images * sizeof(char*)); + + if (!dirptr->filename_buf) { + return 1; + } + for (i = 0; i < num_images; i++) { + dirptr->filename[i] = dirptr->filename_buf + i * OPJ_PATH_LEN; + } + } + if (load_images(dirptr, img_fol.imgdirpath) == 1) { + return 1; + } + if (num_images == 0) { + fprintf(stdout, "Folder is empty\n"); + return 1; + } + } else { + num_images = 1; + } + + /*Encoding image one by one*/ + for (imageno = 0; imageno < num_images ; imageno++) { + image = NULL; + fprintf(stderr, "\n"); + + if (img_fol.set_imgdir == 1) { + if (get_next_file(imageno, dirptr, &img_fol, ¶meters)) { + fprintf(stderr, "skipping file...\n"); + continue; + } + } + + /* read the input file and put it in memory */ + /* ---------------------------------------- */ + fsrc = fopen(parameters.infile, "rb"); + if (!fsrc) { + fprintf(stderr, "ERROR -> failed to open %s for reading\n", parameters.infile); + return 1; + } + fseek(fsrc, 0, SEEK_END); + file_length = ftell(fsrc); + fseek(fsrc, 0, SEEK_SET); + src = (unsigned char *) malloc(file_length); + if (fread(src, 1, file_length, fsrc) != (size_t)file_length) { + free(src); + fclose(fsrc); + fprintf(stderr, + "\nERROR: fread return a number of element different from the expected.\n"); + return 1; + } + fclose(fsrc); + + /* decode the code-stream */ + /* ---------------------- */ + + switch (parameters.decod_format) { + case J2K_CFMT: { + /* JPEG-2000 codestream */ + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_J2K); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); + + /* decode the stream and fill the image structure */ + if (*indexfilename) { /* If need to extract codestream information*/ + image = opj_decode_with_info(dinfo, cio, &cstr_info); + } else { + image = opj_decode(dinfo, cio); + } + if (!image) { + fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n"); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + free(src); + return 1; + } + + /* close the byte stream */ + opj_cio_close(cio); + + /* Write the index to disk */ + if (*indexfilename) { + opj_bool bSuccess; + bSuccess = write_index_file(&cstr_info, indexfilename); + if (bSuccess) { + fprintf(stderr, "Failed to output index file\n"); + } + } + } + break; + + case JP2_CFMT: { + /* JPEG 2000 compressed image data */ + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_JP2); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using the current image and user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); + + /* decode the stream and fill the image structure */ + if (*indexfilename) { /* If need to extract codestream information*/ + image = opj_decode_with_info(dinfo, cio, &cstr_info); + } else { + image = opj_decode(dinfo, cio); + } + if (!image) { + fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n"); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + free(src); + return 1; + } + + /* close the byte stream */ + opj_cio_close(cio); + + /* Write the index to disk */ + if (*indexfilename) { + opj_bool bSuccess; + bSuccess = write_index_file(&cstr_info, indexfilename); + if (bSuccess) { + fprintf(stderr, "Failed to output index file\n"); + } + } + } + break; + + case JPT_CFMT: { + /* JPEG 2000, JPIP */ + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_JPT); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); + + /* decode the stream and fill the image structure */ + if (*indexfilename) { /* If need to extract codestream information*/ + image = opj_decode_with_info(dinfo, cio, &cstr_info); + } else { + image = opj_decode(dinfo, cio); + } + if (!image) { + fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n"); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + free(src); + return 1; + } + + /* close the byte stream */ + opj_cio_close(cio); + + /* Write the index to disk */ + if (*indexfilename) { + opj_bool bSuccess; + bSuccess = write_index_file(&cstr_info, indexfilename); + if (bSuccess) { + fprintf(stderr, "Failed to output index file\n"); + } + } + } + break; + + default: + fprintf(stderr, "skipping file..\n"); + continue; + } + + /* free the memory containing the code-stream */ + free(src); + src = NULL; + + if (image->color_space == CLRSPC_SYCC) { + color_sycc_to_rgb(image); + } + + if (image->icc_profile_buf) { +#if defined(OPJ_HAVE_LIBLCMS1) || defined(OPJ_HAVE_LIBLCMS2) + color_apply_icc_profile(image); +#endif + + free(image->icc_profile_buf); + image->icc_profile_buf = NULL; + image->icc_profile_len = 0; + } + + /* create output image */ + /* ------------------- */ + switch (parameters.cod_format) { + case PXM_DFMT: /* PNM PGM PPM */ + if (imagetopnm(image, parameters.outfile)) { + fprintf(stdout, "Outfile %s not generated\n", parameters.outfile); + } else { + fprintf(stdout, "Generated Outfile %s\n", parameters.outfile); + } + break; + + case PGX_DFMT: /* PGX */ + if (imagetopgx(image, parameters.outfile)) { + fprintf(stdout, "Outfile %s not generated\n", parameters.outfile); + } else { + fprintf(stdout, "Generated Outfile %s\n", parameters.outfile); + } + break; + + case BMP_DFMT: /* BMP */ + if (imagetobmp(image, parameters.outfile)) { + fprintf(stdout, "Outfile %s not generated\n", parameters.outfile); + } else { + fprintf(stdout, "Generated Outfile %s\n", parameters.outfile); + } + break; +#ifdef OPJ_HAVE_LIBTIFF + case TIF_DFMT: /* TIFF */ + if (imagetotif(image, parameters.outfile)) { + fprintf(stdout, "Outfile %s not generated\n", parameters.outfile); + } else { + fprintf(stdout, "Generated Outfile %s\n", parameters.outfile); + } + break; +#endif /* OPJ_HAVE_LIBTIFF */ + case RAW_DFMT: /* RAW */ + if (imagetoraw(image, parameters.outfile)) { + fprintf(stdout, "Error generating raw file. Outfile %s not generated\n", + parameters.outfile); + } else { + fprintf(stdout, "Successfully generated Outfile %s\n", parameters.outfile); + } + break; + + case TGA_DFMT: /* TGA */ + if (imagetotga(image, parameters.outfile)) { + fprintf(stdout, "Error generating tga file. Outfile %s not generated\n", + parameters.outfile); + } else { + fprintf(stdout, "Successfully generated Outfile %s\n", parameters.outfile); + } + break; +#ifdef OPJ_HAVE_LIBPNG + case PNG_DFMT: /* PNG */ + if (imagetopng(image, parameters.outfile)) { + fprintf(stdout, "Error generating png file. Outfile %s not generated\n", + parameters.outfile); + } else { + fprintf(stdout, "Successfully generated Outfile %s\n", parameters.outfile); + } + break; +#endif /* OPJ_HAVE_LIBPNG */ + /* Can happen if output file is TIFF or PNG + * and OPJ_HAVE_LIBTIF or OPJ_HAVE_LIBPNG is undefined + */ + default: + fprintf(stderr, "Outfile %s not generated\n", parameters.outfile); + } + + /* free remaining structures */ + if (dinfo) { + opj_destroy_decompress(dinfo); + } + /* free codestream information structure */ + if (*indexfilename) { + opj_destroy_cstr_info(&cstr_info); + } + /* free image data structure */ + opj_image_destroy(image); + + } + return 0; +} +/*end main*/ + + + + diff --git a/openjpeg/src/bin/jpwl/windirent.h b/openjpeg/src/bin/jpwl/windirent.h new file mode 100644 index 000000000..b7ed9a3c1 --- /dev/null +++ b/openjpeg/src/bin/jpwl/windirent.h @@ -0,0 +1,680 @@ + +/* + * uce-dirent.h - operating system independent dirent implementation + * + * Copyright (C) 1998-2002 Toni Ronkko + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * ``Software''), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * + * May 28 1998, Toni Ronkko <tronkko@messi.uku.fi> + * + * $Id: uce-dirent.h,v 1.7 2002/05/13 10:48:35 tr Exp $ + * + * $Log: uce-dirent.h,v $ + * Revision 1.7 2002/05/13 10:48:35 tr + * embedded some source code directly to the header so that no source + * modules need to be included in the MS Visual C project using the + * interface, removed all the dependencies to other headers of the `uce' + * library so that the header can be made public + * + * Revision 1.6 2002/04/12 16:22:04 tr + * Unified Compiling Environment (UCE) replaced `std' library + * + * Revision 1.5 2001/07/20 16:33:40 tr + * moved to `std' library and re-named defines accordingly + * + * Revision 1.4 2001/07/10 16:47:18 tronkko + * revised comments + * + * Revision 1.3 2001/01/11 13:16:43 tr + * using ``uce-machine.h'' for finding out defines such as `FREEBSD' + * + * Revision 1.2 2000/10/08 16:00:41 tr + * copy of FreeBSD man page + * + * Revision 1.1 2000/07/10 05:53:16 tr + * Initial revision + * + * Revision 1.2 1998/07/19 18:29:14 tr + * Added error reporting capabilities and some asserts. + * + * Revision 1.1 1998/07/04 16:27:51 tr + * Initial revision + * + * + * MSVC 1.0 scans automatic dependencies incorrectly when your project + * contains this very header. The problem is that MSVC cannot handle + * include directives inside #if..#endif block those are never entered. + * Since this header ought to compile in many different operating systems, + * there had to be several conditional blocks that are compiled only in + * operating systems for what they were designed for. MSVC 1.0 cannot + * handle inclusion of sys/dir.h in a part that is compiled only in Apollo + * operating system. To fix the problem you need to insert DIR.H into + * SYSINCL.DAT located in MSVC\BIN directory and restart visual C++. + * Consult manuals for more informaton about the problem. + * + * Since many UNIX systems have dirent.h we assume to have one also. + * However, if your UNIX system does not have dirent.h you can download one + * for example at: http://ftp.uni-mannheim.de/ftp/GNU/dirent/dirent.tar.gz. + * You can also see if you have one of dirent.h, direct.h, dir.h, ndir.h, + * sys/dir.h and sys/ndir.h somewhere. Try defining HAVE_DIRENT_H, + * HAVE_DIRECT_H, HAVE_DIR_H, HAVE_NDIR_H, HAVE_SYS_DIR_H and + * HAVE_SYS_NDIR_H according to the files found. + */ +#ifndef DIRENT_H +#define DIRENT_H +#define DIRENT_H_INCLUDED + +/* find out platform */ +#if defined(MSDOS) /* MS-DOS */ +#elif defined(__MSDOS__) /* Turbo C/Borland */ +# define MSDOS +#elif defined(__DOS__) /* Watcom */ +# define MSDOS +#endif + +#if defined(WIN32) /* MS-Windows */ +#elif defined(__NT__) /* Watcom */ +# define WIN32 +#elif defined(_WIN32) /* Microsoft */ +# define WIN32 +#elif defined(__WIN32__) /* Borland */ +# define WIN32 +#endif + +/* + * See what kind of dirent interface we have unless autoconf has already + * determinated that. + */ +#if !defined(HAVE_DIRENT_H) && !defined(HAVE_DIRECT_H) && !defined(HAVE_SYS_DIR_H) && !defined(HAVE_NDIR_H) && !defined(HAVE_SYS_NDIR_H) && !defined(HAVE_DIR_H) +# if defined(_MSC_VER) /* Microsoft C/C++ */ +/* no dirent.h */ +# elif defined(__MINGW32__) /* MinGW */ +/* no dirent.h */ +# elif defined(__BORLANDC__) /* Borland C/C++ */ +# define HAVE_DIRENT_H +# define VOID_CLOSEDIR +# elif defined(__TURBOC__) /* Borland Turbo C */ +/* no dirent.h */ +# elif defined(__WATCOMC__) /* Watcom C/C++ */ +# define HAVE_DIRECT_H +# elif defined(__apollo) /* Apollo */ +# define HAVE_SYS_DIR_H +# elif defined(__hpux) /* HP-UX */ +# define HAVE_DIRENT_H +# elif (defined(__alpha) || defined(__alpha__)) && !defined(__linux__) /* Alpha OSF1 */ +# error "not implemented" +# elif defined(__sgi) /* Silicon Graphics */ +# define HAVE_DIRENT_H +# elif defined(sun) || defined(__sun) /* Sun Solaris */ +# define HAVE_DIRENT_H +# elif defined(__FreeBSD__) /* FreeBSD */ +# define HAVE_DIRENT_H +# elif defined(__linux__) /* Linux */ +# define HAVE_DIRENT_H +# elif defined(__GNUC__) /* GNU C/C++ */ +# define HAVE_DIRENT_H +# else +# error "not implemented" +# endif +#endif + +/* include proper interface headers */ +#if defined(HAVE_DIRENT_H) +# include <dirent.h> +# ifdef FREEBSD +# define NAMLEN(dp) ((int)((dp)->d_namlen)) +# else +# define NAMLEN(dp) ((int)(strlen((dp)->d_name))) +# endif + +#elif defined(HAVE_NDIR_H) +# include <ndir.h> +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_SYS_NDIR_H) +# include <sys/ndir.h> +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_DIRECT_H) +# include <direct.h> +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_DIR_H) +# include <dir.h> +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(HAVE_SYS_DIR_H) +# include <sys/types.h> +# include <sys/dir.h> +# ifndef dirent +# define dirent direct +# endif +# define NAMLEN(dp) ((int)((dp)->d_namlen)) + +#elif defined(MSDOS) || defined(WIN32) + +/* figure out type of underlaying directory interface to be used */ +# if defined(WIN32) +# define DIRENT_WIN32_INTERFACE +# elif defined(MSDOS) +# define DIRENT_MSDOS_INTERFACE +# else +# error "missing native dirent interface" +# endif + +/*** WIN32 specifics ***/ +# if defined(DIRENT_WIN32_INTERFACE) +# include <windows.h> +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN (MAX_PATH) +# endif + + +/*** MS-DOS specifics ***/ +# elif defined(DIRENT_MSDOS_INTERFACE) +# include <dos.h> + +/* Borland defines file length macros in dir.h */ +# if defined(__BORLANDC__) +# include <dir.h> +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN ((MAXFILE)+(MAXEXT)) +# endif +# if !defined(_find_t) +# define _find_t find_t +# endif + +/* Turbo C defines ffblk structure in dir.h */ +# elif defined(__TURBOC__) +# include <dir.h> +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN ((MAXFILE)+(MAXEXT)) +# endif +# define DIRENT_USE_FFBLK + +/* MSVC */ +# elif defined(_MSC_VER) +# if !defined(DIRENT_MAXNAMLEN) +# define DIRENT_MAXNAMLEN (12) +# endif + +/* Watcom */ +# elif defined(__WATCOMC__) +# if !defined(DIRENT_MAXNAMLEN) +# if defined(__OS2__) || defined(__NT__) +# define DIRENT_MAXNAMLEN (255) +# else +# define DIRENT_MAXNAMLEN (12) +# endif +# endif + +# endif +# endif + +/*** generic MS-DOS and MS-Windows stuff ***/ +# if !defined(NAME_MAX) && defined(DIRENT_MAXNAMLEN) +# define NAME_MAX DIRENT_MAXNAMLEN +# endif +# if NAME_MAX < DIRENT_MAXNAMLEN +# error "assertion failed: NAME_MAX >= DIRENT_MAXNAMLEN" +# endif + + +/* + * Substitute for real dirent structure. Note that `d_name' field is a + * true character array although we have it copied in the implementation + * dependent data. We could save some memory if we had declared `d_name' + * as a pointer referring the name within implementation dependent data. + * We have not done that since some code may rely on sizeof(d_name) to be + * something other than four. Besides, directory entries are typically so + * small that it takes virtually no time to copy them from place to place. + */ +typedef struct dirent { + char d_name[NAME_MAX + 1]; + + /*** Operating system specific part ***/ +# if defined(DIRENT_WIN32_INTERFACE) /*WIN32*/ + WIN32_FIND_DATA data; +# elif defined(DIRENT_MSDOS_INTERFACE) /*MSDOS*/ +# if defined(DIRENT_USE_FFBLK) + struct ffblk data; +# else + struct _find_t data; +# endif +# endif +} dirent; + +/* DIR substitute structure containing directory name. The name is + * essential for the operation of ``rewinndir'' function. */ +typedef struct DIR { + char *dirname; /* directory being scanned */ + dirent current; /* current entry */ + int dirent_filled; /* is current un-processed? */ + + /*** Operating system specific part ***/ +# if defined(DIRENT_WIN32_INTERFACE) + HANDLE search_handle; +# elif defined(DIRENT_MSDOS_INTERFACE) +# endif +} DIR; + +# ifdef __cplusplus +extern "C" { +# endif + +/* supply prototypes for dirent functions */ +static DIR *opendir(const char *dirname); +static struct dirent *readdir(DIR *dirp); +static int closedir(DIR *dirp); +static void rewinddir(DIR *dirp); + +/* + * Implement dirent interface as static functions so that the user does not + * need to change his project in any way to use dirent function. With this + * it is sufficient to include this very header from source modules using + * dirent functions and the functions will be pulled in automatically. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> + +/* use ffblk instead of _find_t if requested */ +#if defined(DIRENT_USE_FFBLK) +# define _A_ARCH (FA_ARCH) +# define _A_HIDDEN (FA_HIDDEN) +# define _A_NORMAL (0) +# define _A_RDONLY (FA_RDONLY) +# define _A_SUBDIR (FA_DIREC) +# define _A_SYSTEM (FA_SYSTEM) +# define _A_VOLID (FA_LABEL) +# define _dos_findnext(dest) findnext(dest) +# define _dos_findfirst(name,flags,dest) findfirst(name,dest,flags) +#endif + +static int _initdir(DIR *p); +static const char *_getdirname(const struct dirent *dp); +static void _setdirname(struct DIR *dirp); + +/* + * <function name="opendir"> + * <intro>open directory stream for reading + * <syntax>DIR *opendir (const char *dirname); + * + * <desc>Open named directory stream for read and return pointer to the + * internal working area that is used for retrieving individual directory + * entries. The internal working area has no fields of your interest. + * + * <ret>Returns a pointer to the internal working area or NULL in case the + * directory stream could not be opened. Global `errno' variable will set + * in case of error as follows: + * + * <table> + * [EACESS |Permission denied. + * [EMFILE |Too many open files used by the process. + * [ENFILE |Too many open files in system. + * [ENOENT |Directory does not exist. + * [ENOMEM |Insufficient memory. + * [ENOTDIR |dirname does not refer to directory. This value is not + * reliable on MS-DOS and MS-Windows platforms. Many + * implementations return ENOENT even when the name refers to a + * file.] + * </table> + * </function> + */ +static DIR *opendir(const char *dirname) +{ + DIR *dirp; + assert(dirname != NULL); + + dirp = (DIR*)malloc(sizeof(struct DIR)); + if (dirp != NULL) { + char *p; + + /* allocate room for directory name */ + dirp->dirname = (char*) malloc(strlen(dirname) + 1 + strlen("\\*.*")); + if (dirp->dirname == NULL) { + /* failed to duplicate directory name. errno set by malloc() */ + free(dirp); + return NULL; + } + /* Copy directory name while appending directory separator and "*.*". + * Directory separator is not appended if the name already ends with + * drive or directory separator. Directory separator is assumed to be + * '/' or '\' and drive separator is assumed to be ':'. */ + strcpy(dirp->dirname, dirname); + p = strchr(dirp->dirname, '\0'); + if (dirp->dirname < p && + *(p - 1) != '\\' && *(p - 1) != '/' && *(p - 1) != ':') { + strcpy(p++, "\\"); + } +# ifdef DIRENT_WIN32_INTERFACE + strcpy(p, "*"); /*scan files with and without extension in win32*/ +# else + strcpy(p, "*.*"); /*scan files with and without extension in DOS*/ +# endif + + /* open stream */ + if (_initdir(dirp) == 0) { + /* initialization failed */ + free(dirp->dirname); + free(dirp); + return NULL; + } + } + return dirp; +} + + +/* + * <function name="readdir"> + * <intro>read a directory entry + * <syntax>struct dirent *readdir (DIR *dirp); + * + * <desc>Read individual directory entry and return pointer to a structure + * containing the name of the entry. Individual directory entries returned + * include normal files, sub-directories, pseudo-directories "." and ".." + * and also volume labels, hidden files and system files in MS-DOS and + * MS-Windows. You might want to use stat(2) function to determinate which + * one are you dealing with. Many dirent implementations already contain + * equivalent information in dirent structure but you cannot depend on + * this. + * + * The dirent structure contains several system dependent fields that + * generally have no interest to you. The only interesting one is char + * d_name[] that is also portable across different systems. The d_name + * field contains the name of the directory entry without leading path. + * While d_name is portable across different systems the actual storage + * capacity of d_name varies from system to system and there is no portable + * way to find out it at compile time as different systems define the + * capacity of d_name with different macros and some systems do not define + * capacity at all (besides actual declaration of the field). If you really + * need to find out storage capacity of d_name then you might want to try + * NAME_MAX macro. The NAME_MAX is defined in POSIX standard although + * there are many MS-DOS and MS-Windows implementations those do not define + * it. There are also systems that declare d_name as "char d_name[1]" and + * then allocate suitable amount of memory at run-time. Thanks to Alain + * Decamps (Alain.Decamps@advalvas.be) for pointing it out to me. + * + * This all leads to the fact that it is difficult to allocate space + * for the directory names when the very same program is being compiled on + * number of operating systems. Therefore I suggest that you always + * allocate space for directory names dynamically. + * + * <ret> + * Returns a pointer to a structure containing name of the directory entry + * in `d_name' field or NULL if there was an error. In case of an error the + * global `errno' variable will set as follows: + * + * <table> + * [EBADF |dir parameter refers to an invalid directory stream. This value + * is not set reliably on all implementations.] + * </table> + * </function> + */ +static struct dirent * +readdir(DIR *dirp) +{ + assert(dirp != NULL); + if (dirp == NULL) { + errno = EBADF; + return NULL; + } + +#if defined(DIRENT_WIN32_INTERFACE) + if (dirp->search_handle == INVALID_HANDLE_VALUE) { + /* directory stream was opened/rewound incorrectly or it ended normally */ + errno = EBADF; + return NULL; + } +#endif + + if (dirp->dirent_filled != 0) { + /* + * Directory entry has already been retrieved and there is no need to + * retrieve a new one. Directory entry will be retrieved in advance + * when the user calls readdir function for the first time. This is so + * because real dirent has separate functions for opening and reading + * the stream whereas Win32 and DOS dirents open the stream + * automatically when we retrieve the first file. Therefore, we have to + * save the first file when opening the stream and later we have to + * return the saved entry when the user tries to read the first entry. + */ + dirp->dirent_filled = 0; + } else { + /* fill in entry and return that */ +#if defined(DIRENT_WIN32_INTERFACE) + if (FindNextFile(dirp->search_handle, &dirp->current.data) == FALSE) { + /* Last file has been processed or an error occurred */ + FindClose(dirp->search_handle); + dirp->search_handle = INVALID_HANDLE_VALUE; + errno = ENOENT; + return NULL; + } + +# elif defined(DIRENT_MSDOS_INTERFACE) + if (_dos_findnext(&dirp->current.data) != 0) { + /* _dos_findnext and findnext will set errno to ENOENT when no + * more entries could be retrieved. */ + return NULL; + } +# endif + + _setdirname(dirp); + assert(dirp->dirent_filled == 0); + } + return &dirp->current; +} + + +/* + * <function name="closedir"> + * <intro>close directory stream. + * <syntax>int closedir (DIR *dirp); + * + * <desc>Close directory stream opened by the `opendir' function. Close of + * directory stream invalidates the DIR structure as well as previously read + * dirent entry. + * + * <ret>The function typically returns 0 on success and -1 on failure but + * the function may be declared to return void on same systems. At least + * Borland C/C++ and some UNIX implementations use void as a return type. + * The dirent wrapper tries to define VOID_CLOSEDIR whenever closedir is + * known to return nothing. The very same definition is made by the GNU + * autoconf if you happen to use it. + * + * The global `errno' variable will set to EBADF in case of error. + * </function> + */ +static int +closedir(DIR *dirp) +{ + int retcode = 0; + + /* make sure that dirp points to legal structure */ + assert(dirp != NULL); + if (dirp == NULL) { + errno = EBADF; + return -1; + } + + /* free directory name and search handles */ + if (dirp->dirname != NULL) { + free(dirp->dirname); + } + +#if defined(DIRENT_WIN32_INTERFACE) + if (dirp->search_handle != INVALID_HANDLE_VALUE) { + if (FindClose(dirp->search_handle) == FALSE) { + /* Unknown error */ + retcode = -1; + errno = EBADF; + } + } +#endif + + /* clear dirp structure to make sure that it cannot be used anymore*/ + memset(dirp, 0, sizeof(*dirp)); +# if defined(DIRENT_WIN32_INTERFACE) + dirp->search_handle = INVALID_HANDLE_VALUE; +# endif + + free(dirp); + return retcode; +} + + +/* + * <function name="rewinddir"> + * <intro>rewind directory stream to the beginning + * <syntax>void rewinddir (DIR *dirp); + * + * <desc>Rewind directory stream to the beginning so that the next call of + * readdir() returns the very first directory entry again. However, note + * that next call of readdir() may not return the same directory entry as it + * did in first time. The directory stream may have been affected by newly + * created files. + * + * Almost every dirent implementation ensure that rewinddir will update + * the directory stream to reflect any changes made to the directory entries + * since the previous ``opendir'' or ``rewinddir'' call. Keep an eye on + * this if your program depends on the feature. I know at least one dirent + * implementation where you are required to close and re-open the stream to + * see the changes. + * + * <ret>Returns nothing. If something went wrong while rewinding, you will + * notice it later when you try to retrieve the first directory entry. + */ +static void +rewinddir(DIR *dirp) +{ + /* make sure that dirp is legal */ + assert(dirp != NULL); + if (dirp == NULL) { + errno = EBADF; + return; + } + assert(dirp->dirname != NULL); + + /* close previous stream */ +#if defined(DIRENT_WIN32_INTERFACE) + if (dirp->search_handle != INVALID_HANDLE_VALUE) { + if (FindClose(dirp->search_handle) == FALSE) { + /* Unknown error */ + errno = EBADF; + } + } +#endif + + /* re-open previous stream */ + if (_initdir(dirp) == 0) { + /* initialization failed but we cannot deal with error. User will notice + * error later when she tries to retrieve first directory enty. */ + /*EMPTY*/; + } +} + + +/* + * Open native directory stream object and retrieve first file. + * Be sure to close previous stream before opening new one. + */ +static int +_initdir(DIR *dirp) +{ + assert(dirp != NULL); + assert(dirp->dirname != NULL); + dirp->dirent_filled = 0; + +# if defined(DIRENT_WIN32_INTERFACE) + /* Open stream and retrieve first file */ + dirp->search_handle = FindFirstFile(dirp->dirname, &dirp->current.data); + if (dirp->search_handle == INVALID_HANDLE_VALUE) { + /* something went wrong but we don't know what. GetLastError() could + * give us more information about the error, but then we should map + * the error code into errno. */ + errno = ENOENT; + return 0; + } + +# elif defined(DIRENT_MSDOS_INTERFACE) + if (_dos_findfirst(dirp->dirname, + _A_SUBDIR | _A_RDONLY | _A_ARCH | _A_SYSTEM | _A_HIDDEN, + &dirp->current.data) != 0) { + /* _dos_findfirst and findfirst will set errno to ENOENT when no + * more entries could be retrieved. */ + return 0; + } +# endif + + /* initialize DIR and it's first entry */ + _setdirname(dirp); + dirp->dirent_filled = 1; + return 1; +} + + +/* + * Return implementation dependent name of the current directory entry. + */ +static const char * +_getdirname(const struct dirent *dp) +{ +#if defined(DIRENT_WIN32_INTERFACE) + return dp->data.cFileName; + +#elif defined(DIRENT_USE_FFBLK) + return dp->data.ff_name; + +#else + return dp->data.name; +#endif +} + + +/* + * Copy name of implementation dependent directory entry to the d_name field. + */ +static void +_setdirname(struct DIR *dirp) +{ + /* make sure that d_name is long enough */ + assert(strlen(_getdirname(&dirp->current)) <= NAME_MAX); + + strncpy(dirp->current.d_name, + _getdirname(&dirp->current), + NAME_MAX); + dirp->current.d_name[NAME_MAX] = '\0'; /*char d_name[NAME_MAX+1]*/ +} + +# ifdef __cplusplus +} +# endif +# define NAMLEN(dp) ((int)(strlen((dp)->d_name))) + +#else +# error "missing dirent interface" +#endif + + +#endif /*DIRENT_H*/ diff --git a/openjpeg/src/bin/mj2/CMakeLists.txt b/openjpeg/src/bin/mj2/CMakeLists.txt new file mode 100644 index 000000000..5d3e288b6 --- /dev/null +++ b/openjpeg/src/bin/mj2/CMakeLists.txt @@ -0,0 +1,47 @@ +# Makefile for the MJ2 codecs of the OpenJPEG library: frames_to_mj2, mj2_to_frames, extract_j2k_from_mj2 and wrap_j2k_in_mj2 + +set(common_SRCS ${OPENJPEG_SOURCE_DIR}/src/bin/common/opj_getopt.c) + +if(WIN32) + if(BUILD_SHARED_LIBS) + add_definitions(-DOPJ_EXPORTS) + else() + add_definitions(-DOPJ_STATIC) + endif() +endif() + +# Headers file are located here: +include_directories( + ${OPENJPEG_BINARY_DIR}/src/lib/openjp2 # opj_config.h + ${OPENJPEG_BINARY_DIR}/src/bin/common # opj_apps_config.h + ${OPENJPEG_SOURCE_DIR}/src/lib/openmj2 + ${OPENJPEG_SOURCE_DIR}/src/bin/common + ${LCMS_INCLUDE_DIRNAME} + ) + +foreach(exe + opj_mj2_wrap + opj_mj2_extract + opj_mj2_decompress + opj_mj2_compress +) + add_definitions(-DOPJ_USE_LEGACY) + add_executable(${exe} + ${exe}.c + ${common_SRCS} + ${MJ2_SRCS} + ${OPENJPEG_SOURCE_DIR}/src/bin/common/color.c + ) + set_property( + TARGET ${exe} + APPEND PROPERTY COMPILE_DEFINITIONS USE_MJ2 + ) + target_link_libraries(${exe} ${LCMS_LIBNAME} openmj2) + + if(UNIX) + target_link_libraries(${exe} m) + endif() + + install(TARGETS ${exe} + DESTINATION ${OPENJPEG_INSTALL_BIN_DIR}) +endforeach() diff --git a/openjpeg/src/bin/mj2/meta_out.c b/openjpeg/src/bin/mj2/meta_out.c new file mode 100644 index 000000000..2c0e27377 --- /dev/null +++ b/openjpeg/src/bin/mj2/meta_out.c @@ -0,0 +1,2858 @@ +/* meta_out.c */ +/* Dump MJ2, JP2 metadata (partial so far) to xml file */ +/* Callable from mj2_to_metadata */ +/* Contributed to Open JPEG by Glenn Pearson, contract software developer, U.S. National Library of Medicine. + +The base code in this file was developed by the author as part of a video archiving +project for the U.S. National Library of Medicine, Bethesda, MD. +It is the policy of NLM (and U.S. government) to not assert copyright. + +A non-exclusive copy of this code has been contributed to the Open JPEG project. +Except for copyright, inclusion of the code within Open JPEG for distribution and use +can be bound by the Open JPEG open-source license and disclaimer, expressed elsewhere. +*/ + +#include <windows.h> /* for time functions */ + +#include "opj_includes.h" +#include "mj2.h" + +#include <time.h> +#include "meta_out.h" + +static BOOL notes = TRUE; +static BOOL sampletables = FALSE; +static BOOL raw = TRUE; +static BOOL derived = TRUE; + +opj_tcp_t *j2k_default_tcp; + +/* Forwards */ +int xml_write_overall_header(FILE *file, FILE *xmlout, opj_mj2_t * movie, + unsigned int sampleframe, opj_event_mgr_t *event_mgr); +int xml_write_moov(FILE *file, FILE *xmlout, opj_mj2_t * movie, + unsigned int sampleframe, opj_event_mgr_t *event_mgr); + +void uint_to_chars(unsigned int value, char* buf); + +void xml_write_trak(FILE* file, FILE* xmlout, mj2_tk_t *track, + unsigned int tnum, unsigned int sampleframe, opj_event_mgr_t *event_mgr); +void xml_write_tkhd(FILE* file, FILE* xmlout, mj2_tk_t *track, + unsigned int tnum); +void xml_write_udta(FILE* file, FILE* xmlout, mj2_tk_t *track, + unsigned int tnum); +void xml_write_mdia(FILE* file, FILE* xmlout, mj2_tk_t *track, + unsigned int tnum); +void xml_write_stbl(FILE* file, FILE* xmlout, mj2_tk_t *track, + unsigned int tnum); + +void UnixTimeToFileTime(time_t t, LPFILETIME pft); +void UnixTimeToSystemTime(time_t t, LPSYSTEMTIME pst); +void xml_time_out(FILE* xmlout, time_t t); + +void int16_to_3packedchars(short int value, char* buf); + +void xml_write_moov_udta(FILE* xmlout, opj_mj2_t * movie); +void xml_write_free_and_skip(FILE* xmlout, opj_mj2_t * movie); +void xml_write_uuid(FILE* xmlout, opj_mj2_t * movie); + +int xml_out_frame(FILE* file, FILE* xmlout, mj2_sample_t *sample, + unsigned int snum, opj_event_mgr_t *event_mgr); + +void xml_out_frame_siz(FILE* xmlout, opj_image_t *img, opj_cp_t *cp); +void xml_out_frame_cod(FILE* xmlout, opj_tcp_t *tcp); +void xml_out_frame_coc(FILE* xmlout, opj_tcp_t *tcp, + int numcomps); /* opj_image_t *img); */ +BOOL same_component_style(opj_tccp_t *tccp1, opj_tccp_t *tccp2); +void xml_out_frame_qcd(FILE* xmlout, opj_tcp_t *tcp); +void xml_out_frame_qcc(FILE* xmlout, opj_tcp_t *tcp, + int numcomps); /* opj_image_t *img); */ +BOOL same_component_quantization(opj_tccp_t *tccp1, opj_tccp_t *tccp2); +void xml_out_frame_rgn(FILE* xmlout, opj_tcp_t *tcp, + int numcomps);/* opj_image_t *img);*/ +void xml_out_frame_poc(FILE* xmlout, opj_tcp_t *tcp); +void xml_out_frame_ppm(FILE* xmlout, opj_cp_t *cp); +void xml_out_frame_ppt(FILE* xmlout, opj_tcp_t *tcp); +void xml_out_frame_tlm(FILE* + xmlout); /* j2k_default_tcp is passed globally */ /* NO-OP. TLM NOT SAVED IN DATA STRUCTURE */ +void xml_out_frame_plm(FILE* + xmlout); /* j2k_default_tcp is passed globally */ /* NO-OP. PLM NOT SAVED IN DATA STRUCTURE. opt in main; can be used in conjunction with PLT */ +void xml_out_frame_plt(FILE* xmlout, + opj_tcp_t *tcp); /* NO-OP. PLM NOT SAVED IN DATA STRUCTURE. opt in main; can be used in conjunction with PLT */ +void xml_out_frame_crg(FILE* + xmlout); /* j2k_default_tcp is passed globally */ /* opt in main; */ +void xml_out_frame_com(FILE* xmlout, + opj_tcp_t *tcp); /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */ /* opt in main; */ +void xml_out_dump_hex(FILE* xmlout, char *data, int data_len, char* s); +void xml_out_dump_hex_and_ascii(FILE* xmlout, char *data, int data_len, + char* s); +void xml_out_frame_jp2h(FILE* xmlout, opj_jp2_t *jp2_struct); +#ifdef NOTYET +/* Shown with cp, extended, as data structure... but it could be a new different one */ +void xml_out_frame_jp2i(FILE* xmlout, + opj_cp_t *cp);/* IntellectualProperty 'jp2i' (no restrictions on location) */ +void xml_out_frame_xml(FILE* xmlout, + opj_cp_t *cp); /* XML 'xml\040' (0x786d6c20). Can appear multiply */ +void xml_out_frame_uuid(FILE* xmlout, + opj_cp_t *cp); /* UUID 'uuid' (top level only) */ +void xml_out_frame_uinf(FILE* xmlout, + opj_cp_t *cp); /* UUIDInfo 'uinf', includes UUIDList 'ulst' and URL 'url\40' */ +void xml_out_frame_unknown_type(FILE* xmlout, opj_cp_t *cp); +#endif + + +void xml_write_init(BOOL n, BOOL t, BOOL r, BOOL d) +{ + /* Init file globals */ + notes = n; + sampletables = t; + raw = r; + derived = d; +} + +int xml_write_struct(FILE* file, FILE *xmlout, opj_mj2_t * movie, + unsigned int sampleframe, char* stringDTD, opj_event_mgr_t *event_mgr) +{ + + if (stringDTD != NULL) { + fprintf(xmlout, "<?xml version=\"1.0\" standalone=\"no\"?>\n"); + /* stringDTD is known to start with "SYSTEM " or "PUBLIC " */ + /* typical: SYSTEM mj2_to_metadata.dtd */ + stringDTD[6] = + '\0'; /* Break into two strings at space, so quotes can be inserted. */ + fprintf(xmlout, "<!DOCTYPE MJ2_File %s \"%s\">\n", stringDTD, stringDTD + 7); + stringDTD[6] = ' '; /* restore for sake of debugger or memory allocator */ + } else { + fprintf(xmlout, "<?xml version=\"1.0\" standalone=\"yes\"?>\n"); + } + + fprintf(xmlout, "<MJ2_File>\n"); + xml_write_overall_header(file, xmlout, movie, sampleframe, event_mgr); + fprintf(xmlout, "</MJ2_File>"); + return 0; +} + +/* ------------- */ + +int xml_write_overall_header(FILE *file, FILE *xmlout, opj_mj2_t * movie, + unsigned int sampleframe, opj_event_mgr_t *event_mgr) +{ + int i; + char buf[5]; + buf[4] = '\0'; + + fprintf(xmlout, + " <JP2 BoxType=\"jP[space][space]\" Signature=\"0x0d0a870a\" />\n"); + // Called after structure initialized by mj2_read_ftyp + fprintf(xmlout, " <FileType BoxType=\"ftyp\">\n"); + uint_to_chars(movie->brand, buf); + fprintf(xmlout, " <Brand>%s</Brand>\n", + buf); /* 4 character; BR */ + fprintf(xmlout, " <MinorVersion>%u</MinorVersion>\n", + movie->minversion); /* 4 char; MinV */ + fprintf(xmlout, " <CompatibilityList Count=\"%d\">\n", movie->num_cl); + for (i = movie->num_cl - 1; i > -1; + i--) { /* read routine stored in reverse order, so let's undo damage */ + uint_to_chars(movie->cl[i], buf); + fprintf(xmlout, " <CompatibleBrand>%s</CompatibleBrand>\n", + buf); /*4 characters, each CLi */ + } + fprintf(xmlout, " </CompatibilityList>\n"); + fprintf(xmlout, " </FileType>\n"); + xml_write_moov(file, xmlout, movie, sampleframe, event_mgr); + // To come? <mdat> // This is the container for media data that can also be accessed through track structures, + // so is redundant, and simply not of interest as metadata + // <moof> // Allows incremental build up of movie. Probably not in Simple Profile + xml_write_free_and_skip(xmlout, + movie); /* NO OP so far */ /* May be a place where user squirrels metadata */ + xml_write_uuid(xmlout, + movie); /* NO OP so far */ /* May be a place where user squirrels metadata */ + return 0; +} + +/* ------------- */ + +int xml_write_moov(FILE *file, FILE *xmlout, opj_mj2_t * movie, + unsigned int sampleframe, opj_event_mgr_t *event_mgr) +{ + unsigned int tnum; + mj2_tk_t *track; + + fprintf(xmlout, " <MovieBox BoxType=\"moov\">\n"); + fprintf(xmlout, " <MovieHeader BoxType=\"mvhd\">\n"); + fprintf(xmlout, " <CreationTime>\n"); + if (raw) { + fprintf(xmlout, " <InSeconds>%u</InSeconds>\n", movie->creation_time); + } + if (notes) { + fprintf(xmlout, + " <!-- Seconds since start of Jan. 1, 1904 UTC (Greenwich) -->\n"); + } + /* 2082844800 = seconds between 1/1/04 and 1/1/70 */ + /* There's still a time zone offset problem not solved... but spec is ambiguous as to whether stored time + should be local or UTC */ + if (derived) { + fprintf(xmlout, " <AsLocalTime>"); + xml_time_out(xmlout, movie->creation_time - 2082844800); + fprintf(xmlout, "</AsLocalTime>\n"); + } + fprintf(xmlout, " </CreationTime>\n"); + fprintf(xmlout, " <ModificationTime>\n"); + if (raw) { + fprintf(xmlout, " <InSeconds>%u</InSeconds>\n", + movie->modification_time); + } + if (derived) { + fprintf(xmlout, " <AsLocalTime>"); + xml_time_out(xmlout, movie->modification_time - 2082844800); + fprintf(xmlout, "</AsLocalTime>\n"); + } + fprintf(xmlout, " </ModificationTime>\n"); + fprintf(xmlout, " <Timescale>%d</Timescale>\n", movie->timescale); + if (notes) { + fprintf(xmlout, " <!-- Timescale defines time units in one second -->\n"); + } + fprintf(xmlout, + " <Rate>\n"); /* Rate to play presentation (default = 0x00010000) */ + if (notes) { + fprintf(xmlout, + " <!-- Rate to play presentation is stored as fixed-point binary 16.16 value. Decimal value is approximation. -->\n"); + fprintf(xmlout, + " <!-- Rate is expressed relative to normal (default) value of 0x00010000 (1.0) -->\n"); + } + if (raw) { + fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n", movie->rate); + } + if (derived) { + fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n", + (double)movie->rate / (double)0x00010000); + } + fprintf(xmlout, " </Rate>\n"); + fprintf(xmlout, " <Duration>\n"); + if (raw) { + fprintf(xmlout, " <InTimeUnits>%u</InTimeUnits>\n", movie->duration); + } + if (derived) { + fprintf(xmlout, " <InSeconds>%12.3f</InSeconds>\n", + (double)movie->duration / (double) + movie->timescale); // Make this double later to get fractional seconds + } + fprintf(xmlout, " </Duration>\n"); +#ifdef CURRENTSTRUCT + movie->volume = movie->volume << 8; +#endif + fprintf(xmlout, " <Volume>\n"); + if (notes) { + fprintf(xmlout, + " <!-- Audio volume stored as fixed-point binary 8.8 value. Decimal value is approximation. -->\n"); + fprintf(xmlout, + " <!-- Full, normal (default) value is 0x0100 (1.0) -->\n"); + } + if (raw) { + fprintf(xmlout, " <AsHex>0x%04x</AsHex>\n", movie->volume); + } + if (derived) { + fprintf(xmlout, " <AsDecimal>%6.3f</AsDecimal>\n", + (double)movie->volume / (double)0x0100); + } + fprintf(xmlout, " </Volume>\n"); +#ifdef CURRENTSTRUCT + if (notes) { + fprintf(xmlout, + " <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n"); + } + movie->volume = movie->volume >> 8; +#endif + /* Transformation matrix for video */ + fprintf(xmlout, " <TransformationMatrix>\n"); + if (notes) { + fprintf(xmlout, + " <!-- 3 x 3 Video Transformation Matrix {a,b,u,c,d,v,x,y,w}. Required: u=0, v=0, w=1 -->\n"); + fprintf(xmlout, + " <!-- Maps decompressed point (p,q) to rendered point (ap + cq + x, bp + dq + y) -->\n"); + fprintf(xmlout, + " <!-- Stored as Fixed Point Hex: all are binary 16.16, except u,v,w are 2.30 -->\n"); + fprintf(xmlout, + " <!-- Unity = 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 -->\n"); + } + fprintf(xmlout, " <TMa>0x%08x</TMa>\n", movie->trans_matrix[0]); + fprintf(xmlout, " <TMb>0x%08x</TMb>\n", movie->trans_matrix[1]); + fprintf(xmlout, " <TMu>0x%08x</TMu>\n", movie->trans_matrix[2]); + fprintf(xmlout, " <TMc>0x%08x</TMc>\n", movie->trans_matrix[3]); + fprintf(xmlout, " <TMd>0x%08x</TMd>\n", movie->trans_matrix[4]); + fprintf(xmlout, " <TMv>0x%08x</TMv>\n", movie->trans_matrix[5]); + fprintf(xmlout, " <TMx>0x%08x</TMx>\n", movie->trans_matrix[6]); + fprintf(xmlout, " <TMy>0x%08x</TMy>\n", movie->trans_matrix[7]); + fprintf(xmlout, " <TMw>0x%08x</TMw>\n", movie->trans_matrix[8]); + fprintf(xmlout, " </TransformationMatrix>\n"); + fprintf(xmlout, " </MovieHeader>\n"); + + fprintf(xmlout, " <Statistics>\n"); + fprintf(xmlout, " <TracksFound>\n"); + fprintf(xmlout, " <Video>%d</Video>\n", movie->num_vtk); + fprintf(xmlout, " <Audio>%d</Audio>\n", movie->num_stk); + fprintf(xmlout, " <Hint>%d</Hint>\n", movie->num_htk); + if (notes) { + fprintf(xmlout, + " <!-- Hint tracks for streaming video are not part of MJ2, but are a defined extension. -->\n"); + } + /* See Part 3 Amend 2 Section 4.2 for relation of MJ2 to Part 12 Sections 7 and 10 hints */ + fprintf(xmlout, " </TracksFound>\n"); + fprintf(xmlout, " </Statistics>\n"); + /* Idea for the future: It would be possible to add code to verify that the file values: + 1) are legal and self-consistent + 2) comply with particular JP2 and/or MJ2 profiles. + This could be reported here as additional XML elements */ + + // Find first video track + tnum = 0; + while (movie->tk[tnum].track_type != 0) { + tnum ++; + } + + track = &(movie->tk[tnum]); + // For now, output info on first video track + xml_write_trak(file, xmlout, track, tnum, sampleframe, event_mgr); + + // to come: <MovieExtends mvek> // possibly not in Simple Profile + xml_write_moov_udta(xmlout, + movie); /* NO OP so far */ /* <UserDataBox udta> contains <CopyrightBox cprt> */ + fprintf(xmlout, " </MovieBox>\n"); + return 0; +} + +/* --------------- */ + +void uint_to_chars(unsigned int value, char* buf) +{ + /* buf is at least char[5] */ + int i; + for (i = 3; i >= 0; i--) { + buf[i] = (value & 0x000000ff); + value = (value >> 8); + } + buf[4] = '\0'; /* Precautionary */ +} + +/* ------------- */ + +/* WINDOWS SPECIFIC */ + +void UnixTimeToFileTime(time_t t, LPFILETIME pft) +{ + /* Windows specific. From MS Q167296 */ + /* 'time_t' represents seconds since midnight January 1, 1970 UTC (coordinated universal time). */ + /* 64-bit FILETIME structure represents the number of 100-nanosecond intervals since January 1, 1601 UTC (coordinate universal time). */ + LONGLONG ll; /* LONGLONG is a 64-bit value. */ + ll = Int32x32To64(t, 10000000) + 116444736000000000; + pft->dwLowDateTime = (DWORD)ll; + /* pft->dwLowDateTime = (DWORD)(0x00000000ffffffff & ll); */ + pft->dwHighDateTime = (DWORD)(ll >> 32); +} +// Once the UNIX time is converted to a FILETIME structure, +// other Win32 time formats can be easily obtained by using Win32 functions such +// as FileTimeToSystemTime() and FileTimeToDosDateTime(). + +/* ------------- */ + +void UnixTimeToSystemTime(time_t t, LPSYSTEMTIME pst) +{ + /* Windows specific */ + FILETIME ft; + UnixTimeToFileTime(t, &ft); + FileTimeToLocalFileTime(&ft, &ft); /* Adjust from UTC to local time zone */ + FileTimeToSystemTime(&ft, pst); +} + +/* ------------- */ + +void xml_time_out(FILE* xmlout, time_t t) +{ + /* Windows specific */ + SYSTEMTIME st; + char szLocalDate[255], szLocalTime[255]; + UnixTimeToSystemTime(t, &st); + GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, szLocalDate, 255); + GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, szLocalTime, 255); + fprintf(xmlout, "%s %s", szLocalDate, szLocalTime); +} + +/* END WINDOWS SPECIFIC */ + +/* ------------- */ + +void xml_write_moov_udta(FILE* xmlout, opj_mj2_t * movie) +{ + /* Compare with xml_write_udta */ +#ifdef NOTYET + /* NO-OP so far. Optional UserData 'udta' (zero or one in moov or each trak) + can contain multiple Copyright 'cprt' with different language codes */ + /* There may be nested non-standard boxes within udta */ + IMAGINE movie->udta, movie->copyright_count, + movie->copyright_language[i](array of 16bit ints), + movie->copyright_notice[i](array of buffers) + PROBABLY ALSO NEED movie->udta_len or special handler for non - standard boxes + char buf[5]; + int i; + + if (movie->udta != 1) { + return; /* Not present */ + } + + fprintf(xmlout, " <UserData BoxType=\"udta\">\n"); + for (i = 0; i < movie->copyright_count; i++) { + fprintf(xmlout, " <Copyright BoxType=\"cprt\"> Instance=\"%d\">\n", + i + 1); + int16_to_3packedchars((short int)movie->copyright_languages[i], buf); + fprintf(xmlout, " <Language>%s</Language>\n", buf); /* 3 chars */ + fprintf(xmlout, " <Notice>%s</Notice>\n", movie->copyright_notices[i]); + fprintf(xmlout, " </Copyright>\n", i + 1); + } + /* TO DO: Non-standard boxes */ + fprintf(xmlout, " </UserData>\n"); +#endif +} + +void xml_write_free_and_skip(FILE* xmlout, opj_mj2_t * movie) +{ +#ifdef NOTYET + /* NO-OP so far. There can be zero or more instances of free and/or skip + at the top level of the file. This may be a place where the user squirrel's metadata. + Let's assume unstructured, and do a dump */ + IMAGINE movie->free_and_skip, movie->free_and_skip_count, + movie->free_and_skip_content[i](array of buffers), + movie->free_and_skip_len[i](array of ints), movie->is_skip[i](array of BOOL) + int i; + + if (movie->free_and_skip != 1) { + return; /* Not present */ + } + + for (i = 0; i < movie->free_and_skip_count; i++) { + if (movie->is_skip[i]) { + fprintf(xmlout, " <Skip BoxType=\"skip\">\n"); + } else { + fprintf(xmlout, " <Free BoxType=\"free\">\n"); + } + + xml_out_dump_hex_and_ascii(xmlout, movie->free_and_skip_contents[i], + movie->free_and_skip_len[i]); + + if (movie->is_skip[i]) { + fprintf(xmlout, " </Skip>\n"); + } else { + fprintf(xmlout, " </Free>\n"); + } + } +#endif +} + +void xml_write_uuid(FILE* xmlout, opj_mj2_t * movie) +{ + /* Universal Unique IDs of 16 bytes. */ +#ifdef NOTYET + /* NO-OP so far. There can be zero or more instances of private uuid boxes in a file. + This function supports the top level of the file, but uuid may be elsewhere [not yet supported]. + This may be a place where the user squirrel's metadata. Let's assume unstructured, and do a dump */ + IMAGINE movie->uuid, movie->uuid_count, + movie->uuid_content[i](array of buffers), + movie->uuid_len[i](array of ints), + movie->uuid_type[i](array of 17 - byte(16 + null termination) buffers) + int i; + + if (movie->uuid != 1) { + return; /* Not present */ + } + + for (i = 0; i < movie->uuid_count; i++) { + fprintf(xmlout, " <PrivateExtension BoxType=\"uuid\" UUID=\"%s\">\n", + movie->uuid_type[i]); + // See Part III section 5.2.1, 6.1, 6.2 + xml_out_dump_hex_and_ascii(xmlout, movie->uuid_contents[i], movie->uuid_len[i]); + fprintf(xmlout, " </PrivateExtension>\n"); + } +#endif +} + +/* ------------- */ + +void xml_write_trak(FILE* file, FILE* xmlout, mj2_tk_t *track, + unsigned int tnum, unsigned int sampleframe, opj_event_mgr_t *event_mgr) +{ + fprintf(xmlout, " <Track BoxType=\"trak\" Instance=\"%d\">\n", tnum); + xml_write_tkhd(file, xmlout, track, tnum); + // TO DO: TrackReferenceContainer 'tref' just used in hint track + // TO DO: EditListContainer 'edts', contains EditList 'elst' with media-time, segment-duration, media-rate + xml_write_mdia(file, xmlout, track, tnum); + xml_write_udta(file, xmlout, track, + tnum); // NO-OP so far. Optional UserData 'udta', can contain multiple Copyright 'cprt' + + if (track->track_type == 0) { /* Only do for visual track */ + /* sampleframe is from user option -f. 1 = first frame */ + /* sampleframe of 0 is a user requests: no jp2 header */ + /* Treat out-of-bounds values in the same way */ + if (sampleframe > 0 && sampleframe <= track->num_samples) { + mj2_sample_t *sample; + unsigned int snum; + + snum = sampleframe - 1; + // Someday maybe do a smart range scan... for (snum=0; snum < track->num_samples; snum++){ + // fprintf(stdout,"Frame %d: ",snum+1); + sample = &track->sample[snum]; + if (xml_out_frame(file, xmlout, sample, snum, event_mgr)) { + return; /* Not great error handling here */ + } + } + } + fprintf(xmlout, " </Track>\n"); +} + +/* ------------- */ + +void xml_write_tkhd(FILE* file, FILE* xmlout, mj2_tk_t *track, + unsigned int tnum) +{ + fprintf(xmlout, " <TrackHeader BoxType=\"tkhd\">\n"); + if (notes) { + fprintf(xmlout, + " <!-- Not shown here: CreationTime, ModificationTime, Duration. -->\n"); + fprintf(xmlout, + " <!-- These 3 fields are reported under MediaHeader below. When reading these 3, -->\n"); + fprintf(xmlout, + " <!-- m2j_to_metadata currently doesn't distinguish between TrackHeader and MediaHeader source. -->\n"); + fprintf(xmlout, + " <!-- If both found, value read from MediaHeader is used. -->\n"); + } + fprintf(xmlout, " <TrackID>%u</TrackID>\n", track->track_ID); + if (track->track_type == 0) { /* For visual track */ + fprintf(xmlout, " <TrackLayer>%d</TrackLayer>\n", track->layer); + if (notes) { + fprintf(xmlout, + " <!-- front-to-back ordering of video tracks. 0 = normal, -1 is closer, etc. -->\n"); + } + } + if (track->track_type != 0) { /* volume irrelevant for visual track */ +#ifdef CURRENTSTRUCT + track->volume = track->volume << 8; +#endif + fprintf(xmlout, " <Volume>\n"); + if (notes) { + fprintf(xmlout, + " <!-- Track audio volume stored as fixed-point binary 8.8 value. Decimal value is approximation. -->\n"); + fprintf(xmlout, + " <!-- Full, normal (default) value is 0x0100 (1.0) -->\n"); + } + if (raw) { + fprintf(xmlout, " <AsHex>0x%04x</AsHex>\n", track->volume); + } + if (derived) { + fprintf(xmlout, " <AsDecimal>%6.3f</AsDecimal>\n", + (double)track->volume / (double)0x0100); + } + fprintf(xmlout, " </Volume>\n"); +#ifdef CURRENTSTRUCT + if (notes) { + fprintf(xmlout, + " <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n"); + } + track->volume = track->volume >> 8; +#endif + } + if (track->track_type == 0) { + /* Transformation matrix for video */ + fprintf(xmlout, " <TransformationMatrix>\n"); + if (notes) { + fprintf(xmlout, + " <!-- Comments about matrix in MovieHeader apply here as well. -->\n"); + fprintf(xmlout, + " <!-- This matrix is applied before MovieHeader one. -->\n"); + } + fprintf(xmlout, " <TMa>0x%08x</TMa>\n", track->trans_matrix[0]); + fprintf(xmlout, " <TMb>0x%08x</TMb>\n", track->trans_matrix[1]); + fprintf(xmlout, " <TMu>0x%08x</TMu>\n", track->trans_matrix[2]); + fprintf(xmlout, " <TMc>0x%08x</TMc>\n", track->trans_matrix[3]); + fprintf(xmlout, " <TMd>0x%08x</TMd>\n", track->trans_matrix[4]); + fprintf(xmlout, " <TMv>0x%08x</TMv>\n", track->trans_matrix[5]); + fprintf(xmlout, " <TMx>0x%08x</TMx>\n", track->trans_matrix[6]); + fprintf(xmlout, " <TMy>0x%08x</TMy>\n", track->trans_matrix[7]); + fprintf(xmlout, " <TMw>0x%08x</TMw>\n", track->trans_matrix[8]); + fprintf(xmlout, " </TransformationMatrix>\n"); + } +#ifdef CURRENTSTRUCT + track->w = track->w << 16; + track->h = track->h << 16; +#endif + if (notes) { + fprintf(xmlout, + " <!-- Width and Height in pixels are for the presentation; frames will be scaled to this. -->\n"); + fprintf(xmlout, + " <!-- Both stored as fixed-point binary 16.16 values. Decimal values are approximations. -->\n"); + } + fprintf(xmlout, " <Width>\n"); + if (raw) { + fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n", track->w); + } + if (derived) { + fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n", + (double)track->w / (double) + 0x00010000); /* Rate to play presentation (default = 0x00010000) */ + } + fprintf(xmlout, " </Width>\n"); + fprintf(xmlout, " <Height>\n"); + if (raw) { + fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n", track->h); + } + if (derived) { + fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n", + (double)track->h / (double) + 0x00010000); /* Rate to play presentation (default = 0x00010000) */ + } + fprintf(xmlout, " </Height>\n"); +#ifdef CURRENTSTRUCT + if (notes) { + fprintf(xmlout, + " <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n"); + fprintf(xmlout, + " <!-- Also, width and height values shown here will actually be those read from track's <VisualSampleEntry> if given. -->\n"); + } + track->w = track->w >> 16; + track->h = track->h >> 16; +#endif + fprintf(xmlout, " </TrackHeader>\n"); +} + +/* ------------- */ + +void xml_write_udta(FILE* file, FILE* xmlout, mj2_tk_t *track, + unsigned int tnum) +{ + /* NO-OP so far. Optional UserData 'udta' (zero or one in moov or each trak) + can contain multiple Copyright 'cprt' with different language codes */ + /* There may be nested non-standard boxes within udta */ +#ifdef NOTYET + IMAGINE track->udta, track->copyright_count, + track->copyright_language[i](array of 16bit ints), + track->copyright_notice[i](array of buffers) + PROBABLY ALSO NEED track->udta_len or special handler for non - standard boxes + char buf[5]; + int i; + + if (track->udta != 1) { + return; /* Not present */ + } + + fprintf(xmlout, " <UserData BoxType=\"udta\">\n"); + for (i = 0; i < track->copyright_count; i++) { + fprintf(xmlout, " <Copyright BoxType=\"cprt\"> Instance=\"%d\">\n", + i + 1); + int16_to_3packedchars((short int)track->copyright_languages[i], buf); + fprintf(xmlout, " <Language>%s</Language>\n", buf); /* 3 chars */ + fprintf(xmlout, " <Notice>%s</Notice>\n", + track->copyright_notices[i]); + fprintf(xmlout, " </Copyright>\n", i + 1); + } + /* TO DO: Non-standard boxes */ + fprintf(xmlout, " </UserData>\n"); +#endif +} + +/* ------------- */ + +void xml_write_mdia(FILE* file, FILE* xmlout, mj2_tk_t *track, + unsigned int tnum) +{ + char buf[5]; + int i, k; + buf[4] = '\0'; + + fprintf(xmlout, " <Media BoxType=\"mdia\">\n"); + fprintf(xmlout, " <MediaHeader BoxType=\"mdhd\">\n"); + fprintf(xmlout, " <CreationTime>\n"); + if (raw) { + fprintf(xmlout, " <InSeconds>%u</InSeconds>\n", + track->creation_time); + } + if (notes) { + fprintf(xmlout, + " <!-- Seconds since start of Jan. 1, 1904 UTC (Greenwich) -->\n"); + } + /* 2082844800 = seconds between 1/1/04 and 1/1/70 */ + /* There's still a time zone offset problem not solved... but spec is ambiguous as to whether stored time + should be local or UTC */ + if (derived) { + fprintf(xmlout, " <AsLocalTime>"); + xml_time_out(xmlout, track->creation_time - 2082844800); + fprintf(xmlout, "</AsLocalTime>\n"); + } + fprintf(xmlout, " </CreationTime>\n"); + fprintf(xmlout, " <ModificationTime>\n"); + if (raw) { + fprintf(xmlout, " <InSeconds>%u</InSeconds>\n", + track->modification_time); + } + if (derived) { + fprintf(xmlout, " <AsLocalTime>"); + xml_time_out(xmlout, track->modification_time - 2082844800); + fprintf(xmlout, "</AsLocalTime>\n"); + } + fprintf(xmlout, " </ModificationTime>\n"); + fprintf(xmlout, " <Timescale>%d</Timescale>\n", track->timescale); + if (notes) { + fprintf(xmlout, + " <!-- Timescale defines time units in one second -->\n"); + } + fprintf(xmlout, " <Duration>\n"); + if (raw) { + fprintf(xmlout, " <InTimeUnits>%u</InTimeUnits>\n", + track->duration); + } + if (derived) { + fprintf(xmlout, " <InSeconds>%12.3f</InSeconds>\n", + (double)track->duration / (double) + track->timescale); // Make this double later to get fractional seconds + } + fprintf(xmlout, " </Duration>\n"); + int16_to_3packedchars((short int)track->language, buf); + fprintf(xmlout, " <Language>%s</Language>\n", buf); /* 3 chars */ + fprintf(xmlout, " </MediaHeader>\n"); + fprintf(xmlout, " <HandlerReference BoxType=\"hdlr\">\n"); + switch (track->track_type) { + case 0: + fprintf(xmlout, + " <HandlerType Code=\"vide\">video media track</HandlerType>\n"); + break; + case 1: + fprintf(xmlout, " <HandlerType Code=\"soun\">Sound</HandlerType>\n"); + break; + case 2: + fprintf(xmlout, " <HandlerType Code=\"hint\">Hint</HandlerType>\n"); + break; + } + if (notes) { + fprintf(xmlout, + " <!-- String value shown is not actually read from file. -->\n"); + fprintf(xmlout, + " <!-- Shown value is one used for our encode. -->\n"); + } + fprintf(xmlout, " </HandlerReference>\n"); + fprintf(xmlout, " <MediaInfoContainer BoxType=\"minf\">\n"); + switch (track->track_type) { + case 0: + fprintf(xmlout, " <VideoMediaHeader BoxType=\"vmhd\">\n"); + fprintf(xmlout, " <GraphicsMode>0x%02x</GraphicsMode>\n", + track->graphicsmode); + if (notes) { + fprintf(xmlout, " <!-- Enumerated values of graphics mode: -->\n"); + fprintf(xmlout, " <!-- 0x00 = copy (over existing image); -->\n"); + fprintf(xmlout, + " <!-- 0x24 = transparent; 'blue-screen' this image using opcolor; -->\n"); + fprintf(xmlout, + " <!-- 0x100 = alpha; alpha-blend this image -->\n"); + /* fprintf(xmlout," <!-- 0x101 = whitealpha; alpha-blend this image, which has been blended with white; -->\n"); This was evidently dropped upon amendment */ + fprintf(xmlout, + " <!-- 0x102 = pre-multiplied black alpha; image has been already been alpha-blended with black. -->\n"); + fprintf(xmlout, + " <!-- 0x110 = component alpha; blend alpha channel(s) and color channels individually. -->\n"); + } + fprintf(xmlout, " <Opcolor>\n"); + fprintf(xmlout, " <Red>0x%02x</Red>\n", track->opcolor[0]); + fprintf(xmlout, " <Green>0x%02x</Green>\n", track->opcolor[1]); + fprintf(xmlout, " <Blue>0x%02x</Blue>\n", track->opcolor[2]); + fprintf(xmlout, " </Opcolor>\n"); + fprintf(xmlout, " </VideoMediaHeader>\n"); + break; + case 1: + fprintf(xmlout, " <SoundMediaHeader BoxType=\"smhd\">\n"); +#ifdef CURRENTSTRUCT + track->balance = track->balance << 8; +#endif + fprintf(xmlout, " <Balance>\n"); + if (notes) { + fprintf(xmlout, + " <!-- Track audio balance fixes mono track in stereo space. -->\n"); + fprintf(xmlout, + " <!-- Stored as fixed-point binary 8.8 value. Decimal value is approximation. -->\n"); + fprintf(xmlout, + " <!-- 0.0 = center, -1.0 = full left, 1.0 = full right -->\n"); + } + if (raw) { + fprintf(xmlout, " <AsHex>0x%04x</AsHex>\n", track->balance); + } + if (derived) { + fprintf(xmlout, " <AsDecimal>%6.3f</AsDecimal>\n", + (double)track->balance / (double)0x0100); + } + fprintf(xmlout, " </Balance>\n"); +#ifdef CURRENTSTRUCT + if (notes) { + fprintf(xmlout, + " <!-- Current m2j_to_metadata implementation always shows bits to right of decimal as zeroed. -->\n"); + } + track->balance = track->balance >> 8; +#endif + fprintf(xmlout, " </SoundMediaHeader>\n"); + break; + case 2: + fprintf(xmlout, " <HintMediaHeader BoxType=\"hmhd\">\n"); + fprintf(xmlout, " <MaxPDU_Size>%d</MaxPDU_Size>\n", + track->maxPDUsize); + if (notes) { + fprintf(xmlout, + " <!-- Size in bytes of largest PDU in this hint stream. -->\n"); + } + fprintf(xmlout, " <AvgPDU_Size>%d</AvgPDU_Size>\n", + track->avgPDUsize); + if (notes) { + fprintf(xmlout, + " <!-- Average size in bytes of a PDU over the entire presentation. -->\n"); + } + fprintf(xmlout, " <MaxBitRate>%d</MaxBitRate>\n", + track->maxbitrate); + if (notes) { + fprintf(xmlout, + " <!-- Maximum rate in bits per second over any window of 1 second. -->\n"); + } + fprintf(xmlout, " <AvgBitRate>%d</AvgBitRate>\n", + track->avgbitrate); + if (notes) { + fprintf(xmlout, + " <!-- Averate rate in bits per second over the entire presentation. -->\n"); + } + fprintf(xmlout, " <SlidingAvgBit>%d</SlidingAvgBitRate>\n", + track->slidingavgbitrate); + if (notes) { + fprintf(xmlout, + " <!-- Maximum rate in bits per second over any window of one minute. -->\n"); + } + fprintf(xmlout, " </HintMediaHeader>\n"); + break; + } + fprintf(xmlout, " <DataInfo BoxType=\"dinf\">\n"); + fprintf(xmlout, + " <DataReference BoxType=\"dref\" URL_Count=\"%d\" URN_Count=\"%d\">\n", + track->num_url, track->num_urn); // table w. flags, URLs, URNs + // Data structure does not distinguish between single URL, single URN, or DREF table or URLs & URNs. + // We could infer those, but for now just present everything as a DREF table. + if (notes) { + fprintf(xmlout, + " <!-- No entries here mean that file is self-contained, as required by Simple Profile. -->\n"); + } + for (k = 0; k < track->num_url; k++) { + fprintf(xmlout, + " <DataEntryUrlBox BoxType=\"url[space]\">\n"); // table w. flags, URLs, URNs + if (notes) { + fprintf(xmlout, + " <!-- Only the first 16 bytes of URL location are recorded in mj2_to_metadata data structure. -->\n"); + } + for (i = 0; i < 4; i++) { + uint_to_chars(track->url[track->num_url].location[i], buf); + fprintf(xmlout, " <Location>%s</Location>\n"); + } + fprintf(xmlout, + " </DataEntryUrlBox>\n"); // table w. flags, URLs, URNs + } + for (k = 0; k < track->num_urn; k++) { + fprintf(xmlout, + " <DataEntryUrnBox BoxType=\"urn[space]\">\n"); // table w. flags, URLs, URNs + // Only the first 16 bytes are recorded in the data structure currently. + if (notes) { + fprintf(xmlout, + " <!-- Only the first 16 bytes each of URN name and optional location are recorded in mj2_to_metadata data structure. -->\n"); + } + fprintf(xmlout, " <Name>"); + for (i = 0; i < 4; i++) { + uint_to_chars(track->urn[track->num_urn].name[i], buf); + fprintf(xmlout, "%s", buf); + } + fprintf(xmlout, "</Name>\n"); + fprintf(xmlout, " <Location>"); + for (i = 0; i < 4; i++) { + uint_to_chars(track->urn[track->num_urn].location[i], buf); + fprintf(xmlout, "%s"); + } + fprintf(xmlout, "</Location>\n"); + fprintf(xmlout, " </DataEntryUrnBox>\n"); + } + fprintf(xmlout, " </DataReference>\n"); + fprintf(xmlout, " </DataInfo>\n"); + + xml_write_stbl(file, xmlout, track, tnum); /* SampleTable */ + + fprintf(xmlout, " </MediaInfoContainer>\n"); + fprintf(xmlout, " </Media>\n"); +} + +/* ------------- */ + +void xml_write_stbl(FILE* file, FILE* xmlout, mj2_tk_t *track, + unsigned int tnum) +{ + char buf[5], buf33[33]; + int i, len; + buf[4] = '\0'; + + fprintf(xmlout, " <SampleTable BoxType=\"stbl\">\n"); + if (notes) { + fprintf(xmlout, + " <!-- What follows are specific instances of generic SampleDescription BoxType=\"stsd\" -->\n"); + } + switch (track->track_type) { + case 0: + // There could be multiple instances of this, but "entry_count" is just a local at read-time. + // And it's used wrong, too, as count of just visual type, when it's really all 3 types. + // This is referred to as "smj2" within mj2.c + fprintf(xmlout, " <VisualSampleEntry BoxType=\"mjp2\">\n"); + if (notes) { + fprintf(xmlout, + " <!-- If multiple instances of this box, only first is shown here. -->\n"); + fprintf(xmlout, + " <!-- Width and Height are in pixels. Unlike the Track Header, there is no fractional part. -->\n"); + fprintf(xmlout, + " <!-- In mj2_to_metadata implementation, the values are not represented separately from Track Header's values. -->\n"); + } + /* No shifting required. If CURRENTSTRUCT gets changed, then may need to revisit treatment of these */ + fprintf(xmlout, " <WidthAsInteger>%d</WidthAsInteger>\n", + track->w); + fprintf(xmlout, " <HeightAsInteger>%d</HeightAsInteger>\n", + track->h); +// Horizresolution and vertresolution don't require shifting, already stored right in CURRENTSTRUCT + if (notes) { + fprintf(xmlout, + " <!-- Resolutions are in pixels per inch, for the highest-resolution component (typically luminance). -->\n"); + fprintf(xmlout, + " <!-- Both stored as fixed-point binary 16.16 values. Decimal values are approximations. -->\n"); + fprintf(xmlout, + " <!-- Typical value for both resolutions is 0x00480000 (72.0) -->\n"); + } + fprintf(xmlout, " <HorizontalRes>\n"); + if (raw) { + fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n", + track->horizresolution); + } + if (derived) { + fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n", + (double)track->horizresolution / (double) + 0x00010000); /* Rate to play presentation (default = 0x00010000) */ + } + fprintf(xmlout, " </HorizontalRes>\n"); + fprintf(xmlout, " <VerticalRes>\n"); + if (raw) { + fprintf(xmlout, " <AsHex>0x%08x</AsHex>\n", + track->vertresolution); + } + if (derived) { + fprintf(xmlout, " <AsDecimal>%12.6f</AsDecimal>\n", + (double)track->vertresolution / (double) + 0x00010000); /* Rate to play presentation (default = 0x00010000) */ + } + fprintf(xmlout, " </VerticalRes>\n"); + + buf33[0] = '\0'; + for (i = 0; i < 8; i++) { + uint_to_chars((unsigned int)track->compressorname[i], buf); + strcat(buf33, + buf); /* This loads up (4 * 8) + 1 chars, but trailing ones are usually junk */ + } + len = (int) + buf33[0]; /* First byte has string length in bytes. There may be garbage beyond it. */ + buf33[len + 1] = '\0'; /* Suppress it */ + fprintf(xmlout, " <CompressorName>%s</CompressorName>\n", + buf33 + 1); /* Start beyond first byte */ + if (notes) { + fprintf(xmlout, + " <!-- Compressor name for debugging. Standard restricts max length to 31 bytes. -->\n"); + fprintf(xmlout, + " <!-- Usually blank or \"Motion JPEG2000\" -->\n"); + } + fprintf(xmlout, " <Depth>0x%02x</Depth>\n", track->depth); + if (notes) { + fprintf(xmlout, " <!-- Depth is: -->\n"); + fprintf(xmlout, + " <!-- 0x20: alpha channels present (color or grayscale) -->\n"); + fprintf(xmlout, " <!-- 0x28: grayscale without alpha -->\n"); + fprintf(xmlout, " <!-- 0x18: color without alpha -->\n"); + } + + xml_out_frame_jp2h(xmlout, &(track->jp2_struct)); /* JP2 Header */ + + /* Following subboxes are optional */ + fprintf(xmlout, " <FieldCoding BoxType=\"fiel\">\n"); + fprintf(xmlout, " <FieldCount>%d</FieldCount>\n", + (unsigned int)track->fieldcount); /* uchar as 1 byte uint */ + if (notes) { + fprintf(xmlout, " <!-- Must be either 1 or 2 -->\n"); + } + fprintf(xmlout, " <FieldOrder>%d</FieldOrder>\n", + (unsigned int)track->fieldorder); /* uchar as 1 byte uint */ + if (notes) { + fprintf(xmlout, + " <!-- When FieldCount=2, FieldOrder means: -->\n"); + fprintf(xmlout, " <!-- 0: Field coding unknown -->\n"); + fprintf(xmlout, + " <!-- 1: Field with topmost line is stored first in sample; fields are in temporal order -->\n"); + fprintf(xmlout, + " <!-- 6: Field with topmost line is stored second in sample; fields are in temporal order -->\n"); + fprintf(xmlout, + " <!-- Defaults: FieldCount=1, FieldOrder=0 if FieldCoding box not present -->\n"); + fprintf(xmlout, + " <!-- Current implementation doesn't retain whether box was actually present. -->\n"); + } + fprintf(xmlout, " </FieldCoding>\n"); + + fprintf(xmlout, + " <MJP2_Profile BoxType=\"jp2p\" Count=\"%d\">\n", track->num_br); + for (i = 0; i < track->num_br; + i++) { /* read routine stored in reverse order, so let's undo damage */ + uint_to_chars(track->br[i], buf); + fprintf(xmlout, " <CompatibleBrand>%s</CompatibleBrand>\n", + buf); /*4 characters, each CLi */ + } + fprintf(xmlout, " </MJP2_Profile>\n"); + + fprintf(xmlout, + " <MJP2_Prefix BoxType=\"jp2x\" Count=\"%d\">\n", track->num_jp2x); + for (i = 0; i < track->num_jp2x; i++) { + // We'll probably need better formatting than this + fprintf(xmlout, " <Data>0x%02x</Data>\n", + track->jp2xdata[i]); /* Each entry is single byte */ + } + fprintf(xmlout, " </MJP2_Prefix>\n"); + + fprintf(xmlout, + " <MJP2_SubSampling BoxType=\"jsub\">\n"); /* These values are all 1 byte */ + if (notes) { + fprintf(xmlout, + " <!-- Typical subsample value is 2 for 4:2:0 -->\n"); + } + fprintf(xmlout, " <HorizontalSub>%d</HorizontalSub>\n", + track->hsub); + fprintf(xmlout, " <VerticalSub>%d</VerticalSub>\n", + track->vsub); + fprintf(xmlout, " <HorizontalOffset>%d</HorizontalOffset>\n", + track->hoff); + fprintf(xmlout, " <VerticalOffset>%d</VerticalOffset>\n", + track->voff); + if (notes) { + fprintf(xmlout, + " <!-- Typical {horizontal, vertical} chroma offset values: -->\n"); + fprintf(xmlout, + " <!-- 4:2:2 format (CCIR601, H.262, MPEG2, MPEG4, recom. Exif): {0, 0} -->\n"); + fprintf(xmlout, + " <!-- 4:2:2 format (JFIF): {1, 0} -->\n"); + fprintf(xmlout, + " <!-- 4:2:0 format (H.262, MPEG2, MPEG4): {0, 1} -->\n"); + fprintf(xmlout, + " <!-- 4:2:0 format (MPEG1, H.261, JFIF, recom. Exif): {1, 1} -->\n"); + } + fprintf(xmlout, + " </MJP2_SubSampling>\n"); /* These values are all 1 byte */ + + fprintf(xmlout, + " <MJP2_OriginalFormat BoxType=\"orfo\">\n"); /* Part III Appx. 2 */ + fprintf(xmlout, + " <OriginalFieldCount>%u</OriginalFieldCount>\n", + (unsigned int)track->or_fieldcount); /* uchar as 1-byte uint */ + if (notes) { + fprintf(xmlout, + " <!-- In original material before encoding. Must be either 1 or 2 -->\n"); + } + fprintf(xmlout, + " <OriginalFieldOrder>%u</OriginalFieldOrder>\n", + (unsigned int)track->or_fieldorder); /* uchar as 1-byte uint */ + if (notes) { + fprintf(xmlout, + " <!-- When FieldCount=2, FieldOrder means: -->\n"); + fprintf(xmlout, " <!-- 0: Field coding unknown -->\n"); + fprintf(xmlout, + " <!-- 11: Topmost line came from the earlier field; -->\n"); + fprintf(xmlout, + " <!-- 16: Topmost line came form the later field. -->\n"); + fprintf(xmlout, + " <!-- Defaults: FieldCount=1, FieldOrder=0 if FieldCoding box not present -->\n"); + fprintf(xmlout, + " <!-- Current implementation doesn't retain whether box was actually present. -->\n"); + } + fprintf(xmlout, " </MJP2_OriginalFormat>\n"); + fprintf(xmlout, " </VisualSampleEntry>\n"); + break; + case 1: + case 2: + if (notes) { + fprintf(xmlout, + " <!-- mj2_to_metadata's data structure doesn't record this currently. -->\n"); + } + break; + } + fprintf(xmlout, " <TimeToSample BoxType=\"stts\">\n"); + fprintf(xmlout, " <SampleStatistics>\n"); + fprintf(xmlout, " <TotalSamples>%d</TotalSamples>\n", + track->num_samples); + if (notes) { + fprintf(xmlout, + " <!-- For video, gives the total frames in the track, by summing all entries in the Sample Table -->\n"); + } + fprintf(xmlout, " </SampleStatistics>\n"); + fprintf(xmlout, " <SampleEntries EntryCount=\"%d\">\n", + track->num_tts); + for (i = 0; i < track->num_tts; i++) { + fprintf(xmlout, + " <Table Entry=\"%u\" SampleCount=\"%d\" SampleDelta=\"%u\" />\n", + i + 1, track->tts[i].sample_count, track->tts[i].sample_delta); + } + fprintf(xmlout, " </SampleEntries>\n"); + fprintf(xmlout, " </TimeToSample>\n"); + + fprintf(xmlout, + " <SampleToChunk BoxType=\"stsc\" Count=\"%d\">\n", + track->num_samplestochunk); + for (i = 0; i < track->num_samplestochunk; i++) { + fprintf(xmlout, " <FirstChunk>%u</FirstChunk>\n", + track->sampletochunk[i].first_chunk); /* 4 bytes */ + fprintf(xmlout, " <SamplesPerChunk>%u</SamplesPerChunk>\n", + track->sampletochunk[i].samples_per_chunk); /* 4 bytes */ + fprintf(xmlout, " <SampleDescrIndex>%u</SampleDescrIndex>\n", + track->sampletochunk[i].sample_descr_idx); /* 4 bytes */ + } + fprintf(xmlout, " </SampleToChunk>\n"); + // After reading this info in, track->num_chunks is calculated and a decompressed table established internally. + + fprintf(xmlout, " <SampleSize BoxType=\"stsz\">\n"); + if (track->same_sample_size) { + // all values in track->sample[i].sample_size are equal. Grab the first one. + fprintf(xmlout, " <Sample_Size>%u</Sample_Size>\n", + track->sample[0].sample_size); + if (notes) { + fprintf(xmlout, + " <!-- Non-zero value means all samples have that size. -->\n"); + fprintf(xmlout, + " <!-- So <Sample_Count> (aka Entry_Count in std.) has no meaning, is suppressed from this output, and no table follows. -->\n"); + } + } else { + fprintf(xmlout, " <Sample_Size>0</Sample_Size>\n"); + if (notes) + if (sampletables) { + fprintf(xmlout, + " <!-- Zero value means samples have different sizes, given in table next of length Sample_Count (aka Entry_Count in std). -->\n"); + } else { + fprintf(xmlout, + " <!-- Zero value means samples have different sizes, given in table (not shown) of length Sample_Count (aka Entry_Count in std). -->\n"); + } + fprintf(xmlout, " <Sample_Count>%u</Sample_Count>\n", + track->num_samples); + if (sampletables) + for (i = 0; i < (int)track->num_samples; i++) { + fprintf(xmlout, " <EntrySize Num=\"%u\">%u</EntrySize>\n", i + 1, + track->sample[i].sample_size); + } + } + fprintf(xmlout, " </SampleSize>\n"); + + fprintf(xmlout, " <ChunkOffset BoxType=\"stco\">\n"); + // Structure not yet - Variant ChunkLargeOffset 'co64' + fprintf(xmlout, " <EntryCount>%u</EntryCount>\n", + track->num_chunks); + if (notes) { + fprintf(xmlout, + " <!-- For this implementation, EntryCount shown is one calculated during file read of <SampleToChunk> data. -->\n"); + fprintf(xmlout, + " <!-- Implementation will report failure during file read of <ChunkOffset> data if read entry-count disagrees. -->\n"); + } + if (sampletables) + for (i = 0; i < (int)track->num_chunks; i++) { + fprintf(xmlout, " <Chunk_Offset Num=\"%d\">%u</Chunk_Offset>\n", + i + 1, track->chunk[i].offset); + } + fprintf(xmlout, " </ChunkOffset>\n"); + + fprintf(xmlout, " </SampleTable>\n"); +} + +/* ------------- */ + +int xml_out_frame(FILE* file, FILE* xmlout, mj2_sample_t *sample, + unsigned int snum, opj_event_mgr_t *event_mgr) +{ + opj_dparameters_t parameters; /* decompression parameters */ + opj_image_t *img; + opj_cp_t *cp; + int i; + int numcomps; + unsigned char* frame_codestream; + opj_dinfo_t* dinfo = NULL; /* handle to a decompressor */ + opj_cio_t *cio = NULL; + opj_j2k_t *j2k; + + /* JPEG 2000 compressed image data */ + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_J2K); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, event_mgr, stderr); + + /* setup the decoder decoding parameters using the current image and user parameters */ + parameters.cp_limit_decoding = DECODE_ALL_BUT_PACKETS; + opj_setup_decoder(dinfo, ¶meters); + + frame_codestream = (unsigned char*) malloc(sample->sample_size - + 8); /* Skipping JP2C marker */ + if (frame_codestream == NULL) { + return 1; + } + + fseek(file, sample->offset + 8, SEEK_SET); + fread(frame_codestream, sample->sample_size - 8, 1, + file); /* Assuming that jp and ftyp markers size do */ + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, frame_codestream, + sample->sample_size - 8); + + /* Decode J2K to image: */ + img = opj_decode(dinfo, cio); + if (!img) { + fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n"); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + return 1; + } + + j2k = (opj_j2k_t*)dinfo->j2k_handle; + j2k_default_tcp = j2k->default_tcp; + cp = j2k->cp; + + numcomps = img->numcomps; + /* Alignments: " < To help maintain xml pretty-printing */ + fprintf(xmlout, " <JP2_Frame Num=\"%d\">\n", snum + 1); + fprintf(xmlout, " <MainHeader>\n"); + /* There can be multiple codestreams; a particular image is entirely within a single codestream */ + /* TO DO: A frame can be represented by two I-guess-contiguous codestreams if its interleaved. */ + fprintf(xmlout, " <StartOfCodestream Marker=\"SOC\" />\n"); + /* "cp" stands for "coding parameter"; "tcp" is tile coding parameters, "tccp" is tile-component coding parameters */ + xml_out_frame_siz(xmlout, img, cp); /* reqd in main */ + xml_out_frame_cod(xmlout, j2k_default_tcp); /* reqd in main */ + xml_out_frame_coc(xmlout, j2k_default_tcp, + numcomps); /* opt in main, at most 1 per component */ + xml_out_frame_qcd(xmlout, j2k_default_tcp); /* reqd in main */ + xml_out_frame_qcc(xmlout, j2k_default_tcp, + numcomps); /* opt in main, at most 1 per component */ + xml_out_frame_rgn(xmlout, j2k_default_tcp, + numcomps); /* opt, at most 1 per component */ + xml_out_frame_poc(xmlout, + j2k_default_tcp); /* opt (but reqd in main or tile for any progression order changes) */ + /* Next four get j2k_default_tcp passed globally: */ +#ifdef SUPPRESS_FOR_NOW + xml_out_frame_ppm(xmlout, + cp); /* opt (but either PPM or PPT [distributed in tile headers] or codestream packet header reqd) */ +#endif + xml_out_frame_tlm( + xmlout); /* NO-OP. TLM NOT SAVED IN DATA STRUCTURE */ /* opt */ + xml_out_frame_plm( + xmlout); /* NO-OP. PLM NOT SAVED IN DATA STRUCTURE */ /* opt in main; can be used in conjunction with PLT */ + xml_out_frame_crg( + xmlout); /* NO-OP. CRG NOT SAVED IN DATA STRUCTURE */ /* opt in main; */ + xml_out_frame_com(xmlout, + j2k_default_tcp); /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */ /* opt in main; */ + + fprintf(xmlout, " </MainHeader>\n"); + + /* TO DO: all the tile headers (sigh) */ + fprintf(xmlout, " <TilePartHeaders Count=\"%d\">\n", + cp->tileno_size); /* size of the vector tileno */ + for (i = 0; i < cp->tileno_size; + i++) { /* I think cp->tileno_size will be same number as (cp->tw * cp->th) or as global j2k_curtileno */ + // Standard seems to use zero-based # for tile-part. + fprintf(xmlout, " <TilePartHeader Num=\"%d\" ID=\"%d\">\n", i, + cp->tileno[i]); /* ID number of the tiles present in the codestream */ + fprintf(xmlout, " <StartOfTilePart Marker=\"SOT\" />\n"); + /* All markers in tile-part headers (between SOT and SOD) are optional, unless structure requires. */ + if (i == 0) { + xml_out_frame_cod(xmlout, &(cp->tcps[i])); /* No more than 1 per tile */ + xml_out_frame_coc(xmlout, &(cp->tcps[i]), + numcomps); /* No more than 1 per component */ + xml_out_frame_qcd(xmlout, &(cp->tcps[i])); /* No more than 1 per tile */ + xml_out_frame_qcc(xmlout, &(cp->tcps[i]), + numcomps); /* No more than 1 per component */ + xml_out_frame_rgn(xmlout, &(cp->tcps[i]), + numcomps); /* No more than 1 per component */ + } + xml_out_frame_poc(xmlout, + &(cp->tcps[i])); /* Reqd only if any progression order changes different from main POC */ +#ifdef SUPPRESS_FOR_NOW + xml_out_frame_ppt(xmlout, + &(cp->tcps[i])); /* Either PPT [distributed in tile headers] or PPM or codestream packet header reqd. */ +#endif + xml_out_frame_plt(xmlout, + &(cp->tcps[i])); /* NO-OP. PLT NOT SAVED IN DATA STRUCTURE */ /* Can be used in conjunction with main's PLM */ + xml_out_frame_com(xmlout, + &(cp->tcps[i])); /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */ + /* opj_tcp_t * cp->tcps; "tile coding parameters" */ + /* Maybe not: fprintf(xmlout, " <>%d</>, cp->matrice[i]; */ /* Fixed layer */ + fprintf(xmlout, " <StartOfData Marker=\"SOD\" />\n"); + if (notes) { + fprintf(xmlout, + " <!-- Tile-part bitstream, not shown, follows tile-part header and SOD marker. -->\n"); + } + fprintf(xmlout, " </TilePartHeader>\n"); + } + fprintf(xmlout, + " </TilePartHeaders>\n"); /* size of the vector tileno */ + +#ifdef NOTYET + IMAGINE the cp object has data to support the following... but we could use an + new different data structure instead + /* I'm unclear if the span of the original fread(frame_codestream...) included the following items if they're trailing. */ + /* ALSO TO DO, BUT DATA STRUCTURE DOESN'T HANDLE YET: boxes (anywhere in file except before the Filetype box): */ + xml_out_frame_jp2i(xmlout, + &cp); /* IntellectualProperty 'jp2i' (no restrictions on location) */ + xml_out_frame_xml(xmlout, + &cp); /* XML 'xml\040' (0x786d6c20). Can appear multiply */ + xml_out_frame_uuid(xmlout, &cp); /* UUID 'uuid' (top level only) */ + xml_out_frame_uinf(xmlout, + &cp); /* UUIDInfo 'uinf', includes UUIDList 'ulst' and URL 'url\40' */ +#endif + + fprintf(xmlout, " </JP2_Frame>\n"); + + /* Extra commentary: */ + if (notes) { + fprintf(xmlout, + " <!-- Given the number and size of components, mj2_to_frame would try to convert this -->\n"); + if (((img->numcomps == 3) && (img->comps[0].dx == img->comps[1].dx / 2) + && (img->comps[0].dx == img->comps[2].dx / 2) && (img->comps[0].dx == 1)) + || (img->numcomps == 1)) { + fprintf(xmlout, " <!-- file to a YUV movie in the normal manner. -->\n"); + } else if ((img->numcomps == 3) && + (img->comps[0].dx == 1) && (img->comps[1].dx == 1) && + (img->comps[2].dx == 1)) {// If YUV 4:4:4 input --> to bmp + fprintf(xmlout, " <!-- YUV 4:4:4 file to a series of .bmp files. -->\n"); + } else { + fprintf(xmlout, + " <!-- file whose image component dimension are unknown, to a series of .j2k files. -->\n"); + } + } + + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + free(frame_codestream); + + return 0; +} + +/* ------------- */ + +void int16_to_3packedchars(short int value, char* buf) +{ + /* This is to retrieve the 3-letter ASCII language code */ + /* Each char is packed into 5 bits, as difference from 0x60 */ + int i; + for (i = 2; i >= 0; i--) { + buf[i] = (value & 0x001f) + 0x60; + value = (value >> 5); + } + buf[3] = '\0'; +} + +/* ------------- */ + +void xml_out_frame_siz(FILE* xmlout, opj_image_t *img, opj_cp_t *cp) +{ + opj_image_comp_t *comp; + int i; + + fprintf(xmlout, " <ImageAndFileSize Marker=\"SIZ\">\n"); + // This is similar to j2k.c's j2k_dump_image. + // Not of interest: Lsiz, Rsiz + fprintf(xmlout, " <Xsiz>%d</Xsiz>\n", img->x1); + fprintf(xmlout, " <Ysiz>%d</Ysiz>\n", img->y1); + if (notes) { + fprintf(xmlout, + " <!-- Xsiz, Ysiz is the size of the reference grid. -->\n"); + } + fprintf(xmlout, " <XOsiz>%d</XOsiz>\n", img->x0); + fprintf(xmlout, " <YOsiz>%d</YOsiz>\n", img->y0); + if (notes) { + fprintf(xmlout, + " <!-- XOsiz, YOsiz are offsets from grid origin to image origin. -->\n"); + } + fprintf(xmlout, " <XTsiz>%d</XTsiz>\n", cp->tdx); + fprintf(xmlout, " <YTsiz>%d</YTsiz>\n", cp->tdy); + if (notes) { + fprintf(xmlout, + " <!-- XTsiz, YTsiz is the size of one tile with respect to the grid. -->\n"); + } + fprintf(xmlout, " <XTOsiz>%d</XTOsiz>\n", cp->tx0); + fprintf(xmlout, " <YTOsiz>%d</YTOsiz>\n", cp->ty0); + if (notes) { + fprintf(xmlout, + " <!-- XTOsiz, YTOsiz are offsets from grid origin to first tile origin. -->\n"); + } + fprintf(xmlout, " <Csiz>%d</Csiz>\n", img->numcomps); + if (notes) { + fprintf(xmlout, + " <!-- Csiz is the number of components in the image. -->\n"); + fprintf(xmlout, " <!-- For image components next: -->\n"); + fprintf(xmlout, + " <!-- XRsiz, YRsiz denote pixel-sample-spacing on the grid, per Part I Annex B. -->\n"); + //fprintf(xmlout," <!-- XO, YO is offset of the component compared to the whole image. -->\n"); + fprintf(xmlout, + " <!-- Bits per pixel (bpp) is the pixel depth. -->\n"); + fprintf(xmlout, + " <!-- WidthOfData and HeightOfData are calculated values, e.g.: w = roundup((Xsiz - XOsiz)/ XRsiz) -->\n"); + } + + for (i = 0; i < img->numcomps; i++) {/* image-components */ + comp = &(img->comps[i]); + fprintf(xmlout, " <Component Num=\"%d\">\n", i + 1); + fprintf(xmlout, " <Ssiz>\n"); + if (raw) { + fprintf(xmlout, " <AsHex>0x%02x</AsHex>\n", + (comp->sgnd << 7) & (comp->prec - 1)); + } + if (derived) { + fprintf(xmlout, " <Signed>%d</Signed>\n", comp->sgnd); + fprintf(xmlout, " <PrecisionInBits>%d</PrecisionInBits>\n", + comp->prec); + } + fprintf(xmlout, " </Ssiz>\n"); + fprintf(xmlout, " <XRsiz>%d</XRsiz>\n", comp->dx); + fprintf(xmlout, " <YRsiz>%d</YRsiz>\n", comp->dy); + fprintf(xmlout, " <WidthOfData>%d</WidthOfData>\n", comp->w); + fprintf(xmlout, " <HeightOfData>%d</HeightOfData>\n", comp->h); + /* Rest of these aren't calculated when SIZ is read: + fprintf(xmlout, " <XO>%d</XO>\n", comp->x0); + fprintf(xmlout, " <YO>%d</YO>\n", comp->y0); + if(notes) + fprintf(xmlout," <!-- XO, YO is offset of the component compared to the whole image. -->\n"); + fprintf(xmlout, " <BitsPerPixel>%d</BitsPerPixel>\n", comp->bpp); + fprintf(xmlout, " <NumberOfDecodedResolution>%d</NumberOfDecodedResolution>\n", comp->resno_decoded); */ + // SUPPRESS: n/a to mj2_to_metadata. fprintf(xmlout," <Factor>%d</Factor\n", comp->factor); + /* factor = number of division by 2 of the out image compare to the original size of image */ + // TO DO comp->data: int *data; /* image-component data */ + + fprintf(xmlout, " </Component>\n"); + } + fprintf(xmlout, " </ImageAndFileSize>\n"); +} + +/* ------------- */ + +void xml_out_frame_cod(FILE* xmlout, opj_tcp_t *tcp) +{ + /* Could be called with tcp = &j2k_default_tcp; + /* Or, for tile-part header, with &j2k_cp->tcps[j2k_curtileno] + /* Alignment for main:" < < < < To help maintain xml pretty-printing */ + /* Alignment for tile:" < < < To help maintain xml pretty-printing */ + opj_tccp_t *tccp; + int i; + char spaces[13] = " "; /* 12 spaces if tilepart*/ + char* s = spaces; + if (tcp == j2k_default_tcp) { + s++; + s++; /* shorten s to 10 spaces if main */ + } + tccp = &(tcp->tccps[0]); + + fprintf(xmlout, "%s<CodingStyleDefault Marker=\"COD\">\n", + s); /* Required in main header */ + /* Not retained or of interest: Lcod */ + fprintf(xmlout, "%s <Scod>0x%02x</Scod>\n", s, tcp->csty); /* 1 byte */ + if (notes) { + fprintf(xmlout, + "%s <!-- For Scod, specific bits mean (where bit 0 is lowest or rightmost): -->\n", + s); + fprintf(xmlout, "%s <!-- bit 0: Defines entropy coder precincts -->\n", s); + fprintf(xmlout, + "%s <!-- 0 = (PPx=15, PPy=15); 1 = precincts defined below. -->\n", s); + fprintf(xmlout, "%s <!-- bit 1: 1 = SOP marker may be used; 0 = not. -->\n", + s); + fprintf(xmlout, "%s <!-- bit 2: 1 = EPH marker may be used; 0 = not. -->\n", + s); + } + fprintf(xmlout, "%s <SGcod>\n", s); + fprintf(xmlout, "%s <ProgressionOrder>%d</ProgressionOrder>\n", s, + tcp->prg); /* 1 byte, SGcod (A) */ + if (notes) { + fprintf(xmlout, "%s <!-- Defined Progression Order Values are: -->\n", s); + fprintf(xmlout, + "%s <!-- 0 = LRCP; 1 = RLCP; 2 = RPCL; 3 = PCRL; 4 = CPRL -->\n", s); + fprintf(xmlout, + "%s <!-- where L = \"layer\", R = \"resolution level\", C = \"component\", P = \"position\". -->\n", + s); + } + fprintf(xmlout, "%s <NumberOfLayers>%d</NumberOfLayers>\n", s, + tcp->numlayers); /* 2 bytes, SGcod (B) */ + fprintf(xmlout, + "%s <MultipleComponentTransformation>%d</MultipleComponentTransformation>\n", + s, tcp->mct); /* 1 byte, SGcod (C). More or less boolean */ + if (notes) { + fprintf(xmlout, + "%s <!-- For MCT, 0 = none, 1 = transform first 3 components for efficiency, per Part I Annex G -->\n", + s); + } + fprintf(xmlout, "%s </SGcod>\n", s); + /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */ + fprintf(xmlout, "%s <SPcod>\n", s); + /* Internal data structure tccp defines separate defaults for each component, but they all get the same values */ + /* So we only have to report the first component's values here. */ + /* Compare j2k_read_cox(...) */ + fprintf(xmlout, + "%s <NumberOfDecompositionLevels>%d</NumberOfDecompositionLevels>\n", s, + tccp->numresolutions - 1); /* 1 byte, SPcox (D) */ + fprintf(xmlout, "%s <CodeblockWidth>%d</CodeblockWidth>\n", s, + tccp->cblkw - 2); /* 1 byte, SPcox (E) */ + fprintf(xmlout, "%s <CodeblockHeight>%d</CodeblockHeight>\n", s, + tccp->cblkh - 2); /* 1 byte, SPcox (F) */ + if (notes) { + fprintf(xmlout, + "%s <!-- CBW and CBH are non-negative, and summed cannot exceed 8 -->\n", s); + fprintf(xmlout, "%s <!-- Codeblock dimension is 2^(value + 2) -->\n", s); + } + fprintf(xmlout, "%s <CodeblockStyle>0x%02x</CodeblockStyle>\n", s, + tccp->cblksty); /* 1 byte, SPcox (G) */ + if (notes) { + fprintf(xmlout, + "%s <!-- For CodeblockStyle, bits mean (with value 1=feature on, 0=off): -->\n", + s); + fprintf(xmlout, + "%s <!-- bit 0: Selective arithmetic coding bypass. -->\n", s); + fprintf(xmlout, + "%s <!-- bit 1: Reset context probabilities on coding pass boundaries. -->\n", + s); + fprintf(xmlout, "%s <!-- bit 2: Termination on each coding pass. -->\n", + s); + fprintf(xmlout, "%s <!-- bit 3: Vertically causal context. -->\n", s); + fprintf(xmlout, "%s <!-- bit 4: Predictable termination. -->\n", s); + fprintf(xmlout, "%s <!-- bit 5: Segmentation symbols are used. -->\n", s); + } + fprintf(xmlout, "%s <Transformation>%d</Transformation>\n", s, + tccp->qmfbid); /* 1 byte, SPcox (H) */ + if (notes) { + fprintf(xmlout, + "%s <!-- For Transformation, 0=\"9-7 irreversible filter\", 1=\"5-3 reversible filter\" -->\n", + s); + } + if (tccp->csty & J2K_CP_CSTY_PRT) { + fprintf(xmlout, "%s <PrecinctSize>\n", s); /* 1 byte, SPcox (I_i) */ + if (notes) { + fprintf(xmlout, + "%s <!-- These are size exponents PPx and PPy. May be zero only for first level (aka N(L)LL subband)-->\n", + s); + } + for (i = 0; i < tccp->numresolutions; i++) { + fprintf(xmlout, "%s <PrecinctHeightAndWidth ResolutionLevel=\"%d\">\n", + s, i); + if (raw) { + fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s, + (tccp->prch[i] << 4) | tccp->prcw[i]); /* packed into 1 byte, SPcox (G) */ + } + if (derived) { + fprintf(xmlout, "%s <WidthAsDecimal>%d</WidthAsDecimal>\n", s, + tccp->prcw[i]); + fprintf(xmlout, "%s <HeightAsDecimal>%d</HeightAsDecimal>\n", s, + tccp->prch[i]); + } + fprintf(xmlout, "%s </PrecinctHeightAndWidth>\n", s, i); + } + fprintf(xmlout, "%s </PrecinctSize>\n", s); /* 1 byte, SPcox (I_i) */ + } + fprintf(xmlout, "%s </SPcod>\n", s); + fprintf(xmlout, "%s</CodingStyleDefault>\n", s); +} + +/* ------------- */ + +void xml_out_frame_coc(FILE* xmlout, opj_tcp_t *tcp, + int numcomps) /* Optional in main & tile-part headers */ +{ + /* Uses global j2k_default_tcp */ + opj_tccp_t *tccp, *firstcomp_tccp; + int i, compno; + char spaces[13] = " "; /* 12 spaces if tilepart*/ + char* s = spaces; + if (tcp == j2k_default_tcp) { + s++; + s++; /* shorten s to 10 spaces if main */ + } + + firstcomp_tccp = &(tcp->tccps[0]); + /* Internal data structure tccp defines separate defaults for each component, set from main */ + /* default, then selectively overwritten. */ + /* Compare j2k_read_cox(...) */ + /* We don't really know which was the default, and which were not */ + /* Let's pretend that [0] is the default and all others are not */ + if (notes) { + fprintf(xmlout, + "%s<!-- mj2_to_metadata implementation always reports component[0] as using default COD, -->\n", + s); + if (tcp == j2k_default_tcp) { + fprintf(xmlout, + "%s<!-- and any other component, with main-header style values different from [0], as COC. -->\n", + s); + } else { + fprintf(xmlout, + "%s<!-- and any other component, with tile-part-header style values different from [0], as COC. -->\n", + s); + } + } + for (compno = 1; compno < numcomps; + compno++) { /* spec says components are zero-based */ + tccp = &tcp->tccps[compno]; + if (same_component_style(firstcomp_tccp, tccp)) { + continue; + } + + /* Alignments: " < < < < < To help maintain xml pretty-printing */ + fprintf(xmlout, "%s<CodingStyleComponent Marker=\"COC\">\n", + s); /* Optional in main header, at most 1 per component */ + if (notes) { + fprintf(xmlout, + "%s <!-- See Ccoc below for zero-based component number. -->\n", s); + } + /* Overrides the main COD for the specific component */ + /* Not retained or of interest: Lcod */ + fprintf(xmlout, "%s <Scoc>0x%02x</Scoc>\n", s, tccp->csty); /* 1 byte */ + if (notes) { + fprintf(xmlout, "%s <!-- Scoc defines entropy coder precincts: -->\n", s); + fprintf(xmlout, + "%s <!-- 0 = maximum, namely (PPx=15, PPy=15); 1 = precincts defined below. -->\n", + s); + } + fprintf(xmlout, "%s <Ccoc>%d</Ccoc>\n", s, compno); /* 1 or 2 bytes */ + /* Unfortunately compo isn't retained in j2k_read_coc: compno = cio_read(j2k_img->numcomps <= 256 ? 1 : 2); /* Ccoc */ + /*if(j2k_img_numcomps <=256) + component is 1 byte + else + compno is 2 byte */ + + /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */ + fprintf(xmlout, "%s <SPcoc>\n", s); + fprintf(xmlout, + "%s <NumberOfDecompositionLevels>%d</NumberOfDecompositionLevels>\n", s, + tccp->numresolutions - 1); /* 1 byte, SPcox (D) */ + fprintf(xmlout, "%s <CodeblockWidth>%d</CodeblockWidth>\n", s, + tccp->cblkw - 2); /* 1 byte, SPcox (E) */ + fprintf(xmlout, "%s <CodeblockHeight>%d</CodeblockHeight>\n", s, + tccp->cblkh - 2); /* 1 byte, SPcox (F) */ + if (notes) { + fprintf(xmlout, + "%s <!-- CBW and CBH are non-negative, and summed cannot exceed 8 -->\n", s); + fprintf(xmlout, "%s <!-- Codeblock dimension is 2^(value + 2) -->\n", s); + } + fprintf(xmlout, "%s <CodeblockStyle>0x%02x</CodeblockStyle>\n", s, + tccp->cblksty); /* 1 byte, SPcox (G) */ + if (notes) { + fprintf(xmlout, + "%s <!-- For CodeblockStyle, bits mean (with value 1=feature on, 0=off): -->\n", + s); + fprintf(xmlout, + "%s <!-- bit 0: Selective arithmetic coding bypass. -->\n", s); + fprintf(xmlout, + "%s <!-- bit 1: Reset context probabilities on coding pass boundaries. -->\n", + s); + fprintf(xmlout, "%s <!-- bit 2: Termination on each coding pass. -->\n", + s); + fprintf(xmlout, "%s <!-- bit 3: Vertically causal context. -->\n", s); + fprintf(xmlout, "%s <!-- bit 4: Predictable termination. -->\n", s); + fprintf(xmlout, "%s <!-- bit 5: Segmentation symbols are used. -->\n", s); + } + fprintf(xmlout, "%s <Transformation>%d</Transformation>\n", s, + tccp->qmfbid); /* 1 byte, SPcox (H) */ + if (notes) { + fprintf(xmlout, + "%s <!-- For Transformation, 0=\"9-7 irreversible filter\", 1=\"5-3 reversible filter\" -->\n", + s); + } + if (tccp->csty & J2K_CP_CSTY_PRT) { + fprintf(xmlout, "%s <PrecinctSize>\n", s); /* 1 byte, SPcox (I_i) */ + if (notes) { + fprintf(xmlout, + "%s <!-- These are size exponents PPx and PPy. May be zero only for first level (aka N(L)LL subband)-->\n", + s); + } + for (i = 0; i < tccp->numresolutions - 1; + i++) { /* subtract 1 to get # of decomposition levels */ + fprintf(xmlout, "%s <PrecinctHeightAndWidth ResolutionLevel=\"%d\">\n", + s, i); + if (raw) { + fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s, + (tccp->prch[i] << 4) | tccp->prcw[i]); /* packed into 1 byte, SPcox (G) */ + } + if (derived) { + fprintf(xmlout, "%s <WidthAsDecimal>%d</WidthAsDecimal>\n", s, + tccp->prcw[i]); + fprintf(xmlout, "%s <HeightAsDecimal>%d</HeightAsDecimal>\n", s, + tccp->prch[i]); + } + fprintf(xmlout, "%s </PrecinctHeightAndWidth>\n", s, i); + } + fprintf(xmlout, "%s </PrecinctSize>\n", s); /* 1 byte, SPcox (I_i) */ + } + fprintf(xmlout, "%s </SPcoc>\n", s); + fprintf(xmlout, "%s</CodingStyleComponent>\n", s); + } +} + +/* ------------- */ + +BOOL same_component_style(opj_tccp_t *tccp1, opj_tccp_t *tccp2) +{ + int i; + + if (tccp1->numresolutions != tccp2->numresolutions) { + return FALSE; + } + if (tccp1->cblkw != tccp2->cblkw) { + return FALSE; + } + if (tccp1->cblkh != tccp2->cblkh) { + return FALSE; + } + if (tccp1->cblksty != tccp2->cblksty) { + return FALSE; + } + if (tccp1->csty != tccp2->csty) { + return FALSE; + } + + if (tccp1->csty & J2K_CP_CSTY_PRT) { + for (i = 0; i < tccp1->numresolutions; i++) { + if (tccp1->prcw[i] != tccp2->prcw[i] || tccp1->prch[i] != tccp2->prch[i]) { + return FALSE; + } + } + } + return TRUE; +} + +/* ------------- */ + +void xml_out_frame_qcd(FILE* xmlout, opj_tcp_t *tcp) +{ + /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */ + opj_tccp_t *tccp; + int bandno, numbands; + char spaces[13] = " "; /* 12 spaces if tilepart*/ + char* s = spaces; + if (tcp == j2k_default_tcp) { + s++; + s++; /* shorten s to 10 spaces if main */ + } + + /* Compare j2k_read_qcx */ + fprintf(xmlout, "%s<QuantizationDefault Marker=\"QCD\">\n", + s); /* Required in main header, single occurrence */ + tccp = &(tcp->tccps[0]); + /* Not retained or of interest: Lqcd */ + fprintf(xmlout, "%s <Sqcd>\n", s); /* 1 byte */ + if (notes) { + fprintf(xmlout, + "%s <!-- Default quantization style for all components. -->\n", s); + } + if (raw) { + fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s, + (tccp->numgbits) << 5 | tccp->qntsty); + } + if (derived) { + fprintf(xmlout, "%s <QuantizationStyle>%d</QuantizationStyle>\n", s, + tccp->qntsty); + } + if (notes) { + fprintf(xmlout, + "%s <!-- Quantization style (in Sqcd's low 5 bits) may be: -->\n", s); + fprintf(xmlout, "%s <!-- 0 = No quantization. SPqcd size = 8 bits-->\n", + s); + fprintf(xmlout, + "%s <!-- 1 = Scalar derived (values signaled for N(L)LL subband only). Use Eq. E.5. SPqcd size = 16. -->\n", + s); + fprintf(xmlout, + "%s <!-- 2 = Scalar expounded (values signaled for each subband). SPqcd size = 16. -->\n", + s); + } + if (derived) { + fprintf(xmlout, "%s <NumberOfGuardBits>%d</NumberOfGuardBits>\n", s, + tccp->numgbits); + } + if (notes) { + fprintf(xmlout, + "%s <!-- 0-7 guard bits allowed (stored in Sqcd's high 3 bits) -->\n", s); + } + fprintf(xmlout, "%s </Sqcd>\n", s); + + /* Problem: numbands in some cases is calculated from len, which is not retained or available here at this time */ + /* So we'll just dump all internal values */ + /* We could calculate it, but I'm having trouble believing the length equations in the standard */ + + fprintf(xmlout, "%s <SPqcd>\n", s); + switch (tccp->qntsty) { + case J2K_CCP_QNTSTY_NOQNT: /* no quantization */ + /* This is what standard says, but I don't believe it: len = 4 + (3*decomp); */ + numbands = J2K_MAXBANDS; /* should be: numbands = len - 1; */ + /* Better: IMAGINE numbands = tccp->stepsize_numbands; */ + /* Instead look for first zero exponent, quit there. Adequate? */ + fprintf(xmlout, "%s <ReversibleStepSizeValue>\n", s); + if (notes) { + fprintf(xmlout, + "%s <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n", + s); + fprintf(xmlout, + "%s <!-- until an exponent with zero value is reached. -->\n", s); + fprintf(xmlout, + "%s <!-- Exponent epsilon(b) of reversible dynamic range. -->\n", s); + fprintf(xmlout, + "%s <!-- Hex value is as stored, in high-order 5 bits. -->\n", s); + } + for (bandno = 0; bandno < numbands; bandno++) { + if (tccp->stepsizes[bandno].expn == 0) { + break; /* Remove when we have real numbands */ + } + fprintf(xmlout, "%s <DynamicRangeExponent Subband=\"%d\">\n", s, bandno); + if (raw) { + fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s, + tccp->stepsizes[bandno].expn << 3); + } + if (derived) { + fprintf(xmlout, "%s <AsDecimal>%d</AsDecimal>\n", s, + tccp->stepsizes[bandno].expn); + } + fprintf(xmlout, "%s </DynamicRangeExponent>\n", s); + } + fprintf(xmlout, "%s </ReversibleStepSizeValue>\n", s); + break; + case J2K_CCP_QNTSTY_SIQNT: /* scalar quantization derived */ + /* This is what standard says. Should I believe it:: len = 5; + /* numbands = 1; */ + fprintf(xmlout, "%s <QuantizationStepSizeValues>\n", s); + if (notes) { + fprintf(xmlout, + "%s <!-- For irreversible transformation only. See Part I Annex E Equation E.3 -->\n", + s); + } + fprintf(xmlout, "%s <QuantizationValues Subband=\"0\">\n", s); + if (notes) { + fprintf(xmlout, "%s <!-- For N(L)LL subband: >\n", s); + } + if (raw) { + fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s, + (tccp->stepsizes[0].expn << 11) | tccp->stepsizes[0].mant); + } + if (derived) { + fprintf(xmlout, "%s <Exponent>%d</Exponent>\n", s, + tccp->stepsizes[0].expn); + fprintf(xmlout, "%s <Mantissa>%d</Mantissa>\n", s, + tccp->stepsizes[0].mant); + } + fprintf(xmlout, "%s </QuantizationValues>\n", s); + if (notes) { + fprintf(xmlout, + "%s <!-- Exponents for subbands beyond 0 are not from header, but calculated per Eq. E.5 -->\n", + s); + fprintf(xmlout, + "%s <!-- The mantissa for all subbands is the same, given by the value above. -->\n", + s); + fprintf(xmlout, + "%s <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n", + s); + fprintf(xmlout, + "%s <!-- until a subband with exponent of zero value is reached. -->\n", + s); + } + + for (bandno = 1; bandno < J2K_MAXBANDS; bandno++) { + if (tccp->stepsizes[bandno].expn == 0) { + break; + } + + fprintf(xmlout, + "%s <CalculatedExponent Subband=\"%d\">%d</CalculatedExponent>\n", s, + bandno, tccp->stepsizes[bandno].expn); + } + + fprintf(xmlout, "%s </QuantizationStepSizeValues>\n", s); + break; + + default: /* J2K_CCP_QNTSTY_SEQNT */ /* scalar quantization expounded */ + /* This is what standard says, but should I believe it: len = 5 + 6*decomp; */ + numbands = J2K_MAXBANDS; /* should be: (len - 1) / 2;*/ + /* Better: IMAGINE numbands = tccp->stepsize_numbands; */ + fprintf(xmlout, "%s <QuantizationStepSizeValues>\n", s); + if (notes) { + fprintf(xmlout, + "%s <!-- For irreversible transformation only. See Part I Annex E Equation E.3 -->\n", + s); + fprintf(xmlout, + "%s <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n", + s); + fprintf(xmlout, + "%s <!-- until a subband with mantissa and exponent of zero values is reached. -->\n", + s); + } + for (bandno = 0; bandno < numbands; bandno++) { + if (tccp->stepsizes[bandno].expn == 0 && tccp->stepsizes[bandno].mant == 0) { + break; /* Remove when we have real numbands */ + } + + fprintf(xmlout, "%s <QuantizationValues Subband=\"%d\">\n", s, bandno); + if (raw) { + fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s, + (tccp->stepsizes[bandno].expn << 11) | tccp->stepsizes[bandno].mant); + } + if (derived) { + fprintf(xmlout, "%s <Exponent>%d</Exponent>\n", s, + tccp->stepsizes[bandno].expn); + fprintf(xmlout, "%s <Mantissa>%d</Mantissa>\n", s, + tccp->stepsizes[bandno].mant); + } + fprintf(xmlout, "%s </QuantizationValues>\n", s); + } + fprintf(xmlout, "%s </QuantizationStepSizeValues>\n", s); + break; + } /* switch */ + fprintf(xmlout, "%s </SPqcd>\n", s); + fprintf(xmlout, "%s</QuantizationDefault>\n", s); + + /* Alignments: " < < < < < To help maintain xml pretty-printing */ +} + +/* ------------- */ + +void xml_out_frame_qcc(FILE* xmlout, opj_tcp_t *tcp, int numcomps) +{ + /* Uses global j2k_default_tcp */ + /* This code will compile only if declaration of j2k_default_tcp is changed from static (to implicit extern) in j2k.c */ + opj_tccp_t *tccp, *firstcomp_tccp; + int bandno, numbands; + int compno; + char spaces[13] = " "; /* 12 spaces if tilepart*/ + char* s = spaces; + if (tcp == j2k_default_tcp) { + s++; + s++; /* shorten s to 10 spaces if main */ + } + + firstcomp_tccp = &(tcp->tccps[0]); + /* Internal data structure tccp defines separate defaults for each component, set from main */ + /* default, then selectively overwritten. */ + /* Compare j2k_read_qcx(...) */ + /* We don't really know which was the default, and which were not */ + /* Let's pretend that [0] is the default and all others are not */ + if (notes) { + fprintf(xmlout, + "%s<!-- mj2_to_metadata implementation always reports component[0] as using default QCD, -->\n", + s); + if (tcp == j2k_default_tcp) { + fprintf(xmlout, + "%s<!-- and any other component, with main-header quantization values different from [0], as QCC. -->\n", + s); + } else { + fprintf(xmlout, + "%s<!-- and any other component, with tile-part-header quantization values different from [0], as QCC. -->\n", + s); + } + } + for (compno = 1; compno < numcomps; + compno++) { /* spec says components are zero-based */ + tccp = &(tcp->tccps[compno]); + if (same_component_quantization(firstcomp_tccp, tccp)) { + continue; + } + + /* Compare j2k_read_qcx */ + fprintf(xmlout, + "%s<QuantizationComponent Marker=\"QCC\" Component=\"%d\">\n", s, + compno); /* Required in main header, single occurrence */ + tccp = &j2k_default_tcp->tccps[0]; + /* Not retained or perhaps of interest: Lqcd It maybe can be calculated. */ + fprintf(xmlout, "%s <Sqcc>\n", s); /* 1 byte */ + if (notes) { + fprintf(xmlout, "%s <!-- Quantization style for this component. -->\n", s); + } + if (raw) { + fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s, + (tccp->numgbits) << 5 | tccp->qntsty); + } + if (derived) { + fprintf(xmlout, "%s <QuantizationStyle>%d</QuantizationStyle>\n", s, + tccp->qntsty); + } + if (notes) { + fprintf(xmlout, + "%s <!-- Quantization style (in Sqcc's low 5 bits) may be: -->\n", s); + fprintf(xmlout, "%s <!-- 0 = No quantization. SPqcc size = 8 bits-->\n", + s); + fprintf(xmlout, + "%s <!-- 1 = Scalar derived (values signaled for N(L)LL subband only). Use Eq. E.5. SPqcc size = 16. -->\n", + s); + fprintf(xmlout, + "%s <!-- 2 = Scalar expounded (values signaled for each subband). SPqcc size = 16. -->\n", + s); + } + if (derived) { + fprintf(xmlout, "%s <NumberOfGuardBits>%d</NumberOfGuardBits>\n", s, + tccp->numgbits); + } + if (notes) { + fprintf(xmlout, + "%s <!-- 0-7 guard bits allowed (stored in Sqcc's high 3 bits) -->\n", s); + } + fprintf(xmlout, "%s </Sqcc>\n", s); + + /* Problem: numbands in some cases is calculated from len, which is not retained or available here at this time */ + /* So we'll just dump all internal values */ + fprintf(xmlout, "%s <SPqcc>\n", s); + switch (tccp->qntsty) { + case J2K_CCP_QNTSTY_NOQNT: + numbands = J2K_MAXBANDS; /* should be: numbands = len - 1; */ + /* Better: IMAGINE numbands = tccp->stepsize_numbands; */ + + /* Instead look for first zero exponent, quit there. Adequate? */ + fprintf(xmlout, "%s <ReversibleStepSizeValue>\n", s); + if (notes) { + fprintf(xmlout, + "%s <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n", + s); + fprintf(xmlout, + "%s <!-- until an exponent with zero value is reached. -->\n", s); + fprintf(xmlout, + "%s <!-- Exponent epsilon(b) of reversible dynamic range. -->\n", s); + fprintf(xmlout, + "%s <!-- Hex value is as stored, in high-order 5 bits. -->\n", s); + } + for (bandno = 0; bandno < numbands; bandno++) { + if (tccp->stepsizes[bandno].expn == 0) { + break; /* Remove this once we have real numbands */ + } + fprintf(xmlout, "%s <Exponent Subband=\"%d\">\n", s, bandno); + if (raw) { + fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s, + tccp->stepsizes[bandno].expn << 3); + } + if (derived) { + fprintf(xmlout, "%s <AsDecimal>%d</AsDecimal>\n", s, + tccp->stepsizes[bandno].expn); + } + fprintf(xmlout, "%s </Exponent>\n", s); + } + fprintf(xmlout, "%s </ReversibleStepSizeValue>\n", s); + break; + case J2K_CCP_QNTSTY_SIQNT: + /* numbands = 1; */ + fprintf(xmlout, "%s <QuantizationStepSizeValues>\n", s); + if (notes) { + fprintf(xmlout, + "%s <!-- For irreversible transformation only. See Part I Annex E Equation E.3 -->\n", + s); + } + fprintf(xmlout, "%s <QuantizationValuesForSubband0>\n", s); + if (notes) { + fprintf(xmlout, "%s <!-- For N(L)LL subband: >\n", s); + } + if (raw) { + fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s, + (tccp->stepsizes[0].expn << 11) | tccp->stepsizes[0].mant); + } + if (derived) { + fprintf(xmlout, "%s <Exponent>%d</Exponent>\n", s, + tccp->stepsizes[0].expn); + fprintf(xmlout, "%s <Mantissa>%d</Mantissa>\n", s, + tccp->stepsizes[0].mant); + } + fprintf(xmlout, "%s </QuantizationValuesForSubband0>\n", s); + if (notes) { + fprintf(xmlout, + "%s <!-- Exponents for subbands beyond 0 are not from header, but calculated per Eq. E.5 -->\n", + s); + fprintf(xmlout, + "%s <!-- The mantissa for all subbands is the same, given by the value above. -->\n", + s); + fprintf(xmlout, + "%s <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n", + s); + fprintf(xmlout, + "%s <!-- until a subband with exponent of zero value is reached. -->\n", + s); + } + + for (bandno = 1; bandno < J2K_MAXBANDS; bandno++) { + if (tccp->stepsizes[bandno].expn == 0) { + break; + } + + fprintf(xmlout, + "%s <CalculatedExponent Subband=\"%d\">%d</CalculatedExponent>\n", s, + bandno, tccp->stepsizes[bandno].expn); + } + fprintf(xmlout, "%s </QuantizationStepSizeValues>\n", s); + break; + + default: /* J2K_CCP_QNTSTY_SEQNT */ + numbands = J2K_MAXBANDS; /* should be: (len - 1) / 2;*/ + /* Better: IMAGINE numbands = tccp->stepsize_numbands; */ + fprintf(xmlout, "%s <QuantizationStepSizeValues>\n", s); + if (notes) { + fprintf(xmlout, + "%s <!-- For irreversible transformation only. See Part I Annex E Equation E.3 -->\n", + s); + fprintf(xmlout, + "%s <!-- Current mj2_to_metadata implementation dumps entire internal table, -->\n", + s); + fprintf(xmlout, + "%s <!-- until a subband with mantissa and exponent of zero values is reached. -->\n", + s); + } + for (bandno = 0; bandno < numbands; bandno++) { + if (tccp->stepsizes[bandno].expn == 0 && tccp->stepsizes[bandno].mant == 0) { + break; /* Remove this once we have real numbands count */ + } + fprintf(xmlout, "%s <QuantizationValues Subband=\"%d\">\n", s, bandno); + if (raw) { + fprintf(xmlout, "%s <AsHex>0x%02x</AsHex>\n", s, + (tccp->stepsizes[bandno].expn << 11) | tccp->stepsizes[bandno].mant); + } + if (derived) { + fprintf(xmlout, "%s <Exponent>%d</Exponent>\n", s, + tccp->stepsizes[bandno].expn); + fprintf(xmlout, "%s <Mantissa>%d</Mantissa>\n", s, + tccp->stepsizes[bandno].mant); + } + fprintf(xmlout, "%s </QuantizationValues>\n", s); + } + fprintf(xmlout, "%s </QuantizationStepSizeValues>\n", s); + break; + } /* switch */ + fprintf(xmlout, "%s </SPqcc>\n", s); + fprintf(xmlout, "%s</QuantizationComponent>\n", s); + } + /* Alignments: " < < < < < To help maintain xml pretty-printing */ +} + +/* ------------- */ + +BOOL same_component_quantization(opj_tccp_t *tccp1, opj_tccp_t *tccp2) +{ + int bandno, numbands; + + if (tccp1->qntsty != tccp2->qntsty) { + return FALSE; + } + if (tccp1->numgbits != tccp2->numgbits) { + return FALSE; + } + + switch (tccp1->qntsty) { + case J2K_CCP_QNTSTY_NOQNT: + numbands = J2K_MAXBANDS; /* should be: numbands = len - 1; */ + /* Instead look for first zero exponent, quit there. Adequate? */ + for (bandno = 0; bandno < numbands; bandno++) { + if (tccp1->stepsizes[bandno].expn == 0) { + break; + } + if (tccp1->stepsizes[bandno].expn != tccp2->stepsizes[bandno].expn) { + return FALSE; + } + } + break; + case J2K_CCP_QNTSTY_SIQNT: + /* numbands = 1; */ + if (tccp1->stepsizes[0].expn != tccp2->stepsizes[0].expn || + tccp1->stepsizes[0].mant != tccp2->stepsizes[0].mant) { + return FALSE; + } + /* Don't need to check remainder, since they are calculated from [0] */ + break; + + default: /* J2K_CCP_QNTSTY_SEQNT */ + numbands = J2K_MAXBANDS; /* should be: (len - 1) / 2;*/ + /* This comparison may cause us problems with trailing junk values. */ + for (bandno = 0; bandno < numbands; bandno++) { + if (tccp1->stepsizes[bandno].expn != tccp2->stepsizes[bandno].expn || + tccp1->stepsizes[bandno].mant != tccp2->stepsizes[bandno].mant); + return FALSE; + } + break; + } /* switch */ + return TRUE; +} + +/* ------------- */ + +void xml_out_frame_rgn(FILE* xmlout, opj_tcp_t *tcp, int numcomps) +{ + int compno, SPrgn; + /* MJ2 files can have regions of interest if hybridized with JPX Part II */ + char spaces[13] = " "; /* 12 spaces if tilepart*/ + char* s = spaces; + if (tcp == j2k_default_tcp) { + s++; + s++; /* shorten s to 10 spaces if main */ + } + + for (compno = 0; compno < numcomps; compno++) { + SPrgn = tcp->tccps[compno].roishift; /* 1 byte; SPrgn */ + if (SPrgn == 0) { + continue; /* Yet another kludge */ + } + + fprintf(xmlout, "%s<RegionOfInterest Marker=\"RGN\">\n", + s); /* Optional in main header, at most 1 per component */ + if (notes) { + fprintf(xmlout, "%s<!-- See Crgn below for zero-based component number. -->\n", + s); + } + /* Not retained or of interest: Lrgd */ + fprintf(xmlout, "%s <Srgn>0</Srgn>\n", s); /* 1 byte */ + if (notes) { + fprintf(xmlout, + "%s <!-- Srgn is ROI style. Only style=0 defined: Implicit ROI (max. shift) -->\n", + s); + } + fprintf(xmlout, "%s <Crgn>%d</Crgn>\n", s, compno); /* 1 or 2 bytes */ + fprintf(xmlout, "%s <SPrgn>%d</SPrgn>\n", s, SPrgn); /* 1 byte */ + if (notes) { + fprintf(xmlout, + "%s <!-- SPrgn is implicit ROI shift, i.e., binary shifting of ROI coefficients above background. -->\n", + s); + } + fprintf(xmlout, "</RegionOfInterest\n", + s); /* Optional in main header, at most 1 per component */ + } +} + +/* ------------- */ + +void xml_out_frame_poc(FILE* xmlout, + opj_tcp_t *tcp) /* Progression Order Change */ +{ + /* Compare j2k_read_poc() */ + int i; + opj_poc_t *poc; + char spaces[13] = " "; /* 12 spaces if tilepart*/ + char* s = spaces; + if (tcp == j2k_default_tcp) { + s++; + s++; /* shorten s to 10 spaces if main */ + } + + if (tcp->POC != 1) { + return; /* Not present */ + } + + fprintf(xmlout, "%s<ProgressionOrderChange Marker=\"POC\">\n", + s); /* Optional in main header, at most 1 per component */ + /* j2k_read_poc seems to allow accumulation of default pocs from multiple POC segments, but does + the spec really allow that? */ + /* 2 bytes, not retained; Lpoc */ + /* I probably didn't get this dump precisely right. */ + for (i = 0; i < tcp->numpocs; i++) { + poc = &tcp->pocs[i]; + fprintf(xmlout, "%s <Progression Num=\"%d\">\n", s, i + 1); + fprintf(xmlout, "%S <RSpoc>%d</RSpoc>\n", s, + poc->resno0); /* 1 byte, RSpoc_i */ + if (notes) { + fprintf(xmlout, + "%s <!-- Resolution level index (inclusive) for progression start. Range: 0 to 33 -->\n", + s); + } + fprintf(xmlout, "%s <CSpoc>%d</CSpoc>\n", s, + poc->compno0);/* j2k_img->numcomps <= 256 ? 1 byte : 2 bytes; CSpoc_i */ + if (notes) { + fprintf(xmlout, + "%s <!-- Component index (inclusive) for progression start. -->\n", s); + } + fprintf(xmlout, "%s <LYEpoc>%d</LYEpoc>\n", s, + poc->layno1); /* int_min(cio_read(2), tcp->numlayers); /* 2 bytes; LYEpoc_i */ + if (notes) { + fprintf(xmlout, "%s <!-- Layer index (exclusive) for progression end. -->\n", + s); + } + fprintf(xmlout, "%s <REpoc>%d</REpoc>\n", s, + poc->resno1); /*int_min(cio_read(1), tccp->numresolutions); /* REpoc_i */ + if (notes) { + fprintf(xmlout, + "%s <!-- Resolution level index (exclusive) for progression end. Range: RSpoc to 33 -->\n", + s); + } + fprintf(xmlout, "%s <CEpoc>%d</CEpoc>\n", s, + poc->compno1); /* int_min(cio_read(j2k_img->numcomps <= 256 ? 1 : 2), j2k_img->numcomps); /* CEpoc_i */ + if (notes) { + fprintf(xmlout, + "%s <!-- Component index (exclusive) for progression end. Minimum: CSpoc -->\n", + s); + } + fprintf(xmlout, "%s <Ppoc>%d</Ppoc>\n", s, poc->prg); /* 1 byte Ppoc_i */ + if (notes) { + fprintf(xmlout, "%s <!-- Defined Progression Order Values are: -->\n", s); + fprintf(xmlout, + "%s <!-- 0 = LRCP; 1 = RLCP; 2 = RPCL; 3 = PCRL; 4 = CPRL -->\n", s); + fprintf(xmlout, + "%s <!-- where L = \"layer\", R = \"resolution level\", C = \"component\", P = \"position\". -->\n", + s); + } + fprintf(xmlout, "%s </Progression>\n", s); + } + fprintf(xmlout, "%s</ProgressionOrderChange\n", s); +} + +/* ------------- */ + +#ifdef SUPPRESS_FOR_NOW +/* Suppress PPM and PPT since we're not showing data from the third option, namely within the codestream, and +that's evidently what frames_to_mj2 uses. And a hex dump isn't so useful anyway */ + +void xml_out_frame_ppm(FILE *xmlout, + opj_cp_t *cp) /* For main header, not tile-part (which uses PPT instead). */ +{ + /* Either the PPM or PPT is required if the packet headers are not distributed in the bit stream */ + /* Use of PPM and PPT are mutually exclusive. */ + /* Compare j2k_read_ppm() */ + int j; + + if (cp->ppm != 1) { + return; /* Not present */ + } + /* Main header uses indent of 10 spaces */ + fprintf(xmlout, + " <PackedPacketHeadersMainHeader Marker=\"PPM\">\n"); /* Optional in main header, but if not, must be in PPT or codestream */ + /* 2 bytes Lppm not saved */ + if (notes) { + fprintf(xmlout, + " <!-- If there are multiple PPM marker segments in the main header, -->\n"); + fprintf(xmlout, + " <!-- this mj2_to_metadata implementation will report them as a single consolidated PPM header. -->\n"); + fprintf(xmlout, + " <!-- The implementation can't currently segregate by tile-part. -->\n"); + fprintf(xmlout, + " <!-- TO DO? further map the packet headers to xml. -->\n"); + } + + /* 1 byte, not retained ; Zppm is sequence # of this PPM header */ + /* 4 bytes, possibly overwritten multiple times in j2k_cp->ppm_previous: Nppm */ + /* Use j symbol for index instead of i, to make comparable with j2k_read_ppm */ + /* Not real clear whether to use ppm->store or ppm_len as upper bound */ + fprintf(xmlout, " <PackedData>\n"); + xml_out_dump_hex(xmlout, cp->ppm_data, cp->ppm_len); + /* Dump packet headers 1 byte at a time: lppm[i][j] */ + fprintf(xmlout, " </PackedData>\n"); + fprintf(xmlout, + " </PackedPacketHeadersMainHeader>\n"); /* Optional in main header, but if not, must be in PPT or codestream */ +} + +/* ------------- */ + +void xml_out_frame_ppt(FILE *xmlout, + opj_tcp_t *tcp) /* For tile-part header, not main (which uses PPM instead). */ +{ + /* Either the PPM or PPT is required if the packet headers are not distributed in the bit stream */ + /* Use of PPM and PPT are mutually exclusive. */ + /* Compare j2k_read_ppt() */ + int j; + + if (tcp->ppt != 1) { + return; /* Not present */ + } + + /* Tile-part indents are 12 spaces */ + fprintf(xmlout, + " <PackedPacketHeadersTilePartHeader Marker=\"PPT\">\n"); /* Optional in main header, but if not, must be in PPT or codestream */ + /* 2 bytes Lppm not saved */ + if (notes) { + fprintf(xmlout, + " <!-- If there are multiple PPT marker segments in the tile-part header, -->\n"); + fprintf(xmlout, + " <!-- this mj2_to_metadata implementation will report them as a single consolidated PPT header. -->\n"); + fprintf(xmlout, + " <!-- The implementation can't currently segregate by tile-part. -->\n"); + fprintf(xmlout, + " <!-- TO DO? further map the packet headers to xml. -->\n"); + } + + /* 1 byte, not retained ; Zppt is sequence # of this PPT header */ + /* 4 bytes, possibly overwritten multiple times in j2k_cp->ppt_previous: Nppt */ + /* Use j symbol for index instead of i, to make comparable with j2k_read_ppt */ + /* Not real clear whether to use ppt->store or ppt_len as upper bound */ + fprintf(xmlout, " <PackedData>\n"); + xml_out_dump_hex(xmlout, tcp->ppt_data, tcp->ppt_len); + /* Dump packet headers 1 byte at a time: lppt[i][j] */ + fprintf(xmlout, " </PackedData>\n"); + fprintf(xmlout, + " </PackedPacketHeadersTileHeader>\n"); /* Optional in tile-part header, but if not, must be in PPM or codestream */ +} +#endif SUPPRESS_FOR_NOW + +/* ------------- */ + +void xml_out_frame_tlm(FILE* + xmlout) /* opt, main header only. May be multiple. */ +{ + /* Compare j2k_read_tlm()... which doesn't retain anything! */ + /* Plan: Since this is only called from main header, not tilepart, use global j2k_default_tcp rather than parameter */ + /* Main header indents are 10 spaces */ +} + +/* ------------- */ + +void xml_out_frame_plm(FILE* + xmlout) /* opt, main header only; can be used in conjunction with tile-part's PLT */ +{ + /* NO-OP. PLM NOT SAVED IN DATA STRUCTURE */ + /* Compare j2k_read_plm()... which doesn't retain anything! */ + /* Plan: Since this is only called from main header, not tilepart, use global j2k_default_tcp rather than parameter */ + /* Main header indents are 10 spaces */ +} + +/* ------------- */ + +void xml_out_frame_plt(FILE* xmlout, + opj_tcp_t *tcp) /* opt, tile-part headers only; can be used in conjunction with main header's PLM */ +{ + /* NO-OP. PLT NOT SAVED IN DATA STRUCTURE */ + /* Compare j2k_read_plt()... which doesn't retain anything! */ + /* Tile-part header indents are 12 spaces */ +} + +/* ------------- */ + +void xml_out_frame_crg(FILE* xmlout) +{ + /* NO-OP. CRG NOT SAVED IN DATA STRUCTURE */ /* opt, main header only; */ + /* Compare j2k_read_crg()... which doesn't retain anything! */ + /* Plan: Since this is only called from main header, not tilepart, use global j2k_default_tcp rather than parameter */ +#ifdef NOTYET +THIS PSEUDOCODE IMAGINES THESE EXIST: + j2k_default_tcp->crg, j2k_default_tcp->crg_i, j2k_default_tcp->crg_xcrg*, + j2k_default_tcp->crg_ycrg* + (POSSIBLY DON'T NEED crg_i, CAN GET NUMBER OR COMPONENTS FROM ELSEWHERE) + if (j2k_default_tcp->crg != 1 || j2k_default_tcp->crg_i == 0) + return; /* Not present */ + + /* Main header indents are 10 spaces */ + fprintf(xmlout, + " <ComponentRegistration Marker=\"RG\" Count=\"%d\">\n", + j2k_default_tcp->crg_i); + if (notes) { + fprintf(xmlout, + " <!-- Fine tuning of registration of components with respect to each other, -->\n"); + fprintf(xmlout, + " <!-- not required but potentially helpful for decoder. -->\n"); + fprintf(xmlout, + " <!-- These supplementary fractional offsets are in units of 1/65536 of the horizontal -->\n"); + fprintf(xmlout, + " <!-- or vertical separation (e.g., XRsiz[i] or YRsiz[i] for component i). -->\n"); + } + /* This isn't the most compact form of table, but is OK when number of components is small, as is likely. */ + for (i = 0; i < j2k_default_tcp->crg_i; i++) { + fprintf(xmlout, " <Component Num=\"%d\">\n", i + 1); + fprintf(xmlout, " <Xcrg>\n"); + if (raw) { + fprintf(xmlout, " <AsNumerator>%d</AsNumerator>\n", + j2k_default_tcp->crg_xcrg[i]); + } + if (derived) { + /* Calculate n * 100%/65536; 4 digits after decimal point is sufficiently accurate */ + fprintf(xmlout, " <AsPercentage>%.4f</AsPercentage>\n", + ((double)j2k_default_tcp->crg_xcrg[i]) / 655.36); + /* We could do another calculation that include XRsiz[i]; maybe later. */ + } + fprintf(xmlout, " </Xcrg>\n"); + fprintf(xmlout, " <Ycrg>\n"); + if (raw) { + fprintf(xmlout, " <AsNumerator>%d</AsNumerator>\n", + j2k_default_tcp->crg_ycrg[i]); + } + if (derived) { + fprintf(xmlout, " <AsPercentage>%f</AsPercentage>\n", + ((double)j2k_default_tcp->crg_ycrg[i]) / 655.36); + } + fprintf(xmlout, " </Ycrg>\n"); + fprintf(xmlout, " </Component>\n"); + } + + fprintf(xmlout, " </ComponentRegistration>\n"); + +#endif +} + +/* ------------- */ + +/* Regrettably from a metadata point of view, j2k_read_com() skips over any comments in main header or tile-part-header */ +void xml_out_frame_com(FILE* xmlout, opj_tcp_t *tcp) +{ + /* NO-OP. COM NOT SAVED IN DATA STRUCTURE */ /* opt in main or tile-part headers; */ + /* Compare j2k_read_com()... which doesn't retain anything! */ +#ifdef NOTYET + char spaces[13] = " "; /* 12 spaces if tilepart*/ + char* s = spaces; + if (tcp == &j2k_default_tcp) { + s++; + s++; /* shorten s to 10 spaces if main */ + } +THIS PSEUDOCODE IMAGINES THESE EXIST: + tcp->com, tcp->com_len, tcp->com_data array + if (tcp->com != 1) { + return; /* Not present */ + } + + fprintf(xmlout, "%s<Comment Marker=\"COM\">\n", + s); /* Optional in main or tile-part header */ + xml_out_dump_hex_and_ascii(tcp->com_data, tcp->com_len, s); + fprintf(xmlout, "%s</Comment>\n", s); +#endif +} + +void xml_out_dump_hex(FILE* xmlout, char *data, int data_len, char* s) +{ + /* s is a string of spaces for indent */ + int i; + + /* This is called when raw is true, or there is no appropriate derived form */ + fprintf(xmlout, "%s<AsHex>\n", s); + fprintf(xmlout, "%s ", s); /* Inadequate for pretty printing */ + for (i = 0; i < data_len; i++) { /* Dump packet headers */ + fprintf(xmlout, "%02x", data[i]); + } + fprintf(xmlout, "%s</AsHex>\n", s); +} + +/* Define this as an even number: */ +#define BYTES_PER_DUMP_LINE 40 +/* Current total width for Hex and ASCII is : 11 spaces lead + (3 * BPDL) + 2 spaces + BPDL */ +void xml_out_dump_hex_and_ascii(FILE* xmlout, char *data, int data_len, + char* s) +{ + /* s is a string of spaces for indent */ + int i, j; + + if (raw) { + xml_out_dump_hex(xmlout, data, data_len, s); + } + + if (derived) { + fprintf(xmlout, "%s<AsHexAndASCII>\n", s); + for (i = 0; i < data_len;) { + fprintf(xmlout, "%s ", s); /* Additional leading space added in loop */ + /* First column: hex */ + for (j = 0; j < BYTES_PER_DUMP_LINE; j++) { /* Dump bytes */ + fprintf(xmlout, " %02x", data[i + j]); + } + /* Space between columns... */ fprintf(xmlout, " "); + /* Second column: ASCII */ + for (j = 0; j < BYTES_PER_DUMP_LINE; j++, i++) { + if (isprint((int)data[i]) && i < data_len) { + fprintf(xmlout, "%c", data[i]); + } else { + fprintf(xmlout, " "); + } + } + /* If we also wanted to output UCS-2 Unicode as a third column, then entire document + must use fwprintf. Forget about it for now. As it stands, if data is UCS-2 format but still + the ASCII set, then we'll be able to read every other byte as ASCII in column 2. If + data is UTF-8 format but still ASCII, then we'll be able to read every byte as ASCII + in column 2. */ + } + fprintf(xmlout, "%s</AsHexAndASCII>\n", s); + } +} + + +/* ------------- */ + +void xml_out_frame_jp2h(FILE* xmlout, opj_jp2_t *jp2_struct) /* JP2 Header */ +{ + /* Compare jp2_read_jp2h(opj_jp2_t * jp2_struct) */ + int i; + + fprintf(xmlout, " <JP2Header BoxType=\"jp2h\">\n"); + + /* Compare jp2_read_ihdr(jp2_struct)) */ + fprintf(xmlout, " <ImageHeader BoxType=\"ihdr\">\n"); + fprintf(xmlout, " <HEIGHT>%d</HEIGHT>\n", + jp2_struct->h); /* 4 bytes */ + fprintf(xmlout, " <WIDTH>%d</WIDTH>\n", + jp2_struct->w); /* 4 bytes */ + if (notes) { + fprintf(xmlout, + " <!-- HEIGHT here, if 2 fields per image, is of total deinterlaced height. -->\n"); + } + fprintf(xmlout, " <NC>%d</NC>\n", + jp2_struct->numcomps); /* 2 bytes */ + if (notes) { + fprintf(xmlout, + " <!-- NC is number of components -->\n"); /* 2 bytes */ + } + fprintf(xmlout, " <BPC>\n"); /* 1 byte */ + if (jp2_struct->bpc == 255) { + fprintf(xmlout, " <AsHex>0x%02x</AsHex>\n", + jp2_struct->bpc); /* 1 byte */ + if (notes) { + fprintf(xmlout, + " <!-- BPC = 0xff means bits per pixel varies with component; see table below. -->\n"); + } + } else { /* Not 0xff */ + if (raw) { + fprintf(xmlout, " <AsHex>0x%02x</AsHex>\n", + jp2_struct->bpc); /* 1 byte */ + if (notes) { + fprintf(xmlout, + " <!-- BPC = 0xff means bits per pixel varies with component; see table below. -->\n"); + } + } + if (derived) { + fprintf(xmlout, " <BitsPerPixel>%d</BitsPerPixel>\n", + jp2_struct->bpc & 0x7f); + fprintf(xmlout, " <Signed>%d</Signed>\n", + jp2_struct->bpc >> 7); + } + } + fprintf(xmlout, " </BPC>\n"); + fprintf(xmlout, " <C>%d</C>\n", + jp2_struct->C); /* 1 byte */ + if (notes) { + fprintf(xmlout, + " <!-- C is compression type. Only \"7\" is allowed to date. -->\n"); /* 2 bytes */ + } + fprintf(xmlout, " <UnkC>%d</UnkC>\n", + jp2_struct->UnkC); /* 1 byte */ + if (notes) { + fprintf(xmlout, + " <!-- Colourspace Unknown. 1 = unknown, 0 = known (e.g., colourspace spec is accurate) -->\n"); /* 1 byte */ + } + fprintf(xmlout, " <IPR>%d</IPR>\n", + jp2_struct->IPR); /* 1 byte */ + if (notes) { + fprintf(xmlout, + " <!-- IPR is 1 if frame contains an Intellectual Property box; 0 otherwise. -->\n"); /* 2 bytes */ + } + fprintf(xmlout, " </ImageHeader>\n"); + + if (jp2_struct->bpc == 255) { + fprintf(xmlout, " <BitsPerComponent BoxType=\"bpcc\">\n"); + if (notes) { + fprintf(xmlout, + " <!-- Pixel depth (range 1 to 38) is low 7 bits of hex value + 1 -->\n"); + } + /* Bits per pixel varies with components */ + /* Compare jp2_read_bpcc(jp2_struct) */ + for (i = 0; i < (int)jp2_struct->numcomps; i++) { + if (raw) { + fprintf(xmlout, " <AsHex>0x%02x</AsHex>\n", + jp2_struct->comps[i].bpcc); /* 1 byte */ + } + if (derived) { + fprintf(xmlout, " <BitsPerPixel>%d</BitsPerPixel>\n", + (jp2_struct->comps[i].bpcc & 0x7f) + 1); + fprintf(xmlout, " <Signed>%d</Signed>\n", + jp2_struct->comps[i].bpcc >> 7); + } + } + fprintf(xmlout, " </BitsPerComponent>\n"); + } + + /* Compare jp2_read_colr(jp2_struct) */ + fprintf(xmlout, + " <ColourSpecification BoxType=\"colr\">\n"); + fprintf(xmlout, " <METH>%d</METH>\n", + jp2_struct->meth); /* 1 byte */ + if (notes) { + fprintf(xmlout, + " <!-- Valid values of specification method so far: -->\n"); + fprintf(xmlout, + " <!-- 1 = Enumerated colourspace, in EnumCS field -->\n"); + fprintf(xmlout, + " <!-- 2 = Restricted ICC Profile, in PROFILE field -->\n"); + } + fprintf(xmlout, " <PREC>%d</PREC>\n", + jp2_struct->precedence); /* 1 byte */ + if (notes) { + fprintf(xmlout, + " <!-- 0 is only valid value of precedence so far. -->\n"); + } + fprintf(xmlout, " <APPROX>%d</APPROX>\n", + jp2_struct->approx); /* 1 byte */ + if (notes) { + fprintf(xmlout, + " <!-- 0 is only valid value of colourspace approximation so far. -->\n"); + } + + if (jp2_struct->meth == 1) { + fprintf(xmlout, " <EnumCS>%d</EnumCS>\n", + jp2_struct->enumcs); /* 4 bytes */ + if (notes) { + fprintf(xmlout, + " <!-- Valid values of enumerated MJ2 colourspace so far: -->\n"); + fprintf(xmlout, + " <!-- 16: sRGB as defined by IEC 61966-2-1. -->\n"); + fprintf(xmlout, + " <!-- 17: greyscale (related to sRGB). -->\n"); + fprintf(xmlout, + " <!-- 18: sRGB YCC (from JPEG 2000 Part II). -->\n"); + fprintf(xmlout, + " <!-- (Additional JPX values are defined in Part II). -->\n"); + } + } else if (notes) { + fprintf(xmlout, + " <!-- PROFILE is not handled by current OpenJPEG implementation. -->\n"); + } + /* only 1 byte is read and nothing stored */ + fprintf(xmlout, " </ColourSpecification>\n"); + + /* TO DO? No OpenJPEG support. + Palette 'pclr' + ComponentMapping 'cmap' + ChannelDefinition 'cdef' + Resolution 'res' + */ + fprintf(xmlout, " </JP2Header>\n"); +} +/* ------------- */ + +#ifdef NOTYET +IMAGE these use cp structure, + extended... but we could use a new data structure instead + void xml_out_frame_jp2i(FILE* xmlout, opj_cp_t *cp) +{ + /* IntellectualProperty 'jp2i' (no restrictions on location) */ + int i; + IMAGE cp->jp2i, cp->jp2i_count, cp->jp2i_data(array of chars), + cp->cp2i_len(array of ints) + if (cp->jp2i != 1) { + return; /* Not present */ + } + + for (i = 0; i < cp->jp2i_count; i++) { + fprintf(xmlout, " <IntellectualProperty BoxType=\"jp2i\">\n"); + /* I think this can be anything, including binary, so do a dump */ + /* Is it better to indent or not indent this content? Indent is better for reading, but + worse for cut/paste. */ + xml_out_dump_hex_and_ascii(xmlout, cp->jp2i_data[i], cp->jp2i_len[i]); + fprintf(xmlout, " </IntellectualProperty>\n"); + } +} + +void xml_out_frame_xml(FILE* xmlout, opj_cp_t *cp) +{ + /* XML 'xml\040' (0x786d6c20). Can appear multiply, before or after jp2c codestreams */ + IMAGE cp->xml, cp->xml_count, cp->xml_data(array of chars) + MAYBE WE DON'T NEED cp->xml_len (array of ints) IF WE ASSUME xml_data IS NULL-TERMINATED. + ASSUME ASSUME EACH LINE IS ENDED BY \n. + int i; + if (cp->xml != 1) { + return; /* Not present */ + } + + for (i = 0; i < cp->xml_count; i++) { + fprintf(xmlout, " <TextFormXML BoxType=\"xml[space]" Instance = + \"%d\">\n", i + 1); + /* Is it better to indent or not indent this content? Indent is better for reading, but + worse for cut/paste. Being lazy, didn't indent here. */ + fprintf(xmlout, + cp->xml_data[i]); /* May be multiple lines */ /* Could check if this is well-formed */ + fprintf(xmlout, " </TextFormXML>\n"); + } +} + +void xml_out_frame_uuid(FILE* xmlout, opj_cp_t *cp) +{ + /* UUID 'uuid' (top level only) */ + /* Part I 1.7.2 says: may appear multiply in JP2 file, anywhere except before File Type box */ + /* Part III 5.2.1 says: Private extensions shall be achieved through the 'uuid' type. */ + /* A UUID is a 16-byte value. There is a conventional string representation for it: + "0x12345678-9ABC-DEF0-1234-567890ABCDEF". Let's assume that is what is stored in uuid_value */ + + /* Part III 6.1 Any other MJ2 box type could be alternatively written as a 'uuid' box, with value given + as : 0xXXXXXXXX-0011-0010-8000-00AA00389B71, where the Xs are the boxtype in hex. However, + such a file is "not compliant; systems may choose to read [such] objects ... as equivalent to the box of + the same type, or not." Here, we choose not to. */ + int i; + IMAGE cp->uuid, cp->uuid_count, + cp->uuid_value(array of uuids... + let's say fixed-length strings) cp->uuid_data (array of char buffers), cp->uuid_len (array of ints) + if (cp->juuid != 1) + return; /* Not present */ + + for (i = 0; i < cp->uuid_count; i++) { + fprintf(xmlout, " <UniversalUniqueID BoxType=\"uuid\"> + fprintf(xmlout, " <UUID>%s</UUDI>\n", cp->uuid_value[i]); + fprintf(xmlout, " <Data>\n"); + /* I think this can be anything, including binary, so do a dump */ + /* Is it better to indent or not indent this content? Indent is better for reading, but + worse for cut/paste. */ + xml_out_dump_hex_and_ascii(xmlout, cp->uuid_data[i], cp->uuid_len[i]); + fprintf(xmlout, " </Data>\n"); + fprintf(xmlout, " </UniversalUniqueID>\n"); + } +} + +void xml_out_frame_uinf(FILE* xmlout, opj_cp_t *cp) +{ + /* UUIDInfo 'uinf', includes UUIDList 'ulst' and URL 'url\40' */ + /* Part I 1.7.3 says: may appear multiply in JP2 file, anywhere at the top level except before File Type box */ + /* So there may be multiple ulst's, and each can have multiple UUIDs listed (with a single URL) */ + /* This is not quite as vendor-specific as UUIDs, or at least is meant to be generally readable */ + /* Assume UUIDs stored in canonical string format */ + int i, j; + IMAGE cp->uinf, cp->uinf_count, cp->uinf_ulst_nu(array of ints) + cp->uinf_uuid(2 dimensional array of uuids... let's say fixed-length strings), + cp->uinf_url(array of char buffers) + + if (cp->uinf != 1) + return; /* Not present */ + + for (i = 0; i < cp->uuid_count; i++) { + fprintf(xmlout, " <UUIDInfo BoxType=\"uinf\">\n"); + fprintf(xmlout, " <UUIDList BoxType=\"ulst\" Count=\"%d\">\n", + cp->cp->uinf_ulst_nu[i]); + for (j = 0; j < cp->uinf_ulst_nu[i]; j++) { + fprintf(xmlout, " <ID Instance=\"%s\">%s</ID>\n", + cp->uuif_uuid[i][j], j + 1); + } + fprintf(xmlout, " </UUIDList>\n"); + fprintf(xmlout, " <DataEntryURL>\n"); + /* Could add VERS and FLAG here */ + fprintf(xmlout, " <LOC>\n"); + fprintf(xmlout, " %s", + cp->uinf_url[i]); /* Probably single line, so indent works */ /* In theory, could check if this is well-formed, or good live link */ + fprintf(xmlout, " </LOC>\n"); + fprintf(xmlout, " </DataEntryURL>\n"); + fprintf(xmlout, " </UUIDInfo>\n"); + } +} + +IMAGE these use cp structure, +extended... but we could use a new data structure instead +void xml_out_frame_unknown_type(FILE* xmlout, opj_cp_t *cp) +{ + /* Part III 5.2.1 says "Type fields not defined here are reserved. Private extensions + shall be acieved through the 'uuid' type." [This implies an unknown + type would be an error, but then...] "Boxes not explicitly defined in this standard, + or otherwise unrecognized by a reader, may be ignored." + Also, it says "the following types are not and will not be used, or used only in + their existing sense, in future versions of this specification, to avoid conflict + with existing content using earlier pre-standard versions of this format: + clip, crgn, matt, kmat, pnot, ctab, load, imap; + track reference types tmcd, chap, sync,scpt, ssrc" + [But good luck figuring out the mapping.] + Part III Amend. 2 4.1 is stronger: "All these specifications [of this family, e.g., + JP2 Part I, ISO Base format (Part 12) leading to MP4, Quicktime, and possibly including + MJ2] require that readers ignore objects that are unrecognizable to them". + */ + int i; + IMAGE cp->unknown_type, cp->unknown_type_count, + cp->unknown_type_boxtype(array of buf[5]s), + cp->unknown_type_data(array of chars), cp->unknown_type_len(array of ints) + if (cp->unknown_type != 1) { + return; /* Not present */ + } + + for (i = 0; i < cp->unknown_type_count; i++) { + fprintf(xmlout, " <UnknownType BoxType=\"%s\">\n", + cp->unknown_type_boxtype[i]); + /* Can be anything, including binary, so do a dump */ + /* Is it better to indent or not indent this content? Indent is better for reading, but + worse for cut/paste. */ + xml_out_dump_hex_and_ascii(xmlout, cp->unknown_type_data[i], + cp->unknown_type_len[i]); + fprintf(xmlout, " </UnknownType>\n"); + } +} + +#endif diff --git a/openjpeg/src/bin/mj2/meta_out.h b/openjpeg/src/bin/mj2/meta_out.h new file mode 100644 index 000000000..769ff3917 --- /dev/null +++ b/openjpeg/src/bin/mj2/meta_out.h @@ -0,0 +1,14 @@ +/* meta_out.h */ +/* Dump MJ2, JP2 metadata (partial so far) to xml file */ +/* Callable from mj2_to_metadata */ +/* Contributed to Open JPEG by Glenn Pearson, U.S. National Library of Medicine */ + +#define BOOL int +#define FALSE 0 +#define TRUE 1 + +void xml_write_init(BOOL n, BOOL t, BOOL r, BOOL d); + +int xml_write_struct(FILE *file, FILE *xmlout, opj_mj2_t * movie, + unsigned int sampleframe, char* stringDTD, opj_event_mgr_t *event_mgr); + diff --git a/openjpeg/src/bin/mj2/mj2_to_metadata.c b/openjpeg/src/bin/mj2/mj2_to_metadata.c new file mode 100644 index 000000000..44858c86a --- /dev/null +++ b/openjpeg/src/bin/mj2/mj2_to_metadata.c @@ -0,0 +1,349 @@ +/* mj2_to_metadata.c */ +/* Dump MJ2, JP2 metadata (partial so far) to xml file */ +/* Contributed to Open JPEG by Glenn Pearson, contract software developer, U.S. National Library of Medicine. + +The base code in this file was developed by the author as part of a video archiving +project for the U.S. National Library of Medicine, Bethesda, MD. +It is the policy of NLM (and U.S. government) to not assert copyright. + +A non-exclusive copy of this code has been contributed to the Open JPEG project. +Except for copyright, inclusion of the code within Open JPEG for distribution and use +can be bound by the Open JPEG open-source license and disclaimer, expressed elsewhere. +*/ + +#include "opj_includes.h" +#include "mj2.h" + +#include "mj2_to_metadata.h" +#include <string.h> +#include "opj_getopt.h" + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) +{ + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) +{ + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting a FILE* client object +*/ +void info_callback(const char *msg, void *client_data) +{ + FILE *stream = (FILE*)client_data; + fprintf(stream, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + + + +/* ------------- */ + +void help_display() +{ + /* "1234567890123456789012345678901234567890123456789012345678901234567890123456789" */ + fprintf(stdout, " Help for the 'mj2_to_metadata' Program\n"); + fprintf(stdout, " ======================================\n"); + fprintf(stdout, "The -h option displays this information on screen.\n\n"); + + fprintf(stdout, + "mj2_to_metadata generates an XML file from a Motion JPEG 2000 file.\n"); + fprintf(stdout, + "The generated XML shows the structural, but not (yet) curatorial,\n"); + fprintf(stdout, + "metadata from the movie header and from the JPEG 2000 image and tile\n"); + fprintf(stdout, + "headers of a sample frame. Excluded: low-level packed-bits image data.\n\n"); + + fprintf(stdout, "By Default\n"); + fprintf(stdout, "----------\n"); + fprintf(stdout, + "The metadata includes the jp2 image and tile headers of the first frame.\n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "Metadata values are shown in 'raw' form (e.g., hexadecimal) as stored in the\n"); + fprintf(stdout, + "file, and, if apt, in a 'derived' form that is more quickly grasped.\n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "Notes explaining the XML are embedded as terse comments. These include\n"); + fprintf(stdout, " meaning of non-obvious tag abbreviations;\n"); + fprintf(stdout, " range and precision of valid values;\n"); + fprintf(stdout, " interpretations of values, such as enumerations; and\n"); + fprintf(stdout, " current implementation limitations.\n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "The sample-size and chunk-offset tables, each with 1 row per frame, are not reported.\n"); + fprintf(stdout, "\n"); + fprintf(stdout, + "The file is self-contained and no verification (e.g., against a DTD) is requested.\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "Required Parameters (except with -h)\n"); + fprintf(stdout, "------------------------------------\n"); + fprintf(stdout, + "[Caution: file strings that contain spaces should be wrapped with quotes.]\n"); + fprintf(stdout, + "-i input.mj2 : where 'input' is any source file name or path.\n"); + fprintf(stdout, + " MJ2 files created with 'frames_to_mj2' are supported so far.\n"); + fprintf(stdout, + " These are silent, single-track, 'MJ2 Simple Profile' videos.\n"); + fprintf(stdout, + "-o output.xml : where 'output' is any destination file name or path.\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "Optional Parameters\n"); + fprintf(stdout, "-------------------\n"); + fprintf(stdout, "-h : Display this help information.\n"); + fprintf(stdout, "-n : Suppress all mj2_to_metadata notes.\n"); + fprintf(stdout, + "-t : Include sample-size and chunk-offset tables.\n"); + fprintf(stdout, + "-f n : where n > 0. Include jp2 header info for frame n [default=1].\n"); + fprintf(stdout, "-f 0 : No jp2 header info.\n"); + fprintf(stdout, + "-r : Suppress all 'raw' data for which a 'derived' form exists.\n"); + fprintf(stdout, "-d : Suppress all 'derived' data.\n"); + fprintf(stdout, + " (If both -r and -d given, -r will be ignored.)\n"); + fprintf(stdout, + "-v string : Verify against the DTD file located by the string.\n"); + fprintf(stdout, + " Prepend quoted 'string' with either SYSTEM or PUBLIC keyword.\n"); + fprintf(stdout, + " Thus, for the distributed DTD placed in the same directory as\n"); + fprintf(stdout, + " the output file: -v \"SYSTEM mj2_to_metadata.dtd\"\n"); + fprintf(stdout, + " \"PUBLIC\" is used with an access protocol (e.g., http:) + URL.\n"); + /* More to come */ + fprintf(stdout, "\n"); + /* "1234567890123456789012345678901234567890123456789012345678901234567890123456789" */ +} + +/* ------------- */ + +int main(int argc, char *argv[]) +{ + + opj_dinfo_t* dinfo; + opj_event_mgr_t event_mgr; /* event manager */ + + FILE *file, *xmlout; + /* char xmloutname[50]; */ + opj_mj2_t *movie; + + char* infile = 0; + char* outfile = 0; + char* s, S1, S2, S3; + int len; + unsigned int sampleframe = 1; /* First frame */ + char* stringDTD = NULL; + BOOL notes = TRUE; + BOOL sampletables = FALSE; + BOOL raw = TRUE; + BOOL derived = TRUE; + mj2_dparameters_t parameters; + + while (TRUE) { + /* ':' after letter means it takes an argument */ + int c = getopt(argc, argv, "i:o:f:v:hntrd"); + /* FUTURE: Reserve 'p' for pruning file (which will probably make -t redundant) */ + if (c == -1) { + break; + } + switch (c) { + case 'i': /* IN file */ + infile = optarg; + s = optarg; + while (*s) { + s++; /* Run to filename end */ + } + s--; + S3 = *s; + s--; + S2 = *s; + s--; + S1 = *s; + + if ((S1 == 'm' && S2 == 'j' && S3 == '2') + || (S1 == 'M' && S2 == 'J' && S3 == '2')) { + break; + } + fprintf(stderr, "Input file name must have .mj2 extension, not .%c%c%c.\n", S1, + S2, S3); + return 1; + + /* ----------------------------------------------------- */ + case 'o': /* OUT file */ + outfile = optarg; + while (*outfile) { + outfile++; /* Run to filename end */ + } + outfile--; + S3 = *outfile; + outfile--; + S2 = *outfile; + outfile--; + S1 = *outfile; + + outfile = optarg; + + if ((S1 == 'x' && S2 == 'm' && S3 == 'l') + || (S1 == 'X' && S2 == 'M' && S3 == 'L')) { + break; + } + + fprintf(stderr, + "Output file name must have .xml extension, not .%c%c%c\n", S1, S2, S3); + return 1; + + /* ----------------------------------------------------- */ + case 'f': /* Choose sample frame. 0 = none */ + sscanf(optarg, "%u", &sampleframe); + break; + + /* ----------------------------------------------------- */ + case 'v': /* Verification by DTD. */ + stringDTD = optarg; + /* We will not insist upon last 3 chars being "dtd", since non-file + access protocol may be used. */ + if (strchr(stringDTD, '"') != NULL) { + fprintf(stderr, + "-D's string must not contain any embedded double-quote characters.\n"); + return 1; + } + + if (strncmp(stringDTD, "PUBLIC ", 7) == 0 || + strncmp(stringDTD, "SYSTEM ", 7) == 0) { + break; + } + + fprintf(stderr, "-D's string must start with \"PUBLIC \" or \"SYSTEM \"\n"); + return 1; + + /* ----------------------------------------------------- */ + case 'n': /* Suppress comments */ + notes = FALSE; + break; + + /* ----------------------------------------------------- */ + case 't': /* Show sample size and chunk offset tables */ + sampletables = TRUE; + break; + + /* ----------------------------------------------------- */ + case 'h': /* Display an help description */ + help_display(); + return 0; + + /* ----------------------------------------------------- */ + case 'r': /* Suppress raw data */ + raw = FALSE; + break; + + /* ----------------------------------------------------- */ + case 'd': /* Suppress derived data */ + derived = FALSE; + break; + + /* ----------------------------------------------------- */ + default: + return 1; + } /* switch */ + } /* while */ + + if (!raw && !derived) { + raw = TRUE; /* At least one of 'raw' and 'derived' must be true */ + } + + /* Error messages */ + /* -------------- */ + if (!infile || !outfile) { + fprintf(stderr, + "Correct usage: mj2_to_metadata -i mj2-file -o xml-file (plus options)\n"); + return 1; + } + + /* was: + if (argc != 3) { + printf("Bad syntax: Usage: MJ2_to_metadata inputfile.mj2 outputfile.xml\n"); + printf("Example: MJ2_to_metadata foreman.mj2 foreman.xml\n"); + return 1; + } + */ + len = strlen(infile); + if (infile[0] == ' ') { + infile++; /* There may be a leading blank if user put space after -i */ + } + + file = fopen(infile, "rb"); /* was: argv[1] */ + + if (!file) { + fprintf(stderr, "Failed to open %s for reading.\n", infile); /* was: argv[1] */ + return 1; + } + + len = strlen(outfile); + if (outfile[0] == ' ') { + outfile++; /* There may be a leading blank if user put space after -o */ + } + + // Checking output file + xmlout = fopen(outfile, "w"); /* was: argv[2] */ + if (!xmlout) { + fprintf(stderr, "Failed to open %s for writing.\n", outfile); /* was: argv[2] */ + return 1; + } + // Leave it open + + /* + configure the event callbacks (not required) + setting of each callback is optional + */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* get a MJ2 decompressor handle */ + dinfo = mj2_create_decompress(); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using user parameters */ + movie = (opj_mj2_t*) dinfo->mj2_handle; + mj2_setup_decoder(dinfo->mj2_handle, ¶meters); + + if (mj2_read_struct(file, movie)) { // Creating the movie structure + fclose(xmlout); + return 1; + } + + xml_write_init(notes, sampletables, raw, derived); + xml_write_struct(file, xmlout, movie, sampleframe, stringDTD, &event_mgr); + fclose(xmlout); + + fprintf(stderr, "Metadata correctly extracted to XML file \n");; + + /* free remaining structures */ + if (dinfo) { + mj2_destroy_decompress((opj_mj2_t*)dinfo->mj2_handle); + } + + return 0; +} + + diff --git a/openjpeg/src/bin/mj2/mj2_to_metadata.dtd b/openjpeg/src/bin/mj2/mj2_to_metadata.dtd new file mode 100644 index 000000000..249de1a07 --- /dev/null +++ b/openjpeg/src/bin/mj2/mj2_to_metadata.dtd @@ -0,0 +1,425 @@ +<!-- +Preliminary DTD for Open JPEG "mj2_to_metadata" function. +Last revised: April 20, 2005 +Author: Glenn Pearson, at U.S. National Library of Medicine. +See mj2_to_metadata.c regarding copyright, license, disclaimer status. + +While the vocabulary of this DTD is based on the relevant portions of the +ISO/IEC JPEG 200 standard, the detailed representation is the author's own. +It is neither an ISO/IEC nor NLM official or consensus representation. +Furthermore, it deviates from a pure representation of the ISO/IEC standard +in these aspects: + + - it is incomplete in a number of ways (which to some extent may be + addressed over time); + - it has extensions for "derived" data and "statistics"; + - it is more flexible. That is, some elements are marked as optional + not because they are optional in an MJ2 file, but because reporting + of them is optional based on current or projected mj2_to_metadata + command-line flags. +--> +<!ELEMENT MJ2_File (JP2?, FileType?, MovieBox?)> +<!ELEMENT JP2 EMPTY> +<!ATTLIST JP2 BoxType CDATA #FIXED "jP[space][space]"> +<!ATTLIST JP2 Signature CDATA #FIXED "0x0d0a870a"> +<!ELEMENT FileType (Brand, MinorVersion, CompatibilityList)> +<!ATTLIST FileType BoxType CDATA #FIXED "ftyp"> +<!ELEMENT Brand (#PCDATA)> <!-- 4 characters max --> +<!ELEMENT MinorVersion (#PCDATA)> <!-- 4 chararcters max --> +<!ELEMENT CompatibilityList (CompatibleBrand)*> +<!ATTLIST CompatibilityList Count CDATA #REQUIRED> <!-- Count >= 0 --> +<!ELEMENT CompatibleBrand (#PCDATA)> <!-- 4 characters max --> +<!ELEMENT MovieBox (MovieHeader, Statistics?, Track*)> +<!ATTLIST MovieBox BoxType CDATA #FIXED "moov"> +<!ELEMENT MovieHeader (CreationTime, ModificationTime, Timescale, Rate, Duration, Volume, TransformationMatrix)> +<!ATTLIST MovieHeader BoxType CDATA #FIXED "mvhd"> +<!ELEMENT CreationTime (InSeconds?,AsLocalTime?)> +<!ELEMENT InSeconds (#PCDATA)> +<!ELEMENT AsLocalTime (#PCDATA)> +<!ELEMENT ModificationTime (InSeconds?,AsLocalTime?)> +<!ELEMENT Timescale (#PCDATA)> <!-- Timescale defines time units in one second --> +<!ELEMENT Rate (AsHex | (AsHex, AsDecimal) | AsDecimal)> <!-- Decimal is Approximation; Optional on input. --> +<!ELEMENT AsHex (#PCDATA)> +<!ELEMENT AsDecimal (#PCDATA)> +<!ELEMENT Duration (InTimeUnits | (InTimeUnits, InSeconds) | InSeconds)> <!-- InSeconds Optional on input. --> +<!ELEMENT InTimeUnits (#PCDATA)> +<!ELEMENT Volume (AsHex | (AsHex, AsDecimal) | AsDecimal)> <!-- hex default = 0x0100 --> +<!-- Fixed 8.8 value of audio volume. Full, normal value is 1.0 (0x0100) --> +<!ELEMENT TransformationMatrix (TMa,TMb,TMu,TMc,TMd,TMv,TMx,TMy,TMw)> <!-- for video --> +<!-- 3 x 3 Video Transformation Matrix {a,b,u,c,d,v,x,y,w}. Required: u=0, v=0, w=1 --> +<!-- Maps decompressed point (p,q) to rendered point (ap + cq + x, bp + dq + y) --> +<!-- Stored as Fixed Point Hex: all are 16.16, except u,v,w are 2.30 --> +<!-- Unity = 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 --> +<!ELEMENT TMa (#PCDATA)> +<!ELEMENT TMb (#PCDATA)> +<!ELEMENT TMu (#PCDATA)> <!--Always "0x00000000" --> +<!ELEMENT TMc (#PCDATA)> +<!ELEMENT TMd (#PCDATA)> +<!ELEMENT TMv (#PCDATA)> <!--Always "0x00000000" --> +<!ELEMENT TMx (#PCDATA)> +<!ELEMENT TMy (#PCDATA)> +<!ELEMENT TMw (#PCDATA)> <!--Always "0x40000000" --> + +<!ELEMENT Statistics (TracksFound)> +<!ELEMENT TracksFound (Video,Audio,Hint)> +<!ELEMENT Video (#PCDATA)> +<!ELEMENT Audio (#PCDATA)> +<!ELEMENT Hint (#PCDATA)> + + +<!-- For now, output info on at most one video track --> + + +<!ELEMENT Track (TrackHeader, TrackReferenceContainer?, EditListContainer?, Media, JP2_Frame?)> <!-- JP2_Frame is mj2_to_metadata extension --> +<!ATTLIST Track BoxType CDATA #FIXED "trak"> +<!ATTLIST Track Instance CDATA #REQUIRED> +<!ELEMENT TrackHeader (TrackID, TrackLayer?, Volume?, TransformationMatrix?, Width?, Height?)> +<!ATTLIST TrackHeader BoxType CDATA #FIXED "tkhd"> +<!-- Not shown here: CreationTime, ModificationTime, Duration. --> +<!-- These 3 fields are reported under MediaHeader below. When reading these 3, --> +<!-- m2j_to_metadata currently doesn't distinguish between TrackHeader and MediaHeader source. --> +<!-- If both found, value read from MediaHeader is used. --> +<!ELEMENT TrackID (#PCDATA)> +<!ELEMENT TrackLayer (#PCDATA)> <!-- front-to-back ordering of video tracks. 0 = normal, -1 is closer, etc. --> +<!-- "Volume" element described above; here it is for particular audio track. Full, normal (default = 0x0100) --> +<!-- "TransformationMatrix" element described above; matrix here is applied before MovieHeader one. --> +<!ELEMENT Width (AsHex | (AsHex, AsDecimal) | AsDecimal)> +<!ELEMENT Height (AsHex | (AsHex, AsDecimal) | AsDecimal)> +<!-- AsHex, AsDecimal already defined above --> + <!-- Width and Height are for the presentation; frames will be scaled to this --> +<!-- /TrackHeader --> +<!ELEMENT TrackReferenceContainer ANY> <!-- TO DO: TrackReferenceContainer 'tref' just used in hint track --> +<!ELEMENT EditListContainer ANY> <!-- TO DO: EditListContainer 'edts', contains EditList 'elst' with media-time, segment-duration, media-rate --> +<!ELEMENT Media (MediaHeader, HandlerReference,MediaInfoContainer)> +<!ATTLIST Media BoxType CDATA #FIXED "mdia"> +<!ELEMENT MediaHeader (CreationTime,ModificationTime,Timescale,Duration,Language)> +<!ATTLIST MediaHeader BoxType CDATA #FIXED "mdhd"> +<!-- Elements already defined above: CreationTime, ModificationTime, Timescale, Duration --> +<!ELEMENT Language (#PCDATA)> <!-- 3 chars max. There's an enumeration available --> +<!ELEMENT HandlerReference (HandlerType)> +<!ATTLIST HandlerReference BoxType CDATA #FIXED "hdlr"> +<!ELEMENT HandlerType (#PCDATA)> +<!ATTLIST HandlerType Code ( vide | soun | hint ) "vide"> + +<!-- make the media headers multiple? --> +<!ELEMENT MediaInfoContainer ((VideoMediaHeader | SoundMediaHeader | HintMediaHeader), DataInfo, SampleTable)> +<!ATTLIST MediaInfoContainer BoxType CDATA #FIXED "minf"> +<!ELEMENT VideoMediaHeader (GraphicsMode, Opcolor)> +<!ATTLIST VideoMediaHeader BoxType CDATA #FIXED "vmhd"> +<!ELEMENT GraphicsMode (#PCDATA)> + <!-- Enumerated values of graphics mode: --> + <!-- 0x00 = copy (over existing image); --> + <!-- 0x24 = transparent; 'blue-screen' this image using opcolor; --> + <!-- 0x100 = alpha; alpha-blend this image --> + <!-- 0x101 = whitealpha; alpha-blend this image, which has been blended with white; --> + <!-- 0x102 = blackalpha; alpha-blend this image, which has been blended with black. --> +<!ELEMENT Opcolor (Red,Green,Blue)> +<!ELEMENT Red (#PCDATA)> +<!ELEMENT Green (#PCDATA)> +<!ELEMENT Blue (#PCDATA)> +<!ELEMENT SoundMediaHeader (Balance)> +<!ATTLIST SoundMediaHeader BoxType CDATA #FIXED "smhd"> +<!ELEMENT Balance (#PCDATA)> + <!-- Fixed Point 8.8, fixes mono track in stereo space. --> + <!-- 0.0 = center, -1.0 = full left, 1.0 = full right --> +<!ELEMENT HintMediaHeader (MaxPDU_Size, AvgPDU_Size, MaxBitRate, AvgBitRate, SlidingAvgBitRate)> +<!ATTLIST HintMediaHeader BoxType CDATA #FIXED "hmhd"> +<!ELEMENT MaxPDU_Size (#PCDATA)> + <!-- Size in bytes of largest PDU in this hint stream. --> +<!ELEMENT AvgPDU_Size (#PCDATA)> + <!-- Average size in bytes of a PDU over the entire presentation. --> +<!ELEMENT MaxBitRate (#PCDATA)> + <!-- Maximum rate in bits per second over any window of 1 second. --> +<!ELEMENT AvgBitRate (#PCDATA)> + <!-- Averate rate in bits per second over the entire presentation. --> +<!ELEMENT SlidingAvgBit (#PCDATA)> + <!-- Maximum rate in bits per second over any window of one minute. --> + +<!ELEMENT DataInfo (DataReference)> +<!ATTLIST DataInfo BoxType CDATA #FIXED "dinf"> +<!ELEMENT DataReference (DataEntryUrlBox | DataEntryUrnBox )*> +<!ATTLIST DataReference BoxType CDATA #FIXED "dref"> +<!ATTLIST DataReference URL_Count CDATA #REQUIRED> +<!ATTLIST DataReference URN_Count CDATA #REQUIRED> <!-- table w. flags, URLs, URNs --> +<!-- // Data structure does not distinguish between single URL, single URN, or DREF table or URLs & URNs. + // We could infer those, but for now just present everything as a DREF table. +--> + <!-- No entries here mean that file is self-contained, as required by Simple Profile. --> + +<!ELEMENT DataEntryUrlBox (Location)> +<!ATTLIST DataEntryUrlBox BoxType CDATA #FIXED "url[space]"> <!-- table w. flags, URLs, URNs --> + <!-- Only the first 16 bytes of URL location are recorded in mj2_to_metadata data structure. --> +<!ELEMENT DataEntryUrnBox (Name, Location?)> +<!ATTLIST DataEntryUrnBox BoxType CDATA #FIXED "urn[space]\"> + <!-- Only the first 16 bytes each of URN name and optional location are recorded in mj2_to_metadata data structure. --> + +<!ELEMENT SampleTable (VisualSampleEntry,TimeToSample,SampleToChunk,SampleSize,ChunkOffset)> <!-- structure doesn't do non-visual sample entry yet --> +<!ATTLIST SampleTable BoxType CDATA #FIXED "stbl"> <!-- to add: entry count --> + <!-- Next are instances of generic SampleDescription BoxType=\"stsd\" --> + + <!-- There could be multiple instances of this, but "entry_count" is just a local at read-time. + And it's used wrong, too, as count of just visual type, when it's really all 3 types. + This is referred to as "smj2" within mj2.c --> +<!ELEMENT VisualSampleEntry (WidthAsInteger, HeightAsInteger, HorizontalRes, VerticalRes, CompressorName, Depth, JP2Header?, FieldCoding?, MJP2_Profile?, MJP2_Prefix?, MJP2_SubSampling?, MJP2_OriginalFormat?)> +<!ATTLIST VisualSampleEntry BoxType CDATA #FIXED "mjp2"> + <!-- If multiple instances of this, only first is shown here. --> +<!ELEMENT WidthAsInteger (#PCDATA)> +<!ELEMENT HeightAsInteger (#PCDATA)> +<!ELEMENT HorizontalRes (AsHex | (AsHex, AsDecimal) | AsDecimal)> +<!ELEMENT VerticalRes (AsHex | (AsHex, AsDecimal) | AsDecimal)> +<!-- Typical value for both resolution is 72 (0x00480000) --> +<!ELEMENT CompressorName (#PCDATA)> + <!-- Compressor name for debugging. Standard restricts max length to 31 bytes. --> + <!-- Usually blank or \"Motion JPEG2000\" --> +<!ELEMENT Depth (#PCDATA)> + <!-- Depth is: --> + <!-- 0x20: alpha channels present (color or grayscale) --> + <!-- 0x28: grayscale without alpha --> + <!-- 0x18: color without alpha --> + +<!-- TODO somewhere: tk->jp2_struct.numcomps --> +<!ELEMENT JP2Header (ImageHeader, ColourSpecification)> +<!ATTLIST JP2Header BoxType CDATA #FIXED "jp2h"> +<!ELEMENT ImageHeader (HEIGHT, WIDTH, NC, BPC, C, UnkC, IPR)> +<!ATTLIST ImageHeader BoxType CDATA #FIXED "ihdr"> +<!ELEMENT HEIGHT (#PCDATA)> <!-- If 2 fields/frame, total deinterlaced height --> +<!ELEMENT WIDTH (#PCDATA)> +<!ELEMENT NC (#PCDATA)> <!-- number of components --> +<!ELEMENT BPC (AsHex | (AsHex,BitsPerPixel,Signed) | (BitsPerPixel,Signed))> +<!ELEMENT BitsPerPixel (#PCDATA)> +<!ELEMENT Signed (#PCDATA)> +<!ELEMENT C (#PCDATA)> <!-- Compression type. Only "7" defined --> +<!ELEMENT UnkC (#PCDATA)> <!-- Colourspace Unknown. 1 = unknown, 0 = known --> +<!ELEMENT IPR (#PCDATA)> <!-- 1 = frame has Intellectual Prop. box; otherwise 0 --> +<!ELEMENT ColourSpecification (METH, PREC, APPROX, EnumCS)> +<!ATTLIST ColourSpecification BoxType CDATA #FIXED "colr"> +<!ELEMENT METH (#PCDATA)> <!-- 1 = EnumCS field; 2 = PROFILE field (not yet generated) --> +<!ELEMENT PREC (#PCDATA)> <!-- precedence must be 0 so far --> +<!ELEMENT APPROX (#PCDATA)> <!-- colourspace approximation must be 0 so far --> +<!ELEMENT EnumCS (#PCDATA)> <!-- Valid enumerated MJ2 colourspaces: 16 (sRGB), 17 (grey sRGB), 18 (YCC) --> + +<!-- Following subboxes are optional --> +<!ELEMENT FieldCoding (FieldCount, FieldOrder)> +<!ATTLIST FieldCoding BoxType CDATA #FIXED "fiel"> +<!ELEMENT FieldCount (#PCDATA)> + <!-- Must be either 1 or 2 --> +<!ELEMENT FieldOrder (#PCDATA)> + <!-- When FieldCount=2, FieldOrder means: --> + <!-- 0: Field coding unknown --> + <!-- 1: Field with topmost line is stored first in sample; fields are in temporal order --> + <!-- 6: Field with topmost line is stored second in sample; fields are in temporal order --> + <!-- Defaults: FieldCount=1, FieldOrder=0 if FieldCoding box not present --> + <!-- Current implementation doesn't retain whether box was actually present. --> + +<!ELEMENT MJP2_Profile (CompatibleBrand*)> +<!ATTLIST MJP2_Profile BoxType CDATA #FIXED "jp2p"> +<!ATTLIST MJP2_Profile Count CDATA #REQUIRED> + +<!ELEMENT MJP2_Prefix (Data*)> +<!ATTLIST MJP2_Prefix BoxType CDATA #FIXED "jp2x"> +<!ATTLIST MJP2_Prefix Count CDATA #REQUIRED> +<!-- We'll probably need better formatting than this --> +<!ELEMENT Data (#PCDATA)> <!-- Multiple. Each entry is single byte --> + +<!ELEMENT MJP2_SubSampling (HorizontalSub, VerticalSub, HorizontalOffset, VerticalOffset)> +<!ATTLIST MJP2_SubSampling BoxType CDATA #FIXED "jsub"> +<!-- These values are all 1 byte --> + <!-- Typical subsample value is 2 for 4:2:0 --> +<!ELEMENT HorizontalSub (#PCDATA)> +<!ELEMENT VerticalSub (#PCDATA)> +<!ELEMENT HorizontalOffset (#PCDATA)> +<!ELEMENT VerticalOffset (#PCDATA)> + +<!ELEMENT MJP2_OriginalFormat (OriginalFieldCount, OriginalFieldOrder)> +<!ATTLIST MJP2_OriginalFormat BoxType CDATA #FIXED "orfo"> <!-- Part III Appx. 2 --> +<!ELEMENT OriginalFieldCount (#PCDATA)> + <!-- In original material before encoding. Must be either 1 or 2 --> +<!ELEMENT OriginalFieldOrder (#PCDATA)> + <!-- When FieldCount=2, FieldOrder means: --> + <!-- 0: Field coding unknown --> + <!-- 11: Topmost line came from the earlier field; --> + <!-- 16: Topmost line came form the later field. --> + <!-- Defaults: FieldCount=1, FieldOrder=0 if FieldCoding box not present --> + <!-- Current implementation doesn't retain whether box was actually present. --> + + + <!-- mj2_to_metadata's data structure doesn't record Audio and Hint sample data currently. --> + +<!-- Within SampleTable: --> +<!ELEMENT TimeToSample (SampleStatistics, SampleEntries)> +<!ATTLIST TimeToSample BoxType CDATA #FIXED "stts"> +<!ELEMENT SampleStatistics (TotalSamples)> <!-- Not part of standard --> +<!ELEMENT TotalSamples (#PCDATA)> + <!-- For video, gives the total frames in the track, by summing all entries in the Sample Table --> + +<!ELEMENT SampleEntries (Table*)> +<!ATTLIST SampleEntries EntryCount CDATA #REQUIRED> +<!ELEMENT Table EMPTY> <!-- Multiple. Attributes have values --> +<!ATTLIST Table Entry CDATA #REQUIRED> +<!ATTLIST Table SampleCount CDATA #REQUIRED> +<!ATTLIST Table SampleDelta CDATA #REQUIRED> + +<!-- Within SampleTable: --> +<!ELEMENT SampleToChunk (FirstChunk,SamplesPerChunk,SampleDescrIndex)> +<!ATTLIST SampleToChunk BoxType CDATA #FIXED "stsc"> +<!ATTLIST SampleToChunk Count CDATA #REQUIRED> +<!ELEMENT FirstChunk (#PCDATA)> +<!ELEMENT SamplesPerChunk (#PCDATA)> +<!ELEMENT SampleDescrIndex (#PCDATA)> +<!ELEMENT SampleSize (Sample_Size,Sample_Count,EntrySize*)> +<!ATTLIST SampleSize BoxType CDATA #FIXED "stsz"> +<!ELEMENT Sample_Size (#PCDATA)> +<!ELEMENT Sample_Count (#PCDATA)> +<!ELEMENT EntrySize (#PCDATA)> <!-- appears multiply, but only with mj2_to_metadata option -t --> +<!ATTLIST EntrySize Num CDATA #REQUIRED> +<!ELEMENT ChunkOffset (EntryCount, Chunk_Offset*)> +<!ATTLIST ChunkOffset BoxType CDATA #FIXED "stco"> +<!ELEMENT EntryCount (#PCDATA)> +<!ELEMENT Chunk_Offset (#PCDATA)> <!-- appears multiply, but only with mj2_to_metadata option -t --> +<!ATTLIST Chunk_Offset Num CDATA #REQUIRED> +<!-- </SampleTable> </MediaInfoContainer> </Media> --> + +<!-- TO DO: optional UserData 'udat', can contain multiple Copyright 'cprt' --> + + +<!-- Optional, and only for Visual Track: given individual frame --> +<!ELEMENT JP2_Frame (MainHeader, TilePartHeaders)> +<!ATTLIST JP2_Frame Num CDATA #REQUIRED> +<!ELEMENT MainHeader (StartOfCodestream,ImageAndFileSize,CodingStyleDefault,QuantizationDefault,QuantizationComponent*,RegionOfInterest?,ProgressionOrderChange*)> +<!ELEMENT StartOfCodestream EMPTY> +<!ATTLIST StartOfCodestream Marker CDATA #FIXED "SOC"> +<!ELEMENT ImageAndFileSize (Xsiz,Ysiz,XOsiz,YOsiz,XTsiz,YTsiz,XTOsiz,YTOsiz,Csiz,Component+)> +<!ATTLIST ImageAndFileSize Marker CDATA #FIXED "SIZ"> +<!ELEMENT Xsiz (#PCDATA)> +<!ELEMENT Ysiz (#PCDATA)> <!-- Xsiz, Ysiz is the size of the reference grid. --> +<!ELEMENT XOsiz (#PCDATA)> +<!ELEMENT YOsiz (#PCDATA)> <!-- XOsiz, YOsiz are offsets from grid origin to image origin. --> +<!ELEMENT XTsiz (#PCDATA)> +<!ELEMENT YTsiz (#PCDATA)> <!-- XTsiz, YTsiz is the size of one tile with respect to the grid. --> +<!ELEMENT XTOsiz (#PCDATA)> +<!ELEMENT YTOsiz (#PCDATA)> <!-- XTOsiz, YTOsiz are offsets from grid origin to first tile origin. --> +<!ELEMENT Csiz (#PCDATA)> <!-- Csiz is the number of components in the image. --> +<!-- For image components next --> +<!ELEMENT Component (Ssiz,XRsiz,YRsiz,WidthOfData,HeightOfData)> +<!ATTLIST Component Num CDATA #REQUIRED> +<!ELEMENT Ssiz (AsHex | (AsHex,Signed,PrecisionInBits) | (Signed,PrecisionInBits))> +<!-- Signed already defined --> +<!ELEMENT PrecisionInBits (#PCDATA)> <!-- Bits per pixel (bpp) or pixel depth. --> +<!ELEMENT XRsiz (#PCDATA)> +<!ELEMENT YRsiz (#PCDATA)> <!-- XRsiz, YRsiz denote pixel-sample-spacing on the grid, per Part I Annex B. --> +<!ELEMENT WidthOfData (#PCDATA)> +<!ELEMENT HeightOfData (#PCDATA)> <!-- WidthOfData and HeightOfData are calculated values, e.g.: w = roundup((Xsiz - XOsiz)/ XRsiz) --> +<!-- --> +<!ELEMENT CodingStyleDefault (Scod,SGcod,SPcod)> +<!ATTLIST CodingStyleDefault Marker CDATA #FIXED "COD"> +<!ELEMENT Scod (#PCDATA)> + <!-- For Scod, specific bits mean (where bit 0 is lowest or rightmost): --> + <!-- bit 0: Defines entropy coder precincts --> + <!-- 0 = (PPx=15, PPy=15); 1 = precincts defined below. --> + <!-- bit 1: 1 = SOP marker may be used; 0 = not. --> + <!-- bit 2: 1 = EPH marker may be used; 0 = not. --> +<!ELEMENT SGcod (ProgressionOrder,NumberOfLayers,MultipleComponentTransformation)> +<!ELEMENT ProgressionOrder (#PCDATA)> + <!-- Defined Progression Order Values are: --> + <!-- 0 = LRCP; 1 = RLCP; 2 = RPCL; 3 = PCRL; 4 = CPRL --> + <!-- where L = "layer", R = "resolution level", C = "component", P = "position". --> +<!ELEMENT NumberOfLayers (#PCDATA)> +<!ELEMENT MultipleComponentTransformation (#PCDATA)> + <!-- For MCT, 0 = none, 1 = transform first 3 components for efficiency, per Part I Annex G --> +<!ELEMENT SPcod (NumberOfDecompositionLevels,CodeblockWidth,CodeblockHeight,CodeblockStyle,Transformation)> +<!ELEMENT NumberOfDecompositionLevels (#PCDATA)> +<!ELEMENT CodeblockWidth (#PCDATA)> <!-- CBW and CBH are non-negative, and summed cannot exceed 8 --> +<!ELEMENT CodeblockHeight (#PCDATA)> <!-- Codeblock dimension is 2^(value + 2) --> +<!ELEMENT CodeblockStyle (#PCDATA)> + <!-- For CodeblockStyle, bits mean (with value 1=feature on, 0=off): --> + <!-- bit 0: Selective arithmetic coding bypass. --> + <!-- bit 1: Reset context probabilities on coding pass boundaries. --> + <!-- bit 2: Termination on each coding pass. --> + <!-- bit 3: Vertically causal context. --> + <!-- bit 4: Predictable termination. --> + <!-- bit 5: Segmentation symbols are used. --> +<!ELEMENT Transformation (#PCDATA)> <!-- For Transformation, 0="9-7 irreversible filter", 1="5-3 reversible filter" --> + <!-- mj2_to_metadata implementation always reports component[0] as using default COD, --> + <!-- and any other component, with main-header style values different from [0], as COC. --> +<!ELEMENT QuantizationDefault (Sqcd,SPqcd)> +<!ATTLIST QuantizationDefault Marker CDATA #FIXED "QCD"> +<!ELEMENT Sqcd (AsHex | (AsHex,QuantizationStyle,NumberOfGuardBits) | (QuantizationStyle,NumberOfGuardBits))> +<!ELEMENT QuantizationStyle (#PCDATA)> <!-- Default quantization style for all components. --> + <!-- Quantization style (in Sqcd's low 5 bits) may be: --> + <!-- 0 = No quantization. SPqcd size = 8 bits--> + <!-- 1 = Scalar derived (values signaled for N(L)LL subband only). Use Eq. E.5. SPqcd size = 16. --> + <!-- 2 = Scalar expounded (values signaled for each subband). SPqcd size = 16. --> +<!ELEMENT NumberOfGuardBits (#PCDATA)> <!-- 0-7 guard bits allowed (stored in Sqcd's high 3 bits) --> +<!ELEMENT SPqcd (ReversibleStepSizeValue | QuantizationStepSizeValues )> <!-- TO DO: Irreversible choices --> +<!ELEMENT ReversibleStepSizeValue (DynamicRangeExponent+)> + <!-- Current mj2_to_metadata implementation dumps entire internal table, --> + <!-- until an exponent with zero value is reached. --> + <!-- Exponent epsilon(b) of reversible dynamic range. --> + <!-- Hex value is as stored, in high-order 5 bits. --> +<!ELEMENT DynamicRangeExponent (AsHex | (AsHex, AsDecimal) | AsDecimal)> +<!ATTLIST DynamicRangeExponent Subband CDATA #REQUIRED> +<!ELEMENT QuantizationStepSizeValues (QuantizationValues+, CalculatedExponent*)> <!-- Calculated exponents iff only subband 0 reported --> +<!ELEMENT QuantizationValues (AsHex | (AsHex,Exponent,Mantissa) | (Exponent,Mantissa))> +<!ATTLIST QuantizationValues Subband CDATA #REQUIRED> +<!ELEMENT Exponent (#PCDATA)> +<!ELEMENT Mantissa (#PCDATA)> +<!ELEMENT CalculatedExponent (#PCDATA)> +<!ATTLIST CalculatedExponent Subband CDATA #REQUIRED> +<!-- /QuantizationDefault --> + <!-- mj2_to_metadata implementation always reports component[0] as using default QCD, --> + <!-- and any other component, with main-header quantization values different from [0], as QCC. --> +<!ELEMENT QuantizationComponent (Sqcc,SPqcc)> +<!ATTLIST QuantizationComponent Marker CDATA #FIXED "QCC"> +<!ATTLIST QuantizationComponent Component CDATA #REQUIRED> +<!ELEMENT Sqcc (AsHex | (AsHex,QuantizationStyle,NumberOfGuardBits) | (QuantizationStyle,NumberOfGuardBits))> +<!ELEMENT SPqcc (ReversibleStepSizeValue | QuantizationStepSizeValues )> <!-- TO DO: Irreversible choices --> +<!-- /QuantizationComponent --> +<!-- Don't know if MJ2 files can have regions of interest. Assume yes --> +<!ELEMENT RegionOfInterest (Srgn,Crgn,Sprgn)> <!-- Optional in main header, at most 1 per component --> +<!ATTLIST RegionOfInterest Marker CDATA #FIXED "RGN"> +<!ELEMENT Srgn (#PCDATA)> <!-- ROI style. Only style=0 defined: Implicit ROI (max. shift) --> +<!ELEMENT Crgn (#PCDATA)> <!-- Zero-based component number. --> +<!ELEMENT SPrgn (#PCDATA)> <!-- Implicit ROI shift, i.e., binary shifting of ROI coefficients above background. --> +<!-- </RegionOfInterest> --> +<!ELEMENT ProgressionOrderChange (Progression+)> <!-- Optional in main header, at most 1 per component (but impl allows more?) --> +<!ATTLIST ProgressionOrderChange Marker CDATA #REQUIRED> +<!ELEMENT Progression (RSpoc,CSpoc,LYEpoc,REpoc,CEpoc,Ppoc)> +<!ATTLIST Progression Num CDATA #REQUIRED> +<!ELEMENT RSpoc (#PCDATA)> <!-- Resolution level index (inclusive) for progression start. Range: 0 to 33 --> +<!ELEMENT CSpoc (#PCDATA)> <!-- Component index (inclusive) for progression start. --> +<!ELEMENT LYEpoc (#PCDATA)> <!-- Layer index (exclusive) for progression end. --> +<!ELEMENT REpoc (#PCDATA)> <!-- Resolution level index (exclusive) for progression end. Range: RSpoc to 33 --> +<!ELEMENT CEpoc (#PCDATA)> <!-- Component index (exclusive) for progression end. Minimum: CSpoc --> +<!ELEMENT Ppoc (#PCDATA)> <!-- Defined Progression Order Values are: --> + <!-- 0 = LRCP; 1 = RLCP; 2 = RPCL; 3 = PCRL; 4 = CPRL --> + <!-- where L = "layer", R = "resolution level", C = "component", P = "position". --> +<!-- </Progression>, </ProgressionOrderChange --> +<!-- /MainHeader --> +<!ELEMENT TilePartHeaders (TilePartHeader+)> +<!ATTLIST TilePartHeaders Count CDATA #REQUIRED> +<!ELEMENT TilePartHeader (StartOfTilePart,CodingStyleDefault,QuantizationDefault,QuantizationComponent*,RegionOfInterest?,ProgressionOrderChange*,StartOfData)> +<!ATTLIST TilePartHeader Num CDATA #REQUIRED> +<!ATTLIST TilePartHeader ID CDATA #REQUIRED> +<!ELEMENT StartOfTilePart EMPTY> +<!ATTLIST StartOfTilePart Marker CDATA #FIXED "SOT"> +<!-- CodingStyleDefault, QuantizationDefault, QuantizationComponent already defined --> + <!-- mj2_to_metadata implementation always reports component[0] as using default QCD, --> + <!-- and any other component, with tile-part-header quantization values different from [0], as QCC. --> +<!ELEMENT StartOfData EMPTY> <!-- always empty for now --> +<!ATTLIST StartOfData Marker CDATA #FIXED "SOD"> + <!-- Tile-part bitstream, not shown, follows tile-part header and SOD marker. --> +<!-- /TilePartHeader, /TilePartHeaders, /JP2_Frame --> +<!-- </Track> --> + +<!-- to come: + <MovieExtends mvek> // possibly not in Simple Profile + <UserDataBox udat> contains <CopyrightBox cprt> + --> +<!-- /MovieBox --> +<!-- To come: + <mdat> + <moof> // probably not in Simple Profile + <free> + <skip> + --> +<!-- </MJ2_File> -->
\ No newline at end of file diff --git a/openjpeg/src/bin/mj2/mj2_to_metadata.h b/openjpeg/src/bin/mj2/mj2_to_metadata.h new file mode 100644 index 000000000..f4c349191 --- /dev/null +++ b/openjpeg/src/bin/mj2/mj2_to_metadata.h @@ -0,0 +1,9 @@ +/* mj2_to_metadata.h */ +/* Dump MJ2, JP2 metadata (partial so far) to xml file */ +/* Contributed to Open JPEG by Glenn Pearson, U.S. National Library of Medicine */ + +#define BOOL int +#define FALSE 0 +#define TRUE 1 + +#include "meta_out.h" diff --git a/openjpeg/src/bin/mj2/mj2_to_metadata.sln b/openjpeg/src/bin/mj2/mj2_to_metadata.sln new file mode 100644 index 000000000..f579c536a --- /dev/null +++ b/openjpeg/src/bin/mj2/mj2_to_metadata.sln @@ -0,0 +1,29 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mj2_to_metadata", "mj2_to_metadata.vcproj", "{69BE42AB-E7CE-4DA1-BBD2-39FEA2C91E0B}" + ProjectSection(ProjectDependencies) = postProject + {0B1B7713-35B6-40A7-9BFF-A7D0EB06A8BD} = {0B1B7713-35B6-40A7-9BFF-A7D0EB06A8BD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibOpenJPEG", "..\LibOpenJPEG.vcproj", "{0B1B7713-35B6-40A7-9BFF-A7D0EB06A8BD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {69BE42AB-E7CE-4DA1-BBD2-39FEA2C91E0B}.Debug|Win32.ActiveCfg = Debug|Win32 + {69BE42AB-E7CE-4DA1-BBD2-39FEA2C91E0B}.Debug|Win32.Build.0 = Debug|Win32 + {69BE42AB-E7CE-4DA1-BBD2-39FEA2C91E0B}.Release|Win32.ActiveCfg = Release|Win32 + {69BE42AB-E7CE-4DA1-BBD2-39FEA2C91E0B}.Release|Win32.Build.0 = Release|Win32 + {0B1B7713-35B6-40A7-9BFF-A7D0EB06A8BD}.Debug|Win32.ActiveCfg = Debug|Win32 + {0B1B7713-35B6-40A7-9BFF-A7D0EB06A8BD}.Debug|Win32.Build.0 = Debug|Win32 + {0B1B7713-35B6-40A7-9BFF-A7D0EB06A8BD}.Release|Win32.ActiveCfg = Release|Win32 + {0B1B7713-35B6-40A7-9BFF-A7D0EB06A8BD}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/openjpeg/src/bin/mj2/mj2_to_metadata.vcproj b/openjpeg/src/bin/mj2/mj2_to_metadata.vcproj new file mode 100644 index 000000000..a8000f306 --- /dev/null +++ b/openjpeg/src/bin/mj2/mj2_to_metadata.vcproj @@ -0,0 +1,349 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8,00" + Name="mj2_to_metadata" + ProjectGUID="{69BE42AB-E7CE-4DA1-BBD2-39FEA2C91E0B}" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory=".\mj2_to_metadata___Win32_Debug0" + IntermediateDirectory=".\mj2_to_metadata___Win32_Debug0" + ConfigurationType="1" + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops" + UseOfMFC="0" + ATLMinimizesCRunTimeLibraryUsage="false" + CharacterSet="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TypeLibraryName=".\mj2_to_metadata___Win32_Debug0/mj2_to_metadata.tlb" + HeaderFileName="" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="../libopenjpeg" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;OPJ_STATIC;_CRT_SECURE_NO_DEPRECATE" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="1" + PrecompiledHeaderFile=".\mj2_to_metadata___Win32_Debug0/mj2_to_metadata.pch" + AssemblerListingLocation=".\mj2_to_metadata___Win32_Debug0/" + ObjectFile=".\mj2_to_metadata___Win32_Debug0/" + ProgramDataBaseFileName=".\mj2_to_metadata___Win32_Debug0/" + BrowseInformation="1" + WarningLevel="3" + SuppressStartupBanner="true" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + PreprocessorDefinitions="_DEBUG" + Culture="2057" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + OutputFile=".\mj2_to_metadata___Win32_Debug0/mj2_to_metadata.exe" + LinkIncremental="2" + SuppressStartupBanner="true" + IgnoreDefaultLibraryNames="LIBCMT" + GenerateDebugInformation="true" + ProgramDatabaseFile=".\mj2_to_metadata___Win32_Debug0/mj2_to_metadata.pdb" + SubSystem="1" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + SuppressStartupBanner="true" + OutputFile=".\mj2_to_metadata___Win32_Debug0/mj2_to_metadata.bsc" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory=".\Release" + IntermediateDirectory=".\Release" + ConfigurationType="1" + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops" + UseOfMFC="0" + ATLMinimizesCRunTimeLibraryUsage="false" + CharacterSet="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TypeLibraryName=".\Release/mj2_to_metadata.tlb" + HeaderFileName="" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + InlineFunctionExpansion="1" + AdditionalIncludeDirectories="../libopenjpeg" + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;OPJ_STATIC;_CRT_SECURE_NO_DEPRECATE" + StringPooling="true" + RuntimeLibrary="0" + EnableFunctionLevelLinking="true" + PrecompiledHeaderFile=".\Release/mj2_to_metadata.pch" + AssemblerListingLocation=".\Release/" + ObjectFile=".\Release/" + ProgramDataBaseFileName=".\Release/" + WarningLevel="3" + SuppressStartupBanner="true" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + PreprocessorDefinitions="NDEBUG" + Culture="2057" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + OutputFile=".\Release/mj2_to_metadata.exe" + LinkIncremental="1" + SuppressStartupBanner="true" + IgnoreDefaultLibraryNames="libcmtd" + ProgramDatabaseFile=".\Release/mj2_to_metadata.pdb" + SubSystem="1" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + SuppressStartupBanner="true" + OutputFile=".\Release/mj2_to_metadata.bsc" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="MJ2" + > + <Filter + Name="MJ2 Header Files" + > + <File + RelativePath="compat\opj_getopt.h" + > + </File> + <File + RelativePath="meta_out.h" + > + </File> + <File + RelativePath="mj2.h" + > + </File> + <File + RelativePath="mj2_convert.h" + > + </File> + <File + RelativePath="mj2_to_metadata.h" + > + </File> + </Filter> + <Filter + Name="MJ2 Source Files" + > + <File + RelativePath="compat\opj_getopt.c" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="" + /> + </FileConfiguration> + </File> + <File + RelativePath="meta_out.c" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="" + /> + </FileConfiguration> + </File> + <File + RelativePath="mj2.c" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="" + /> + </FileConfiguration> + </File> + <File + RelativePath="mj2_convert.c" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="" + /> + </FileConfiguration> + </File> + <File + RelativePath="mj2_to_metadata.c" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="" + /> + </FileConfiguration> + </File> + </Filter> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/openjpeg/src/bin/mj2/mj2_to_metadata_Notes.doc b/openjpeg/src/bin/mj2/mj2_to_metadata_Notes.doc Binary files differnew file mode 100644 index 000000000..05ccec206 --- /dev/null +++ b/openjpeg/src/bin/mj2/mj2_to_metadata_Notes.doc diff --git a/openjpeg/src/bin/mj2/opj_mj2_compress.c b/openjpeg/src/bin/mj2/opj_mj2_compress.c new file mode 100644 index 000000000..4baefe670 --- /dev/null +++ b/openjpeg/src/bin/mj2/opj_mj2_compress.c @@ -0,0 +1,852 @@ +/* +* Copyright (c) 2003-2004, Francois-Olivier Devaux +* Copyright (c) 2002-2004, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "opj_apps_config.h" +#include "openjpeg.h" +#include "j2k_lib.h" +#include "cio.h" +#include "j2k.h" +#include "jp2.h" +#include "mj2.h" +#include "mj2_convert.h" +#include "opj_getopt.h" + +/** +Size of memory first allocated for MOOV box +*/ +#define TEMP_BUF 10000 + + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +static void error_callback(const char *msg, void *client_data) +{ + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +static void warning_callback(const char *msg, void *client_data) +{ + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + + +static void help_display() +{ + fprintf(stdout, "HELP for frames_to_mj2\n----\n\n"); + fprintf(stdout, "- the -h option displays this help information on screen\n\n"); + + + fprintf(stdout, "List of parameters for the MJ2 encoder:\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "REMARKS:\n"); + fprintf(stdout, "---------\n"); + fprintf(stdout, "\n"); + fprintf + (stdout, "The markers written to the main_header are : SOC SIZ COD QCD COM.\n"); + fprintf + (stdout, "COD and QCD never appear in the tile_header.\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "By default:\n"); + fprintf(stdout, "------------\n"); + fprintf(stdout, "\n"); + fprintf(stdout, " * Lossless\n"); + fprintf(stdout, " * 1 tile\n"); + fprintf(stdout, " * Size of precinct : 2^15 x 2^15 (means 1 precinct)\n"); + fprintf(stdout, " * Size of code-block : 64 x 64\n"); + fprintf(stdout, " * Number of resolutions: 6\n"); + fprintf(stdout, " * No SOP marker in the codestream\n"); + fprintf(stdout, " * No EPH marker in the codestream\n"); + fprintf(stdout, " * No sub-sampling in x or y direction\n"); + fprintf(stdout, " * No mode switch activated\n"); + fprintf(stdout, " * Progression order: LRCP\n"); + fprintf(stdout, " * No index file\n"); + fprintf(stdout, " * No ROI upshifted\n"); + fprintf(stdout, " * No offset of the origin of the image\n"); + fprintf(stdout, " * No offset of the origin of the tiles\n"); + fprintf(stdout, " * Reversible DWT 5-3\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "Parameters:\n"); + fprintf(stdout, "------------\n"); + fprintf(stdout, "\n"); + fprintf + (stdout, "Required Parameters (except with -h):\n"); + fprintf + (stdout, "-i : source file (-i source.yuv) \n"); + fprintf + (stdout, "-o : destination file (-o dest.mj2) \n"); + fprintf + (stdout, "Optional Parameters:\n"); + fprintf(stdout, "-h : display the help information \n"); + fprintf(stdout, + "-r : different compression ratios for successive layers (-r 20,10,5)\n"); + fprintf(stdout, + " - The rate specified for each quality level is the desired \n"); + fprintf(stdout, " compression factor.\n"); + fprintf(stdout, " Example: -r 20,10,1 means quality 1: compress 20x, \n"); + fprintf(stdout, + " quality 2: compress 10x and quality 3: compress lossless\n"); + fprintf(stdout, " (options -r and -q cannot be used together)\n"); + + fprintf(stdout, "-q : different psnr for successive layers (-q 30,40,50) \n"); + fprintf(stdout, " (options -r and -q cannot be used together)\n"); + + fprintf(stdout, "-n : number of resolutions (-n 3) \n"); + fprintf(stdout, "-b : size of code block (-b 32,32) \n"); + fprintf(stdout, "-c : size of precinct (-c 128,128) \n"); + fprintf(stdout, "-t : size of tile (-t 512,512) \n"); + fprintf + (stdout, "-p : progression order (-p LRCP) [LRCP, RLCP, RPCL, PCRL, CPRL] \n"); + fprintf + (stdout, "-s : subsampling factor (-s 2,2) [-s X,Y] \n"); + fprintf(stdout, " Remark: subsampling bigger than 2 can produce error\n"); + fprintf + (stdout, "-S : write SOP marker before each packet \n"); + fprintf + (stdout, "-E : write EPH marker after each header packet \n"); + fprintf + (stdout, "-M : mode switch (-M 3) [1=BYPASS(LAZY) 2=RESET 4=RESTART(TERMALL)\n"); + fprintf + (stdout, " 8=VSC 16=ERTERM(SEGTERM) 32=SEGMARK(SEGSYM)] \n"); + fprintf + (stdout, " Indicate multiple modes by adding their values. \n"); + fprintf + (stdout, " Example: RESTART(4) + RESET(2) + SEGMARK(32) = -M 38\n"); + fprintf + (stdout, "-R : c=%%d,U=%%d : quantization indices upshifted \n"); + fprintf + (stdout, " for component c=%%d [%%d = 0,1,2]\n"); + fprintf + (stdout, " with a value of U=%%d [0 <= %%d <= 37] (i.e. -ROI:c=0,U=25) \n"); + fprintf + (stdout, "-d : offset of the origin of the image (-d 150,300) \n"); + fprintf + (stdout, "-T : offset of the origin of the tiles (-T 100,75) \n"); + fprintf(stdout, "-I : use the irreversible DWT 9-7 (-I) \n"); + fprintf(stdout, "-W : image width, height and the dx and dy subsampling \n"); + fprintf(stdout, " of the Cb and Cr components for YUV files \n"); + fprintf(stdout, + " (default is '352,288,2,2' for CIF format's 352x288 and 4:2:0)\n"); + fprintf(stdout, "-F : video frame rate (set to 25 by default)\n"); + fprintf(stdout, "-D : depth, precision in bits [8 .. 16]; default:8\n"); + fprintf(stdout, "-C : comment\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "IMPORTANT:\n"); + fprintf(stdout, "-----------\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "The index file has the structure below:\n"); + fprintf(stdout, "---------------------------------------\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "Image_height Image_width\n"); + fprintf(stdout, "progression order\n"); + fprintf(stdout, "Tiles_size_X Tiles_size_Y\n"); + fprintf(stdout, "Components_nb\n"); + fprintf(stdout, "Layers_nb\n"); + fprintf(stdout, "decomposition_levels\n"); + fprintf(stdout, "[Precincts_size_X_res_Nr Precincts_size_Y_res_Nr]...\n"); + fprintf(stdout, " [Precincts_size_X_res_0 Precincts_size_Y_res_0]\n"); + fprintf(stdout, "Main_header_end_position\n"); + fprintf(stdout, "Codestream_size\n"); + fprintf(stdout, + "Tile_0 start_pos end_Theader end_pos TotalDisto NumPix MaxMSE\n"); + fprintf(stdout, + "Tile_1 '' '' '' '' '' ''\n"); + fprintf(stdout, "...\n"); + fprintf(stdout, + "Tile_Nt '' '' '' '' '' ''\n"); + fprintf(stdout, + "Tpacket_0 Tile layer res. comp. prec. start_pos end_pos disto\n"); + fprintf(stdout, "...\n"); + fprintf(stdout, + "Tpacket_Np '' '' '' '' '' '' '' ''\n"); + + fprintf(stdout, "MaxDisto\n"); + + fprintf(stdout, "TotalDisto\n\n"); +} + +static OPJ_PROG_ORDER give_progression(const char progression[5]) +{ + if (progression[0] == 'L' && progression[1] == 'R' + && progression[2] == 'C' && progression[3] == 'P') { + return LRCP; + } else { + if (progression[0] == 'R' && progression[1] == 'L' + && progression[2] == 'C' && progression[3] == 'P') { + return RLCP; + } else { + if (progression[0] == 'R' && progression[1] == 'P' + && progression[2] == 'C' && progression[3] == 'L') { + return RPCL; + } else { + if (progression[0] == 'P' && progression[1] == 'C' + && progression[2] == 'R' && progression[3] == 'L') { + return PCRL; + } else { + if (progression[0] == 'C' && progression[1] == 'P' + && progression[2] == 'R' && progression[3] == 'L') { + return CPRL; + } else { + return PROG_UNKNOWN; + } + } + } + } + } +} + + + + +int main(int argc, char **argv) +{ + mj2_cparameters_t mj2_parameters; /* MJ2 compression parameters */ + opj_cparameters_t *j2k_parameters; /* J2K compression parameters */ + opj_event_mgr_t event_mgr; /* event manager */ + opj_cio_t *cio; + int value; + opj_mj2_t *movie; + opj_image_t *img; + int i, j; + char *s, S1, S2, S3; + unsigned char *buf; + int x1, y1, len; + long mdat_initpos, offset; + FILE *mj2file; + int sampleno; + opj_cinfo_t* cinfo; + opj_bool bSuccess; + int numframes; + int prec = 8;/* DEFAULT */ + double total_time = 0; + + memset(&mj2_parameters, 0, sizeof(mj2_cparameters_t)); + /* default value */ + /* ------------- */ + mj2_parameters.w = 352; /* CIF default value*/ + mj2_parameters.h = 288; /* CIF default value*/ + mj2_parameters.CbCr_subsampling_dx = 2; /* CIF default value*/ + mj2_parameters.CbCr_subsampling_dy = 2; /* CIF default value*/ + mj2_parameters.frame_rate = 25; + mj2_parameters.prec = 8; /* DEFAULT */ + mj2_parameters.enumcs = ENUMCS_SYCC; /* FIXME: ENUMCS_YUV420 */ + mj2_parameters.meth = 1; /* enumerated color space */ + + /* + configure the event callbacks (not required) + setting of each callback is optionnal + */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = NULL; + + /* set J2K encoding parameters to default values */ + opj_set_default_encoder_parameters(&mj2_parameters.j2k_parameters); + j2k_parameters = &mj2_parameters.j2k_parameters; + + /* Create comment for codestream */ + if (j2k_parameters->cp_comment == NULL) { + const char comment[] = "Created by OpenJPEG version "; + const size_t clen = strlen(comment); + const char *version = opj_version(); + j2k_parameters->cp_comment = (char*)malloc(clen + strlen(version) + 1); + sprintf(j2k_parameters->cp_comment, "%s%s", comment, version); + } + + while (1) { + int c = opj_getopt(argc, argv, + "i:o:r:q:f:t:n:c:b:p:s:d:P:S:E:M:R:T:C:I:W:F:D:h"); + if (c == -1) { + break; + } + switch (c) { + case 'i': { /* IN fill */ + char *infile = opj_optarg; + s = opj_optarg; + while (*s) { + s++; + } + s--; + S3 = *s; + s--; + S2 = *s; + s--; + S1 = *s; + + if ((S1 == 'y' && S2 == 'u' && S3 == 'v') + || (S1 == 'Y' && S2 == 'U' && S3 == 'V')) { + mj2_parameters.decod_format = YUV_DFMT; + } else { + fprintf(stderr, + "!! Unrecognized format for infile : %c%c%c [accept only *.yuv] !!\n\n", + S1, S2, S3); + return 1; + } + strncpy(mj2_parameters.infile, infile, sizeof(mj2_parameters.infile) - 1); + } + break; + /* ----------------------------------------------------- */ + case 'o': { /* OUT fill */ + char *outfile = opj_optarg; + while (*outfile) { + outfile++; + } + outfile--; + S3 = *outfile; + outfile--; + S2 = *outfile; + outfile--; + S1 = *outfile; + + outfile = opj_optarg; + + if ((S1 == 'm' && S2 == 'j' && S3 == '2') + || (S1 == 'M' && S2 == 'J' && S3 == '2')) { + mj2_parameters.cod_format = MJ2_CFMT; + } else { + fprintf(stderr, + "Unknown output format image *.%c%c%c [only *.mj2]!! \n", + S1, S2, S3); + return 1; + } + strncpy(mj2_parameters.outfile, outfile, sizeof(mj2_parameters.outfile) - 1); + } + break; + /* ----------------------------------------------------- */ + case 'r': { /* rates rates/distorsion */ + float rate; + s = opj_optarg; + while (sscanf(s, "%f", &rate) == 1) { + j2k_parameters->tcp_rates[j2k_parameters->tcp_numlayers] = rate * 2; + j2k_parameters->tcp_numlayers++; + while (*s && *s != ',') { + s++; + } + if (!*s) { + break; + } + s++; + } + j2k_parameters->cp_disto_alloc = 1; + } + break; + /* ----------------------------------------------------- */ + case 'q': /* add fixed_quality */ + s = opj_optarg; + while (sscanf(s, "%f", + &j2k_parameters->tcp_distoratio[j2k_parameters->tcp_numlayers]) == 1) { + j2k_parameters->tcp_numlayers++; + while (*s && *s != ',') { + s++; + } + if (!*s) { + break; + } + s++; + } + j2k_parameters->cp_fixed_quality = 1; + break; + /* dda */ + /* ----------------------------------------------------- */ + case 'f': { /* mod fixed_quality (before : -q) */ + int *row = NULL, *col = NULL; + int numlayers = 0, numresolution = 0, matrix_width = 0; + + s = opj_optarg; + sscanf(s, "%d", &numlayers); + s++; + if (numlayers > 9) { + s++; + } + + j2k_parameters->tcp_numlayers = numlayers; + numresolution = j2k_parameters->numresolution; + matrix_width = numresolution * 3; + j2k_parameters->cp_matrice = (int *) malloc(numlayers * matrix_width * sizeof( + int)); + s = s + 2; + + for (i = 0; i < numlayers; i++) { + row = &j2k_parameters->cp_matrice[i * matrix_width]; + col = row; + j2k_parameters->tcp_rates[i] = 1; + sscanf(s, "%d,", &col[0]); + s += 2; + if (col[0] > 9) { + s++; + } + col[1] = 0; + col[2] = 0; + for (j = 1; j < numresolution; j++) { + col += 3; + sscanf(s, "%d,%d,%d", &col[0], &col[1], &col[2]); + s += 6; + if (col[0] > 9) { + s++; + } + if (col[1] > 9) { + s++; + } + if (col[2] > 9) { + s++; + } + } + if (i < numlayers - 1) { + s++; + } + } + j2k_parameters->cp_fixed_alloc = 1; + } + break; + /* ----------------------------------------------------- */ + case 't': /* tiles */ + sscanf(opj_optarg, "%d,%d", &j2k_parameters->cp_tdx, &j2k_parameters->cp_tdy); + j2k_parameters->tile_size_on = OPJ_TRUE; + break; + /* ----------------------------------------------------- */ + case 'n': /* resolution */ + sscanf(opj_optarg, "%d", &j2k_parameters->numresolution); + break; + /* ----------------------------------------------------- */ + case 'c': { /* precinct dimension */ + char sep; + int res_spec = 0; + + char *s = opj_optarg; + do { + sep = 0; + sscanf(s, "[%d,%d]%c", &j2k_parameters->prcw_init[res_spec], + &j2k_parameters->prch_init[res_spec], &sep); + j2k_parameters->csty |= 0x01; + res_spec++; + s = strpbrk(s, "]") + 2; + } while (sep == ','); + j2k_parameters->res_spec = res_spec; + } + break; + + /* ----------------------------------------------------- */ + case 'b': { /* code-block dimension */ + int cblockw_init = 0, cblockh_init = 0; + sscanf(opj_optarg, "%d,%d", &cblockw_init, &cblockh_init); + if (cblockw_init * cblockh_init > 4096 || cblockw_init > 1024 + || cblockw_init < 4 || cblockh_init > 1024 || cblockh_init < 4) { + fprintf(stderr, + "!! Size of code_block error (option -b) !!\n\nRestriction :\n" + " * width*height<=4096\n * 4<=width,height<= 1024\n\n"); + return 1; + } + j2k_parameters->cblockw_init = cblockw_init; + j2k_parameters->cblockh_init = cblockh_init; + } + break; + /* ----------------------------------------------------- */ + case 'p': { /* progression order */ + char progression[5]; + + strncpy(progression, opj_optarg, 5); + j2k_parameters->prog_order = give_progression(progression); + if (j2k_parameters->prog_order == -1) { + fprintf(stderr, "Unrecognized progression order " + "[LRCP, RLCP, RPCL, PCRL, CPRL] !!\n"); + return 1; + } + } + break; + /* ----------------------------------------------------- */ + case 's': { /* subsampling factor */ + if (sscanf(opj_optarg, "%d,%d", &j2k_parameters->subsampling_dx, + &j2k_parameters->subsampling_dy) != 2) { + fprintf(stderr, "'-s' sub-sampling argument error ! [-s dx,dy]\n"); + return 1; + } + } + break; + /* ----------------------------------------------------- */ + case 'd': { /* coordonnate of the reference grid */ + if (sscanf(opj_optarg, "%d,%d", &j2k_parameters->image_offset_x0, + &j2k_parameters->image_offset_y0) != 2) { + fprintf(stderr, "-d 'coordonnate of the reference grid' argument " + "error !! [-d x0,y0]\n"); + return 1; + } + } + break; + /* ----------------------------------------------------- */ + case 'h': /* Display an help description */ + help_display(); + return 0; + break; + /* ----------------------------------------------------- */ + case 'P': { /* POC */ + int numpocs = 0; /* number of progression order change (POC) default 0 */ + opj_poc_t *POC = NULL; /* POC : used in case of Progression order change */ + + char *s = opj_optarg; + POC = j2k_parameters->POC; + + while (sscanf(s, "T%d=%d,%d,%d,%d,%d,%4s", &POC[numpocs].tile, + &POC[numpocs].resno0, &POC[numpocs].compno0, + &POC[numpocs].layno1, &POC[numpocs].resno1, + &POC[numpocs].compno1, POC[numpocs].progorder) == 7) { + POC[numpocs].prg1 = give_progression(POC[numpocs].progorder); + numpocs++; + while (*s && *s != '/') { + s++; + } + if (!*s) { + break; + } + s++; + } + j2k_parameters->numpocs = numpocs; + } + break; + /* ------------------------------------------------------ */ + case 'S': /* SOP marker */ + j2k_parameters->csty |= 0x02; + break; + /* ------------------------------------------------------ */ + case 'E': /* EPH marker */ + j2k_parameters->csty |= 0x04; + break; + /* ------------------------------------------------------ */ + case 'M': /* Mode switch pas tous au point !! */ + if (sscanf(opj_optarg, "%d", &value) == 1) { + for (i = 0; i <= 5; i++) { + int cache = value & (1 << i); + if (cache) { + j2k_parameters->mode |= (1 << i); + } + } + } + break; + /* ------------------------------------------------------ */ + case 'R': { /* ROI */ + if (sscanf(opj_optarg, "OI:c=%d,U=%d", &j2k_parameters->roi_compno, + &j2k_parameters->roi_shift) != 2) { + fprintf(stderr, "ROI error !! [-ROI:c='compno',U='shift']\n"); + return 1; + } + } + break; + /* ------------------------------------------------------ */ + case 'T': { /* Tile offset */ + if (sscanf(opj_optarg, "%d,%d", &j2k_parameters->cp_tx0, + &j2k_parameters->cp_ty0) != 2) { + fprintf(stderr, "-T 'tile offset' argument error !! [-T X0,Y0]"); + return 1; + } + } + break; + /* ------------------------------------------------------ */ + case 'C': { /* Add a comment */ + j2k_parameters->cp_comment = (char*)malloc(strlen(opj_optarg) + 1); + if (j2k_parameters->cp_comment) { + strcpy(j2k_parameters->cp_comment, opj_optarg); + } + } + break; + /* ------------------------------------------------------ */ + case 'I': { /* reversible or not */ + j2k_parameters->irreversible = 1; + } + break; + /* ------------------------------------------------------ */ + case 'W': /* Width and Height and Cb and Cr subsampling in case of YUV format files */ + if (sscanf + (opj_optarg, "%d,%d,%d,%d", &mj2_parameters.w, &mj2_parameters.h, + &mj2_parameters.CbCr_subsampling_dx, + &mj2_parameters.CbCr_subsampling_dy) != 4) { + fprintf(stderr, "-W argument error"); + return 1; + } + break; + /* ------------------------------------------------------ */ + case 'F': /* Video frame rate */ + if (sscanf(opj_optarg, "%d", &mj2_parameters.frame_rate) != 1) { + fprintf(stderr, "-F argument error"); + return 1; + } + break; + /* ------------------------------------------------------ */ + case 'D': /* Depth: the precision */ + if (sscanf(opj_optarg, "%d", &prec) != 1) { + prec = 0; + } + break; + + default: + return 1; + } + } + + /* Error messages */ + /* -------------- */ + if (!mj2_parameters.cod_format || !mj2_parameters.decod_format) { + fprintf(stderr, + "Usage: %s -i yuv-file -o mj2-file (+ options)\n", argv[0]); + return 1; + } + if (prec < 1 || prec > 16) { + fprintf(stderr, "Error: Depth %d must be in the range 8 .. 16\n", prec); + return 1; + } + if ((j2k_parameters->cp_disto_alloc || j2k_parameters->cp_fixed_alloc || + j2k_parameters->cp_fixed_quality) + && (!(j2k_parameters->cp_disto_alloc ^ j2k_parameters->cp_fixed_alloc ^ + j2k_parameters->cp_fixed_quality))) { + fprintf(stderr, "Error: options -r -q and -f cannot be used together !!\n"); + return 1; + } /* mod fixed_quality */ + + /* if no rate entered, lossless by default */ + if (j2k_parameters->tcp_numlayers == 0) { + j2k_parameters->tcp_rates[0] = 0; /* MOD antonin : losslessbug */ + j2k_parameters->tcp_numlayers++; + j2k_parameters->cp_disto_alloc = 1; + } + + if ((j2k_parameters->cp_tx0 > j2k_parameters->image_offset_x0) || + (j2k_parameters->cp_ty0 > j2k_parameters->image_offset_y0)) { + fprintf(stderr, + "Error: Tile offset dimension is unnappropriate --> TX0(%d)<=IMG_X0(%d) TYO(%d)<=IMG_Y0(%d) \n", + j2k_parameters->cp_tx0, j2k_parameters->image_offset_x0, j2k_parameters->cp_ty0, + j2k_parameters->image_offset_y0); + return 1; + } + + for (i = 0; i < j2k_parameters->numpocs; i++) { + if (j2k_parameters->POC[i].prg == -1) { + fprintf(stderr, + "Unrecognized progression order in option -P (POC n %d) [LRCP, RLCP, RPCL, PCRL, CPRL] !!\n", + i + 1); + } + } + + if (j2k_parameters->cp_tdx > mj2_parameters.Dim[0] || + j2k_parameters->cp_tdy > mj2_parameters.Dim[1]) { + fprintf(stderr, + "Error: Tile offset dimension is unnappropriate --> TX0(%d)<=IMG_X0(%d) TYO(%d)<=IMG_Y0(%d) \n", + j2k_parameters->cp_tdx, mj2_parameters.Dim[0], j2k_parameters->cp_tdy, + mj2_parameters.Dim[1]); + return 1; + } + + /* to respect profile - 0 */ + /* ---------------------- */ + + x1 = !mj2_parameters.Dim[0] ? (mj2_parameters.w - 1) * + j2k_parameters->subsampling_dx + + 1 : mj2_parameters.Dim[0] + (mj2_parameters.w - 1) * + j2k_parameters->subsampling_dx + 1; + y1 = !mj2_parameters.Dim[1] ? (mj2_parameters.h - 1) * + j2k_parameters->subsampling_dy + + 1 : mj2_parameters.Dim[1] + (mj2_parameters.h - 1) * + j2k_parameters->subsampling_dy + 1; + mj2_parameters.numcomps = 3; /* YUV files only have 3 components */ + + mj2_parameters.prec = prec; + + j2k_parameters->tcp_mct = 0; + + mj2file = fopen(mj2_parameters.outfile, "wb"); + + if (!mj2file) { + fprintf(stderr, "failed to open %s for writing\n", argv[2]); + return 1; + } + + /* get a MJ2 decompressor handle */ + cinfo = mj2_create_compress(); + movie = (opj_mj2_t*)cinfo->mj2_handle; + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr); + + /* setup encoder parameters */ + mj2_setup_encoder(movie, &mj2_parameters); + + movie->tk[0].num_samples = + yuv_num_frames(&movie->tk[0], mj2_parameters.infile); + + if (movie->tk[0].num_samples == 0) { + return 1; + } + + /* One sample per chunk*/ + movie->tk[0].chunk = (mj2_chunk_t*) + malloc(movie->tk[0].num_samples * sizeof(mj2_chunk_t)); + movie->tk[0].sample = (mj2_sample_t*) + malloc(movie->tk[0].num_samples * sizeof(mj2_sample_t)); + + if (mj2_init_stdmovie(movie)) { + fprintf(stderr, "Error with movie initialization"); + return 1; + } + + /* Writing JP, FTYP and MDAT boxes */ + /* Assuming that the JP and FTYP boxes won't be longer than 300 bytes:*/ + buf = (unsigned char*) + malloc(300 * sizeof(unsigned char)); + + cio = opj_cio_open((opj_common_ptr)movie->cinfo, buf, 300); + + mj2_write_jp(cio); + mj2_write_ftyp(movie, cio); + + mdat_initpos = cio_tell(cio); + cio_skip(cio, 4); + + cio_write(cio, MJ2_MDAT, 4); + + fwrite(buf, cio_tell(cio), 1, mj2file); + + offset = cio_tell(cio); + opj_cio_close(cio); + free(buf); + + for (i = 0; i < movie->num_stk + movie->num_htk + movie->num_vtk; i++) { + if (movie->tk[i].track_type != 0) { + fprintf(stderr, "Unable to write sound or hint tracks\n"); + } else { + mj2_tk_t *tk; + int buflen = 0; + + tk = &movie->tk[i]; + tk->num_chunks = tk->num_samples; + numframes = tk->num_samples; + tk->depth = prec; + + fprintf(stderr, "Video Track number %d\n", i); + + img = mj2_image_create(tk, j2k_parameters); + + buflen = 2 * (tk->w * tk->h * 8); + buf = (unsigned char *) malloc(buflen * sizeof(unsigned char)); + + for (sampleno = 0; sampleno < numframes; sampleno++) { + double init_time = opj_clock(); + double elapsed_time; + + if (yuvtoimage(tk, img, sampleno, j2k_parameters, + mj2_parameters.infile)) { + fprintf(stderr, "Error with frame number %d in YUV file\n", sampleno); + return 1; + } + + /* setup the encoder parameters using the current image and user parameters */ + opj_setup_encoder(cinfo, j2k_parameters, img); + + cio = opj_cio_open((opj_common_ptr)movie->cinfo, buf, buflen); + + cio_skip(cio, 4); + cio_write(cio, JP2_JP2C, 4); /* JP2C*/ + + /* encode the image */ + bSuccess = opj_encode(cinfo, cio, img, NULL); + + if (!bSuccess) { + opj_cio_close(cio); + fprintf(stderr, "failed to encode image\n"); + return 1; + } + + len = cio_tell(cio) - 8; + cio_seek(cio, 0); + cio_write(cio, len + 8, 4); + opj_cio_close(cio); + + tk->sample[sampleno].sample_size = len + 8; + tk->sample[sampleno].offset = offset; + tk->chunk[sampleno].offset = offset; /* There is one sample per chunk */ + fwrite(buf, 1, len + 8, mj2file); + offset += len + 8; + + elapsed_time = opj_clock() - init_time; + fprintf(stderr, "Frame number %d/%d encoded in %.2f mseconds\n", + sampleno + 1, numframes, elapsed_time * 1000); + total_time += elapsed_time; + } /* for(sampleno */ + + free(buf); + opj_image_destroy(img); + } + }/* for(i */ + + fseek(mj2file, mdat_initpos, SEEK_SET); + + buf = (unsigned char*) malloc(4 * sizeof(unsigned char)); + + /* Init a cio to write box length variable in a little endian way */ + cio = opj_cio_open(NULL, buf, 4); + cio_write(cio, offset - mdat_initpos, 4); + fwrite(buf, 4, 1, mj2file); + fseek(mj2file, 0, SEEK_END); + free(buf); + + /* Writing MOOV box */ + buf = (unsigned char*) + malloc((TEMP_BUF + numframes * 20) * sizeof(unsigned char)); + cio = opj_cio_open(movie->cinfo, buf, (TEMP_BUF + numframes * 20)); + mj2_write_moov(movie, cio); + fwrite(buf, cio_tell(cio), 1, mj2file); + free(buf); + + fprintf(stdout, "Total encoding time: %.2f s for %d frames (%.1f fps)\n", + total_time, numframes, (float)numframes / total_time); + + /* Ending program */ + + fclose(mj2file); + /* free remaining compression structures */ + mj2_destroy_compress(movie); + free(cinfo); + + if (j2k_parameters->cp_comment) { + free(j2k_parameters->cp_comment); + } + if (j2k_parameters->cp_matrice) { + free(j2k_parameters->cp_matrice); + } + opj_cio_close(cio); + + return 0; +} diff --git a/openjpeg/src/bin/mj2/opj_mj2_decompress.c b/openjpeg/src/bin/mj2/opj_mj2_decompress.c new file mode 100644 index 000000000..6b26d5636 --- /dev/null +++ b/openjpeg/src/bin/mj2/opj_mj2_decompress.c @@ -0,0 +1,258 @@ +/* +* Copyright (c) 2003-2004, Francois-Olivier Devaux +* Copyright (c) 2002-2004, Communications and remote sensing Laboratory, Universite catholique de Louvain, Belgium +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "opj_apps_config.h" +#include "openjpeg.h" +#include "j2k_lib.h" +#include "cio.h" +#include "j2k.h" +#include "jp2.h" +#include "mj2.h" +#include "mj2_convert.h" + +#ifdef OPJ_HAVE_LIBLCMS2 +#include <lcms2.h> +#endif +#ifdef OPJ_HAVE_LIBLCMS1 +#include <lcms.h> +#endif +#include "color.h" +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +static void error_callback(const char *msg, void *client_data) +{ + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +static void warning_callback(const char *msg, void *client_data) +{ + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + + +int main(int argc, char *argv[]) +{ + mj2_dparameters_t mj2_parameters; /* decompression parameters */ + opj_dinfo_t* dinfo; + opj_event_mgr_t event_mgr; /* event manager */ + opj_cio_t *cio = NULL; + unsigned int tnum, snum; + opj_mj2_t *movie; + mj2_tk_t *track; + mj2_sample_t *sample; + unsigned char* frame_codestream; + FILE *file, *outfile; + char outfilename[50]; + opj_image_t *img = NULL; + unsigned int max_codstrm_size = 0; + double total_time = 0; + unsigned int numframes = 0; + + if (argc != 3) { + printf("Usage: %s inputfile.mj2 outputfile.yuv\n", argv[0]); + return 1; + } + + file = fopen(argv[1], "rb"); + + if (!file) { + fprintf(stderr, "failed to open %s for reading\n", argv[1]); + return 1; + } + + /* Checking output file */ + outfile = fopen(argv[2], "w"); + if (!file) { + fprintf(stderr, "failed to open %s for writing\n", argv[2]); + return 1; + } + fclose(outfile); + + /* + configure the event callbacks (not required) + setting of each callback is optional + */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = NULL; + + /* get a MJ2 decompressor handle */ + dinfo = mj2_create_decompress(); + movie = (opj_mj2_t*)dinfo->mj2_handle; + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + memset(&mj2_parameters, 0, sizeof(mj2_dparameters_t)); + /* set J2K decoding parameters to default values */ + opj_set_default_decoder_parameters(&mj2_parameters.j2k_parameters); + + /* setup the decoder decoding parameters using user parameters */ + mj2_setup_decoder(movie, &mj2_parameters); + + if (mj2_read_struct(file, movie)) { /* Creating the movie structure */ + return 1; + } + + /* Decode first video track */ + for (tnum = 0; + tnum < (unsigned int)(movie->num_htk + movie->num_stk + movie->num_vtk); + tnum++) { + if (movie->tk[tnum].track_type == 0) { + break; + } + } + + if (movie->tk[tnum].track_type != 0) { + printf("Error. Movie does not contain any video track\n"); + return 1; + } + + track = &movie->tk[tnum]; + + /* Output info on first video tracl */ + fprintf(stdout, + "The first video track contains %d frames.\nWidth: %d, Height: %d \n\n", + track->num_samples, track->w, track->h); + + max_codstrm_size = track->sample[0].sample_size - 8; + frame_codestream = (unsigned char*) malloc(max_codstrm_size * sizeof( + unsigned char)); + + numframes = track->num_samples; + + for (snum = 0; snum < numframes; snum++) { + double init_time = opj_clock(); + double elapsed_time; + + sample = &track->sample[snum]; + if (sample->sample_size - 8 > max_codstrm_size) { + max_codstrm_size = sample->sample_size - 8; + if ((frame_codestream = (unsigned char*) + realloc(frame_codestream, max_codstrm_size)) == NULL) { + printf("Error reallocation memory\n"); + return 1; + }; + } + fseek(file, sample->offset + 8, SEEK_SET); + fread(frame_codestream, sample->sample_size - 8, 1, + file); /* Assuming that jp and ftyp markers size do */ + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, frame_codestream, + sample->sample_size - 8); + + img = opj_decode(dinfo, cio); /* Decode J2K to image */ + +#ifdef WANT_SYCC_TO_RGB + if (img->color_space == CLRSPC_SYCC) { + color_sycc_to_rgb(img); + } +#endif + + if (img->icc_profile_buf) { +#if defined(OPJ_HAVE_LIBLCMS1) || defined(OPJ_HAVE_LIBLCMS2) + color_apply_icc_profile(img); +#endif + + free(img->icc_profile_buf); + img->icc_profile_buf = NULL; + img->icc_profile_len = 0; + } + + if (((img->numcomps == 3) && (img->comps[0].dx == img->comps[1].dx / 2) + && (img->comps[0].dx == img->comps[2].dx / 2) && (img->comps[0].dx == 1)) + || (img->numcomps == 1)) { + + if (!imagetoyuv(img, argv[2])) { /* Convert image to YUV */ + return 1; + } + } else if ((img->numcomps == 3) && + (img->comps[0].dx == 1) && (img->comps[1].dx == 1) && + (img->comps[2].dx == 1)) { /* If YUV 4:4:4 input --> to bmp */ + fprintf(stdout, + "The frames will be output in a bmp format (output_1.bmp, ...)\n"); + sprintf(outfilename, "output_%d.bmp", snum); + if (imagetobmp(img, outfilename)) { /* Convert image to BMP */ + return 1; + } + + } else { + fprintf(stdout, + "Image component dimensions are unknown. Unable to output image\n"); + fprintf(stdout, + "The frames will be output in a j2k file (output_1.j2k, ...)\n"); + + sprintf(outfilename, "output_%d.j2k", snum); + outfile = fopen(outfilename, "wb"); + if (!outfile) { + fprintf(stderr, "failed to open %s for writing\n", outfilename); + return 1; + } + fwrite(frame_codestream, sample->sample_size - 8, 1, outfile); + fclose(outfile); + } + /* close the byte stream */ + opj_cio_close(cio); + /* free image data structure */ + opj_image_destroy(img); + elapsed_time = opj_clock() - init_time; + fprintf(stderr, "Frame number %d/%d decoded in %.2f mseconds\n", snum + 1, + numframes, elapsed_time * 1000); + total_time += elapsed_time; + + } + + free(frame_codestream); + fclose(file); + + /* free remaining structures */ + if (dinfo) { + mj2_destroy_decompress((opj_mj2_t*)dinfo->mj2_handle); + } + free(dinfo); + + fprintf(stdout, "%d frame(s) correctly decompressed\n", snum); + fprintf(stdout, "Total decoding time: %.2f seconds (%.1f fps)\n", total_time, + (float)numframes / total_time); + + return 0; +} diff --git a/openjpeg/src/bin/mj2/opj_mj2_extract.c b/openjpeg/src/bin/mj2/opj_mj2_extract.c new file mode 100644 index 000000000..a062e17d8 --- /dev/null +++ b/openjpeg/src/bin/mj2/opj_mj2_extract.c @@ -0,0 +1,162 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "openjpeg.h" +#include "cio.h" +#include "j2k.h" +#include "jp2.h" +#include "mj2.h" + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) +{ + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) +{ + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting a FILE* client object +*/ +void info_callback(const char *msg, void *client_data) +{ + FILE *stream = (FILE*)client_data; + fprintf(stream, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + + +int main(int argc, char *argv[]) +{ + opj_dinfo_t* dinfo; + opj_event_mgr_t event_mgr; /* event manager */ + int tnum; + unsigned int snum; + opj_mj2_t *movie; + mj2_tk_t *track; + mj2_sample_t *sample; + unsigned char* frame_codestream; + FILE *file, *outfile; + char outfilename[50]; + mj2_dparameters_t parameters; + + if (argc != 3) { + printf("Usage: %s mj2filename output_location\n", argv[0]); + printf("Example: %s foreman.mj2 output/foreman\n", argv[0]); + return 1; + } + + file = fopen(argv[1], "rb"); + + if (!file) { + fprintf(stderr, "failed to open %s for reading\n", argv[1]); + return 1; + } + + /* + configure the event callbacks (not required) + setting of each callback is optional + */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* get a MJ2 decompressor handle */ + dinfo = mj2_create_decompress(); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using user parameters */ + memset(¶meters, 0, sizeof(mj2_dparameters_t)); + movie = (opj_mj2_t*) dinfo->mj2_handle; + mj2_setup_decoder(movie, ¶meters); + + if (mj2_read_struct(file, movie)) { /* Creating the movie structure*/ + return 1; + } + + /* Decode first video track */ + tnum = 0; + while (movie->tk[tnum].track_type != 0) { + tnum ++; + } + + track = &movie->tk[tnum]; + + fprintf(stdout, "Extracting %d frames from file...\n", track->num_samples); + + for (snum = 0; snum < track->num_samples; snum++) { + sample = &track->sample[snum]; + frame_codestream = (unsigned char*) malloc(sample->sample_size - + 8); /* Skipping JP2C marker*/ + fseek(file, sample->offset + 8, SEEK_SET); + fread(frame_codestream, sample->sample_size - 8, 1, + file); /* Assuming that jp and ftyp markers size do*/ + + sprintf(outfilename, "%s_%05d.j2k", argv[2], snum); + outfile = fopen(outfilename, "wb"); + if (!outfile) { + fprintf(stderr, "failed to open %s for writing\n", outfilename); + return 1; + } + fwrite(frame_codestream, sample->sample_size - 8, 1, outfile); + fclose(outfile); + free(frame_codestream); + } + fclose(file); + fprintf(stdout, "%d frames correctly extracted\n", snum); + + /* free remaining structures */ + if (dinfo) { + mj2_destroy_decompress((opj_mj2_t*)dinfo->mj2_handle); + } + + return 0; +} diff --git a/openjpeg/src/bin/mj2/opj_mj2_wrap.c b/openjpeg/src/bin/mj2/opj_mj2_wrap.c new file mode 100644 index 000000000..84a066e21 --- /dev/null +++ b/openjpeg/src/bin/mj2/opj_mj2_wrap.c @@ -0,0 +1,537 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2014, Professor Benoit Macq + * Copyright (c) 2003-2007, Francois-Olivier Devaux + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "openjpeg.h" +#include "cio.h" +#include "j2k.h" +#include "jp2.h" +#include "mj2.h" + +static int int_ceildiv(int a, int b) +{ + return (a + b - 1) / b; +} + +/** +Size of memory first allocated for MOOV box +*/ +#define TEMP_BUF 10000 + +#define J2K_CODESTREAM_MAGIC "\xff\x4f\xff\x51" + +/* -------------------------------------------------------------------------- */ + +static int test_image(const char *fname, mj2_cparameters_t *cp) +{ + FILE *reader; + opj_image_t *image; + unsigned char *src; + opj_dinfo_t *dinfo; + opj_cio_t *cio; + opj_dparameters_t dparameters; + int success; + long src_len; + + success = 0; + + if ((reader = fopen(fname, "rb")) == NULL) { + return success; + } + + fseek(reader, 0, SEEK_END); + src_len = ftell(reader); + fseek(reader, 0, SEEK_SET); + src = (unsigned char*) malloc(src_len); + fread(src, 1, src_len, reader); + fclose(reader); + + if (memcmp(src, J2K_CODESTREAM_MAGIC, 4) != 0) { + free(src); + return success; + } + memset(&dparameters, 0, sizeof(opj_dparameters_t)); + + opj_set_default_decoder_parameters(&dparameters); + + dinfo = opj_create_decompress(CODEC_J2K); + + opj_setup_decoder(dinfo, &dparameters); + + cio = opj_cio_open((opj_common_ptr)dinfo, src, src_len); + + image = opj_decode(dinfo, cio); + + free(src); + cio->buffer = NULL; + opj_cio_close(cio); + + if (image == NULL) { + goto fin; + } + + cp->numcomps = image->numcomps; + cp->w = image->comps[0].w; + cp->h = image->comps[0].h; + cp->prec = image->comps[0].prec; + + if (image->numcomps > 2) { + if ((image->comps[0].dx == 1) + && (image->comps[1].dx == 2) + && (image->comps[2].dx == 2) + && (image->comps[0].dy == 1) + && (image->comps[1].dy == 2) + && (image->comps[2].dy == 2)) { /* horizontal and vertical*/ + /* Y420*/ + cp->enumcs = ENUMCS_SYCC; + cp->CbCr_subsampling_dx = 2; + cp->CbCr_subsampling_dy = 2; + } else if ((image->comps[0].dx == 1) + && (image->comps[1].dx == 2) + && (image->comps[2].dx == 2) + && (image->comps[0].dy == 1) + && (image->comps[1].dy == 1) + && (image->comps[2].dy == 1)) { /* horizontal only*/ + /* Y422*/ + cp->enumcs = ENUMCS_SYCC; + cp->CbCr_subsampling_dx = 2; + cp->CbCr_subsampling_dy = 1; + } else if ((image->comps[0].dx == 1) + && (image->comps[1].dx == 1) + && (image->comps[2].dx == 1) + && (image->comps[0].dy == 1) + && (image->comps[1].dy == 1) + && (image->comps[2].dy == 1)) { + /* Y444 or RGB */ + + if (image->color_space == CLRSPC_SRGB) { + cp->enumcs = ENUMCS_SRGB; + + /* cp->CbCr_subsampling_dx = 0; */ + /* cp->CbCr_subsampling_dy = 0; */ + } else { + cp->enumcs = ENUMCS_SYCC; + + cp->CbCr_subsampling_dx = 1; + cp->CbCr_subsampling_dy = 1; + } + } else { + goto fin; + } + } else { + cp->enumcs = ENUMCS_GRAY; + /* cp->CbCr_subsampling_dx = 0; */ + /* cp->CbCr_subsampling_dy = 0; */ + } + if (image->icc_profile_buf) { + cp->meth = 2; + free(image->icc_profile_buf); + image->icc_profile_buf = NULL; + } else { + cp->meth = 1; + } + + success = 1; +fin: + if (dinfo) { + opj_destroy_decompress(dinfo); + } + + if (image) { + opj_image_destroy(image); + } + + return success; +} + +/** +sample error callback expecting a FILE* client object +*/ +static void error_callback(const char *msg, void *client_data) +{ + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +static void warning_callback(const char *msg, void *client_data) +{ + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting a FILE* client object +*/ +static void info_callback(const char *msg, void *client_data) +{ + FILE *stream = (FILE*)client_data; + fprintf(stream, "[INFO] %s", msg); +} + +/* -------------------------------------------------------------------------- */ + + + +static void read_siz_marker(FILE *file, opj_image_t *image) +{ + int len, i; + char buf, buf2[2]; + unsigned char *siz_buffer; + opj_cio_t *cio; + + fseek(file, 0, SEEK_SET); + do { + fread(&buf, 1, 1, file); + if (buf == (char)0xff) { + fread(&buf, 1, 1, file); + } + } while (!(buf == (char)0x51)); + + fread(buf2, 2, 1, file); /* Lsiz */ + len = ((buf2[0]) << 8) + buf2[1]; + + siz_buffer = (unsigned char*) malloc(len * sizeof(unsigned char)); + fread(siz_buffer, len, 1, file); + cio = opj_cio_open(NULL, siz_buffer, len); + + cio_read(cio, 2); /* Rsiz (capabilities) */ + image->x1 = cio_read(cio, 4); /* Xsiz */ + image->y1 = cio_read(cio, 4); /* Ysiz */ + image->x0 = cio_read(cio, 4); /* X0siz */ + image->y0 = cio_read(cio, 4); /* Y0siz */ + cio_skip(cio, 16); /* XTsiz, YTsiz, XT0siz, YT0siz */ + + image->numcomps = cio_read(cio, 2); /* Csiz */ + image->comps = + (opj_image_comp_t *) malloc(image->numcomps * sizeof(opj_image_comp_t)); + + for (i = 0; i < image->numcomps; i++) { + int tmp; + tmp = cio_read(cio, 1); /* Ssiz_i */ + image->comps[i].prec = (tmp & 0x7f) + 1; + image->comps[i].sgnd = tmp >> 7; + image->comps[i].dx = cio_read(cio, 1); /* XRsiz_i */ + image->comps[i].dy = cio_read(cio, 1); /* YRsiz_i */ + image->comps[i].resno_decoded = 0; /* number of resolution decoded */ + image->comps[i].factor = 0; /* reducing factor by component */ + } + fseek(file, 0, SEEK_SET); + opj_cio_close(cio); + free(siz_buffer); +} + +static void setparams(opj_mj2_t *movie, opj_image_t *image) +{ + int i, depth_0, depth, sign; + + movie->tk[0].w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx); + movie->tk[0].h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy); + mj2_init_stdmovie(movie); + + movie->tk[0].depth = image->comps[0].prec; + + if (image->numcomps == 3) { + if ((image->comps[0].dx == 1) + && (image->comps[1].dx == 1) + && (image->comps[2].dx == 1)) { + movie->tk[0].CbCr_subsampling_dx = 1; + } else if ((image->comps[0].dx == 1) + && (image->comps[1].dx == 2) + && (image->comps[2].dx == 2)) { + movie->tk[0].CbCr_subsampling_dx = 2; + } else { + fprintf(stderr, "Image component sizes are incoherent\n"); + } + + if ((image->comps[0].dy == 1) + && (image->comps[1].dy == 1) + && (image->comps[2].dy == 1)) { + movie->tk[0].CbCr_subsampling_dy = 1; + } else if ((image->comps[0].dy == 1) + && (image->comps[1].dy == 2) + && (image->comps[2].dy == 2)) { + movie->tk[0].CbCr_subsampling_dy = 2; + } else { + fprintf(stderr, "Image component sizes are incoherent\n"); + } + } + + movie->tk[0].sample_rate = 25; + + movie->tk[0].jp2_struct.numcomps = image->numcomps; /* NC */ + + /* Init Standard jp2 structure */ + + movie->tk[0].jp2_struct.comps = + (opj_jp2_comps_t *) malloc(movie->tk[0].jp2_struct.numcomps * sizeof( + opj_jp2_comps_t)); + movie->tk[0].jp2_struct.precedence = 0; /* PRECEDENCE*/ + movie->tk[0].jp2_struct.approx = 0; /* APPROX*/ + movie->tk[0].jp2_struct.brand = JP2_JP2; /* BR */ + movie->tk[0].jp2_struct.minversion = 0; /* MinV */ + movie->tk[0].jp2_struct.numcl = 1; + movie->tk[0].jp2_struct.cl = (unsigned int *) malloc( + movie->tk[0].jp2_struct.numcl * sizeof(int)); + movie->tk[0].jp2_struct.cl[0] = JP2_JP2; /* CL0 : JP2 */ + movie->tk[0].jp2_struct.C = 7; /* C : Always 7*/ + movie->tk[0].jp2_struct.UnkC = + 0; /* UnkC, colorspace specified in colr box*/ + movie->tk[0].jp2_struct.IPR = 0; /* IPR, no intellectual property*/ + movie->tk[0].jp2_struct.w = int_ceildiv(image->x1 - image->x0, + image->comps[0].dx); + movie->tk[0].jp2_struct.h = int_ceildiv(image->y1 - image->y0, + image->comps[0].dy); + + depth_0 = image->comps[0].prec - 1; + sign = image->comps[0].sgnd; + movie->tk[0].jp2_struct.bpc = depth_0 + (sign << 7); + + for (i = 1; i < image->numcomps; i++) { + depth = image->comps[i].prec - 1; + sign = image->comps[i].sgnd; + if (depth_0 != depth) { + movie->tk[0].jp2_struct.bpc = 255; + } + } + + for (i = 0; i < image->numcomps; i++) + movie->tk[0].jp2_struct.comps[i].bpcc = + image->comps[i].prec - 1 + (image->comps[i].sgnd << 7); + + if ((image->numcomps == 1 || image->numcomps == 3) + && (movie->tk[0].jp2_struct.bpc != 255)) { + movie->tk[0].jp2_struct.meth = 1; + } else { + movie->tk[0].jp2_struct.meth = 2; + } + + if (image->numcomps == 1) { + movie->tk[0].jp2_struct.enumcs = 17; /* Grayscale */ + } + + else if ((image->comps[0].dx == 1) + && (image->comps[1].dx == 1) + && (image->comps[2].dx == 1) + && (image->comps[0].dy == 1) + && (image->comps[1].dy == 1) + && (image->comps[2].dy == 1)) { + movie->tk[0].jp2_struct.enumcs = 16; /* RGB */ + } + + else if ((image->comps[0].dx == 1) + && (image->comps[1].dx == 2) + && (image->comps[2].dx == 2) + && (image->comps[0].dy == 1) + && (image->comps[1].dy == 2) + && (image->comps[2].dy == 2)) { + movie->tk[0].jp2_struct.enumcs = 18; /* YUV */ + } + + else { + movie->tk[0].jp2_struct.enumcs = 0; /* Unknown profile */ + } +} + +int main(int argc, char *argv[]) +{ + opj_cinfo_t* cinfo; + opj_event_mgr_t event_mgr; /* event manager */ + unsigned int snum; + opj_mj2_t *movie; + mj2_sample_t *sample; + unsigned char* frame_codestream; + FILE *mj2file, *j2kfile; + char *j2kfilename; + unsigned char *buf; + int offset, mdat_initpos; + opj_image_t img; + opj_cio_t *cio; + mj2_cparameters_t parameters; + + if (argc != 3) { + printf("Usage: %s source_location mj2_filename\n", argv[0]); + printf("Example: %s input/input output.mj2\n", argv[0]); + return 1; + } + + mj2file = fopen(argv[2], "wb"); + + if (!mj2file) { + fprintf(stderr, "failed to open %s for writing\n", argv[2]); + return 1; + } + memset(&img, 0, sizeof(opj_image_t)); + /* + configure the event callbacks (not required) + setting of each callback is optional + */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* get a MJ2 decompressor handle */ + cinfo = mj2_create_compress(); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr); + + /* setup the decoder encoding parameters using user parameters */ + memset(¶meters, 0, sizeof(mj2_cparameters_t)); + movie = (opj_mj2_t*) cinfo->mj2_handle; + + j2kfilename = (char*)malloc(strlen(argv[1]) + 12);/* max. '%6d' */ + sprintf(j2kfilename, "%s_00001.j2k", argv[1]); + + if (test_image(j2kfilename, ¶meters) == 0) { + goto fin; + } + + parameters.frame_rate = 25; /* DEFAULT */ + + mj2_setup_encoder(movie, ¶meters); + + + /* Writing JP, FTYP and MDAT boxes + Assuming that the JP and FTYP boxes won't be longer than 300 bytes */ + + buf = (unsigned char*) malloc(300 * sizeof(unsigned char)); + cio = opj_cio_open(movie->cinfo, buf, 300); + mj2_write_jp(cio); + mj2_write_ftyp(movie, cio); + mdat_initpos = cio_tell(cio); + cio_skip(cio, 4); + cio_write(cio, MJ2_MDAT, 4); + fwrite(buf, cio_tell(cio), 1, mj2file); + free(buf); + + /* Insert each j2k codestream in a JP2C box */ + snum = 0; + offset = 0; + while (1) { + mj2_sample_t * new_sample; + mj2_chunk_t * new_chunk; + sample = &movie->tk[0].sample[snum]; + sprintf(j2kfilename, "%s_%05d.j2k", argv[1], snum); + j2kfile = fopen(j2kfilename, "rb"); + if (!j2kfile) { + if (snum == 0) { /* Could not open a single codestream */ + fprintf(stderr, "failed to open %s for reading\n", j2kfilename); + return 1; + } else { /* Tried to open a inexistent codestream */ + fprintf(stdout, "%d frames are being added to the MJ2 file\n", snum); + break; + } + } + + /* Calculating offset for samples and chunks */ + offset += cio_tell(cio); + sample->offset = offset; + movie->tk[0].chunk[snum].offset = + offset; /* There will be one sample per chunk */ + + /* Calculating sample size */ + fseek(j2kfile, 0, SEEK_END); + sample->sample_size = ftell(j2kfile) + + 8; /* Sample size is codestream + JP2C box header */ + fseek(j2kfile, 0, SEEK_SET); + + /* Reading siz marker of j2k image for the first codestream */ + if (snum == 0) { + read_siz_marker(j2kfile, &img); + } + + /* Writing JP2C box header */ + frame_codestream = (unsigned char*) malloc(sample->sample_size + 8); + cio = opj_cio_open(movie->cinfo, frame_codestream, sample->sample_size); + cio_write(cio, sample->sample_size, 4); /* Sample size */ + cio_write(cio, JP2_JP2C, 4); /* JP2C */ + + /* Writing codestream from J2K file to MJ2 file */ + fread(frame_codestream + 8, sample->sample_size - 8, 1, j2kfile); + fwrite(frame_codestream, sample->sample_size, 1, mj2file); + cio_skip(cio, sample->sample_size - 8); + + /* Ending loop */ + fclose(j2kfile); + snum++; + new_sample = (mj2_sample_t*) + realloc(movie->tk[0].sample, (snum + 1) * sizeof(mj2_sample_t)); + new_chunk = (mj2_chunk_t*) + realloc(movie->tk[0].chunk, (snum + 1) * sizeof(mj2_chunk_t)); + if (new_sample && new_chunk) { + movie->tk[0].sample = new_sample; + movie->tk[0].chunk = new_chunk; + } else { + fprintf(stderr, "Failed to allocate enough memory to read %s\n", j2kfilename); + return 1; + } + free(frame_codestream); + } + + /* Writing the MDAT box length in header */ + offset += cio_tell(cio); + buf = (unsigned char*) malloc(4 * sizeof(unsigned char)); + cio = opj_cio_open(movie->cinfo, buf, 4); + cio_write(cio, offset - mdat_initpos, 4); + fseek(mj2file, (long)mdat_initpos, SEEK_SET); + fwrite(buf, 4, 1, mj2file); + fseek(mj2file, 0, SEEK_END); + free(buf); + + /* Setting movie parameters */ + movie->tk[0].num_samples = snum; + movie->tk[0].num_chunks = snum; + setparams(movie, &img); + + /* Writing MOOV box */ + buf = (unsigned char*) malloc((TEMP_BUF + snum * 20) * sizeof(unsigned char)); + cio = opj_cio_open(movie->cinfo, buf, (TEMP_BUF + snum * 20)); + mj2_write_moov(movie, cio); + fwrite(buf, cio_tell(cio), 1, mj2file); + + /* Ending program */ + free(img.comps); + opj_cio_close(cio); + +fin: + fclose(mj2file); + mj2_destroy_compress(movie); + free(j2kfilename); + + return 0; +} diff --git a/openjpeg/src/bin/mj2/readme.txt b/openjpeg/src/bin/mj2/readme.txt new file mode 100644 index 000000000..9419d2a2d --- /dev/null +++ b/openjpeg/src/bin/mj2/readme.txt @@ -0,0 +1,3 @@ +Attention : the motion jpeg 2000 files currently only work with OpenJPEG v0.97 that you can find here : + +http://www.openjpeg.org/openjpeg_v097.tar.gz
\ No newline at end of file diff --git a/openjpeg/src/bin/wx/CMakeLists.txt b/openjpeg/src/bin/wx/CMakeLists.txt new file mode 100644 index 000000000..effb5b8d1 --- /dev/null +++ b/openjpeg/src/bin/wx/CMakeLists.txt @@ -0,0 +1,4 @@ +# +if(BUILD_VIEWER) + add_subdirectory(OPJViewer) +endif() diff --git a/openjpeg/src/bin/wx/OPJViewer/CMakeLists.txt b/openjpeg/src/bin/wx/OPJViewer/CMakeLists.txt new file mode 100644 index 000000000..66cf01d24 --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/CMakeLists.txt @@ -0,0 +1,29 @@ +project(viewer CXX) + +find_package(wxWidgets REQUIRED) +include(${wxWidgets_USE_FILE}) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/../.. + ${CMAKE_CURRENT_SOURCE_DIR}/.. + ${OPENJPEG_SOURCE_DIR}/src/lib + ${OPENJPEG_SOURCE_DIR}/src/bin + ${OPENJPEG_SOURCE_DIR}/src/lib/openjp2 + ${OPENJPEG_BINARY_DIR}/src/lib/openjp2 # opj_config.h and opj_config_private.h + ) + +# original flags: +# -DUSE_JPWL -DwxUSE_LIBOPENJPEG -DwxUSE_GUI=1 -DOPJ_STATIC -DOPJ_HTMLABOUT -DOPJ_INICONFIG -DUSE_JPSEC -DOPJ_MANYFORMATS +add_definitions(-DwxUSE_LIBOPENJPEG -DOPENJPEG_VERSION="1.5.0") +set(OPJV_SRCS + ${CMAKE_CURRENT_SOURCE_DIR}/source/imagjpeg2000.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/source/wxj2kparser.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/source/OPJViewer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/source/wxjp2parser.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/source/OPJDialogs.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/source/OPJThreads.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/source/OPJAbout.cpp + ${OPENJPEG_SOURCE_DIR}/src/bin/jp2/index.c + ) +add_executable(opjviewer ${OPJV_SRCS}) +target_link_libraries(opjviewer ${wxWidgets_LIBRARIES} openjpeg) diff --git a/openjpeg/src/bin/wx/OPJViewer/OPJViewer.iss b/openjpeg/src/bin/wx/OPJViewer/OPJViewer.iss new file mode 100644 index 000000000..0cf20da97 --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/OPJViewer.iss @@ -0,0 +1,48 @@ +; Script generated by the Inno Setup Script Wizard. +; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! + +[Setup] +AppName=OPJViewer +AppVerName=OPJViewer 0.4 beta +AppPublisher=OpenJPEG +AppPublisherURL=http://www.openjpeg.org +AppSupportURL=http://www.openjpeg.org +AppUpdatesURL=http://www.openjpeg.org +DefaultDirName={pf}\OPJViewer +DefaultGroupName=OPJViewer +OutputDir=setup +OutputBaseFilename=OPJViewer04beta_setup +Compression=lzma +SolidCompression=true +InfoBeforeFile=source\readmebefore.txt +InfoAfterFile=source\readmeafter.txt +LicenseFile=source\license.txt +VersionInfoVersion=0.4.0.0 +VersionInfoCompany=OpenJPEG +VersionInfoDescription=JPEG 2000 viewer +ShowLanguageDialog=yes +SetupIconFile=source\OPJViewer.ico + +[Languages] +Name: english; MessagesFile: compiler:Default.isl + +[Tasks] +Name: desktopicon; Description: {cm:CreateDesktopIcon}; GroupDescription: {cm:AdditionalIcons}; Flags: unchecked + +[Files] +Source: Release\OPJViewer.exe; DestDir: {app}; Flags: ignoreversion +;Source: about\about.htm; DestDir: {app}/about; Flags: ignoreversion +;Source: about\opj_logo.png; DestDir: {app}/about; Flags: ignoreversion +; NOTE: Don't use "Flags: ignoreversion" on any shared system files + +[Icons] +Name: {group}\OPJViewer; Filename: {app}\OPJViewer.exe; WorkingDir: {app}; IconIndex: 0 +Name: {group}\{cm:UninstallProgram,OPJViewer}; Filename: {uninstallexe} +Name: {userdesktop}\OPJViewer; Filename: {app}\OPJViewer.exe; Tasks: desktopicon; WorkingDir: {app}; IconIndex: 0 + +[Run] +Filename: {app}\OPJViewer.exe; Description: {cm:LaunchProgram,OPJViewer}; Flags: nowait postinstall skipifsilent; WorkingDir: {app} + +[Registry] +Root: HKCU; Subkey: Software\OpenJPEG; ValueType: none; ValueData: 1; Flags: uninsdeletekey; Tasks: ; Languages: +Root: HKCU; Subkey: Software\OpenJPEG\OPJViewer; ValueType: none; ValueData: 1; Flags: uninsdeletekey; Tasks: ; Languages: diff --git a/openjpeg/src/bin/wx/OPJViewer/Readme.txt b/openjpeg/src/bin/wx/OPJViewer/Readme.txt new file mode 100644 index 000000000..fe104bbf2 --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/Readme.txt @@ -0,0 +1,100 @@ +=============================================================================== + JPEG2000 Visualization Software - OPJViewer + + Version 0.4 beta +=============================================================================== + + +1. Scope +============= + +This document describes the installation and use of the OPJViewer in the framework of OpenJPEG library. + +This implementation has been developed using the OpenJPEG library as decoding engine and wxWidgets 2.8 as GUI engine. + +If you find some bugs or if you have problems using the viewer, please send an e-mail to jpwl@diei.unipg.it + +2. Installing the viewer +========================== + +There are two options available, at the moment: + +a) compile from source code +b) download a precompiled binary. + +In order to use option a), it is mandatory to have compiled and built the LibOpenJPEG_JPWL library and the wxWidgets 2.8 framework (you have to download it from http://www.wxwidgets.org/ and compile the wx* libraries). + +2.1. Compiling the source code in Windows +------------------------------------------- + +The steps required to compile the viewer under windows are: + +a) Download at least the libopenjpeg, jpwl, and opjviewer folders from the SVN trunk. +b) Open the OPJViewer.dsw workspace with Visual C++ 6 and activate the "OPJViewer - Win32 Release" configuration. +c) In the configuration settings, go to the C++ tab and modify the wxWidgets paths in order to reflect your wx* install configuration (Preprocessor -> Additional include directories): simply update each instance of the two wx paths, do not remove or add them. +d) In the configuration settings, go to the Link tab and modify the wxWidgets path in order to reflect your wx* install configuration (Input -> Additional library path): simply update the wx path. +e) In the configuration settings, go to the Resources tab and modify the wxWidgets path in order to reflect your wx* install configuration (Additional resource include directories): simply update the wx path. +f) Build! +g) Run! +h) (OPTIONAL) Prepare an installer by compiling the InnoSetup script OPJViewer.iss (you need to download InnoSetup from http://www.jrsoftware.org/isinfo.php). + +2.1.1 Additional libraries +---------------------------- + +Since we are also working on the Digital Cinema JPEG 2000, we are integrating the viewer with the MXF library, which is used to prepare the DCPs for digital movies. You can enable its linking in the code by specifying the USE_MXF preprocessor directive but, remember, the integration is at a very early stage. + +2.2. Compiling the source code in Unix-like systems +----------------------------------------------------- + +The porting is possible and under way. + + +3. General information on the viewer +==================================== + +This viewer is conceived to open and display information and image content of J2K, JP2, and MJ2 files. +The viewer application interface is divided into three main panels: +- a browsing pane; +- a viewing pane; +- a log/peek pane. + +The browsing pane will present the markers or boxes hierarchy, with position (byte number where marker/box starts and stops) and length information (i.e., inner length as signalled by marker/box and total length, with marker/box sign included), in the following form: + +filename +| +|_ #000: Marker/Box short name (Hex code) +| | +| |_ *** Marker/Box long name *** +| |_ startbyte > stopbyte, inner_length + marker/box sign length (total length) +| |_ Additional info, depending on the marker/box type +| |_ ... +| +|_ #001: Marker/Box short name (Hex code) +| | +| |_ ... +| +... + + +The viewing pane will display the decoded image contained in the JPEG 2000 file. +It should display correctly images as large as 4000x2000, provided that a couple of GB of RAM are available. Nothing is known about the display of larger sizes: let us know if you manage to get it working. + + +The log/peek pane is shared among two different subpanels: + +- the log panel will report a lot of debugging info coming out from the wx GUI as well as from the openjpeg library +- the peek pane tries to give a peek on the codestream/file portion which is currently selected in the browsing pane. It shows both hex and ascii values corresponding to the marker/box section. + + +4. Known bugs and limitations +=============================== + +4.1. Bugs +----------- + +* + +4.2. Limitations +------------------ + +* For mj2 files, rendering is only in B/W diff --git a/openjpeg/src/bin/wx/OPJViewer/about/about.htm b/openjpeg/src/bin/wx/OPJViewer/about/about.htm new file mode 100644 index 000000000..cdde97738 --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/about/about.htm @@ -0,0 +1,36 @@ +<html> +<body bgcolor="#FFFFFF"> +<table cellspacing=7 cellpadding=1 border=0 width="100%"> +<tr> +<td rowspan=3 valign=top align=center width=70> +<img src="opj_logo.png"><br><br> +</td> +<td align=center> +<font size=+2 color="#000000"><b>OPJViewer v0.2 alpha</b></font><br> +<font size=+0 color="#000000"><b>A JPEG 2000 image viewer</b></font> +</td> +</tr> +<tr height=3 valign=center> +<td valign=center bgcolor=#cc3300></td> +</tr> +<tr> +<td align=justify> +<center><font size=+0 color="#000000"><a href="http://www.openjpeg.org/">OpenJPEG</a></font></center> +<font size=-1 color="#000000">The OpenJPEG library is an open-source JPEG 2000 codec written in C language. +In addition to the basic codec, various other features are under development, +among them the JP2 and MJ2 (Motion JPEG 2000) file formats, an indexing tool +useful for the JPIP protocol, JPWL-tools for error-resilience, ...</font> +</td> +</tr> +<tr> +<td colspan=2 bgcolor="#CC3300" height=3 valign=center></td> +</tr> +<tr> +<td colspan=2> +<font size=-2 color="#444444">OpenJPEG is © 2002-2007 <a href="http://www.tele.ucl.ac.be/">TELE</a> - <a href="http://www.uclouvain.be/">Université Catholique de Louvain</a></font><br> +<font size=-2 color="#444444">OPJViewer is also © 2005-2007 <a href="http://dsplab.diei.unipg.it/">DSPLab</a> - <a href="http://www.unipg.it/">Università degli studi di Perugia</a></font> +</td> +</tr> +</table> +</body> +</html> diff --git a/openjpeg/src/bin/wx/OPJViewer/about/opj_logo.png b/openjpeg/src/bin/wx/OPJViewer/about/opj_logo.png Binary files differnew file mode 100644 index 000000000..0f43840a0 --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/about/opj_logo.png diff --git a/openjpeg/src/bin/wx/OPJViewer/source/OPJAbout.cpp b/openjpeg/src/bin/wx/OPJViewer/source/OPJAbout.cpp new file mode 100644 index 000000000..1f701e260 --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/OPJAbout.cpp @@ -0,0 +1,92 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2007, Digital Signal Processing Laboratory, Universita' degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifdef USE_MXF +#include "mxflib/mxflib.h" +#endif // USE_MXF + +#include "OPJViewer.h" + +// about window for the frame +void OPJFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) +{ +#ifdef OPJ_HTMLABOUT +#include "about_htm.h" +#include "opj_logo.xpm" + + wxBoxSizer *topsizer; + wxHtmlWindow *html; + wxDialog dlg(this, wxID_ANY, wxString(_("About"))); + + wxMemoryFSHandler::AddFile(wxT("opj_logo.xpm"), wxBitmap(opj_logo), wxBITMAP_TYPE_XPM); + + topsizer = new wxBoxSizer(wxVERTICAL); + + html = new wxHtmlWindow(&dlg, wxID_ANY, wxDefaultPosition, wxSize(320, 250), wxHW_SCROLLBAR_NEVER); + html->SetBorders(0); + //html->LoadPage(wxT("about/about.htm")); + //html->SetPage("<html><body>Hello, world!</body></html>"); + html->SetPage(htmlaboutpage); + html->SetSize(html->GetInternalRepresentation()->GetWidth(), + html->GetInternalRepresentation()->GetHeight()); + + topsizer->Add(html, 1, wxALL, 10); + + topsizer->Add(new wxStaticLine(&dlg, wxID_ANY), 0, wxEXPAND | wxLEFT | wxRIGHT, 10); + + wxButton *bu1 = new wxButton(&dlg, wxID_OK, wxT("OK")); + bu1->SetDefault(); + + topsizer->Add(bu1, 0, wxALL | wxALIGN_RIGHT, 15); + + dlg.SetSizer(topsizer); + topsizer->Fit(&dlg); + + dlg.ShowModal(); + +#else + + wxMessageBox(wxString::Format(OPJ_APPLICATION_TITLEBAR + wxT("\n\n") + wxT("Built with %s and OpenJPEG ") + wxT(OPENJPEG_VERSION) + wxT("\non ") wxT(__DATE__) wxT(", ") wxT(__TIME__) + wxT("\nRunning under %s\n\n") + OPJ_APPLICATION_COPYRIGHT, + wxVERSION_STRING, + wxGetOsDescription().c_str()), + wxT("About ") OPJ_APPLICATION_NAME, + wxOK | wxICON_INFORMATION, + this + ); + +#endif + +} diff --git a/openjpeg/src/bin/wx/OPJViewer/source/OPJChild.ico b/openjpeg/src/bin/wx/OPJViewer/source/OPJChild.ico Binary files differnew file mode 100644 index 000000000..7a127189d --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/OPJChild.ico diff --git a/openjpeg/src/bin/wx/OPJViewer/source/OPJChild16.xpm b/openjpeg/src/bin/wx/OPJViewer/source/OPJChild16.xpm new file mode 100644 index 000000000..99b7b2cfa --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/OPJChild16.xpm @@ -0,0 +1,28 @@ +/* XPM */ +static char *OPJChild16[] = { +/* columns rows colors chars-per-pixel */ +"16 16 6 1", +" c black", +". c #008000", +"X c red", +"o c #800080", +"O c gray100", +"+ c None", +/* pixels */ +"++++++++++++++++", +"+OOOOOOOOOOOOOO+", +"+OooooooooooooO+", +"+OooooooooooooO+", +"+OooOOOOOOOOOoO+", +"+OooO.......OoO+", +"+OooO.......OoO+", +"+OooO..OOO..OoO+", +"+OooO..OXO..OoO+", +"+OooO..OOO..OoO+", +"+OooO.......OoO+", +"+OooO.......OoO+", +"+OooOOOOOOOOOoO+", +"+OooooooooooooO+", +"+OOOOOOOOOOOOOO+", +"++++++++++++++++" +}; diff --git a/openjpeg/src/bin/wx/OPJViewer/source/OPJDialogs.cpp b/openjpeg/src/bin/wx/OPJViewer/source/OPJDialogs.cpp new file mode 100644 index 000000000..953cb7ea5 --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/OPJDialogs.cpp @@ -0,0 +1,1378 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2007, Digital Signal Processing Laboratory, Universita' degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "OPJViewer.h" + +// ---------------------------------------------------------------------------- +// OPJDecoderDialog +// ---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(OPJDecoderDialog, wxPropertySheetDialog) + +BEGIN_EVENT_TABLE(OPJDecoderDialog, wxPropertySheetDialog) + EVT_CHECKBOX(OPJDECO_ENABLEDECO, OPJDecoderDialog::OnEnableDeco) +#ifdef USE_JPWL + EVT_CHECKBOX(OPJDECO_ENABLEJPWL, OPJDecoderDialog::OnEnableJPWL) +#endif // USE_JPWL +END_EVENT_TABLE() + +OPJDecoderDialog::OPJDecoderDialog(wxWindow* win, int dialogType) +{ + SetExtraStyle(wxDIALOG_EX_CONTEXTHELP|wxWS_EX_VALIDATE_RECURSIVELY); + + Create(win, wxID_ANY, wxT("Decoder settings"), + wxDefaultPosition, wxDefaultSize, + wxDEFAULT_DIALOG_STYLE| (int) wxPlatform::IfNot(wxOS_WINDOWS_CE, wxRESIZE_BORDER) + ); + + CreateButtons(wxOK | wxCANCEL | (int)wxPlatform::IfNot(wxOS_WINDOWS_CE, wxHELP)); + + m_settingsNotebook = GetBookCtrl(); + + wxPanel* mainSettings = CreateMainSettingsPage(m_settingsNotebook); + wxPanel* jpeg2000Settings = CreatePart1SettingsPage(m_settingsNotebook); + if (!wxGetApp().m_enabledeco) + jpeg2000Settings->Enable(false); + wxPanel* mjpeg2000Settings = CreatePart3SettingsPage(m_settingsNotebook); + if (!wxGetApp().m_enabledeco) + mjpeg2000Settings->Enable(false); +#ifdef USE_JPWL + wxPanel* jpwlSettings = CreatePart11SettingsPage(m_settingsNotebook); + if (!wxGetApp().m_enabledeco) + jpwlSettings->Enable(false); +#endif // USE_JPWL + + m_settingsNotebook->AddPage(mainSettings, wxT("Display"), false); + m_settingsNotebook->AddPage(jpeg2000Settings, wxT("JPEG 2000"), false); + m_settingsNotebook->AddPage(mjpeg2000Settings, wxT("MJPEG 2000"), false); +#ifdef USE_JPWL + m_settingsNotebook->AddPage(jpwlSettings, wxT("JPWL"), false); +#endif // USE_JPWL + + LayoutDialog(); +} + +OPJDecoderDialog::~OPJDecoderDialog() +{ +} + +wxPanel* OPJDecoderDialog::CreateMainSettingsPage(wxWindow* parent) +{ + wxPanel* panel = new wxPanel(parent, wxID_ANY); + + // top sizer + wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL); + + // sub top sizer + wxBoxSizer *subtopSizer = new wxBoxSizer(wxVERTICAL); + + // add decoding enabling check box + subtopSizer->Add( + m_enabledecoCheck = new wxCheckBox(panel, OPJDECO_ENABLEDECO, wxT("Enable decoding"), wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 5); + m_enabledecoCheck->SetValue(wxGetApp().m_enabledeco); + + // add parsing enabling check box + subtopSizer->Add( + m_enableparseCheck = new wxCheckBox(panel, OPJDECO_ENABLEPARSE, wxT("Enable parsing"), wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 5); + m_enableparseCheck->SetValue(wxGetApp().m_enableparse); + + // resize settings, column + wxString choices[] = {wxT("Don't resize"), wxT("Low quality"), wxT("High quality")}; + m_resizeBox = new wxRadioBox(panel, OPJDECO_RESMETHOD, + wxT("Resize method"), + wxDefaultPosition, wxDefaultSize, + WXSIZEOF(choices), + choices, + 1, + wxRA_SPECIFY_ROWS); + m_resizeBox->SetSelection(wxGetApp().m_resizemethod + 1); + + subtopSizer->Add(m_resizeBox, 0, wxGROW | wxALL, 5); + + topSizer->Add(subtopSizer, 1, wxGROW | wxALIGN_CENTRE | wxALL, 5); + + // assign top and fit it + panel->SetSizer(topSizer); + topSizer->Fit(panel); + + return panel; +} + +wxPanel* OPJDecoderDialog::CreatePart3SettingsPage(wxWindow* parent) +{ + wxPanel* panel = new wxPanel(parent, wxID_ANY); + + // top sizer + wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL); + + // add some space + //topSizer->AddSpacer(5); + + // sub top sizer + wxBoxSizer *subtopSizer = new wxBoxSizer(wxVERTICAL); + + // frame settings, column + wxStaticBox* frameBox = new wxStaticBox(panel, wxID_ANY, wxT("Frame")); + wxBoxSizer* frameSizer = new wxStaticBoxSizer(frameBox, wxVERTICAL); + + // selected frame number, row + wxBoxSizer* framenumSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + framenumSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Displayed frame:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 5); + + // add some horizontal space + framenumSizer->Add(5, 5, 1, wxALL, 0); + + // add the value control + framenumSizer->Add( + m_framenumCtrl = new wxSpinCtrl(panel, OPJDECO_FRAMENUM, + wxString::Format(wxT("%d"), wxGetApp().m_framenum), + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxSP_ARROW_KEYS, + 1, 100000, wxGetApp().m_framenum), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5); + + frameSizer->Add(framenumSizer, 0, wxGROW | wxALL, 5); + + subtopSizer->Add(frameSizer, 0, wxGROW | wxALL, 5); + + topSizer->Add(subtopSizer, 1, wxGROW | wxALIGN_CENTRE | wxALL, 5); + + // assign top and fit it + panel->SetSizer(topSizer); + topSizer->Fit(panel); + + return panel; +} + +wxPanel* OPJDecoderDialog::CreatePart1SettingsPage(wxWindow* parent) +{ + wxPanel* panel = new wxPanel(parent, wxID_ANY); + + // top sizer + wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL); + + // add some space + //topSizer->AddSpacer(5); + + // sub top sizer + wxBoxSizer *subtopSizer = new wxBoxSizer(wxVERTICAL); + + // resolutions settings, column + wxStaticBox* resolutionBox = new wxStaticBox(panel, wxID_ANY, wxT("Resolutions")); + wxBoxSizer* resolutionSizer = new wxStaticBoxSizer(resolutionBox, wxVERTICAL); + + // reduce factor sizer, row + wxBoxSizer* reduceSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + reduceSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Reduce factor:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 5); + + // add some horizontal space + reduceSizer->Add(5, 5, 1, wxALL, 0); + + // add the value control + reduceSizer->Add( + m_reduceCtrl = new wxSpinCtrl(panel, OPJDECO_REDUCEFACTOR, + wxString::Format(wxT("%d"), wxGetApp().m_reducefactor), + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxSP_ARROW_KEYS, + 0, 10000, wxGetApp().m_reducefactor), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5); + + resolutionSizer->Add(reduceSizer, 0, wxGROW | wxALL, 5); + + subtopSizer->Add(resolutionSizer, 0, wxGROW | wxALL, 5); + + // quality layer settings, column + wxStaticBox* layerBox = new wxStaticBox(panel, wxID_ANY, wxT("Layers")); + wxBoxSizer* layerSizer = new wxStaticBoxSizer(layerBox, wxVERTICAL); + + // quality layers sizer, row + wxBoxSizer* qualitySizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + qualitySizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Quality layers:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 5); + + // add some horizontal space + qualitySizer->Add(5, 5, 1, wxALL, 0); + + // add the value control + qualitySizer->Add( + m_layerCtrl = new wxSpinCtrl(panel, OPJDECO_QUALITYLAYERS, + wxString::Format(wxT("%d"), wxGetApp().m_qualitylayers), + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxSP_ARROW_KEYS, + 0, 100000, wxGetApp().m_qualitylayers), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5); + + layerSizer->Add(qualitySizer, 0, wxGROW | wxALL, 5); + + subtopSizer->Add(layerSizer, 0, wxGROW | wxALL, 5); + + // component settings, column + wxStaticBox* compoBox = new wxStaticBox(panel, wxID_ANY, wxT("Components")); + wxBoxSizer* compoSizer = new wxStaticBoxSizer(compoBox, wxVERTICAL); + + // quality layers sizer, row + wxBoxSizer* numcompsSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + numcompsSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Component displayed:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 5); + + // add some horizontal space + numcompsSizer->Add(5, 5, 1, wxALL, 0); + + // add the value control + numcompsSizer->Add( + m_numcompsCtrl = new wxSpinCtrl(panel, OPJDECO_NUMCOMPS, + wxString::Format(wxT("%d"), wxGetApp().m_components), + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxSP_ARROW_KEYS, + 0, 100000, wxGetApp().m_components), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5); + m_numcompsCtrl->Enable(true); + + compoSizer->Add(numcompsSizer, 0, wxGROW | wxALL, 5); + + subtopSizer->Add(compoSizer, 0, wxGROW | wxALL, 5); + + topSizer->Add(subtopSizer, 1, wxGROW | wxALIGN_CENTRE | wxALL, 5); + + // assign top and fit it + panel->SetSizer(topSizer); + topSizer->Fit(panel); + + return panel; +} + +#ifdef USE_JPWL +wxPanel* OPJDecoderDialog::CreatePart11SettingsPage(wxWindow* parent) +{ + wxPanel* panel = new wxPanel(parent, wxID_ANY); + + // top sizer + wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL); + + // add some space + //topSizer->AddSpacer(5); + + // sub top sizer + wxBoxSizer *subtopSizer = new wxBoxSizer(wxVERTICAL); + + // add JPWL enabling check box + subtopSizer->Add( + m_enablejpwlCheck = new wxCheckBox(panel, OPJDECO_ENABLEJPWL, wxT("Enable JPWL"), wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 5); + m_enablejpwlCheck->SetValue(wxGetApp().m_enablejpwl); + + // component settings, column + wxStaticBox* compoBox = new wxStaticBox(panel, wxID_ANY, wxT("Components")); + wxBoxSizer* compoSizer = new wxStaticBoxSizer(compoBox, wxVERTICAL); + + // expected components sizer, row + wxBoxSizer* expcompsSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + expcompsSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Expected comps.:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 5); + + // add some horizontal space + expcompsSizer->Add(5, 5, 1, wxALL, 0); + + // add the value control + expcompsSizer->Add( + m_expcompsCtrl = new wxSpinCtrl(panel, OPJDECO_EXPCOMPS, + wxString::Format(wxT("%d"), wxGetApp().m_expcomps), + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxSP_ARROW_KEYS, + 1, 100000, wxGetApp().m_expcomps), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5); + m_expcompsCtrl->Enable(wxGetApp().m_enablejpwl); + + compoSizer->Add(expcompsSizer, 0, wxGROW | wxALL, 5); + + subtopSizer->Add(compoSizer, 0, wxGROW | wxALL, 5); + + // tiles settings, column + wxStaticBox* tileBox = new wxStaticBox(panel, wxID_ANY, wxT("Tiles")); + wxBoxSizer* tileSizer = new wxStaticBoxSizer(tileBox, wxVERTICAL); + + // maximum tiles sizer, row + wxBoxSizer* maxtileSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + maxtileSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Max. no. of tiles:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 5); + + // add some horizontal space + maxtileSizer->Add(5, 5, 1, wxALL, 0); + + // add the value control + maxtileSizer->Add( + m_maxtilesCtrl = new wxSpinCtrl(panel, OPJDECO_MAXTILES, + wxString::Format(wxT("%d"), wxGetApp().m_maxtiles), + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxSP_ARROW_KEYS, + 1, 100000, wxGetApp().m_maxtiles), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5); + m_maxtilesCtrl->Enable(wxGetApp().m_enablejpwl); + + tileSizer->Add(maxtileSizer, 0, wxGROW | wxALL, 5); + + subtopSizer->Add(tileSizer, 0, wxGROW | wxALL, 5); + + topSizer->Add(subtopSizer, 1, wxGROW | wxALIGN_CENTRE | wxALL, 5); + + // assign top and fit it + panel->SetSizer(topSizer); + topSizer->Fit(panel); + + return panel; +} + +void OPJDecoderDialog::OnEnableJPWL(wxCommandEvent& event) +{ + if (event.IsChecked()) { + wxLogMessage(wxT("JPWL enabled")); + m_expcompsCtrl->Enable(true); + m_maxtilesCtrl->Enable(true); + } else { + wxLogMessage(wxT("JPWL disabled")); + m_expcompsCtrl->Enable(false); + m_maxtilesCtrl->Enable(false); + } + +} + +#endif // USE_JPWL + +void OPJDecoderDialog::OnEnableDeco(wxCommandEvent& event) +{ + size_t pp; + + if (event.IsChecked()) { + wxLogMessage(wxT("Decoding enabled")); + m_resizeBox->Enable(true); + // enable all tabs except ourselves + for (pp = 0; pp < m_settingsNotebook->GetPageCount(); pp++) { + if (m_settingsNotebook->GetPageText(pp) != wxT("Display")) + m_settingsNotebook->GetPage(pp)->Enable(true); + } + } else { + wxLogMessage(wxT("Decoding disabled")); + m_resizeBox->Enable(false); + // disable all tabs except ourselves + for (pp = 0; pp < m_settingsNotebook->GetPageCount(); pp++) { + if (m_settingsNotebook->GetPageText(pp) != wxT("Display")) + m_settingsNotebook->GetPage(pp)->Enable(false); + } + } + +} + + + + +// ---------------------------------------------------------------------------- +// OPJEncoderDialog +// ---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(OPJEncoderDialog, wxPropertySheetDialog) + +BEGIN_EVENT_TABLE(OPJEncoderDialog, wxPropertySheetDialog) + EVT_CHECKBOX(OPJENCO_ENABLECOMM, OPJEncoderDialog::OnEnableComm) + EVT_CHECKBOX(OPJENCO_ENABLEINDEX, OPJEncoderDialog::OnEnableIdx) + EVT_CHECKBOX(OPJENCO_ENABLEPOC, OPJEncoderDialog::OnEnablePoc) + EVT_RADIOBUTTON(OPJENCO_RATERADIO, OPJEncoderDialog::OnRadioQualityRate) + EVT_RADIOBUTTON(OPJENCO_QUALITYRADIO, OPJEncoderDialog::OnRadioQualityRate) +#ifdef USE_JPWL + EVT_CHECKBOX(OPJENCO_ENABLEJPWL, OPJEncoderDialog::OnEnableJPWL) + EVT_CHOICE(OPJENCO_HPROT, OPJEncoderDialog::OnHprotSelect) + EVT_CHOICE(OPJENCO_PPROT, OPJEncoderDialog::OnPprotSelect) + EVT_CHOICE(OPJENCO_SENSI, OPJEncoderDialog::OnSensiSelect) +#endif // USE_JPWL +END_EVENT_TABLE() + +OPJEncoderDialog::OPJEncoderDialog(wxWindow* win, int dialogType) +{ + SetExtraStyle(wxDIALOG_EX_CONTEXTHELP|wxWS_EX_VALIDATE_RECURSIVELY); + + Create(win, wxID_ANY, wxT("Encoder settings"), + wxDefaultPosition, wxDefaultSize, + wxDEFAULT_DIALOG_STYLE| (int) wxPlatform::IfNot(wxOS_WINDOWS_CE, wxRESIZE_BORDER) + ); + + CreateButtons(wxOK | wxCANCEL | (int)wxPlatform::IfNot(wxOS_WINDOWS_CE, wxHELP)); + + m_settingsNotebook = GetBookCtrl(); + + wxPanel* jpeg2000_1Settings = CreatePart1_1SettingsPage(m_settingsNotebook); + wxPanel* jpeg2000_2Settings = CreatePart1_2SettingsPage(m_settingsNotebook); + wxPanel* mainSettings = CreateMainSettingsPage(m_settingsNotebook); +#ifdef USE_JPWL + wxPanel* jpwlSettings = CreatePart11SettingsPage(m_settingsNotebook); +#endif // USE_JPWL + +#ifdef USE_JPWL + m_settingsNotebook->AddPage(jpwlSettings, wxT("JPWL"), false); +#endif // USE_JPWL + m_settingsNotebook->AddPage(jpeg2000_1Settings, wxT("JPEG 2000 - 1"), false); + m_settingsNotebook->AddPage(jpeg2000_2Settings, wxT("JPEG 2000 - 2"), false); + m_settingsNotebook->AddPage(mainSettings, wxT("General"), false); + + LayoutDialog(); +} + +OPJEncoderDialog::~OPJEncoderDialog() +{ +} + +wxPanel* OPJEncoderDialog::CreateMainSettingsPage(wxWindow* parent) +{ + wxPanel* panel = new wxPanel(parent, wxID_ANY); + + // top sizer + wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL); + + // sub top sizer + wxBoxSizer *subtopSizer = new wxBoxSizer(wxVERTICAL); + + topSizer->Add(subtopSizer, 1, wxGROW | wxALIGN_CENTRE | wxALL, 5); + + // assign top and fit it + panel->SetSizer(topSizer); + topSizer->Fit(panel); + + return panel; +} + +#ifdef USE_JPWL +wxPanel* OPJEncoderDialog::CreatePart11SettingsPage(wxWindow* parent) +{ + wxPanel* panel = new wxPanel(parent, wxID_ANY); + int specno; + + // top sizer + wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL); + + // add JPWL enabling check box + topSizer->Add( + m_enablejpwlCheck = new wxCheckBox(panel, OPJENCO_ENABLEJPWL, wxT("Enable JPWL"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL | wxALIGN_CENTER, 5); + m_enablejpwlCheck->SetValue(wxGetApp().m_enablejpwle); + + // sub top sizer + wxFlexGridSizer *subtopSizer = new wxFlexGridSizer(2, 3, 3); + + // header settings, column + wxStaticBox* headerBox = new wxStaticBox(panel, wxID_ANY, wxT("Header protection")); + wxBoxSizer* headerSizer = new wxStaticBoxSizer(headerBox, wxVERTICAL); + + // info sizer, row + wxBoxSizer* info1Sizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + info1Sizer->Add(new wxStaticText(panel, wxID_ANY, + wxT("Type")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 1); + + // add some horizontal space + info1Sizer->Add(3, 3, 1, wxALL, 0); + + // add some text + info1Sizer->Add(new wxStaticText(panel, wxID_ANY, + wxT("Tile part")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 1); + + headerSizer->Add(info1Sizer, 0, wxGROW | wxALL, 0); + + // specify specs + wxString hprotvalues[] = {wxT("None"), wxT("Pred."), wxT("CRC16"), wxT("CRC32"), + wxT("RS37"), wxT("RS38"), wxT("RS40"), wxT("RS43"), wxT("RS45"), wxT("RS48"), + wxT("RS51"), wxT("RS53"), wxT("RS56"), wxT("RS64"), wxT("RS75"), wxT("RS80"), + wxT("RS85"), wxT("RS96"), wxT("RS112"), wxT("RS128")}; + for (specno = 0; specno < MYJPWL_MAX_NO_TILESPECS; specno++) { + + // tile+hprot sizer, row + wxBoxSizer* tilehprotSizer = new wxBoxSizer(wxHORIZONTAL); + + // add the value selection + tilehprotSizer->Add( + m_hprotChoice[specno] = new wxChoice(panel, OPJENCO_HPROT, + wxDefaultPosition, wxSize(60, wxDefaultCoord), + WXSIZEOF(hprotvalues), hprotvalues), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 1); + m_hprotChoice[specno]->SetSelection(wxGetApp().m_hprotsel[specno]); + + // add some horizontal space + tilehprotSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + tilehprotSizer->Add( + m_htileCtrl[specno] = new wxSpinCtrl(panel, OPJENCO_HTILE, + wxString::Format(wxT("%d"), wxGetApp().m_htileval[specno]), + wxDefaultPosition, wxSize(45, wxDefaultCoord), + wxSP_ARROW_KEYS, + 0, JPWL_MAXIMUM_TILES - 1, 0), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 1); + + headerSizer->Add(tilehprotSizer, 0, wxGROW | wxALL, 0); + } + + wxCommandEvent event1; + OnHprotSelect(event1); + + subtopSizer->Add(headerSizer, 0, wxGROW | wxALL, 3); + + // packet settings, column + wxStaticBox* packetBox = new wxStaticBox(panel, wxID_ANY, wxT("Packet protection")); + wxBoxSizer* packetSizer = new wxStaticBoxSizer(packetBox, wxVERTICAL); + + // info sizer, row + wxBoxSizer* info2Sizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + info2Sizer->Add(new wxStaticText(panel, wxID_ANY, + wxT("Type")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 1); + + // add some horizontal space + info2Sizer->Add(3, 3, 1, wxALL, 0); + + // add some text + info2Sizer->Add(new wxStaticText(panel, wxID_ANY, + wxT("Tile part")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 1); + + // add some horizontal space + info2Sizer->Add(3, 3, 1, wxALL, 0); + + // add some text + info2Sizer->Add(new wxStaticText(panel, wxID_ANY, + wxT("Packet")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 1); + + packetSizer->Add(info2Sizer, 0, wxGROW | wxALL, 0); + + // specify specs + wxString pprotvalues[] = {wxT("None"), wxT("Pred."), wxT("CRC16"), wxT("CRC32"), + wxT("RS37"), wxT("RS38"), wxT("RS40"), wxT("RS43"), wxT("RS45"), wxT("RS48"), + wxT("RS51"), wxT("RS53"), wxT("RS56"), wxT("RS64"), wxT("RS75"), wxT("RS80"), + wxT("RS85"), wxT("RS96"), wxT("RS112"), wxT("RS128")}; + for (specno = 0; specno < MYJPWL_MAX_NO_TILESPECS; specno++) { + + // tile+pprot sizer, row + wxBoxSizer* tilepprotSizer = new wxBoxSizer(wxHORIZONTAL); + + // add the value selection + tilepprotSizer->Add( + m_pprotChoice[specno] = new wxChoice(panel, OPJENCO_PPROT, + wxDefaultPosition, wxSize(60, wxDefaultCoord), + WXSIZEOF(pprotvalues), pprotvalues), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 1); + m_pprotChoice[specno]->SetSelection(wxGetApp().m_pprotsel[specno]); + + // add some horizontal space + tilepprotSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + tilepprotSizer->Add( + m_ptileCtrl[specno] = new wxSpinCtrl(panel, OPJENCO_PTILE, + wxString::Format(wxT("%d"), wxGetApp().m_ptileval[specno]), + wxDefaultPosition, wxSize(45, wxDefaultCoord), + wxSP_ARROW_KEYS, + 0, JPWL_MAXIMUM_TILES - 1, 0), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 1); + + // add some horizontal space + tilepprotSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + tilepprotSizer->Add( + m_ppackCtrl[specno] = new wxSpinCtrl(panel, OPJENCO_PPACK, + wxString::Format(wxT("%d"), wxGetApp().m_ppackval[specno]), + wxDefaultPosition, wxSize(50, wxDefaultCoord), + wxSP_ARROW_KEYS, + 0, 2047, 0), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 1); + + packetSizer->Add(tilepprotSizer, 0, wxGROW | wxALL, 0); + } + + wxCommandEvent event2; + OnPprotSelect(event2); + + subtopSizer->Add(packetSizer, 0, wxGROW | wxALL, 3); + + // sensitivity settings, column + wxStaticBox* sensiBox = new wxStaticBox(panel, wxID_ANY, wxT("Sensitivity")); + wxBoxSizer* sensiSizer = new wxStaticBoxSizer(sensiBox, wxVERTICAL); + + // info sizer, row + wxBoxSizer* info3Sizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + info3Sizer->Add(new wxStaticText(panel, wxID_ANY, + wxT("Type")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 1); + + // add some horizontal space + info3Sizer->Add(3, 3, 1, wxALL, 0); + + // add some text + info3Sizer->Add(new wxStaticText(panel, wxID_ANY, + wxT("Tile part")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 1); + + sensiSizer->Add(info3Sizer, 0, wxGROW | wxALL, 0); + + // specify specs + wxString sensivalues[] = {wxT("None"), wxT("RELATIVE ERROR"), wxT("MSE"), + wxT("MSE REDUCTION"), wxT("PSNR INCREMENT"), wxT("MAXERR"), wxT("TSE")}; + for (specno = 0; specno < MYJPWL_MAX_NO_TILESPECS; specno++) { + + // tile+sensi sizer, row + wxBoxSizer* tilesensiSizer = new wxBoxSizer(wxHORIZONTAL); + + // add the value selection + tilesensiSizer->Add( + m_sensiChoice[specno] = new wxChoice(panel, OPJENCO_SENSI, + wxDefaultPosition, wxSize(110, wxDefaultCoord), + WXSIZEOF(sensivalues), sensivalues), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 1); + m_sensiChoice[specno]->SetSelection(wxGetApp().m_sensisel[specno]); + + // add some horizontal space + tilesensiSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + tilesensiSizer->Add( + m_stileCtrl[specno] = new wxSpinCtrl(panel, OPJENCO_STILE, + wxString::Format(wxT("%d"), wxGetApp().m_stileval[specno]), + wxDefaultPosition, wxSize(45, wxDefaultCoord), + wxSP_ARROW_KEYS, + 0, JPWL_MAXIMUM_TILES - 1, 0), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 1); + + sensiSizer->Add(tilesensiSizer, 0, wxGROW | wxALL, 0); + } + + wxCommandEvent event3; + OnSensiSelect(event3); + + subtopSizer->Add(sensiSizer, 0, wxGROW | wxALL, 3); + + topSizer->Add(subtopSizer, 1, wxGROW | wxALIGN_CENTRE | wxALL, 5); + + // assign top and fit it + panel->SetSizer(topSizer); + topSizer->Fit(panel); + + return panel; +} +#endif // USE_JPWL + +wxPanel* OPJEncoderDialog::CreatePart1_1SettingsPage(wxWindow* parent) +{ + wxPanel* panel = new wxPanel(parent, wxID_ANY); + + // top sizer + wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL); + + // add some space + //topSizer->AddSpacer(5); + + // sub top sizer + wxFlexGridSizer *subtopSizer = new wxFlexGridSizer(2, 3, 3); + + // image settings, column + wxStaticBox* imageBox = new wxStaticBox(panel, wxID_ANY, wxT("Image")); + wxBoxSizer* imageSizer = new wxStaticBoxSizer(imageBox, wxVERTICAL); + + // subsampling factor sizer, row + wxBoxSizer* subsSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + subsSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Subsampling:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 3); + + // add some horizontal space + subsSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + subsSizer->Add( + m_subsamplingCtrl = new wxTextCtrl(panel, OPJENCO_SUBSAMPLING, + wxGetApp().m_subsampling, + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxTE_LEFT), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + + imageSizer->Add(subsSizer, 0, wxGROW | wxALL, 3); + + // origin sizer, row + wxBoxSizer* imorigSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + imorigSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Origin:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 3); + + // add some horizontal space + imorigSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + imorigSizer->Add( + m_originCtrl = new wxTextCtrl(panel, OPJENCO_IMORIG, + wxGetApp().m_origin, + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxTE_LEFT), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + + imageSizer->Add(imorigSizer, 0, wxGROW | wxALL, 3); + + subtopSizer->Add(imageSizer, 0, wxGROW | wxALL, 3); + + // layer settings, column + wxStaticBox* layerBox = new wxStaticBox(panel, wxID_ANY, wxT("Layers/compression")); + wxBoxSizer* layerSizer = new wxStaticBoxSizer(layerBox, wxVERTICAL); + + // rate factor sizer, row + wxBoxSizer* rateSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + /*rateSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Rate values:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 3);*/ + + // add the radio button + rateSizer->Add( + m_rateRadio = new wxRadioButton(panel, OPJENCO_RATERADIO, wxT("&Rate values"), + wxDefaultPosition, wxDefaultSize, + wxRB_GROUP), + 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL + ); + m_rateRadio->SetValue(!(wxGetApp().m_enablequality)); + + // add some horizontal space + rateSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + rateSizer->Add( + m_rateCtrl = new wxTextCtrl(panel, OPJENCO_RATEFACTOR, + wxGetApp().m_rates, + wxDefaultPosition, wxSize(100, wxDefaultCoord), + wxTE_LEFT), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + if (wxGetApp().m_enablequality == true) + m_rateCtrl->Enable(false); + + layerSizer->Add(rateSizer, 0, wxGROW | wxALL, 3); + + // quality factor sizer, row + wxBoxSizer* qualitySizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + /*qualitySizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Quality values:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 3);*/ + + // add the radio button + qualitySizer->Add( + m_qualityRadio = new wxRadioButton(panel, OPJENCO_QUALITYRADIO, wxT("&Quality values"), + wxDefaultPosition, wxDefaultSize), + 0, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL + ); + m_qualityRadio->SetValue(wxGetApp().m_enablequality); + + // add some horizontal space + qualitySizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + qualitySizer->Add( + m_qualityCtrl = new wxTextCtrl(panel, OPJENCO_QUALITYFACTOR, + wxGetApp().m_quality, + wxDefaultPosition, wxSize(100, wxDefaultCoord), + wxTE_LEFT), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + if (wxGetApp().m_enablequality == false) + m_qualityCtrl->Enable(false); + + layerSizer->Add(qualitySizer, 0, wxGROW | wxALL, 3); + + subtopSizer->Add(layerSizer, 0, wxGROW | wxALL, 3); + + // wavelet settings, column + wxStaticBox* transformBox = new wxStaticBox(panel, wxID_ANY, wxT("Transforms")); + wxBoxSizer* transformSizer = new wxStaticBoxSizer(transformBox, wxVERTICAL); + + // multiple component check box + transformSizer->Add( + m_mctCheck = new wxCheckBox(panel, OPJENCO_ENABLEMCT, wxT("Multiple component"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_mctCheck->SetValue(wxGetApp().m_multicomp); + + // irreversible wavelet check box + transformSizer->Add( + m_irrevCheck = new wxCheckBox(panel, OPJENCO_ENABLEIRREV, wxT("Irreversible wavelet"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_irrevCheck->SetValue(wxGetApp().m_irreversible); + + // resolution number sizer, row + wxBoxSizer* resnumSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + resnumSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Resolutions:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 3); + + // add some horizontal space + resnumSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + resnumSizer->Add( + m_resolutionsCtrl = new wxSpinCtrl(panel, OPJENCO_RESNUMBER, + wxString::Format(wxT("%d"), wxGetApp().m_resolutions), + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxSP_ARROW_KEYS, + 1, 256, 6), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + + transformSizer->Add(resnumSizer, 0, wxGROW | wxALL, 3); + + subtopSizer->Add(transformSizer, 0, wxGROW | wxALL, 3); + + // codestream settings, column + wxStaticBox* codestreamBox = new wxStaticBox(panel, wxID_ANY, wxT("Codestream")); + wxBoxSizer* codestreamSizer = new wxStaticBoxSizer(codestreamBox, wxVERTICAL); + + // codeblock sizer, row + wxBoxSizer* codeblockSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + codeblockSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Codeblocks size:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 3); + + // add some horizontal space + codeblockSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + codeblockSizer->Add( + m_cbsizeCtrl = new wxTextCtrl(panel, OPJENCO_CODEBLOCKSIZE, + wxGetApp().m_cbsize, + wxDefaultPosition, wxSize(100, wxDefaultCoord), + wxTE_LEFT), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + + codestreamSizer->Add(codeblockSizer, 0, wxGROW | wxALL, 3); + + // precinct sizer, row + wxBoxSizer* precinctSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + precinctSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Precincts size:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 3); + + // add some horizontal space + precinctSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + precinctSizer->Add( + m_prsizeCtrl = new wxTextCtrl(panel, OPJENCO_PRECINCTSIZE, + wxGetApp().m_prsize, + wxDefaultPosition, wxSize(100, wxDefaultCoord), + wxTE_LEFT), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + + codestreamSizer->Add(precinctSizer, 0, wxGROW | wxALL, 3); + + subtopSizer->Add(codestreamSizer, 0, wxGROW | wxALL, 3); + + // tile settings, column + wxStaticBox* tileBox = new wxStaticBox(panel, wxID_ANY, wxT("Tiles")); + wxBoxSizer* tileSizer = new wxStaticBoxSizer(tileBox, wxVERTICAL); + + // tile size sizer, row + wxBoxSizer* tilesizeSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + tilesizeSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Size:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 3); + + // add some horizontal space + tilesizeSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + tilesizeSizer->Add( + m_tsizeCtrl = new wxTextCtrl(panel, OPJENCO_TILESIZE, + wxGetApp().m_tsize, + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxTE_LEFT), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + + tileSizer->Add(tilesizeSizer, 0, wxGROW | wxALL, 3); + + // tile origin sizer, row + wxBoxSizer* tilorigSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + tilorigSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Origin:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 3); + + // add some horizontal space + tilorigSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + tilorigSizer->Add( + m_toriginCtrl = new wxTextCtrl(panel, OPJENCO_TILORIG, + wxGetApp().m_torigin, + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxTE_LEFT), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + + tileSizer->Add(tilorigSizer, 0, wxGROW | wxALL, 3); + + subtopSizer->Add(tileSizer, 0, wxGROW | wxALL, 3); + + // progression and profile settings, column + wxString choices[] = {wxT("LRCP"), wxT("RLCP"), wxT("RPCL"), wxT("PCRL"), wxT("CPRL"), + wxT("DCI2K24"), wxT("DCI2K48"), wxT("DCI4K")}; + progressionBox = new wxRadioBox(panel, OPJENCO_PROGRESSION, + wxT("Progression order/profile"), + wxDefaultPosition, wxDefaultSize, + WXSIZEOF(choices), + choices, + 3, + wxRA_SPECIFY_COLS); + progressionBox->SetSelection(wxGetApp().m_progression); + + subtopSizer->Add(progressionBox, 0, wxGROW | wxALL, 3); + + topSizer->Add(subtopSizer, 1, wxGROW | wxALIGN_CENTRE | wxALL, 5); + + // assign top and fit it + panel->SetSizer(topSizer); + topSizer->Fit(panel); + + return panel; +} + +wxPanel* OPJEncoderDialog::CreatePart1_2SettingsPage(wxWindow* parent) +{ + wxPanel* panel = new wxPanel(parent, wxID_ANY); + + // top sizer + wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL); + + // add some space + //topSizer->AddSpacer(5); + + // sub top sizer + wxFlexGridSizer *subtopSizer = new wxFlexGridSizer(2, 3, 3); + + // resilience settings, column + wxStaticBox* resilBox = new wxStaticBox(panel, wxID_ANY, wxT("Error resilience")); + wxBoxSizer* resilSizer = new wxStaticBoxSizer(resilBox, wxVERTICAL); + + // resil2 sizer, row + wxBoxSizer* resil2Sizer = new wxBoxSizer(wxHORIZONTAL); + + // SOP check box + resil2Sizer->Add( + m_sopCheck = new wxCheckBox(panel, OPJENCO_ENABLESOP, wxT("SOP"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_sopCheck->SetValue(wxGetApp().m_enablesop); + + // EPH check box + resil2Sizer->Add( + m_ephCheck = new wxCheckBox(panel, OPJENCO_ENABLEEPH, wxT("EPH"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_ephCheck->SetValue(wxGetApp().m_enableeph); + + resilSizer->Add(resil2Sizer, 0, wxGROW | wxALL, 3); + + // separation + resilSizer->Add(new wxStaticLine(panel, wxID_ANY), 0, wxEXPAND | wxLEFT | wxRIGHT, 3); + + // resil3 sizer, row + wxFlexGridSizer* resil3Sizer = new wxFlexGridSizer(3, 3, 3); + + // BYPASS check box + resil3Sizer->Add( + m_enablebypassCheck = new wxCheckBox(panel, OPJENCO_ENABLEBYPASS, wxT("BYPASS"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_enablebypassCheck->SetValue(wxGetApp().m_enablebypass); + + // RESET check box + resil3Sizer->Add( + m_enableresetCheck = new wxCheckBox(panel, OPJENCO_ENABLERESET, wxT("RESET"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_enableresetCheck->SetValue(wxGetApp().m_enablereset); + + // RESTART check box + resil3Sizer->Add( + m_enablerestartCheck = new wxCheckBox(panel, OPJENCO_ENABLERESTART, wxT("RESTART"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_enablerestartCheck->SetValue(wxGetApp().m_enablerestart); + + // VSC check box + resil3Sizer->Add( + m_enablevscCheck = new wxCheckBox(panel, OPJENCO_ENABLEVSC, wxT("VSC"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_enablevscCheck->SetValue(wxGetApp().m_enablevsc); + + // ERTERM check box + resil3Sizer->Add( + m_enableertermCheck = new wxCheckBox(panel, OPJENCO_ENABLEERTERM, wxT("ERTERM"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_enableertermCheck->SetValue(wxGetApp().m_enableerterm); + + // SEGMARK check box + resil3Sizer->Add( + m_enablesegmarkCheck = new wxCheckBox(panel, OPJENCO_ENABLESEGMARK, wxT("SEGMARK"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_enablesegmarkCheck->SetValue(wxGetApp().m_enablesegmark); + + resilSizer->Add(resil3Sizer, 0, wxGROW | wxALL, 3); + + subtopSizer->Add(resilSizer, 0, wxGROW | wxALL, 3); + + // ROI settings, column + wxStaticBox* roiBox = new wxStaticBox(panel, wxID_ANY, wxT("Region Of Interest")); + wxBoxSizer* roiSizer = new wxStaticBoxSizer(roiBox, wxVERTICAL); + + // component number sizer, row + wxBoxSizer* roicompSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + roicompSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Component:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 3); + + // add some horizontal space + roicompSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + roicompSizer->Add( + /*m_layerCtrl =*/ new wxSpinCtrl(panel, OPJENCO_ROICOMP, + wxT("0"), + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxSP_ARROW_KEYS, + 0, 256, 0), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + + roiSizer->Add(roicompSizer, 0, wxGROW | wxALL, 3); + + // upshift sizer, row + wxBoxSizer* roishiftSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + roishiftSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Upshift:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 3); + + // add some horizontal space + roishiftSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + roishiftSizer->Add( + /*m_layerCtrl =*/ new wxSpinCtrl(panel, OPJENCO_ROISHIFT, + wxT("0"), + wxDefaultPosition, wxSize(80, wxDefaultCoord), + wxSP_ARROW_KEYS, + 0, 37, 0), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + + roiSizer->Add(roishiftSizer, 0, wxGROW | wxALL, 3); + + subtopSizer->Add(roiSizer, 0, wxGROW | wxALL, 3); + + // POC settings, column + wxStaticBox* pocBox = new wxStaticBox(panel, wxID_ANY, wxT("POC")); + wxBoxSizer* pocSizer = new wxStaticBoxSizer(pocBox, wxVERTICAL); + + // POC check box + pocSizer->Add( + m_enablepocCheck = new wxCheckBox(panel, OPJENCO_ENABLEPOC, wxT("Enabled (tn=rs,cs,le,re,ce,pr)"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_enablepocCheck->SetValue(wxGetApp().m_enablepoc); + + // POC sizer, row + wxBoxSizer* pocspecSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + pocspecSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&Changes:")), + 0, wxALL | wxALIGN_TOP, 3); + + // add some horizontal space + pocspecSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + pocspecSizer->Add( + m_pocCtrl = new wxTextCtrl(panel, OPJENCO_POCSPEC, + wxGetApp().m_poc, + wxDefaultPosition, wxSize(140, 60), + wxTE_LEFT | wxTE_MULTILINE), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + m_pocCtrl->Enable(wxGetApp().m_enablepoc); + + pocSizer->Add(pocspecSizer, 0, wxGROW | wxALL, 3); + + subtopSizer->Add(pocSizer, 0, wxGROW | wxALL, 3); + + // Comment settings, column + wxStaticBox* commentBox = new wxStaticBox(panel, wxID_ANY, wxT("Comment")); + wxBoxSizer* commentSizer = new wxStaticBoxSizer(commentBox, wxVERTICAL); + + // commenting check box + commentSizer->Add( + m_enablecommCheck = new wxCheckBox(panel, OPJENCO_ENABLECOMM, wxT("Enabled (empty to reset)"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_enablecommCheck->SetValue(wxGetApp().m_enablecomm); + + // add some horizontal space + commentSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + commentSizer->Add( + m_commentCtrl = new wxTextCtrl(panel, OPJENCO_COMMENTTEXT, + wxGetApp().m_comment, + wxDefaultPosition, wxSize(wxDefaultCoord, 60), + wxTE_LEFT | wxTE_MULTILINE), + 0, wxGROW | wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + m_commentCtrl->Enable(wxGetApp().m_enablecomm); + + subtopSizer->Add(commentSizer, 0, wxGROW | wxALL, 3); + + // Index file settings, column + wxStaticBox* indexBox = new wxStaticBox(panel, wxID_ANY, wxT("Indexing")); + wxBoxSizer* indexSizer = new wxStaticBoxSizer(indexBox, wxVERTICAL); + + // indexing check box + indexSizer->Add( + m_enableidxCheck = new wxCheckBox(panel, OPJENCO_ENABLEINDEX, wxT("Enabled"), + wxDefaultPosition, wxDefaultSize), + 0, wxGROW | wxALL, 3); + m_enableidxCheck->SetValue(wxGetApp().m_enableidx); + + // index file sizer, row + wxBoxSizer* indexnameSizer = new wxBoxSizer(wxHORIZONTAL); + + // add some text + indexnameSizer->Add(new wxStaticText(panel, wxID_ANY, wxT("&File name:")), + 0, wxALL | wxALIGN_CENTER_VERTICAL, 3); + + // add some horizontal space + indexnameSizer->Add(3, 3, 1, wxALL, 0); + + // add the value control + indexnameSizer->Add( + m_indexCtrl = new wxTextCtrl(panel, OPJENCO_INDEXNAME, + wxGetApp().m_index, + wxDefaultPosition, wxSize(120, wxDefaultCoord), + wxTE_LEFT), + 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 3); + m_indexCtrl->Enable(wxGetApp().m_enableidx); + + indexSizer->Add(indexnameSizer, 0, wxGROW | wxALL, 3); + + subtopSizer->Add(indexSizer, 0, wxGROW | wxALL, 3); + + topSizer->Add(subtopSizer, 1, wxGROW | wxALIGN_CENTRE | wxALL, 5); + + // assign top and fit it + panel->SetSizer(topSizer); + topSizer->Fit(panel); + + return panel; +} + +void OPJEncoderDialog::OnEnableComm(wxCommandEvent& event) +{ + if (event.IsChecked()) { + wxLogMessage(wxT("Comment enabled")); + m_commentCtrl->Enable(true); + } else { + wxLogMessage(wxT("Comment disabled")); + m_commentCtrl->Enable(false); + } + +} + +void OPJEncoderDialog::OnEnableIdx(wxCommandEvent& event) +{ + if (event.IsChecked()) { + wxLogMessage(wxT("Index enabled")); + m_indexCtrl->Enable(true); + } else { + wxLogMessage(wxT("Index disabled")); + m_indexCtrl->Enable(false); + } + +} + +void OPJEncoderDialog::OnEnablePoc(wxCommandEvent& event) +{ + if (event.IsChecked()) { + wxLogMessage(wxT("POC enabled")); + m_pocCtrl->Enable(true); + } else { + wxLogMessage(wxT("POC disabled")); + m_pocCtrl->Enable(false); + } + +} + +void OPJEncoderDialog::OnRadioQualityRate(wxCommandEvent& event) +{ + if (event.GetId() == OPJENCO_QUALITYRADIO) { + wxLogMessage(wxT("Quality selected")); + m_rateCtrl->Enable(false); + m_qualityCtrl->Enable(true); + } else { + wxLogMessage(wxT("Rate selected")); + m_rateCtrl->Enable(true); + m_qualityCtrl->Enable(false); + } +} + +#ifdef USE_JPWL +void OPJEncoderDialog::OnEnableJPWL(wxCommandEvent& event) +{ + int specno; + + if (event.IsChecked()) { + wxLogMessage(wxT("JPWL enabled")); + for (specno = 0; specno < MYJPWL_MAX_NO_TILESPECS; specno++) { + m_hprotChoice[specno]->Enable(true); + m_htileCtrl[specno]->Enable(true); + m_pprotChoice[specno]->Enable(true); + m_ptileCtrl[specno]->Enable(true); + m_ppackCtrl[specno]->Enable(true); + m_sensiChoice[specno]->Enable(true); + m_stileCtrl[specno]->Enable(true); + } + OnHprotSelect(event); + OnPprotSelect(event); + OnSensiSelect(event); + } else { + wxLogMessage(wxT("JPWL disabled")); + for (specno = 0; specno < MYJPWL_MAX_NO_TILESPECS; specno++) { + m_hprotChoice[specno]->Enable(false); + m_htileCtrl[specno]->Enable(false); + m_pprotChoice[specno]->Enable(false); + m_ptileCtrl[specno]->Enable(false); + m_ppackCtrl[specno]->Enable(false); + m_sensiChoice[specno]->Enable(false); + m_stileCtrl[specno]->Enable(false); + } + } + +} + +void OPJEncoderDialog::OnHprotSelect(wxCommandEvent& event) +{ + int specno; + + // deactivate properly + for (specno = MYJPWL_MAX_NO_TILESPECS - 1; specno >= 0; specno--) { + if (!m_hprotChoice[specno]->GetSelection()) { + m_hprotChoice[specno]->Enable(false); + m_htileCtrl[specno]->Enable(false); + } else + break; + } + if (specno < (MYJPWL_MAX_NO_TILESPECS - 1)) { + m_hprotChoice[specno + 1]->Enable(true); + m_htileCtrl[specno + 1]->Enable(true); + } + + //wxLogMessage(wxT("hprot changed: %d"), specno); +} + +void OPJEncoderDialog::OnPprotSelect(wxCommandEvent& event) +{ + int specno; + + // deactivate properly + for (specno = MYJPWL_MAX_NO_TILESPECS - 1; specno >= 0; specno--) { + if (!m_pprotChoice[specno]->GetSelection()) { + m_pprotChoice[specno]->Enable(false); + m_ptileCtrl[specno]->Enable(false); + m_ppackCtrl[specno]->Enable(false); + } else + break; + } + if (specno < (MYJPWL_MAX_NO_TILESPECS - 1)) { + m_pprotChoice[specno + 1]->Enable(true); + m_ptileCtrl[specno + 1]->Enable(true); + m_ppackCtrl[specno + 1]->Enable(true); + } + + //wxLogMessage(wxT("pprot changed: %d"), specno); +} + +void OPJEncoderDialog::OnSensiSelect(wxCommandEvent& event) +{ + int specno; + + // deactivate properly + for (specno = MYJPWL_MAX_NO_TILESPECS - 1; specno >= 0; specno--) { + if (!m_sensiChoice[specno]->GetSelection()) { + m_sensiChoice[specno]->Enable(false); + m_stileCtrl[specno]->Enable(false); + } else + break; + } + if (specno < (MYJPWL_MAX_NO_TILESPECS - 1)) { + m_sensiChoice[specno + 1]->Enable(true); + m_stileCtrl[specno + 1]->Enable(true); + } + + //wxLogMessage(wxT("sprot changed: %d"), specno); +} + + +#endif // USE_JPWL + diff --git a/openjpeg/src/bin/wx/OPJViewer/source/OPJThreads.cpp b/openjpeg/src/bin/wx/OPJViewer/source/OPJThreads.cpp new file mode 100644 index 000000000..90a9206e1 --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/OPJThreads.cpp @@ -0,0 +1,1293 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2007, Digital Signal Processing Laboratory, Universita' degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "OPJViewer.h" + + +///////////////////////////////////////////////////////////////////// +// Encoding thread class +///////////////////////////////////////////////////////////////////// + +OPJEncoThread::OPJEncoThread(OPJCanvas *canvas) + : wxThread() +{ + m_count = 0; + m_canvas = canvas; +} + +void OPJEncoThread::WriteText(const wxString& text) +{ + wxString msg; + + // before doing any GUI calls we must ensure that this thread is the only + // one doing it! + +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif // __WXGTK__ + + msg << text; + m_canvas->WriteText(msg); + +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif // __WXGTK__ +} + +void OPJEncoThread::OnExit() +{ + wxCriticalSectionLocker locker(wxGetApp().m_enco_critsect); + + wxArrayThread& ethreads = wxGetApp().m_enco_threads; + ethreads.Remove(this); + + if (ethreads.IsEmpty()) { + // signal the main thread that there are no more threads left if it is + // waiting for us + if (wxGetApp().m_enco_waitingUntilAllDone) { + wxGetApp().m_enco_waitingUntilAllDone = false; + wxGetApp().m_enco_semAllDone.Post(); + } + } +} + +void *OPJEncoThread::Entry() +{ + wxString text; + + srand(GetId()); + //int m_countnum = rand() % 9; + //text.Printf(wxT("Deco thread 0x%lx started (priority = %u, time = %d)."), + // GetId(), GetPriority(), m_countnum); + text.Printf(wxT("Enco thread %d started"), m_canvas->m_childframe->m_winnumber); + WriteText(text); + + // set handler properties + wxJPEG2000Handler *jpeg2000handler = (wxJPEG2000Handler *) wxImage::FindHandler( + wxBITMAP_TYPE_JPEG2000); + jpeg2000handler->m_subsampling = wxGetApp().m_subsampling; + jpeg2000handler->m_origin = wxGetApp().m_origin; + jpeg2000handler->m_rates = wxGetApp().m_rates; + jpeg2000handler->m_quality = wxGetApp().m_quality; + jpeg2000handler->m_enablequality = wxGetApp().m_enablequality; + jpeg2000handler->m_multicomp = wxGetApp().m_multicomp; + jpeg2000handler->m_irreversible = wxGetApp().m_irreversible; + jpeg2000handler->m_resolutions = wxGetApp().m_resolutions; + jpeg2000handler->m_progression = wxGetApp().m_progression; + jpeg2000handler->m_cbsize = wxGetApp().m_cbsize; + jpeg2000handler->m_prsize = wxGetApp().m_prsize; + jpeg2000handler->m_tsize = wxGetApp().m_tsize; + jpeg2000handler->m_torigin = wxGetApp().m_torigin; + jpeg2000handler->m_enablesop = wxGetApp().m_enablesop; + jpeg2000handler->m_enableeph = wxGetApp().m_enableeph; + jpeg2000handler->m_enablebypass = wxGetApp().m_enablebypass; + jpeg2000handler->m_enablerestart = wxGetApp().m_enablerestart; + jpeg2000handler->m_enablereset = wxGetApp().m_enablereset; + jpeg2000handler->m_enablesegmark = wxGetApp().m_enablesegmark; + jpeg2000handler->m_enableerterm = wxGetApp().m_enableerterm; + jpeg2000handler->m_enablevsc = wxGetApp().m_enablevsc; + jpeg2000handler->m_enableidx = wxGetApp().m_enableidx; + jpeg2000handler->m_index = m_canvas->m_savename.GetPath( + wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR) + wxGetApp().m_index; + jpeg2000handler->m_enablecomm = wxGetApp().m_enablecomm; + jpeg2000handler->m_comment = wxGetApp().m_comment; + jpeg2000handler->m_enablepoc = wxGetApp().m_enablepoc; + jpeg2000handler->m_poc = wxGetApp().m_poc; + + // save the file + if (!m_canvas->m_image100.SaveFile(m_canvas->m_savename.GetFullPath(), + (wxBitmapType) wxBITMAP_TYPE_JPEG2000)) { + WriteText(wxT("Can't save image")); + return NULL; + } + + text.Printf(wxT("Enco thread %d finished"), + m_canvas->m_childframe->m_winnumber); + WriteText(text); + return NULL; +} + + +///////////////////////////////////////////////////////////////////// +// Decoding thread class +///////////////////////////////////////////////////////////////////// +OPJDecoThread::OPJDecoThread(OPJCanvas *canvas) + : wxThread() +{ + m_count = 0; + m_canvas = canvas; +} + +void OPJDecoThread::WriteText(const wxString& text) +{ + wxString msg; + + // we use a fake event and post it for inter-thread gui communication + wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, OPJFRAME_THREADLOGMSG); + event.SetInt(-1); + msg << text; + event.SetString(msg); + wxPostEvent(this->m_canvas->m_childframe->m_frame, event); + + /* + // before doing any GUI calls we must ensure that this thread is the only + // one doing it! + + #ifndef __WXGTK__ + wxMutexGuiEnter(); + #endif // __WXGTK__ + + msg << text; + m_canvas->WriteText(msg); + + #ifndef __WXGTK__ + wxMutexGuiLeave(); + #endif // __WXGTK__ + */ +} + +void OPJDecoThread::OnExit() +{ + wxCriticalSectionLocker locker(wxGetApp().m_deco_critsect); + + wxArrayThread& dthreads = wxGetApp().m_deco_threads; + dthreads.Remove(this); + + if (dthreads.IsEmpty()) { + // signal the main thread that there are no more threads left if it is + // waiting for us + if (wxGetApp().m_deco_waitingUntilAllDone) { + wxGetApp().m_deco_waitingUntilAllDone = false; + wxGetApp().m_deco_semAllDone.Post(); + } + } +} + +void *OPJDecoThread::Entry() +{ + + wxString text; + + //srand(GetId()); + //int m_countnum = rand() % 9; + //text.Printf(wxT("Deco thread 0x%lx started (priority = %u, time = %d)."), + // GetId(), GetPriority(), m_countnum); + + // we have started + text.Printf(wxT("Deco thread %d started"), m_canvas->m_childframe->m_winnumber); + WriteText(text); + + // prepare dummy wximage + wxBitmap bitmap(100, 100); + wxImage image(100, 100, true); //= bitmap.ConvertToImage(); + image.Destroy(); + + // show image full name + WriteText(m_canvas->m_fname.GetFullPath()); + + // set handler properties + wxJPEG2000Handler *jpeg2000handler = (wxJPEG2000Handler *) wxImage::FindHandler( + wxBITMAP_TYPE_JPEG2000); + jpeg2000handler->m_reducefactor = wxGetApp().m_reducefactor; + jpeg2000handler->m_qualitylayers = wxGetApp().m_qualitylayers; + jpeg2000handler->m_components = wxGetApp().m_components; + jpeg2000handler->m_framenum = wxGetApp().m_framenum; +#ifdef USE_JPWL + jpeg2000handler->m_enablejpwl = wxGetApp().m_enablejpwl; + jpeg2000handler->m_expcomps = wxGetApp().m_expcomps; + jpeg2000handler->m_maxtiles = wxGetApp().m_maxtiles; +#endif // USE_JPWL + +#ifdef USE_MXF + wxMXFHandler *mxfffhandler = (wxMXFHandler *) wxImage::FindHandler( + wxBITMAP_TYPE_MXF); + mxfffhandler->m_reducefactor = wxGetApp().m_reducefactor; + mxfffhandler->m_qualitylayers = wxGetApp().m_qualitylayers; + mxfffhandler->m_components = wxGetApp().m_components; + mxfffhandler->m_framenum = wxGetApp().m_framenum; + mxfffhandler->m_filename = m_canvas->m_fname; +#ifdef USE_JPWL + mxfffhandler->m_enablejpwl = wxGetApp().m_enablejpwl; + mxfffhandler->m_expcomps = wxGetApp().m_expcomps; + mxfffhandler->m_maxtiles = wxGetApp().m_maxtiles; +#endif // USE_JPWL +#endif // USE_MXF + + // if decoding is enabled... + if (wxGetApp().m_enabledeco) { + + // load the file + if (!image.LoadFile(m_canvas->m_fname.GetFullPath(), wxBITMAP_TYPE_ANY, 0)) { + WriteText(wxT("Can't load image!")); + return NULL; + } + + } else { + + // display a warning + if (!image.Create(300, 5, false)) { + WriteText(wxT("Can't create image!")); + return NULL; + } + + } + + // assign 100% image + m_canvas->m_image100 = wxBitmap(image); + + // signal the frame to refresh the canvas + wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, OPJFRAME_VIEWFIT); + event.SetString(wxT("Fit me")); + event.SetInt(m_canvas->m_childframe->m_winnumber); + wxPostEvent(m_canvas->m_childframe->m_frame, event); + + // find a fit-to-width zoom + /*int zooml, wzooml, hzooml; + wxSize clientsize = m_canvas->GetClientSize(); + wzooml = (int) floor(100.0 * (double) clientsize.GetWidth() / (double) (2 * OPJ_CANVAS_BORDER + image.GetWidth())); + hzooml = (int) floor(100.0 * (double) clientsize.GetHeight() / (double) (2 * OPJ_CANVAS_BORDER + image.GetHeight())); + zooml = wxMin(100, wxMin(wzooml, hzooml));*/ + + // fit to width +#ifndef __WXGTK__ + //m_canvas->m_childframe->m_frame->Rescale(zooml, m_canvas->m_childframe); +#endif // __WXGTK__ + + //m_canvas->m_image = m_canvas->m_image100; + //m_canvas->Refresh(); + //m_canvas->SetScrollbars(20, 20, (int)(0.5 + (double) image.GetWidth() / 20.0), (int)(0.5 + (double) image.GetHeight() / 20.0)); + + //text.Printf(wxT("Deco thread 0x%lx finished."), GetId()); + text.Printf(wxT("Deco thread %d finished"), + m_canvas->m_childframe->m_winnumber); + WriteText(text); + return NULL; + +} + +///////////////////////////////////////////////////////////////////// +// Parsing thread class +///////////////////////////////////////////////////////////////////// + +OPJParseThread::OPJParseThread(OPJMarkerTree *tree, wxTreeItemId parentid) + : wxThread() +{ + m_count = 0; + m_tree = tree; + m_parentid = parentid; +} + +void OPJParseThread::WriteText(const wxString& text) +{ + wxString msg; + + // we use a fake event and post it for inter-thread gui communication + wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, OPJFRAME_THREADLOGMSG); + event.SetInt(-1); + msg << text; + event.SetString(msg); + wxPostEvent(this->m_tree->m_childframe->m_frame, event); + + /* // before doing any GUI calls we must ensure that this thread is the only + // one doing it! + + #ifndef __WXGTK__ + wxMutexGuiEnter(); + #endif // __WXGTK + + msg << text; + m_tree->WriteText(msg); + + #ifndef __WXGTK__ + wxMutexGuiLeave(); + #endif // __WXGTK*/ +} + +void OPJParseThread::OnExit() +{ + wxCriticalSectionLocker locker(wxGetApp().m_parse_critsect); + + wxArrayThread& threads = wxGetApp().m_parse_threads; + threads.Remove(this); + + if (threads.IsEmpty()) { + // signal the main thread that there are no more threads left if it is + // waiting for us + if (wxGetApp().m_parse_waitingUntilAllDone) { + wxGetApp().m_parse_waitingUntilAllDone = false; + wxGetApp().m_parse_semAllDone.Post(); + } + } +} + +void *OPJParseThread::Entry() +{ + + printf("Entering\n\n"); + + wxString text; + + srand(GetId()); + int m_countnum = rand() % 9; + text.Printf(wxT("Parse thread 0x%lx started (priority = %u, time = %d)."), + GetId(), GetPriority(), m_countnum); + WriteText(text); + LoadFile(m_tree->m_fname); + text.Printf(wxT("Parse thread 0x%lx finished."), GetId()); + WriteText(text); + + + //wxLogMessage(wxT("Entering\n")); //test wxLog thread safeness + + //wxBusyCursor wait; + //wxBusyInfo wait(wxT("Decoding image ...")); + + + /*for ( m_count = 0; m_count < m_countnum; m_count++ ) + { + // check if we were asked to exit + if ( TestDestroy() ) + break; + + text.Printf(wxT("[%u] Parse thread 0x%lx here."), m_count, GetId()); + WriteText(text); + + // wxSleep() can't be called from non-GUI thread! + wxThread::Sleep(10); + }*/ + + // wxLogMessage(text); -- test wxLog thread safeness + + printf("Exiting\n\n"); + + return NULL; +} + + +/////////////////////////////////////////// +// Parsing hread and related +/////////////////////////////////////////// + +#if USE_GENERIC_TREECTRL +BEGIN_EVENT_TABLE(OPJMarkerTree, wxGenericTreeCtrl) +#else + BEGIN_EVENT_TABLE(OPJMarkerTree, wxTreeCtrl) +#endif + /*EVT_TREE_BEGIN_DRAG(TreeTest_Ctrl, OPJMarkerTree::OnBeginDrag) + EVT_TREE_BEGIN_RDRAG(TreeTest_Ctrl, OPJMarkerTree::OnBeginRDrag) + EVT_TREE_END_DRAG(TreeTest_Ctrl, OPJMarkerTree::OnEndDrag)*/ + /*EVT_TREE_BEGIN_LABEL_EDIT(TreeTest_Ctrl, OPJMarkerTree::OnBeginLabelEdit) + EVT_TREE_END_LABEL_EDIT(TreeTest_Ctrl, OPJMarkerTree::OnEndLabelEdit)*/ + /*EVT_TREE_DELETE_ITEM(TreeTest_Ctrl, OPJMarkerTree::OnDeleteItem)*/ +#if 0 // there are so many of those that logging them causes flicker + /*EVT_TREE_GET_INFO(TreeTest_Ctrl, OPJMarkerTree::OnGetInfo)*/ +#endif + /*EVT_TREE_SET_INFO(TreeTest_Ctrl, OPJMarkerTree::OnSetInfo) + EVT_TREE_ITEM_EXPANDED(TreeTest_Ctrl, OPJMarkerTree::OnItemExpanded)*/ + EVT_TREE_ITEM_EXPANDING(TreeTest_Ctrl, OPJMarkerTree::OnItemExpanding) + /*EVT_TREE_ITEM_COLLAPSED(TreeTest_Ctrl, OPJMarkerTree::OnItemCollapsed) + EVT_TREE_ITEM_COLLAPSING(TreeTest_Ctrl, OPJMarkerTree::OnItemCollapsing)*/ + + EVT_TREE_SEL_CHANGED(TreeTest_Ctrl, OPJMarkerTree::OnSelChanged) + /*EVT_TREE_SEL_CHANGING(TreeTest_Ctrl, OPJMarkerTree::OnSelChanging)*/ + /*EVT_TREE_KEY_DOWN(TreeTest_Ctrl, OPJMarkerTree::OnTreeKeyDown)*/ + /*EVT_TREE_ITEM_ACTIVATED(TreeTest_Ctrl, OPJMarkerTree::OnItemActivated)*/ + + // so many different ways to handle right mouse button clicks... + /*EVT_CONTEXT_MENU(OPJMarkerTree::OnContextMenu)*/ + // EVT_TREE_ITEM_MENU is the preferred event for creating context menus + // on a tree control, because it includes the point of the click or item, + // meaning that no additional placement calculations are required. + EVT_TREE_ITEM_MENU(TreeTest_Ctrl, OPJMarkerTree::OnItemMenu) + /*EVT_TREE_ITEM_RIGHT_CLICK(TreeTest_Ctrl, OPJMarkerTree::OnItemRClick)*/ + + /*EVT_RIGHT_DOWN(OPJMarkerTree::OnRMouseDown) + EVT_RIGHT_UP(OPJMarkerTree::OnRMouseUp) + EVT_RIGHT_DCLICK(OPJMarkerTree::OnRMouseDClick)*/ +END_EVENT_TABLE() + +// OPJMarkerTree implementation +#if USE_GENERIC_TREECTRL +IMPLEMENT_DYNAMIC_CLASS(OPJMarkerTree, wxGenericTreeCtrl) +#else +IMPLEMENT_DYNAMIC_CLASS(OPJMarkerTree, wxTreeCtrl) +#endif + +OPJMarkerTree::OPJMarkerTree(wxWindow *parent, OPJChildFrame *subframe, + wxFileName fname, wxString name, const wxWindowID id, + const wxPoint& pos, const wxSize& size, long style) + : wxTreeCtrl(parent, id, pos, size, style) +{ + m_reverseSort = false; + m_fname = fname; + + m_peektextCtrl = ((OPJFrame *)( + parent->GetParent()->GetParent()))->m_textCtrlbrowse; + CreateImageList(); + + // Add some items to the tree + //AddTestItemsToTree(5, 5); + int image = wxGetApp().ShowImages() ? OPJMarkerTree::TreeCtrlIcon_Folder : -1; + wxTreeItemId rootId = AddRoot(name, + image, image, + new OPJMarkerData(name)); + + OPJParseThread *pthread = CreateParseThread(0x00, subframe); + if (pthread->Run() != wxTHREAD_NO_ERROR) { + wxLogMessage(wxT("Can't start parse thread!")); + } else { + wxLogMessage(wxT("New parse thread started.")); + } + + m_childframe = subframe; +} + +void OPJMarkerTree::CreateImageList(int size) +{ + if (size == -1) { + SetImageList(NULL); + return; + } + if (size == 0) { + size = m_imageSize; + } else { + m_imageSize = size; + } + + // Make an image list containing small icons + wxImageList *images = new wxImageList(size, size, true); + + // should correspond to TreeCtrlIcon_xxx enum + wxBusyCursor wait; + wxIcon icons[5]; + icons[0] = wxIcon(icon1_xpm); + icons[1] = wxIcon(icon2_xpm); + icons[2] = wxIcon(icon3_xpm); + icons[3] = wxIcon(icon4_xpm); + icons[4] = wxIcon(icon5_xpm); + + int sizeOrig = icons[0].GetWidth(); + for (size_t i = 0; i < WXSIZEOF(icons); i++) { + if (size == sizeOrig) { + images->Add(icons[i]); + } else { + images->Add(wxBitmap(wxBitmap(icons[i]).ConvertToImage().Rescale(size, size))); + } + } + + AssignImageList(images); +} + +#if USE_GENERIC_TREECTRL || !defined(__WXMSW__) +void OPJMarkerTree::CreateButtonsImageList(int size) +{ + if (size == -1) { + SetButtonsImageList(NULL); + return; + } + + // Make an image list containing small icons + wxImageList *images = new wxImageList(size, size, true); + + // should correspond to TreeCtrlIcon_xxx enum + wxBusyCursor wait; + wxIcon icons[4]; + icons[0] = wxIcon(icon3_xpm); // closed + icons[1] = wxIcon(icon3_xpm); // closed, selected + icons[2] = wxIcon(icon5_xpm); // open + icons[3] = wxIcon(icon5_xpm); // open, selected + + for (size_t i = 0; i < WXSIZEOF(icons); i++) { + int sizeOrig = icons[i].GetWidth(); + if (size == sizeOrig) { + images->Add(icons[i]); + } else { + images->Add(wxBitmap(wxBitmap(icons[i]).ConvertToImage().Rescale(size, size))); + } + } + + AssignButtonsImageList(images); +#else +void OPJMarkerTree::CreateButtonsImageList(int WXUNUSED(size)) +{ +#endif +} + +void OPJParseThread::LoadFile(wxFileName fname) +{ + wxTreeItemId rootid; + + // this is the root node + int image = wxGetApp().ShowImages() ? m_tree->TreeCtrlIcon_Folder : -1; + + if (this->m_parentid) { + // leaf of a tree + rootid = m_parentid; + m_tree->SetItemText(rootid, wxT("Parsing...")); + + } else { + + // delete the existing tree hierarchy + m_tree->DeleteAllItems(); + + // new tree + rootid = m_tree->AddRoot(wxT("Parsing..."), + image, + image, + new OPJMarkerData(fname.GetFullPath()) + ); + //m_tree->SetItemFont(rootid, *wxITALIC_FONT); + m_tree->SetItemBold(rootid); + } + + // open the file + wxFile m_file(fname.GetFullPath().c_str(), wxFile::read); + + // parsing enabled? + if (wxGetApp().m_enableparse) { + + // what is the extension? + if ((fname.GetExt() == wxT("j2k")) || (fname.GetExt() == wxT("j2c"))) { + + // parse the file + ParseJ2KFile(&m_file, 0, m_file.Length(), rootid); + + } else if ((fname.GetExt() == wxT("jp2")) || (fname.GetExt() == wxT("mj2"))) { + + // parse the file + if (this->m_parentid) { + //WriteText(wxT("Only a subsection of jp2")); + OPJMarkerData *data = (OPJMarkerData *) m_tree->GetItemData(rootid); + ParseJ2KFile(&m_file, data->m_start, data->m_length, rootid); + m_tree->Expand(rootid); + + } else { + // as usual + ParseJP2File(&m_file, 0, m_file.Length(), rootid); + } + + } else { + + // unknown extension + WriteText(wxT("Unknown file format!")); + + } + + } + + // this is the root node + if (this->m_parentid) { + m_tree->SetItemText(rootid, wxT("Codestream")); + } else + //m_tree->SetItemText(rootid, wxString::Format(wxT("%s (%d B)"), fname.GetFullName(), m_file.Length())); + { + m_tree->SetItemText(rootid, fname.GetFullName()); + } + + // close the file + m_file.Close(); + + WriteText(wxT("Parsing finished!")); +} + +/*int OPJMarkerTree::OnCompareItems(const wxTreeItemId& item1, + const wxTreeItemId& item2) +{ + if ( m_reverseSort ) + { + // just exchange 1st and 2nd items + return wxTreeCtrl::OnCompareItems(item2, item1); + } + else + { + return wxTreeCtrl::OnCompareItems(item1, item2); + } +}*/ + +/*void OPJMarkerTree::AddItemsRecursively(const wxTreeItemId& idParent, + size_t numChildren, + size_t depth, + size_t folder) +{ + if ( depth > 0 ) + { + bool hasChildren = depth > 1; + + wxString str; + for ( size_t n = 0; n < numChildren; n++ ) + { + // at depth 1 elements won't have any more children + if ( hasChildren ) + str.Printf(wxT("%s child %u"), wxT("Folder"), unsigned(n + 1)); + else + str.Printf(wxT("%s child %u.%u"), wxT("File"), unsigned(folder), unsigned(n + 1)); + + // here we pass to AppendItem() normal and selected item images (we + // suppose that selected image follows the normal one in the enum) + int image, imageSel; + if ( wxGetApp().ShowImages() ) + { + image = depth == 1 ? TreeCtrlIcon_File : TreeCtrlIcon_Folder; + imageSel = image + 1; + } + else + { + image = imageSel = -1; + } + wxTreeItemId id = AppendItem(idParent, str, image, imageSel, + new OPJMarkerData(str)); + + // and now we also set the expanded one (only for the folders) + if ( hasChildren && wxGetApp().ShowImages() ) + { + SetItemImage(id, TreeCtrlIcon_FolderOpened, + wxTreeItemIcon_Expanded); + } + + // remember the last child for OnEnsureVisible() + if ( !hasChildren && n == numChildren - 1 ) + { + m_lastItem = id; + } + + AddItemsRecursively(id, numChildren, depth - 1, n + 1); + } + } + //else: done! +}*/ + +/*void OPJMarkerTree::AddTestItemsToTree(size_t numChildren, + size_t depth) +{ + int image = wxGetApp().ShowImages() ? OPJMarkerTree::TreeCtrlIcon_Folder : -1; + wxTreeItemId rootId = AddRoot(wxT("Root"), + image, image, + new OPJMarkerData(wxT("Root item"))); + if ( image != -1 ) + { + SetItemImage(rootId, TreeCtrlIcon_FolderOpened, wxTreeItemIcon_Expanded); + } + + AddItemsRecursively(rootId, numChildren, depth, 0); + + // set some colours/fonts for testing + SetItemFont(rootId, *wxITALIC_FONT); + + wxTreeItemIdValue cookie; + wxTreeItemId id = GetFirstChild(rootId, cookie); + SetItemTextColour(id, *wxBLUE); + + id = GetNextChild(rootId, cookie); + id = GetNextChild(rootId, cookie); + SetItemTextColour(id, *wxRED); + SetItemBackgroundColour(id, *wxLIGHT_GREY); +}*/ + +/*void OPJMarkerTree::GetItemsRecursively(const wxTreeItemId& idParent, + wxTreeItemIdValue cookie) +{ + wxTreeItemId id; + + if ( !cookie ) + id = GetFirstChild(idParent, cookie); + else + id = GetNextChild(idParent, cookie); + + if ( !id.IsOk() ) + return; + + wxString text = GetItemText(id); + wxLogMessage(text); + + if (ItemHasChildren(id)) + GetItemsRecursively(id); + + GetItemsRecursively(idParent, cookie); +}*/ + +/*void OPJMarkerTree::DoToggleIcon(const wxTreeItemId& item) +{ + int image = (GetItemImage(item) == TreeCtrlIcon_Folder) + ? TreeCtrlIcon_File + : TreeCtrlIcon_Folder; + SetItemImage(item, image, wxTreeItemIcon_Normal); + + image = (GetItemImage(item) == TreeCtrlIcon_FolderSelected) + ? TreeCtrlIcon_FileSelected + : TreeCtrlIcon_FolderSelected; + SetItemImage(item, image, wxTreeItemIcon_Selected); +}*/ + +void OPJMarkerTree::LogEvent(const wxChar *name, const wxTreeEvent& event) +{ + wxTreeItemId item = event.GetItem(); + wxString text; + if (item.IsOk()) { + text << wxT('"') << GetItemText(item).c_str() << wxT('"'); + } else { + text = wxT("invalid item"); + } + wxLogMessage(wxT("%s(%s)"), name, text.c_str()); +} + +OPJParseThread *OPJMarkerTree::CreateParseThread(wxTreeItemId parentid, + OPJChildFrame *subframe) +{ + OPJParseThread *pthread = new OPJParseThread(this, parentid); + + if (pthread->Create() != wxTHREAD_NO_ERROR) { + wxLogError(wxT("Can't create parse thread!")); + } + + wxCriticalSectionLocker enter(wxGetApp().m_parse_critsect); + wxGetApp().m_parse_threads.Add(pthread); + + return pthread; +} + + +/*// avoid repetition +#define TREE_EVENT_HANDLER(name) \ +void OPJMarkerTree::name(wxTreeEvent& event) \ +{ \ + LogEvent(_T(#name), event); \ + SetLastItem(wxTreeItemId()); \ + event.Skip(); \ +}*/ + +/*TREE_EVENT_HANDLER(OnBeginRDrag)*/ +/*TREE_EVENT_HANDLER(OnDeleteItem)*/ +/*TREE_EVENT_HANDLER(OnGetInfo) +TREE_EVENT_HANDLER(OnSetInfo)*/ +/*TREE_EVENT_HANDLER(OnItemExpanded) +TREE_EVENT_HANDLER(OnItemExpanding)*/ +/*TREE_EVENT_HANDLER(OnItemCollapsed)*/ +/*TREE_EVENT_HANDLER(OnSelChanged) +TREE_EVENT_HANDLER(OnSelChanging)*/ + +/*#undef TREE_EVENT_HANDLER*/ + +void OPJMarkerTree::OnItemExpanding(wxTreeEvent& event) +{ + wxTreeItemId item = event.GetItem(); + OPJMarkerData* data = (OPJMarkerData *) GetItemData(item); + wxString text; + + if (item.IsOk()) { + text << wxT('"') << GetItemText(item).c_str() << wxT('"'); + } else { + text = wxT("invalid item"); + } + + if (wxStrcmp(data->GetDesc1(), wxT("INFO-CSTREAM"))) { + return; + } + + wxLogMessage(wxT("Expanding... (%s -> %s, %s, %d, %d)"), + text.c_str(), data->GetDesc1(), data->GetDesc2(), + data->m_start, data->m_length); + + // the codestream box is being asked for expansion + wxTreeItemIdValue cookie; + if (!GetFirstChild(item, cookie).IsOk()) { + OPJParseThread *pthread = CreateParseThread(item); + if (pthread->Run() != wxTHREAD_NO_ERROR) { + wxLogMessage(wxT("Can't start parse thread!")); + } else { + wxLogMessage(wxT("New parse thread started.")); + } + } +} + +void OPJMarkerTree::OnSelChanged(wxTreeEvent& event) +{ + int bunch_linesize = 16; + int bunch_numlines = 7; + + wxTreeItemId item = event.GetItem(); + OPJMarkerData* data = (OPJMarkerData *) GetItemData(item); + wxString text; + int l, c, pos = 0, pre_pos; + + m_peektextCtrl->Clear(); + + /*text << wxString::Format(wxT("Selected... (%s -> %s, %s, %d, %d)"), + text.c_str(), data->GetDesc1(), data->GetDesc2(), + data->m_start, data->m_length) << wxT("\n");*/ + + // open the file and browse a little + wxFile *fp = new wxFile(m_fname.GetFullPath().c_str(), wxFile::read); + + // go to position claimed + fp->Seek(data->m_start, wxFromStart); + + // read a bunch + int max_read = wxMin(wxFileOffset(bunch_linesize * bunch_numlines), + data->m_length - data->m_start + 1); + if (data->m_desc == wxT("MARK (65380)")) { + /*wxLogMessage(data->m_desc);*/ + max_read = data->m_length - data->m_start + 1; + bunch_numlines = (int) ceil((float) max_read / (float) bunch_linesize); + } + unsigned char *buffer = new unsigned char[bunch_linesize * bunch_numlines]; + fp->Read(buffer, max_read); + + // write the file data between start and stop + pos = 0; + for (l = 0; l < bunch_numlines; l++) { + + text << wxString::Format(wxT("%010d:"), data->m_start + pos); + + pre_pos = pos; + + // add hex browsing text + for (c = 0; c < bunch_linesize; c++) { + + if (!(c % 8)) { + text << wxT(" "); + } + + if (pos < max_read) { + text << wxString::Format(wxT("%02X "), buffer[pos]); + } else { + text << wxT(" "); + } + pos++; + } + + text << wxT(" "); + + // add char browsing text + for (c = 0; c < bunch_linesize; c++) { + + if (pre_pos < max_read) { + if ((buffer[pre_pos] == '\n') || + (buffer[pre_pos] == '\t') || + (buffer[pre_pos] == '\0') || + (buffer[pre_pos] == 0x0D) || + (buffer[pre_pos] == 0x0B)) { + buffer[pre_pos] = ' '; + } + text << wxString::FromAscii((char) buffer[pre_pos]) << wxT("."); + } else { + text << wxT(" "); + } + pre_pos++; + } + + text << wxT("\n"); + + } + + // close the file + fp->Close(); + + m_peektextCtrl->WriteText(text); + + delete [] buffer; +} + +/*void LogKeyEvent(const wxChar *name, const wxKeyEvent& event) +{ + wxString key; + long keycode = event.GetKeyCode(); + { + switch ( keycode ) + { + case WXK_BACK: key = wxT("BACK"); break; + case WXK_TAB: key = wxT("TAB"); break; + case WXK_RETURN: key = wxT("RETURN"); break; + case WXK_ESCAPE: key = wxT("ESCAPE"); break; + case WXK_SPACE: key = wxT("SPACE"); break; + case WXK_DELETE: key = wxT("DELETE"); break; + case WXK_START: key = wxT("START"); break; + case WXK_LBUTTON: key = wxT("LBUTTON"); break; + case WXK_RBUTTON: key = wxT("RBUTTON"); break; + case WXK_CANCEL: key = wxT("CANCEL"); break; + case WXK_MBUTTON: key = wxT("MBUTTON"); break; + case WXK_CLEAR: key = wxT("CLEAR"); break; + case WXK_SHIFT: key = wxT("SHIFT"); break; + case WXK_ALT: key = wxT("ALT"); break; + case WXK_CONTROL: key = wxT("CONTROL"); break; + case WXK_MENU: key = wxT("MENU"); break; + case WXK_PAUSE: key = wxT("PAUSE"); break; + case WXK_CAPITAL: key = wxT("CAPITAL"); break; + case WXK_END: key = wxT("END"); break; + case WXK_HOME: key = wxT("HOME"); break; + case WXK_LEFT: key = wxT("LEFT"); break; + case WXK_UP: key = wxT("UP"); break; + case WXK_RIGHT: key = wxT("RIGHT"); break; + case WXK_DOWN: key = wxT("DOWN"); break; + case WXK_SELECT: key = wxT("SELECT"); break; + case WXK_PRINT: key = wxT("PRINT"); break; + case WXK_EXECUTE: key = wxT("EXECUTE"); break; + case WXK_SNAPSHOT: key = wxT("SNAPSHOT"); break; + case WXK_INSERT: key = wxT("INSERT"); break; + case WXK_HELP: key = wxT("HELP"); break; + case WXK_NUMPAD0: key = wxT("NUMPAD0"); break; + case WXK_NUMPAD1: key = wxT("NUMPAD1"); break; + case WXK_NUMPAD2: key = wxT("NUMPAD2"); break; + case WXK_NUMPAD3: key = wxT("NUMPAD3"); break; + case WXK_NUMPAD4: key = wxT("NUMPAD4"); break; + case WXK_NUMPAD5: key = wxT("NUMPAD5"); break; + case WXK_NUMPAD6: key = wxT("NUMPAD6"); break; + case WXK_NUMPAD7: key = wxT("NUMPAD7"); break; + case WXK_NUMPAD8: key = wxT("NUMPAD8"); break; + case WXK_NUMPAD9: key = wxT("NUMPAD9"); break; + case WXK_MULTIPLY: key = wxT("MULTIPLY"); break; + case WXK_ADD: key = wxT("ADD"); break; + case WXK_SEPARATOR: key = wxT("SEPARATOR"); break; + case WXK_SUBTRACT: key = wxT("SUBTRACT"); break; + case WXK_DECIMAL: key = wxT("DECIMAL"); break; + case WXK_DIVIDE: key = wxT("DIVIDE"); break; + case WXK_F1: key = wxT("F1"); break; + case WXK_F2: key = wxT("F2"); break; + case WXK_F3: key = wxT("F3"); break; + case WXK_F4: key = wxT("F4"); break; + case WXK_F5: key = wxT("F5"); break; + case WXK_F6: key = wxT("F6"); break; + case WXK_F7: key = wxT("F7"); break; + case WXK_F8: key = wxT("F8"); break; + case WXK_F9: key = wxT("F9"); break; + case WXK_F10: key = wxT("F10"); break; + case WXK_F11: key = wxT("F11"); break; + case WXK_F12: key = wxT("F12"); break; + case WXK_F13: key = wxT("F13"); break; + case WXK_F14: key = wxT("F14"); break; + case WXK_F15: key = wxT("F15"); break; + case WXK_F16: key = wxT("F16"); break; + case WXK_F17: key = wxT("F17"); break; + case WXK_F18: key = wxT("F18"); break; + case WXK_F19: key = wxT("F19"); break; + case WXK_F20: key = wxT("F20"); break; + case WXK_F21: key = wxT("F21"); break; + case WXK_F22: key = wxT("F22"); break; + case WXK_F23: key = wxT("F23"); break; + case WXK_F24: key = wxT("F24"); break; + case WXK_NUMLOCK: key = wxT("NUMLOCK"); break; + case WXK_SCROLL: key = wxT("SCROLL"); break; + case WXK_PAGEUP: key = wxT("PAGEUP"); break; + case WXK_PAGEDOWN: key = wxT("PAGEDOWN"); break; + case WXK_NUMPAD_SPACE: key = wxT("NUMPAD_SPACE"); break; + case WXK_NUMPAD_TAB: key = wxT("NUMPAD_TAB"); break; + case WXK_NUMPAD_ENTER: key = wxT("NUMPAD_ENTER"); break; + case WXK_NUMPAD_F1: key = wxT("NUMPAD_F1"); break; + case WXK_NUMPAD_F2: key = wxT("NUMPAD_F2"); break; + case WXK_NUMPAD_F3: key = wxT("NUMPAD_F3"); break; + case WXK_NUMPAD_F4: key = wxT("NUMPAD_F4"); break; + case WXK_NUMPAD_HOME: key = wxT("NUMPAD_HOME"); break; + case WXK_NUMPAD_LEFT: key = wxT("NUMPAD_LEFT"); break; + case WXK_NUMPAD_UP: key = wxT("NUMPAD_UP"); break; + case WXK_NUMPAD_RIGHT: key = wxT("NUMPAD_RIGHT"); break; + case WXK_NUMPAD_DOWN: key = wxT("NUMPAD_DOWN"); break; + case WXK_NUMPAD_PAGEUP: key = wxT("NUMPAD_PAGEUP"); break; + case WXK_NUMPAD_PAGEDOWN: key = wxT("NUMPAD_PAGEDOWN"); break; + case WXK_NUMPAD_END: key = wxT("NUMPAD_END"); break; + case WXK_NUMPAD_BEGIN: key = wxT("NUMPAD_BEGIN"); break; + case WXK_NUMPAD_INSERT: key = wxT("NUMPAD_INSERT"); break; + case WXK_NUMPAD_DELETE: key = wxT("NUMPAD_DELETE"); break; + case WXK_NUMPAD_EQUAL: key = wxT("NUMPAD_EQUAL"); break; + case WXK_NUMPAD_MULTIPLY: key = wxT("NUMPAD_MULTIPLY"); break; + case WXK_NUMPAD_ADD: key = wxT("NUMPAD_ADD"); break; + case WXK_NUMPAD_SEPARATOR: key = wxT("NUMPAD_SEPARATOR"); break; + case WXK_NUMPAD_SUBTRACT: key = wxT("NUMPAD_SUBTRACT"); break; + case WXK_NUMPAD_DECIMAL: key = wxT("NUMPAD_DECIMAL"); break; + + default: + { + if ( keycode < 128 && wxIsprint((int)keycode) ) + key.Printf(wxT("'%c'"), (char)keycode); + else if ( keycode > 0 && keycode < 27 ) + key.Printf(_("Ctrl-%c"), wxT('A') + keycode - 1); + else + key.Printf(wxT("unknown (%ld)"), keycode); + } + } + } + + wxLogMessage(wxT("%s event: %s (flags = %c%c%c%c)"), + name, + key.c_str(), + event.ControlDown() ? wxT('C') : wxT('-'), + event.AltDown() ? wxT('A') : wxT('-'), + event.ShiftDown() ? wxT('S') : wxT('-'), + event.MetaDown() ? wxT('M') : wxT('-')); +} + +void OPJMarkerTree::OnTreeKeyDown(wxTreeEvent& event) +{ + LogKeyEvent(wxT("Tree key down "), event.GetKeyEvent()); + + event.Skip(); +}*/ + +/*void OPJMarkerTree::OnBeginDrag(wxTreeEvent& event) +{ + // need to explicitly allow drag + if ( event.GetItem() != GetRootItem() ) + { + m_draggedItem = event.GetItem(); + + wxLogMessage(wxT("OnBeginDrag: started dragging %s"), + GetItemText(m_draggedItem).c_str()); + + event.Allow(); + } + else + { + wxLogMessage(wxT("OnBeginDrag: this item can't be dragged.")); + } +} + +void OPJMarkerTree::OnEndDrag(wxTreeEvent& event) +{ + wxTreeItemId itemSrc = m_draggedItem, + itemDst = event.GetItem(); + m_draggedItem = (wxTreeItemId)0l; + + // where to copy the item? + if ( itemDst.IsOk() && !ItemHasChildren(itemDst) ) + { + // copy to the parent then + itemDst = GetItemParent(itemDst); + } + + if ( !itemDst.IsOk() ) + { + wxLogMessage(wxT("OnEndDrag: can't drop here.")); + + return; + } + + wxString text = GetItemText(itemSrc); + wxLogMessage(wxT("OnEndDrag: '%s' copied to '%s'."), + text.c_str(), GetItemText(itemDst).c_str()); + + // just do append here - we could also insert it just before/after the item + // on which it was dropped, but this requires slightly more work... we also + // completely ignore the client data and icon of the old item but could + // copy them as well. + // + // Finally, we only copy one item here but we might copy the entire tree if + // we were dragging a folder. + int image = wxGetApp().ShowImages() ? TreeCtrlIcon_File : -1; + AppendItem(itemDst, text, image); +}*/ + +/*void OPJMarkerTree::OnBeginLabelEdit(wxTreeEvent& event) +{ + wxLogMessage(wxT("OnBeginLabelEdit")); + + // for testing, prevent this item's label editing + wxTreeItemId itemId = event.GetItem(); + if ( IsTestItem(itemId) ) + { + wxMessageBox(wxT("You can't edit this item.")); + + event.Veto(); + } + else if ( itemId == GetRootItem() ) + { + // test that it is possible to change the text of the item being edited + SetItemText(itemId, _T("Editing root item")); + } +} + +void OPJMarkerTree::OnEndLabelEdit(wxTreeEvent& event) +{ + wxLogMessage(wxT("OnEndLabelEdit")); + + // don't allow anything except letters in the labels + if ( !event.GetLabel().IsWord() ) + { + wxMessageBox(wxT("The new label should be a single word.")); + + event.Veto(); + } +}*/ + +/*void OPJMarkerTree::OnItemCollapsing(wxTreeEvent& event) +{ + wxLogMessage(wxT("OnItemCollapsing")); + + // for testing, prevent the user from collapsing the first child folder + wxTreeItemId itemId = event.GetItem(); + if ( IsTestItem(itemId) ) + { + wxMessageBox(wxT("You can't collapse this item.")); + + event.Veto(); + } +}*/ + +/*void OPJMarkerTree::OnItemActivated(wxTreeEvent& event) +{ + // show some info about this item + wxTreeItemId itemId = event.GetItem(); + OPJMarkerData *item = (OPJMarkerData *)GetItemData(itemId); + + if ( item != NULL ) + { + item->ShowInfo(this); + } + + wxLogMessage(wxT("OnItemActivated")); +}*/ + +void OPJMarkerTree::OnItemMenu(wxTreeEvent& event) +{ + /*wxTreeItemId itemId = event.GetItem(); + OPJMarkerData *item = itemId.IsOk() ? (OPJMarkerData *)GetItemData(itemId) + : NULL; + + wxLogMessage(wxT("OnItemMenu for item \"%s\""), item ? item->GetDesc() + : _T(""));*/ + + //wxLogMessage(wxT("EEEEEEEEEE")); + + //event.Skip(); +} + +/*void OPJMarkerTree::OnContextMenu(wxContextMenuEvent& event) +{ + wxPoint pt = event.GetPosition(); + wxTreeItemId item; + wxLogMessage(wxT("OnContextMenu at screen coords (%i, %i)"), pt.x, pt.y); + + // check if event was generated by keyboard (MSW-specific?) + if ( pt.x == -1 && pt.y == -1 ) //(this is how MSW indicates it) + { + if ( !HasFlag(wxTR_MULTIPLE) ) + item = GetSelection(); + + // attempt to guess where to show the menu + if ( item.IsOk() ) + { + // if an item was clicked, show menu to the right of it + wxRect rect; + GetBoundingRect(item, rect, true );// only the label + pt = wxPoint(rect.GetRight(), rect.GetTop()); + } + else + { + pt = wxPoint(0, 0); + } + } + else // event was generated by mouse, use supplied coords + { + pt = ScreenToClient(pt); + item = HitTest(pt); + } + + ShowMenu(item, pt); +}*/ + +/*void OPJMarkerTree::ShowMenu(wxTreeItemId id, const wxPoint& pt) +{ + wxString title; + if ( id.IsOk() ) + { + title << wxT("Menu for ") << GetItemText(id); + } + else + { + title = wxT("Menu for no particular item"); + } + +#if wxUSE_MENUS + wxMenu menu(title); + menu.Append(TreeTest_About, wxT("&About...")); + menu.AppendSeparator(); + menu.Append(TreeTest_Highlight, wxT("&Highlight item")); + menu.Append(TreeTest_Dump, wxT("&Dump")); + + PopupMenu(&menu, pt); +#endif // wxUSE_MENUS +}*/ + +/*void OPJMarkerTree::OnItemRClick(wxTreeEvent& event) +{ + wxTreeItemId itemId = event.GetItem(); + OPJMarkerData *item = itemId.IsOk() ? (OPJMarkerData *)GetItemData(itemId) + : NULL; + + wxLogMessage(wxT("Item \"%s\" right clicked"), item ? item->GetDesc() + : _T("")); + + event.Skip(); +}*/ + +/* +void OPJMarkerTree::OnRMouseDown(wxMouseEvent& event) +{ + wxLogMessage(wxT("Right mouse button down")); + + event.Skip(); +} + +void OPJMarkerTree::OnRMouseUp(wxMouseEvent& event) +{ + wxLogMessage(wxT("Right mouse button up")); + + event.Skip(); +} + +void OPJMarkerTree::OnRMouseDClick(wxMouseEvent& event) +{ + wxTreeItemId id = HitTest(event.GetPosition()); + if ( !id ) + wxLogMessage(wxT("No item under mouse")); + else + { + OPJMarkerData *item = (OPJMarkerData *)GetItemData(id); + if ( item ) + wxLogMessage(wxT("Item '%s' under mouse"), item->GetDesc()); + } + + event.Skip(); +} +*/ + +static inline const wxChar *Bool2String(bool b) +{ + return b ? wxT("") : wxT("not "); +} + +void OPJMarkerData::ShowInfo(wxTreeCtrl *tree) +{ + wxLogMessage(wxT("Item '%s': %sselected, %sexpanded, %sbold,\n") + wxT("%u children (%u immediately under this item)."), + m_desc.c_str(), + Bool2String(tree->IsSelected(GetId())), + Bool2String(tree->IsExpanded(GetId())), + Bool2String(tree->IsBold(GetId())), + unsigned(tree->GetChildrenCount(GetId())), + unsigned(tree->GetChildrenCount(GetId(), false))); +} diff --git a/openjpeg/src/bin/wx/OPJViewer/source/OPJViewer.cpp b/openjpeg/src/bin/wx/OPJViewer/source/OPJViewer.cpp new file mode 100644 index 000000000..bb1ea05da --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/OPJViewer.cpp @@ -0,0 +1,1671 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2007, Digital Signal Processing Laboratory, Universita' degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +///////////////////////////////////////////////////////////////////////////// +// Name: sashtest.cpp +// Purpose: Layout/sash sample +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: sashtest.cpp,v 1.18 2005/08/23 15:54:35 ABX Exp $ +// Copyright: (c) Julian Smart +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: treetest.cpp +// Purpose: wxTreeCtrl sample +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: treetest.cpp,v 1.110 2006/11/04 11:26:51 VZ Exp $ +// Copyright: (c) Julian Smart +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: dialogs.cpp +// Purpose: Common dialogs demo +// Author: Julian Smart +// Modified by: ABX (2004) - adjustements for conditional building + new menu +// Created: 04/01/98 +// RCS-ID: $Id: dialogs.cpp,v 1.163 2006/11/04 10:57:24 VZ Exp $ +// Copyright: (c) Julian Smart +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: thread.cpp +// Purpose: wxWidgets thread sample +// Author: Guilhem Lavaux, Vadim Zeitlin +// Modified by: +// Created: 06/16/98 +// RCS-ID: $Id: thread.cpp,v 1.26 2006/10/02 05:36:28 PC Exp $ +// Copyright: (c) 1998-2002 wxWidgets team +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Name: samples/image/image.cpp +// Purpose: sample showing operations with wxImage +// Author: Robert Roebling +// Modified by: +// Created: 1998 +// RCS-ID: $Id: image.cpp,v 1.120 2006/12/06 17:13:11 VZ Exp $ +// Copyright: (c) 1998-2005 Robert Roebling +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: samples/console/console.cpp +// Purpose: A sample console (as opposed to GUI) program using wxWidgets +// Author: Vadim Zeitlin +// Modified by: +// Created: 04.10.99 +// RCS-ID: $Id: console.cpp,v 1.206 2006/11/12 19:55:19 VZ Exp $ +// Copyright: (c) 1999 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: samples/notebook/notebook.cpp +// Purpose: a sample demonstrating notebook usage +// Author: Julian Smart +// Modified by: Dimitri Schoolwerth +// Created: 26/10/98 +// RCS-ID: $Id: notebook.cpp,v 1.49 2006/11/04 18:24:07 RR Exp $ +// Copyright: (c) 1998-2002 wxWidgets team +// License: wxWindows license +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: dialogs.cpp +// Purpose: Common dialogs demo +// Author: Julian Smart +// Modified by: ABX (2004) - adjustements for conditional building + new menu +// Created: 04/01/98 +// RCS-ID: $Id: dialogs.cpp,v 1.163 2006/11/04 10:57:24 VZ Exp $ +// Copyright: (c) Julian Smart +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: dnd.cpp +// Purpose: Drag and drop sample +// Author: Vadim Zeitlin +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: dnd.cpp,v 1.107 2006/10/30 20:23:41 VZ Exp $ +// Copyright: +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: test.cpp +// Purpose: wxHtml testing example +///////////////////////////////////////////////////////////////////////////// + + +#include "OPJViewer.h" + +IMPLEMENT_APP(OPJViewerApp) + +// For drawing lines in a canvas +long xpos = -1; +long ypos = -1; + +int winNumber = 1; + +// Initialise this in OnInit, not statically +bool OPJViewerApp::OnInit(void) +{ + int n; +#if wxUSE_UNICODE + + wxChar **wxArgv = new wxChar *[argc + 1]; + + for (n = 0; n < argc; n++ ) { + wxMB2WXbuf warg = wxConvertMB2WX((char *) argv[n]); + wxArgv[n] = wxStrdup(warg); + } + + wxArgv[n] = NULL; + +#else // !wxUSE_UNICODE + + #define wxArgv argv + +#endif // wxUSE_UNICODE/!wxUSE_UNICODE + +#if wxUSE_CMDLINE_PARSER + + static const wxCmdLineEntryDesc cmdLineDesc[] = + { + { wxCMD_LINE_SWITCH, _T("h"), _T("help"), _T("show this help message"), + wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP }, + + { wxCMD_LINE_PARAM, NULL, NULL, _T("input file"), + wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE }, + + { wxCMD_LINE_NONE } + }; + + wxCmdLineParser parser(cmdLineDesc, argc, wxArgv); + + switch (parser.Parse()) { + case -1: + wxLogMessage(wxT("Help was given, terminating.")); + break; + + case 0: + ShowCmdLine(parser); + break; + + default: + wxLogMessage(wxT("Syntax error detected.")); + break; + } + +#endif // wxUSE_CMDLINE_PARSER + + //wxInitAllImageHandlers(); +#if wxUSE_LIBJPEG + wxImage::AddHandler( new wxJPEGHandler ); +#endif +#if wxUSE_LIBOPENJPEG + wxImage::AddHandler( new wxJPEG2000Handler ); +#endif +#if USE_MXF + wxImage::AddHandler( new wxMXFHandler ); +#endif // USE_MXF +#if OPJ_MANYFORMATS + wxImage::AddHandler( new wxBMPHandler ); + wxImage::AddHandler( new wxPNGHandler ); + wxImage::AddHandler( new wxGIFHandler ); + wxImage::AddHandler( new wxPNMHandler ); + wxImage::AddHandler( new wxTIFFHandler ); +#endif + // we use a XPM image in our HTML page + wxImage::AddHandler(new wxXPMHandler); + + // memory file system + wxFileSystem::AddHandler(new wxMemoryFSHandler); + +#ifdef OPJ_INICONFIG + //load decoding engine parameters + OPJconfig = new wxConfig(OPJ_APPLICATION, OPJ_APPLICATION_VENDOR); + + OPJconfig->Read(wxT("decode/enabledeco"), &m_enabledeco, (bool) true); + OPJconfig->Read(wxT("decode/enableparse"), &m_enableparse, (bool) true); + OPJconfig->Read(wxT("decode/resizemethod"), &m_resizemethod, (long) 0); + OPJconfig->Read(wxT("decode/xxxreducefactor"), &m_reducefactor, (long) 0); + OPJconfig->Read(wxT("decode/xxxqualitylayers"), &m_qualitylayers, (long) 0); + OPJconfig->Read(wxT("decode/xxxcomponents"), &m_components, (long) 0); + OPJconfig->Read(wxT("decode/xxxframenum"), &m_framenum, (long) 0); +#ifdef USE_JPWL + OPJconfig->Read(wxT("decode/enablejpwl"), &m_enablejpwl, (bool) true); + OPJconfig->Read(wxT("decode/expcomps"), &m_expcomps, (long) JPWL_EXPECTED_COMPONENTS); + OPJconfig->Read(wxT("decode/maxtiles"), &m_maxtiles, (long) JPWL_MAXIMUM_TILES); +#endif // USE_JPWL + + OPJconfig->Write(wxT("teststring"), wxT("This is a test value")); + OPJconfig->Write(wxT("testbool"), (bool) true); + OPJconfig->Write(wxT("testlong"), (long) 245); + + OPJconfig->Read(wxT("showtoolbar"), &m_showtoolbar, (bool) true); + OPJconfig->Read(wxT("showbrowser"), &m_showbrowser, (bool) true); + OPJconfig->Read(wxT("showpeeker"), &m_showpeeker, (bool) true); + OPJconfig->Read(wxT("browserwidth"), &m_browserwidth, (long) OPJ_BROWSER_WIDTH); + OPJconfig->Read(wxT("peekerheight"), &m_peekerheight, (long) OPJ_PEEKER_HEIGHT); + OPJconfig->Read(wxT("framewidth"), &m_framewidth, (long) OPJ_FRAME_WIDTH); + OPJconfig->Read(wxT("frameheight"), &m_frameheight, (long) OPJ_FRAME_HEIGHT); + + // load encoding engine parameters + OPJconfig->Read(wxT("encode/subsampling"), &m_subsampling, (wxString) wxT("1,1")); + OPJconfig->Read(wxT("encode/origin"), &m_origin, (wxString) wxT("0,0")); + OPJconfig->Read(wxT("encode/rates"), &m_rates, (wxString) wxT("20,10,5")); + OPJconfig->Read(wxT("encode/quality"), &m_quality, (wxString) wxT("30,35,40")); + OPJconfig->Read(wxT("encode/enablequality"), &m_enablequality, (bool) false); + OPJconfig->Read(wxT("encode/multicomp"), &m_multicomp, (bool) false); + OPJconfig->Read(wxT("encode/irreversible"), &m_irreversible, (bool) false); + OPJconfig->Read(wxT("encode/resolutions"), &m_resolutions, (int) 6); + OPJconfig->Read(wxT("encode/progression"), &m_progression, (int) 0); + OPJconfig->Read(wxT("encode/cbsize"), &m_cbsize, (wxString) wxT("32,32")); + OPJconfig->Read(wxT("encode/prsize"), &m_prsize, (wxString) wxT("[128,128],[128,128]")); + OPJconfig->Read(wxT("encode/tsize"), &m_tsize, (wxString) wxT("")); + OPJconfig->Read(wxT("encode/torigin"), &m_torigin, (wxString) wxT("0,0")); + OPJconfig->Read(wxT("encode/enablesop"), &m_enablesop, (bool) false); + OPJconfig->Read(wxT("encode/enableeph"), &m_enableeph, (bool) false); + OPJconfig->Read(wxT("encode/enablebypass"), &m_enablebypass, (bool) false); + OPJconfig->Read(wxT("encode/enablereset"), &m_enablereset, (bool) false); + OPJconfig->Read(wxT("encode/enablerestart"), &m_enablerestart, (bool) false); + OPJconfig->Read(wxT("encode/enablevsc"), &m_enablevsc, (bool) false); + OPJconfig->Read(wxT("encode/enableerterm"), &m_enableerterm, (bool) false); + OPJconfig->Read(wxT("encode/enablesegmark"), &m_enablesegmark, (bool) false); + OPJconfig->Read(wxT("encode/enablecomm"), &m_enablecomm, (bool) true); + OPJconfig->Read(wxT("encode/enablepoc"), &m_enablepoc, (bool) false); + OPJconfig->Read(wxT("encode/comment"), &m_comment, (wxString) wxT("")); + OPJconfig->Read(wxT("encode/poc"), &m_poc, (wxString) wxT("T1=0,0,1,5,3,CPRL/T1=5,0,1,6,3,CPRL")); + OPJconfig->Read(wxT("encode/enableidx"), &m_enableidx, (bool) false); + OPJconfig->Read(wxT("encode/index"), &m_index, (wxString) wxT("index.txt")); +#ifdef USE_JPWL + OPJconfig->Read(wxT("encode/enablejpwl"), &m_enablejpwle, (bool) true); + for (n = 0; n < MYJPWL_MAX_NO_TILESPECS; n++) { + OPJconfig->Read(wxT("encode/jpwl/hprotsel") + wxString::Format(wxT("%02d"), n), &m_hprotsel[n], 0); + OPJconfig->Read(wxT("encode/jpwl/htileval") + wxString::Format(wxT("%02d"), n), &m_htileval[n], 0); + OPJconfig->Read(wxT("encode/jpwl/pprotsel") + wxString::Format(wxT("%02d"), n), &m_pprotsel[n], 0); + OPJconfig->Read(wxT("encode/jpwl/ptileval") + wxString::Format(wxT("%02d"), n), &m_ptileval[n], 0); + OPJconfig->Read(wxT("encode/jpwl/ppackval") + wxString::Format(wxT("%02d"), n), &m_ppackval[n], 0); + OPJconfig->Read(wxT("encode/jpwl/sensisel") + wxString::Format(wxT("%02d"), n), &m_sensisel[n], 0); + OPJconfig->Read(wxT("encode/jpwl/stileval") + wxString::Format(wxT("%02d"), n), &m_stileval[n], 0); + } +#endif // USE_JPWL + +#else + // set decoding engine parameters + m_enabledeco = true; + m_enableparse = true; + m_resizemethod = 0; + m_reducefactor = 0; + m_qualitylayers = 0; + m_components = 0; + m_framenum = 0; +#ifdef USE_JPWL + m_enablejpwl = true; + m_expcomps = JPWL_EXPECTED_COMPONENTS; + m_maxtiles = JPWL_MAXIMUM_TILES; +#endif // USE_JPWL + m_showtoolbar = true; + m_showbrowser = true; + m_showpeeker = true; + m_browserwidth = OPJ_BROWSER_WIDTH; + m_peekerheight = OPJ_PEEKER_HEIGHT; + m_framewidth = OPJ_FRAME_WIDTH; + m_frameheight = OPJ_FRAME_HEIGHT; + + // set encoding engine parameters + m_subsampling = wxT("1,1"); + m_origin = wxT("0,0"); + m_rates = wxT("20,10,5"); + m_quality = wxT("30,35,40"); + m_enablequality = false; + m_multicomp = false; + m_irreversible = false; + m_resolutions = 6; + m_progression = 0; + m_cbsize= wxT("32,32"); + m_prsize= wxT("[128,128],[128,128]"); + m_tsize = wxT(""); + m_torigin = wxT("0,0"); + m_enablesop = false; + m_enableeph = false; + m_enablebypass = false; + m_enablereset = false; + m_enablerestart = false; + m_enablevsc = false; + m_enableerterm = false; + m_enablesegmark = false; + m_enableidx = false; + m_index = wxT("index.txt"); + m_enablecomm = true; + m_comment = wxT(""); + m_enablepoc = false; + m_poc = wxT("T1=0,0,1,5,3,CPRL/T1=5,0,1,6,3,CPRL"); +#ifdef USE_JPWL + m_enablejpwle = true; + for (n = 0; n < MYJPWL_MAX_NO_TILESPECS; n++) { + m_hprotsel[n] = 0; + m_htileval[n] = 0; + m_pprotsel[n] = 0; + m_ptileval[n] = 0; + m_sensisel[n] = 0; + m_stileval[n] = 0; + } +#endif // USE_JPWL + +#endif // OPJ_INICONFIG + + if (m_comment == wxT("")) { +#if defined __WXMSW__ + m_comment = wxT("Created by OPJViewer Win32 - OpenJPEG version "); +#elif defined __WXGTK__ + m_comment = wxT("Created by OPJViewer Lin32 - OpenJPEG version "); +#else + m_comment = wxT("Created by OPJViewer - OpenJPEG version "); +#endif + +#ifdef USE_JPWL + m_comment += wxString::Format(wxT("%s with JPWL"), (char *) opj_version()); +#else + m_comment += wxString::Format(wxT("%s"), (char *) opj_version()); +#endif + } + + // Create the main frame window + OPJFrame *frame = new OPJFrame(NULL, wxID_ANY, OPJ_APPLICATION_TITLEBAR, + wxDefaultPosition, wxSize(wxGetApp().m_framewidth, wxGetApp().m_frameheight), + wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE | + wxHSCROLL | wxVSCROLL); + + // Give it an icon (this is ignored in MDI mode: uses resources) +#ifdef __WXMSW__ + frame->SetIcon(wxIcon(wxT("OPJViewer16"))); +#endif + + frame->Show(true); + + SetTopWindow(frame); + + // if there are files on the command line, open them + if (!(m_filelist.IsEmpty())) { + //wxLogMessage(wxT("Habemus files!!!")); + wxArrayString paths, filenames; + for (unsigned int f = 0; f < wxGetApp().m_filelist.GetCount(); f++) { + paths.Add(wxFileName(wxGetApp().m_filelist[f]).GetFullPath()); + filenames.Add(wxFileName(wxGetApp().m_filelist[f]).GetFullName()); + } + //wxLogMessage(paths[0]); + frame->OpenFiles(paths, filenames); + } + + return true; +} + +int OPJViewerApp::OnExit() +{ + int n; + +#ifdef OPJ_INICONFIG + OPJconfig->Write(wxT("decode/enabledeco"), m_enabledeco); + OPJconfig->Write(wxT("decode/enableparse"), m_enableparse); + OPJconfig->Write(wxT("decode/resizemethod"), m_resizemethod); + OPJconfig->Write(wxT("decode/reducefactor"), m_reducefactor); + OPJconfig->Write(wxT("decode/qualitylayers"), m_qualitylayers); + OPJconfig->Write(wxT("decode/components"), m_components); + OPJconfig->Write(wxT("decode/framenum"), m_framenum); +#ifdef USE_JPWL + OPJconfig->Write(wxT("decode/enablejpwl"), m_enablejpwl); + OPJconfig->Write(wxT("decode/expcomps"), m_expcomps); + OPJconfig->Write(wxT("decode/maxtiles"), m_maxtiles); +#endif // USE_JPWL + OPJconfig->Write(wxT("showtoolbar"), m_showtoolbar); + OPJconfig->Write(wxT("showbrowser"), m_showbrowser); + OPJconfig->Write(wxT("showpeeker"), m_showpeeker); + OPJconfig->Write(wxT("browserwidth"), m_browserwidth); + OPJconfig->Write(wxT("peekerheight"), m_peekerheight); + OPJconfig->Write(wxT("framewidth"), m_framewidth); + OPJconfig->Write(wxT("frameheight"), m_frameheight); + + OPJconfig->Write(wxT("encode/subsampling"), m_subsampling); + OPJconfig->Write(wxT("encode/origin"), m_origin); + OPJconfig->Write(wxT("encode/rates"), m_rates); + OPJconfig->Write(wxT("encode/quality"), m_quality); + OPJconfig->Write(wxT("encode/enablequality"), m_enablequality); + OPJconfig->Write(wxT("encode/multicomp"), m_multicomp); + OPJconfig->Write(wxT("encode/irreversible"), m_irreversible); + OPJconfig->Write(wxT("encode/resolutions"), m_resolutions); + OPJconfig->Write(wxT("encode/progression"), m_progression); + OPJconfig->Write(wxT("encode/cbsize"), m_cbsize); + OPJconfig->Write(wxT("encode/prsize"), m_prsize); + OPJconfig->Write(wxT("encode/tiles"), m_tsize); + OPJconfig->Write(wxT("encode/torigin"), m_torigin); + OPJconfig->Write(wxT("encode/enablesop"), m_enablesop); + OPJconfig->Write(wxT("encode/enableeph"), m_enableeph); + OPJconfig->Write(wxT("encode/enablebypass"), m_enablebypass); + OPJconfig->Write(wxT("encode/enablereset"), m_enablereset); + OPJconfig->Write(wxT("encode/enablerestart"), m_enablerestart); + OPJconfig->Write(wxT("encode/enablevsc"), m_enablevsc); + OPJconfig->Write(wxT("encode/enableerterm"), m_enableerterm); + OPJconfig->Write(wxT("encode/enablesegmark"), m_enablesegmark); + OPJconfig->Write(wxT("encode/enableidx"), m_enableidx); + OPJconfig->Write(wxT("encode/index"), m_index); + OPJconfig->Write(wxT("encode/enablecomm"), m_enablecomm); + OPJconfig->Write(wxT("encode/comment"), m_comment); + OPJconfig->Write(wxT("encode/enablepoc"), m_enablepoc); + OPJconfig->Write(wxT("encode/poc"), m_poc); +#ifdef USE_JPWL + OPJconfig->Write(wxT("encode/enablejpwl"), m_enablejpwle); + for (n = 0; n < MYJPWL_MAX_NO_TILESPECS; n++) { + OPJconfig->Write(wxT("encode/jpwl/hprotsel") + wxString::Format(wxT("%02d"), n), m_hprotsel[n]); + OPJconfig->Write(wxT("encode/jpwl/htileval") + wxString::Format(wxT("%02d"), n), m_htileval[n]); + OPJconfig->Write(wxT("encode/jpwl/pprotsel") + wxString::Format(wxT("%02d"), n), m_pprotsel[n]); + OPJconfig->Write(wxT("encode/jpwl/ptileval") + wxString::Format(wxT("%02d"), n), m_ptileval[n]); + OPJconfig->Write(wxT("encode/jpwl/ppackval") + wxString::Format(wxT("%02d"), n), m_ppackval[n]); + OPJconfig->Write(wxT("encode/jpwl/sensisel") + wxString::Format(wxT("%02d"), n), m_sensisel[n]); + OPJconfig->Write(wxT("encode/jpwl/stileval") + wxString::Format(wxT("%02d"), n), m_stileval[n]); + } +#endif // USE_JPWL + +#endif // OPJ_INICONFIG + + return 1; +} + +void OPJViewerApp::ShowCmdLine(const wxCmdLineParser& parser) +{ + wxString s = wxT("Command line parsed successfully:\nInput files: "); + + size_t count = parser.GetParamCount(); + for (size_t param = 0; param < count; param++) { + s << parser.GetParam(param) << ';'; + m_filelist.Add(parser.GetParam(param)); + } + + //wxLogMessage(s); +} + +// OPJFrame events + +// Event class for sending text messages between worker and GUI threads +BEGIN_EVENT_TABLE(OPJFrame, wxMDIParentFrame) + EVT_MENU(OPJFRAME_HELPABOUT, OPJFrame::OnAbout) + EVT_MENU(OPJFRAME_FILEOPEN, OPJFrame::OnFileOpen) + EVT_MENU(OPJFRAME_FILESAVEAS, OPJFrame::OnFileSaveAs) + EVT_MENU(OPJFRAME_MEMORYOPEN, OPJFrame::OnMemoryOpen) + EVT_SIZE(OPJFrame::OnSize) + EVT_MENU(OPJFRAME_FILEEXIT, OPJFrame::OnQuit) + EVT_MENU(OPJFRAME_FILECLOSE, OPJFrame::OnClose) + EVT_MENU(OPJFRAME_VIEWZOOM, OPJFrame::OnZoom) + EVT_MENU(OPJFRAME_VIEWFIT, OPJFrame::OnFit) + EVT_MENU(OPJFRAME_VIEWRELOAD, OPJFrame::OnReload) + EVT_MENU(OPJFRAME_VIEWPREVFRAME, OPJFrame::OnPrevFrame) + EVT_MENU(OPJFRAME_VIEWHOMEFRAME, OPJFrame::OnHomeFrame) + EVT_MENU(OPJFRAME_VIEWNEXTFRAME, OPJFrame::OnNextFrame) + EVT_MENU(OPJFRAME_VIEWLESSLAYERS, OPJFrame::OnLessLayers) + EVT_MENU(OPJFRAME_VIEWALLLAYERS, OPJFrame::OnAllLayers) + EVT_MENU(OPJFRAME_VIEWMORELAYERS, OPJFrame::OnMoreLayers) + EVT_MENU(OPJFRAME_VIEWLESSRES, OPJFrame::OnLessRes) + EVT_MENU(OPJFRAME_VIEWFULLRES, OPJFrame::OnFullRes) + EVT_MENU(OPJFRAME_VIEWMORERES, OPJFrame::OnMoreRes) + EVT_MENU(OPJFRAME_VIEWPREVCOMP, OPJFrame::OnPrevComp) + EVT_MENU(OPJFRAME_VIEWALLCOMPS, OPJFrame::OnAllComps) + EVT_MENU(OPJFRAME_VIEWNEXTCOMP, OPJFrame::OnNextComp) + EVT_MENU(OPJFRAME_FILETOGGLEB, OPJFrame::OnToggleBrowser) + EVT_MENU(OPJFRAME_FILETOGGLEP, OPJFrame::OnTogglePeeker) + EVT_MENU(OPJFRAME_FILETOGGLET, OPJFrame::OnToggleToolbar) + EVT_MENU(OPJFRAME_SETSENCO, OPJFrame::OnSetsEnco) + EVT_MENU(OPJFRAME_SETSDECO, OPJFrame::OnSetsDeco) + EVT_SASH_DRAGGED_RANGE(OPJFRAME_BROWSEWIN, OPJFRAME_LOGWIN, OPJFrame::OnSashDrag) + EVT_NOTEBOOK_PAGE_CHANGED(LEFT_NOTEBOOK_ID, OPJFrame::OnNotebook) + EVT_MENU(OPJFRAME_THREADLOGMSG, OPJFrame::OnThreadLogmsg) +END_EVENT_TABLE() + +// this is the frame constructor +OPJFrame::OPJFrame(wxWindow *parent, const wxWindowID id, const wxString& title, + const wxPoint& pos, const wxSize& size, const long style) + : wxMDIParentFrame(parent, id, title, pos, size, style) +{ + // file menu and its items + wxMenu *file_menu = new wxMenu; + + file_menu->Append(OPJFRAME_FILEOPEN, wxT("&Open\tCtrl+O")); + file_menu->SetHelpString(OPJFRAME_FILEOPEN, wxT("Open one or more files")); + + file_menu->Append(OPJFRAME_MEMORYOPEN, wxT("&Memory\tCtrl+M")); + file_menu->SetHelpString(OPJFRAME_MEMORYOPEN, wxT("Open a memory buffer")); + + file_menu->Append(OPJFRAME_FILECLOSE, wxT("&Close\tCtrl+C")); + file_menu->SetHelpString(OPJFRAME_FILECLOSE, wxT("Close current image")); + + file_menu->AppendSeparator(); + + file_menu->Append(OPJFRAME_FILESAVEAS, wxT("&Save as\tCtrl+S")); + file_menu->SetHelpString(OPJFRAME_FILESAVEAS, wxT("Save the current image")); + //file_menu->Enable(OPJFRAME_FILESAVEAS, false); + + file_menu->AppendSeparator(); + + file_menu->Append(OPJFRAME_FILETOGGLEB, wxT("Toggle &browser\tCtrl+B")); + file_menu->SetHelpString(OPJFRAME_FILETOGGLEB, wxT("Toggle the left browsing pane")); + + file_menu->Append(OPJFRAME_FILETOGGLEP, wxT("Toggle &peeker\tCtrl+P")); + file_menu->SetHelpString(OPJFRAME_FILETOGGLEP, wxT("Toggle the bottom peeking pane")); + + file_menu->Append(OPJFRAME_FILETOGGLET, wxT("Toggle &toolbar\tCtrl+T")); + file_menu->SetHelpString(OPJFRAME_FILETOGGLET, wxT("Toggle the toolbar")); + + file_menu->AppendSeparator(); + + file_menu->Append(OPJFRAME_FILEEXIT, wxT("&Exit\tCtrl+Q")); + file_menu->SetHelpString(OPJFRAME_FILEEXIT, wxT("Quit this program")); + + // view menu and its items + wxMenu *view_menu = new wxMenu; + + view_menu->Append(OPJFRAME_VIEWZOOM, wxT("&Zoom\tCtrl+Z")); + view_menu->SetHelpString(OPJFRAME_VIEWZOOM, wxT("Rescale the image")); + + view_menu->Append(OPJFRAME_VIEWFIT, wxT("Zoom to &fit\tCtrl+F")); + view_menu->SetHelpString(OPJFRAME_VIEWFIT, wxT("Fit the image in canvas")); + + view_menu->Append(OPJFRAME_VIEWRELOAD, wxT("&Reload image\tCtrl+R")); + view_menu->SetHelpString(OPJFRAME_VIEWRELOAD, wxT("Reload the current image")); + + view_menu->AppendSeparator(); + + view_menu->Append(OPJFRAME_VIEWPREVFRAME, wxT("&Prev frame\tLeft")); + view_menu->SetHelpString(OPJFRAME_VIEWPREVFRAME, wxT("View previous frame")); + + view_menu->Append(OPJFRAME_VIEWHOMEFRAME, wxT("&Start frame\tHome")); + view_menu->SetHelpString(OPJFRAME_VIEWHOMEFRAME, wxT("View starting frame")); + + view_menu->Append(OPJFRAME_VIEWNEXTFRAME, wxT("&Next frame\tRight")); + view_menu->SetHelpString(OPJFRAME_VIEWNEXTFRAME, wxT("View next frame")); + + view_menu->AppendSeparator(); + + view_menu->Append(OPJFRAME_VIEWLESSLAYERS, wxT("&Less layers\t-")); + view_menu->SetHelpString(OPJFRAME_VIEWLESSLAYERS, wxT("Remove a layer")); + + view_menu->Append(OPJFRAME_VIEWALLLAYERS, wxT("&All layers\t0")); + view_menu->SetHelpString(OPJFRAME_VIEWALLLAYERS, wxT("Show all layers")); + + view_menu->Append(OPJFRAME_VIEWMORELAYERS, wxT("&More layers\t+")); + view_menu->SetHelpString(OPJFRAME_VIEWMORELAYERS, wxT("Add a layer")); + + view_menu->AppendSeparator(); + + view_menu->Append(OPJFRAME_VIEWLESSRES, wxT("&Less resolution\t<")); + view_menu->SetHelpString(OPJFRAME_VIEWLESSRES, wxT("Reduce the resolution")); + + view_menu->Append(OPJFRAME_VIEWFULLRES, wxT("&Full resolution\tf")); + view_menu->SetHelpString(OPJFRAME_VIEWFULLRES, wxT("Full resolution")); + + view_menu->Append(OPJFRAME_VIEWMORERES, wxT("&More resolution\t>")); + view_menu->SetHelpString(OPJFRAME_VIEWMORERES, wxT("Increase the resolution")); + + view_menu->AppendSeparator(); + + view_menu->Append(OPJFRAME_VIEWPREVCOMP, wxT("&Prev component\tDown")); + view_menu->SetHelpString(OPJFRAME_VIEWPREVCOMP, wxT("View previous component")); + + view_menu->Append(OPJFRAME_VIEWALLCOMPS, wxT("&All components\ta")); + view_menu->SetHelpString(OPJFRAME_VIEWALLCOMPS, wxT("View all components")); + + view_menu->Append(OPJFRAME_VIEWNEXTCOMP, wxT("&Next component\tUp")); + view_menu->SetHelpString(OPJFRAME_VIEWNEXTCOMP, wxT("View next component")); + + + // settings menu and its items + wxMenu *sets_menu = new wxMenu; + + sets_menu->Append(OPJFRAME_SETSENCO, wxT("&Encoder\tCtrl+E")); + sets_menu->SetHelpString(OPJFRAME_SETSENCO, wxT("Encoder settings")); + + sets_menu->Append(OPJFRAME_SETSDECO, wxT("&Decoder\tCtrl+D")); + sets_menu->SetHelpString(OPJFRAME_SETSDECO, wxT("Decoder settings")); + + // help menu and its items + wxMenu *help_menu = new wxMenu; + + help_menu->Append(OPJFRAME_HELPABOUT, wxT("&About\tF1")); + help_menu->SetHelpString(OPJFRAME_HELPABOUT, wxT("Basic info on the program")); + + // the whole menubar + wxMenuBar *menu_bar = new wxMenuBar; + menu_bar->Append(file_menu, wxT("&File")); + menu_bar->Append(view_menu, wxT("&View")); + menu_bar->Append(sets_menu, wxT("&Settings")); + menu_bar->Append(help_menu, wxT("&Help")); + + // Associate the menu bar with the frame + SetMenuBar(menu_bar); + + // the status bar + CreateStatusBar(); + + // the toolbar + tool_bar = new wxToolBar(this, OPJFRAME_TOOLBAR, + wxDefaultPosition, wxDefaultSize, + wxTB_HORIZONTAL | wxNO_BORDER); + wxBitmap bmpOpen = wxArtProvider::GetBitmap(wxART_FILE_OPEN, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpSaveAs = wxArtProvider::GetBitmap(wxART_FILE_SAVE_AS, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpZoom = wxArtProvider::GetBitmap(wxART_FIND, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpFit = wxArtProvider::GetBitmap(wxART_FIND_AND_REPLACE, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpReload = wxArtProvider::GetBitmap(wxART_EXECUTABLE_FILE, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpDecosettings = wxArtProvider::GetBitmap(wxART_REPORT_VIEW, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpEncosettings = wxArtProvider::GetBitmap(wxART_LIST_VIEW, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpPrevframe = wxArtProvider::GetBitmap(wxART_GO_BACK, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpHomeframe = wxArtProvider::GetBitmap(wxART_GO_HOME, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpNextframe = wxArtProvider::GetBitmap(wxART_GO_FORWARD, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpLesslayers = bmpPrevframe; + wxBitmap bmpAlllayers = wxArtProvider::GetBitmap(wxART_GO_TO_PARENT, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpMorelayers = bmpNextframe; + wxBitmap bmpLessres = bmpPrevframe; + wxBitmap bmpFullres = wxArtProvider::GetBitmap(wxART_GO_TO_PARENT, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpMoreres = bmpNextframe; + wxBitmap bmpPrevcomp = bmpPrevframe; + wxBitmap bmpAllcomps = wxArtProvider::GetBitmap(wxART_GO_TO_PARENT, wxART_TOOLBAR, + wxDefaultSize); + wxBitmap bmpNextcomp = bmpNextframe; + + tool_bar->AddTool(OPJFRAME_FILEOPEN, bmpOpen, wxT("Open")); + tool_bar->AddTool(OPJFRAME_FILESAVEAS, bmpSaveAs, wxT("Save as ")); + //tool_bar->EnableTool(OPJFRAME_FILESAVEAS, false); + tool_bar->AddSeparator(); + tool_bar->AddTool(OPJFRAME_VIEWZOOM, bmpZoom, wxT("Zoom")); + tool_bar->AddTool(OPJFRAME_VIEWFIT, bmpFit, wxT("Zoom to fit")); + tool_bar->AddTool(OPJFRAME_VIEWRELOAD, bmpReload, wxT("Reload")); + tool_bar->AddSeparator(); + tool_bar->AddTool(OPJFRAME_SETSDECO, bmpDecosettings, wxT("Decoder settings")); + tool_bar->AddTool(OPJFRAME_SETSENCO, bmpEncosettings, wxT("Encoder settings")); + tool_bar->AddSeparator(); + tool_bar->AddTool(OPJFRAME_VIEWPREVFRAME, bmpPrevframe, wxT("Previous frame")); + tool_bar->AddTool(OPJFRAME_VIEWHOMEFRAME, bmpHomeframe, wxT("Starting frame")); + tool_bar->AddTool(OPJFRAME_VIEWNEXTFRAME, bmpNextframe, wxT("Next frame")); + tool_bar->AddSeparator(); + tool_bar->AddTool(OPJFRAME_VIEWLESSLAYERS, bmpLesslayers, wxT("Remove a layer")); + tool_bar->AddTool(OPJFRAME_VIEWALLLAYERS, bmpAlllayers, wxT("Show all layers")); + tool_bar->AddTool(OPJFRAME_VIEWMORELAYERS, bmpMorelayers, wxT("Add a layer")); + tool_bar->AddSeparator(); + tool_bar->AddTool(OPJFRAME_VIEWLESSRES, bmpLessres, wxT("Reduce the resolution")); + tool_bar->AddTool(OPJFRAME_VIEWFULLRES, bmpFullres, wxT("Full resolution")); + tool_bar->AddTool(OPJFRAME_VIEWMORERES, bmpMoreres, wxT("Increase the resolution")); + tool_bar->AddSeparator(); + tool_bar->AddTool(OPJFRAME_VIEWPREVCOMP, bmpPrevcomp, wxT("Previous component")); + tool_bar->AddTool(OPJFRAME_VIEWALLCOMPS, bmpAllcomps, wxT("All components")); + tool_bar->AddTool(OPJFRAME_VIEWNEXTCOMP, bmpNextcomp, wxT("Next component")); + tool_bar->Realize(); + + // associate the toolbar with the frame + SetToolBar(tool_bar); + + // show the toolbar? + if (!wxGetApp().m_showtoolbar) + tool_bar->Show(false); + else + tool_bar->Show(true); + + // the logging window + loggingWindow = new wxSashLayoutWindow(this, OPJFRAME_LOGWIN, + wxDefaultPosition, wxSize(400, wxGetApp().m_peekerheight), + wxNO_BORDER | wxSW_3D | wxCLIP_CHILDREN + ); + loggingWindow->SetDefaultSize(wxSize(1000, wxGetApp().m_peekerheight)); + loggingWindow->SetOrientation(wxLAYOUT_HORIZONTAL); + loggingWindow->SetAlignment(wxLAYOUT_BOTTOM); + //loggingWindow->SetBackgroundColour(wxColour(0, 0, 255)); + loggingWindow->SetSashVisible(wxSASH_TOP, true); + + // show the logging? + if (!wxGetApp().m_showpeeker) + loggingWindow->Show(false); + else + loggingWindow->Show(true); + + // create the bottom notebook + m_bookCtrlbottom = new wxNotebook(loggingWindow, BOTTOM_NOTEBOOK_ID, + wxDefaultPosition, wxDefaultSize, + wxBK_LEFT); + + // create the text control of the logger + m_textCtrl = new wxTextCtrl(m_bookCtrlbottom, wxID_ANY, wxT(""), + wxDefaultPosition, wxDefaultSize, + wxTE_MULTILINE | wxSUNKEN_BORDER | wxTE_READONLY + ); + m_textCtrl->SetValue(_T("Logging window\n")); + + // add it to the notebook + m_bookCtrlbottom->AddPage(m_textCtrl, wxT("Log")); + + // create the text control of the browser + m_textCtrlbrowse = new wxTextCtrl(m_bookCtrlbottom, wxID_ANY, wxT(""), + wxDefaultPosition, wxDefaultSize, + wxTE_MULTILINE | wxSUNKEN_BORDER | wxTE_READONLY | wxTE_RICH + ); + wxFont *browsefont = new wxFont(wxNORMAL_FONT->GetPointSize(), + wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL); + m_textCtrlbrowse->SetDefaultStyle(wxTextAttr(wxNullColour, wxNullColour, *browsefont)); + m_textCtrlbrowse->AppendText(wxT("Browsing window\n")); + + // add it the notebook + m_bookCtrlbottom->AddPage(m_textCtrlbrowse, wxT("Peek"), false); + + // the browser window + markerTreeWindow = new wxSashLayoutWindow(this, OPJFRAME_BROWSEWIN, + wxDefaultPosition, wxSize(wxGetApp().m_browserwidth, 30), + wxNO_BORDER | wxSW_3D | wxCLIP_CHILDREN + ); + markerTreeWindow->SetDefaultSize(wxSize(wxGetApp().m_browserwidth, 1000)); + markerTreeWindow->SetOrientation(wxLAYOUT_VERTICAL); + markerTreeWindow->SetAlignment(wxLAYOUT_LEFT); + //markerTreeWindow->SetBackgroundColour(wxColour(0, 255, 0)); + markerTreeWindow->SetSashVisible(wxSASH_RIGHT, true); + markerTreeWindow->SetExtraBorderSize(0); + + // create the browser notebook + m_bookCtrl = new wxNotebook(markerTreeWindow, LEFT_NOTEBOOK_ID, + wxDefaultPosition, wxDefaultSize, + wxBK_TOP); + + // show the browser? + if (!wxGetApp().m_showbrowser) + markerTreeWindow->Show(false); + else + markerTreeWindow->Show(true); + +#ifdef __WXMOTIF__ + // For some reason, we get a memcpy crash in wxLogStream::DoLogStream + // on gcc/wxMotif, if we use wxLogTextCtl. Maybe it's just gcc? + delete wxLog::SetActiveTarget(new wxLogStderr); +#else + // set our text control as the log target + wxLogTextCtrl *logWindow = new wxLogTextCtrl(m_textCtrl); + delete wxLog::SetActiveTarget(logWindow); +#endif + + // associate drop targets with the controls + SetDropTarget(new OPJDnDFile(this)); + +} + +// this is the frame destructor +OPJFrame::~OPJFrame(void) +{ + // save size settings + GetSize(&(wxGetApp().m_framewidth), &(wxGetApp().m_frameheight)); + + // delete all possible things + delete m_bookCtrl; + m_bookCtrl = NULL; + + delete markerTreeWindow; + markerTreeWindow = NULL; + + delete m_textCtrl; + m_textCtrl = NULL; + + delete m_bookCtrlbottom; + m_bookCtrlbottom = NULL; + + delete loggingWindow; + loggingWindow = NULL; +} + +void OPJFrame::OnNotebook(wxNotebookEvent& event) +{ + int sel = event.GetSelection(); + long childnum; + + m_bookCtrl->GetPageText(sel).ToLong(&childnum); + + if (m_childhash[childnum]) + m_childhash[childnum]->Activate(); + + //wxLogMessage(wxT("Selection changed (now %d --> %d)"), childnum, m_childhash[childnum]->m_winnumber); + +} + + +void OPJFrame::Resize(int number) +{ + wxSize size = GetClientSize(); +} + +void OPJFrame::OnSetsEnco(wxCommandEvent& event) +{ + int n; + + OPJEncoderDialog dialog(this, event.GetId()); + + if (dialog.ShowModal() == wxID_OK) { + + // load settings + wxGetApp().m_subsampling = dialog.m_subsamplingCtrl->GetValue(); + wxGetApp().m_origin = dialog.m_originCtrl->GetValue(); + wxGetApp().m_rates = dialog.m_rateCtrl->GetValue(); + wxGetApp().m_quality = dialog.m_qualityCtrl->GetValue(); + wxGetApp().m_enablequality = dialog.m_qualityRadio->GetValue(); + wxGetApp().m_multicomp = dialog.m_mctCheck->GetValue(); + wxGetApp().m_irreversible = dialog.m_irrevCheck->GetValue(); + wxGetApp().m_resolutions = dialog.m_resolutionsCtrl->GetValue(); + wxGetApp().m_cbsize = dialog.m_cbsizeCtrl->GetValue(); + wxGetApp().m_prsize = dialog.m_prsizeCtrl->GetValue(); + wxGetApp().m_tsize = dialog.m_tsizeCtrl->GetValue(); + wxGetApp().m_torigin = dialog.m_toriginCtrl->GetValue(); + wxGetApp().m_progression = dialog.progressionBox->GetSelection(); + wxGetApp().m_enablesop = dialog.m_sopCheck->GetValue(); + wxGetApp().m_enableeph = dialog.m_ephCheck->GetValue(); + wxGetApp().m_enablebypass = dialog.m_enablebypassCheck->GetValue(); + wxGetApp().m_enablereset = dialog.m_enableresetCheck->GetValue(); + wxGetApp().m_enablerestart = dialog.m_enablerestartCheck->GetValue(); + wxGetApp().m_enablevsc = dialog.m_enablevscCheck->GetValue(); + wxGetApp().m_enableerterm = dialog.m_enableertermCheck->GetValue(); + wxGetApp().m_enablesegmark = dialog.m_enablesegmarkCheck->GetValue(); + wxGetApp().m_enableidx = dialog.m_enableidxCheck->GetValue(); + wxGetApp().m_index = dialog.m_indexCtrl->GetValue(); + wxGetApp().m_enablecomm = dialog.m_enablecommCheck->GetValue(); + wxGetApp().m_comment = dialog.m_commentCtrl->GetValue(); + wxGetApp().m_enablepoc = dialog.m_enablepocCheck->GetValue(); + wxGetApp().m_poc = dialog.m_pocCtrl->GetValue(); +#ifdef USE_JPWL + wxGetApp().m_enablejpwle = dialog.m_enablejpwlCheck->GetValue(); + for (n = 0; n < MYJPWL_MAX_NO_TILESPECS; n++) { + wxGetApp().m_hprotsel[n] = dialog.m_hprotChoice[n]->GetSelection(); + wxGetApp().m_htileval[n] = dialog.m_htileCtrl[n]->GetValue(); + wxGetApp().m_pprotsel[n] = dialog.m_pprotChoice[n]->GetSelection(); + wxGetApp().m_ptileval[n] = dialog.m_ptileCtrl[n]->GetValue(); + wxGetApp().m_ppackval[n] = dialog.m_ppackCtrl[n]->GetValue(); + wxGetApp().m_sensisel[n] = dialog.m_sensiChoice[n]->GetSelection(); + wxGetApp().m_stileval[n] = dialog.m_stileCtrl[n]->GetValue(); + } +#endif // USE_JPWL + }; +} + +void OPJFrame::OnSetsDeco(wxCommandEvent& event) +{ + OPJDecoderDialog dialog(this, event.GetId()); + + if (dialog.ShowModal() == wxID_OK) { + + // load settings + wxGetApp().m_enabledeco = dialog.m_enabledecoCheck->GetValue(); + wxGetApp().m_enableparse = dialog.m_enableparseCheck->GetValue(); + wxGetApp().m_resizemethod = dialog.m_resizeBox->GetSelection() - 1; + wxGetApp().m_reducefactor = dialog.m_reduceCtrl->GetValue(); + wxGetApp().m_qualitylayers = dialog.m_layerCtrl->GetValue(); + wxGetApp().m_components = dialog.m_numcompsCtrl->GetValue(); + wxGetApp().m_framenum = dialog.m_framenumCtrl->GetValue(); +#ifdef USE_JPWL + wxGetApp().m_enablejpwl = dialog.m_enablejpwlCheck->GetValue(); + wxGetApp().m_expcomps = dialog.m_expcompsCtrl->GetValue(); + wxGetApp().m_maxtiles = dialog.m_maxtilesCtrl->GetValue(); +#endif // USE_JPWL + + }; +} + +void OPJFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) +{ + Close(true); +} + +void OPJFrame::OnClose(wxCommandEvent& WXUNUSED(event)) +{ + // current frame + OPJChildFrame *currframe = (OPJChildFrame *) GetActiveChild(); + + if (!currframe) + return; + + wxCloseEvent e; + currframe->OnClose(e); +} + +void OPJFrame::OnFit(wxCommandEvent& event) +{ + OPJChildFrame *currchild; + wxString eventstring = event.GetString(); + + //wxLogMessage(wxT("OnFit:%d:%s"), event.GetInt(), eventstring); + + // current child + if (event.GetInt() >= 1) { + currchild = m_childhash[event.GetInt()]; + } else { + currchild = (OPJChildFrame *) GetActiveChild(); + } + + // problems + if (!currchild) + return; + + // current canvas + OPJCanvas *currcanvas = currchild->m_canvas; + + // find a fit-to-width zoom + /*int zooml, wzooml, hzooml; + wxSize clientsize = currcanvas->GetClientSize(); + wzooml = (int) ceil(100.0 * (double) (clientsize.GetWidth() - 2 * OPJ_CANVAS_BORDER) / (double) (currcanvas->m_image100.GetWidth())); + hzooml = (int) ceil(100.0 * (double) (clientsize.GetHeight() - 2 * OPJ_CANVAS_BORDER) / (double) (currcanvas->m_image100.GetHeight())); + zooml = wxMin(100, wxMin(wzooml, hzooml));*/ + + // fit to width + Rescale(-1, currchild); +} + +void OPJFrame::OnZoom(wxCommandEvent& WXUNUSED(event)) +{ + // current frame + OPJChildFrame *currframe = (OPJChildFrame *) GetActiveChild(); + + if (!currframe) + return; + + // get the preferred zoom + long zooml = wxGetNumberFromUser(wxT("Choose a scale between 5% and 300%"), + wxT("Zoom (%)"), + wxT("Image scale"), + currframe->m_canvas->m_zooml, 5, 300, NULL, wxDefaultPosition); + + // rescale current frame image if necessary + if (zooml >= 5) { + Rescale(zooml, currframe); + wxLogMessage(wxT("zoom to %d%%"), zooml); + } +} + +void OPJFrame::Rescale(int zooml, OPJChildFrame *currframe) +{ + wxImage new_image = currframe->m_canvas->m_image100.ConvertToImage(); + + // resizing enabled? + if (wxGetApp().m_resizemethod == -1) { + + zooml = 100; + + } else { + + if (zooml < 0) { + // find a fit-to-width zoom + int wzooml, hzooml; + //wxSize clientsize = currframe->m_canvas->GetClientSize(); + wxSize clientsize = currframe->m_frame->GetActiveChild()->GetClientSize(); + wzooml = (int) floor(100.0 * (double) clientsize.GetWidth() / (double) (2 * OPJ_CANVAS_BORDER + currframe->m_canvas->m_image100.GetWidth())); + hzooml = (int) floor(100.0 * (double) clientsize.GetHeight() / (double) (2 * OPJ_CANVAS_BORDER + currframe->m_canvas->m_image100.GetHeight())); + zooml = wxMin(100, wxMin(wzooml, hzooml)); + } + } + + if (zooml != 100) + new_image.Rescale((int) ((double) zooml * (double) new_image.GetWidth() / 100.0), + (int) ((double) zooml * (double) new_image.GetHeight() / 100.0), + wxGetApp().m_resizemethod ? wxIMAGE_QUALITY_HIGH : wxIMAGE_QUALITY_NORMAL); + currframe->m_canvas->m_image = wxBitmap(new_image); + currframe->m_canvas->SetScrollbars(20, + 20, + (int)(0.5 + (double) new_image.GetWidth() / 20.0), + (int)(0.5 + (double) new_image.GetHeight() / 20.0) + ); + + currframe->m_canvas->Refresh(); + + wxLogMessage(wxT("Rescale said %d%%"), zooml); + + // update zoom + currframe->m_canvas->m_zooml = zooml; +} + + +void OPJFrame::OnReload(wxCommandEvent& event) +{ + OPJChildFrame *currframe = (OPJChildFrame *) GetActiveChild(); + + if (currframe) { + OPJDecoThread *dthread = currframe->m_canvas->CreateDecoThread(); + + if (dthread->Run() != wxTHREAD_NO_ERROR) + wxLogMessage(wxT("Can't start deco thread!")); + else + wxLogMessage(wxT("New deco thread started.")); + + currframe->m_canvas->Refresh(); + + // update zoom + //currframe->m_canvas->m_zooml = zooml; + } +} + +void OPJFrame::OnPrevFrame(wxCommandEvent& event) +{ + if (--wxGetApp().m_framenum < 0) + wxGetApp().m_framenum = 0; + + wxCommandEvent e; + OnReload(e); +} + +void OPJFrame::OnHomeFrame(wxCommandEvent& event) +{ + wxGetApp().m_framenum = 0; + + wxCommandEvent e; + OnReload(e); +} + +void OPJFrame::OnNextFrame(wxCommandEvent& event) +{ + ++wxGetApp().m_framenum; + + wxCommandEvent e; + OnReload(e); +} + +void OPJFrame::OnLessLayers(wxCommandEvent& event) +{ + if (--wxGetApp().m_qualitylayers < 1) + wxGetApp().m_qualitylayers = 1; + + wxCommandEvent e; + OnReload(e); +} + +void OPJFrame::OnAllLayers(wxCommandEvent& event) +{ + wxGetApp().m_qualitylayers = 0; + + wxCommandEvent e; + OnReload(e); +} + +void OPJFrame::OnMoreLayers(wxCommandEvent& event) +{ + ++wxGetApp().m_qualitylayers; + + wxCommandEvent e; + OnReload(e); +} + +void OPJFrame::OnLessRes(wxCommandEvent& event) +{ + ++wxGetApp().m_reducefactor; + + wxCommandEvent e; + OnReload(e); +} + +void OPJFrame::OnFullRes(wxCommandEvent& event) +{ + wxGetApp().m_reducefactor = 0; + + wxCommandEvent e; + OnReload(e); +} + +void OPJFrame::OnMoreRes(wxCommandEvent& event) +{ + if (--wxGetApp().m_reducefactor < 0) + wxGetApp().m_reducefactor = 0; + + wxCommandEvent e; + OnReload(e); +} + +void OPJFrame::OnPrevComp(wxCommandEvent& event) +{ + if (--wxGetApp().m_components < 1) + wxGetApp().m_components = 1; + + wxCommandEvent e; + OnReload(e); +} + +void OPJFrame::OnAllComps(wxCommandEvent& event) +{ + wxGetApp().m_components = 0; + + wxCommandEvent e; + OnReload(e); +} + +void OPJFrame::OnNextComp(wxCommandEvent& event) +{ + ++wxGetApp().m_components; + + wxCommandEvent e; + OnReload(e); +} + +void OPJFrame::OnToggleBrowser(wxCommandEvent& WXUNUSED(event)) +{ + if (markerTreeWindow->IsShown()) + markerTreeWindow->Show(false); + else + markerTreeWindow->Show(true); + + wxLayoutAlgorithm layout; + layout.LayoutMDIFrame(this); + + wxGetApp().m_showbrowser = markerTreeWindow->IsShown(); + + // Leaves bits of itself behind sometimes + GetClientWindow()->Refresh(); +} + +void OPJFrame::OnTogglePeeker(wxCommandEvent& WXUNUSED(event)) +{ + if (loggingWindow->IsShown()) + loggingWindow->Show(false); + else + loggingWindow->Show(true); + + wxLayoutAlgorithm layout; + layout.LayoutMDIFrame(this); + + wxGetApp().m_showpeeker = loggingWindow->IsShown(); + + // Leaves bits of itself behind sometimes + GetClientWindow()->Refresh(); +} + +void OPJFrame::OnToggleToolbar(wxCommandEvent& WXUNUSED(event)) +{ + if (tool_bar->IsShown()) + tool_bar->Show(false); + else + tool_bar->Show(true); + + wxLayoutAlgorithm layout; + layout.LayoutMDIFrame(this); + + wxGetApp().m_showtoolbar = tool_bar->IsShown(); + + // Leaves bits of itself behind sometimes + GetClientWindow()->Refresh(); +} + +void OPJFrame::OnSashDrag(wxSashEvent& event) +{ + int wid, hei; + + if (event.GetDragStatus() == wxSASH_STATUS_OUT_OF_RANGE) + return; + + switch (event.GetId()) { + case OPJFRAME_BROWSEWIN: + { + markerTreeWindow->SetDefaultSize(wxSize(event.GetDragRect().width, 1000)); + break; + } + case OPJFRAME_LOGWIN: + { + loggingWindow->SetDefaultSize(wxSize(1000, event.GetDragRect().height)); + break; + } + } + + wxLayoutAlgorithm layout; + layout.LayoutMDIFrame(this); + + // Leaves bits of itself behind sometimes + GetClientWindow()->Refresh(); + + // update dimensions + markerTreeWindow->GetSize(&wid, &hei); + wxGetApp().m_browserwidth = wid; + + loggingWindow->GetSize(&wid, &hei); + wxGetApp().m_peekerheight = hei; + +} + +void OPJFrame::OnThreadLogmsg(wxCommandEvent& event) +{ +#if 1 + wxLogMessage(wxT("Frame got message from worker thread: %d"), event.GetInt()); + wxLogMessage(event.GetString()); +#else + int n = event.GetInt(); + if ( n == -1 ) + { + m_dlgProgress->Destroy(); + m_dlgProgress = (wxProgressDialog *)NULL; + + // the dialog is aborted because the event came from another thread, so + // we may need to wake up the main event loop for the dialog to be + // really closed + wxWakeUpIdle(); + } + else + { + if ( !m_dlgProgress->Update(n) ) + { + wxCriticalSectionLocker lock(m_critsectWork); + + m_cancelled = true; + } + } +#endif +} + + +// physically save the file +void OPJFrame::SaveFile(wxArrayString paths, wxArrayString filenames) +{ + size_t count = paths.GetCount(); + wxString msg, s; + + if (wxFile::Exists(paths[0].c_str())) { + + s.Printf(wxT("File %s already exists. Do you want to overwrite it?\n"), filenames[0].c_str()); + wxMessageDialog dialog3(this, s, _T("File exists"), wxYES_NO); + if (dialog3.ShowModal() == wxID_NO) + return; + } + + /*s.Printf(_T("File %d: %s (%s)\n"), (int)0, paths[0].c_str(), filenames[0].c_str()); + msg += s; + + wxMessageDialog dialog2(this, msg, _T("Selected files")); + dialog2.ShowModal();*/ + + if (!GetActiveChild()) + return; + + ((OPJChildFrame *) GetActiveChild())->m_canvas->m_savename = paths[0]; + + OPJEncoThread *ethread = ((OPJChildFrame *) GetActiveChild())->m_canvas->CreateEncoThread(); + + if (ethread->Run() != wxTHREAD_NO_ERROR) + wxLogMessage(wxT("Can't start enco thread!")); + else + wxLogMessage(wxT("New enco thread started.")); + + +} + +// physically open the files +void OPJFrame::OpenFiles(wxArrayString paths, wxArrayString filenames) +{ + + size_t count = paths.GetCount(); + for (size_t n = 0; n < count; n++) { + + wxString msg, s; + s.Printf(_T("File %d: %s (%s)\n"), (int)n, paths[n].c_str(), filenames[n].c_str()); + + msg += s; + + /*wxMessageDialog dialog2(this, msg, _T("Selected files")); + dialog2.ShowModal();*/ + + // Make another frame, containing a canvas + OPJChildFrame *subframe = new OPJChildFrame(this, + paths[n], + winNumber, + wxT("Canvas Frame"), + wxDefaultPosition, wxSize(300, 300), + wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE + ); + m_childhash[winNumber] = subframe; + + // create own marker tree + m_treehash[winNumber] = new OPJMarkerTree(m_bookCtrl, subframe, paths[n], wxT("Parsing..."), TreeTest_Ctrl, + wxDefaultPosition, wxDefaultSize, + wxTR_DEFAULT_STYLE | wxSUNKEN_BORDER + ); + + m_bookCtrl->AddPage(m_treehash[winNumber], wxString::Format(wxT("%u"), winNumber), false); + + for (unsigned int p = 0; p < m_bookCtrl->GetPageCount(); p++) { + if (m_bookCtrl->GetPageText(p) == wxString::Format(wxT("%u"), winNumber)) { + m_bookCtrl->ChangeSelection(p); + break; + } + } + + winNumber++; + } +} + +void OPJFrame::OnFileOpen(wxCommandEvent& WXUNUSED(event)) +{ + wxString wildcards = +#ifdef __WXMOTIF__ + wxT("JPEG 2000 files (*.jp2,*.j2k,*.j2c,*.mj2)|*.*j*2*"); +#else +#if wxUSE_LIBOPENJPEG + wxT("JPEG 2000 files (*.jp2,*.j2k,*.j2c,*.mj2)|*.jp2;*.j2k;*.j2c;*.mj2") +#endif +#if USE_MXF + wxT("|MXF JPEG 2000 video (*.mxf)|*.mxf") +#endif // USE_MXF +#if wxUSE_LIBJPEG + wxT("|JPEG files (*.jpg)|*.jpg") +#endif +#if OPJ_MANYFORMATS + wxT("|BMP files (*.bmp)|*.bmp") + wxT("|PNG files (*.png)|*.png") + wxT("|GIF files (*.gif)|*.gif") + wxT("|PNM files (*.pnm)|*.pnm") + wxT("|TIFF files (*.tif,*.tiff)|*.tif*") +#endif + wxT("|All files|*"); +#endif + wxFileDialog dialog(this, _T("Open image file(s)"), + wxEmptyString, wxEmptyString, wildcards, + wxFD_OPEN|wxFD_MULTIPLE); + + if (dialog.ShowModal() == wxID_OK) { + wxArrayString paths, filenames; + + dialog.GetPaths(paths); + dialog.GetFilenames(filenames); + + OpenFiles(paths, filenames); + } + +} + +void OPJFrame::OnFileSaveAs(wxCommandEvent& WXUNUSED(event)) +{ + wxString wildcards = +#ifdef wxUSE_LIBOPENJPEG +#ifdef __WXMOTIF__ + wxT("JPEG 2000 codestream (*.j2k)|*.*j*2*"); +#else + wxT("JPEG 2000 codestream (*.j2k)|*.j2k") + wxT("|JPEG 2000 file format (*.jp2)|*.jp2"); +#endif +#else + wxT("Houston we have a problem"); +#endif + + wxFileDialog dialog(this, _T("Save image file"), + wxEmptyString, wxEmptyString, wildcards, + wxFD_SAVE); + + if (dialog.ShowModal() == wxID_OK) { + wxArrayString paths, filenames; + + dialog.GetPaths(paths); + dialog.GetFilenames(filenames); + + SaveFile(paths, filenames); + } + + +} + +void OPJFrame::OnMemoryOpen(wxCommandEvent& WXUNUSED(event)) +{ + // do nothing + return; + + wxTextEntryDialog dialog(this, wxT("Memory HEX address range: start_address-stop_address"), + wxT("Decode a memory buffer"), + wxT("0x-0x"), + wxOK | wxCANCEL | wxCENTRE, + wxDefaultPosition); + + if (dialog.ShowModal() == wxID_OK) { + + } + +} + +BEGIN_EVENT_TABLE(OPJCanvas, wxScrolledWindow) + EVT_MOUSE_EVENTS(OPJCanvas::OnEvent) + EVT_MENU(OPJCANVAS_THREADSIGNAL, OPJCanvas::OnThreadSignal) +END_EVENT_TABLE() + +// Define a constructor for my canvas +OPJCanvas::OPJCanvas(wxFileName fname, wxWindow *parent, const wxPoint& pos, const wxSize& size) + : wxScrolledWindow(parent, wxID_ANY, pos, size, + wxSUNKEN_BORDER | wxNO_FULL_REPAINT_ON_RESIZE) +{ + SetBackgroundColour(OPJ_CANVAS_COLOUR); + + m_fname = fname; + m_childframe = (OPJChildFrame *) parent; + // 100% zoom + m_zooml = 100; + + + OPJDecoThread *dthread = CreateDecoThread(); + + if (dthread->Run() != wxTHREAD_NO_ERROR) + wxLogMessage(wxT("Can't start deco thread!")); + else + wxLogMessage(wxT("New deco thread started.")); + + // 100% zoom + //m_zooml = 100; + +} + +OPJDecoThread *OPJCanvas::CreateDecoThread(void) +{ + OPJDecoThread *dthread = new OPJDecoThread(this); + + if (dthread->Create() != wxTHREAD_NO_ERROR) + wxLogError(wxT("Can't create deco thread!")); + + wxCriticalSectionLocker enter(wxGetApp().m_deco_critsect); + wxGetApp().m_deco_threads.Add(dthread); + + return dthread; +} + +OPJEncoThread *OPJCanvas::CreateEncoThread(void) +{ + OPJEncoThread *ethread = new OPJEncoThread(this); + + if (ethread->Create() != wxTHREAD_NO_ERROR) + wxLogError(wxT("Can't create enco thread!")); + + wxCriticalSectionLocker enter(wxGetApp().m_enco_critsect); + wxGetApp().m_enco_threads.Add(ethread); + + return ethread; +} + +#define activeoverlay 0 +// Define the repainting behaviour +void OPJCanvas::OnDraw(wxDC& dc) +{ + if (m_image.Ok()) { + dc.DrawBitmap(m_image, OPJ_CANVAS_BORDER, OPJ_CANVAS_BORDER); + + if (activeoverlay) { + dc.SetPen(*wxRED_PEN); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + //int tw, th; + dc.DrawRectangle(OPJ_CANVAS_BORDER, OPJ_CANVAS_BORDER, + (unsigned long int) (0.5 + (double) m_zooml * (double) m_childframe->m_twidth / 100.0), + (unsigned long int) (0.5 + (double) m_zooml * (double) m_childframe->m_theight / 100.0)); + } + + } else { + dc.SetFont(*wxSWISS_FONT); + dc.SetPen(*wxBLACK_PEN); +#ifdef __WXGTK__ + dc.DrawText(_T("Decoding image, please wait... (press \"Zoom to Fit\" to show the image)"), 40, 50); +#else + dc.DrawText(_T("Decoding image, please wait..."), 40, 50); +#endif + } +} + +// This implements a tiny doodling program! Drag the mouse using +// the left button. +void OPJCanvas::OnEvent(wxMouseEvent& event) +{ +#if USE_PENCIL_ON_CANVAS + wxClientDC dc(this); + PrepareDC(dc); + + wxPoint pt(event.GetLogicalPosition(dc)); + + if ((xpos > -1) && (ypos > -1) && event.Dragging()) { + dc.SetPen(*wxRED_PEN); + dc.DrawLine(xpos, ypos, pt.x, pt.y); + } + xpos = pt.x; + ypos = pt.y; +#endif +} + +void OPJFrame::OnSize(wxSizeEvent& WXUNUSED(event)) +{ + wxLayoutAlgorithm layout; + layout.LayoutMDIFrame(this); +} + +void OPJCanvas::OnThreadSignal(wxCommandEvent& event) +{ +#if 1 + wxLogMessage(wxT("Canvas got signal from deco thread: %d"), event.GetInt()); + wxLogMessage(event.GetString()); +#else + int n = event.GetInt(); + if ( n == -1 ) + { + m_dlgProgress->Destroy(); + m_dlgProgress = (wxProgressDialog *)NULL; + + // the dialog is aborted because the event came from another thread, so + // we may need to wake up the main event loop for the dialog to be + // really closed + wxWakeUpIdle(); + } + else + { + if ( !m_dlgProgress->Update(n) ) + { + wxCriticalSectionLocker lock(m_critsectWork); + + m_cancelled = true; + } + } +#endif +} + + +// Note that OPJFRAME_FILEOPEN and OPJFRAME_HELPABOUT commands get passed +// to the parent window for processing, so no need to +// duplicate event handlers here. + +BEGIN_EVENT_TABLE(OPJChildFrame, wxMDIChildFrame) + /*EVT_MENU(SASHTEST_CHILD_QUIT, OPJChildFrame::OnQuit)*/ + EVT_CLOSE(OPJChildFrame::OnClose) + EVT_SET_FOCUS(OPJChildFrame::OnGotFocus) + EVT_KILL_FOCUS(OPJChildFrame::OnLostFocus) +END_EVENT_TABLE() + +OPJChildFrame::OPJChildFrame(OPJFrame *parent, wxFileName fname, int winnumber, const wxString& title, const wxPoint& pos, const wxSize& size, +const long style): + wxMDIChildFrame(parent, wxID_ANY, title, pos, size, style) +{ + m_frame = (OPJFrame *) parent; + m_canvas = NULL; + //my_children.Append(this); + m_fname = fname; + m_winnumber = winnumber; + SetTitle(wxString::Format(_T("%d: "), m_winnumber) + m_fname.GetFullName()); + + // Give it an icon (this is ignored in MDI mode: uses resources) +#ifdef __WXMSW__ + SetIcon(wxIcon(wxT("OPJChild16"))); +#endif + + // Give it a status line + /*CreateStatusBar();*/ + + int width, height; + GetClientSize(&width, &height); + + OPJCanvas *canvas = new OPJCanvas(fname, this, wxPoint(0, 0), wxSize(width, height)); +#if USE_PENCIL_ON_CANVAS + canvas->SetCursor(wxCursor(wxCURSOR_PENCIL)); +#endif + m_canvas = canvas; + + // Give it scrollbars + canvas->SetScrollbars(20, 20, 5, 5); + + Show(true); + Maximize(true); + + /*wxLogError(wxString::Format(wxT("Created tree %d (0x%x)"), m_winnumber, m_frame->m_treehash[m_winnumber]));*/ + +} + +OPJChildFrame::~OPJChildFrame(void) +{ + //my_children.DeleteObject(this); +} + + +void OPJChildFrame::OnClose(wxCloseEvent& event) +{ + for (unsigned int p = 0; p < m_frame->m_bookCtrl->GetPageCount(); p++) { + if (m_frame->m_bookCtrl->GetPageText(p) == wxString::Format(wxT("%u"), m_winnumber)) { + m_frame->m_bookCtrl->DeletePage(p); + break; + } + } + Destroy(); + + wxLogMessage(wxT("Closed: %d"), m_winnumber); +} + +void OPJChildFrame::OnActivate(wxActivateEvent& event) +{ + /*if (event.GetActive() && m_canvas) + m_canvas->SetFocus();*/ +} + +void OPJChildFrame::OnGotFocus(wxFocusEvent& event) +{ + // we need to check if the notebook is being destroyed or not + if (!m_frame->m_bookCtrl) + return; + + for (unsigned int p = 0; p < m_frame->m_bookCtrl->GetPageCount(); p++) { + + if (m_frame->m_bookCtrl->GetPageText(p) == wxString::Format(wxT("%u"), m_winnumber)) { + m_frame->m_bookCtrl->ChangeSelection(p); + break; + } + + } + + //wxLogMessage(wxT("Got focus: %d (%x)"), m_winnumber, event.GetWindow()); +} + +void OPJChildFrame::OnLostFocus(wxFocusEvent& event) +{ + //wxLogMessage(wxT("Lost focus: %d (%x)"), m_winnumber, event.GetWindow()); +} + + +//////////////////////////////// +// drag and drop +//////////////////////////////// + +bool OPJDnDFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& filenames) +{ + /*size_t nFiles = filenames.GetCount(); + wxString str; + str.Printf( _T("%d files dropped\n"), (int)nFiles); + for ( size_t n = 0; n < nFiles; n++ ) { + str << filenames[n] << wxT("\n"); + } + wxLogMessage(str);*/ + m_pOwner->OpenFiles(filenames, filenames); + + return true; +} + diff --git a/openjpeg/src/bin/wx/OPJViewer/source/OPJViewer.h b/openjpeg/src/bin/wx/OPJViewer/source/OPJViewer.h new file mode 100644 index 000000000..b60e0d141 --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/OPJViewer.h @@ -0,0 +1,869 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2007, Digital Signal Processing Laboratory, Universita degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +///////////////////////////////////////////////////////////////////////////// +// Name: sashtest.h +// Purpose: Layout window/sash sample +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: sashtest.h,v 1.5 2005/06/02 12:04:24 JS Exp $ +// Copyright: (c) Julian Smart +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: treectrl.h +// Purpose: wxTreeCtrl sample +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: treetest.h,v 1.50 2006/11/04 11:26:51 VZ Exp $ +// Copyright: (c) Julian Smart +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Name: dialogs.h +// Purpose: Common dialogs demo +// Author: Julian Smart +// Modified by: ABX (2004) - adjustementd for conditional building +// Created: 04/01/98 +// RCS-ID: $Id: dialogs.h,v 1.50 2006/10/08 14:12:59 VZ Exp $ +// Copyright: (c) Julian Smart +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// + +#ifndef __OPJ_VIEWER_H__ +#define __OPJ_VIEWER_H__ + +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#include "wx/mdi.h" +#endif + +#include "wx/toolbar.h" +#include "wx/laywin.h" +#include "wx/treectrl.h" + +#include "icon1.xpm" +#include "icon2.xpm" +#include "icon3.xpm" +#include "icon4.xpm" +#include "icon5.xpm" + +#include "wx/filedlg.h" +#include "wx/toolbar.h" +#include <wx/filename.h> +#include <wx/busyinfo.h> +#include <wx/cmdline.h> +#include <wx/file.h> +#include "wx/notebook.h" +#include <wx/numdlg.h> + +#include "wx/propdlg.h" +#include "wx/spinctrl.h" + +#include <wx/dnd.h> +#include "wx/wxhtml.h" +#include "wx/statline.h" +#include <wx/fs_mem.h> + +#include <wx/imaglist.h> + +#include "wx/toolbar.h" +#include "wx/artprov.h" + +#include "openjp2/openjpeg.h" + +//#include "imagj2k.h" +//#include "imagjp2.h" +//#include "imagmj2.h" +#include "imagjpeg2000.h" +#ifdef USE_MXF +#include "imagmxf.h" +#endif // USE_MXF + +#ifdef __WXMSW__ +typedef unsigned __int64 int8byte; +#endif // __WXMSW__ + +#ifdef __WXGTK__ +typedef unsigned long long int8byte; +#endif // __WXGTK__ + +#define USE_GENERIC_TREECTRL 0 +#define USE_PENCIL_ON_CANVAS 0 + +#if USE_GENERIC_TREECTRL +#include "wx/generic/treectlg.h" +#ifndef wxTreeCtrl +#define wxTreeCtrl wxGenericTreeCtrl +#define sm_classwxTreeCtrl sm_classwxGenericTreeCtrl +#endif +#endif + +#define OPJ_APPLICATION wxT("OPJViewer") +#define OPJ_APPLICATION_NAME wxT("OpenJPEG Viewer") +#define OPJ_APPLICATION_VERSION wxT("0.4 beta") +#define OPJ_APPLICATION_TITLEBAR OPJ_APPLICATION_NAME wxT(" ") OPJ_APPLICATION_VERSION +#define OPJ_APPLICATION_COPYRIGHT wxT("(C) 2007-2008, Giuseppe Baruffa") +#define OPJ_APPLICATION_VENDOR wxT("OpenJPEG") + +#ifdef __WXMSW__ +#define OPJ_APPLICATION_PLATFORM wxT("Windows") +#endif + +#ifdef __WXGTK__ +#define OPJ_APPLICATION_PLATFORM wxT("Linux") +#endif + +#define OPJ_FRAME_WIDTH 800 +#define OPJ_FRAME_HEIGHT 600 + +#define OPJ_BROWSER_WIDTH 300 +#define OPJ_PEEKER_HEIGHT 130 + +#define OPJ_CANVAS_BORDER 10 +#define OPJ_CANVAS_COLOUR *wxWHITE + + + +#ifdef USE_JPWL + +//#define MYJPWL_MAX_NO_TILESPECS JPWL_MAX_NO_TILESPECS +#define MYJPWL_MAX_NO_TILESPECS 4 + +#endif // USE_JPWL + + +class OPJDecoThread; +class OPJEncoThread; +class OPJParseThread; +WX_DEFINE_ARRAY_PTR(wxThread *, wxArrayThread); +class OPJChildFrame; + +////////////////////////////////// +// this is our main application // +////////////////////////////////// +class OPJViewerApp: public wxApp +{ + // public methods and variables +public: + + // class constructor + OPJViewerApp() + { + m_showImages = true; + m_showButtons = false; + } + + // other methods + bool OnInit(void); + int OnExit(void); + void SetShowImages(bool show) + { + m_showImages = show; + } + bool ShowImages() const + { + return m_showImages; + } + void ShowCmdLine(const wxCmdLineParser& parser); + + // all the threads currently alive - as soon as the thread terminates, it's + // removed from the array + wxArrayThread m_deco_threads, m_parse_threads, m_enco_threads; + + // crit section protects access to all of the arrays below + wxCriticalSection m_deco_critsect, m_parse_critsect, m_enco_critsect; + + // semaphore used to wait for the threads to exit, see OPJFrame::OnQuit() + wxSemaphore m_deco_semAllDone, m_parse_semAllDone, m_enco_semAllDone; + + // the last exiting thread should post to m_semAllDone if this is true + // (protected by the same m_critsect) + bool m_deco_waitingUntilAllDone, m_parse_waitingUntilAllDone, + m_enco_waitingUntilAllDone; + + // the list of all filenames written in the command line + wxArrayString m_filelist; + + // displaying engine parameters + int m_resizemethod; + + // decoding engine parameters + bool m_enabledeco, m_enableparse; + int m_reducefactor, m_qualitylayers, m_components, m_framenum; +#ifdef USE_JPWL + bool m_enablejpwl, m_enablejpwle; + int m_expcomps, m_maxtiles; +#endif // USE_JPWL + int m_framewidth, m_frameheight; + + // encoding engine parameters + wxString m_subsampling, m_origin, m_rates, m_comment, m_index, m_quality; + wxString m_cbsize, m_prsize, m_tsize, m_torigin, m_poc; + bool m_enablecomm, m_enableidx, m_multicomp, m_irreversible, m_enablesop, + m_enableeph; + bool m_enablebypass, m_enablereset, m_enablerestart, m_enablevsc, + m_enableerterm; + bool m_enablesegmark, m_enablepoc; + bool m_enablequality; + int m_resolutions, m_progression; +#ifdef USE_JPWL + int m_hprotsel[MYJPWL_MAX_NO_TILESPECS], m_pprotsel[MYJPWL_MAX_NO_TILESPECS]; + int m_htileval[MYJPWL_MAX_NO_TILESPECS], m_ptileval[MYJPWL_MAX_NO_TILESPECS], + m_ppackval[MYJPWL_MAX_NO_TILESPECS]; + int m_sensisel[MYJPWL_MAX_NO_TILESPECS], m_stileval[MYJPWL_MAX_NO_TILESPECS]; +#endif // USE_JPWL + + // some layout settings + bool m_showtoolbar, m_showbrowser, m_showpeeker; + int m_browserwidth, m_peekerheight; + + // application configuration + wxConfig *OPJconfig; + + // private methods and variables +private: + bool m_showImages, m_showButtons; + +}; + +DECLARE_APP(OPJViewerApp) + +/////////////////////////////////////////// +// this canvas is used to draw the image // +/////////////////////////////////////////// +class OPJCanvas: public wxScrolledWindow +{ + // public methods and variables +public: + + // class constructor + OPJCanvas(wxFileName fname, wxWindow *parent, const wxPoint& pos, + const wxSize& size); + + virtual void OnDraw(wxDC& dc); + void OnEvent(wxMouseEvent& event); + void WriteText(const wxString& text) + { +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif //__WXGTK__ + wxLogMessage(text); +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif //__WXGTK__ + } + + void OnThreadSignal(wxCommandEvent& event); + + OPJDecoThread *CreateDecoThread(void); + OPJEncoThread *CreateEncoThread(void); + + + OPJChildFrame *m_childframe; + + wxBitmap m_image, m_image100; + wxFileName m_fname, m_savename; + long m_zooml; + + DECLARE_EVENT_TABLE() +}; + +/////////////////////////////////////////////////// +// the data associated to each tree leaf or node // +/////////////////////////////////////////////////// +class OPJMarkerData : public wxTreeItemData +{ + // public methods and variables +public: + + // class constructor + OPJMarkerData(const wxString& desc, const wxString& fname = wxT(""), + wxFileOffset start = 0, wxFileOffset length = 0) : m_desc(desc), + m_filestring(fname) + { + m_start = start; + m_length = length; + } + + void ShowInfo(wxTreeCtrl *tree); + const wxChar *GetDesc1() const + { + return m_desc.c_str(); + } + const wxChar *GetDesc2() const + { + return m_filestring.c_str(); + } + wxFileOffset m_start, m_length; + wxString m_desc; + + // private methods and variables +private: + wxString m_filestring; +}; + + +class OPJMarkerTree : public wxTreeCtrl +{ +public: + enum { + TreeCtrlIcon_File, + TreeCtrlIcon_FileSelected, + TreeCtrlIcon_Folder, + TreeCtrlIcon_FolderSelected, + TreeCtrlIcon_FolderOpened + }; + + OPJMarkerTree() { }; + OPJMarkerTree(wxWindow *parent, OPJChildFrame *subframe, wxFileName fname, + wxString name, const wxWindowID id, + const wxPoint& pos, const wxSize& size, + long style); + virtual ~OPJMarkerTree() {}; + OPJParseThread *CreateParseThread(wxTreeItemId parentid = 0x00, + OPJChildFrame *subframe = NULL); + void WriteText(const wxString& text) + { + wxMutexGuiEnter(); + wxLogMessage(text); + wxMutexGuiLeave(); + } + + wxFileName m_fname; + wxTextCtrl *m_peektextCtrl; + OPJChildFrame *m_childframe; + + /*void OnBeginDrag(wxTreeEvent& event); + void OnBeginRDrag(wxTreeEvent& event); + void OnEndDrag(wxTreeEvent& event);*/ + /*void OnBeginLabelEdit(wxTreeEvent& event); + void OnEndLabelEdit(wxTreeEvent& event);*/ + /*void OnDeleteItem(wxTreeEvent& event);*/ + /*void OnContextMenu(wxContextMenuEvent& event);*/ + void OnItemMenu(wxTreeEvent& event); + /*void OnGetInfo(wxTreeEvent& event); + void OnSetInfo(wxTreeEvent& event);*/ + /*void OnItemExpanded(wxTreeEvent& event);*/ + void OnItemExpanding(wxTreeEvent& event); + /*void OnItemCollapsed(wxTreeEvent& event); + void OnItemCollapsing(wxTreeEvent& event);*/ + void OnSelChanged(wxTreeEvent& event); + /*void OnSelChanging(wxTreeEvent& event);*/ + /*void OnTreeKeyDown(wxTreeEvent& event);*/ + /*void OnItemActivated(wxTreeEvent& event);*/ + /*void OnItemRClick(wxTreeEvent& event);*/ + /*void OnRMouseDown(wxMouseEvent& event); + void OnRMouseUp(wxMouseEvent& event); + void OnRMouseDClick(wxMouseEvent& event);*/ + /*void GetItemsRecursively(const wxTreeItemId& idParent, + wxTreeItemIdValue cookie = 0);*/ + + void CreateImageList(int size = 16); + void CreateButtonsImageList(int size = 11); + + /*void AddTestItemsToTree(size_t numChildren, size_t depth);*/ + /*void DoSortChildren(const wxTreeItemId& item, bool reverse = false) + { m_reverseSort = reverse; wxTreeCtrl::SortChildren(item); }*/ + /*void DoEnsureVisible() { if (m_lastItem.IsOk()) EnsureVisible(m_lastItem); }*/ + /*void DoToggleIcon(const wxTreeItemId& item);*/ + /*void ShowMenu(wxTreeItemId id, const wxPoint& pt);*/ + + int ImageSize(void) const + { + return m_imageSize; + } + + void SetLastItem(wxTreeItemId id) + { + m_lastItem = id; + } + +protected: + /*virtual int OnCompareItems(const wxTreeItemId& i1, const wxTreeItemId& i2);*/ + + // is this the test item which we use in several event handlers? + /*bool IsTestItem(const wxTreeItemId& item) + { + // the test item is the first child folder + return GetItemParent(item) == GetRootItem() && !GetPrevSibling(item); + }*/ + +private: + /*void AddItemsRecursively(const wxTreeItemId& idParent, + size_t nChildren, + size_t depth, + size_t folder);*/ + + void LogEvent(const wxChar *name, const wxTreeEvent& event); + + int m_imageSize; // current size of images + bool m_reverseSort; // flag for OnCompareItems + wxTreeItemId m_lastItem, // for OnEnsureVisible() + m_draggedItem; // item being dragged right now + + // NB: due to an ugly wxMSW hack you _must_ use DECLARE_DYNAMIC_CLASS() + // if you want your overloaded OnCompareItems() to be called. + // OTOH, if you don't want it you may omit the next line - this will + // make default (alphabetical) sorting much faster under wxMSW. + DECLARE_DYNAMIC_CLASS(OPJMarkerTree) + DECLARE_EVENT_TABLE() +}; + +// this hash map stores all the trees of currently opened images, with an integer key +WX_DECLARE_HASH_MAP(int, OPJMarkerTree*, wxIntegerHash, wxIntegerEqual, + OPJMarkerTreeHash); + +// this hash map stores all the children of currently opened images, with an integer key +WX_DECLARE_HASH_MAP(int, OPJChildFrame*, wxIntegerHash, wxIntegerEqual, + OPJChildFrameHash); + +// Define a new frame +class OPJFrame: public wxMDIParentFrame +{ +public: + + OPJFrame(wxWindow *parent, const wxWindowID id, const wxString& title, + const wxPoint& pos, const wxSize& size, const long style); + + ~OPJFrame(void); + void OnSize(wxSizeEvent& WXUNUSED(event)); + void OnAbout(wxCommandEvent& WXUNUSED(event)); + void OnFileOpen(wxCommandEvent& WXUNUSED(event)); + void OnFileSaveAs(wxCommandEvent& WXUNUSED(event)); + void OnMemoryOpen(wxCommandEvent& WXUNUSED(event)); + void OnQuit(wxCommandEvent& WXUNUSED(event)); + void OnClose(wxCommandEvent& WXUNUSED(event)); + void OnZoom(wxCommandEvent& WXUNUSED(event)); + void OnFit(wxCommandEvent& event); + void OnToggleBrowser(wxCommandEvent& WXUNUSED(event)); + void OnTogglePeeker(wxCommandEvent& WXUNUSED(event)); + void OnToggleToolbar(wxCommandEvent& WXUNUSED(event)); + void OnReload(wxCommandEvent& event); + void OnPrevFrame(wxCommandEvent& event); + void OnHomeFrame(wxCommandEvent& event); + void OnNextFrame(wxCommandEvent& event); + void OnLessLayers(wxCommandEvent& event); + void OnAllLayers(wxCommandEvent& event); + void OnMoreLayers(wxCommandEvent& event); + void OnLessRes(wxCommandEvent& event); + void OnFullRes(wxCommandEvent& event); + void OnMoreRes(wxCommandEvent& event); + void OnPrevComp(wxCommandEvent& event); + void OnAllComps(wxCommandEvent& event); + void OnNextComp(wxCommandEvent& event); + void OnSetsEnco(wxCommandEvent& event); + void OnSetsDeco(wxCommandEvent& event); + void OnSashDrag(wxSashEvent& event); + void OpenFiles(wxArrayString paths, wxArrayString filenames); + void SaveFile(wxArrayString paths, wxArrayString filenames); + void OnNotebook(wxNotebookEvent& event); + void Rescale(int scale, OPJChildFrame *child); + void OnThreadLogmsg(wxCommandEvent& event); + + OPJMarkerTreeHash m_treehash; + OPJChildFrameHash m_childhash; + wxSashLayoutWindow* markerTreeWindow; + wxSashLayoutWindow* loggingWindow; + wxToolBar* tool_bar; + void Resize(int number); + wxNotebook *m_bookCtrl; + wxNotebook *m_bookCtrlbottom; + wxTextCtrl *m_textCtrlbrowse; + +private: + void TogStyle(int id, long flag); + + void DoSort(bool reverse = false); + + wxPanel *m_panel; + wxTextCtrl *m_textCtrl; + + void DoSetBold(bool bold = true); + +protected: + wxSashLayoutWindow* m_topWindow; + wxSashLayoutWindow* m_leftWindow2; + + DECLARE_EVENT_TABLE() +}; + +class OPJChildFrame: public wxMDIChildFrame +{ +public: + OPJCanvas *m_canvas; + OPJChildFrame(OPJFrame *parent, wxFileName fname, int winnumber, + const wxString& title, const wxPoint& pos, const wxSize& size, + const long style); + ~OPJChildFrame(void); + void OnActivate(wxActivateEvent& event); + /*void OnQuit(wxCommandEvent& WXUNUSED(event));*/ + void OnClose(wxCloseEvent& event); + void OnGotFocus(wxFocusEvent& event); + void OnLostFocus(wxFocusEvent& event); + OPJFrame *m_frame; + wxFileName m_fname; + int m_winnumber; + + unsigned long m_twidth, m_theight, m_tx, m_ty; + + DECLARE_EVENT_TABLE() +}; + +// frame and main menu ids +enum { + OPJFRAME_FILEEXIT = wxID_EXIT, + OPJFRAME_HELPABOUT = wxID_ABOUT, + OPJFRAME_FILEOPEN, + OPJFRAME_MEMORYOPEN, + OPJFRAME_FILESAVEAS, + OPJFRAME_FILETOGGLEB, + OPJFRAME_FILETOGGLEP, + OPJFRAME_FILETOGGLET, + OPJFRAME_VIEWZOOM, + OPJFRAME_VIEWFIT, + OPJFRAME_VIEWRELOAD, + OPJFRAME_VIEWPREVFRAME, + OPJFRAME_VIEWHOMEFRAME, + OPJFRAME_VIEWNEXTFRAME, + OPJFRAME_VIEWLESSLAYERS, + OPJFRAME_VIEWALLLAYERS, + OPJFRAME_VIEWMORELAYERS, + OPJFRAME_VIEWLESSRES, + OPJFRAME_VIEWFULLRES, + OPJFRAME_VIEWMORERES, + OPJFRAME_VIEWPREVCOMP, + OPJFRAME_VIEWALLCOMPS, + OPJFRAME_VIEWNEXTCOMP, + OPJFRAME_FILECLOSE, + OPJFRAME_SETSENCO, + OPJFRAME_SETSDECO, + + OPJFRAME_BROWSEWIN = 10000, + OPJFRAME_LOGWIN, + OPJFRAME_TOOLBAR, + + OPJFRAME_THREADLOGMSG, + OPJCANVAS_THREADSIGNAL +}; + + +// menu and control ids +enum { + TreeTest_Quit = wxID_EXIT, + TreeTest_About = wxID_ABOUT, + TreeTest_TogButtons = wxID_HIGHEST, + TreeTest_TogTwist, + TreeTest_TogLines, + TreeTest_TogEdit, + TreeTest_TogHideRoot, + TreeTest_TogRootLines, + TreeTest_TogBorder, + TreeTest_TogFullHighlight, + TreeTest_SetFgColour, + TreeTest_SetBgColour, + TreeTest_ResetStyle, + TreeTest_Highlight, + TreeTest_Dump, + TreeTest_DumpSelected, + TreeTest_Count, + TreeTest_CountRec, + TreeTest_Sort, + TreeTest_SortRev, + TreeTest_SetBold, + TreeTest_ClearBold, + TreeTest_Rename, + TreeTest_Delete, + TreeTest_DeleteChildren, + TreeTest_DeleteAll, + TreeTest_Recreate, + TreeTest_ToggleImages, + TreeTest_ToggleButtons, + TreeTest_SetImageSize, + TreeTest_ToggleSel, + TreeTest_CollapseAndReset, + TreeTest_EnsureVisible, + TreeTest_AddItem, + TreeTest_InsertItem, + TreeTest_IncIndent, + TreeTest_DecIndent, + TreeTest_IncSpacing, + TreeTest_DecSpacing, + TreeTest_ToggleIcon, + TreeTest_Select, + TreeTest_Unselect, + TreeTest_SelectRoot, + TreeTest_Ctrl = 1000, + BOTTOM_NOTEBOOK_ID, + LEFT_NOTEBOOK_ID +}; + +class OPJEncoThread : public wxThread +{ +public: + OPJEncoThread(OPJCanvas *canvas); + + // thread execution starts here + virtual void *Entry(); + + // called when the thread exits - whether it terminates normally or is + // stopped with Delete() (but not when it is Kill()ed!) + virtual void OnExit(); + + // write something to the text control + void WriteText(const wxString& text); + +public: + unsigned m_count; + OPJCanvas *m_canvas; +}; + +class OPJDecoThread : public wxThread +{ +public: + OPJDecoThread(OPJCanvas *canvas); + + // thread execution starts here + virtual void *Entry(); + + // called when the thread exits - whether it terminates normally or is + // stopped with Delete() (but not when it is Kill()ed!) + virtual void OnExit(); + + // write something to the text control + void WriteText(const wxString& text); + +public: + unsigned m_count; + OPJCanvas *m_canvas; +}; + +class OPJParseThread : public wxThread +{ +public: + OPJParseThread(OPJMarkerTree *tree, wxTreeItemId parentid = 0x00); + + // thread execution starts here + virtual void *Entry(); + + // called when the thread exits - whether it terminates normally or is + // stopped with Delete() (but not when it is Kill()ed!) + virtual void OnExit(); + + // write something to the text control + void WriteText(const wxString& text); + void LoadFile(wxFileName fname); + void ParseJ2KFile(wxFile *m_file, wxFileOffset offset, wxFileOffset length, + wxTreeItemId parentid); + void ParseJP2File(wxFile *fileid, wxFileOffset filepoint, + wxFileOffset filelimit, wxTreeItemId parentid); + + unsigned m_count; + OPJMarkerTree *m_tree; + wxTreeItemId m_parentid; + +private: + int jpeg2000parse(wxFile *fileid, wxFileOffset filepoint, + wxFileOffset filelimit, + wxTreeItemId parentid, int level, char *scansign, unsigned long int *scanpoint); + int box_handler_function(int boxtype, wxFile *fileid, wxFileOffset filepoint, + wxFileOffset filelimit, + wxTreeItemId parentid, int level, char *scansign, unsigned long int *scanpoint); + +}; + + +// Drag and drop files target +class OPJDnDFile: public wxFileDropTarget +{ +public: + OPJDnDFile(OPJFrame *pOwner) + { + m_pOwner = pOwner; + } + virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames); + +private: + OPJFrame *m_pOwner; +}; + + + +// Property sheet dialog: encoder +class OPJEncoderDialog: public wxPropertySheetDialog +{ + DECLARE_CLASS(OPJEncoderDialog) +public: + OPJEncoderDialog(wxWindow* parent, int dialogType); + ~OPJEncoderDialog(); + + wxBookCtrlBase* m_settingsNotebook; + + wxPanel* CreateMainSettingsPage(wxWindow* parent); + wxPanel* CreatePart1_1SettingsPage(wxWindow* parent); + wxPanel* CreatePart1_2SettingsPage(wxWindow* parent); + /* wxPanel* CreatePart3SettingsPage(wxWindow* parent);*/ + void OnEnableComm(wxCommandEvent& event); + void OnEnableIdx(wxCommandEvent& event); + void OnEnablePoc(wxCommandEvent& event); + void OnRadioQualityRate(wxCommandEvent& event); +#ifdef USE_JPWL + void OnEnableJPWL(wxCommandEvent& event); + wxPanel* CreatePart11SettingsPage(wxWindow* parent); + /*wxCheckBox *m_enablejpwlCheck;*/ + wxChoice *m_hprotChoice[MYJPWL_MAX_NO_TILESPECS]; + wxSpinCtrl *m_htileCtrl[MYJPWL_MAX_NO_TILESPECS]; + wxChoice *m_pprotChoice[MYJPWL_MAX_NO_TILESPECS]; + wxSpinCtrl *m_ptileCtrl[MYJPWL_MAX_NO_TILESPECS]; + wxSpinCtrl *m_ppackCtrl[MYJPWL_MAX_NO_TILESPECS]; + wxChoice *m_sensiChoice[MYJPWL_MAX_NO_TILESPECS]; + wxSpinCtrl *m_stileCtrl[MYJPWL_MAX_NO_TILESPECS]; + void OnHprotSelect(wxCommandEvent& event); + void OnPprotSelect(wxCommandEvent& event); + void OnSensiSelect(wxCommandEvent& event); +#endif // USE_JPWL + + wxTextCtrl *m_subsamplingCtrl, *m_originCtrl, *m_rateCtrl, *m_commentCtrl; + wxRadioButton *m_rateRadio, *m_qualityRadio; + wxTextCtrl *m_indexCtrl, *m_qualityCtrl, *m_cbsizeCtrl, *m_prsizeCtrl, + *m_pocCtrl; + wxTextCtrl *m_tsizeCtrl, *m_toriginCtrl; + wxRadioBox *progressionBox; + wxCheckBox *m_enablecommCheck, *m_enableidxCheck, *m_mctCheck, *m_irrevCheck; + wxCheckBox *m_sopCheck, *m_ephCheck, *m_enablebypassCheck, *m_enableresetCheck, + *m_enablerestartCheck, *m_enablevscCheck, *m_enableertermCheck, + *m_enablesegmarkCheck; + wxCheckBox *m_enablepocCheck, *m_enablejpwlCheck; + wxSpinCtrl *m_resolutionsCtrl; + +protected: + + enum { + OPJENCO_ENABLEJPWL = 100, + OPJENCO_RATEFACTOR, + OPJENCO_RATERADIO, + OPJENCO_QUALITYFACTOR, + OPJENCO_QUALITYRADIO, + OPJENCO_RESNUMBER, + OPJENCO_CODEBLOCKSIZE, + OPJENCO_PRECINCTSIZE, + OPJENCO_TILESIZE, + OPJENCO_PROGRESSION, + OPJENCO_SUBSAMPLING, + OPJENCO_ENABLESOP, + OPJENCO_ENABLEEPH, + OPJENCO_ENABLEBYPASS, + OPJENCO_ENABLERESET, + OPJENCO_ENABLERESTART, + OPJENCO_ENABLEVSC, + OPJENCO_ENABLEERTERM, + OPJENCO_ENABLESEGMARK, + OPJENCO_ENABLEPOC, + OPJENCO_ROICOMP, + OPJENCO_ROISHIFT, + OPJENCO_IMORIG, + OPJENCO_TILORIG, + OPJENCO_ENABLEMCT, + OPJENCO_ENABLEIRREV, + OPJENCO_ENABLEINDEX, + OPJENCO_INDEXNAME, + OPJENCO_POCSPEC, + OPJENCO_ENABLECOMM, + OPJENCO_COMMENTTEXT, + OPJENCO_HPROT, + OPJENCO_HTILE, + OPJENCO_PPROT, + OPJENCO_PTILE, + OPJENCO_PPACK, + OPJENCO_SENSI, + OPJENCO_STILE + }; + + DECLARE_EVENT_TABLE() +}; + +// Property sheet dialog: decoder +class OPJDecoderDialog: public wxPropertySheetDialog +{ + DECLARE_CLASS(OPJDecoderDialog) +public: + OPJDecoderDialog(wxWindow* parent, int dialogType); + ~OPJDecoderDialog(); + + wxBookCtrlBase* m_settingsNotebook; + wxCheckBox *m_enabledecoCheck, *m_enableparseCheck; + wxSpinCtrl *m_reduceCtrl, *m_layerCtrl, *m_numcompsCtrl; + wxRadioBox* m_resizeBox; + + void OnEnableDeco(wxCommandEvent& event); + + wxPanel* CreateMainSettingsPage(wxWindow* parent); + wxPanel* CreatePart1SettingsPage(wxWindow* parent); + wxPanel* CreatePart3SettingsPage(wxWindow* parent); +#ifdef USE_JPWL + void OnEnableJPWL(wxCommandEvent& event); + wxPanel* CreatePart11SettingsPage(wxWindow* parent); + wxSpinCtrl *m_expcompsCtrl, *m_maxtilesCtrl; + wxCheckBox *m_enablejpwlCheck; +#endif // USE_JPWL + wxSpinCtrl *m_framenumCtrl; + + +protected: + + enum { + OPJDECO_RESMETHOD = 100, + OPJDECO_REDUCEFACTOR, + OPJDECO_QUALITYLAYERS, + OPJDECO_NUMCOMPS, + OPJDECO_ENABLEDECO, + OPJDECO_ENABLEPARSE, + OPJDECO_ENABLEJPWL, + OPJDECO_EXPCOMPS, + OPJDECO_MAXTILES, + OPJDECO_FRAMENUM + }; + + DECLARE_EVENT_TABLE() +}; + +#endif //__OPJ_VIEWER_H__ + + + diff --git a/openjpeg/src/bin/wx/OPJViewer/source/OPJViewer.ico b/openjpeg/src/bin/wx/OPJViewer/source/OPJViewer.ico Binary files differnew file mode 100644 index 000000000..931d5e021 --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/OPJViewer.ico diff --git a/openjpeg/src/bin/wx/OPJViewer/source/OPJViewer.rc b/openjpeg/src/bin/wx/OPJViewer/source/OPJViewer.rc new file mode 100644 index 000000000..82af985bb --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/OPJViewer.rc @@ -0,0 +1,3 @@ +OPJChild16 ICON OPJChild.ico +OPJViewer16 ICON OPJViewer.ico +#include "wx/msw/wx.rc"
\ No newline at end of file diff --git a/openjpeg/src/bin/wx/OPJViewer/source/OPJViewer16.xpm b/openjpeg/src/bin/wx/OPJViewer/source/OPJViewer16.xpm new file mode 100644 index 000000000..7c65acb38 --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/OPJViewer16.xpm @@ -0,0 +1,26 @@ +/* XPM */ +static char *OPJViewer16[] = { +/* columns rows colors chars-per-pixel */ +"16 16 4 1", +" c black", +". c #800000", +"X c red", +"o c None", +/* pixels */ +"oooooooooooooooo", +"ooo.XXXXoooooooo", +"ooXXoo .Xooooooo", +"o..oooo .ooooooo", +"oX.oooo ooooooo", +"oX.oooo .ooooooo", +"oXXoooo .ooooooo", +"o.XXoo .oooooooo", +"oo.XXXXooooooooo", +"ooooooooo.Xo .oo", +"ooooooooo X. ooo", +"oooooooooo...ooo", +"oooooooooo XXooo", +"oooooooooo .Xooo", +"oooooooooooooooo", +"oooooooooooooooo" +}; diff --git a/openjpeg/src/bin/wx/OPJViewer/source/about_htm.h b/openjpeg/src/bin/wx/OPJViewer/source/about_htm.h new file mode 100644 index 000000000..2d5dec272 --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/about_htm.h @@ -0,0 +1,56 @@ +wxString htmlaboutpage = wxT( + "<html>" + "<body bgcolor=#FFFFFF>" + "<table cellspacing=7 cellpadding=1 border=0 width=100%>" + "<tr>" + "<td rowspan=3 valign=top align=center width=70>" + "<img src=\"memory:opj_logo.xpm\"><br><br>" + "</td>" + "<td align=center>" + "<font size=+0 color=#000000><b>" + OPJ_APPLICATION " " OPJ_APPLICATION_VERSION + "</b></font><br>" + "<font size=-1 color=#000000><b>A JPEG 2000 image viewer</b></font><br>" + "<font size=-2 color=#000000><b>" OPJ_APPLICATION_PLATFORM " version</b></font>" + "</td>" + "</tr>" + "<tr height=3 valign=center>" + "<td valign=center bgcolor=#cc3300></td>" + "</tr>" + "<tr>" + "<td align=justify>" + "<center><font size=+0 color=#000000><a href=\"http://www.openjpeg.org/\">OpenJPEG</a></font></center>" + "<p><font size=-1 color=#000000>The OpenJPEG library is an open-source JPEG 2000 codec written in C language. " + "In addition to the basic codec, various other features are under development.</font></p><br>" + "<font size=-2 color=red>* Build: ") +#include "build.h" + wxT(", " __DATE__ ", " __TIME__ "</font><br>") + wxT("<font size=-2 color=red>* " wxVERSION_STRING "</font><br>") + wxT("<font size=-2 color=red>* OpenJPEG " OPENJPEG_VERSION " (") +#ifdef USE_JPWL + wxT("<font size=-2 color=green>JPWL</font> ") +#endif // USE_JPWL +#ifdef USE_JPSEC + wxT("<font size=-2 color=green>JPSEC</font> ") +#endif // USE_JPSEC + wxT(")</font><br>") +#ifdef USE_MXF + wxT("<font size=-2 color=red>* MXFLib " MXFLIB_VERSION_MAJOR "." + MXFLIB_VERSION_MINOR "." MXFLIB_VERSION_TWEAK " (" MXFLIB_VERSION_BUILD + ")</font><br>") +#endif // USE_MXF + wxT("</td>" + "</tr>" + "<tr>" + "<td colspan=2 bgcolor=#CC3300 height=3 valign=center></td>" + "</tr>" + "<tr>" + "<td colspan=2>" + "<font size=-2 color=#444444>OpenJPEG is © 2002-2008 <a href=\"http://www.tele.ucl.ac.be/\">TELE</a> - <a href=\"http://www.uclouvain.be/\">Universite' Catholique de Louvain</a></font><br>" + "<font size=-2 color=#444444>OPJViewer is © 2007-2008 <a href=\"http://dsplab.diei.unipg.it/\">DSPLab</a> - <a href=\"http://www.unipg.it/\">Universita' degli studi di Perugia</a></font>" + "</td>" + "</tr>" + "</table>" + "</body>" + "</html>" + ); diff --git a/openjpeg/src/bin/wx/OPJViewer/source/build.h b/openjpeg/src/bin/wx/OPJViewer/source/build.h new file mode 100644 index 000000000..d49d58b62 --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/build.h @@ -0,0 +1 @@ +wxT("491") diff --git a/openjpeg/src/bin/wx/OPJViewer/source/icon1.xpm b/openjpeg/src/bin/wx/OPJViewer/source/icon1.xpm new file mode 100644 index 000000000..69131fb53 --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/icon1.xpm @@ -0,0 +1,79 @@ +/* XPM */ +static const char *icon1_xpm[] = { +/* columns rows colors chars-per-pixel */ +"32 32 41 1", +"> c #97C4E7", +"# c #4381AA", +"d c #FFFFFF", +"< c #71B2DE", +"+ c #538BB1", +"& c #D1E5F5", +"q c #63B3DE", +"6 c #F1F4F7", +"* c #CAE1F3", +"y c #7AC4E5", +"= c #C3DDF1", +"X c #74A1BD", +"- c #BCD9EF", +"5 c #619BC4", +"3 c #E6EAF1", +"2 c #4B8EBF", +"o c #6B97B6", +". c #4B82A8", +" c None", +"w c #54A6D8", +"1 c #71A8D1", +", c #85BBE2", +"t c #EFF6FC", +"7 c #DEEDF8", +"@ c #4388B4", +"a c #F7FBFD", +"$ c #D7E0E9", +"r c #FAFCFE", +"4 c #DAEAF7", +"e c #E9F3FA", +"0 c #76BAE2", +"% c #7FA6C0", +"s c #FDFDFE", +"O c #5896BE", +"p c #B6D5EE", +"8 c #87ABC3", +": c #A5CCEA", +"9 c #E5F0F9", +"; c #AFD1EC", +"i c #F4F9FD", +"u c #8FB0C3", +/* pixels */ +" ", +" ", +" ", +" ", +" ", +" .XXXooOO++@#$ ", +" %&*=-;:>>,<123 ", +" %4&*=-;:>>,1>56 ", +" %74&*=-;:>>1*>56 ", +" 89700qqqqwq1e*>X ", +" 8e974&*=-;:1re*>8 ", +" 8te974&*=-;11111# ", +" 8tty000qqqqqww>,+ ", +" uitte974&*=-p:>>+ ", +" uaitte974&*=-p:>O ", +" uaayyyy000qqqqp:O ", +" uraaitte974&*=-po ", +" urraaitte974&*=-o ", +" usryyyyyyy000q*=X ", +" ussrraaitte974&*X ", +" udssrraaitte974&X ", +" uddyyyyyyyyyy074% ", +" udddssrraaitte97% ", +" uddddssrraaitte9% ", +" udddddssrraaitte8 ", +" uddddddssrraaitt8 ", +" uuuuuuuuuuuuuu88u ", +" ", +" ", +" ", +" ", +" " +}; diff --git a/openjpeg/src/bin/wx/OPJViewer/source/icon2.xpm b/openjpeg/src/bin/wx/OPJViewer/source/icon2.xpm new file mode 100644 index 000000000..cb8f10321 --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/icon2.xpm @@ -0,0 +1,53 @@ +/* XPM */ +static const char *icon2_xpm[] = { +/* columns rows colors chars-per-pixel */ +"32 32 15 1", +". c Black", +"O c #97C4E7", +"$ c #63B3DE", +"@ c #CAE1F3", +"; c #7AC4E5", +"* c #74A1BD", +"+ c #619BC4", +"o c #4B8EBF", +" c None", +"% c #54A6D8", +"= c #FAFCFE", +"& c #E9F3FA", +"# c #76BAE2", +"X c #C00000", +"- c #87ABC3", +/* pixels */ +" ", +" ", +" ", +" ", +" ", +" ............. ", +" .XXXXXXXXXX.o. ", +" .XXXXXXXXXX.O+. ", +" .XXXXXXXXXX.@O+. ", +" .XX##$$$$%$.&@O* ", +" .XXXXXXXXXX.=&@O- ", +" .XXXXXXXXXX...... ", +" .XX;###$$$$$%%XX. ", +" .XXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXX. ", +" .XX;;;;###$$$$XX. ", +" .XXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXX. ", +" .XX;;;;;;;###$XX. ", +" .XXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXX. ", +" .XX;;;;;;;;;;#XX. ", +" .XXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXX. ", +" ................. ", +" ", +" ", +" ", +" ", +" " +}; diff --git a/openjpeg/src/bin/wx/OPJViewer/source/icon3.xpm b/openjpeg/src/bin/wx/OPJViewer/source/icon3.xpm new file mode 100644 index 000000000..ddfa18b9d --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/icon3.xpm @@ -0,0 +1,79 @@ +/* XPM */ +static const char *icon3_xpm[] = { +/* columns rows colors chars-per-pixel */ +"32 32 41 1", +"6 c #EDF2FB", +"- c #AAC1E8", +": c #B9CDED", +"X c #295193", +", c #C6D6F0", +"a c #4A7CCE", +"u c #779DDB", +"y c #7FA2DD", +"$ c #3263B4", +"5 c #EAF0FA", +". c #2D59A3", +"o c #6E96D8", +"* c #356AC1", +"r c #F7F9FD", +"> c #BED0EE", +"3 c #E1E9F7", +"7 c #F0F5FC", +"< c #CBD9F1", +"2 c #DAE5F6", +"# c #3161B1", +" c None", +"0 c #FDFEFF", +"= c #9FB9E5", +"e c #AEC5EA", +"t c #89A9DF", +"q c #98B5E4", +"p c #5584D1", +"d c #3A70CA", +"@ c #305FAC", +"i c #5D89D3", +"1 c #D2DFF4", +"% c #3366B9", +"9 c #FAFCFE", +"8 c #F5F8FD", +"s c #4075CC", +"O c #638ED5", +"w c #90AFE2", +"& c #3467BC", +"+ c #2F5DA9", +"; c #B3C8EB", +"4 c #E5EDF9", +/* pixels */ +" ", +" ", +" ", +" ", +" ", +" ", +" ......X ", +" .oooooO+ ", +" .ooooooo. ", +" .+@@@##$%%&&&&&****. ", +" .=-;:>,<12345678900. ", +" .q=-;:>,<1234567890. ", +" .wq=-e:>,<12345678r. ", +" .twq=-e:>,<12345678. ", +" .ytwq=-e:>,<1234567. ", +" .uytwq=-e:>,<123456. ", +" .ouytwq=-e:>,<12345. ", +" .Oouytwq=-e;>,<1234. ", +" .iOouytwq=-e;>,<123. ", +" .piOouytwq=-e;>,<12. ", +" .apiOouytwq=-e;>,<1. ", +" .sapiOouytwq=-e;>,<. ", +" .dsapiOouytwq=-e;>,. ", +" ...................# ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" " +}; diff --git a/openjpeg/src/bin/wx/OPJViewer/source/icon4.xpm b/openjpeg/src/bin/wx/OPJViewer/source/icon4.xpm new file mode 100644 index 000000000..37f95798d --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/icon4.xpm @@ -0,0 +1,43 @@ +/* XPM */ +static const char *icon4_xpm[] = { +/* columns rows colors chars-per-pixel */ +"32 32 5 1", +". c Black", +"o c #8399B4", +"X c #8DA0B9", +" c None", +"O c #800000", +/* pixels */ +" ", +" ", +" ", +" ", +" ", +" ", +" ....... ", +" .XXXXXo. ", +" .XXXXXXX. ", +" .................... ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .OOOOOOOOOOOOOOOOOO. ", +" .................... ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" " +}; diff --git a/openjpeg/src/bin/wx/OPJViewer/source/icon5.xpm b/openjpeg/src/bin/wx/OPJViewer/source/icon5.xpm new file mode 100644 index 000000000..d4e8b1182 --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/icon5.xpm @@ -0,0 +1,79 @@ +/* XPM */ +static const char *icon5_xpm[] = { +/* columns rows colors chars-per-pixel */ +"32 32 41 1", +"0 c #AAC1E8", +"q c #B9CDED", +"X c #295193", +"e c #C6D6F0", +"a c #4A7CCE", +"& c #779DDB", +"* c #7FA2DD", +"2 c #EAF0FA", +"@ c #2D59A3", +"o c #6E96D8", +"y c #356AC1", +"d c #214279", +"w c #BED0EE", +"= c #85A7DF", +"< c #E1E9F7", +"3 c #F0F5FC", +"s c #CBD9F1", +", c #DAE5F6", +"7 c #3161B1", +" c None", +". c #274D8B", +"6 c #FDFEFF", +"i c #E7EEF9", +"9 c #9FB9E5", +"- c #89A9DF", +"8 c #98B5E4", +"$ c #5584D1", +"+ c #3569BF", +"% c #305FAC", +"O c #5D89D3", +"> c #D2DFF4", +"p c #3366B9", +"5 c #FAFCFE", +"4 c #F5F8FD", +"t c #4075CC", +"u c #638ED5", +"r c #CEDCF2", +"; c #90AFE2", +"# c #2F5DA9", +": c #B3C8EB", +"1 c #E5EDF9", +/* pixels */ +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ......X ", +" XoooooO. ", +" Xoooooo+. ", +" Xooooooo@XXXXXXXXXX# ", +" Xoooooooooooooooooo# ", +" Xoooooooooooooooooo# ", +" Xoo$################### ", +" Xoo%O&*=-;:>,<123445667 ", +" XooX890:qwer>,<123445q# ", +" Xoty;890:qwer>,<12344# ", +" Xo%u-;890:qwer>,<i234# ", +" XoX&*-;890:qwer>,<i2r# ", +" Xtpo&*-;890:qwer>,<i# ", +" X%auo&*-;890:qwer>,<# ", +" XX$Ouo&*-;890:qwer>s# ", +" d%a$Ouo&*-;890:qwer# ", +" d+ta$Ouo&*-;890:qwe# ", +" d..................# ", +" ", +" ", +" ", +" ", +" ", +" ", +" " +}; diff --git a/openjpeg/src/bin/wx/OPJViewer/source/imagjpeg2000.cpp b/openjpeg/src/bin/wx/OPJViewer/source/imagjpeg2000.cpp new file mode 100644 index 000000000..9e1ab90dc --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/imagjpeg2000.cpp @@ -0,0 +1,1595 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2007, Digital Signal Processing Laboratory, Università degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +///////////////////////////////////////////////////////////////////////////// +// Name: imagjpeg2000.cpp +// Purpose: wxImage JPEG 2000 family file format handler +// Author: Giuseppe Baruffa - based on imagjpeg.cpp, Vaclav Slavik +// RCS-ID: $Id: imagjpeg2000.cpp,v 0.00 2008/01/31 10:58:00 MW Exp $ +// Copyright: (c) Giuseppe Baruffa +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_LIBOPENJPEG + +#include "imagjpeg2000.h" + +#ifndef WX_PRECOMP +#include "wx/log.h" +#include "wx/app.h" +#include "wx/intl.h" +#include "wx/bitmap.h" +#include "wx/module.h" +#endif + +#include "openjp2/openjpeg.h" + +#include "wx/filefn.h" +#include "wx/wfstream.h" + +// ---------------------------------------------------------------------------- +// types +// ---------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// wxJPEG2000Handler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxJPEG2000Handler, wxImageHandler) + +#if wxUSE_STREAMS + +//------------- JPEG 2000 Data Source Manager + +#define J2K_CFMT 0 +#define JP2_CFMT 1 +#define JPT_CFMT 2 +#define MJ2_CFMT 3 +#define PXM_DFMT 0 +#define PGX_DFMT 1 +#define BMP_DFMT 2 +#define YUV_DFMT 3 + +#define MAX_MESSAGE_LEN 200 + +/* check file type */ +int +jpeg2000familytype(unsigned char *hdr, int hdr_len) +{ + // check length + if (hdr_len < 24) { + return -1; + } + + // check format + if (hdr[0] == 0x00 && + hdr[1] == 0x00 && + hdr[2] == 0x00 && + hdr[3] == 0x0C && + hdr[4] == 0x6A && + hdr[5] == 0x50 && + hdr[6] == 0x20 && + hdr[7] == 0x20 && + hdr[20] == 0x6A && + hdr[21] == 0x70 && + hdr[22] == 0x32) + // JP2 file format + { + return JP2_CFMT; + } else if (hdr[0] == 0x00 && + hdr[1] == 0x00 && + hdr[2] == 0x00 && + hdr[3] == 0x0C && + hdr[4] == 0x6A && + hdr[5] == 0x50 && + hdr[6] == 0x20 && + hdr[7] == 0x20 && + hdr[20] == 0x6D && + hdr[21] == 0x6A && + hdr[22] == 0x70 && + hdr[23] == 0x32) + // MJ2 file format + { + return MJ2_CFMT; + } else if (hdr[0] == 0xFF && + hdr[1] == 0x4F) + // J2K file format + { + return J2K_CFMT; + } else + // unknown format + { + return -1; + } + +} + +/* we have to use this to avoid GUI-noGUI threads crashing */ +void printevent(const char *msg) +{ +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif /* __WXGTK__ */ + wxLogMessage(wxT("%s"), msg); +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif /* __WXGTK__ */ +} + +/* sample error callback expecting a FILE* client object */ +void jpeg2000_error_callback(const char *msg, void *client_data) +{ + char mess[MAX_MESSAGE_LEN + 20]; + int message_len = strlen(msg); + + if (message_len > MAX_MESSAGE_LEN) { + message_len = MAX_MESSAGE_LEN; + } + + if (msg[message_len - 1] == '\n') { + message_len--; + } + + sprintf(mess, "[ERROR] %.*s", message_len, msg); + printevent(mess); +} + +/* sample warning callback expecting a FILE* client object */ +void jpeg2000_warning_callback(const char *msg, void *client_data) +{ + char mess[MAX_MESSAGE_LEN + 20]; + int message_len = strlen(msg); + + if (message_len > MAX_MESSAGE_LEN) { + message_len = MAX_MESSAGE_LEN; + } + + if (msg[message_len - 1] == '\n') { + message_len--; + } + + sprintf(mess, "[WARNING] %.*s", message_len, msg); + printevent(mess); +} + +/* sample debug callback expecting no client object */ +void jpeg2000_info_callback(const char *msg, void *client_data) +{ + char mess[MAX_MESSAGE_LEN + 20]; + int message_len = strlen(msg); + + if (message_len > MAX_MESSAGE_LEN) { + message_len = MAX_MESSAGE_LEN; + } + + if (msg[message_len - 1] == '\n') { + message_len--; + } + + sprintf(mess, "[INFO] %.*s", message_len, msg); + printevent(mess); +} + +/* macro functions */ +/* From little endian to big endian, 2 and 4 bytes */ +#define BYTE_SWAP2(X) ((X & 0x00FF) << 8) | ((X & 0xFF00) >> 8) +#define BYTE_SWAP4(X) ((X & 0x000000FF) << 24) | ((X & 0x0000FF00) << 8) | ((X & 0x00FF0000) >> 8) | ((X & 0xFF000000) >> 24) + +#ifdef __WXGTK__ +#define BYTE_SWAP8(X) ((X & 0x00000000000000FFULL) << 56) | ((X & 0x000000000000FF00ULL) << 40) | \ + ((X & 0x0000000000FF0000ULL) << 24) | ((X & 0x00000000FF000000ULL) << 8) | \ + ((X & 0x000000FF00000000ULL) >> 8) | ((X & 0x0000FF0000000000ULL) >> 24) | \ + ((X & 0x00FF000000000000ULL) >> 40) | ((X & 0xFF00000000000000ULL) >> 56) +#else +#define BYTE_SWAP8(X) ((X & 0x00000000000000FF) << 56) | ((X & 0x000000000000FF00) << 40) | \ + ((X & 0x0000000000FF0000) << 24) | ((X & 0x00000000FF000000) << 8) | \ + ((X & 0x000000FF00000000) >> 8) | ((X & 0x0000FF0000000000) >> 24) | \ + ((X & 0x00FF000000000000) >> 40) | ((X & 0xFF00000000000000) >> 56) +#endif + +/* From codestream to int values */ +#define STREAM_TO_UINT32(C, P) (((unsigned long int) (C)[(P) + 0] << 24) + \ + ((unsigned long int) (C)[(P) + 1] << 16) + \ + ((unsigned long int) (C)[(P) + 2] << 8) + \ + ((unsigned long int) (C)[(P) + 3] << 0)) + +#define STREAM_TO_UINT16(C, P) (((unsigned long int) (C)[(P) + 0] << 8) + \ + ((unsigned long int) (C)[(P) + 1] << 0)) + +/* defines */ +#define SHORT_DESCR_LEN 32 +#define LONG_DESCR_LEN 256 + +/* enumeration for file formats */ +#define JPEG2000FILENUM 4 +typedef enum { + + JP2_FILE, + J2K_FILE, + MJ2_FILE, + UNK_FILE + +} jpeg2000filetype; + +/* enumeration for the box types */ +#define JPEG2000BOXNUM 23 +typedef enum { + + FILE_BOX, + JP_BOX, + FTYP_BOX, + JP2H_BOX, + IHDR_BOX, + COLR_BOX, + JP2C_BOX, + JP2I_BOX, + XML_BOX, + UUID_BOX, + UINF_BOX, + MOOV_BOX, + MVHD_BOX, + TRAK_BOX, + TKHD_BOX, + MDIA_BOX, + MINF_BOX, + STBL_BOX, + STSD_BOX, + MJP2_BOX, + MDAT_BOX, + ANY_BOX, + UNK_BOX + +} jpeg2000boxtype; + +/* jpeg2000 family box signatures */ +#define FILE_SIGN "" +#define JP_SIGN "jP\040\040" +#define FTYP_SIGN "ftyp" +#define JP2H_SIGN "jp2h" +#define IHDR_SIGN "ihdr" +#define COLR_SIGN "colr" +#define JP2C_SIGN "jp2c" +#define JP2I_SIGN "jp2i" +#define XML_SIGN "xml\040" +#define UUID_SIGN "uuid" +#define UINF_SIGN "uinf" +#define MOOV_SIGN "moov" +#define MVHD_SIGN "mvhd" +#define TRAK_SIGN "trak" +#define TKHD_SIGN "tkhd" +#define MDIA_SIGN "mdia" +#define MINF_SIGN "minf" +#define VMHD_SIGN "vmhd" +#define STBL_SIGN "stbl" +#define STSD_SIGN "stsd" +#define MJP2_SIGN "mjp2" +#define MDAT_SIGN "mdat" +#define ANY_SIGN "" +#define UNK_SIGN "" + +/* the box structure itself */ +struct jpeg2000boxdef { + + char value[5]; /* hexadecimal value/string*/ + char name[SHORT_DESCR_LEN]; /* short description */ + char descr[LONG_DESCR_LEN]; /* long description */ + int sbox; /* is it a superbox? */ + int req[JPEG2000FILENUM]; /* mandatory box */ + jpeg2000boxtype ins; /* contained in box... */ + +}; + +/* the possible boxes */ +struct jpeg2000boxdef jpeg2000box[] = { + /* sign */ { + FILE_SIGN, + /* short */ "placeholder for nothing", + /* long */ "Nothing to say", + /* sbox */ 0, + /* req */ {1, 1, 1}, + /* ins */ FILE_BOX + }, + + /* sign */ { + JP_SIGN, + /* short */ "JPEG 2000 Signature box", + /* long */ "This box uniquely identifies the file as being part of the JPEG 2000 family of files", + /* sbox */ 0, + /* req */ {1, 1, 1}, + /* ins */ FILE_BOX + }, + + /* sign */ { + FTYP_SIGN, + /* short */ "File Type box", + /* long */ "This box specifies file type, version and compatibility information, including specifying if this file " + "is a conforming JP2 file or if it can be read by a conforming JP2 reader", + /* sbox */ 0, + /* req */ {1, 1, 1}, + /* ins */ FILE_BOX + }, + + /* sign */ { + JP2H_SIGN, + /* short */ "JP2 Header box", + /* long */ "This box contains a series of boxes that contain header-type information about the file", + /* sbox */ 1, + /* req */ {1, 1, 1}, + /* ins */ FILE_BOX + }, + + /* sign */ { + IHDR_SIGN, + /* short */ "Image Header box", + /* long */ "This box specifies the size of the image and other related fields", + /* sbox */ 0, + /* req */ {1, 1, 1}, + /* ins */ JP2H_BOX + }, + + /* sign */ { + COLR_SIGN, + /* short */ "Colour Specification box", + /* long */ "This box specifies the colourspace of the image", + /* sbox */ 0, + /* req */ {1, 1, 1}, + /* ins */ JP2H_BOX + }, + + /* sign */ { + JP2C_SIGN, + /* short */ "Contiguous Codestream box", + /* long */ "This box contains the codestream as defined by Annex A", + /* sbox */ 0, + /* req */ {1, 1, 1}, + /* ins */ FILE_BOX + }, + + /* sign */ { + JP2I_SIGN, + /* short */ "Intellectual Property box", + /* long */ "This box contains intellectual property information about the image", + /* sbox */ 0, + /* req */ {0, 0, 0}, + /* ins */ FILE_BOX + }, + + /* sign */ { + XML_SIGN, + /* short */ "XML box", + /* long */ "This box provides a tool by which vendors can add XML formatted information to a JP2 file", + /* sbox */ 0, + /* req */ {0, 0, 0}, + /* ins */ FILE_BOX + }, + + /* sign */ { + UUID_SIGN, + /* short */ "UUID box", + /* long */ "This box provides a tool by which vendors can add additional information to a file " + "without risking conflict with other vendors", + /* sbox */ 0, + /* req */ {0, 0, 0}, + /* ins */ FILE_BOX + }, + + /* sign */ { + UINF_SIGN, + /* short */ "UUID Info box", + /* long */ "This box provides a tool by which a vendor may provide access to additional information associated with a UUID", + /* sbox */ 0, + /* req */ {0, 0, 0}, + /* ins */ FILE_BOX + }, + + /* sign */ { + MOOV_SIGN, + /* short */ "Movie box", + /* long */ "This box contains the media data. In video tracks, this box would contain JPEG2000 video frames", + /* sbox */ 1, + /* req */ {1, 1, 1}, + /* ins */ FILE_BOX + }, + + /* sign */ { + MVHD_SIGN, + /* short */ "Movie Header box", + /* long */ "This box defines overall information which is media-independent, and relevant to the entire presentation " + "considered as a whole", + /* sbox */ 0, + /* req */ {1, 1, 1}, + /* ins */ MOOV_BOX + }, + + /* sign */ { + TRAK_SIGN, + /* short */ "Track box", + /* long */ "This is a container box for a single track of a presentation. A presentation may consist of one or more tracks", + /* sbox */ 1, + /* req */ {1, 1, 1}, + /* ins */ MOOV_BOX + }, + + /* sign */ { + TKHD_SIGN, + /* short */ "Track Header box", + /* long */ "This box specifies the characteristics of a single track. Exactly one Track Header Box is contained in a track", + /* sbox */ 0, + /* req */ {1, 1, 1}, + /* ins */ TRAK_BOX + }, + + /* sign */ { + MDIA_SIGN, + /* short */ "Media box", + /* long */ "The media declaration container contains all the objects which declare information about the media data " + "within a track", + /* sbox */ 1, + /* req */ {1, 1, 1}, + /* ins */ TRAK_BOX + }, + + /* sign */ { + MINF_SIGN, + /* short */ "Media Information box", + /* long */ "This box contains all the objects which declare characteristic information of the media in the track", + /* sbox */ 1, + /* req */ {1, 1, 1}, + /* ins */ MDIA_BOX + }, + + /* sign */ { + STBL_SIGN, + /* short */ "Sample Table box", + /* long */ "The sample table contains all the time and data indexing of the media samples in a track", + /* sbox */ 1, + /* req */ {1, 1, 1}, + /* ins */ MINF_BOX + }, + + /* sign */ { + STSD_SIGN, + /* short */ "Sample Description box", + /* long */ "The sample description table gives detailed information about the coding type used, and any initialization " + "information needed for that coding", + /* sbox */ 0, + /* req */ {1, 1, 1}, + /* ins */ MINF_BOX + }, + + /* sign */ { + MJP2_SIGN, + /* short */ "MJP2 Sample Description box", + /* long */ "The MJP2 sample description table gives detailed information about the coding type used, and any initialization " + "information needed for that coding", + /* sbox */ 0, + /* req */ {1, 1, 1}, + /* ins */ MINF_BOX + }, + + /* sign */ { + MDAT_SIGN, + /* short */ "Media Data box", + /* long */ "The meta-data for a presentation is stored in the single Movie Box which occurs at the top-level of a file", + /* sbox */ 1, + /* req */ {1, 1, 1}, + /* ins */ FILE_BOX + }, + + /* sign */ { + ANY_SIGN, + /* short */ "Any box", + /* long */ "All the existing boxes", + /* sbox */ 0, + /* req */ {0, 0, 0}, + /* ins */ FILE_BOX + }, + + /* sign */ { + UNK_SIGN, + /* short */ "Unknown Type box", + /* long */ "The signature is not recognised to be that of an existing box", + /* sbox */ 0, + /* req */ {0, 0, 0}, + /* ins */ ANY_BOX + } + +}; + +/* declaration */ +int +jpeg2000_box_handler_function(jpeg2000boxtype boxtype, wxInputStream& stream, + unsigned long int filepoint, + unsigned long int filelimit, int level, char *scansign, + unsigned long int *scanpoint); + +#ifdef __WXMSW__ +typedef unsigned __int64 int8byte; +#endif // __WXMSW__ + +#ifdef __WXGTK__ +typedef unsigned long long int8byte; +#endif // __WXGTK__ + +/* internal mini-search for a box signature */ +int +jpeg2000_file_parse(wxInputStream& stream, unsigned long int filepoint, + unsigned long int filelimit, int level, + char *scansign, unsigned long int *scanpoint) +{ + unsigned long int LBox = 0x00000000; + char TBox[5] = "\0\0\0\0"; + int8byte XLBox = 0x0000000000000000; + unsigned long int box_length = 0; + int last_box = 0, box_num = 0; + int box_type = ANY_BOX; + unsigned char fourbytes[4]; + int box_number = 0; + + /* cycle all over the file */ + box_num = 0; + last_box = 0; + while (!last_box) { + + /* do not exceed file limit */ + if (filepoint >= filelimit) { + return (0); + } + + /* seek on file */ + if (stream.SeekI(filepoint, wxFromStart) == wxInvalidOffset) { + return (-1); + } + + /* read the mandatory LBox, 4 bytes */ + if (!stream.Read(fourbytes, 4)) { + wxLogError(wxT("Problem reading LBox from the file (file ended?)")); + return -1; + }; + LBox = STREAM_TO_UINT32(fourbytes, 0); + + /* read the mandatory TBox, 4 bytes */ + if (!stream.Read(TBox, 4)) { + wxLogError(wxT("Problem reading TBox from the file (file ended?)")); + return -1; + }; + + /* look if scansign is got */ + if ((scansign != NULL) && (memcmp(TBox, scansign, 4) == 0)) { + /* hack/exploit */ + // stop as soon as you find the level-th codebox + if (box_number == level) { + memcpy(scansign, " ", 4); + *scanpoint = filepoint; + return (0); + } else { + box_number++; + } + + }; + + /* determine the box type */ + for (box_type = JP_BOX; box_type < UNK_BOX; box_type++) + if (memcmp(TBox, jpeg2000box[box_type].value, 4) == 0) { + break; + } + + /* read the optional XLBox, 8 bytes */ + if (LBox == 1) { + + if (!stream.Read(&XLBox, 8)) { + wxLogError(wxT("Problem reading XLBox from the file (file ended?)")); + return -1; + }; + box_length = (unsigned long int) BYTE_SWAP8(XLBox); + + } else if (LBox == 0x00000000) { + + /* last box in file */ + last_box = 1; + box_length = filelimit - filepoint; + + } else + + { + box_length = LBox; + } + + + /* go deep in the box */ + jpeg2000_box_handler_function((jpeg2000boxtype) box_type, + stream, (LBox == 1) ? (filepoint + 16) : (filepoint + 8), + filepoint + box_length, level, scansign, scanpoint); + + /* if it's a superbox go inside it */ + if (jpeg2000box[box_type].sbox) + jpeg2000_file_parse(stream, (LBox == 1) ? (filepoint + 16) : (filepoint + 8), + filepoint + box_length, + level, scansign, scanpoint); + + /* increment box number and filepoint*/ + box_num++; + filepoint += box_length; + + }; + + /* all good */ + return (0); +} + +// search first contiguos codestream box in an mj2 file +unsigned long int +searchjpeg2000c(wxInputStream& stream, unsigned long int fsize, int number) +{ + char scansign[] = "jp2c"; + unsigned long int scanpoint = 0L; + + wxLogMessage(wxT("Searching jp2c box... ")); + + /* do the parsing */ + if (jpeg2000_file_parse(stream, 0, fsize, number, scansign, &scanpoint) < 0) { + wxLogMessage( + wxT("Unrecoverable error during JPEG 2000 box parsing: stopping")); + } + + if (strcmp(scansign, " ")) { + wxLogMessage(wxT("Box not found")); + } else { + + wxLogMessage(wxString::Format(wxT("Box found at byte %d"), scanpoint)); + + }; + + return (scanpoint); +} + +// search the jp2h box in the file +unsigned long int +searchjpeg2000headerbox(wxInputStream& stream, unsigned long int fsize) +{ + char scansign[] = "jp2h"; + unsigned long int scanpoint = 0L; + + wxLogMessage(wxT("Searching jp2h box... ")); + + /* do the parsing */ + if (jpeg2000_file_parse(stream, 0, fsize, 0, scansign, &scanpoint) < 0) { + wxLogMessage( + wxT("Unrecoverable error during JPEG 2000 box parsing: stopping")); + } + + if (strcmp(scansign, " ")) { + wxLogMessage(wxT("Box not found")); + } else { + wxLogMessage(wxString::Format(wxT("Box found at byte %d"), scanpoint)); + } + + return (scanpoint); +} + +/* handling functions */ +#define ITEM_PER_ROW 10 + +/* Box handler function */ +int +jpeg2000_box_handler_function(jpeg2000boxtype boxtype, wxInputStream& stream, + unsigned long int filepoint, + unsigned long int filelimit, int level, + char *scansign, unsigned long int *scanpoint) +{ + switch (boxtype) { + + /* Sample Description box */ + case (STSD_BOX): + jpeg2000_file_parse(stream, filepoint + 8, filelimit, level, scansign, + scanpoint); + break; + + /* MJP2 Sample Description box */ + case (MJP2_BOX): + jpeg2000_file_parse(stream, filepoint + 78, filelimit, level, scansign, + scanpoint); + break; + + /* not yet implemented */ + default: + break; + + }; + + return (0); +} + +// the jP and ftyp parts of the header +#define jpeg2000headSIZE 32 +unsigned char jpeg2000head[jpeg2000headSIZE] = { + 0x00, 0x00, 0x00, 0x0C, 'j', 'P', ' ', ' ', + 0x0D, 0x0A, 0x87, 0x0A, 0x00, 0x00, 0x00, 0x14, + 'f', 't', 'y', 'p', 'j', 'p', '2', ' ', + 0x00, 0x00, 0x00, 0x00, 'j', 'p', '2', ' ' +}; + +///////////////////////////////////////////////// +///////////////////////////////////////////////// + +// load the jpeg2000 file format +bool wxJPEG2000Handler::LoadFile(wxImage *image, wxInputStream& stream, + bool verbose, int index) +{ + opj_dparameters_t parameters; /* decompression parameters */ + opj_event_mgr_t event_mgr; /* event manager */ + opj_image_t *opjimage = NULL; + unsigned char *src = NULL; + unsigned char *ptr; + int file_length, jp2c_point, jp2h_point; + unsigned long int jp2hboxlen, jp2cboxlen; + opj_codestream_info_t cstr_info; /* Codestream information structure */ + unsigned char hdr[24]; + int jpfamform; + + // destroy the image + image->Destroy(); + + /* read the beginning of the file to check the type */ + if (!stream.Read(hdr, WXSIZEOF(hdr))) { + return false; + } + if ((jpfamform = jpeg2000familytype(hdr, WXSIZEOF(hdr))) < 0) { + return false; + } + stream.SeekI(0, wxFromStart); + + /* handle to a decompressor */ + opj_dinfo_t* dinfo = NULL; + opj_cio_t *cio = NULL; + + /* configure the event callbacks */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = jpeg2000_error_callback; + event_mgr.warning_handler = jpeg2000_warning_callback; + event_mgr.info_handler = jpeg2000_info_callback; + + /* set decoding parameters to default values */ + opj_set_default_decoder_parameters(¶meters); + + /* prepare parameters */ + strncpy(parameters.infile, "", sizeof(parameters.infile) - 1); + strncpy(parameters.outfile, "", sizeof(parameters.outfile) - 1); + parameters.decod_format = jpfamform; + parameters.cod_format = BMP_DFMT; + if (m_reducefactor) { + parameters.cp_reduce = m_reducefactor; + } + if (m_qualitylayers) { + parameters.cp_layer = m_qualitylayers; + } + /*if (n_components) + parameters. = n_components;*/ + + /* JPWL only */ +#ifdef USE_JPWL + parameters.jpwl_exp_comps = m_expcomps; + parameters.jpwl_max_tiles = m_maxtiles; + parameters.jpwl_correct = m_enablejpwl; +#endif /* USE_JPWL */ + + /* get a decoder handle */ + if (jpfamform == JP2_CFMT || jpfamform == MJ2_CFMT) { + dinfo = opj_create_decompress(CODEC_JP2); + } else if (jpfamform == J2K_CFMT) { + dinfo = opj_create_decompress(CODEC_J2K); + } else { + return false; + } + + /* find length of the stream */ + stream.SeekI(0, wxFromEnd); + file_length = (int) stream.TellI(); + + /* it's a movie */ + if (jpfamform == MJ2_CFMT) { + /* search for the first codestream box and the movie header box */ + jp2c_point = searchjpeg2000c(stream, file_length, m_framenum); + jp2h_point = searchjpeg2000headerbox(stream, file_length); + + // read the jp2h box and store it + stream.SeekI(jp2h_point, wxFromStart); + stream.Read(&jp2hboxlen, sizeof(unsigned long int)); + jp2hboxlen = BYTE_SWAP4(jp2hboxlen); + + // read the jp2c box and store it + stream.SeekI(jp2c_point, wxFromStart); + stream.Read(&jp2cboxlen, sizeof(unsigned long int)); + jp2cboxlen = BYTE_SWAP4(jp2cboxlen); + + // malloc memory source + src = (unsigned char *) malloc(jpeg2000headSIZE + jp2hboxlen + jp2cboxlen); + + // copy the jP and ftyp + memcpy(src, jpeg2000head, jpeg2000headSIZE); + + // copy the jp2h + stream.SeekI(jp2h_point, wxFromStart); + stream.Read(&src[jpeg2000headSIZE], jp2hboxlen); + + // copy the jp2c + stream.SeekI(jp2c_point, wxFromStart); + stream.Read(&src[jpeg2000headSIZE + jp2hboxlen], jp2cboxlen); + } else if (jpfamform == JP2_CFMT || jpfamform == J2K_CFMT) { + /* It's a plain image */ + /* get data */ + stream.SeekI(0, wxFromStart); + src = (unsigned char *) malloc(file_length); + stream.Read(src, file_length); + } else { + return false; + } + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + if (jpfamform == MJ2_CFMT) { + cio = opj_cio_open((opj_common_ptr)dinfo, src, + jpeg2000headSIZE + jp2hboxlen + jp2cboxlen); + } else if (jpfamform == JP2_CFMT || jpfamform == J2K_CFMT) { + cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); + } else { + free(src); + return false; + } + + /* decode the stream and fill the image structure */ + opjimage = opj_decode_with_info(dinfo, cio, &cstr_info); + if (!opjimage) { + wxMutexGuiEnter(); + wxLogError(wxT("JPEG 2000 failed to decode image!")); + wxMutexGuiLeave(); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + free(src); + return false; + } + + /* close the byte stream */ + opj_cio_close(cio); + + /* + + - At this point, we have the structure "opjimage" that is filled with decompressed + data, as processed by the OpenJPEG decompression engine + + - We need to fill the class "image" with the proper pixel sample values + + */ + { + int shiftbpp; + int c, tempcomps; + + // check components number + if (m_components > opjimage->numcomps) { + m_components = opjimage->numcomps; + } + + // check image depth (only on the first one, for now) + if (m_components) { + shiftbpp = opjimage->comps[m_components - 1].prec - 8; + } else { + shiftbpp = opjimage->comps[0].prec - 8; + } + + // prepare image size + if (m_components) { + image->Create(opjimage->comps[m_components - 1].w, + opjimage->comps[m_components - 1].h, true); + } else { + image->Create(opjimage->comps[0].w, opjimage->comps[0].h, true); + } + + // access image raw data + image->SetMask(false); + ptr = image->GetData(); + + // workaround for components different from 1 or 3 + if ((opjimage->numcomps != 1) && (opjimage->numcomps != 3)) { +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif /* __WXGTK__ */ + wxLogMessage(wxT("JPEG2000: weird number of components")); +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif /* __WXGTK__ */ + tempcomps = 1; + } else { + tempcomps = opjimage->numcomps; + } + + // workaround for subsampled components + for (c = 1; c < tempcomps; c++) { + if ((opjimage->comps[c].w != opjimage->comps[c - 1].w) || + (opjimage->comps[c].h != opjimage->comps[c - 1].h)) { + tempcomps = 1; + break; + } + } + + // workaround for different precision components + for (c = 1; c < tempcomps; c++) { + if (opjimage->comps[c].bpp != opjimage->comps[c - 1].bpp) { + tempcomps = 1; + break; + } + } + + // only one component selected + if (m_components) { + tempcomps = 1; + } + + // RGB color picture + if (tempcomps == 3) { + int row, col; + int *r = opjimage->comps[0].data; + int *g = opjimage->comps[1].data; + int *b = opjimage->comps[2].data; + if (shiftbpp > 0) { + for (row = 0; row < opjimage->comps[0].h; row++) { + for (col = 0; col < opjimage->comps[0].w; col++) { + + *(ptr++) = (*(r++)) >> shiftbpp; + *(ptr++) = (*(g++)) >> shiftbpp; + *(ptr++) = (*(b++)) >> shiftbpp; + + } + } + + } else if (shiftbpp < 0) { + for (row = 0; row < opjimage->comps[0].h; row++) { + for (col = 0; col < opjimage->comps[0].w; col++) { + + *(ptr++) = (*(r++)) << -shiftbpp; + *(ptr++) = (*(g++)) << -shiftbpp; + *(ptr++) = (*(b++)) << -shiftbpp; + + } + } + + } else { + for (row = 0; row < opjimage->comps[0].h; row++) { + for (col = 0; col < opjimage->comps[0].w; col++) { + + *(ptr++) = *(r++); + *(ptr++) = *(g++); + *(ptr++) = *(b++); + + } + } + } + } + + // B/W picture + if (tempcomps == 1) { + int row, col; + int selcomp; + + if (m_components) { + selcomp = m_components - 1; + } else { + selcomp = 0; + } + + int *y = opjimage->comps[selcomp].data; + if (shiftbpp > 0) { + for (row = 0; row < opjimage->comps[selcomp].h; row++) { + for (col = 0; col < opjimage->comps[selcomp].w; col++) { + + *(ptr++) = (*(y)) >> shiftbpp; + *(ptr++) = (*(y)) >> shiftbpp; + *(ptr++) = (*(y++)) >> shiftbpp; + + } + } + } else if (shiftbpp < 0) { + for (row = 0; row < opjimage->comps[selcomp].h; row++) { + for (col = 0; col < opjimage->comps[selcomp].w; col++) { + + *(ptr++) = (*(y)) << -shiftbpp; + *(ptr++) = (*(y)) << -shiftbpp; + *(ptr++) = (*(y++)) << -shiftbpp; + + } + } + } else { + for (row = 0; row < opjimage->comps[selcomp].h; row++) { + for (col = 0; col < opjimage->comps[selcomp].w; col++) { + + *(ptr++) = *(y); + *(ptr++) = *(y); + *(ptr++) = *(y++); + + } + } + } + } + + + } + + wxMutexGuiEnter(); + wxLogMessage(wxT("JPEG 2000 image loaded.")); + wxMutexGuiLeave(); + + /* close openjpeg structs */ + opj_destroy_decompress(dinfo); + opj_image_destroy(opjimage); + free(src); + + if (!image->Ok()) { + return false; + } else { + return true; + } + +} + +#define CINEMA_24_CS 1302083 /* Codestream length for 24fps */ +#define CINEMA_48_CS 651041 /* Codestream length for 48fps */ +#define COMP_24_CS 1041666 /* Maximum size per color component for 2K & 4K @ 24fps */ +#define COMP_48_CS 520833 /* Maximum size per color component for 2K @ 48fps */ + +// save the j2k codestream +bool wxJPEG2000Handler::SaveFile(wxImage *wimage, wxOutputStream& stream, + bool verbose) +{ + opj_cparameters_t parameters; /* compression parameters */ + opj_event_mgr_t event_mgr; /* event manager */ + opj_image_t *oimage = NULL; + opj_image_cmptparm_t *cmptparm; + opj_cio_t *cio = NULL; + opj_codestream_info_t cstr_info; + int codestream_length; + bool bSuccess; + int i; + char indexfilename[OPJ_PATH_LEN] = ""; /* index file name */ + + /* + configure the event callbacks (not required) + setting of each callback is optional + */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = jpeg2000_error_callback; + event_mgr.warning_handler = jpeg2000_warning_callback; + event_mgr.info_handler = jpeg2000_info_callback; + + /* set encoding parameters to default values */ + opj_set_default_encoder_parameters(¶meters); + + /* load parameters */ + parameters.cp_cinema = OFF; + + /* subsampling */ + if (sscanf(m_subsampling.ToAscii(), "%d,%d", &(parameters.subsampling_dx), + &(parameters.subsampling_dy)) != 2) { + wxLogError(wxT("Wrong sub-sampling encoder setting: dx,dy")); + return false; + } + + /* compression rates */ + if ((m_rates != wxT("")) && (!m_enablequality)) { + const char *s1 = m_rates.ToAscii(); + wxLogMessage(wxT("rates %s"), s1); + while (sscanf(s1, "%f", &(parameters.tcp_rates[parameters.tcp_numlayers])) == + 1) { + parameters.tcp_numlayers++; + while (*s1 && *s1 != ',') { + s1++; + } + if (!*s1) { + break; + } + s1++; + } + wxLogMessage(wxT("%d layers"), parameters.tcp_numlayers); + parameters.cp_disto_alloc = 1; + } + + /* image quality, dB */ + if ((m_quality != wxT("")) && (m_enablequality)) { + const char *s2 = m_quality.ToAscii(); + wxLogMessage(wxT("qualities %s"), s2); + while (sscanf(s2, "%f", ¶meters.tcp_distoratio[parameters.tcp_numlayers]) == + 1) { + parameters.tcp_numlayers++; + while (*s2 && *s2 != ',') { + s2++; + } + if (!*s2) { + break; + } + s2++; + } + wxLogMessage(wxT("%d layers"), parameters.tcp_numlayers); + parameters.cp_fixed_quality = 1; + } + + /* image origin */ + if (sscanf(m_origin.ToAscii(), "%d,%d", ¶meters.image_offset_x0, + ¶meters.image_offset_y0) != 2) { + wxLogError(wxT("bad coordinate of the image origin: x0,y0")); + return false; + } + + /* Create comment for codestream */ + if (m_enablecomm) { + parameters.cp_comment = (char *) malloc(strlen(m_comment.ToAscii()) + 1); + if (parameters.cp_comment) { + strcpy(parameters.cp_comment, m_comment.ToAscii()); + } + } else { + parameters.cp_comment = NULL; + } + + /* indexing file */ + if (m_enableidx) { + strncpy(indexfilename, m_index.ToAscii(), OPJ_PATH_LEN); + wxLogMessage(wxT("index file is %s"), indexfilename); + } + + /* if no rate entered, lossless by default */ + if (parameters.tcp_numlayers == 0) { + parameters.tcp_rates[0] = 0; /* MOD antonin : losslessbug */ + parameters.tcp_numlayers++; + parameters.cp_disto_alloc = 1; + } + + /* irreversible transform */ + parameters.irreversible = (m_irreversible == true) ? 1 : 0; + + /* resolutions */ + parameters.numresolution = m_resolutions; + + /* codeblocks size */ + if (m_cbsize != wxT("")) { + int cblockw_init = 0, cblockh_init = 0; + sscanf(m_cbsize.ToAscii(), "%d,%d", &cblockw_init, &cblockh_init); + if (cblockw_init * cblockh_init > 4096 || cblockw_init > 1024 || + cblockw_init < 4 || cblockh_init > 1024 || cblockh_init < 4) { + wxLogError( + wxT("!! Size of code_block error !! Restrictions:\n width*height<=4096\n 4<=width,height<= 1024")); + return false; + } + parameters.cblockw_init = cblockw_init; + parameters.cblockh_init = cblockh_init; + } + + /* precincts size */ + if (m_prsize != wxT("")) { + char sep; + int res_spec = 0; + char *s = (char *) m_prsize.c_str(); + do { + sep = 0; + sscanf(s, "[%d,%d]%c", ¶meters.prcw_init[res_spec], + ¶meters.prch_init[res_spec], &sep); + parameters.csty |= 0x01; + res_spec++; + s = strpbrk(s, "]") + 2; + } while (sep == ','); + parameters.res_spec = res_spec; + } + + /* tiles */ + if (m_tsize != wxT("")) { + sscanf(m_tsize.ToAscii(), "%d,%d", ¶meters.cp_tdx, ¶meters.cp_tdy); + parameters.tile_size_on = true; + } + + /* tile origin */ + if (sscanf(m_torigin.ToAscii(), "%d,%d", ¶meters.cp_tx0, + ¶meters.cp_ty0) != 2) { + wxLogError(wxT("tile offset setting error: X0,Y0")); + return false; + } + + /* use SOP */ + if (m_enablesop) { + parameters.csty |= 0x02; + } + + /* use EPH */ + if (m_enableeph) { + parameters.csty |= 0x04; + } + + /* multiple component transform */ + if (m_multicomp) { + parameters.tcp_mct = 1; + } else { + parameters.tcp_mct = 0; + } + + /* mode switch */ + parameters.mode = (m_enablebypass ? 1 : 0) + (m_enablereset ? 2 : 0) + + (m_enablerestart ? 4 : 0) + (m_enablevsc ? 8 : 0) + + (m_enableerterm ? 16 : 0) + (m_enablesegmark ? 32 : 0); + + /* progression order */ + switch (m_progression) { + + /* LRCP */ + case 0: + parameters.prog_order = LRCP; + break; + + /* RLCP */ + case 1: + parameters.prog_order = RLCP; + break; + + /* RPCL */ + case 2: + parameters.prog_order = RPCL; + break; + + /* PCRL */ + case 3: + parameters.prog_order = PCRL; + break; + + /* CPRL */ + case 4: + parameters.prog_order = CPRL; + break; + + /* DCI2K24 */ + case 5: + parameters.cp_cinema = CINEMA2K_24; + parameters.cp_rsiz = CINEMA2K; + break; + + /* DCI2K48 */ + case 6: + parameters.cp_cinema = CINEMA2K_48; + parameters.cp_rsiz = CINEMA2K; + break; + + /* DCI4K */ + case 7: + parameters.cp_cinema = CINEMA4K_24; + parameters.cp_rsiz = CINEMA4K; + break; + + default: + break; + } + + /* check cinema */ + if (parameters.cp_cinema) { + + /* set up */ + parameters.tile_size_on = false; + parameters.cp_tdx = 1; + parameters.cp_tdy = 1; + + /*Tile part*/ + parameters.tp_flag = 'C'; + parameters.tp_on = 1; + + /*Tile and Image shall be at (0,0)*/ + parameters.cp_tx0 = 0; + parameters.cp_ty0 = 0; + parameters.image_offset_x0 = 0; + parameters.image_offset_y0 = 0; + + /*Codeblock size= 32*32*/ + parameters.cblockw_init = 32; + parameters.cblockh_init = 32; + parameters.csty |= 0x01; + + /*The progression order shall be CPRL*/ + parameters.prog_order = CPRL; + + /* No ROI */ + parameters.roi_compno = -1; + + parameters.subsampling_dx = 1; + parameters.subsampling_dy = 1; + + /* 9-7 transform */ + parameters.irreversible = 1; + + } + + /* convert wx image into opj image */ + cmptparm = (opj_image_cmptparm_t*) malloc(3 * sizeof(opj_image_cmptparm_t)); + + /* initialize opj image components */ + memset(&cmptparm[0], 0, 3 * sizeof(opj_image_cmptparm_t)); + for (i = 0; i < 3; i++) { + cmptparm[i].prec = 8; + cmptparm[i].bpp = 8; + cmptparm[i].sgnd = false; + cmptparm[i].dx = parameters.subsampling_dx; + cmptparm[i].dy = parameters.subsampling_dy; + cmptparm[i].w = wimage->GetWidth(); + cmptparm[i].h = wimage->GetHeight(); + } + + /* create the image */ + oimage = opj_image_create(3, &cmptparm[0], CLRSPC_SRGB); + if (!oimage) { + if (cmptparm) { + free(cmptparm); + } + return false; + } + + /* set image offset and reference grid */ + oimage->x0 = parameters.image_offset_x0; + oimage->y0 = parameters.image_offset_y0; + oimage->x1 = parameters.image_offset_x0 + (wimage->GetWidth() - 1) * 1 + 1; + oimage->y1 = parameters.image_offset_y0 + (wimage->GetHeight() - 1) * 1 + 1; + + /* load image data */ + unsigned char *value = wimage->GetData(); + int area = wimage->GetWidth() * wimage->GetHeight(); + for (i = 0; i < area; i++) { + oimage->comps[0].data[i] = *(value++); + oimage->comps[1].data[i] = *(value++); + oimage->comps[2].data[i] = *(value++); + } + + /* check cinema again */ + if (parameters.cp_cinema) { + int i; + float temp_rate; + opj_poc_t *POC = NULL; + + switch (parameters.cp_cinema) { + + case CINEMA2K_24: + case CINEMA2K_48: + if (parameters.numresolution > 6) { + parameters.numresolution = 6; + } + if (!((oimage->comps[0].w == 2048) | (oimage->comps[0].h == 1080))) { + wxLogWarning( + wxT("Image coordinates %d x %d is not 2K compliant. JPEG Digital Cinema Profile-3 " + "(2K profile) compliance requires that at least one of coordinates match 2048 x 1080"), + oimage->comps[0].w, oimage->comps[0].h); + parameters.cp_rsiz = STD_RSIZ; + } + break; + + case CINEMA4K_24: + if (parameters.numresolution < 1) { + parameters.numresolution = 1; + } else if (parameters.numresolution > 7) { + parameters.numresolution = 7; + } + if (!((oimage->comps[0].w == 4096) | (oimage->comps[0].h == 2160))) { + wxLogWarning( + wxT("Image coordinates %d x %d is not 4K compliant. JPEG Digital Cinema Profile-4" + "(4K profile) compliance requires that at least one of coordinates match 4096 x 2160"), + oimage->comps[0].w, oimage->comps[0].h); + parameters.cp_rsiz = STD_RSIZ; + } + parameters.POC[0].tile = 1; + parameters.POC[0].resno0 = 0; + parameters.POC[0].compno0 = 0; + parameters.POC[0].layno1 = 1; + parameters.POC[0].resno1 = parameters.numresolution - 1; + parameters.POC[0].compno1 = 3; + parameters.POC[0].prg1 = CPRL; + parameters.POC[1].tile = 1; + parameters.POC[1].resno0 = parameters.numresolution - 1; + parameters.POC[1].compno0 = 0; + parameters.POC[1].layno1 = 1; + parameters.POC[1].resno1 = parameters.numresolution; + parameters.POC[1].compno1 = 3; + parameters.POC[1].prg1 = CPRL; + parameters.numpocs = 2; + break; + } + + switch (parameters.cp_cinema) { + case CINEMA2K_24: + case CINEMA4K_24: + for (i = 0 ; i < parameters.tcp_numlayers; i++) { + temp_rate = 0; + if (parameters.tcp_rates[i] == 0) { + parameters.tcp_rates[0] = ((float)(oimage->numcomps * oimage->comps[0].w * + oimage->comps[0].h * oimage->comps[0].prec)) / + (CINEMA_24_CS * 8 * oimage->comps[0].dx * oimage->comps[0].dy); + } else { + temp_rate = ((float)(oimage->numcomps * oimage->comps[0].w * oimage->comps[0].h + * oimage->comps[0].prec)) / + (parameters.tcp_rates[i] * 8 * oimage->comps[0].dx * oimage->comps[0].dy); + if (temp_rate > CINEMA_24_CS) { + parameters.tcp_rates[i] = ((float)(oimage->numcomps * oimage->comps[0].w * + oimage->comps[0].h * oimage->comps[0].prec)) / + (CINEMA_24_CS * 8 * oimage->comps[0].dx * oimage->comps[0].dy); + } else { + /* do nothing */ + } + } + } + parameters.max_comp_size = COMP_24_CS; + break; + + case CINEMA2K_48: + for (i = 0; i < parameters.tcp_numlayers; i++) { + temp_rate = 0 ; + if (parameters.tcp_rates[i] == 0) { + parameters.tcp_rates[0] = ((float)(oimage->numcomps * oimage->comps[0].w * + oimage->comps[0].h * oimage->comps[0].prec)) / + (CINEMA_48_CS * 8 * oimage->comps[0].dx * oimage->comps[0].dy); + } else { + temp_rate = ((float)(oimage->numcomps * oimage->comps[0].w * oimage->comps[0].h + * oimage->comps[0].prec)) / + (parameters.tcp_rates[i] * 8 * oimage->comps[0].dx * oimage->comps[0].dy); + if (temp_rate > CINEMA_48_CS) { + parameters.tcp_rates[0] = ((float)(oimage->numcomps * oimage->comps[0].w * + oimage->comps[0].h * oimage->comps[0].prec)) / + (CINEMA_48_CS * 8 * oimage->comps[0].dx * oimage->comps[0].dy); + } else { + /* do nothing */ + } + } + } + parameters.max_comp_size = COMP_48_CS; + break; + } + + parameters.cp_disto_alloc = 1; + } + + /* get a J2K compressor handle */ + opj_cinfo_t* cinfo = opj_create_compress(CODEC_J2K); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr); + + /* setup the encoder parameters using the current image and user parameters */ + opj_setup_encoder(cinfo, ¶meters, oimage); + + /* open a byte stream for writing */ + /* allocate memory for all tiles */ + cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0); + + /* encode the image */ + bSuccess = opj_encode_with_info(cinfo, cio, oimage, &cstr_info); + if (!bSuccess) { + + opj_cio_close(cio); + opj_destroy_compress(cinfo); + opj_image_destroy(oimage); + if (cmptparm) { + free(cmptparm); + } + if (parameters.cp_comment) { + free(parameters.cp_comment); + } + if (parameters.cp_matrice) { + free(parameters.cp_matrice); + } + +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif /* __WXGTK__ */ + + wxLogError(wxT("failed to encode image")); + +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif /* __WXGTK__ */ + + return false; + } + codestream_length = cio_tell(cio); + wxLogMessage(wxT("Codestream: %d bytes"), codestream_length); + + /* write the buffer to stream */ + stream.Write(cio->buffer, codestream_length); + + /* close and free the byte stream */ + opj_cio_close(cio); + + /* Write the index to disk */ + if (*indexfilename) { + if (write_index_file(&cstr_info, indexfilename)) { + wxLogError(wxT("Failed to output index file")); + } + } + + /* free remaining compression structures */ + opj_destroy_compress(cinfo); + + /* free image data */ + opj_image_destroy(oimage); + + if (cmptparm) { + free(cmptparm); + } + if (parameters.cp_comment) { + free(parameters.cp_comment); + } + if (parameters.cp_matrice) { + free(parameters.cp_matrice); + } + +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif /* __WXGTK__ */ + + wxLogMessage(wxT("J2K: Image encoded!")); + +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif /* __WXGTK__ */ + + return true; +} + +#ifdef __VISUALC__ +#pragma warning(default:4611) +#endif /* VC++ */ + +// recognize the JPEG 2000 family starting box or the 0xFF4F JPEG 2000 SOC marker +bool wxJPEG2000Handler::DoCanRead(wxInputStream& stream) +{ + unsigned char hdr[24]; + int jpfamform; + + if (!stream.Read(hdr, WXSIZEOF(hdr))) { + return false; + } + + jpfamform = jpeg2000familytype(hdr, WXSIZEOF(hdr)); + + return ((jpfamform == JP2_CFMT) || (jpfamform == MJ2_CFMT) || + (jpfamform == J2K_CFMT)); +} + +#endif // wxUSE_STREAMS + +#endif // wxUSE_LIBOPENJPEG + diff --git a/openjpeg/src/bin/wx/OPJViewer/source/imagjpeg2000.h b/openjpeg/src/bin/wx/OPJViewer/source/imagjpeg2000.h new file mode 100644 index 000000000..ca7f7f29e --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/imagjpeg2000.h @@ -0,0 +1,184 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2007, Digital Signal Processing Laboratory, Universita degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +///////////////////////////////////////////////////////////////////////////// +// Name: imagalljpeg2000.h +// Purpose: wxImage JPEG 2000 family file format handler +// Author: G. Baruffa - based on imagjpeg.h, Vaclav Slavik +// RCS-ID: $Id: imagalljpeg2000.h,v 0.0 2008/01/31 11:22:00 VZ Exp $ +// Copyright: (c) Giuseppe Baruffa +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_IMAGJPEG2000_H_ +#define _WX_IMAGJPEG2000_H_ + +#include "wx/defs.h" + +//----------------------------------------------------------------------------- +// wxJPEG2000Handler +//----------------------------------------------------------------------------- + +#if wxUSE_LIBOPENJPEG + +#include "wx/image.h" +#include "openjp2/openjpeg.h" +#include "jp2/index.h" + +#define wxBITMAP_TYPE_JPEG2000 50 + +class WXDLLEXPORT wxJPEG2000Handler: public wxImageHandler +{ +public: + inline wxJPEG2000Handler() + { + m_name = wxT("JPEG 2000 family file format"); + m_extension = wxT("mj2"); + m_type = wxBITMAP_TYPE_JPEG2000; + m_mime = wxT("image/mj2"); + + /* decoding */ + m_reducefactor = 0; + m_qualitylayers = 0; + m_components = 0; +#ifdef USE_JPWL + m_enablejpwl = true; + m_expcomps = JPWL_EXPECTED_COMPONENTS; + m_maxtiles = JPWL_MAXIMUM_TILES; +#endif // USE_JPWL + + /* encoding */ + m_subsampling = wxT("1,1"); + m_origin = wxT("0,0"); + m_rates = wxT("20,10,5"); + m_quality = wxT("30,35,40"); + m_enablequality = false; + m_multicomp = false; + m_irreversible = false; + m_resolutions = 6; + m_progression = 0; + m_cbsize = wxT("32,32"); + m_prsize = wxT("[128,128],[128,128]"); + m_tsize = wxT(""); + m_torigin = wxT("0,0"); + /*m_progression + m_resilience*/ + m_enablesop = false; + m_enableeph = false; + m_enablereset = false; + m_enablesegmark = false; + m_enablevsc = false; + m_enablerestart = false; + m_enableerterm = false; + m_enablebypass = false; + /*m_roicompo + m_roiup + m_indexfname*/ + m_enableidx = false; + m_index = wxT("index.txt"); + m_enablepoc = false; + m_poc = wxT("T1=0,0,1,5,3,CPRL/T1=5,0,1,6,3,CPRL"); + m_enablecomm = true; + +#if defined __WXMSW__ + m_comment = wxT("Created by OPJViewer Win32 - OpenJPEG version "); +#elif defined __WXGTK__ + m_comment = wxT("Created by OPJViewer Lin32 - OpenJPEG version "); +#else + m_comment = wxT("Created by OPJViewer - OpenJPEG version "); +#endif + +#ifdef USE_JPWL + m_comment += wxString::Format(wxT("%s with JPWL"), (char *) opj_version()); +#else + m_comment += wxString::Format(wxT("%s"), (char *) opj_version()); +#endif + + } + + // decoding engine parameters + int m_reducefactor, m_qualitylayers, m_components, m_framenum; +#ifdef USE_JPWL + bool m_enablejpwl; + int m_expcomps, m_maxtiles; +#endif // USE_JPWL + + // encoding engine parameters + wxString m_subsampling; + wxString m_origin; + wxString m_rates; + wxString m_quality; + bool m_enablequality; + bool m_multicomp; + bool m_irreversible; + int m_resolutions; + int m_progression; + wxString m_cbsize; + wxString m_prsize; + wxString m_tsize; + wxString m_torigin; + /*m_progression + m_resilience*/ + bool m_enablesop; + bool m_enableeph; + bool m_enablebypass; + bool m_enableerterm; + bool m_enablerestart; + bool m_enablereset; + bool m_enablesegmark; + bool m_enablevsc; + /*m_roicompo + m_roiup + m_indexfname*/ + bool m_enableidx; + wxString m_index; + bool m_enablecomm; + wxString m_comment; + bool m_enablepoc; + wxString m_poc; + +#if wxUSE_STREAMS + virtual bool LoadFile(wxImage *image, wxInputStream& stream, + bool verbose = true, int index = -1); + virtual bool SaveFile(wxImage *image, wxOutputStream& stream, + bool verbose = true); +protected: + virtual bool DoCanRead(wxInputStream& stream); +#endif + +private: + OPJ_PROG_ORDER give_progression(char progression[4]); + DECLARE_DYNAMIC_CLASS(wxJPEG2000Handler) +}; + +#endif // wxUSE_LIBOPENJPEG + +#endif // _WX_IMAGJPEG2000_H_ + diff --git a/openjpeg/src/bin/wx/OPJViewer/source/imagmxf.cpp b/openjpeg/src/bin/wx/OPJViewer/source/imagmxf.cpp new file mode 100644 index 000000000..4bf3ce37d --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/imagmxf.cpp @@ -0,0 +1,507 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2007, Digital Signal Processing Laboratory, Università degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +///////////////////////////////////////////////////////////////////////////// +// Name: imagmxf.cpp +// Purpose: wxImage MXF (Material eXchange Format) JPEG 2000 file format handler +// Author: Giuseppe Baruffa - based on imagjpeg.cpp, Vaclav Slavik +// RCS-ID: $Id: imagmxf.cpp,v 0.00 2007/11/19 17:00:00 MW Exp $ +// Copyright: (c) Giuseppe Baruffa +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef USE_MXF + +#include "mxflib/mxflib.h" +using namespace mxflib; + +namespace +{ + //! Structure holding information about the essence in each body stream + struct EssenceInfo + { + UMIDPtr PackageID; + PackagePtr Package; + MDObjectPtr Descriptor; + }; + //! Map of EssenceInfo structures indexed by BodySID + typedef std::map<UInt32, EssenceInfo> EssenceInfoMap; + + //! The map of essence info for this file + EssenceInfoMap EssenceLookup; +}; + +//! Build an EssenceInfoMap for the essence in a given file +/*! \return True if al OK, else false + */ +bool BuildEssenceInfo(MXFFilePtr &File, EssenceInfoMap &EssenceLookup); + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_LIBOPENJPEG + +#include "imagmxf.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/app.h" + #include "wx/intl.h" + #include "wx/bitmap.h" + #include "wx/module.h" +#endif + + +#include "libopenjpeg/openjpeg.h" + + +#include "wx/filefn.h" +#include "wx/wfstream.h" + +// ---------------------------------------------------------------------------- +// types +// ---------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// wxMXFHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxMXFHandler,wxImageHandler) + +#if wxUSE_STREAMS + +#include <stdarg.h> +#define MAX_MESSAGE_LEN 200 + +//------------- MXF Manager + +// Debug and error messages + +//! Display a warning message +void mxflib::warning(const char *Fmt, ...) +{ + char msg[MAX_MESSAGE_LEN]; + va_list args; + + va_start(args, Fmt); + _vsnprintf(msg, MAX_MESSAGE_LEN, Fmt, args); + va_end(args); + + int message_len = strlen(msg) - 1; + if (msg[message_len] != '\n') + message_len = MAX_MESSAGE_LEN; +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif /* __WXGTK__ */ + wxLogMessage(wxT("[WARNING_MXF] %.*s"), message_len, msg); +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif /* __WXGTK__ */ +} + +//! Display an error message +void mxflib::error(const char *Fmt, ...) +{ + char msg[MAX_MESSAGE_LEN]; + va_list args; + + va_start(args, Fmt); + _vsnprintf(msg, MAX_MESSAGE_LEN, Fmt, args); + va_end(args); + + int message_len = strlen(msg) - 1; + if (msg[message_len] != '\n') + message_len = MAX_MESSAGE_LEN; +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif /* __WXGTK__ */ + wxLogMessage(wxT("[ERROR_MXF] %.*s"), message_len, msg); +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif /* __WXGTK__ */ +} + +//! Display an error message +void mxflib::debug(const char *Fmt, ...) +{ + char msg[MAX_MESSAGE_LEN]; + va_list args; + + va_start(args, Fmt); + _vsnprintf(msg, MAX_MESSAGE_LEN, Fmt, args); + va_end(args); + + int message_len = strlen(msg) - 1; + if (msg[message_len] != '\n') + message_len = MAX_MESSAGE_LEN; +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif /* __WXGTK__ */ + wxLogMessage(wxT("[DEBUG_MXF] %.*s"), message_len, msg); +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif /* __WXGTK__ */ +} + + + +//------------- JPEG 2000 Data Source Manager + +#define J2K_CFMT 0 +#define JP2_CFMT 1 +#define JPT_CFMT 2 +#define MJ2_CFMT 3 +#define PXM_DFMT 0 +#define PGX_DFMT 1 +#define BMP_DFMT 2 +#define YUV_DFMT 3 + +/* sample error callback expecting a FILE* client object */ +void mxf_error_callback(const char *msg, void *client_data) { + int message_len = strlen(msg) - 1; + if (msg[message_len] != '\n') + message_len = MAX_MESSAGE_LEN; +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif /* __WXGTK__ */ + wxLogMessage(wxT("[ERROR] %.*s"), message_len, msg); +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif /* __WXGTK__ */ +} + +/* sample warning callback expecting a FILE* client object */ +void mxf_warning_callback(const char *msg, void *client_data) { + int message_len = strlen(msg) - 1; + if (msg[message_len] != '\n') + message_len = MAX_MESSAGE_LEN; +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif /* __WXGTK__ */ + wxLogMessage(wxT("[WARNING] %.*s"), message_len, msg); +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif /* __WXGTK__ */ +} + +/* sample debug callback expecting no client object */ +void mxf_info_callback(const char *msg, void *client_data) { + int message_len = strlen(msg) - 1; + if (msg[message_len] != '\n') + message_len = MAX_MESSAGE_LEN; +#ifndef __WXGTK__ + wxMutexGuiEnter(); +#endif /* __WXGTK__ */ + wxLogMessage(wxT("[INFO] %.*s"), message_len, msg); +#ifndef __WXGTK__ + wxMutexGuiLeave(); +#endif /* __WXGTK__ */ +} + + +///////////////////////////////////////////////// +///////////////////////////////////////////////// + +// load the mxf file format +bool wxMXFHandler::LoadFile(wxImage *image, wxInputStream& stream, bool verbose, int index) +{ + opj_dparameters_t parameters; /* decompression parameters */ + opj_event_mgr_t event_mgr; /* event manager */ + opj_image_t *opjimage = NULL; + unsigned char *src = NULL; + unsigned char *ptr; + int file_length, j2k_point, j2k_len; + opj_codestream_info_t cstr_info; /* Codestream information structure */ + + // simply display the version of the library + wxLogMessage(wxT("Version of MXF: %s "), wxString::FromAscii(LibraryVersion().c_str())); + //wxLogMessage(wxT("MXF file name: %s"), m_filename.GetFullPath()); + + // open MXF file + MXFFilePtr TestFile = new MXFFile; + if (! TestFile->Open(m_filename.GetFullPath().c_str(), true)) + { + wxLogError(wxT("Could not find %s"), m_filename.GetFullPath().c_str()); + return false; + } else + wxLogMessage(wxT("Found %s"), m_filename.GetFullPath().c_str()); + + // Get the size + TestFile->SeekEnd(); + wxLogMessage(wxT("Size is %d bytes"), TestFile->Tell()); + TestFile->Seek(0); + + // essence information + //BuildEssenceInfo(TestFile, EssenceLookup); + + // close MXF file + TestFile->Close(); + + return false; + + // destroy the image + image->Destroy(); + + /* handle to a decompressor */ + opj_dinfo_t* dinfo = NULL; + opj_cio_t *cio = NULL; + + /* configure the event callbacks (not required) */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = mxf_error_callback; + event_mgr.warning_handler = mxf_warning_callback; + event_mgr.info_handler = mxf_info_callback; + + /* set decoding parameters to default values */ + opj_set_default_decoder_parameters(¶meters); + + /* prepare parameters */ + strncpy(parameters.infile, "", sizeof(parameters.infile)-1); + strncpy(parameters.outfile, "", sizeof(parameters.outfile)-1); + parameters.decod_format = J2K_CFMT; + parameters.cod_format = BMP_DFMT; + if (m_reducefactor) + parameters.cp_reduce = m_reducefactor; + if (m_qualitylayers) + parameters.cp_layer = m_qualitylayers; + /*if (n_components) + parameters. = n_components;*/ + + /* JPWL only */ +#ifdef USE_JPWL + parameters.jpwl_exp_comps = m_expcomps; + parameters.jpwl_max_tiles = m_maxtiles; + parameters.jpwl_correct = m_enablejpwl; +#endif /* USE_JPWL */ + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_J2K); + + /* find length of the stream */ + stream.SeekI(0, wxFromEnd); + file_length = (int) stream.TellI(); + + /* search for the m_framenum codestream position and length */ + //jp2c_point = searchjp2c(stream, file_length, m_framenum); + //jp2c_len = searchjp2c(stream, file_length, m_framenum); + j2k_point = 0; + j2k_len = 10; + + // malloc memory source + src = (unsigned char *) malloc(j2k_len); + + // copy the jp2c + stream.SeekI(j2k_point, wxFromStart); + stream.Read(src, j2k_len); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, src, j2k_len); + + /* decode the stream and fill the image structure */ + opjimage = opj_decode_with_info(dinfo, cio, &cstr_info); + if (!opjimage) { + wxMutexGuiEnter(); + wxLogError(wxT("MXF: failed to decode image!")); + wxMutexGuiLeave(); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + free(src); + return false; + } + + /* close the byte stream */ + opj_cio_close(cio); + + /* common rendering method */ +#include "imagjpeg2000.cpp" + + wxMutexGuiEnter(); + wxLogMessage(wxT("MXF: image loaded.")); + wxMutexGuiLeave(); + + /* close openjpeg structs */ + opj_destroy_decompress(dinfo); + opj_image_destroy(opjimage); + free(src); + + if (!image->Ok()) + return false; + else + return true; + +} + +// save the mxf file format +bool wxMXFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) +{ + wxLogError(wxT("MXF: Couldn't save movie -> not implemented.")); + return false; +} + +#ifdef __VISUALC__ + #pragma warning(default:4611) +#endif /* VC++ */ + +// recognize the MXF JPEG 2000 starting box +bool wxMXFHandler::DoCanRead( wxInputStream& stream ) +{ + unsigned char hdr[4]; + + if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) + return false; + + return (hdr[0] == 0x06 && + hdr[1] == 0x0E && + hdr[2] == 0x2B && + hdr[3] == 0x34); +} + +//! Build an EssenceInfoMap for the essence in a given file +/*! \return True if al OK, else false + */ +bool BuildEssenceInfo(MXFFilePtr &File, EssenceInfoMap &EssenceLookup) +{ + // Empty any old data + EssenceLookup.clear(); + + // Get the master metadata set (or the header if we must) + PartitionPtr MasterPartition = File->ReadMasterPartition(); + if(!MasterPartition) + { + File->Seek(0); + MasterPartition = File->ReadPartition(); + warning("File %s does not contain a cloased copy of header metadata - using the open copy in the file header\n", File->Name.c_str()); + } + + if(!MasterPartition) + { + error("Could not read header metadata from file %s\n", File->Name.c_str()); + return false; + } + + // Read and parse the metadata + MasterPartition->ReadMetadata(); + MetadataPtr HMeta = MasterPartition->ParseMetadata(); + + if(!HMeta) + { + error("Could not read header metadata from file %s\n", File->Name.c_str()); + return false; + } + + /* Scan the Essence container data sets to get PackageID to BodySID mapping */ + MDObjectPtr ECDSet = HMeta[ContentStorage_UL]; + if(ECDSet) ECDSet = ECDSet->GetLink(); + if(ECDSet) ECDSet = ECDSet[EssenceContainerDataBatch_UL]; + if(!ECDSet) + { + error("Header metadata in file %s does not contain an EssenceContainerData set\n", File->Name.c_str()); + return false; + } + + MDObject::iterator it = ECDSet->begin(); + while(it != ECDSet->end()) + { + MDObjectPtr ThisECDSet = (*it).second->GetLink(); + MDObjectPtr PackageID; + if(ThisECDSet) PackageID = ThisECDSet->Child(LinkedPackageUID_UL); + if(PackageID) + { + EssenceInfo NewEI; + NewEI.PackageID = new UMID(PackageID->PutData()->Data); + + // Inset the basic essence info - but not if this is external essence (BodySID == 0) + UInt32 BodySID = ThisECDSet->GetUInt(BodySID_UL); + if(BodySID) EssenceLookup[BodySID] = NewEI; + } + it++; + } + + /* Now find the other items for the essence lookup map */ + if(EssenceLookup.size()) + { + PackageList::iterator it = HMeta->Packages.begin(); + while(it != HMeta->Packages.end()) + { + // Only Source Packages are of interest + if((*it)->IsA(SourcePackage_UL)) + { + MDObjectPtr Descriptor = (*it)->Child(Descriptor_UL); + if(Descriptor) Descriptor = Descriptor->GetLink(); + + if(Descriptor) + { + MDObjectPtr PackageID = (*it)->Child(PackageUID_UL); + if(PackageID) + { + UMIDPtr TheID = new UMID(PackageID->PutData()->Data); + + /* Now do a lookup in the essence lookup map (it will need to be done the long way here */ + EssenceInfoMap::iterator EL_it = EssenceLookup.begin(); + while(EL_it != EssenceLookup.end()) + { + if((*((*EL_it).second.PackageID)) == (*TheID)) + { + // If found, set the missing items and stop searching + (*EL_it).second.Package = (*it); + (*EL_it).second.Descriptor = Descriptor; + break; + } + EL_it++; + } + } + } + } + + it++; + } + } + + return true; +} + + +#endif // wxUSE_STREAMS + +#endif // wxUSE_LIBOPENJPEG + +#endif // USE_MXF + diff --git a/openjpeg/src/bin/wx/OPJViewer/source/imagmxf.h b/openjpeg/src/bin/wx/OPJViewer/source/imagmxf.h new file mode 100644 index 000000000..099aa1cc3 --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/imagmxf.h @@ -0,0 +1,106 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2007, Digital Signal Processing Laboratory, Universita degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +///////////////////////////////////////////////////////////////////////////// +// Name: imagmxf.h +// Purpose: wxImage MXF (Material eXchange Format) JPEG 2000 file format handler +// Author: G. Baruffa - based on imagjpeg.h, Vaclav Slavik +// RCS-ID: $Id: imagmj2.h,v 0.0 2007/11/19 17:00:00 VZ Exp $ +// Copyright: (c) Giuseppe Baruffa +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_IMAGMXF_H_ +#define _WX_IMAGMXF_H_ + +#ifdef USE_MXF + +#include "wx/defs.h" +#include "wx/filename.h" + +//----------------------------------------------------------------------------- +// wxMXFHandler +//----------------------------------------------------------------------------- + +#if wxUSE_LIBOPENJPEG + +#include "wx/image.h" +#include "libopenjpeg/openjpeg.h" + +#define wxBITMAP_TYPE_MXF 51 + +class WXDLLEXPORT wxMXFHandler: public wxImageHandler +{ +public: + inline wxMXFHandler() + { + m_name = wxT("MXF JPEG 2000 file format"); + m_extension = wxT("mxf"); + m_type = wxBITMAP_TYPE_MXF; + m_mime = wxT("image/mxf"); + + m_reducefactor = 0; + m_qualitylayers = 0; + m_components = 0; + m_filename = wxT(""); +#ifdef USE_JPWL + m_enablejpwl = true; + m_expcomps = JPWL_EXPECTED_COMPONENTS; + m_maxtiles = JPWL_MAXIMUM_TILES; +#endif // USE_JPWL + } + + // decoding engine parameters + int m_reducefactor, m_qualitylayers, m_components, m_framenum; + wxFileName m_filename; +#ifdef USE_JPWL + bool m_enablejpwl; + int m_expcomps, m_maxtiles; +#endif // USE_JPWL + +#if wxUSE_STREAMS + virtual bool LoadFile(wxImage *image, wxInputStream& stream, + bool verbose = true, int index = -1); + virtual bool SaveFile(wxImage *image, wxOutputStream& stream, + bool verbose = true); +protected: + virtual bool DoCanRead(wxInputStream& stream); +#endif + +private: + DECLARE_DYNAMIC_CLASS(wxMXFHandler) +}; + +#endif // wxUSE_LIBOPENJPEG + +#endif // USE_MXF + +#endif // _WX_IMAGMXF_H_ + diff --git a/openjpeg/src/bin/wx/OPJViewer/source/license.txt b/openjpeg/src/bin/wx/OPJViewer/source/license.txt new file mode 100644 index 000000000..919566d17 --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/license.txt @@ -0,0 +1,14 @@ +Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium +Copyright (c) 2002-2014, Professor Benoit Macq +Copyright (c) 2001-2003, David Janssens +Copyright (c) 2002-2003, Yannick Verschueren +Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe +Copyright (c) 2005, Herve Drolon, FreeImage Team +Copyright (c) 2007, Digital Signal Processing Laboratory, Università degli studi di Perugia (UPG), Italy +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditionsare met: +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file diff --git a/openjpeg/src/bin/wx/OPJViewer/source/opj_logo.xpm b/openjpeg/src/bin/wx/OPJViewer/source/opj_logo.xpm new file mode 100644 index 000000000..c64d0a7b4 --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/opj_logo.xpm @@ -0,0 +1,285 @@ +/* XPM */ +static char *opj_logo[] = { +/* columns rows colors chars-per-pixel */ +"90 61 218 2", +" c #BE3D12", +". c #BF461D", +"X c #AD5435", +"o c #B64925", +"O c #B54E2B", +"+ c #BC4620", +"@ c #BB4B25", +"# c #BC4E29", +"$ c #B5502F", +"% c #BD512C", +"& c #B45334", +"* c #B35638", +"= c #B45B3D", +"- c #BB5533", +"; c #BE5937", +": c #BC5C3D", +"> c #9C766A", +", c #AD5D42", +"< c #B55F41", +"1 c #BA5E40", +"2 c #A7634D", +"3 c #A76C57", +"4 c #AA6750", +"5 c #AC6B56", +"6 c #AA6E5A", +"7 c #A4705E", +"8 c #B46045", +"9 c #B1644B", +"0 c #BD6244", +"q c #B96448", +"w c #BC694D", +"e c #B36B53", +"r c #B26E58", +"t c #BB6C52", +"y c #B2725D", +"u c #BD7056", +"i c #BB745C", +"p c #A67566", +"a c #A57B6D", +"s c #AE7562", +"d c #AB7867", +"f c #AA7C6C", +"g c #A07E73", +"h c #AA7F71", +"j c #B37661", +"k c #B47863", +"l c #B27D6B", +"z c #BB7863", +"x c #BA7E69", +"c c #C73605", +"v c #C63A0B", +"b c #CB3300", +"n c #CA3807", +"m c #C93A0A", +"M c #C43E11", +"N c #C93E10", +"B c #C44115", +"V c #C3441A", +"C c #C4481E", +"Z c #CA4113", +"A c #C94519", +"S c #CB481C", +"D c #C24A23", +"F c #C24F28", +"G c #CD4D23", +"H c #C4522D", +"J c #CB532B", +"K c #C25632", +"L c #C35936", +"P c #C25C3B", +"I c #C85630", +"U c #CB5933", +"Y c #CB5E3A", +"T c #D05026", +"R c #CC613D", +"E c #C26343", +"W c #C46748", +"Q c #C1694C", +"! c #CD6744", +"~ c #CA6C4D", +"^ c #C37155", +"/ c #C4755B", +"( c #CB7356", +") c #C8765B", +"_ c #D06D4C", +"` c #D07253", +"' c #D47B5E", +"] c #C37B63", +"[ c #C27E68", +"{ c #C97F68", +"} c #A68175", +"| c #A48479", +" . c #AD8172", +".. c #AD8578", +"X. c #AB897D", +"o. c #B1806F", +"O. c #BA816F", +"+. c #B38373", +"@. c #B58778", +"#. c #B3897B", +"$. c #BA8472", +"%. c #BB8C7C", +"&. c #C2816B", +"*. c #CD846C", +"=. c #C38470", +"-. c #C38976", +";. c #C38D7B", +":. c #CC8973", +">. c #CF8F7A", +",. c #CB907D", +"<. c #D1937F", +"1. c #948E8C", +"2. c #9D8C86", +"3. c #9D8F89", +"4. c #96908E", +"5. c #9C918D", +"6. c #949392", +"7. c #9B9492", +"8. c #9D9997", +"9. c #9D9C9C", +"0. c #A38B83", +"q. c #AA8D83", +"w. c #A4918B", +"e. c #AC9087", +"r. c #AB938C", +"t. c #A49590", +"y. c #A29996", +"u. c #A19D9C", +"i. c #AA9790", +"p. c #AC9994", +"a. c #AC9E99", +"s. c #B18D81", +"d. c #B59084", +"f. c #B49389", +"g. c #BA9184", +"h. c #B89589", +"j. c #BA988D", +"k. c #B29B93", +"l. c #BC9C92", +"z. c #ACA19D", +"x. c #B1A19D", +"c. c #BCA39B", +"v. c #A3A3A3", +"b. c #ABA5A3", +"n. c #AEA9A7", +"m. c #ABABAA", +"M. c #B3A5A1", +"N. c #B3A9A6", +"B. c #B3ADAA", +"V. c #B9A6A0", +"C. c #B9AAA5", +"Z. c #BAADA9", +"A. c #B4B0AF", +"S. c #BAB0AD", +"D. c #B4B3B3", +"F. c #BAB5B3", +"G. c #BDB8B6", +"H. c #BBBBBB", +"J. c #C39384", +"K. c #C0978A", +"L. c #C2998B", +"P. c #CA9483", +"I. c #CD9A8A", +"U. c #C19D92", +"Y. c #D69B89", +"T. c #DB9680", +"R. c #C2A095", +"E. c #C4A69C", +"W. c #CCA193", +"Q. c #C8A599", +"!. c #CBA99D", +"~. c #C6AEA6", +"^. c #CCACA2", +"/. c #CBB2AB", +"(. c #C3B8B5", +"). c #C2BDBC", +"_. c #C9B9B3", +"`. c #D3ADA0", +"'. c #D3B4A9", +"]. c #DCB2A4", +"[. c #DEB6A8", +"{. c #D1BFB9", +"}. c #D9BEB5", +"|. c #C5C0BE", +" X c #CDC0BC", +".X c #D2C1BB", +"XX c #DDC3BB", +"oX c #E0C5BC", +"OX c #E0C8BF", +"+X c #C2C2C2", +"@X c #CBC4C2", +"#X c #CDC8C6", +"$X c #CCCBCB", +"%X c #D2C6C2", +"&X c #D1CECD", +"*X c #DDC8C1", +"=X c #DECFCA", +"-X c #D9D1CE", +";X c #D3D3D3", +":X c #D9D5D4", +">X c #DED9D7", +",X c #DBDBDB", +"<X c #E1CAC3", +"1X c #E2CFC8", +"2X c #E1D3CE", +"3X c #E2D5D0", +"4X c #E5D8D3", +"5X c #E4DDDB", +"6X c #E8DBD6", +"7X c #EADEDA", +"8X c #E6E0DE", +"9X c #EBE0DC", +"0X c #E4E4E4", +"qX c #E8E2E0", +"wX c #EBEBEB", +"eX c #F0EAE8", +"rX c #F3F3F3", +"tX c #FEFEFE", +/* pixels */ +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXrXrXtXrXrXrXrXrXrXrXtXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXrXtXrXrXrXwXwXrXwXrXrXrXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXrXrXrXwXwX0X0XqX0X0X0X0XwXwXwXrXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXtXtXrXtXrXwXwX2X[.[.].].].].].1XwXrXwXrXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXrXrXrXwX0X0XL.J b b b b b b b J '.0X0XwXwXrXrXrXrXrXrXrXrXrXrXtXrXrXrXtXrXrXrXrXrXrXrXrXrXrXrXrXrXrXrXrXrXtXtXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXtXrXrXwX0XXXt m b m B V N b b v >.;X0XwXwXwXwXrXwXwXrXrXrXrXtXrXtXrXrXrXwXrXrXrXrXrXrXrXrXrXrXrXwXrXrXwXrXrXrXtXtXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXrXrXrX0X,X'.S b b P l.z.M.k.w n b b g.;X,X,X,X0X0X0X0X0XwXwXwXwXwXwXwXwXwX0X0X0XwX0X0XwXwXwXwX0X0X0X0X0X0XwXwXwXwXrXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXrXrXrXwX0X:XT.m b A ] G.D.D.m.$.m b b $.$X&X.X}.XX>XOX}.oXXX<X0X0XwXwXwX0X2XXXoXXXoXOX5X0XwX0X1XoXXX5X*X}.}.oX<XqXrXrXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXrXrXwX0X,XL.b b D M.H.D.D.D.D.m.L b b W H.Z.# b Y / m b b b Z P.:X:X:X$X:.Z b b b b n :.;X;X;XR b A &.Z b b b b *.wXwXrXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXrXwX0X:X$.b b E B.H.H.D.D.D.D.P b b E H.V.. b U L v v n b b ( #X;X$X~.Y b m N m b b ! {.&X#XI b C R v v n b b ! 0XwXrXrXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXrXwX0X:X!.A b Z F.H.H.H.H.H.D.m.L b b e b.+.b b V k i.r.t n b b s.H.x v b L q.b.p.D b b t F.$.n b M l a.M.y b b A :X0XwXrXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXrXwX0X:XL.m b D H.).H.+XH.H.H.D.H b b 6 v.j b b - a.A.m.@.m b b h D.< b b w z.b.b.P b b q B.z b b @ B.D.m...v b G :X,XwXwXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXwX0X,X&X/ b b , D.H.+X+X+X+XH.f.B b b 5.8.M b M w.v.v.v.r.D b b h l v b b M V v b b q u.X b n @.v.m.v.j b b Q &X,X0XwXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXwX0X,X$X^ b b , H.H.+X+XH.H.H.s.N b n 7.7.v b B 8.v.v.v.w.M b b g r b b b n n n b b b b e y.O b n X.m.v.n.e b b u &X,X0XrXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXrX0X,X$X/ b b + F.H.H.H.+XH.d.b b M | 8.> c b @ 9.v.9.u., b b - 3.& b b 7 1.1.4.4.4.6.7.9.w.m b + t.v.m.p.D b b K.;X,X0XwXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXwX0X,X$X-.b b b i D.H.G.H.J.N b b = 9.9.5 c b B 7.9.v.y.b b m f 4.O b b 3 6.6.6.g 9 4 h u.h b b - b.m.m.s.b b N ~.;X,X0XwXrXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXwX0X,X;XE.G b b I z ] ] ] W n b H l 9.8.9 b b m e 6 r e b b # 0.y.< b b O 6 p 6 < # ; q.v.t b b 0 n.A.A.+.b b H _.;X,XwXwXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXwXwX,X;X#Xf.b b b b b b b b b - a.v.v.w.@ b b v b b b b b @ b.m.v.w.M b b b b b b v ..m.n.A b n g.H.H.H.4 b b [ &X,X0XwXrXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXwXwX0X:X$XZ.Q H v n b m B H E x n.m.m.q.B b v < . v N + E z m.m.m.b.e - M m v M - t k.D.m.; # - V.H.+XH.s # # K.:X,X0XwXrXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXrXwXwX,X,X$X+XG.Z.Z.B.C.S.F.H.H.H.D.D.j b b q v.b.a.n.B.H.H.+X+X+XH.H.D.Z.C.Z.Z.F.H.H.+X+XH.).H.$X&X&X;X$X#X#X:X,X0XwXrXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXrXrXwX0X,X;X#X+X+X+XH.H.+X+X+XH.H.H.D.e b n i n.m.D.H.H.+X#X$X$X+X+X+X+XH.H.H.H.+X+X+X$X&X&X&X$X;X;X;X:X;X:X,X,X0XwXwXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXrXrXwXwX,X,X;X;X$X$X$X;X;X&X;X$X#X+XF b v s.H.H.+X$X&X;X;X,X,X,X;X:X;X;X;X;X;X;X:X,X,X,X0X,X0X,X0X0X0X0X0X0X0XwXwXrXtXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXrXtXrXwXwX0X,X:X;X;X;X;X;X:X;X;X;X$X+XC b B k.+X+X$X$X;X,X,X0X0X0X0X0X;X,X,X,X,X,X,X,X,X0X0X0X0X0X0XwX0X0X0XwXwXrXrXrXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXrXrXrXrXwXwXwX0X0X0X0X0X0X0X,X,X:X^.^.!.$X$X;X,X,X0XwXwXwXwXwXwXwXwX0X0X0X0XwXwXwXwXwXwXrXrXwXrXrXrXrXrXrXrXrXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXtXrXrXrXrXwXwXwXwX0XwXwXwX0X0X,X:X;X$X&X&X;X,X,X0XwXwXwXrXrXrXrXrXwXwXwXwXwXwXwXrXrXrXwXrXrXrXrXrXrXrXrXrXrXtXrXtXtXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXrXrXrXrXrXrXrXrXrXwXwXwXwX0X,X0X0X0XwXwXrXrXrXrXrXrXrXrXrXrXrXrXrXrXwXrXrXrXrXrXtXrXrXrXtXrXrXrXrXrXrXrXrXrXtXtXtXrXrXtXtXtXtXrXrXtXrXrXtXrXtXrXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXrXtXtXrXtXrXrXrXrXrXrXwXwXwX0XwX0XwXwXwXrXrXrXtXtXrXrXrXrXrXrXrXrXwXrXwXrXwXwXrXrXrXrXrXrXrXrXrXrXrXrXrXrXrXrXrXrXrXtXrXrXtXtXrXrXrXrXrXrXrXrXrXrXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXrXrXwXrXrXrXrXrXrXtXrXtXrXrXrXrXrXwXwXwXwXwX0X0XwX0XwXwXwXwXwXwXwXrXwXwXwX0X0X0X0XwX0XwXwXrXrXrXwXrXwXwXwX0XwX0XwXwXwXrXrXrXrXtXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXrXrXrXrXrXrXrXtXtXrXrXtXrXrXeX7X7X9XwXwXwX5X3X3X3X2X2X2X5X0XwXwXwXwXwX8X3X3X2X2X2X2X2X3X6X6X7XwXwXwXwXwXwX7X1XXXOXOX1X8XwXwXrXrXrXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXtXtXtXrXrXrXwXT.T T :.,X,X-X` G G G G G G U _ J.-X,X,X,X[ G G G G G G G G G G _ >XwX0X,X&XI.R N b b b m ! `.5XwXrXrXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXtXtXtXrXtXrXrXrXwX0X' b b ] >X,X%XJ b b b b b b b b Q {.:X;X:Xq b b b b b b b b b b Y >X0X,X-X'.^ n b b b b b m *.1XwXwXrXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXrX0X0X%XL b b L.@X+X-.b b M L L L D b b b M V.+X(.N b b D H H H H H U U W.;X&X^.H b b n W -.-.W n b b J &XwXrXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXwXwX0X XF b b U.+X+X[ b b D z z j P v b b N U.H.S.m b m E Q t ^ ) / ) ) /.$X$X;.m b n A %.H.H.J.N b b N .XwXwXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXwXwX,X:X!.m b L N.D.m.* b b y v.v.v.v.p.n b M f.m.w b b D u.v.m.m.D.G.H.H.+X).g.b b B j.F.D.D.D.D.l.; F I /.0XwXrXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXrXwX,X:XU.n b E B.A.n.$ b b s v.9.v.v.r.n n M r.b.1 b b D u.v.m.m.D.D.H.H.).H.k b b # M.G.D.D.D.D.Z.t w u _.0XwXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXrXwXwX,X;X$XJ b m h b.v.i.m b M a 5.5.2.p M b c < 8.2.+ b b M o o o o # % j G.H.g.m b A M.D.D.D.B.M.M.M.M.Z.(.:X0XwXrXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXrXrXrXrXwX,X,X&X(.n b M 0.v.v.s b b b b b n b b c b M u.v.g M b b b b b b b b b i G.D.0 b b 8 D.D.H.G.P n b b n b U :X,XwXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXrXrXrXwX0X,X;X$XV.n b M w.v.9.< b b b b b b b b c H r 9.v.a n b * < < w w Q Q g.D.B.: b b r D.D.D.m.C b b b b b ) ;X0XwXrXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXrXrXrX6XP.=.K.;X#X+Xx n b D v.u.7.. b b M D . D & 2 q.b.b.v.v.< b b X 6.9.9.b.m.D.D.D.D.n.# b b f D.D.D.b.= 1 * N b n !.;X,XwXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXtXrXrXwX<X~ P x $X+XH.z b b - v.v.3.M b b < r r r k 0.a.m.m.m.v.# b b , 6.9.v.m.D.D.D.H.D.z.O b b s D.D.D.N.f l 9 v b M ~.;X,XwXrXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXtXrXwX0XY.n b e H.H.V.F b b p b.v.h v b v v.m.A.D.H.+X+X+XH.D.p.b b m p 9.v.m.D.D.H.H.H.D.N.- b b - m.A.D.A.m.a.B b b - (.:X0XwXrXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXwXwX0XY.n b ; Z.C.$.A b v 0.m.m.l n b M m.D.D.H.+X#X+X+XH.H.r.b b m < d l l l $.;.J.V.H.B.w b b C @.s.a.k.#.j n b b : ).:X,XwXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXrXwXwX0X'.N b b A B n b n z m.D.B.0 b b 9 H.H.+X$X;X:X;X$X$X+Xl b b b b b b b b b b b s.H.H.B.H b b b n Z Z b b V n b ] $X:X0XwXrXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXwX0X,X.XR b b b b b A P d.D.D.C.H b b j H.$X$X;X:X,X,X;X;X+X/ b b b b b b b b b b b a.H.H.D.u G b b b b b B H : v m ;.$X,XwXwXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXwXwX,X:X Xg.j 5 y s.C.H.H.+X+X|.E.Q.Q. X;X;X,X0XwXwX0X0X,X;X/.U.j.h.g.f.h.j.U.U.U.!.$X$X+X+XH.Z.g.y 4 6 l x.D.A.l.~.#X,X0XwXrXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXrXrXwX0X:X$XG.k.e.f.B.H.H.+X$X$X$X#X$X$X;X;X,X0XwXwXwXwX0X0X;X$X+XH.D.D.D.F.H.+X+X#X&X$X;X$X$X+X+XA.r.X.e.a.H.H.H.+X+X;X,X0XwXrXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXrXwX,X,X$X&X$X$X$X$X;X;X,X,X,X,X,X,X0XwXwXwXrXtXrXrXwXwX0X,X;X$X$X+X$X$X$X;X;X:X,X,X,X,X,X;X$X&X#X#X$X$X$X$X$X;X,X,X0XwXrXrXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXrXwXwX0X,X:X;X;X$X;X;X:X,X,X0X0X,X0X0X0XwXwXwXrXrXtXrXrXwXwX0X;X;X$X&X$X$X&X:X,X,X,X,X0X,X,X:X;X;X$X$X$X$X$X;X:X,X,X0XwXwXrXrXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXtXrXwXwXwX0X0X0X0X0X0XwXwXwXwXwXwXwXwXrXwXrXtXtXrXtXtXrXrXrXwX0X0X0X0X,X,X0X0X0X0XwXwXwXwXwXwX0X0X0X,X,X,X,X0X0XwXwXwXrXtXrXtXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXrXrXrXwXwX0X0X0X0X0XwXwXwXrXwXrXrXrXrXrXtXrXtXtXtXtXrXrXrXwXwXwX0X0X0X0X0X0X0XwXwXwXwXwXwXwXwXwX0X0X0X0XwXwXwXwXwXrXrXrXtXtXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXtXrXrXrXrXrXrXrXrXrXrXtXtXrXtXtXrXtXtXtXtXtXtXtXrXtXrXtXrXrXrXrXwXwXrXrXrXrXrXrXrXtXrXrXrXrXrXrXrXwXrXrXrXrXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXrXtXrXrXrXrXrXrXtXtXrXtXrXtXrXrXtXtXtXtXtXtXtXtXtXtXtXrXrXrXrXrXrXrXrXrXrXrXtXtXrXtXrXrXtXrXrXrXrXrXrXrXrXtXrXrXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX", +"tXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtX" +}; diff --git a/openjpeg/src/bin/wx/OPJViewer/source/readmeafter.txt b/openjpeg/src/bin/wx/OPJViewer/source/readmeafter.txt new file mode 100644 index 000000000..87c122beb --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/readmeafter.txt @@ -0,0 +1,34 @@ +This viewer is conceived to open and display information and image content of J2K, JP2, +and MJ2 files. +The viewer application interface is divided into three main panels: +- a browsing pane; +- a viewing pane; +- a log/peek pane. + +The browsing pane will present the markers or boxes hierarchy, with position (byte number where marker/box starts and stops) and length information (i.e., inner length as signalled by marker/box and total length, with marker/box sign included), in the following form: + +filename +| +|_ #000: Marker/Box short name (Hex code) +| | +| |_ *** Marker/Box long name *** +| |_ startbyte > stopbyte, inner_length + marker/box sign length (total length) +| |_ Additional info, depending on the marker/box type +| |_ ... +| +|_ #001: Marker/Box short name (Hex code) +| | +| |_ ... +| +... + + +The viewing pane will display the decoded image contained in the JPEG 2000 file. +It should display correctly images as large as 4000x2000, provided that a couple of GB of RAM are available. Nothing is known about the display of larger sizes: let us know if you manage to get it working. + + +The log/peek pane is shared among two different subpanels: + +- the log panel will report a lot of debugging info coming out from the wx GUI as well as from the openjpeg library +- the peek pane tries to give a peek on the codestream/file portion which is currently selected in the browsing pane. It shows both hex and ascii values corresponding to the marker/box section. + diff --git a/openjpeg/src/bin/wx/OPJViewer/source/readmebefore.txt b/openjpeg/src/bin/wx/OPJViewer/source/readmebefore.txt new file mode 100644 index 000000000..c945d2911 --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/readmebefore.txt @@ -0,0 +1,11 @@ +What is OpenJPEG ? +================== +The OpenJPEG library is an open-source JPEG 2000 codec written in C language. It has been developed in order to promote the use of JPEG 2000, the new still-image compression standard from the Joint Photographic Experts Group (JPEG). In addition to the basic codec, various other features are under development, among them the JP2 and MJ2 (Motion JPEG 2000) file formats, an indexing tool useful for the JPIP protocol, JPWL-tools for error-resilience, a Java-viewer for j2k-images, ... + +Who can use the library ? +========================= +Anybody. As the OpenJPEG library is released under the BSD license, anybody can use or modify the library, even for commercial applications. The only restriction is to retain the copyright in the sources or the binaries documentation. + +Who is developing the library ? +=============================== +The library is developed by the Communications and Remote Sensing Lab (TELE), in the Université Catholique de Louvain (UCL). The JPWL module is developed and maintained by the Digital Signal Processing Lab (DSPLab) of the University of Perugia, Italy (UNIPG). As our purpose is to make OpenJPEG really useful for those interested in the image compression field, any feedback/advices are obviously welcome ! We will do our best to handle them quickly. diff --git a/openjpeg/src/bin/wx/OPJViewer/source/wxj2kparser.cpp b/openjpeg/src/bin/wx/OPJViewer/source/wxj2kparser.cpp new file mode 100644 index 000000000..7c85d873e --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/wxj2kparser.cpp @@ -0,0 +1,1470 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2007, Digital Signal Processing Laboratory, Università degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "OPJViewer.h" + +/* From little endian to big endian, 2 bytes */ +#define BYTE_SWAP2(X) ((X & 0x00FF) << 8) | ((X & 0xFF00) >> 8) +#define BYTE_SWAP4(X) ((X & 0x000000FF) << 24) | ((X & 0x0000FF00) << 8) | ((X & 0x00FF0000) >> 8) | ((X & 0xFF000000) >> 24) + +/* From codestream to int values */ +#define STREAM_TO_UINT32(C, P) (((unsigned long int) (C)[(P) + 0] << 24) + \ + ((unsigned long int) (C)[(P) + 1] << 16) + \ + ((unsigned long int) (C)[(P) + 2] << 8) + \ + ((unsigned long int) (C)[(P) + 3] << 0)) + +#define STREAM_TO_UINT16(C, P) (((unsigned long int) (C)[(P) + 0] << 8) + \ + ((unsigned long int) (C)[(P) + 1] << 0)) + + +/* Markers values */ +#define J2KMARK_NUM 24 +enum { + SOC_VAL = 0xFF4F, + SOT_VAL = 0xFF90, + SOD_VAL = 0xFF93, + EOC_VAL = 0xFFD9, + SIZ_VAL = 0xFF51, + COD_VAL = 0xFF52, + COC_VAL = 0xFF53, + RGN_VAL = 0xFF5E, + QCD_VAL = 0xFF5C, + QCC_VAL = 0xFF5D, + POD_VAL = 0xFF5F, + TLM_VAL = 0xFF55, + PLM_VAL = 0xFF57, + PLT_VAL = 0xFF58, + PPM_VAL = 0xFF60, + PPT_VAL = 0xFF61, + SOP_VAL = 0xFF91, + EPH_VAL = 0xFF92, + COM_VAL = 0xFF64 +#ifdef USE_JPWL + , EPB_VAL = 0xFF66, + ESD_VAL = 0xFF67, + EPC_VAL = 0xFF68, + RED_VAL = 0xFF69 + /*, EPB_VAL = 0xFF96, + ESD_VAL = 0xFF98, + EPC_VAL = 0xFF97, + RED_VAL = 0xFF99*/ +#endif // USE_JPWL +#ifdef USE_JPSEC + , SEC_VAL = 0xFF65 +#endif // USE_JPSEC +}; + +// All the markers in one vector +unsigned short int marker_val[] = { + SOC_VAL, SOT_VAL, SOD_VAL, EOC_VAL, + SIZ_VAL, + COD_VAL, COC_VAL, RGN_VAL, QCD_VAL, QCC_VAL, POD_VAL, + TLM_VAL, PLM_VAL, PLT_VAL, PPM_VAL, PPT_VAL, + SOP_VAL, EPH_VAL, + COM_VAL +#ifdef USE_JPWL + , EPB_VAL, ESD_VAL, EPC_VAL, RED_VAL +#endif // USE_JPWL +#ifdef USE_JPSEC + , SEC_VAL +#endif // USE_JPSEC +}; + +// Marker names +static const char *marker_name[] = { + "SOC", "SOT", "SOD", "EOC", + "SIZ", + "COD", "COC", "RGN", "QCD", "QCC", "POD", + "TLM", "PLM", "PLT", "PPM", "PPT", + "SOP", "EPH", + "COM" +#ifdef USE_JPWL + , "EPB", "ESD", "EPC", "RED" +#endif // USE_JPWL +#ifdef USE_JPSEC + , "SEC" +#endif // USE_JPSEC +}; + +// Marker descriptions +static const char *marker_descr[] = { + "Start of codestream", "Start of tile-part", "Start of data", "End of codestream", + "Image and tile size", + "Coding style default", "Coding style component", "Region-of-interest", "Quantization default", + "Quantization component", "Progression order change, default", + "Tile-part lengths, main header", "Packet length, main header", "Packets length, tile-part header", + "Packed packet headers, main header", "Packed packet headers, tile-part header", + "Start of packet", "End of packet header", + "Comment and extension" +#ifdef USE_JPWL + , "Error Protection Block", "Error Sensitivity Descriptor", "Error Protection Capability", + "Residual Errors Descriptor" +#endif // USE_JPWL +#ifdef USE_JPSEC + , "Main security marker" +#endif // USE_JPSEC +}; + +void OPJParseThread::ParseJ2KFile(wxFile *m_file, wxFileOffset offset, wxFileOffset length, wxTreeItemId parentid) +{ + unsigned short int csiz = 0; + + // check if the file is opened + if (m_file->IsOpened()) + WriteText(wxT("File OK")); + else + return; + + // position at the beginning + m_file->Seek(offset, wxFromStart); + + // navigate the file + int m, inside_sod = 0, inside_sop = 0; + int nmarks = 0, maxmarks = 10000; + unsigned char onebyte[1]; + unsigned char twobytes[2], firstbyte, secondbyte; + unsigned char fourbytes[4]; + unsigned short int currmark; + unsigned short int currlen; + int lastPsot = 0, lastsotpos = 0; + + WriteText(wxT("Start search...")); + +// advancing macro +#define OPJ_ADVANCE(A) {offset += A; if (offset < length) m_file->Seek(offset, wxFromStart); else return;} + + // begin search + while ((offset < length) && (!m_file->Eof())) { + + // read one byte + if (m_file->Read(&firstbyte, 1) != 1) + break; + + // look for 0xFF + if (firstbyte == 0xFF) { + + // it is a possible marker + if (m_file->Read(&secondbyte, 1) != 1) + break; + else + currmark = (((unsigned short int) firstbyte) << 8) + (unsigned short int) secondbyte; + + } else { + + // nope, advance by one and search again + OPJ_ADVANCE(1); + continue; + } + + // search the marker + for (m = 0; m < J2KMARK_NUM; m++) { + if (currmark == marker_val[m]) + break; + } + + // marker not found + if (m == J2KMARK_NUM) { + // nope, advance by one and search again + OPJ_ADVANCE(1); + continue; + } + + // if we are inside SOD, only some markers are allowed + if (inside_sod) { + + // we are inside SOP + if (inside_sop) { + + } + + // randomly marker coincident data + if ((currmark != SOT_VAL) && + (currmark != EOC_VAL) && + (currmark != SOP_VAL) && + (currmark != EPH_VAL)) { + OPJ_ADVANCE(1); + continue; + } + + // possible SOT? + if ((currmark == SOT_VAL)) { + // too early SOT + if (offset < (lastsotpos + lastPsot)) { + OPJ_ADVANCE(1); + continue; + } + // we were not in the last tile + /*if (lastPsot != 0) { + OPJ_ADVANCE(1); + break; + }*/ + } + } + + // beyond this point, the marker MUST BE real + + // length of current marker segment + if ((currmark == SOD_VAL) || + (currmark == SOC_VAL) || + (currmark == EOC_VAL) || + (currmark == EPH_VAL)) + + // zero length markers + currlen = 0; + + else { + + // read length field + if (m_file->Read(twobytes, 2) != 2) + break; + + currlen = (((unsigned short int) twobytes[0]) << 8) + (unsigned short int) twobytes[1]; + } + + // here we pass to AppendItem() normal and selected item images (we + // suppose that selected image follows the normal one in the enum) + int image, imageSel; + image = m_tree->TreeCtrlIcon_Folder; + imageSel = image + 1; + + // append the marker + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("%03d: "), nmarks) + + wxString::FromAscii(marker_name[m]) + + wxString::Format(wxT(" (0x%04X)"), marker_val[m]), + image, imageSel, + new OPJMarkerData(wxT("MARK") + wxString::Format(wxT(" (%d)"), marker_val[m]), + m_tree->m_fname.GetFullPath(), offset, offset + currlen + 1) + ); + + // append some info + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + // marker name + wxTreeItemId subcurrid1 = m_tree->AppendItem(currid, + wxT("*** ") + wxString::FromAscii(marker_descr[m]) + wxT(" ***"), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + m_tree->SetItemFont(subcurrid1, *wxITALIC_FONT); + + // position and length + wxTreeItemId subcurrid2 = m_tree->AppendItem(currid, + wxLongLong(offset).ToString() + wxT(" > ") + wxLongLong(offset + currlen + 1).ToString() + + wxT(", ") + wxString::Format(wxT("%d + 2 (%d)"), currlen, currlen + 2), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + // give additional info on markers + switch (currmark) { + + ///////// + // SOP // + ///////// + case SOP_VAL: + { + // read packet number + if (m_file->Read(twobytes, 2) != 2) + break; + int packnum = STREAM_TO_UINT16(twobytes, 0); + + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + wxString::Format(wxT("Pack. no. %d"), packnum), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + inside_sop = 1; + }; + break; + +#ifdef USE_JPWL + ///////// + // RED // + ///////// + case RED_VAL: + { + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char pred = onebyte[0]; + + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + wxString address[] = { + wxT("Packet addressing"), + wxT("Byte-range addressing"), + wxT("Packet-range addressing"), + wxT("Reserved") + }; + + wxTreeItemId subcurrid = m_tree->AppendItem(currid, + address[(pred & 0xC0) >> 6], + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("%d bytes range"), (((pred & 0x02) >> 1) + 1) * 2), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + subcurrid = m_tree->AppendItem(currid, + pred & 0x01 ? wxT("Errors/erasures in codestream") : wxT("Error free codestream"), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("Residual corruption level: %d"), (pred & 0x38) >> 3), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + } + break; + + ///////// + // ESD // + ///////// + case ESD_VAL: + { + unsigned short int cesd; + if (csiz < 257) { + if (m_file->Read(onebyte, 1) != 1) + break; + cesd = onebyte[0]; + } else { + if (m_file->Read(twobytes, 2) != 2) + break; + cesd = STREAM_TO_UINT16(twobytes, 0); + } + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char pesd = onebyte[0]; + + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + wxTreeItemId subcurrid = m_tree->AppendItem(currid, + pesd & 0x01 ? wxT("Comp. average") : wxString::Format(wxT("Comp. no. %d"), cesd), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + wxString meth[] = { + wxT("Relative error sensitivity"), + wxT("MSE"), + wxT("MSE reduction"), + wxT("PSNR"), + wxT("PSNR increase"), + wxT("MAXERR (absolute peak error)"), + wxT("TSE (total squared error)"), + wxT("Reserved") + }; + + subcurrid = m_tree->AppendItem(currid, + meth[(pesd & 0x38) >> 3], + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + wxString address[] = { + wxT("Packet addressing"), + wxT("Byte-range addressing"), + wxT("Packet-range addressing"), + wxT("Reserved") + }; + + subcurrid = m_tree->AppendItem(currid, + address[(pesd & 0xC0) >> 6], + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("%d bytes/value, %d bytes range"), ((pesd & 0x04) >> 2) + 1, (((pesd & 0x02) >> 1) + 1) * 2), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + } + break; + + ///////// + // EPC // + ///////// + case EPC_VAL: + { + if (m_file->Read(twobytes, 2) != 2) + break; + unsigned short int pcrc = STREAM_TO_UINT16(twobytes, 0); + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int dl = STREAM_TO_UINT32(fourbytes, 0); + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char pepc = onebyte[0]; + + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + wxTreeItemId subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("CRC-16 = 0x%x"), pcrc), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("Tot. length = %d"), dl), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("%s%s%s%s"), + pepc & 0x10 ? wxT("ESD, ") : wxT(""), + pepc & 0x20 ? wxT("RED, ") : wxT(""), + pepc & 0x40 ? wxT("EPB, ") : wxT(""), + pepc & 0x80 ? wxT("Info") : wxT("") + ), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + } + break; + + ///////// + // EPB // + ///////// + case EPB_VAL: + { + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char depb = onebyte[0]; + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int ldpepb = STREAM_TO_UINT32(fourbytes, 0); + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int pepb = STREAM_TO_UINT32(fourbytes, 0); + + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + wxTreeItemId subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("No. %d, %slatest, %spacked"), + depb & 0x3F, + depb & 0x40 ? wxT("") : wxT("not "), + depb & 0x80 ? wxT("") : wxT("un")), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("%d bytes protected"), ldpepb), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (pepb == 0x00000000) + + subcurrid = m_tree->AppendItem(currid, + wxT("Predefined codes"), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + else if ((pepb >= 0x10000000) && (pepb <= 0x1FFFFFFF)) { + + wxString text = wxT("CRC code"); + if (pepb == 0x10000000) + text << wxT(", CCITT (X25) 16 bits"); + else if (pepb == 0x10000001) + text << wxT(", Ethernet 32 bits"); + else + text << wxT(", JPWL RA"); + subcurrid = m_tree->AppendItem(currid, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + } else if ((pepb >= 0x20000000) && (pepb <= 0x2FFFFFFF)) { + + wxString text; + subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("RS code, RS(%d, %d)"), + (pepb & 0x0000FF00) >> 8, + (pepb & 0x000000FF)), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + } else if ((pepb >= 0x30000000) && (pepb <= 0x3FFFFFFE)) + + subcurrid = m_tree->AppendItem(currid, + wxT("JPWL RA"), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + else if (pepb == 0xFFFFFFFF) + + subcurrid = m_tree->AppendItem(currid, + wxT("No method"), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + } + break; +#endif // USE_JPWL + +#ifdef USE_JPSEC + case SEC_VAL: + { + + } + break; +#endif // USE_JPSEC + + ///////// + // SIZ // + ///////// + case SIZ_VAL: + { + int c; + + if (m_file->Read(twobytes, 2) != 2) + break; + unsigned short int rsiz = STREAM_TO_UINT16(twobytes, 0); + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int xsiz = STREAM_TO_UINT32(fourbytes, 0); + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int ysiz = STREAM_TO_UINT32(fourbytes, 0); + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int xosiz = STREAM_TO_UINT32(fourbytes, 0); + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int yosiz = STREAM_TO_UINT32(fourbytes, 0); + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int xtsiz = STREAM_TO_UINT32(fourbytes, 0); + this->m_tree->m_childframe->m_twidth = xtsiz; + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int ytsiz = STREAM_TO_UINT32(fourbytes, 0); + this->m_tree->m_childframe->m_theight = ytsiz; + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int xtosiz = STREAM_TO_UINT32(fourbytes, 0); + this->m_tree->m_childframe->m_tx = xtosiz; + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int ytosiz = STREAM_TO_UINT32(fourbytes, 0); + this->m_tree->m_childframe->m_ty = ytosiz; + + if (m_file->Read(twobytes, 2) != 2) + break; + csiz = STREAM_TO_UINT16(twobytes, 0); + + bool equaldepth = true, equalsize = true; + unsigned char *ssiz = new unsigned char(csiz); + unsigned char *xrsiz = new unsigned char(csiz); + unsigned char *yrsiz = new unsigned char(csiz); + + for (c = 0; c < csiz; c++) { + + if (m_file->Read(&ssiz[c], 1) != 1) + break; + + if (c > 0) + equaldepth = equaldepth && (ssiz[c] == ssiz[c - 1]); + + if (m_file->Read(&xrsiz[c], 1) != 1) + break; + + if (m_file->Read(&yrsiz[c], 1) != 1) + break; + + if (c > 0) + equalsize = equalsize && (xrsiz[c] == xrsiz[c - 1]) && (yrsiz[c] == yrsiz[c - 1]) ; + + } + + if (equaldepth && equalsize) + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + wxString::Format(wxT("I: %dx%d (%d, %d), %d c., %d%s bpp"), + xsiz, ysiz, + xosiz, yosiz, + csiz, ((ssiz[0] & 0x7F) + 1), + (ssiz[0] & 0x80) ? wxT("s") : wxT("u")), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + else + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + wxString::Format(wxT("I: %dx%d (%d, %d), %d c."), + xsiz, ysiz, + xosiz, yosiz, + csiz), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + wxString::Format(wxT("T: %dx%d (%d, %d)"), + xtsiz, ytsiz, + xtosiz, ytosiz), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + image = m_tree->TreeCtrlIcon_Folder; + imageSel = image + 1; + + wxTreeItemId subcurrid4 = m_tree->AppendItem(currid, + wxT("Components"), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + for (c = 0; c < csiz; c++) { + + wxTreeItemId subcurrid5 = m_tree->AppendItem(subcurrid4, + wxString::Format(wxT("#%d: %dx%d, %d%s bpp"), + c, + xsiz/xrsiz[c], ysiz/yrsiz[c], + ((ssiz[c] & 0x7F) + 1), + (ssiz[c] & 0x80) ? wxT("s") : wxT("u")), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + } + + }; + break; + + ///////// + // SOT // + ///////// + case SOT_VAL: + { + if (m_file->Read(twobytes, 2) != 2) + break; + unsigned short int isot = STREAM_TO_UINT16(twobytes, 0); + + if (m_file->Read(fourbytes, 4) != 4) + break; + unsigned long int psot = STREAM_TO_UINT32(fourbytes, 0); + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char tpsot = onebyte[0]; + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char tnsot = onebyte[0]; + + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + wxString::Format(wxT("tile %d, psot = %d, part %d of %d"), isot, psot, tpsot, tnsot), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + lastPsot = psot; + lastsotpos = offset; + inside_sod = 0; + }; + break; + + ///////// + // COC // + ///////// + case COC_VAL: + { + unsigned short int ccoc; + if (csiz < 257) { + if (m_file->Read(onebyte, 1) != 1) + break; + ccoc = onebyte[0]; + } else { + if (m_file->Read(twobytes, 2) != 2) + break; + ccoc = STREAM_TO_UINT16(twobytes, 0); + } + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char scoc = onebyte[0]; + + wxTreeItemId subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("Comp. no. %d"), ccoc), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + wxString text; + if (scoc & 0x01) + text << wxT("Partitioned entropy coder"); + else + text << wxT("Unpartitioned entropy coder"); + + subcurrid = m_tree->AppendItem(currid, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char decomplevs = onebyte[0]; + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char cbswidth = onebyte[0]; + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char cbsheight = onebyte[0]; + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char cbstyle = onebyte[0]; + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char transform = onebyte[0]; + + subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("%d levels (%d resolutions)"), decomplevs, decomplevs + 1), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (transform & 0x01) + text = wxT("5-3 reversible wavelet"); + else + text = wxT("9-7 irreversible wavelet"); + subcurrid = m_tree->AppendItem(currid, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("Code-blocks: %dx%d"), 1 << ((cbswidth & 0x0F) + 2), 1 << ((cbsheight & 0x0F) + 2)), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + image = m_tree->TreeCtrlIcon_Folder; + imageSel = image + 1; + + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + wxT("Coding styles"), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + if (cbstyle & 0x01) + text = wxT("Selective arithmetic coding bypass"); + else + text = wxT("No selective arithmetic coding bypass"); + wxTreeItemId subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (cbstyle & 0x02) + text = wxT("Reset context probabilities on coding pass boundaries"); + else + text = wxT("No reset of context probabilities on coding pass boundaries"); + subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (cbstyle & 0x04) + text = wxT("Termination on each coding passs"); + else + text = wxT("No termination on each coding pass"); + subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (cbstyle & 0x08) + text = wxT("Vertically stripe causal context"); + else + text = wxT("No vertically stripe causal context"); + subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (cbstyle & 0x10) + text = wxT("Predictable termination"); + else + text = wxT("No predictable termination"); + subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (cbstyle & 0x20) + text = wxT("Segmentation symbols are used"); + else + text = wxT("No segmentation symbols are used"); + subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + } + break; + + ///////// + // COD // + ///////// + case COD_VAL: + { + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char scod = onebyte[0]; + + wxString text; + + if (scod & 0x01) + text << wxT("Partitioned entropy coder"); + else + text << wxT("Unpartitioned entropy coder"); + + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + text = wxT(""); + if (scod & 0x02) + text << wxT("Possible SOPs"); + else + text << wxT("No SOPs"); + + if (scod & 0x04) + text << wxT(", possible EPHs"); + else + text << wxT(", no EPHs"); + + subcurrid3 = m_tree->AppendItem(currid, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char progord = onebyte[0]; + + if (m_file->Read(twobytes, 2) != 2) + break; + unsigned short int numlayers = STREAM_TO_UINT16(twobytes, 0); + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char mctransform = onebyte[0]; + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char decomplevs = onebyte[0]; + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char cbswidth = onebyte[0]; + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char cbsheight = onebyte[0]; + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char cbstyle = onebyte[0]; + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char transform = onebyte[0]; + + subcurrid3 = m_tree->AppendItem(currid, + wxString::Format(wxT("%d levels (%d resolutions)"), decomplevs, decomplevs + 1), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + text = wxT(""); + switch (progord) { + case (0): + text << wxT("LRCP"); + break; + case (1): + text << wxT("RLCP"); + break; + case (2): + text << wxT("LRCP"); + break; + case (3): + text << wxT("RPCL"); + break; + case (4): + text << wxT("CPRL"); + break; + default: + text << wxT("unknown progression"); + break; + } + text << wxString::Format(wxT(", %d layers"), numlayers); + if (transform & 0x01) + text << wxT(", 5-3 rev."); + else + text << wxT(", 9-7 irr."); + subcurrid3 = m_tree->AppendItem(currid, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + subcurrid3 = m_tree->AppendItem(currid, + wxString::Format(wxT("Code-blocks: %dx%d"), 1 << ((cbswidth & 0x0F) + 2), 1 << ((cbsheight & 0x0F) + 2)), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + switch (mctransform) { + case (0): + { + text = wxT("No MCT"); + } + break; + case (1): + { + text = wxT("Reversible MCT on 0, 1, 2"); + } + break; + case (2): + { + text = wxT("Irreversible MCT on 0, 1, 2"); + } + break; + default: + { + text = wxT("Unknown"); + } + break; + }; + subcurrid3 = m_tree->AppendItem(currid, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + + image = m_tree->TreeCtrlIcon_Folder; + imageSel = image + 1; + + subcurrid3 = m_tree->AppendItem(currid, + wxT("Coding styles"), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + if (cbstyle & 0x01) + text = wxT("Selective arithmetic coding bypass"); + else + text = wxT("No selective arithmetic coding bypass"); + wxTreeItemId subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (cbstyle & 0x02) + text = wxT("Reset context probabilities on coding pass boundaries"); + else + text = wxT("No reset of context probabilities on coding pass boundaries"); + subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (cbstyle & 0x04) + text = wxT("Termination on each coding passs"); + else + text = wxT("No termination on each coding pass"); + subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (cbstyle & 0x08) + text = wxT("Vertically stripe causal context"); + else + text = wxT("No vertically stripe causal context"); + subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (cbstyle & 0x10) + text = wxT("Predictable termination"); + else + text = wxT("No predictable termination"); + subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (cbstyle & 0x20) + text = wxT("Segmentation symbols are used"); + else + text = wxT("No segmentation symbols are used"); + subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + }; + break; + + ///////// + // QCC // + ///////// + case QCC_VAL: + { + unsigned short int cqcc; + if (csiz < 257) { + if (m_file->Read(onebyte, 1) != 1) + break; + cqcc = onebyte[0]; + } else { + if (m_file->Read(twobytes, 2) != 2) + break; + cqcc = STREAM_TO_UINT16(twobytes, 0); + } + + wxTreeItemId subcurrid = m_tree->AppendItem(currid, + wxString::Format(wxT("Comp. no. %d"), cqcc), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char sqcc = onebyte[0]; + + wxString text; + switch (sqcc & 0x1F) { + case (0): + text = wxT("No quantization"); + break; + case (1): + text = wxT("Scalar implicit"); + break; + case (2): + text = wxT("Scalar explicit"); + break; + default: + text = wxT("Unknown"); + break; + } + text << wxString::Format(wxT(", %d guard bits"), (sqcc & 0xE0) >> 5); + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + } + break; + + ///////// + // QCD // + ///////// + case QCD_VAL: + { + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char sqcd = onebyte[0]; + + wxString text; + switch (sqcd & 0x1F) { + case (0): + text = wxT("No quantization"); + break; + case (1): + text = wxT("Scalar implicit"); + break; + case (2): + text = wxT("Scalar explicit"); + break; + default: + text = wxT("Unknown"); + break; + } + text << wxString::Format(wxT(", %d guard bits"), (sqcd & 0xE0) >> 5); + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + }; + break; + + ///////// + // COM // + ///////// + case COM_VAL: + { + #define showlen 25 + char comment[showlen]; + wxString comments; + + if (m_file->Read(twobytes, 2) != 2) + break; + unsigned short int rcom = STREAM_TO_UINT16(twobytes, 0); + + wxString text; + if (rcom == 0) + text = wxT("Binary values"); + else if (rcom == 1) + text = wxT("ISO 8859-1 (latin-1) values"); + else if (rcom < 65535) + text = wxT("Reserved for registration"); + else + text = wxT("Reserved for extension"); + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (m_file->Read(comment, showlen) != showlen) + break; + comments = wxString::FromAscii(comment).Truncate(wxMin(showlen, currlen - 4)); + if ((currlen - 4) > showlen) + comments << wxT("..."); + subcurrid3 = m_tree->AppendItem(currid, + comments, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + }; + break; + + ///////// + // TLM // + ///////// + case TLM_VAL: + { + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char ztlm = onebyte[0]; + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char stlm = onebyte[0]; + + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + wxString::Format(wxT("TLM #%d"), ztlm), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + subcurrid3 = m_tree->AppendItem(currid, + wxString::Format(wxT("%d bits/index, %d bits/length"), + 8 * ((stlm & 0x30) >> 4), 16 + 16 * ((stlm & 0x40) >> 6)), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + int n, numparts; + + numparts = (currlen - 2) / ( ((stlm & 0x30) >> 4) + 2 + 2 * ((stlm & 0x40) >> 6)); + + image = m_tree->TreeCtrlIcon_Folder; + imageSel = image + 1; + + subcurrid3 = m_tree->AppendItem(currid, + wxT("Tile parts"), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + for (n = 0; n < numparts; n++) { + + unsigned short int ttlm; + unsigned long int ptlm; + + switch (((stlm & 0x30) >> 4)) { + + case 0: + ttlm = 0; + break; + + case 1: + if (m_file->Read(onebyte, 1) != 1) + break; + ttlm = onebyte[0]; + break; + + case 2: + if (m_file->Read(twobytes, 2) != 2) + break; + ttlm = STREAM_TO_UINT16(twobytes, 0); + break; + + } + + switch (((stlm & 0x40) >> 6)) { + + case 0: + if (m_file->Read(twobytes, 2) != 2) + break; + ptlm = STREAM_TO_UINT16(twobytes, 0); + break; + + case 1: + if (m_file->Read(fourbytes, 4) != 4) + break; + ptlm = STREAM_TO_UINT32(fourbytes, 0); + break; + + } + + wxTreeItemId subcurrid4 = m_tree->AppendItem(subcurrid3, + wxString::Format(wxT("Tile %d: %d bytes"), ttlm, ptlm), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + } + + } + break; + + ///////// + // POD // + ///////// + case POD_VAL: + { + int n, numchanges; + + if (csiz < 257) + numchanges = (currlen - 2) / 7; + else + numchanges = (currlen - 2) / 9; + + for (n = 0; n < numchanges; n++) { + + image = m_tree->TreeCtrlIcon_Folder; + imageSel = image + 1; + + wxTreeItemId subcurrid3 = m_tree->AppendItem(currid, + wxString::Format(wxT("Change #%d"), n), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char rspod = onebyte[0]; + + unsigned short int cspod; + if (csiz < 257) { + if (m_file->Read(onebyte, 1) != 1) + break; + cspod = onebyte[0]; + } else { + if (m_file->Read(twobytes, 2) != 2) + break; + cspod = STREAM_TO_UINT16(twobytes, 0); + } + + if (m_file->Read(twobytes, 2) != 2) + break; + unsigned short int lyepod = STREAM_TO_UINT16(twobytes, 0); + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char repod = onebyte[0]; + + unsigned short int cepod; + if (csiz < 257) { + if (m_file->Read(onebyte, 1) != 1) + break; + cepod = onebyte[0]; + } else { + if (m_file->Read(twobytes, 2) != 2) + break; + cepod = STREAM_TO_UINT16(twobytes, 0); + } + + if (m_file->Read(onebyte, 1) != 1) + break; + unsigned char ppod = onebyte[0]; + + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + wxTreeItemId subcurrid4 = m_tree->AppendItem(subcurrid3, + wxString::Format(wxT("%d <= Resolution < %d"), rspod, repod), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + subcurrid4 = m_tree->AppendItem(subcurrid3, + wxString::Format(wxT("%d <= Component < %d"), cspod, cepod), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + subcurrid4 = m_tree->AppendItem(subcurrid3, + wxString::Format(wxT("0 <= Layer < %d"), lyepod), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + wxString text = wxT(""); + switch (ppod) { + case (0): + text << wxT("LRCP"); + break; + case (1): + text << wxT("RLCP"); + break; + case (2): + text << wxT("LRCP"); + break; + case (3): + text << wxT("RPCL"); + break; + case (4): + text << wxT("CPRL"); + break; + default: + text << wxT("unknown progression"); + break; + } + subcurrid4 = m_tree->AppendItem(subcurrid3, + text, + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + } + + } + break; + + ///////// + // SOD // + ///////// + case SOD_VAL: + { + inside_sod = 1; + }; + break; + + default: + break; + + } + + // increment number of markers + if (nmarks++ >= maxmarks) { + WriteText(wxT("Maximum amount of markers exceeded")); + break; + } + + // advance position + OPJ_ADVANCE(currlen + 2); + } + + WriteText(wxT("Search finished")); +} diff --git a/openjpeg/src/bin/wx/OPJViewer/source/wxjp2parser.cpp b/openjpeg/src/bin/wx/OPJViewer/source/wxjp2parser.cpp new file mode 100644 index 000000000..853c648d8 --- /dev/null +++ b/openjpeg/src/bin/wx/OPJViewer/source/wxjp2parser.cpp @@ -0,0 +1,1121 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2007, Digital Signal Processing Laboratory, Università degli studi di Perugia (UPG), Italy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "OPJViewer.h" + +/* defines */ +#define SHORT_DESCR_LEN 32 +#define LONG_DESCR_LEN 256 + +/* enumeration for file formats */ +#define J2FILENUM 4 +typedef enum { + + JP2_FILE, + J2K_FILE, + MJ2_FILE, + UNK_FILE + +} j2filetype; + +/* enumeration for the box types */ +#define j22boxNUM 23 +typedef enum { + + FILE_BOX, + JP_BOX, + FTYP_BOX, + JP2H_BOX, + IHDR_BOX, + COLR_BOX, + JP2C_BOX, + JP2I_BOX, + XML_BOX, + UUID_BOX, + UINF_BOX, + MOOV_BOX, + MVHD_BOX, + TRAK_BOX, + TKHD_BOX, + MDIA_BOX, + MDHD_BOX, + HDLR_BOX, + MINF_BOX, + VMHD_BOX, + STBL_BOX, + STSD_BOX, + STSZ_BOX, + MJP2_BOX, + MDAT_BOX, + ANY_BOX, + UNK_BOX + +} j22boxtype; + +/* the box structure itself */ +struct boxdef { + + char value[5]; /* hexadecimal value/string*/ + char name[SHORT_DESCR_LEN]; /* short description */ + char descr[LONG_DESCR_LEN]; /* long description */ + int sbox; /* is it a superbox? */ + int req[J2FILENUM]; /* mandatory box */ + j22boxtype ins; /* contained in box... */ + +}; + + +/* jp2 family box signatures */ +#define FILE_SIGN "" +#define JP_SIGN "jP\040\040" +#define FTYP_SIGN "ftyp" +#define JP2H_SIGN "jp2h" +#define IHDR_SIGN "ihdr" +#define COLR_SIGN "colr" +#define JP2C_SIGN "jp2c" +#define JP2I_SIGN "jp2i" +#define XML_SIGN "xml\040" +#define UUID_SIGN "uuid" +#define UINF_SIGN "uinf" +#define MOOV_SIGN "moov" +#define MVHD_SIGN "mvhd" +#define TRAK_SIGN "trak" +#define TKHD_SIGN "tkhd" +#define MDIA_SIGN "mdia" +#define MDHD_SIGN "mdhd" +#define HDLR_SIGN "hdlr" +#define MINF_SIGN "minf" +#define VMHD_SIGN "vmhd" +#define STBL_SIGN "stbl" +#define STSD_SIGN "stsd" +#define STSZ_SIGN "stsz" +#define MJP2_SIGN "mjp2" +#define MDAT_SIGN "mdat" +#define ANY_SIGN "" +#define UNK_SIGN "" + +/* the possible boxes */ +struct boxdef j22box[] = +{ +/* sign */ {FILE_SIGN, +/* short */ "placeholder for nothing", +/* long */ "Nothing to say", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {JP_SIGN, +/* short */ "JPEG 2000 Signature box", +/* long */ "This box uniquely identifies the file as being part of the JPEG 2000 family of files", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {FTYP_SIGN, +/* short */ "File Type box", +/* long */ "This box specifies file type, version and compatibility information, including specifying if this file " + "is a conforming JP2 file or if it can be read by a conforming JP2 reader", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {JP2H_SIGN, +/* short */ "JP2 Header box", +/* long */ "This box contains a series of boxes that contain header-type information about the file", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {IHDR_SIGN, +/* short */ "Image Header box", +/* long */ "This box specifies the size of the image and other related fields", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ JP2H_BOX}, + +/* sign */ {COLR_SIGN, +/* short */ "Colour Specification box", +/* long */ "This box specifies the colourspace of the image", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ JP2H_BOX}, + +/* sign */ {JP2C_SIGN, +/* short */ "Contiguous Codestream box", +/* long */ "This box contains the codestream as defined by Annex A", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {JP2I_SIGN, +/* short */ "Intellectual Property box", +/* long */ "This box contains intellectual property information about the image", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {XML_SIGN, +/* short */ "XML box", +/* long */ "This box provides a tool by which vendors can add XML formatted information to a JP2 file", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {UUID_SIGN, +/* short */ "UUID box", +/* long */ "This box provides a tool by which vendors can add additional information to a file " + "without risking conflict with other vendors", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {UINF_SIGN, +/* short */ "UUID Info box", +/* long */ "This box provides a tool by which a vendor may provide access to additional information associated with a UUID", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {MOOV_SIGN, +/* short */ "Movie box", +/* long */ "This box contains the media data. In video tracks, this box would contain JPEG2000 video frames", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {MVHD_SIGN, +/* short */ "Movie Header box", +/* long */ "This box defines overall information which is media-independent, and relevant to the entire presentation " + "considered as a whole", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ MOOV_BOX}, + +/* sign */ {TRAK_SIGN, +/* short */ "Track box", +/* long */ "This is a container box for a single track of a presentation. A presentation may consist of one or more tracks", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ MOOV_BOX}, + +/* sign */ {TKHD_SIGN, +/* short */ "Track Header box", +/* long */ "This box specifies the characteristics of a single track. Exactly one Track Header Box is contained in a track", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ TRAK_BOX}, + +/* sign */ {MDIA_SIGN, +/* short */ "Media box", +/* long */ "The media declaration container contains all the objects which declare information about the media data " + "within a track", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ TRAK_BOX}, + +/* sign */ {MDHD_SIGN, +/* short */ "Media Header box", +/* long */ "The media header declares overall information which is media-independent, and relevant to characteristics " + "of the media in a track", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ MDIA_BOX}, + +/* sign */ {HDLR_SIGN, +/* short */ "Handler Reference box", +/* long */ "This box within a Media Box declares the process by which the media-data in the track may be presented, " + "and thus, the nature of the media in a track", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ MDIA_BOX}, + +/* sign */ {MINF_SIGN, +/* short */ "Media Information box", +/* long */ "This box contains all the objects which declare characteristic information of the media in the track", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ MDIA_BOX}, + +/* sign */ {VMHD_SIGN, +/* short */ "Video Media Header box", +/* long */ "The video media header contains general presentation information, independent of the coding, for video media", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ MINF_BOX}, + +/* sign */ {STBL_SIGN, +/* short */ "Sample Table box", +/* long */ "The sample table contains all the time and data indexing of the media samples in a track", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ MINF_BOX}, + +/* sign */ {STSD_SIGN, +/* short */ "STSD Sample Description box", +/* long */ "The sample description table gives detailed information about the coding type used, and any initialization " + "information needed for that coding", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ MINF_BOX}, + +/* sign */ {STSZ_SIGN, +/* short */ "Sample Size box", +/* long */ "This box contains the sample count and a table giving the size of each sample", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ STBL_BOX}, + +/* sign */ {MJP2_SIGN, +/* short */ "MJP2 Sample Description box", +/* long */ "The MJP2 sample description table gives detailed information about the coding type used, and any initialization " + "information needed for that coding", +/* sbox */ 0, +/* req */ {1, 1, 1}, +/* ins */ MINF_BOX}, + +/* sign */ {MDAT_SIGN, +/* short */ "Media Data box", +/* long */ "The meta-data for a presentation is stored in the single Movie Box which occurs at the top-level of a file", +/* sbox */ 1, +/* req */ {1, 1, 1}, +/* ins */ FILE_BOX}, + +/* sign */ {ANY_SIGN, +/* short */ "Any box", +/* long */ "All the existing boxes", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ FILE_BOX}, + +/* sign */ {UNK_SIGN, +/* short */ "Unknown Type box", +/* long */ "The signature is not recognised to be that of an existing box", +/* sbox */ 0, +/* req */ {0, 0, 0}, +/* ins */ ANY_BOX} + +}; + + +/* macro functions */ +/* From little endian to big endian, 2 and 4 bytes */ +#define BYTE_SWAP2(X) ((X & 0x00FF) << 8) | ((X & 0xFF00) >> 8) +#define BYTE_SWAP4(X) ((X & 0x000000FF) << 24) | ((X & 0x0000FF00) << 8) | ((X & 0x00FF0000) >> 8) | ((X & 0xFF000000) >> 24) + +#ifdef __WXGTK__ +#define BYTE_SWAP8(X) ((X & 0x00000000000000FFULL) << 56) | ((X & 0x000000000000FF00ULL) << 40) | \ + ((X & 0x0000000000FF0000ULL) << 24) | ((X & 0x00000000FF000000ULL) << 8) | \ + ((X & 0x000000FF00000000ULL) >> 8) | ((X & 0x0000FF0000000000ULL) >> 24) | \ + ((X & 0x00FF000000000000ULL) >> 40) | ((X & 0xFF00000000000000ULL) >> 56) +#else +#define BYTE_SWAP8(X) ((X & 0x00000000000000FF) << 56) | ((X & 0x000000000000FF00) << 40) | \ + ((X & 0x0000000000FF0000) << 24) | ((X & 0x00000000FF000000) << 8) | \ + ((X & 0x000000FF00000000) >> 8) | ((X & 0x0000FF0000000000) >> 24) | \ + ((X & 0x00FF000000000000) >> 40) | ((X & 0xFF00000000000000) >> 56) +#endif + +/* From codestream to int values */ +#define STREAM_TO_UINT32(C, P) (((unsigned long int) (C)[(P) + 0] << 24) + \ + ((unsigned long int) (C)[(P) + 1] << 16) + \ + ((unsigned long int) (C)[(P) + 2] << 8) + \ + ((unsigned long int) (C)[(P) + 3] << 0)) + +#define STREAM_TO_UINT16(C, P) (((unsigned long int) (C)[(P) + 0] << 8) + \ + ((unsigned long int) (C)[(P) + 1] << 0)) + +#define OPJREAD_LONG(F,L,N) { \ + if (F->Read(fourbytes, 4) < 4) { \ + wxLogMessage(wxT("Problem reading " N " from the file (file ended?)")); \ + return -1; \ + }; \ + L = STREAM_TO_UINT32(fourbytes, 0); \ + } + +/* handling functions */ +#define ITEM_PER_ROW 10 + +//#define indprint if (0) printf("%.*s", 2 * level + 9, indent), printf +char indent[] = " " + " " + " " + " "; + +void indprint(wxString printout, int level) +{ + wxLogMessage(/*wxString::Format(wxT("%.*s"), 2 * level + 9, indent) + */printout); +} + +/* Box handler function */ +int OPJParseThread::box_handler_function(int boxtype, wxFile *fileid, wxFileOffset filepoint, wxFileOffset filelimit, + wxTreeItemId parentid, int level, char *scansign, unsigned long int *scanpoint) +{ + switch ((j22boxtype) boxtype) { + + + /* JPEG 2000 Signature box */ + case (JP_BOX): { + + unsigned long int checkdata = 0; + fileid->Read(&checkdata, sizeof(unsigned long int)); + checkdata = BYTE_SWAP4(checkdata); + + // add info + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Check data: %X -> %s"), checkdata, (checkdata == 0x0D0A870A) ? wxT("OK") : wxT("KO")), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + }; + break; + + + /* JPEG 2000 codestream box */ + case (JP2C_BOX): { + + // add info + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString(wxT("Codestream")), + m_tree->TreeCtrlIcon_Folder, m_tree->TreeCtrlIcon_Folder + 1, + new OPJMarkerData(wxT("INFO-CSTREAM"), m_tree->m_fname.GetFullPath(), filepoint, filelimit) + ); + + m_tree->SetItemHasChildren(currid); + + // parse the file + //ParseJ2KFile(fileid, filepoint, filelimit, currid); + + }; + break; + + + + + + /* File Type box */ + case (FTYP_BOX): { + + char BR[4], CL[4]; + unsigned long int MinV, numCL, i; + fileid->Read(BR, sizeof(char) * 4); + fileid->Read(&MinV, sizeof(unsigned long int)); + MinV = BYTE_SWAP4(MinV); + numCL = (filelimit - fileid->Tell()) / 4; + + // add info + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxT("Brand/Minor version: ") + + wxString::FromAscii(BR).Truncate(4) + + wxString::Format(wxT("/%d"), MinV), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Compatibility list")), + m_tree->TreeCtrlIcon_Folder, m_tree->TreeCtrlIcon_Folder + 1, + new OPJMarkerData(wxT("INFO")) + ); + + for (i = 0; i < numCL; i++) { + fileid->Read(CL, sizeof(char) * 4); + m_tree->AppendItem(currid, + wxString::FromAscii(CL).Truncate(4), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + }; + + }; + break; + + + + /* JP2 Header box */ + case (IHDR_BOX): { + + unsigned long int height, width; + unsigned short int nc; + unsigned char bpc, C, UnkC, IPR; + fileid->Read(&height, sizeof(unsigned long int)); + height = BYTE_SWAP4(height); + fileid->Read(&width, sizeof(unsigned long int)); + width = BYTE_SWAP4(width); + fileid->Read(&nc, sizeof(unsigned short int)); + nc = BYTE_SWAP2(nc); + fileid->Read(&bpc, sizeof(unsigned char)); + fileid->Read(&C, sizeof(unsigned char)); + fileid->Read(&UnkC, sizeof(unsigned char)); + fileid->Read(&IPR, sizeof(unsigned char)); + + // add info + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Dimensions: %d x %d x %d @ %d bpc"), width, height, nc, bpc + 1), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Compression type: %d"), C), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Colourspace unknown: %d"), UnkC), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Intellectual Property Rights: %d"), IPR), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + }; + break; + + + + /* Colour Specification box */ + case (COLR_BOX): { + + unsigned char METH, PREC, APPROX; + char methdescr[80], enumcsdescr[80]; + unsigned long int EnumCS; + fileid->Read(&METH, sizeof(unsigned char)); + switch (METH) { + case 1: + strcpy(methdescr, "Enumerated Colourspace"); + break; + case 2: + strcpy(methdescr, "Restricted ICC profile"); + break; + default: + strcpy(methdescr, "Unknown"); + break; + }; + fileid->Read(&PREC, sizeof(unsigned char)); + fileid->Read(&APPROX, sizeof(unsigned char)); + if (METH != 2) { + fileid->Read(&EnumCS, sizeof(unsigned long int)); + EnumCS = BYTE_SWAP4(EnumCS); + switch (EnumCS) { + case 16: + strcpy(enumcsdescr, "sRGB"); + break; + case 17: + strcpy(enumcsdescr, "greyscale"); + break; + case 18: + strcpy(enumcsdescr, "sYCC"); + break; + default: + strcpy(enumcsdescr, "Unknown"); + break; + }; + }; + + // add info + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Specification method: %d ("), METH) + + wxString::FromAscii(methdescr) + + wxT(")"), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Precedence: %d"), PREC), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Colourspace approximation: %d"), APPROX), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + if (METH != 2) + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Enumerated colourspace: %d ("), EnumCS) + + wxString::FromAscii(enumcsdescr) + + wxT(")"), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + if (METH != 1) + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("ICC profile: there is one")), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + + }; + break; + + + + + + + /* Movie Header Box */ + case (MVHD_BOX): { + + unsigned long int version, rate, matrix[9], next_track_ID; + unsigned short int volume; + fileid->Read(&version, sizeof(unsigned long int)); + version = BYTE_SWAP4(version); + if (version == 0) { + unsigned long int creation_time, modification_time, timescale, duration; + fileid->Read(&creation_time, sizeof(unsigned long int)); + creation_time = BYTE_SWAP4(creation_time); + fileid->Read(&modification_time, sizeof(unsigned long int)); + modification_time = BYTE_SWAP4(modification_time); + fileid->Read(×cale, sizeof(unsigned long int)); + timescale = BYTE_SWAP4(timescale); + fileid->Read(&duration, sizeof(unsigned long int)); + duration = BYTE_SWAP4(duration); + const long unix_time = creation_time - 2082844800L; + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Creation time: %u (%.24s)"), creation_time, ctime(&unix_time)), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + const long unix_time1 = modification_time - 2082844800L; + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Modification time: %u (%.24s)"), modification_time, ctime(&unix_time1)), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Timescale: %u (%.6fs)"), timescale, 1.0 / (float) timescale), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Duration: %u (%.3fs)"), duration, (float) duration / (float) timescale), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + } else { + int8byte creation_time, modification_time, duration; + unsigned long int timescale; + fileid->Read(&creation_time, sizeof(int8byte)); + creation_time = BYTE_SWAP8(creation_time); + fileid->Read(&modification_time, sizeof(int8byte)); + modification_time = BYTE_SWAP8(modification_time); + fileid->Read(×cale, sizeof(unsigned long int)); + timescale = BYTE_SWAP4(timescale); + fileid->Read(&duration, sizeof(int8byte)); + duration = BYTE_SWAP8(duration); + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Creation time: %u"), creation_time), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Modification time: %u"), modification_time), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Timescale: %u"), timescale), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Duration: %u"), duration), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + }; + fileid->Read(&rate, sizeof(unsigned long int)); + rate = BYTE_SWAP4(rate); + fileid->Read(&volume, sizeof(unsigned short int)); + volume = BYTE_SWAP2(volume); + fileid->Seek(6, wxFromCurrent); + fileid->Read(&matrix, sizeof(unsigned char) * 9); + fileid->Seek(4, wxFromCurrent); + fileid->Read(&next_track_ID, sizeof(unsigned long int)); + next_track_ID = BYTE_SWAP4(next_track_ID); + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Rate: %d (%d.%d)"), rate, rate >> 16, rate & 0x0000FFFF), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Volume: %d (%d.%d)"), volume, volume >> 8, volume & 0x00FF), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Next track ID: %d"), next_track_ID), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + }; + break; + + + /* Sample Description box */ + case (STSD_BOX): { + + unsigned long int version, entry_count; + fileid->Read(&version, sizeof(unsigned long int)); + version = BYTE_SWAP4(version); + fileid->Read(&entry_count, sizeof(unsigned long int)); + entry_count = BYTE_SWAP4(entry_count); + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Entry count: %d"), entry_count), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO"), m_tree->m_fname.GetFullPath(), filepoint, filelimit) + ); + jpeg2000parse(fileid, filepoint + 8, filelimit, parentid, level + 1, scansign, scanpoint); + }; + break; + + + /* Sample Size box */ + case (STSZ_BOX): { + + unsigned long int version, sample_size, sample_count, entry_size; + + fileid->Read(&version, sizeof(unsigned long int)); + version = BYTE_SWAP4(version); + + fileid->Read(&sample_size, sizeof(unsigned long int)); + sample_size = BYTE_SWAP4(sample_size); + + if (sample_size == 0) { + fileid->Read(&sample_count, sizeof(unsigned long int)); + sample_count = BYTE_SWAP4(sample_count); + + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Sample count: %d"), sample_count), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO"), m_tree->m_fname.GetFullPath(), filepoint, filelimit) + ); + + currid = m_tree->AppendItem(parentid, + wxT("Entries size (bytes)"), + m_tree->TreeCtrlIcon_Folder, m_tree->TreeCtrlIcon_Folder + 1, + new OPJMarkerData(wxT("INFO"), m_tree->m_fname.GetFullPath(), filepoint, filelimit) + ); + + wxString text; + for (unsigned int s = 0; s < sample_count; s++) { + fileid->Read(&entry_size, sizeof(unsigned long int)); + entry_size = BYTE_SWAP4(entry_size); + + text << wxString::Format(wxT("%d, "), entry_size); + + if (((s % 10) == (ITEM_PER_ROW - 1)) || (s == (sample_count - 1))) { + m_tree->AppendItem(currid, + text, + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO"), m_tree->m_fname.GetFullPath(), filepoint, filelimit) + ); + text = wxT(""); + } + + } + + } + + }; + break; + + + /* Video Media Header box */ + case (VMHD_BOX): { + + unsigned long int version; + unsigned short int graphicsmode, opcolor[3]; + char graphicsdescr[100]; + + fileid->Read(&version, sizeof(unsigned long int)); + version = BYTE_SWAP4(version); + + fileid->Read(&graphicsmode, sizeof(unsigned short int)); + graphicsmode = BYTE_SWAP2(graphicsmode); + switch (graphicsmode) { + case (0x00): + strcpy(graphicsdescr, "copy"); + break; + case (0x24): + strcpy(graphicsdescr, "transparent"); + break; + case (0x0100): + strcpy(graphicsdescr, "alpha"); + break; + case (0x0101): + strcpy(graphicsdescr, "whitealpha"); + break; + case (0x0102): + strcpy(graphicsdescr, "blackalpha"); + break; + default: + strcpy(graphicsdescr, "unknown"); + break; + }; + + fileid->Read(opcolor, 3 * sizeof(unsigned short int)); + opcolor[0] = BYTE_SWAP2(opcolor[0]); + opcolor[1] = BYTE_SWAP2(opcolor[1]); + opcolor[2] = BYTE_SWAP2(opcolor[2]); + + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Composition mode: %d (")) + + wxString::FromAscii(graphicsdescr) + + wxT(")"), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO"), m_tree->m_fname.GetFullPath(), filepoint, filelimit) + ); + + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("OP color: %d %d %d"), opcolor[0], opcolor[1], opcolor[2]), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO"), m_tree->m_fname.GetFullPath(), filepoint, filelimit) + ); + }; + break; + + + + /* MJP2 Sample Description box */ + case (MJP2_BOX): { + + unsigned short int height, width, depth; + unsigned long int horizresolution, vertresolution; + char compressor_name[32]; + fileid->Seek(24, wxFromCurrent); + fileid->Read(&width, sizeof(unsigned short int)); + width = BYTE_SWAP2(width); + fileid->Read(&height, sizeof(unsigned short int)); + height = BYTE_SWAP2(height); + fileid->Read(&horizresolution, sizeof(unsigned long int)); + horizresolution = BYTE_SWAP4(horizresolution); + fileid->Read(&vertresolution, sizeof(unsigned long int)); + vertresolution = BYTE_SWAP4(vertresolution); + fileid->Seek(6, wxFromCurrent); + fileid->Read(compressor_name, sizeof(char) * 32); + fileid->Read(&depth, sizeof(unsigned short int)); + depth = BYTE_SWAP2(depth); + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Dimensions: %d x %d @ %d bpp"), width, height, depth), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO"), m_tree->m_fname.GetFullPath(), filepoint, filelimit) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Resolution: %d.%d x %d.%d"), horizresolution >> 16, horizresolution & 0x0000FFFF, + vertresolution >> 16, vertresolution & 0x0000FFFF), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Compressor: %.32s"), compressor_name), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + jpeg2000parse(fileid, filepoint + 78, filelimit, parentid, level + 1, scansign, scanpoint); + + }; + break; + + /* Media Header box */ + case (MDHD_BOX): { + unsigned long int version; + unsigned short int language; + fileid->Read(&version, sizeof(unsigned long int)); + version = BYTE_SWAP4(version); + if (version == 0) { + unsigned long int creation_time, modification_time, timescale, duration; + fileid->Read(&creation_time, sizeof(unsigned long int)); + creation_time = BYTE_SWAP4(creation_time); + fileid->Read(&modification_time, sizeof(unsigned long int)); + modification_time = BYTE_SWAP4(modification_time); + fileid->Read(×cale, sizeof(unsigned long int)); + timescale = BYTE_SWAP4(timescale); + fileid->Read(&duration, sizeof(unsigned long int)); + duration = BYTE_SWAP4(duration); + const long unix_time = creation_time - 2082844800L; + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Creation time: %u (%.24s)"), creation_time, ctime(&unix_time)), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + const long unix_time1 = modification_time - 2082844800L; + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Modification time: %u (%.24s)"), modification_time, ctime(&unix_time1)), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Timescale: %u (%.6fs)"), timescale, 1.0 / (float) timescale), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Duration: %u (%.3fs)"), duration, (float) duration / (float) timescale), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + } else { + int8byte creation_time, modification_time, duration; + unsigned long int timescale; + fileid->Read(&creation_time, sizeof(int8byte)); + creation_time = BYTE_SWAP8(creation_time); + fileid->Read(&modification_time, sizeof(int8byte)); + modification_time = BYTE_SWAP8(modification_time); + fileid->Read(×cale, sizeof(unsigned long int)); + timescale = BYTE_SWAP4(timescale); + fileid->Read(&duration, sizeof(int8byte)); + duration = BYTE_SWAP8(duration); + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Creation time: %u"), creation_time), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Modification time: %u"), modification_time), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Timescale: %u"), timescale), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Duration: %u"), duration), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + } + fileid->Read(&language, sizeof(unsigned short int)); + + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Language: %d (%c%c%c)"), language & 0xEFFF, + 0x60 + (char) ((language >> 10) & 0x001F), 0x60 + (char) ((language >> 5) & 0x001F), 0x60 + (char) ((language >> 0) & 0x001F)), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + }; + break; + + /* Media Handler box */ + case (HDLR_BOX): { + unsigned long int version, predefined, temp[3]; + char handler[4], name[256]; + int namelen = wxMin(256, (filelimit - filepoint - 24)); + fileid->Read(&version, sizeof(unsigned long int)); + version = BYTE_SWAP4(version); + fileid->Read(&predefined, sizeof(unsigned long int)); + fileid->Read(handler, 4 * sizeof(char)); + fileid->Read(&temp, 3 * sizeof(unsigned long int)); + fileid->Read(name, namelen * sizeof(char)); + + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Handler: %.4s"), handler), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("Name: %.255s"), name), + m_tree->TreeCtrlIcon_File, m_tree->TreeCtrlIcon_File + 1, + new OPJMarkerData(wxT("INFO")) + ); + + } + break; + + /* not yet implemented */ + default: + break; + + }; + + return (0); +} + + +void OPJParseThread::ParseJP2File(wxFile *fileid, wxFileOffset filepoint, wxFileOffset filelimit, wxTreeItemId parentid) +{ + unsigned long int scanpoint; + + jpeg2000parse(fileid, filepoint, filelimit, parentid, 0, NULL, &scanpoint); +} + +/* the parsing function itself */ +/* + fileid = fid of the file to scan (you should open it by yourself) + filepoint = first byte where to start to scan from (usually 0) + filelimit = first byte where to stop to scan from (usually the file size) + level = set this to 0 + scansign = signature to scan for (NULL avoids search, returns " " if successful) + scanpoint = point where the scan signature lies +*/ +int OPJParseThread::jpeg2000parse(wxFile *fileid, wxFileOffset filepoint, wxFileOffset filelimit, + wxTreeItemId parentid, int level, char *scansign, unsigned long int *scanpoint) +{ + unsigned long int LBox = 0x00000000; + //int LBox_read; + char TBox[5] = "\0\0\0\0"; + //int TBox_read; + int8byte XLBox = 0x0000000000000000; + //int XLBox_read; + unsigned long int box_length = 0; + int last_box = 0, box_num = 0; + int box_type = ANY_BOX; + unsigned char /*onebyte[1], twobytes[2],*/ fourbytes[4]; + + /* cycle all over the file */ + box_num = 0; + last_box = 0; + while (!last_box) { + + /* do not exceed file limit */ + if (filepoint >= filelimit) + return (0); + + /* seek on file */ + if (fileid->Seek(filepoint, wxFromStart) == wxInvalidOffset) + return (-1); + + /* read the mandatory LBox, 4 bytes */ + if (fileid->Read(fourbytes, 4) < 4) { + WriteText(wxT("Problem reading LBox from the file (file ended?)")); + return -1; + }; + LBox = STREAM_TO_UINT32(fourbytes, 0); + + /* read the mandatory TBox, 4 bytes */ + if (fileid->Read(TBox, 4) < 4) { + WriteText(wxT("Problem reading TBox from the file (file ended?)")); + return -1; + }; + + /* look if scansign is got */ + if ((scansign != NULL) && (memcmp(TBox, scansign, 4) == 0)) { + memcpy(scansign, " ", 4); + *scanpoint = filepoint; + + /* hack/exploit */ + // stop as soon as you find the codebox + return (0); + + }; + + /* determine the box type */ + for (box_type = JP_BOX; box_type < UNK_BOX; box_type++) + if (memcmp(TBox, j22box[box_type].value, 4) == 0) + break; + + /* read the optional XLBox, 8 bytes */ + if (LBox == 1) { + + if (fileid->Read(&XLBox, 8) < 8) { + WriteText(wxT("Problem reading XLBox from the file (file ended?)")); + return -1; + }; + box_length = (unsigned long int) BYTE_SWAP8(XLBox); + + } else if (LBox == 0x00000000) { + + /* last box in file */ + last_box = 1; + box_length = filelimit - filepoint; + + } else + + box_length = LBox; + + /* show box info */ + + // append the marker + int image, imageSel; + image = m_tree->TreeCtrlIcon_Folder; + imageSel = image + 1; + wxTreeItemId currid = m_tree->AppendItem(parentid, + wxString::Format(wxT("%03d: "), box_num) + + wxString::FromAscii(TBox) + + wxString::Format(wxT(" (0x%04X)"), + ((unsigned long int) TBox[3]) + ((unsigned long int) TBox[2] << 8) + + ((unsigned long int) TBox[1] << 16) + ((unsigned long int) TBox[0] << 24) + ), + image, imageSel, + new OPJMarkerData(wxT("BOX"), m_tree->m_fname.GetFullPath(), filepoint, filepoint + box_length) + ); + + // append some info + image = m_tree->TreeCtrlIcon_File; + imageSel = image + 1; + + // box name + wxTreeItemId subcurrid1 = m_tree->AppendItem(currid, + wxT("*** ") + wxString::FromAscii(j22box[box_type].name) + wxT(" ***"), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + m_tree->SetItemFont(subcurrid1, *wxITALIC_FONT); + + // position and length + wxTreeItemId subcurrid2 = m_tree->AppendItem(currid, + wxLongLong(filepoint).ToString() + wxT(" > ") + wxLongLong(filepoint + box_length - 1).ToString() + + wxT(", ") + wxString::Format(wxT("%d + 8 (%d)"), box_length, box_length + 8), + image, imageSel, + new OPJMarkerData(wxT("INFO")) + ); + + /* go deep in the box */ + box_handler_function((int) box_type, fileid, (LBox == 1) ? (filepoint + 16) : (filepoint + 8), filepoint + box_length, + currid, level, scansign, scanpoint); + + /* if it's a superbox go inside it */ + if (j22box[box_type].sbox) + jpeg2000parse(fileid, (LBox == 1) ? (filepoint + 16) : (filepoint + 8), filepoint + box_length, + currid, level + 1, scansign, scanpoint); + + /* increment box number and filepoint*/ + box_num++; + filepoint += box_length; + + }; + + /* all good */ + return (0); +} + diff --git a/openjpeg/src/lib/openjp2/CMakeLists.txt b/openjpeg/src/lib/openjp2/CMakeLists.txt index 57c1751ef..0b4520384 100644 --- a/openjpeg/src/lib/openjp2/CMakeLists.txt +++ b/openjpeg/src/lib/openjp2/CMakeLists.txt @@ -54,6 +54,8 @@ set(OPENJPEG_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/opj_malloc.c ${CMAKE_CURRENT_SOURCE_DIR}/opj_malloc.h ${CMAKE_CURRENT_SOURCE_DIR}/opj_stdint.h + ${CMAKE_CURRENT_SOURCE_DIR}/sparse_array.c + ${CMAKE_CURRENT_SOURCE_DIR}/sparse_array.h ) if(BUILD_JPIP) add_definitions(-DUSE_JPIP) @@ -89,11 +91,15 @@ if(WIN32) add_library(${OPENJPEG_LIBRARY_NAME} ${OPENJPEG_SRCS}) set(INSTALL_LIBS ${OPENJPEG_LIBRARY_NAME}) else() - # Builds both static and dynamic libs - add_library(${OPENJPEG_LIBRARY_NAME} SHARED ${OPENJPEG_SRCS}) - add_library(openjp2_static STATIC ${OPENJPEG_SRCS}) - set_target_properties(openjp2_static PROPERTIES OUTPUT_NAME ${OPENJPEG_LIBRARY_NAME}) - set(INSTALL_LIBS ${OPENJPEG_LIBRARY_NAME} openjp2_static) + if(BUILD_SHARED_LIBS AND BUILD_STATIC_LIBS) + # Builds both static and dynamic libs + add_library(${OPENJPEG_LIBRARY_NAME} SHARED ${OPENJPEG_SRCS}) + add_library(openjp2_static STATIC ${OPENJPEG_SRCS}) + set_target_properties(openjp2_static PROPERTIES OUTPUT_NAME ${OPENJPEG_LIBRARY_NAME}) + set(INSTALL_LIBS ${OPENJPEG_LIBRARY_NAME} openjp2_static) + else() + add_library(${OPENJPEG_LIBRARY_NAME} ${OPENJPEG_SRCS}) + endif() endif() if(UNIX) @@ -192,12 +198,20 @@ if(OPJ_USE_THREAD AND Threads_FOUND AND CMAKE_USE_PTHREADS_INIT) TARGET_LINK_LIBRARIES(${OPENJPEG_LIBRARY_NAME} ${CMAKE_THREAD_LIBS_INIT}) endif(OPJ_USE_THREAD AND Threads_FOUND AND CMAKE_USE_PTHREADS_INIT) -if(BUILD_BENCH_DWT) - add_executable(bench_dwt bench_dwt.c dwt.c opj_malloc.c thread.c) +if(BUILD_UNIT_TESTS) + add_executable(bench_dwt bench_dwt.c) if(UNIX) - target_link_libraries(bench_dwt m) + target_link_libraries(bench_dwt m ${OPENJPEG_LIBRARY_NAME}) endif() if(OPJ_USE_THREAD AND Threads_FOUND AND CMAKE_USE_PTHREADS_INIT) target_link_libraries(bench_dwt ${CMAKE_THREAD_LIBS_INIT}) endif(OPJ_USE_THREAD AND Threads_FOUND AND CMAKE_USE_PTHREADS_INIT) -endif(BUILD_BENCH_DWT) + + add_executable(test_sparse_array test_sparse_array.c) + if(UNIX) + target_link_libraries(test_sparse_array m ${OPENJPEG_LIBRARY_NAME}) + endif() + if(OPJ_USE_THREAD AND Threads_FOUND AND CMAKE_USE_PTHREADS_INIT) + target_link_libraries(test_sparse_array ${CMAKE_THREAD_LIBS_INIT}) + endif(OPJ_USE_THREAD AND Threads_FOUND AND CMAKE_USE_PTHREADS_INIT) +endif(BUILD_UNIT_TESTS) diff --git a/openjpeg/src/lib/openjp2/bench_dwt.c b/openjpeg/src/lib/openjp2/bench_dwt.c index 5b07365ca..103b681ae 100644 --- a/openjpeg/src/lib/openjp2/bench_dwt.c +++ b/openjpeg/src/lib/openjp2/bench_dwt.c @@ -62,13 +62,14 @@ void init_tilec(opj_tcd_tilecomp_t * l_tilec, l_tilec->y1 = y1; nValues = (size_t)(l_tilec->x1 - l_tilec->x0) * (size_t)(l_tilec->y1 - l_tilec->y0); - l_tilec->data = opj_malloc(sizeof(OPJ_INT32) * nValues); + l_tilec->data = (OPJ_INT32*) opj_malloc(sizeof(OPJ_INT32) * nValues); for (i = 0; i < nValues; i++) { - l_tilec->data[i] = getValue(i); + l_tilec->data[i] = getValue((OPJ_UINT32)i); } l_tilec->numresolutions = numresolutions; - l_tilec->resolutions = opj_calloc(l_tilec->numresolutions, - sizeof(opj_tcd_resolution_t)); + l_tilec->resolutions = (opj_tcd_resolution_t*) opj_calloc( + l_tilec->numresolutions, + sizeof(opj_tcd_resolution_t)); l_level_no = l_tilec->numresolutions; l_res = l_tilec->resolutions; @@ -133,15 +134,20 @@ OPJ_FLOAT64 opj_clock(void) int main(int argc, char** argv) { int num_threads = 0; + opj_tcd_t tcd; + opj_tcd_image_t tcd_image; + opj_tcd_tile_t tcd_tile; opj_tcd_tilecomp_t tilec; + opj_image_t image; + opj_image_comp_t image_comp; opj_thread_pool_t* tp; OPJ_INT32 i, j, k; OPJ_BOOL display = OPJ_FALSE; OPJ_BOOL check = OPJ_FALSE; OPJ_INT32 size = 16384 - 1; OPJ_FLOAT64 start, stop; - OPJ_UINT32 offset_x = (size + 1) / 2 - 1; - OPJ_UINT32 offset_y = (size + 1) / 2 - 1; + OPJ_UINT32 offset_x = ((OPJ_UINT32)size + 1) / 2 - 1; + OPJ_UINT32 offset_y = ((OPJ_UINT32)size + 1) / 2 - 1; OPJ_UINT32 num_resolutions = 6; for (i = 1; i < argc; i++) { @@ -157,7 +163,7 @@ int main(int argc, char** argv) num_threads = atoi(argv[i + 1]); i ++; } else if (strcmp(argv[i], "-num_resolutions") == 0 && i + 1 < argc) { - num_resolutions = atoi(argv[i + 1]); + num_resolutions = (OPJ_UINT32)atoi(argv[i + 1]); if (num_resolutions == 0 || num_resolutions > 32) { fprintf(stderr, "Invalid value for num_resolutions. Should be >= 1 and <= 32\n"); @@ -165,8 +171,8 @@ int main(int argc, char** argv) } i ++; } else if (strcmp(argv[i], "-offset") == 0 && i + 2 < argc) { - offset_x = atoi(argv[i + 1]); - offset_y = atoi(argv[i + 2]); + offset_x = (OPJ_UINT32)atoi(argv[i + 1]); + offset_y = (OPJ_UINT32)atoi(argv[i + 2]); i += 2; } else { usage(); @@ -175,7 +181,8 @@ int main(int argc, char** argv) tp = opj_thread_pool_create(num_threads); - init_tilec(&tilec, offset_x, offset_y, offset_x + size, offset_y + size, + init_tilec(&tilec, (OPJ_INT32)offset_x, (OPJ_INT32)offset_y, + (OPJ_INT32)offset_x + size, (OPJ_INT32)offset_y + size, num_resolutions); if (display) { @@ -190,8 +197,33 @@ int main(int argc, char** argv) } } + memset(&tcd, 0, sizeof(tcd)); + tcd.thread_pool = tp; + tcd.whole_tile_decoding = OPJ_TRUE; + tcd.win_x0 = (OPJ_UINT32)tilec.x0; + tcd.win_y0 = (OPJ_UINT32)tilec.y0; + tcd.win_x1 = (OPJ_UINT32)tilec.x1; + tcd.win_y1 = (OPJ_UINT32)tilec.y1; + tcd.tcd_image = &tcd_image; + memset(&tcd_image, 0, sizeof(tcd_image)); + tcd_image.tiles = &tcd_tile; + memset(&tcd_tile, 0, sizeof(tcd_tile)); + tcd_tile.x0 = tilec.x0; + tcd_tile.y0 = tilec.y0; + tcd_tile.x1 = tilec.x1; + tcd_tile.y1 = tilec.y1; + tcd_tile.numcomps = 1; + tcd_tile.comps = &tilec; + tcd.image = ℑ + memset(&image, 0, sizeof(image)); + image.numcomps = 1; + image.comps = &image_comp; + memset(&image_comp, 0, sizeof(image_comp)); + image_comp.dx = 1; + image_comp.dy = 1; + start = opj_clock(); - opj_dwt_decode(tp, &tilec, tilec.numresolutions); + opj_dwt_decode(&tcd, &tilec, tilec.numresolutions); stop = opj_clock(); printf("time for dwt_decode: %.03f s\n", stop - start); @@ -225,8 +257,8 @@ int main(int argc, char** argv) size_t idx; size_t nValues = (size_t)(tilec.x1 - tilec.x0) * (size_t)(tilec.y1 - tilec.y0); - for (idx = 0; i < nValues; i++) { - if (tilec.data[idx] != getValue(idx)) { + for (idx = 0; i < (OPJ_INT32)nValues; i++) { + if (tilec.data[idx] != getValue((OPJ_UINT32)idx)) { printf("Difference found at idx = %u\n", (OPJ_UINT32)idx); exit(1); } diff --git a/openjpeg/src/lib/openjp2/dwt.c b/openjpeg/src/lib/openjp2/dwt.c index daac74306..5b98d2b38 100644 --- a/openjpeg/src/lib/openjp2/dwt.c +++ b/openjpeg/src/lib/openjp2/dwt.c @@ -63,6 +63,9 @@ /** @defgroup DWT DWT - Implementation of a discrete wavelet transform */ /*@{*/ +#define OPJ_WS(i) v->mem[(i)*2] +#define OPJ_WD(i) v->mem[(1+(i)*2)] + #ifdef __AVX2__ /** Number of int32 values in a AVX2 register */ #define VREG_INT_COUNT 8 @@ -79,10 +82,9 @@ typedef struct dwt_local { OPJ_INT32* mem; - OPJ_SIZE_T mem_count; - OPJ_INT32 dn; - OPJ_INT32 sn; - OPJ_INT32 cas; + OPJ_INT32 dn; /* number of elements in high pass band */ + OPJ_INT32 sn; /* number of elements in low pass band */ + OPJ_INT32 cas; /* 0 = start on even coord, 1 = start on odd coord */ } opj_dwt_t; typedef union { @@ -91,9 +93,13 @@ typedef union { typedef struct v4dwt_local { opj_v4_t* wavelet ; - OPJ_INT32 dn ; - OPJ_INT32 sn ; - OPJ_INT32 cas ; + OPJ_INT32 dn ; /* number of elements in high pass band */ + OPJ_INT32 sn ; /* number of elements in low pass band */ + OPJ_INT32 cas ; /* 0 = start on even coord, 1 = start on odd coord */ + OPJ_UINT32 win_l_x0; /* start coord in low pass band */ + OPJ_UINT32 win_l_x1; /* end coord in low pass band */ + OPJ_UINT32 win_h_x0; /* start coord in high pass band */ + OPJ_UINT32 win_h_x1; /* end coord in high pass band */ } opj_v4dwt_t ; static const OPJ_FLOAT32 opj_dwt_alpha = 1.586134342f; /* 12994 */ @@ -127,14 +133,13 @@ static void opj_dwt_deinterleave_v(OPJ_INT32 *a, OPJ_INT32 *b, OPJ_INT32 dn, /** Forward 5-3 wavelet transform in 1-D */ -static void opj_dwt_decode_1(const opj_dwt_t *v); -static void opj_dwt_encode_1(OPJ_INT32 *a, OPJ_SIZE_T a_count, OPJ_INT32 dn, - OPJ_INT32 sn, OPJ_INT32 cas); +static void opj_dwt_encode_1(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, + OPJ_INT32 cas); /** Forward 9-7 wavelet transform in 1-D */ -static void opj_dwt_encode_1_real(OPJ_INT32 *a, OPJ_SIZE_T a_count, - OPJ_INT32 dn, OPJ_INT32 sn, OPJ_INT32 cas); +static void opj_dwt_encode_1_real(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, + OPJ_INT32 cas); /** Explicit calculation of the Quantization Stepsizes */ @@ -144,11 +149,14 @@ static void opj_dwt_encode_stepsize(OPJ_INT32 stepsize, OPJ_INT32 numbps, Inverse wavelet transform in 2-D. */ static OPJ_BOOL opj_dwt_decode_tile(opj_thread_pool_t* tp, - const opj_tcd_tilecomp_t* tilec, - OPJ_UINT32 numres, DWT1DFN fn); + opj_tcd_tilecomp_t* tilec, OPJ_UINT32 i); + +static OPJ_BOOL opj_dwt_decode_partial_tile( + opj_tcd_tilecomp_t* tilec, + OPJ_UINT32 numres); -static OPJ_BOOL opj_dwt_encode_procedure(const opj_tcd_tilecomp_t * tilec, - void (*p_function)(OPJ_INT32 *, OPJ_SIZE_T,OPJ_INT32,OPJ_INT32,OPJ_INT32) ); +static OPJ_BOOL opj_dwt_encode_procedure(opj_tcd_tilecomp_t * tilec, + void (*p_function)(OPJ_INT32 *, OPJ_INT32, OPJ_INT32, OPJ_INT32)); static OPJ_UINT32 opj_dwt_max_resolution(opj_tcd_resolution_t* OPJ_RESTRICT r, OPJ_UINT32 i); @@ -158,25 +166,38 @@ static OPJ_UINT32 opj_dwt_max_resolution(opj_tcd_resolution_t* OPJ_RESTRICT r, /* </summary> */ static void opj_v4dwt_decode(opj_v4dwt_t* OPJ_RESTRICT dwt); -static void opj_v4dwt_interleave_h(opj_v4dwt_t* OPJ_RESTRICT w, - OPJ_FLOAT32* OPJ_RESTRICT a, OPJ_INT32 x, OPJ_INT32 size); +static void opj_v4dwt_interleave_h(opj_v4dwt_t* OPJ_RESTRICT dwt, + OPJ_FLOAT32* OPJ_RESTRICT a, + OPJ_UINT32 width, + OPJ_UINT32 remaining_height); -static void opj_v4dwt_interleave_v(opj_v4dwt_t* OPJ_RESTRICT v, - OPJ_FLOAT32* OPJ_RESTRICT a, OPJ_INT32 x, OPJ_INT32 nb_elts_read); +static void opj_v4dwt_interleave_v(opj_v4dwt_t* OPJ_RESTRICT dwt, + OPJ_FLOAT32* OPJ_RESTRICT a, + OPJ_UINT32 width, + OPJ_UINT32 nb_elts_read); #ifdef __SSE__ -static void opj_v4dwt_decode_step1_sse(opj_v4_t* w, OPJ_INT32 count, +static void opj_v4dwt_decode_step1_sse(opj_v4_t* w, + OPJ_UINT32 start, + OPJ_UINT32 end, const __m128 c); -static void opj_v4dwt_decode_step2_sse(opj_v4_t* l, opj_v4_t* w, OPJ_INT32 k, - OPJ_INT32 m, __m128 c); +static void opj_v4dwt_decode_step2_sse(opj_v4_t* l, opj_v4_t* w, + OPJ_UINT32 start, + OPJ_UINT32 end, + OPJ_UINT32 m, __m128 c); #else -static void opj_v4dwt_decode_step1(opj_v4_t* w, OPJ_INT32 count, +static void opj_v4dwt_decode_step1(opj_v4_t* w, + OPJ_UINT32 start, + OPJ_UINT32 end, const OPJ_FLOAT32 c); -static void opj_v4dwt_decode_step2(opj_v4_t* l, opj_v4_t* w, OPJ_INT32 k, - OPJ_INT32 m, OPJ_FLOAT32 c); +static void opj_v4dwt_decode_step2(opj_v4_t* l, opj_v4_t* w, + OPJ_UINT32 start, + OPJ_UINT32 end, + OPJ_UINT32 m, + OPJ_FLOAT32 c); #endif @@ -184,24 +205,19 @@ static void opj_v4dwt_decode_step2(opj_v4_t* l, opj_v4_t* w, OPJ_INT32 k, /*@}*/ -#define IDX_S(i) (i)*2 -#define IDX_D(i) 1+(i)*2 -#define UNDERFLOW_SN(i) ((i)>=sn&&sn>0) -#define UNDERFLOW_DN(i) ((i)>=dn&&dn>0) -#define OVERFLOW_S(i) (IDX_S(i)>=a_count) -#define OVERFLOW_D(i) (IDX_D(i)>=a_count) - -#define OPJ_S(i) a[IDX_S(i)] -#define OPJ_D(i) a[IDX_D(i)] -#define OPJ_S_(i) ((i)<0?OPJ_S(0):(UNDERFLOW_SN(i)?OPJ_S(sn-1):OVERFLOW_S(i)?OPJ_S(i-1):OPJ_S(i))) -#define OPJ_D_(i) ((i)<0?OPJ_D(0):(UNDERFLOW_DN(i)?OPJ_D(dn-1):OVERFLOW_D(i)?OPJ_D(i-1):OPJ_D(i))) +#define OPJ_S(i) a[(i)*2] +#define OPJ_D(i) a[(1+(i)*2)] +#define OPJ_S_(i) ((i)<0?OPJ_S(0):((i)>=sn?OPJ_S(sn-1):OPJ_S(i))) +#define OPJ_D_(i) ((i)<0?OPJ_D(0):((i)>=dn?OPJ_D(dn-1):OPJ_D(i))) /* new */ -#define OPJ_SS_(i) ((i)<0?OPJ_S(0):(UNDERFLOW_DN(i)?OPJ_S(dn-1):OVERFLOW_S(i)?OPJ_S(i-1):OPJ_S(i))) -#define OPJ_DD_(i) ((i)<0?OPJ_D(0):(UNDERFLOW_SN(i)?OPJ_D(sn-1):OVERFLOW_D(i)?OPJ_D(i-1):OPJ_D(i))) +#define OPJ_SS_(i) ((i)<0?OPJ_S(0):((i)>=dn?OPJ_S(dn-1):OPJ_S(i))) +#define OPJ_DD_(i) ((i)<0?OPJ_D(0):((i)>=sn?OPJ_D(sn-1):OPJ_D(i))) /* <summary> */ /* This table contains the norms of the 5-3 wavelets for different bands. */ /* </summary> */ +/* FIXME! the array should really be extended up to 33 resolution levels */ +/* See https://github.com/uclouvain/openjpeg/issues/493 */ static const OPJ_FLOAT64 opj_dwt_norms[4][10] = { {1.000, 1.500, 2.750, 5.375, 10.68, 21.34, 42.67, 85.33, 170.7, 341.3}, {1.038, 1.592, 2.919, 5.703, 11.33, 22.64, 45.25, 90.48, 180.9}, @@ -212,6 +228,8 @@ static const OPJ_FLOAT64 opj_dwt_norms[4][10] = { /* <summary> */ /* This table contains the norms of the 9-7 wavelets for different bands. */ /* </summary> */ +/* FIXME! the array should really be extended up to 33 resolution levels */ +/* See https://github.com/uclouvain/openjpeg/issues/493 */ static const OPJ_FLOAT64 opj_dwt_norms_real[4][10] = { {1.000, 1.965, 4.177, 8.403, 16.90, 33.84, 67.69, 135.3, 270.6, 540.9}, {2.022, 3.989, 8.355, 17.04, 34.27, 68.63, 137.3, 274.6, 549.0}, @@ -265,7 +283,7 @@ static void opj_dwt_deinterleave_v(OPJ_INT32 *a, OPJ_INT32 *b, OPJ_INT32 dn, l_src += 2; } /* b[i*x]=a[2*i+cas]; */ - l_dest = b + sn * x; + l_dest = b + (OPJ_SIZE_T)sn * (OPJ_SIZE_T)x; l_src = a + 1 - cas; i = dn; @@ -311,7 +329,7 @@ static void opj_dwt_interleave_v(const opj_dwt_t* v, OPJ_INT32 *a, OPJ_INT32 x) bi += 2; ai += x; } - ai = a + (v->sn * x); + ai = a + (v->sn * (OPJ_SIZE_T)x); bi = v->mem + 1 - v->cas; i = v->dn ; while (i--) { @@ -326,8 +344,8 @@ static void opj_dwt_interleave_v(const opj_dwt_t* v, OPJ_INT32 *a, OPJ_INT32 x) /* <summary> */ /* Forward 5-3 wavelet transform in 1-D. */ /* </summary> */ -static void opj_dwt_encode_1(OPJ_INT32 *a, OPJ_SIZE_T a_count, OPJ_INT32 dn, - OPJ_INT32 sn, OPJ_INT32 cas) +static void opj_dwt_encode_1(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, + OPJ_INT32 cas) { OPJ_INT32 i; @@ -358,8 +376,8 @@ static void opj_dwt_encode_1(OPJ_INT32 *a, OPJ_SIZE_T a_count, OPJ_INT32 dn, /* <summary> */ /* Inverse 5-3 wavelet transform in 1-D. */ /* </summary> */ -static void opj_dwt_decode_1_(OPJ_INT32 *a, OPJ_SIZE_T a_count, OPJ_INT32 dn, - OPJ_INT32 sn, OPJ_INT32 cas) +static void opj_dwt_decode_1_(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, + OPJ_INT32 cas) { OPJ_INT32 i; @@ -388,7 +406,7 @@ static void opj_dwt_decode_1_(OPJ_INT32 *a, OPJ_SIZE_T a_count, OPJ_INT32 dn, static void opj_dwt_decode_1(const opj_dwt_t *v) { - opj_dwt_decode_1_(v->mem, v->mem_count, v->dn, v->sn, v->cas); + opj_dwt_decode_1_(v->mem, v->dn, v->sn, v->cas); } #endif /* STANDARD_SLOW_VERSION */ @@ -575,7 +593,7 @@ static void opj_idwt53_h(const opj_dwt_t *dwt, #if (defined(__SSE2__) || defined(__AVX2__)) && !defined(STANDARD_SLOW_VERSION) /* Conveniency macros to improve the readabilty of the formulas */ -#if defined(__AVX2__) && __AVX2__ +#if __AVX2__ #define VREG __m256i #define LOAD_CST(x) _mm256_set1_epi32(x) #define LOAD(x) _mm256_load_si256((const VREG*)(x)) @@ -602,7 +620,7 @@ static void opj_idwt53_v_final_memcpy(OPJ_INT32* tiledp_col, const OPJ_INT32* tmp, OPJ_INT32 len, - OPJ_INT32 stride) + OPJ_SIZE_T stride) { OPJ_INT32 i; for (i = 0; i < len; ++i) { @@ -611,9 +629,9 @@ void opj_idwt53_v_final_memcpy(OPJ_INT32* tiledp_col, PARALLEL_COLS_53 * sizeof(OPJ_INT32)) would do but would be a tiny bit slower. We can take here advantage of our knowledge of alignment */ - STOREU(&tiledp_col[i * stride + 0], + STOREU(&tiledp_col[(OPJ_SIZE_T)i * stride + 0], LOAD(&tmp[PARALLEL_COLS_53 * i + 0])); - STOREU(&tiledp_col[i * stride + VREG_INT_COUNT], + STOREU(&tiledp_col[(OPJ_SIZE_T)i * stride + VREG_INT_COUNT], LOAD(&tmp[PARALLEL_COLS_53 * i + VREG_INT_COUNT])); } } @@ -625,18 +643,19 @@ static void opj_idwt53_v_cas0_mcols_SSE2_OR_AVX2( const OPJ_INT32 sn, const OPJ_INT32 len, OPJ_INT32* tiledp_col, - const OPJ_INT32 stride) + const OPJ_SIZE_T stride) { const OPJ_INT32* in_even = &tiledp_col[0]; - const OPJ_INT32* in_odd = &tiledp_col[sn * stride]; + const OPJ_INT32* in_odd = &tiledp_col[(OPJ_SIZE_T)sn * stride]; - OPJ_INT32 i, j; + OPJ_INT32 i; + OPJ_SIZE_T j; VREG d1c_0, d1n_0, s1n_0, s0c_0, s0n_0; VREG d1c_1, d1n_1, s1n_1, s0c_1, s0n_1; const VREG two = LOAD_CST(2); assert(len > 1); -#if defined(__AVX2__) && __AVX2__ +#if __AVX2__ assert(PARALLEL_COLS_53 == 16); assert(VREG_INT_COUNT == 8); #else @@ -647,7 +666,7 @@ static void opj_idwt53_v_cas0_mcols_SSE2_OR_AVX2( /* Note: loads of input even/odd values must be done in a unaligned */ /* fashion. But stores in tmp can be done with aligned store, since */ /* the temporary buffer is properly aligned */ - assert((size_t)tmp % (sizeof(OPJ_INT32) * VREG_INT_COUNT) == 0); + assert((OPJ_SIZE_T)tmp % (sizeof(OPJ_INT32) * VREG_INT_COUNT) == 0); s1n_0 = LOADU(in_even + 0); s1n_1 = LOADU(in_even + VREG_INT_COUNT); @@ -689,7 +708,7 @@ static void opj_idwt53_v_cas0_mcols_SSE2_OR_AVX2( if (len & 1) { VREG tmp_len_minus_1; - s1n_0 = LOADU(in_even + ((len - 1) / 2) * stride); + s1n_0 = LOADU(in_even + (OPJ_SIZE_T)((len - 1) / 2) * stride); /* tmp_len_minus_1 = s1n - ((d1n + 1) >> 1); */ tmp_len_minus_1 = SUB(s1n_0, SAR(ADD3(d1n_0, d1n_0, two), 2)); STORE(tmp + PARALLEL_COLS_53 * (len - 1), tmp_len_minus_1); @@ -697,7 +716,7 @@ static void opj_idwt53_v_cas0_mcols_SSE2_OR_AVX2( STORE(tmp + PARALLEL_COLS_53 * (len - 2), ADD(d1n_0, SAR(ADD(s0n_0, tmp_len_minus_1), 1))); - s1n_1 = LOADU(in_even + ((len - 1) / 2) * stride + VREG_INT_COUNT); + s1n_1 = LOADU(in_even + (OPJ_SIZE_T)((len - 1) / 2) * stride + VREG_INT_COUNT); /* tmp_len_minus_1 = s1n - ((d1n + 1) >> 1); */ tmp_len_minus_1 = SUB(s1n_1, SAR(ADD3(d1n_1, d1n_1, two), 2)); STORE(tmp + PARALLEL_COLS_53 * (len - 1) + VREG_INT_COUNT, @@ -725,19 +744,20 @@ static void opj_idwt53_v_cas1_mcols_SSE2_OR_AVX2( const OPJ_INT32 sn, const OPJ_INT32 len, OPJ_INT32* tiledp_col, - const OPJ_INT32 stride) + const OPJ_SIZE_T stride) { - OPJ_INT32 i, j; + OPJ_INT32 i; + OPJ_SIZE_T j; VREG s1_0, s2_0, dc_0, dn_0; VREG s1_1, s2_1, dc_1, dn_1; const VREG two = LOAD_CST(2); - const OPJ_INT32* in_even = &tiledp_col[sn * stride]; + const OPJ_INT32* in_even = &tiledp_col[(OPJ_SIZE_T)sn * stride]; const OPJ_INT32* in_odd = &tiledp_col[0]; assert(len > 2); -#if defined(__AVX2__) && __AVX2__ +#if __AVX2__ assert(PARALLEL_COLS_53 == 16); assert(VREG_INT_COUNT == 8); #else @@ -748,7 +768,7 @@ static void opj_idwt53_v_cas1_mcols_SSE2_OR_AVX2( /* Note: loads of input even/odd values must be done in a unaligned */ /* fashion. But stores in tmp can be done with aligned store, since */ /* the temporary buffer is properly aligned */ - assert((size_t)tmp % (sizeof(OPJ_INT32) * VREG_INT_COUNT) == 0); + assert((OPJ_SIZE_T)tmp % (sizeof(OPJ_INT32) * VREG_INT_COUNT) == 0); s1_0 = LOADU(in_even + stride); /* in_odd[0] - ((in_even[0] + s1 + 2) >> 2); */ @@ -793,9 +813,9 @@ static void opj_idwt53_v_cas1_mcols_SSE2_OR_AVX2( if (!(len & 1)) { /*dn = in_odd[(len / 2 - 1) * stride] - ((s1 + 1) >> 1); */ - dn_0 = SUB(LOADU(in_odd + (len / 2 - 1) * stride), + dn_0 = SUB(LOADU(in_odd + (OPJ_SIZE_T)(len / 2 - 1) * stride), SAR(ADD3(s1_0, s1_0, two), 2)); - dn_1 = SUB(LOADU(in_odd + (len / 2 - 1) * stride + VREG_INT_COUNT), + dn_1 = SUB(LOADU(in_odd + (OPJ_SIZE_T)(len / 2 - 1) * stride + VREG_INT_COUNT), SAR(ADD3(s1_1, s1_1, two), 2)); /* tmp[len - 2] = s1 + ((dn + dc) >> 1); */ @@ -835,7 +855,7 @@ static void opj_idwt3_v_cas0(OPJ_INT32* tmp, const OPJ_INT32 sn, const OPJ_INT32 len, OPJ_INT32* tiledp_col, - const OPJ_INT32 stride) + const OPJ_SIZE_T stride) { OPJ_INT32 i, j; OPJ_INT32 d1c, d1n, s1n, s0c, s0n; @@ -846,15 +866,15 @@ static void opj_idwt3_v_cas0(OPJ_INT32* tmp, /* accesses and explicit interleaving. */ s1n = tiledp_col[0]; - d1n = tiledp_col[sn * stride]; + d1n = tiledp_col[(OPJ_SIZE_T)sn * stride]; s0n = s1n - ((d1n + 1) >> 1); for (i = 0, j = 0; i < (len - 3); i += 2, j++) { d1c = d1n; s0c = s0n; - s1n = tiledp_col[(j + 1) * stride]; - d1n = tiledp_col[(sn + j + 1) * stride]; + s1n = tiledp_col[(OPJ_SIZE_T)(j + 1) * stride]; + d1n = tiledp_col[(OPJ_SIZE_T)(sn + j + 1) * stride]; s0n = s1n - ((d1c + d1n + 2) >> 2); @@ -866,7 +886,7 @@ static void opj_idwt3_v_cas0(OPJ_INT32* tmp, if (len & 1) { tmp[len - 1] = - tiledp_col[((len - 1) / 2) * stride] - + tiledp_col[(OPJ_SIZE_T)((len - 1) / 2) * stride] - ((d1n + 1) >> 1); tmp[len - 2] = d1n + ((s0n + tmp[len - 1]) >> 1); } else { @@ -874,7 +894,7 @@ static void opj_idwt3_v_cas0(OPJ_INT32* tmp, } for (i = 0; i < len; ++i) { - tiledp_col[i * stride] = tmp[i]; + tiledp_col[(OPJ_SIZE_T)i * stride] = tmp[i]; } } @@ -885,11 +905,11 @@ static void opj_idwt3_v_cas1(OPJ_INT32* tmp, const OPJ_INT32 sn, const OPJ_INT32 len, OPJ_INT32* tiledp_col, - const OPJ_INT32 stride) + const OPJ_SIZE_T stride) { OPJ_INT32 i, j; OPJ_INT32 s1, s2, dc, dn; - const OPJ_INT32* in_even = &tiledp_col[sn * stride]; + const OPJ_INT32* in_even = &tiledp_col[(OPJ_SIZE_T)sn * stride]; const OPJ_INT32* in_odd = &tiledp_col[0]; assert(len > 2); @@ -902,9 +922,9 @@ static void opj_idwt3_v_cas1(OPJ_INT32* tmp, tmp[0] = in_even[0] + dc; for (i = 1, j = 1; i < (len - 2 - !(len & 1)); i += 2, j++) { - s2 = in_even[(j + 1) * stride]; + s2 = in_even[(OPJ_SIZE_T)(j + 1) * stride]; - dn = in_odd[j * stride] - ((s1 + s2 + 2) >> 2); + dn = in_odd[(OPJ_SIZE_T)j * stride] - ((s1 + s2 + 2) >> 2); tmp[i ] = dc; tmp[i + 1] = s1 + ((dn + dc) >> 1); @@ -913,7 +933,7 @@ static void opj_idwt3_v_cas1(OPJ_INT32* tmp, } tmp[i] = dc; if (!(len & 1)) { - dn = in_odd[(len / 2 - 1) * stride] - ((s1 + 1) >> 1); + dn = in_odd[(OPJ_SIZE_T)(len / 2 - 1) * stride] - ((s1 + 1) >> 1); tmp[len - 2] = s1 + ((dn + dc) >> 1); tmp[len - 1] = dn; } else { @@ -921,7 +941,7 @@ static void opj_idwt3_v_cas1(OPJ_INT32* tmp, } for (i = 0; i < len; ++i) { - tiledp_col[i * stride] = tmp[i]; + tiledp_col[(OPJ_SIZE_T)i * stride] = tmp[i]; } } #endif /* !defined(STANDARD_SLOW_VERSION) */ @@ -932,7 +952,7 @@ static void opj_idwt3_v_cas1(OPJ_INT32* tmp, /* Performs interleave, inverse wavelet transform and copy back to buffer */ static void opj_idwt53_v(const opj_dwt_t *dwt, OPJ_INT32* tiledp_col, - OPJ_INT32 stride, + OPJ_SIZE_T stride, OPJ_INT32 nb_cols) { #ifdef STANDARD_SLOW_VERSION @@ -980,14 +1000,14 @@ static void opj_idwt53_v(const opj_dwt_t *dwt, OPJ_INT32* out = dwt->mem; for (c = 0; c < nb_cols; c++, tiledp_col++) { OPJ_INT32 i; - const OPJ_INT32* in_even = &tiledp_col[sn * stride]; + const OPJ_INT32* in_even = &tiledp_col[(OPJ_SIZE_T)sn * stride]; const OPJ_INT32* in_odd = &tiledp_col[0]; out[1] = in_odd[0] - ((in_even[0] + 1) >> 1); out[0] = in_even[0] + out[1]; for (i = 0; i < len; ++i) { - tiledp_col[i * stride] = out[i]; + tiledp_col[(OPJ_SIZE_T)i * stride] = out[i]; } } @@ -1017,8 +1037,8 @@ static void opj_idwt53_v(const opj_dwt_t *dwt, /* <summary> */ /* Forward 9-7 wavelet transform in 1-D. */ /* </summary> */ -static void opj_dwt_encode_1_real(OPJ_INT32 *a, OPJ_SIZE_T a_count, OPJ_INT32 dn, - OPJ_INT32 sn, OPJ_INT32 cas) +static void opj_dwt_encode_1_real(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, + OPJ_INT32 cas) { OPJ_INT32 i; if (!cas) { @@ -1086,8 +1106,8 @@ static void opj_dwt_encode_stepsize(OPJ_INT32 stepsize, OPJ_INT32 numbps, /* <summary> */ /* Forward 5-3 wavelet transform in 2-D. */ /* </summary> */ -static OPJ_BOOL opj_dwt_encode_procedure(const opj_tcd_tilecomp_t * tilec, - void (*p_function)(OPJ_INT32 *, OPJ_SIZE_T,OPJ_INT32,OPJ_INT32,OPJ_INT32) ) +static INLINE OPJ_BOOL opj_dwt_encode_procedure(opj_tcd_tilecomp_t * tilec, + void (*p_function)(OPJ_INT32 *, OPJ_INT32, OPJ_INT32, OPJ_INT32)) { OPJ_INT32 i, j, k; OPJ_INT32 *a = 00; @@ -1097,7 +1117,6 @@ static OPJ_BOOL opj_dwt_encode_procedure(const opj_tcd_tilecomp_t * tilec, OPJ_INT32 rw; /* width of the resolution level computed */ OPJ_INT32 rh; /* height of the resolution level computed */ - OPJ_SIZE_T l_data_count; OPJ_SIZE_T l_data_size; opj_tcd_resolution_t * l_cur_res = 0; @@ -1110,13 +1129,13 @@ static OPJ_BOOL opj_dwt_encode_procedure(const opj_tcd_tilecomp_t * tilec, l_cur_res = tilec->resolutions + l; l_last_res = l_cur_res - 1; - l_data_count = opj_dwt_max_resolution( tilec->resolutions,tilec->numresolutions); + l_data_size = opj_dwt_max_resolution(tilec->resolutions, tilec->numresolutions); /* overflow check */ - if (l_data_count > (SIZE_MAX / sizeof(OPJ_INT32))) { + if (l_data_size > (SIZE_MAX / sizeof(OPJ_INT32))) { /* FIXME event manager error callback */ return OPJ_FALSE; } - l_data_size = l_data_count * (OPJ_UINT32)sizeof(OPJ_INT32); + l_data_size *= sizeof(OPJ_INT32); bj = (OPJ_INT32*)opj_malloc(l_data_size); /* l_data_size is equal to 0 when numresolutions == 1 but bj is not used */ /* in that case, so do not error out */ @@ -1148,7 +1167,7 @@ static OPJ_BOOL opj_dwt_encode_procedure(const opj_tcd_tilecomp_t * tilec, bj[k] = aj[k * w]; } - (*p_function)(bj, l_data_count, dn, sn, cas_col); + (*p_function)(bj, dn, sn, cas_col); opj_dwt_deinterleave_v(bj, aj, dn, sn, w, cas_col); } @@ -1161,7 +1180,7 @@ static OPJ_BOOL opj_dwt_encode_procedure(const opj_tcd_tilecomp_t * tilec, for (k = 0; k < rw; k++) { bj[k] = aj[k]; } - (*p_function)(bj, l_data_count, dn, sn, cas_row); + (*p_function)(bj, dn, sn, cas_row); opj_dwt_deinterleave_h(bj, aj, dn, sn, cas_row); } @@ -1184,10 +1203,14 @@ OPJ_BOOL opj_dwt_encode(opj_tcd_tilecomp_t * tilec) /* <summary> */ /* Inverse 5-3 wavelet transform in 2-D. */ /* </summary> */ -OPJ_BOOL opj_dwt_decode(opj_thread_pool_t* tp, opj_tcd_tilecomp_t* tilec, +OPJ_BOOL opj_dwt_decode(opj_tcd_t *p_tcd, opj_tcd_tilecomp_t* tilec, OPJ_UINT32 numres) { - return opj_dwt_decode_tile(tp, tilec, numres, &opj_dwt_decode_1); + if (p_tcd->whole_tile_decoding) { + return opj_dwt_decode_tile(p_tcd->thread_pool, tilec, numres); + } else { + return opj_dwt_decode_partial_tile(tilec, numres); + } } @@ -1210,6 +1233,14 @@ OPJ_UINT32 opj_dwt_getgain(OPJ_UINT32 orient) /* </summary> */ OPJ_FLOAT64 opj_dwt_getnorm(OPJ_UINT32 level, OPJ_UINT32 orient) { + /* FIXME ! This is just a band-aid to avoid a buffer overflow */ + /* but the array should really be extended up to 33 resolution levels */ + /* See https://github.com/uclouvain/openjpeg/issues/493 */ + if (orient == 0 && level >= 10) { + level = 9; + } else if (orient > 0 && level >= 9) { + level = 8; + } return opj_dwt_norms[orient][level]; } @@ -1235,6 +1266,14 @@ OPJ_UINT32 opj_dwt_getgain_real(OPJ_UINT32 orient) /* </summary> */ OPJ_FLOAT64 opj_dwt_getnorm_real(OPJ_UINT32 level, OPJ_UINT32 orient) { + /* FIXME ! This is just a band-aid to avoid a buffer overflow */ + /* but the array should really be extended up to 33 resolution levels */ + /* See https://github.com/uclouvain/openjpeg/issues/493 */ + if (orient == 0 && level >= 10) { + level = 9; + } else if (orient > 0 && level >= 9) { + level = 8; + } return opj_dwt_norms_real[orient][level]; } @@ -1324,11 +1363,11 @@ static void opj_dwt_decode_v_func(void* user_data, opj_tls_t* tls) job = (opj_dwd_decode_v_job_t*)user_data; for (j = job->min_j; j + PARALLEL_COLS_53 <= job->max_j; j += PARALLEL_COLS_53) { - opj_idwt53_v(&job->v, &job->tiledp[j], (OPJ_INT32)job->w, + opj_idwt53_v(&job->v, &job->tiledp[j], (OPJ_SIZE_T)job->w, PARALLEL_COLS_53); } if (j < job->max_j) - opj_idwt53_v(&job->v, &job->tiledp[j], (OPJ_INT32)job->w, + opj_idwt53_v(&job->v, &job->tiledp[j], (OPJ_SIZE_T)job->w, (OPJ_INT32)(job->max_j - j)); opj_aligned_free(job->v.mem); @@ -1340,8 +1379,7 @@ static void opj_dwt_decode_v_func(void* user_data, opj_tls_t* tls) /* Inverse wavelet transform in 2-D. */ /* </summary> */ static OPJ_BOOL opj_dwt_decode_tile(opj_thread_pool_t* tp, - const opj_tcd_tilecomp_t* tilec, - OPJ_UINT32 numres, DWT1DFN fn) + opj_tcd_tilecomp_t* tilec, OPJ_UINT32 numres) { opj_dwt_t h; opj_dwt_t v; @@ -1353,29 +1391,32 @@ static OPJ_BOOL opj_dwt_decode_tile(opj_thread_pool_t* tp, OPJ_UINT32 rh = (OPJ_UINT32)(tr->y1 - tr->y0); /* height of the resolution level computed */ - OPJ_UINT32 w = (OPJ_UINT32)(tilec->x1 - tilec->x0); + OPJ_UINT32 w = (OPJ_UINT32)(tilec->resolutions[tilec->minimum_num_resolutions - + 1].x1 - + tilec->resolutions[tilec->minimum_num_resolutions - 1].x0); + OPJ_SIZE_T h_mem_size; int num_threads; if (numres == 1U) { return OPJ_TRUE; } num_threads = opj_thread_pool_get_thread_count(tp); - h.mem_count = opj_dwt_max_resolution(tr, numres); - /* overflow check */ - if (h.mem_count > (SIZE_MAX / PARALLEL_COLS_53 / sizeof(OPJ_INT32))) { + h_mem_size = opj_dwt_max_resolution(tr, numres); + /* overflow check */ + if (h_mem_size > (SIZE_MAX / PARALLEL_COLS_53 / sizeof(OPJ_INT32))) { /* FIXME event manager error callback */ return OPJ_FALSE; } /* We need PARALLEL_COLS_53 times the height of the array, */ /* since for the vertical pass */ /* we process PARALLEL_COLS_53 columns at a time */ - h.mem = (OPJ_INT32*)opj_aligned_malloc(h.mem_count * sizeof(OPJ_INT32)); + h_mem_size *= PARALLEL_COLS_53 * sizeof(OPJ_INT32); + h.mem = (OPJ_INT32*)opj_aligned_32_malloc(h_mem_size); if (! h.mem) { /* FIXME event manager error callback */ return OPJ_FALSE; } - v.mem_count = h.mem_count; v.mem = h.mem; while (--numres) { @@ -1394,7 +1435,7 @@ static OPJ_BOOL opj_dwt_decode_tile(opj_thread_pool_t* tp, if (num_threads <= 1 || rh <= 1) { for (j = 0; j < rh; ++j) { - opj_idwt53_h(&h, &tiledp[j * w]); + opj_idwt53_h(&h, &tiledp[(OPJ_SIZE_T)j * w]); } } else { OPJ_UINT32 num_jobs = (OPJ_UINT32)num_threads; @@ -1427,8 +1468,7 @@ static OPJ_BOOL opj_dwt_decode_tile(opj_thread_pool_t* tp, if (j == (num_jobs - 1U)) { /* this will take care of the overflow */ job->max_j = rh; } - job->h.mem = (OPJ_INT32*)opj_aligned_malloc(h.mem_count * sizeof(OPJ_INT32)); - job->h.mem_count = h.mem_count; + job->h.mem = (OPJ_INT32*)opj_aligned_32_malloc(h_mem_size); if (!job->h.mem) { /* FIXME event manager error callback */ opj_thread_pool_wait_completion(tp, 0); @@ -1447,10 +1487,10 @@ static OPJ_BOOL opj_dwt_decode_tile(opj_thread_pool_t* tp, if (num_threads <= 1 || rw <= 1) { for (j = 0; j + PARALLEL_COLS_53 <= rw; j += PARALLEL_COLS_53) { - opj_idwt53_v(&v, &tiledp[j], (OPJ_INT32)w, PARALLEL_COLS_53); + opj_idwt53_v(&v, &tiledp[j], (OPJ_SIZE_T)w, PARALLEL_COLS_53); } if (j < rw) { - opj_idwt53_v(&v, &tiledp[j], (OPJ_INT32)w, (OPJ_INT32)(rw - j)); + opj_idwt53_v(&v, &tiledp[j], (OPJ_SIZE_T)w, (OPJ_INT32)(rw - j)); } } else { OPJ_UINT32 num_jobs = (OPJ_UINT32)num_threads; @@ -1483,8 +1523,7 @@ static OPJ_BOOL opj_dwt_decode_tile(opj_thread_pool_t* tp, if (j == (num_jobs - 1U)) { /* this will take care of the overflow */ job->max_j = rw; } - job->v.mem = (OPJ_INT32*)opj_aligned_malloc(h.mem_count * sizeof(OPJ_INT32)); - job->v.mem_count = h.mem_count; + job->v.mem = (OPJ_INT32*)opj_aligned_32_malloc(h_mem_size); if (!job->v.mem) { /* FIXME event manager error callback */ opj_thread_pool_wait_completion(tp, 0); @@ -1501,136 +1540,847 @@ static OPJ_BOOL opj_dwt_decode_tile(opj_thread_pool_t* tp, return OPJ_TRUE; } -static void opj_v4dwt_interleave_h(opj_v4dwt_t* OPJ_RESTRICT w, - OPJ_FLOAT32* OPJ_RESTRICT a, OPJ_INT32 x, OPJ_INT32 size) +static void opj_dwt_interleave_partial_h(OPJ_INT32 *dest, + OPJ_INT32 cas, + opj_sparse_array_int32_t* sa, + OPJ_UINT32 sa_line, + OPJ_UINT32 sn, + OPJ_UINT32 win_l_x0, + OPJ_UINT32 win_l_x1, + OPJ_UINT32 win_h_x0, + OPJ_UINT32 win_h_x1) +{ + OPJ_BOOL ret; + ret = opj_sparse_array_int32_read(sa, + win_l_x0, sa_line, + win_l_x1, sa_line + 1, + dest + cas + 2 * win_l_x0, + 2, 0, OPJ_TRUE); + assert(ret); + ret = opj_sparse_array_int32_read(sa, + sn + win_h_x0, sa_line, + sn + win_h_x1, sa_line + 1, + dest + 1 - cas + 2 * win_h_x0, + 2, 0, OPJ_TRUE); + assert(ret); + OPJ_UNUSED(ret); +} + + +static void opj_dwt_interleave_partial_v(OPJ_INT32 *dest, + OPJ_INT32 cas, + opj_sparse_array_int32_t* sa, + OPJ_UINT32 sa_col, + OPJ_UINT32 nb_cols, + OPJ_UINT32 sn, + OPJ_UINT32 win_l_y0, + OPJ_UINT32 win_l_y1, + OPJ_UINT32 win_h_y0, + OPJ_UINT32 win_h_y1) +{ + OPJ_BOOL ret; + ret = opj_sparse_array_int32_read(sa, + sa_col, win_l_y0, + sa_col + nb_cols, win_l_y1, + dest + cas * 4 + 2 * 4 * win_l_y0, + 1, 2 * 4, OPJ_TRUE); + assert(ret); + ret = opj_sparse_array_int32_read(sa, + sa_col, sn + win_h_y0, + sa_col + nb_cols, sn + win_h_y1, + dest + (1 - cas) * 4 + 2 * 4 * win_h_y0, + 1, 2 * 4, OPJ_TRUE); + assert(ret); + OPJ_UNUSED(ret); +} + +static void opj_dwt_decode_partial_1(OPJ_INT32 *a, OPJ_INT32 dn, OPJ_INT32 sn, + OPJ_INT32 cas, + OPJ_INT32 win_l_x0, + OPJ_INT32 win_l_x1, + OPJ_INT32 win_h_x0, + OPJ_INT32 win_h_x1) +{ + OPJ_INT32 i; + + if (!cas) { + if ((dn > 0) || (sn > 1)) { /* NEW : CASE ONE ELEMENT */ + + /* Naive version is : + for (i = win_l_x0; i < i_max; i++) { + OPJ_S(i) -= (OPJ_D_(i - 1) + OPJ_D_(i) + 2) >> 2; + } + for (i = win_h_x0; i < win_h_x1; i++) { + OPJ_D(i) += (OPJ_S_(i) + OPJ_S_(i + 1)) >> 1; + } + but the compiler doesn't manage to unroll it to avoid bound + checking in OPJ_S_ and OPJ_D_ macros + */ + + i = win_l_x0; + if (i < win_l_x1) { + OPJ_INT32 i_max; + + /* Left-most case */ + OPJ_S(i) -= (OPJ_D_(i - 1) + OPJ_D_(i) + 2) >> 2; + i ++; + + i_max = win_l_x1; + if (i_max > dn) { + i_max = dn; + } + for (; i < i_max; i++) { + /* No bound checking */ + OPJ_S(i) -= (OPJ_D(i - 1) + OPJ_D(i) + 2) >> 2; + } + for (; i < win_l_x1; i++) { + /* Right-most case */ + OPJ_S(i) -= (OPJ_D_(i - 1) + OPJ_D_(i) + 2) >> 2; + } + } + + i = win_h_x0; + if (i < win_h_x1) { + OPJ_INT32 i_max = win_h_x1; + if (i_max >= sn) { + i_max = sn - 1; + } + for (; i < i_max; i++) { + /* No bound checking */ + OPJ_D(i) += (OPJ_S(i) + OPJ_S(i + 1)) >> 1; + } + for (; i < win_h_x1; i++) { + /* Right-most case */ + OPJ_D(i) += (OPJ_S_(i) + OPJ_S_(i + 1)) >> 1; + } + } + } + } else { + if (!sn && dn == 1) { /* NEW : CASE ONE ELEMENT */ + OPJ_S(0) /= 2; + } else { + for (i = win_l_x0; i < win_l_x1; i++) { + OPJ_D(i) -= (OPJ_SS_(i) + OPJ_SS_(i + 1) + 2) >> 2; + } + for (i = win_h_x0; i < win_h_x1; i++) { + OPJ_S(i) += (OPJ_DD_(i) + OPJ_DD_(i - 1)) >> 1; + } + } + } +} + +#define OPJ_S_off(i,off) a[(OPJ_UINT32)(i)*2*4+off] +#define OPJ_D_off(i,off) a[(1+(OPJ_UINT32)(i)*2)*4+off] +#define OPJ_S__off(i,off) ((i)<0?OPJ_S_off(0,off):((i)>=sn?OPJ_S_off(sn-1,off):OPJ_S_off(i,off))) +#define OPJ_D__off(i,off) ((i)<0?OPJ_D_off(0,off):((i)>=dn?OPJ_D_off(dn-1,off):OPJ_D_off(i,off))) +#define OPJ_SS__off(i,off) ((i)<0?OPJ_S_off(0,off):((i)>=dn?OPJ_S_off(dn-1,off):OPJ_S_off(i,off))) +#define OPJ_DD__off(i,off) ((i)<0?OPJ_D_off(0,off):((i)>=sn?OPJ_D_off(sn-1,off):OPJ_D_off(i,off))) + +static void opj_dwt_decode_partial_1_parallel(OPJ_INT32 *a, + OPJ_UINT32 nb_cols, + OPJ_INT32 dn, OPJ_INT32 sn, + OPJ_INT32 cas, + OPJ_INT32 win_l_x0, + OPJ_INT32 win_l_x1, + OPJ_INT32 win_h_x0, + OPJ_INT32 win_h_x1) +{ + OPJ_INT32 i; + OPJ_UINT32 off; + + (void)nb_cols; + + if (!cas) { + if ((dn > 0) || (sn > 1)) { /* NEW : CASE ONE ELEMENT */ + + /* Naive version is : + for (i = win_l_x0; i < i_max; i++) { + OPJ_S(i) -= (OPJ_D_(i - 1) + OPJ_D_(i) + 2) >> 2; + } + for (i = win_h_x0; i < win_h_x1; i++) { + OPJ_D(i) += (OPJ_S_(i) + OPJ_S_(i + 1)) >> 1; + } + but the compiler doesn't manage to unroll it to avoid bound + checking in OPJ_S_ and OPJ_D_ macros + */ + + i = win_l_x0; + if (i < win_l_x1) { + OPJ_INT32 i_max; + + /* Left-most case */ + for (off = 0; off < 4; off++) { + OPJ_S_off(i, off) -= (OPJ_D__off(i - 1, off) + OPJ_D__off(i, off) + 2) >> 2; + } + i ++; + + i_max = win_l_x1; + if (i_max > dn) { + i_max = dn; + } + +#ifdef __SSE2__ + if (i + 1 < i_max) { + const __m128i two = _mm_set1_epi32(2); + __m128i Dm1 = _mm_load_si128((__m128i * const)(a + 4 + (i - 1) * 8)); + for (; i + 1 < i_max; i += 2) { + /* No bound checking */ + __m128i S = _mm_load_si128((__m128i * const)(a + i * 8)); + __m128i D = _mm_load_si128((__m128i * const)(a + 4 + i * 8)); + __m128i S1 = _mm_load_si128((__m128i * const)(a + (i + 1) * 8)); + __m128i D1 = _mm_load_si128((__m128i * const)(a + 4 + (i + 1) * 8)); + S = _mm_sub_epi32(S, + _mm_srai_epi32(_mm_add_epi32(_mm_add_epi32(Dm1, D), two), 2)); + S1 = _mm_sub_epi32(S1, + _mm_srai_epi32(_mm_add_epi32(_mm_add_epi32(D, D1), two), 2)); + _mm_store_si128((__m128i*)(a + i * 8), S); + _mm_store_si128((__m128i*)(a + (i + 1) * 8), S1); + Dm1 = D1; + } + } +#endif + + for (; i < i_max; i++) { + /* No bound checking */ + for (off = 0; off < 4; off++) { + OPJ_S_off(i, off) -= (OPJ_D_off(i - 1, off) + OPJ_D_off(i, off) + 2) >> 2; + } + } + for (; i < win_l_x1; i++) { + /* Right-most case */ + for (off = 0; off < 4; off++) { + OPJ_S_off(i, off) -= (OPJ_D__off(i - 1, off) + OPJ_D__off(i, off) + 2) >> 2; + } + } + } + + i = win_h_x0; + if (i < win_h_x1) { + OPJ_INT32 i_max = win_h_x1; + if (i_max >= sn) { + i_max = sn - 1; + } + +#ifdef __SSE2__ + if (i + 1 < i_max) { + __m128i S = _mm_load_si128((__m128i * const)(a + i * 8)); + for (; i + 1 < i_max; i += 2) { + /* No bound checking */ + __m128i D = _mm_load_si128((__m128i * const)(a + 4 + i * 8)); + __m128i S1 = _mm_load_si128((__m128i * const)(a + (i + 1) * 8)); + __m128i D1 = _mm_load_si128((__m128i * const)(a + 4 + (i + 1) * 8)); + __m128i S2 = _mm_load_si128((__m128i * const)(a + (i + 2) * 8)); + D = _mm_add_epi32(D, _mm_srai_epi32(_mm_add_epi32(S, S1), 1)); + D1 = _mm_add_epi32(D1, _mm_srai_epi32(_mm_add_epi32(S1, S2), 1)); + _mm_store_si128((__m128i*)(a + 4 + i * 8), D); + _mm_store_si128((__m128i*)(a + 4 + (i + 1) * 8), D1); + S = S2; + } + } +#endif + + for (; i < i_max; i++) { + /* No bound checking */ + for (off = 0; off < 4; off++) { + OPJ_D_off(i, off) += (OPJ_S_off(i, off) + OPJ_S_off(i + 1, off)) >> 1; + } + } + for (; i < win_h_x1; i++) { + /* Right-most case */ + for (off = 0; off < 4; off++) { + OPJ_D_off(i, off) += (OPJ_S__off(i, off) + OPJ_S__off(i + 1, off)) >> 1; + } + } + } + } + } else { + if (!sn && dn == 1) { /* NEW : CASE ONE ELEMENT */ + for (off = 0; off < 4; off++) { + OPJ_S_off(0, off) /= 2; + } + } else { + for (i = win_l_x0; i < win_l_x1; i++) { + for (off = 0; off < 4; off++) { + OPJ_D_off(i, off) -= (OPJ_SS__off(i, off) + OPJ_SS__off(i + 1, off) + 2) >> 2; + } + } + for (i = win_h_x0; i < win_h_x1; i++) { + for (off = 0; off < 4; off++) { + OPJ_S_off(i, off) += (OPJ_DD__off(i, off) + OPJ_DD__off(i - 1, off)) >> 1; + } + } + } + } +} + +static void opj_dwt_get_band_coordinates(opj_tcd_tilecomp_t* tilec, + OPJ_UINT32 resno, + OPJ_UINT32 bandno, + OPJ_UINT32 tcx0, + OPJ_UINT32 tcy0, + OPJ_UINT32 tcx1, + OPJ_UINT32 tcy1, + OPJ_UINT32* tbx0, + OPJ_UINT32* tby0, + OPJ_UINT32* tbx1, + OPJ_UINT32* tby1) +{ + /* Compute number of decomposition for this band. See table F-1 */ + OPJ_UINT32 nb = (resno == 0) ? + tilec->numresolutions - 1 : + tilec->numresolutions - resno; + /* Map above tile-based coordinates to sub-band-based coordinates per */ + /* equation B-15 of the standard */ + OPJ_UINT32 x0b = bandno & 1; + OPJ_UINT32 y0b = bandno >> 1; + if (tbx0) { + *tbx0 = (nb == 0) ? tcx0 : + (tcx0 <= (1U << (nb - 1)) * x0b) ? 0 : + opj_uint_ceildivpow2(tcx0 - (1U << (nb - 1)) * x0b, nb); + } + if (tby0) { + *tby0 = (nb == 0) ? tcy0 : + (tcy0 <= (1U << (nb - 1)) * y0b) ? 0 : + opj_uint_ceildivpow2(tcy0 - (1U << (nb - 1)) * y0b, nb); + } + if (tbx1) { + *tbx1 = (nb == 0) ? tcx1 : + (tcx1 <= (1U << (nb - 1)) * x0b) ? 0 : + opj_uint_ceildivpow2(tcx1 - (1U << (nb - 1)) * x0b, nb); + } + if (tby1) { + *tby1 = (nb == 0) ? tcy1 : + (tcy1 <= (1U << (nb - 1)) * y0b) ? 0 : + opj_uint_ceildivpow2(tcy1 - (1U << (nb - 1)) * y0b, nb); + } +} + +static void opj_dwt_segment_grow(OPJ_UINT32 filter_width, + OPJ_UINT32 max_size, + OPJ_UINT32* start, + OPJ_UINT32* end) +{ + *start = opj_uint_subs(*start, filter_width); + *end = opj_uint_adds(*end, filter_width); + *end = opj_uint_min(*end, max_size); +} + + +static opj_sparse_array_int32_t* opj_dwt_init_sparse_array( + opj_tcd_tilecomp_t* tilec, + OPJ_UINT32 numres) +{ + opj_tcd_resolution_t* tr_max = &(tilec->resolutions[numres - 1]); + OPJ_UINT32 w = (OPJ_UINT32)(tr_max->x1 - tr_max->x0); + OPJ_UINT32 h = (OPJ_UINT32)(tr_max->y1 - tr_max->y0); + OPJ_UINT32 resno, bandno, precno, cblkno; + opj_sparse_array_int32_t* sa = opj_sparse_array_int32_create( + w, h, opj_uint_min(w, 64), opj_uint_min(h, 64)); + if (sa == NULL) { + return NULL; + } + + for (resno = 0; resno < numres; ++resno) { + opj_tcd_resolution_t* res = &tilec->resolutions[resno]; + + for (bandno = 0; bandno < res->numbands; ++bandno) { + opj_tcd_band_t* band = &res->bands[bandno]; + + for (precno = 0; precno < res->pw * res->ph; ++precno) { + opj_tcd_precinct_t* precinct = &band->precincts[precno]; + for (cblkno = 0; cblkno < precinct->cw * precinct->ch; ++cblkno) { + opj_tcd_cblk_dec_t* cblk = &precinct->cblks.dec[cblkno]; + if (cblk->decoded_data != NULL) { + OPJ_UINT32 x = (OPJ_UINT32)(cblk->x0 - band->x0); + OPJ_UINT32 y = (OPJ_UINT32)(cblk->y0 - band->y0); + OPJ_UINT32 cblk_w = (OPJ_UINT32)(cblk->x1 - cblk->x0); + OPJ_UINT32 cblk_h = (OPJ_UINT32)(cblk->y1 - cblk->y0); + + if (band->bandno & 1) { + opj_tcd_resolution_t* pres = &tilec->resolutions[resno - 1]; + x += (OPJ_UINT32)(pres->x1 - pres->x0); + } + if (band->bandno & 2) { + opj_tcd_resolution_t* pres = &tilec->resolutions[resno - 1]; + y += (OPJ_UINT32)(pres->y1 - pres->y0); + } + + if (!opj_sparse_array_int32_write(sa, x, y, + x + cblk_w, y + cblk_h, + cblk->decoded_data, + 1, cblk_w, OPJ_TRUE)) { + opj_sparse_array_int32_free(sa); + return NULL; + } + } + } + } + } + } + + return sa; +} + + +static OPJ_BOOL opj_dwt_decode_partial_tile( + opj_tcd_tilecomp_t* tilec, + OPJ_UINT32 numres) +{ + opj_sparse_array_int32_t* sa; + opj_dwt_t h; + opj_dwt_t v; + OPJ_UINT32 resno; + /* This value matches the maximum left/right extension given in tables */ + /* F.2 and F.3 of the standard. */ + const OPJ_UINT32 filter_width = 2U; + + opj_tcd_resolution_t* tr = tilec->resolutions; + opj_tcd_resolution_t* tr_max = &(tilec->resolutions[numres - 1]); + + OPJ_UINT32 rw = (OPJ_UINT32)(tr->x1 - + tr->x0); /* width of the resolution level computed */ + OPJ_UINT32 rh = (OPJ_UINT32)(tr->y1 - + tr->y0); /* height of the resolution level computed */ + + OPJ_SIZE_T h_mem_size; + + /* Compute the intersection of the area of interest, expressed in tile coordinates */ + /* with the tile coordinates */ + OPJ_UINT32 win_tcx0 = tilec->win_x0; + OPJ_UINT32 win_tcy0 = tilec->win_y0; + OPJ_UINT32 win_tcx1 = tilec->win_x1; + OPJ_UINT32 win_tcy1 = tilec->win_y1; + + if (tr_max->x0 == tr_max->x1 || tr_max->y0 == tr_max->y1) { + return OPJ_TRUE; + } + + sa = opj_dwt_init_sparse_array(tilec, numres); + if (sa == NULL) { + return OPJ_FALSE; + } + + if (numres == 1U) { + OPJ_BOOL ret = opj_sparse_array_int32_read(sa, + tr_max->win_x0 - (OPJ_UINT32)tr_max->x0, + tr_max->win_y0 - (OPJ_UINT32)tr_max->y0, + tr_max->win_x1 - (OPJ_UINT32)tr_max->x0, + tr_max->win_y1 - (OPJ_UINT32)tr_max->y0, + tilec->data_win, + 1, tr_max->win_x1 - tr_max->win_x0, + OPJ_TRUE); + assert(ret); + OPJ_UNUSED(ret); + opj_sparse_array_int32_free(sa); + return OPJ_TRUE; + } + h_mem_size = opj_dwt_max_resolution(tr, numres); + /* overflow check */ + /* in vertical pass, we process 4 columns at a time */ + if (h_mem_size > (SIZE_MAX / (4 * sizeof(OPJ_INT32)))) { + /* FIXME event manager error callback */ + opj_sparse_array_int32_free(sa); + return OPJ_FALSE; + } + + h_mem_size *= 4 * sizeof(OPJ_INT32); + h.mem = (OPJ_INT32*)opj_aligned_32_malloc(h_mem_size); + if (! h.mem) { + /* FIXME event manager error callback */ + opj_sparse_array_int32_free(sa); + return OPJ_FALSE; + } + + v.mem = h.mem; + + for (resno = 1; resno < numres; resno ++) { + OPJ_UINT32 i, j; + /* Window of interest subband-based coordinates */ + OPJ_UINT32 win_ll_x0, win_ll_y0, win_ll_x1, win_ll_y1; + OPJ_UINT32 win_hl_x0, win_hl_x1; + OPJ_UINT32 win_lh_y0, win_lh_y1; + /* Window of interest tile-resolution-based coordinates */ + OPJ_UINT32 win_tr_x0, win_tr_x1, win_tr_y0, win_tr_y1; + /* Tile-resolution subband-based coordinates */ + OPJ_UINT32 tr_ll_x0, tr_ll_y0, tr_hl_x0, tr_lh_y0; + + ++tr; + + h.sn = (OPJ_INT32)rw; + v.sn = (OPJ_INT32)rh; + + rw = (OPJ_UINT32)(tr->x1 - tr->x0); + rh = (OPJ_UINT32)(tr->y1 - tr->y0); + + h.dn = (OPJ_INT32)(rw - (OPJ_UINT32)h.sn); + h.cas = tr->x0 % 2; + + v.dn = (OPJ_INT32)(rh - (OPJ_UINT32)v.sn); + v.cas = tr->y0 % 2; + + /* Get the subband coordinates for the window of interest */ + /* LL band */ + opj_dwt_get_band_coordinates(tilec, resno, 0, + win_tcx0, win_tcy0, win_tcx1, win_tcy1, + &win_ll_x0, &win_ll_y0, + &win_ll_x1, &win_ll_y1); + + /* HL band */ + opj_dwt_get_band_coordinates(tilec, resno, 1, + win_tcx0, win_tcy0, win_tcx1, win_tcy1, + &win_hl_x0, NULL, &win_hl_x1, NULL); + + /* LH band */ + opj_dwt_get_band_coordinates(tilec, resno, 2, + win_tcx0, win_tcy0, win_tcx1, win_tcy1, + NULL, &win_lh_y0, NULL, &win_lh_y1); + + /* Beware: band index for non-LL0 resolution are 0=HL, 1=LH and 2=HH */ + tr_ll_x0 = (OPJ_UINT32)tr->bands[1].x0; + tr_ll_y0 = (OPJ_UINT32)tr->bands[0].y0; + tr_hl_x0 = (OPJ_UINT32)tr->bands[0].x0; + tr_lh_y0 = (OPJ_UINT32)tr->bands[1].y0; + + /* Substract the origin of the bands for this tile, to the subwindow */ + /* of interest band coordinates, so as to get them relative to the */ + /* tile */ + win_ll_x0 = opj_uint_subs(win_ll_x0, tr_ll_x0); + win_ll_y0 = opj_uint_subs(win_ll_y0, tr_ll_y0); + win_ll_x1 = opj_uint_subs(win_ll_x1, tr_ll_x0); + win_ll_y1 = opj_uint_subs(win_ll_y1, tr_ll_y0); + win_hl_x0 = opj_uint_subs(win_hl_x0, tr_hl_x0); + win_hl_x1 = opj_uint_subs(win_hl_x1, tr_hl_x0); + win_lh_y0 = opj_uint_subs(win_lh_y0, tr_lh_y0); + win_lh_y1 = opj_uint_subs(win_lh_y1, tr_lh_y0); + + opj_dwt_segment_grow(filter_width, (OPJ_UINT32)h.sn, &win_ll_x0, &win_ll_x1); + opj_dwt_segment_grow(filter_width, (OPJ_UINT32)h.dn, &win_hl_x0, &win_hl_x1); + + opj_dwt_segment_grow(filter_width, (OPJ_UINT32)v.sn, &win_ll_y0, &win_ll_y1); + opj_dwt_segment_grow(filter_width, (OPJ_UINT32)v.dn, &win_lh_y0, &win_lh_y1); + + /* Compute the tile-resolution-based coordinates for the window of interest */ + if (h.cas == 0) { + win_tr_x0 = opj_uint_min(2 * win_ll_x0, 2 * win_hl_x0 + 1); + win_tr_x1 = opj_uint_min(opj_uint_max(2 * win_ll_x1, 2 * win_hl_x1 + 1), rw); + } else { + win_tr_x0 = opj_uint_min(2 * win_hl_x0, 2 * win_ll_x0 + 1); + win_tr_x1 = opj_uint_min(opj_uint_max(2 * win_hl_x1, 2 * win_ll_x1 + 1), rw); + } + + if (v.cas == 0) { + win_tr_y0 = opj_uint_min(2 * win_ll_y0, 2 * win_lh_y0 + 1); + win_tr_y1 = opj_uint_min(opj_uint_max(2 * win_ll_y1, 2 * win_lh_y1 + 1), rh); + } else { + win_tr_y0 = opj_uint_min(2 * win_lh_y0, 2 * win_ll_y0 + 1); + win_tr_y1 = opj_uint_min(opj_uint_max(2 * win_lh_y1, 2 * win_ll_y1 + 1), rh); + } + + for (j = 0; j < rh; ++j) { + if ((j >= win_ll_y0 && j < win_ll_y1) || + (j >= win_lh_y0 + (OPJ_UINT32)v.sn && j < win_lh_y1 + (OPJ_UINT32)v.sn)) { + + /* Avoids dwt.c:1584:44 (in opj_dwt_decode_partial_1): runtime error: */ + /* signed integer overflow: -1094795586 + -1094795586 cannot be represented in type 'int' */ + /* on opj_decompress -i ../../openjpeg/MAPA.jp2 -o out.tif -d 0,0,256,256 */ + /* This is less extreme than memsetting the whole buffer to 0 */ + /* although we could potentially do better with better handling of edge conditions */ + if (win_tr_x1 >= 1 && win_tr_x1 < rw) { + h.mem[win_tr_x1 - 1] = 0; + } + if (win_tr_x1 < rw) { + h.mem[win_tr_x1] = 0; + } + + opj_dwt_interleave_partial_h(h.mem, + h.cas, + sa, + j, + (OPJ_UINT32)h.sn, + win_ll_x0, + win_ll_x1, + win_hl_x0, + win_hl_x1); + opj_dwt_decode_partial_1(h.mem, h.dn, h.sn, h.cas, + (OPJ_INT32)win_ll_x0, + (OPJ_INT32)win_ll_x1, + (OPJ_INT32)win_hl_x0, + (OPJ_INT32)win_hl_x1); + if (!opj_sparse_array_int32_write(sa, + win_tr_x0, j, + win_tr_x1, j + 1, + h.mem + win_tr_x0, + 1, 0, OPJ_TRUE)) { + /* FIXME event manager error callback */ + opj_sparse_array_int32_free(sa); + opj_aligned_free(h.mem); + return OPJ_FALSE; + } + } + } + + for (i = win_tr_x0; i < win_tr_x1;) { + OPJ_UINT32 nb_cols = opj_uint_min(4U, win_tr_x1 - i); + opj_dwt_interleave_partial_v(v.mem, + v.cas, + sa, + i, + nb_cols, + (OPJ_UINT32)v.sn, + win_ll_y0, + win_ll_y1, + win_lh_y0, + win_lh_y1); + opj_dwt_decode_partial_1_parallel(v.mem, nb_cols, v.dn, v.sn, v.cas, + (OPJ_INT32)win_ll_y0, + (OPJ_INT32)win_ll_y1, + (OPJ_INT32)win_lh_y0, + (OPJ_INT32)win_lh_y1); + if (!opj_sparse_array_int32_write(sa, + i, win_tr_y0, + i + nb_cols, win_tr_y1, + v.mem + 4 * win_tr_y0, + 1, 4, OPJ_TRUE)) { + /* FIXME event manager error callback */ + opj_sparse_array_int32_free(sa); + opj_aligned_free(h.mem); + return OPJ_FALSE; + } + + i += nb_cols; + } + } + opj_aligned_free(h.mem); + + { + OPJ_BOOL ret = opj_sparse_array_int32_read(sa, + tr_max->win_x0 - (OPJ_UINT32)tr_max->x0, + tr_max->win_y0 - (OPJ_UINT32)tr_max->y0, + tr_max->win_x1 - (OPJ_UINT32)tr_max->x0, + tr_max->win_y1 - (OPJ_UINT32)tr_max->y0, + tilec->data_win, + 1, tr_max->win_x1 - tr_max->win_x0, + OPJ_TRUE); + assert(ret); + OPJ_UNUSED(ret); + } + opj_sparse_array_int32_free(sa); + return OPJ_TRUE; +} + +static void opj_v4dwt_interleave_h(opj_v4dwt_t* OPJ_RESTRICT dwt, + OPJ_FLOAT32* OPJ_RESTRICT a, + OPJ_UINT32 width, + OPJ_UINT32 remaining_height) { - OPJ_FLOAT32* OPJ_RESTRICT bi = (OPJ_FLOAT32*)(w->wavelet + w->cas); - OPJ_INT32 count = w->sn; - OPJ_INT32 i, k; + OPJ_FLOAT32* OPJ_RESTRICT bi = (OPJ_FLOAT32*)(dwt->wavelet + dwt->cas); + OPJ_UINT32 i, k; + OPJ_UINT32 x0 = dwt->win_l_x0; + OPJ_UINT32 x1 = dwt->win_l_x1; for (k = 0; k < 2; ++k) { - if (count + 3 * x < size && ((size_t) a & 0x0f) == 0 && - ((size_t) bi & 0x0f) == 0 && (x & 0x0f) == 0) { + if (remaining_height >= 4 && ((OPJ_SIZE_T) a & 0x0f) == 0 && + ((OPJ_SIZE_T) bi & 0x0f) == 0 && (width & 0x0f) == 0) { /* Fast code path */ - for (i = 0; i < count; ++i) { - OPJ_INT32 j = i; + for (i = x0; i < x1; ++i) { + OPJ_UINT32 j = i; bi[i * 8 ] = a[j]; - j += x; + j += width; bi[i * 8 + 1] = a[j]; - j += x; + j += width; bi[i * 8 + 2] = a[j]; - j += x; + j += width; bi[i * 8 + 3] = a[j]; } } else { /* Slow code path */ - for (i = 0; i < count; ++i) { - OPJ_INT32 j = i; + for (i = x0; i < x1; ++i) { + OPJ_UINT32 j = i; bi[i * 8 ] = a[j]; - j += x; - if (j >= size) { + j += width; + if (remaining_height == 1) { continue; } bi[i * 8 + 1] = a[j]; - j += x; - if (j >= size) { + j += width; + if (remaining_height == 2) { continue; } bi[i * 8 + 2] = a[j]; - j += x; - if (j >= size) { + j += width; + if (remaining_height == 3) { continue; } bi[i * 8 + 3] = a[j]; /* This one*/ } } - bi = (OPJ_FLOAT32*)(w->wavelet + 1 - w->cas); - a += w->sn; - size -= w->sn; - count = w->dn; + bi = (OPJ_FLOAT32*)(dwt->wavelet + 1 - dwt->cas); + a += dwt->sn; + x0 = dwt->win_h_x0; + x1 = dwt->win_h_x1; } } -static void opj_v4dwt_interleave_v(opj_v4dwt_t* OPJ_RESTRICT v, - OPJ_FLOAT32* OPJ_RESTRICT a, OPJ_INT32 x, OPJ_INT32 nb_elts_read) +static void opj_v4dwt_interleave_partial_h(opj_v4dwt_t* dwt, + opj_sparse_array_int32_t* sa, + OPJ_UINT32 sa_line, + OPJ_UINT32 remaining_height) { - opj_v4_t* OPJ_RESTRICT bi = v->wavelet + v->cas; - OPJ_INT32 i; + OPJ_UINT32 i; + for (i = 0; i < remaining_height; i++) { + OPJ_BOOL ret; + ret = opj_sparse_array_int32_read(sa, + dwt->win_l_x0, sa_line + i, + dwt->win_l_x1, sa_line + i + 1, + /* Nasty cast from float* to int32* */ + (OPJ_INT32*)(dwt->wavelet + dwt->cas + 2 * dwt->win_l_x0) + i, + 8, 0, OPJ_TRUE); + assert(ret); + ret = opj_sparse_array_int32_read(sa, + (OPJ_UINT32)dwt->sn + dwt->win_h_x0, sa_line + i, + (OPJ_UINT32)dwt->sn + dwt->win_h_x1, sa_line + i + 1, + /* Nasty cast from float* to int32* */ + (OPJ_INT32*)(dwt->wavelet + 1 - dwt->cas + 2 * dwt->win_h_x0) + i, + 8, 0, OPJ_TRUE); + assert(ret); + OPJ_UNUSED(ret); + } +} - for (i = 0; i < v->sn; ++i) { - memcpy(&bi[i * 2], &a[i * x], (size_t)nb_elts_read * sizeof(OPJ_FLOAT32)); +static void opj_v4dwt_interleave_v(opj_v4dwt_t* OPJ_RESTRICT dwt, + OPJ_FLOAT32* OPJ_RESTRICT a, + OPJ_UINT32 width, + OPJ_UINT32 nb_elts_read) +{ + opj_v4_t* OPJ_RESTRICT bi = dwt->wavelet + dwt->cas; + OPJ_UINT32 i; + + for (i = dwt->win_l_x0; i < dwt->win_l_x1; ++i) { + memcpy(&bi[i * 2], &a[i * (OPJ_SIZE_T)width], + (OPJ_SIZE_T)nb_elts_read * sizeof(OPJ_FLOAT32)); } - a += v->sn * x; - bi = v->wavelet + 1 - v->cas; + a += (OPJ_UINT32)dwt->sn * (OPJ_SIZE_T)width; + bi = dwt->wavelet + 1 - dwt->cas; - for (i = 0; i < v->dn; ++i) { - memcpy(&bi[i * 2], &a[i * x], (size_t)nb_elts_read * sizeof(OPJ_FLOAT32)); + for (i = dwt->win_h_x0; i < dwt->win_h_x1; ++i) { + memcpy(&bi[i * 2], &a[i * (OPJ_SIZE_T)width], + (OPJ_SIZE_T)nb_elts_read * sizeof(OPJ_FLOAT32)); } } +static void opj_v4dwt_interleave_partial_v(opj_v4dwt_t* OPJ_RESTRICT dwt, + opj_sparse_array_int32_t* sa, + OPJ_UINT32 sa_col, + OPJ_UINT32 nb_elts_read) +{ + OPJ_BOOL ret; + ret = opj_sparse_array_int32_read(sa, + sa_col, dwt->win_l_x0, + sa_col + nb_elts_read, dwt->win_l_x1, + (OPJ_INT32*)(dwt->wavelet + dwt->cas + 2 * dwt->win_l_x0), + 1, 8, OPJ_TRUE); + assert(ret); + ret = opj_sparse_array_int32_read(sa, + sa_col, (OPJ_UINT32)dwt->sn + dwt->win_h_x0, + sa_col + nb_elts_read, (OPJ_UINT32)dwt->sn + dwt->win_h_x1, + (OPJ_INT32*)(dwt->wavelet + 1 - dwt->cas + 2 * dwt->win_h_x0), + 1, 8, OPJ_TRUE); + assert(ret); + OPJ_UNUSED(ret); +} + #ifdef __SSE__ -static void opj_v4dwt_decode_step1_sse(opj_v4_t* w, OPJ_INT32 count, +static void opj_v4dwt_decode_step1_sse(opj_v4_t* w, + OPJ_UINT32 start, + OPJ_UINT32 end, const __m128 c) { __m128* OPJ_RESTRICT vw = (__m128*) w; - OPJ_INT32 i; + OPJ_UINT32 i; /* 4x unrolled loop */ - for (i = 0; i < count >> 2; ++i) { - *vw = _mm_mul_ps(*vw, c); - vw += 2; - *vw = _mm_mul_ps(*vw, c); - vw += 2; - *vw = _mm_mul_ps(*vw, c); - vw += 2; - *vw = _mm_mul_ps(*vw, c); - vw += 2; - } - count &= 3; - for (i = 0; i < count; ++i) { - *vw = _mm_mul_ps(*vw, c); - vw += 2; + vw += 2 * start; + for (i = start; i + 3 < end; i += 4, vw += 8) { + __m128 xmm0 = _mm_mul_ps(vw[0], c); + __m128 xmm2 = _mm_mul_ps(vw[2], c); + __m128 xmm4 = _mm_mul_ps(vw[4], c); + __m128 xmm6 = _mm_mul_ps(vw[6], c); + vw[0] = xmm0; + vw[2] = xmm2; + vw[4] = xmm4; + vw[6] = xmm6; + } + for (; i < end; ++i, vw += 2) { + vw[0] = _mm_mul_ps(vw[0], c); } } -void opj_v4dwt_decode_step2_sse(opj_v4_t* l, opj_v4_t* w, OPJ_INT32 k, - OPJ_INT32 m, __m128 c) +static void opj_v4dwt_decode_step2_sse(opj_v4_t* l, opj_v4_t* w, + OPJ_UINT32 start, + OPJ_UINT32 end, + OPJ_UINT32 m, + __m128 c) { __m128* OPJ_RESTRICT vl = (__m128*) l; __m128* OPJ_RESTRICT vw = (__m128*) w; - OPJ_INT32 i; + OPJ_UINT32 i; + OPJ_UINT32 imax = opj_uint_min(end, m); __m128 tmp1, tmp2, tmp3; - tmp1 = vl[0]; - for (i = 0; i < m; ++i) { + if (start == 0) { + tmp1 = vl[0]; + } else { + vw += start * 2; + tmp1 = vw[-3]; + } + + i = start; + + /* 4x loop unrolling */ + for (; i + 3 < imax; i += 4) { + __m128 tmp4, tmp5, tmp6, tmp7, tmp8, tmp9; + tmp2 = vw[-1]; + tmp3 = vw[ 0]; + tmp4 = vw[ 1]; + tmp5 = vw[ 2]; + tmp6 = vw[ 3]; + tmp7 = vw[ 4]; + tmp8 = vw[ 5]; + tmp9 = vw[ 6]; + vw[-1] = _mm_add_ps(tmp2, _mm_mul_ps(_mm_add_ps(tmp1, tmp3), c)); + vw[ 1] = _mm_add_ps(tmp4, _mm_mul_ps(_mm_add_ps(tmp3, tmp5), c)); + vw[ 3] = _mm_add_ps(tmp6, _mm_mul_ps(_mm_add_ps(tmp5, tmp7), c)); + vw[ 5] = _mm_add_ps(tmp8, _mm_mul_ps(_mm_add_ps(tmp7, tmp9), c)); + tmp1 = tmp9; + vw += 8; + } + + for (; i < imax; ++i) { tmp2 = vw[-1]; tmp3 = vw[ 0]; vw[-1] = _mm_add_ps(tmp2, _mm_mul_ps(_mm_add_ps(tmp1, tmp3), c)); tmp1 = tmp3; vw += 2; } - vl = vw - 2; - if (m >= k) { - return; - } - c = _mm_add_ps(c, c); - c = _mm_mul_ps(c, vl[0]); - for (; m < k; ++m) { - __m128 tmp = vw[-1]; - vw[-1] = _mm_add_ps(tmp, c); - vw += 2; + if (m < end) { + assert(m + 1 == end); + c = _mm_add_ps(c, c); + c = _mm_mul_ps(c, vw[-2]); + vw[-1] = _mm_add_ps(vw[-1], c); } } #else -static void opj_v4dwt_decode_step1(opj_v4_t* w, OPJ_INT32 count, +static void opj_v4dwt_decode_step1(opj_v4_t* w, + OPJ_UINT32 start, + OPJ_UINT32 end, const OPJ_FLOAT32 c) { OPJ_FLOAT32* OPJ_RESTRICT fw = (OPJ_FLOAT32*) w; - OPJ_INT32 i; - for (i = 0; i < count; ++i) { + OPJ_UINT32 i; + for (i = start; i < end; ++i) { OPJ_FLOAT32 tmp1 = fw[i * 8 ]; OPJ_FLOAT32 tmp2 = fw[i * 8 + 1]; OPJ_FLOAT32 tmp3 = fw[i * 8 + 2]; @@ -1642,13 +2392,21 @@ static void opj_v4dwt_decode_step1(opj_v4_t* w, OPJ_INT32 count, } } -static void opj_v4dwt_decode_step2(opj_v4_t* l, opj_v4_t* w, OPJ_INT32 k, - OPJ_INT32 m, OPJ_FLOAT32 c) +static void opj_v4dwt_decode_step2(opj_v4_t* l, opj_v4_t* w, + OPJ_UINT32 start, + OPJ_UINT32 end, + OPJ_UINT32 m, + OPJ_FLOAT32 c) { OPJ_FLOAT32* fl = (OPJ_FLOAT32*) l; OPJ_FLOAT32* fw = (OPJ_FLOAT32*) w; - OPJ_INT32 i; - for (i = 0; i < m; ++i) { + OPJ_UINT32 i; + OPJ_UINT32 imax = opj_uint_min(end, m); + if (start > 0) { + fw += 8 * start; + fl = fw - 8; + } + for (i = start; i < imax; ++i) { OPJ_FLOAT32 tmp1_1 = fl[0]; OPJ_FLOAT32 tmp1_2 = fl[1]; OPJ_FLOAT32 tmp1_3 = fl[2]; @@ -1668,27 +2426,13 @@ static void opj_v4dwt_decode_step2(opj_v4_t* l, opj_v4_t* w, OPJ_INT32 k, fl = fw; fw += 8; } - if (m < k) { - OPJ_FLOAT32 c1; - OPJ_FLOAT32 c2; - OPJ_FLOAT32 c3; - OPJ_FLOAT32 c4; + if (m < end) { + assert(m + 1 == end); c += c; - c1 = fl[0] * c; - c2 = fl[1] * c; - c3 = fl[2] * c; - c4 = fl[3] * c; - for (; m < k; ++m) { - OPJ_FLOAT32 tmp1 = fw[-4]; - OPJ_FLOAT32 tmp2 = fw[-3]; - OPJ_FLOAT32 tmp3 = fw[-2]; - OPJ_FLOAT32 tmp4 = fw[-1]; - fw[-4] = tmp1 + c1; - fw[-3] = tmp2 + c2; - fw[-2] = tmp3 + c3; - fw[-1] = tmp4 + c4; - fw += 8; - } + fw[-4] = fw[-4] + fl[0] * c; + fw[-3] = fw[-3] + fl[1] * c; + fw[-2] = fw[-2] + fl[2] * c; + fw[-1] = fw[-1] + fl[3] * c; } } @@ -1714,27 +2458,47 @@ static void opj_v4dwt_decode(opj_v4dwt_t* OPJ_RESTRICT dwt) b = 0; } #ifdef __SSE__ - opj_v4dwt_decode_step1_sse(dwt->wavelet + a, dwt->sn, _mm_set1_ps(opj_K)); - opj_v4dwt_decode_step1_sse(dwt->wavelet + b, dwt->dn, _mm_set1_ps(opj_c13318)); - opj_v4dwt_decode_step2_sse(dwt->wavelet + b, dwt->wavelet + a + 1, dwt->sn, - opj_int_min(dwt->sn, dwt->dn - a), _mm_set1_ps(opj_dwt_delta)); - opj_v4dwt_decode_step2_sse(dwt->wavelet + a, dwt->wavelet + b + 1, dwt->dn, - opj_int_min(dwt->dn, dwt->sn - b), _mm_set1_ps(opj_dwt_gamma)); - opj_v4dwt_decode_step2_sse(dwt->wavelet + b, dwt->wavelet + a + 1, dwt->sn, - opj_int_min(dwt->sn, dwt->dn - a), _mm_set1_ps(opj_dwt_beta)); - opj_v4dwt_decode_step2_sse(dwt->wavelet + a, dwt->wavelet + b + 1, dwt->dn, - opj_int_min(dwt->dn, dwt->sn - b), _mm_set1_ps(opj_dwt_alpha)); + opj_v4dwt_decode_step1_sse(dwt->wavelet + a, dwt->win_l_x0, dwt->win_l_x1, + _mm_set1_ps(opj_K)); + opj_v4dwt_decode_step1_sse(dwt->wavelet + b, dwt->win_h_x0, dwt->win_h_x1, + _mm_set1_ps(opj_c13318)); + opj_v4dwt_decode_step2_sse(dwt->wavelet + b, dwt->wavelet + a + 1, + dwt->win_l_x0, dwt->win_l_x1, + (OPJ_UINT32)opj_int_min(dwt->sn, dwt->dn - a), + _mm_set1_ps(opj_dwt_delta)); + opj_v4dwt_decode_step2_sse(dwt->wavelet + a, dwt->wavelet + b + 1, + dwt->win_h_x0, dwt->win_h_x1, + (OPJ_UINT32)opj_int_min(dwt->dn, dwt->sn - b), + _mm_set1_ps(opj_dwt_gamma)); + opj_v4dwt_decode_step2_sse(dwt->wavelet + b, dwt->wavelet + a + 1, + dwt->win_l_x0, dwt->win_l_x1, + (OPJ_UINT32)opj_int_min(dwt->sn, dwt->dn - a), + _mm_set1_ps(opj_dwt_beta)); + opj_v4dwt_decode_step2_sse(dwt->wavelet + a, dwt->wavelet + b + 1, + dwt->win_h_x0, dwt->win_h_x1, + (OPJ_UINT32)opj_int_min(dwt->dn, dwt->sn - b), + _mm_set1_ps(opj_dwt_alpha)); #else - opj_v4dwt_decode_step1(dwt->wavelet + a, dwt->sn, opj_K); - opj_v4dwt_decode_step1(dwt->wavelet + b, dwt->dn, opj_c13318); - opj_v4dwt_decode_step2(dwt->wavelet + b, dwt->wavelet + a + 1, dwt->sn, - opj_int_min(dwt->sn, dwt->dn - a), opj_dwt_delta); - opj_v4dwt_decode_step2(dwt->wavelet + a, dwt->wavelet + b + 1, dwt->dn, - opj_int_min(dwt->dn, dwt->sn - b), opj_dwt_gamma); - opj_v4dwt_decode_step2(dwt->wavelet + b, dwt->wavelet + a + 1, dwt->sn, - opj_int_min(dwt->sn, dwt->dn - a), opj_dwt_beta); - opj_v4dwt_decode_step2(dwt->wavelet + a, dwt->wavelet + b + 1, dwt->dn, - opj_int_min(dwt->dn, dwt->sn - b), opj_dwt_alpha); + opj_v4dwt_decode_step1(dwt->wavelet + a, dwt->win_l_x0, dwt->win_l_x1, + opj_K); + opj_v4dwt_decode_step1(dwt->wavelet + b, dwt->win_h_x0, dwt->win_h_x1, + opj_c13318); + opj_v4dwt_decode_step2(dwt->wavelet + b, dwt->wavelet + a + 1, + dwt->win_l_x0, dwt->win_l_x1, + (OPJ_UINT32)opj_int_min(dwt->sn, dwt->dn - a), + opj_dwt_delta); + opj_v4dwt_decode_step2(dwt->wavelet + a, dwt->wavelet + b + 1, + dwt->win_h_x0, dwt->win_h_x1, + (OPJ_UINT32)opj_int_min(dwt->dn, dwt->sn - b), + opj_dwt_gamma); + opj_v4dwt_decode_step2(dwt->wavelet + b, dwt->wavelet + a + 1, + dwt->win_l_x0, dwt->win_l_x1, + (OPJ_UINT32)opj_int_min(dwt->sn, dwt->dn - a), + opj_dwt_beta); + opj_v4dwt_decode_step2(dwt->wavelet + a, dwt->wavelet + b + 1, + dwt->win_h_x0, dwt->win_h_x1, + (OPJ_UINT32)opj_int_min(dwt->dn, dwt->sn - b), + opj_dwt_alpha); #endif } @@ -1742,8 +2506,9 @@ static void opj_v4dwt_decode(opj_v4dwt_t* OPJ_RESTRICT dwt) /* <summary> */ /* Inverse 9-7 wavelet transform in 2-D. */ /* </summary> */ -OPJ_BOOL opj_dwt_decode_real(opj_tcd_tilecomp_t* OPJ_RESTRICT tilec, - OPJ_UINT32 numres) +static +OPJ_BOOL opj_dwt_decode_tile_97(opj_tcd_tilecomp_t* OPJ_RESTRICT tilec, + OPJ_UINT32 numres) { opj_v4dwt_t h; opj_v4dwt_t v; @@ -1755,9 +2520,11 @@ OPJ_BOOL opj_dwt_decode_real(opj_tcd_tilecomp_t* OPJ_RESTRICT tilec, OPJ_UINT32 rh = (OPJ_UINT32)(res->y1 - res->y0); /* height of the resolution level computed */ - OPJ_UINT32 w = (OPJ_UINT32)(tilec->x1 - tilec->x0); + OPJ_UINT32 w = (OPJ_UINT32)(tilec->resolutions[tilec->minimum_num_resolutions - + 1].x1 - + tilec->resolutions[tilec->minimum_num_resolutions - 1].x0); - size_t l_data_size; + OPJ_SIZE_T l_data_size; l_data_size = opj_dwt_max_resolution(res, numres); /* overflow check */ @@ -1780,9 +2547,7 @@ OPJ_BOOL opj_dwt_decode_real(opj_tcd_tilecomp_t* OPJ_RESTRICT tilec, while (--numres) { OPJ_FLOAT32 * OPJ_RESTRICT aj = (OPJ_FLOAT32*) tilec->data; - OPJ_UINT32 bufsize = (OPJ_UINT32)((tilec->x1 - tilec->x0) * - (tilec->y1 - tilec->y0)); - OPJ_INT32 j; + OPJ_UINT32 j; h.sn = (OPJ_INT32)rw; v.sn = (OPJ_INT32)rh; @@ -1797,53 +2562,59 @@ OPJ_BOOL opj_dwt_decode_real(opj_tcd_tilecomp_t* OPJ_RESTRICT tilec, h.dn = (OPJ_INT32)(rw - (OPJ_UINT32)h.sn); h.cas = res->x0 % 2; - for (j = (OPJ_INT32)rh; j > 3; j -= 4) { - OPJ_INT32 k; - opj_v4dwt_interleave_h(&h, aj, (OPJ_INT32)w, (OPJ_INT32)bufsize); + h.win_l_x0 = 0; + h.win_l_x1 = (OPJ_UINT32)h.sn; + h.win_h_x0 = 0; + h.win_h_x1 = (OPJ_UINT32)h.dn; + for (j = 0; j + 3 < rh; j += 4) { + OPJ_UINT32 k; + opj_v4dwt_interleave_h(&h, aj, w, rh - j); opj_v4dwt_decode(&h); - for (k = (OPJ_INT32)rw; --k >= 0;) { - aj[k ] = h.wavelet[k].f[0]; - aj[k + (OPJ_INT32)w ] = h.wavelet[k].f[1]; - aj[k + (OPJ_INT32)w * 2] = h.wavelet[k].f[2]; - aj[k + (OPJ_INT32)w * 3] = h.wavelet[k].f[3]; + for (k = 0; k < rw; k++) { + aj[k ] = h.wavelet[k].f[0]; + aj[k + (OPJ_SIZE_T)w ] = h.wavelet[k].f[1]; + aj[k + (OPJ_SIZE_T)w * 2] = h.wavelet[k].f[2]; + aj[k + (OPJ_SIZE_T)w * 3] = h.wavelet[k].f[3]; } aj += w * 4; - bufsize -= w * 4; } - if (rh & 0x03) { - OPJ_INT32 k; - j = rh & 0x03; - opj_v4dwt_interleave_h(&h, aj, (OPJ_INT32)w, (OPJ_INT32)bufsize); + if (j < rh) { + OPJ_UINT32 k; + opj_v4dwt_interleave_h(&h, aj, w, rh - j); opj_v4dwt_decode(&h); - for (k = (OPJ_INT32)rw; --k >= 0;) { - switch (j) { + for (k = 0; k < rw; k++) { + switch (rh - j) { case 3: - aj[k + (OPJ_INT32)w * 2] = h.wavelet[k].f[2]; + aj[k + (OPJ_SIZE_T)w * 2] = h.wavelet[k].f[2]; /* FALLTHRU */ case 2: - aj[k + (OPJ_INT32)w ] = h.wavelet[k].f[1]; + aj[k + (OPJ_SIZE_T)w ] = h.wavelet[k].f[1]; /* FALLTHRU */ case 1: - aj[k ] = h.wavelet[k].f[0]; + aj[k] = h.wavelet[k].f[0]; } } } v.dn = (OPJ_INT32)(rh - (OPJ_UINT32)v.sn); v.cas = res->y0 % 2; + v.win_l_x0 = 0; + v.win_l_x1 = (OPJ_UINT32)v.sn; + v.win_h_x0 = 0; + v.win_h_x1 = (OPJ_UINT32)v.dn; aj = (OPJ_FLOAT32*) tilec->data; - for (j = (OPJ_INT32)rw; j > 3; j -= 4) { + for (j = rw; j > 3; j -= 4) { OPJ_UINT32 k; - opj_v4dwt_interleave_v(&v, aj, (OPJ_INT32)w, 4); + opj_v4dwt_interleave_v(&v, aj, w, 4); opj_v4dwt_decode(&v); for (k = 0; k < rh; ++k) { - memcpy(&aj[k * w], &v.wavelet[k], 4 * sizeof(OPJ_FLOAT32)); + memcpy(&aj[k * (OPJ_SIZE_T)w], &v.wavelet[k], 4 * sizeof(OPJ_FLOAT32)); } aj += 4; } @@ -1853,15 +2624,266 @@ OPJ_BOOL opj_dwt_decode_real(opj_tcd_tilecomp_t* OPJ_RESTRICT tilec, j = rw & 0x03; - opj_v4dwt_interleave_v(&v, aj, (OPJ_INT32)w, j); + opj_v4dwt_interleave_v(&v, aj, w, j); opj_v4dwt_decode(&v); for (k = 0; k < rh; ++k) { - memcpy(&aj[k * w], &v.wavelet[k], (size_t)j * sizeof(OPJ_FLOAT32)); + memcpy(&aj[k * (OPJ_SIZE_T)w], &v.wavelet[k], + (OPJ_SIZE_T)j * sizeof(OPJ_FLOAT32)); + } + } + } + + opj_aligned_free(h.wavelet); + return OPJ_TRUE; +} + +static +OPJ_BOOL opj_dwt_decode_partial_97(opj_tcd_tilecomp_t* OPJ_RESTRICT tilec, + OPJ_UINT32 numres) +{ + opj_sparse_array_int32_t* sa; + opj_v4dwt_t h; + opj_v4dwt_t v; + OPJ_UINT32 resno; + /* This value matches the maximum left/right extension given in tables */ + /* F.2 and F.3 of the standard. Note: in opj_tcd_is_subband_area_of_interest() */ + /* we currently use 3. */ + const OPJ_UINT32 filter_width = 4U; + + opj_tcd_resolution_t* tr = tilec->resolutions; + opj_tcd_resolution_t* tr_max = &(tilec->resolutions[numres - 1]); + + OPJ_UINT32 rw = (OPJ_UINT32)(tr->x1 - + tr->x0); /* width of the resolution level computed */ + OPJ_UINT32 rh = (OPJ_UINT32)(tr->y1 - + tr->y0); /* height of the resolution level computed */ + + OPJ_SIZE_T l_data_size; + + /* Compute the intersection of the area of interest, expressed in tile coordinates */ + /* with the tile coordinates */ + OPJ_UINT32 win_tcx0 = tilec->win_x0; + OPJ_UINT32 win_tcy0 = tilec->win_y0; + OPJ_UINT32 win_tcx1 = tilec->win_x1; + OPJ_UINT32 win_tcy1 = tilec->win_y1; + + if (tr_max->x0 == tr_max->x1 || tr_max->y0 == tr_max->y1) { + return OPJ_TRUE; + } + + sa = opj_dwt_init_sparse_array(tilec, numres); + if (sa == NULL) { + return OPJ_FALSE; + } + + if (numres == 1U) { + OPJ_BOOL ret = opj_sparse_array_int32_read(sa, + tr_max->win_x0 - (OPJ_UINT32)tr_max->x0, + tr_max->win_y0 - (OPJ_UINT32)tr_max->y0, + tr_max->win_x1 - (OPJ_UINT32)tr_max->x0, + tr_max->win_y1 - (OPJ_UINT32)tr_max->y0, + tilec->data_win, + 1, tr_max->win_x1 - tr_max->win_x0, + OPJ_TRUE); + assert(ret); + OPJ_UNUSED(ret); + opj_sparse_array_int32_free(sa); + return OPJ_TRUE; + } + + l_data_size = opj_dwt_max_resolution(tr, numres); + /* overflow check */ + if (l_data_size > (SIZE_MAX - 5U)) { + /* FIXME event manager error callback */ + return OPJ_FALSE; + } + l_data_size += 5U; + /* overflow check */ + if (l_data_size > (SIZE_MAX / sizeof(opj_v4_t))) { + /* FIXME event manager error callback */ + return OPJ_FALSE; + } + h.wavelet = (opj_v4_t*) opj_aligned_malloc(l_data_size * sizeof(opj_v4_t)); + if (!h.wavelet) { + /* FIXME event manager error callback */ + return OPJ_FALSE; + } + v.wavelet = h.wavelet; + + for (resno = 1; resno < numres; resno ++) { + OPJ_UINT32 j; + /* Window of interest subband-based coordinates */ + OPJ_UINT32 win_ll_x0, win_ll_y0, win_ll_x1, win_ll_y1; + OPJ_UINT32 win_hl_x0, win_hl_x1; + OPJ_UINT32 win_lh_y0, win_lh_y1; + /* Window of interest tile-resolution-based coordinates */ + OPJ_UINT32 win_tr_x0, win_tr_x1, win_tr_y0, win_tr_y1; + /* Tile-resolution subband-based coordinates */ + OPJ_UINT32 tr_ll_x0, tr_ll_y0, tr_hl_x0, tr_lh_y0; + + ++tr; + + h.sn = (OPJ_INT32)rw; + v.sn = (OPJ_INT32)rh; + + rw = (OPJ_UINT32)(tr->x1 - tr->x0); + rh = (OPJ_UINT32)(tr->y1 - tr->y0); + + h.dn = (OPJ_INT32)(rw - (OPJ_UINT32)h.sn); + h.cas = tr->x0 % 2; + + v.dn = (OPJ_INT32)(rh - (OPJ_UINT32)v.sn); + v.cas = tr->y0 % 2; + + /* Get the subband coordinates for the window of interest */ + /* LL band */ + opj_dwt_get_band_coordinates(tilec, resno, 0, + win_tcx0, win_tcy0, win_tcx1, win_tcy1, + &win_ll_x0, &win_ll_y0, + &win_ll_x1, &win_ll_y1); + + /* HL band */ + opj_dwt_get_band_coordinates(tilec, resno, 1, + win_tcx0, win_tcy0, win_tcx1, win_tcy1, + &win_hl_x0, NULL, &win_hl_x1, NULL); + + /* LH band */ + opj_dwt_get_band_coordinates(tilec, resno, 2, + win_tcx0, win_tcy0, win_tcx1, win_tcy1, + NULL, &win_lh_y0, NULL, &win_lh_y1); + + /* Beware: band index for non-LL0 resolution are 0=HL, 1=LH and 2=HH */ + tr_ll_x0 = (OPJ_UINT32)tr->bands[1].x0; + tr_ll_y0 = (OPJ_UINT32)tr->bands[0].y0; + tr_hl_x0 = (OPJ_UINT32)tr->bands[0].x0; + tr_lh_y0 = (OPJ_UINT32)tr->bands[1].y0; + + /* Substract the origin of the bands for this tile, to the subwindow */ + /* of interest band coordinates, so as to get them relative to the */ + /* tile */ + win_ll_x0 = opj_uint_subs(win_ll_x0, tr_ll_x0); + win_ll_y0 = opj_uint_subs(win_ll_y0, tr_ll_y0); + win_ll_x1 = opj_uint_subs(win_ll_x1, tr_ll_x0); + win_ll_y1 = opj_uint_subs(win_ll_y1, tr_ll_y0); + win_hl_x0 = opj_uint_subs(win_hl_x0, tr_hl_x0); + win_hl_x1 = opj_uint_subs(win_hl_x1, tr_hl_x0); + win_lh_y0 = opj_uint_subs(win_lh_y0, tr_lh_y0); + win_lh_y1 = opj_uint_subs(win_lh_y1, tr_lh_y0); + + opj_dwt_segment_grow(filter_width, (OPJ_UINT32)h.sn, &win_ll_x0, &win_ll_x1); + opj_dwt_segment_grow(filter_width, (OPJ_UINT32)h.dn, &win_hl_x0, &win_hl_x1); + + opj_dwt_segment_grow(filter_width, (OPJ_UINT32)v.sn, &win_ll_y0, &win_ll_y1); + opj_dwt_segment_grow(filter_width, (OPJ_UINT32)v.dn, &win_lh_y0, &win_lh_y1); + + /* Compute the tile-resolution-based coordinates for the window of interest */ + if (h.cas == 0) { + win_tr_x0 = opj_uint_min(2 * win_ll_x0, 2 * win_hl_x0 + 1); + win_tr_x1 = opj_uint_min(opj_uint_max(2 * win_ll_x1, 2 * win_hl_x1 + 1), rw); + } else { + win_tr_x0 = opj_uint_min(2 * win_hl_x0, 2 * win_ll_x0 + 1); + win_tr_x1 = opj_uint_min(opj_uint_max(2 * win_hl_x1, 2 * win_ll_x1 + 1), rw); + } + + if (v.cas == 0) { + win_tr_y0 = opj_uint_min(2 * win_ll_y0, 2 * win_lh_y0 + 1); + win_tr_y1 = opj_uint_min(opj_uint_max(2 * win_ll_y1, 2 * win_lh_y1 + 1), rh); + } else { + win_tr_y0 = opj_uint_min(2 * win_lh_y0, 2 * win_ll_y0 + 1); + win_tr_y1 = opj_uint_min(opj_uint_max(2 * win_lh_y1, 2 * win_ll_y1 + 1), rh); + } + + h.win_l_x0 = win_ll_x0; + h.win_l_x1 = win_ll_x1; + h.win_h_x0 = win_hl_x0; + h.win_h_x1 = win_hl_x1; + for (j = 0; j + 3 < rh; j += 4) { + if ((j + 3 >= win_ll_y0 && j < win_ll_y1) || + (j + 3 >= win_lh_y0 + (OPJ_UINT32)v.sn && + j < win_lh_y1 + (OPJ_UINT32)v.sn)) { + opj_v4dwt_interleave_partial_h(&h, sa, j, opj_uint_min(4U, rh - j)); + opj_v4dwt_decode(&h); + if (!opj_sparse_array_int32_write(sa, + win_tr_x0, j, + win_tr_x1, j + 4, + (OPJ_INT32*)&h.wavelet[win_tr_x0].f[0], + 4, 1, OPJ_TRUE)) { + /* FIXME event manager error callback */ + opj_sparse_array_int32_free(sa); + opj_aligned_free(h.wavelet); + return OPJ_FALSE; + } + } + } + + if (j < rh && + ((j + 3 >= win_ll_y0 && j < win_ll_y1) || + (j + 3 >= win_lh_y0 + (OPJ_UINT32)v.sn && + j < win_lh_y1 + (OPJ_UINT32)v.sn))) { + opj_v4dwt_interleave_partial_h(&h, sa, j, rh - j); + opj_v4dwt_decode(&h); + if (!opj_sparse_array_int32_write(sa, + win_tr_x0, j, + win_tr_x1, rh, + (OPJ_INT32*)&h.wavelet[win_tr_x0].f[0], + 4, 1, OPJ_TRUE)) { + /* FIXME event manager error callback */ + opj_sparse_array_int32_free(sa); + opj_aligned_free(h.wavelet); + return OPJ_FALSE; + } + } + + v.win_l_x0 = win_ll_y0; + v.win_l_x1 = win_ll_y1; + v.win_h_x0 = win_lh_y0; + v.win_h_x1 = win_lh_y1; + for (j = win_tr_x0; j < win_tr_x1; j += 4) { + OPJ_UINT32 nb_elts = opj_uint_min(4U, win_tr_x1 - j); + + opj_v4dwt_interleave_partial_v(&v, sa, j, nb_elts); + opj_v4dwt_decode(&v); + + if (!opj_sparse_array_int32_write(sa, + j, win_tr_y0, + j + nb_elts, win_tr_y1, + (OPJ_INT32*)&h.wavelet[win_tr_y0].f[0], + 1, 4, OPJ_TRUE)) { + /* FIXME event manager error callback */ + opj_sparse_array_int32_free(sa); + opj_aligned_free(h.wavelet); + return OPJ_FALSE; } } } + { + OPJ_BOOL ret = opj_sparse_array_int32_read(sa, + tr_max->win_x0 - (OPJ_UINT32)tr_max->x0, + tr_max->win_y0 - (OPJ_UINT32)tr_max->y0, + tr_max->win_x1 - (OPJ_UINT32)tr_max->x0, + tr_max->win_y1 - (OPJ_UINT32)tr_max->y0, + tilec->data_win, + 1, tr_max->win_x1 - tr_max->win_x0, + OPJ_TRUE); + assert(ret); + OPJ_UNUSED(ret); + } + opj_sparse_array_int32_free(sa); + opj_aligned_free(h.wavelet); return OPJ_TRUE; } + + +OPJ_BOOL opj_dwt_decode_real(opj_tcd_t *p_tcd, + opj_tcd_tilecomp_t* OPJ_RESTRICT tilec, + OPJ_UINT32 numres) +{ + if (p_tcd->whole_tile_decoding) { + return opj_dwt_decode_tile_97(tilec, numres); + } else { + return opj_dwt_decode_partial_97(tilec, numres); + } +} diff --git a/openjpeg/src/lib/openjp2/dwt.h b/openjpeg/src/lib/openjp2/dwt.h index 3c997efd4..4f63e524a 100644 --- a/openjpeg/src/lib/openjp2/dwt.h +++ b/openjpeg/src/lib/openjp2/dwt.h @@ -63,11 +63,12 @@ OPJ_BOOL opj_dwt_encode(opj_tcd_tilecomp_t * tilec); /** Inverse 5-3 wavelet transform in 2-D. Apply a reversible inverse DWT transform to a component of an image. -@param tp Thread pool +@param p_tcd TCD handle @param tilec Tile component information (current tile) @param numres Number of resolution levels to decode */ -OPJ_BOOL opj_dwt_decode(opj_thread_pool_t* tp, opj_tcd_tilecomp_t* tilec, +OPJ_BOOL opj_dwt_decode(opj_tcd_t *p_tcd, + opj_tcd_tilecomp_t* tilec, OPJ_UINT32 numres); /** @@ -92,10 +93,12 @@ OPJ_BOOL opj_dwt_encode_real(opj_tcd_tilecomp_t * tilec); /** Inverse 9-7 wavelet transform in 2-D. Apply an irreversible inverse DWT transform to a component of an image. +@param p_tcd TCD handle @param tilec Tile component information (current tile) @param numres Number of resolution levels to decode */ -OPJ_BOOL opj_dwt_decode_real(opj_tcd_tilecomp_t* OPJ_RESTRICT tilec, +OPJ_BOOL opj_dwt_decode_real(opj_tcd_t *p_tcd, + opj_tcd_tilecomp_t* OPJ_RESTRICT tilec, OPJ_UINT32 numres); /** diff --git a/openjpeg/src/lib/openjp2/image.c b/openjpeg/src/lib/openjp2/image.c index e29172b2b..13bcb8e45 100644 --- a/openjpeg/src/lib/openjp2/image.c +++ b/openjpeg/src/lib/openjp2/image.c @@ -70,7 +70,7 @@ opj_image_t* OPJ_CALLCONV opj_image_create(OPJ_UINT32 numcmpts, comp->sgnd = cmptparms[compno].sgnd; if (comp->h != 0 && (OPJ_SIZE_T)comp->w > SIZE_MAX / comp->h / sizeof(OPJ_INT32)) { - // TODO event manager + /* TODO event manager */ opj_image_destroy(image); return NULL; } @@ -180,7 +180,7 @@ void opj_copy_image_header(const opj_image_t* p_image_src, for (compno = 0; compno < p_image_dest->numcomps; compno++) { opj_image_comp_t *image_comp = &(p_image_dest->comps[compno]); if (image_comp->data) { - opj_free(image_comp->data); + opj_image_data_free(image_comp->data); } } opj_free(p_image_dest->comps); diff --git a/openjpeg/src/lib/openjp2/j2k.c b/openjpeg/src/lib/openjp2/j2k.c index a725c6a7b..07b92d081 100644 --- a/openjpeg/src/lib/openjp2/j2k.c +++ b/openjpeg/src/lib/openjp2/j2k.c @@ -16,6 +16,7 @@ * Copyright (c) 2010-2011, Kaori Hagihara * Copyright (c) 2011-2012, Centre National d'Etudes Spatiales (CNES), France * Copyright (c) 2012, CS Systemes d'Information, France + * Copyright (c) 2017, IntoPIX SA <support@intopix.com> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -48,8 +49,6 @@ /** @name Local static functions */ /*@{*/ -#define OPJ_UNUSED(x) (void)x - /** * Sets up the procedures to do on reading header. Developpers wanting to extend the library can add their own reading procedures. */ @@ -137,7 +136,7 @@ static OPJ_BOOL opj_j2k_build_encoder(opj_j2k_t * p_j2k, opj_event_mgr_t * p_manager); /** - * Creates a tile-coder decoder. + * Creates a tile-coder encoder. * * @param p_stream the stream to write data to. * @param p_j2k J2K codec. @@ -370,7 +369,7 @@ static OPJ_BOOL opj_j2k_pre_write_tile(opj_j2k_t * p_j2k, opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager); -static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd, OPJ_BYTE * p_data, +static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd, opj_image_t* p_output_image); static void opj_get_tile_dimensions(opj_image_t * l_image, @@ -832,13 +831,15 @@ static OPJ_BOOL opj_j2k_write_tlm(opj_j2k_t *p_j2k, * Writes the SOT marker (Start of tile-part) * * @param p_j2k J2K codec. - * @param p_data FIXME DOC - * @param p_data_written FIXME DOC + * @param p_data Output buffer + * @param p_total_data_size Output buffer size + * @param p_data_written Number of bytes written into stream * @param p_stream the stream to write data to. * @param p_manager the user event manager. */ static OPJ_BOOL opj_j2k_write_sot(opj_j2k_t *p_j2k, OPJ_BYTE * p_data, + OPJ_UINT32 p_total_data_size, OPJ_UINT32 * p_data_written, const opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager); @@ -1305,7 +1306,7 @@ typedef struct j2k_prog_order { char str_prog[5]; } j2k_prog_order_t; -static j2k_prog_order_t j2k_prog_order_list[] = { +static const j2k_prog_order_t j2k_prog_order_list[] = { {OPJ_CPRL, "CPRL"}, {OPJ_LRCP, "LRCP"}, {OPJ_PCRL, "PCRL"}, @@ -1602,9 +1603,9 @@ static void opj_j2k_write_float_to_float64(const void * p_src_data, } } -char *opj_j2k_convert_progression_order(OPJ_PROG_ORDER prg_order) +const char *opj_j2k_convert_progression_order(OPJ_PROG_ORDER prg_order) { - j2k_prog_order_t *po; + const j2k_prog_order_t *po; for (po = j2k_prog_order_list; po->enum_prog != -1; po++) { if (po->enum_prog == prg_order) { return po->str_prog; @@ -2141,13 +2142,6 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k, return OPJ_FALSE; } - /* testcase 1610.pdf.SIGSEGV.59c.681 */ - if ((0xFFFFFFFFU / l_image->x1) < l_image->y1) { - opj_event_msg(p_manager, EVT_ERROR, - "Prevent buffer overflow (x1: %d, y1: %d)\n", l_image->x1, l_image->y1); - return OPJ_FALSE; - } - /* testcase issue427-illegal-tile-offset.jp2 */ l_tx1 = opj_uint_adds(l_cp->tx0, l_cp->tdx); /* manage overflow */ l_ty1 = opj_uint_adds(l_cp->ty0, l_cp->tdy); /* manage overflow */ @@ -3512,7 +3506,6 @@ static OPJ_BOOL opj_j2k_read_poc(opj_j2k_t *p_j2k, opj_event_msg(p_manager, EVT_ERROR, "Too many POCs %d\n", l_current_poc_nb); return OPJ_FALSE; } - assert(l_current_poc_nb < 32); /* now poc is in use.*/ l_tcp->POC = 1; @@ -4201,6 +4194,7 @@ static OPJ_BOOL opj_j2k_write_tlm(opj_j2k_t *p_j2k, static OPJ_BOOL opj_j2k_write_sot(opj_j2k_t *p_j2k, OPJ_BYTE * p_data, + OPJ_UINT32 p_total_data_size, OPJ_UINT32 * p_data_written, const opj_stream_private_t *p_stream, opj_event_mgr_t * p_manager @@ -4212,7 +4206,12 @@ static OPJ_BOOL opj_j2k_write_sot(opj_j2k_t *p_j2k, assert(p_stream != 00); OPJ_UNUSED(p_stream); - OPJ_UNUSED(p_manager); + + if (p_total_data_size < 12) { + opj_event_msg(p_manager, EVT_ERROR, + "Not enough bytes in output buffer to write SOT marker\n"); + return OPJ_FALSE; + } opj_write_bytes(p_data, J2K_MS_SOT, 2); /* SOT */ @@ -4304,6 +4303,10 @@ static OPJ_BOOL opj_j2k_read_sot(opj_j2k_t *p_j2k, opj_event_msg(p_manager, EVT_ERROR, "Error reading SOT marker\n"); return OPJ_FALSE; } +#ifdef DEBUG_VERBOSE + fprintf(stderr, "SOT %d %d %d %d\n", + p_j2k->m_current_tile_number, l_tot_len, l_current_part, l_num_parts); +#endif l_cp = &(p_j2k->m_cp); @@ -4318,23 +4321,31 @@ static OPJ_BOOL opj_j2k_read_sot(opj_j2k_t *p_j2k, l_tile_x = p_j2k->m_current_tile_number % l_cp->tw; l_tile_y = p_j2k->m_current_tile_number / l_cp->tw; - /* Fixes issue with id_000020,sig_06,src_001958,op_flip4,pos_149 */ - /* of https://github.com/uclouvain/openjpeg/issues/939 */ - /* We must avoid reading twice the same tile part number for a given tile */ - /* so as to avoid various issues, like opj_j2k_merge_ppt being called */ - /* several times. */ - /* ISO 15444-1 A.4.2 Start of tile-part (SOT) mandates that tile parts */ - /* should appear in increasing order. */ - if (l_tcp->m_current_tile_part_number + 1 != (OPJ_INT32)l_current_part) { - opj_event_msg(p_manager, EVT_ERROR, - "Invalid tile part index for tile number %d. " - "Got %d, expected %d\n", - p_j2k->m_current_tile_number, - l_current_part, - l_tcp->m_current_tile_part_number + 1); - return OPJ_FALSE; + if (p_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec < 0 || + p_j2k->m_current_tile_number == (OPJ_UINT32) + p_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec) { + /* Do only this check if we decode all tile part headers, or if */ + /* we decode one precise tile. Otherwise the m_current_tile_part_number */ + /* might not be valid */ + /* Fixes issue with id_000020,sig_06,src_001958,op_flip4,pos_149 */ + /* of https://github.com/uclouvain/openjpeg/issues/939 */ + /* We must avoid reading twice the same tile part number for a given tile */ + /* so as to avoid various issues, like opj_j2k_merge_ppt being called */ + /* several times. */ + /* ISO 15444-1 A.4.2 Start of tile-part (SOT) mandates that tile parts */ + /* should appear in increasing order. */ + if (l_tcp->m_current_tile_part_number + 1 != (OPJ_INT32)l_current_part) { + opj_event_msg(p_manager, EVT_ERROR, + "Invalid tile part index for tile number %d. " + "Got %d, expected %d\n", + p_j2k->m_current_tile_number, + l_current_part, + l_tcp->m_current_tile_part_number + 1); + return OPJ_FALSE; + } } - ++ l_tcp->m_current_tile_part_number; + + l_tcp->m_current_tile_part_number = (OPJ_INT32) l_current_part; #ifdef USE_JPWL if (l_cp->correct) { @@ -4608,6 +4619,12 @@ static OPJ_BOOL opj_j2k_write_sod(opj_j2k_t *p_j2k, OPJ_UNUSED(p_stream); + if (p_total_data_size < 4) { + opj_event_msg(p_manager, EVT_ERROR, + "Not enough bytes in output buffer to write SOD marker\n"); + return OPJ_FALSE; + } + opj_write_bytes(p_data, J2K_MS_SOD, 2); /* SOD */ p_data += 2; @@ -4651,15 +4668,18 @@ static OPJ_BOOL opj_j2k_write_sod(opj_j2k_t *p_j2k, if (p_j2k->m_specific_param.m_encoder.m_current_tile_part_number == 0) { p_tile_coder->tcd_image->tiles->packno = 0; +#ifdef deadcode if (l_cstr_info) { l_cstr_info->packno = 0; } +#endif } *p_data_written = 0; if (! opj_tcd_encode_tile(p_tile_coder, p_j2k->m_current_tile_number, p_data, - p_data_written, l_remaining_data, l_cstr_info)) { + p_data_written, l_remaining_data, l_cstr_info, + p_manager)) { opj_event_msg(p_manager, EVT_ERROR, "Cannot encode tile\n"); return OPJ_FALSE; } @@ -5147,7 +5167,17 @@ static OPJ_BOOL opj_j2k_update_rates(opj_j2k_t *p_j2k, ++l_img_comp; } - l_tile_size = (OPJ_UINT32)(l_tile_size * 0.1625); /* 1.3/8 = 0.1625 */ + /* TODO: where does this magic value come from ? */ + /* This used to be 1.3 / 8, but with random data and very small code */ + /* block sizes, this is not enough. For example with */ + /* bin/test_tile_encoder 1 256 256 32 32 8 0 reversible_with_precinct.j2k 4 4 3 0 0 1 16 16 */ + /* TODO revise this to take into account the overhead linked to the */ + /* number of packets and number of code blocks in packets */ + l_tile_size = (OPJ_UINT32)(l_tile_size * 1.4 / 8); + + /* Arbitrary amount to make the following work: */ + /* bin/test_tile_encoder 1 256 256 17 16 8 0 reversible_no_precinct.j2k 4 4 3 0 0 1 */ + l_tile_size += 500; l_tile_size += opj_j2k_get_specific_header_sizes(p_j2k); @@ -6407,15 +6437,27 @@ OPJ_BOOL opj_j2k_set_threads(opj_j2k_t *j2k, OPJ_UINT32 num_threads) static int opj_j2k_get_default_thread_count(void) { #if defined(MUTEX_win32) || defined(MUTEX_pthread) - const char* num_threads = getenv("OPJ_NUM_THREADS"); - if (num_threads == NULL || !opj_has_thread_support()) { + const char* num_threads_str = getenv("OPJ_NUM_THREADS"); + int num_cpus; + int num_threads; + + if (num_threads_str == NULL || !opj_has_thread_support()) { return 0; } - if (strcmp(num_threads, "ALL_CPUS") == 0) { - return opj_get_num_cpus(); + num_cpus = opj_get_num_cpus(); + if (strcmp(num_threads_str, "ALL_CPUS") == 0) { + return num_cpus; } - return atoi(num_threads); - + if (num_cpus == 0) { + num_cpus = 32; + } + num_threads = atoi(num_threads_str); + if (num_threads < 0) { + num_threads = 0; + } else if (num_threads > 2 * num_cpus) { + num_threads = 2 * num_cpus; + } + return num_threads; #else return 0; #endif @@ -6577,10 +6619,16 @@ static void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, /* Precincts */ parameters->csty |= 0x01; - parameters->res_spec = parameters->numresolution - 1; - for (i = 0; i < parameters->res_spec; i++) { - parameters->prcw_init[i] = 256; - parameters->prch_init[i] = 256; + if (parameters->numresolution == 1) { + parameters->res_spec = 1; + parameters->prcw_init[0] = 128; + parameters->prch_init[0] = 128; + } else { + parameters->res_spec = parameters->numresolution - 1; + for (i = 0; i < parameters->res_spec; i++) { + parameters->prcw_init[i] = 256; + parameters->prch_init[i] = 256; + } } /* The progression order shall be CPRL */ @@ -6703,6 +6751,7 @@ OPJ_BOOL opj_j2k_setup_encoder(opj_j2k_t *p_j2k, { OPJ_UINT32 i, j, tileno, numpocs_tile; opj_cp_t *cp = 00; + OPJ_UINT32 cblkw, cblkh; if (!p_j2k || !parameters || ! image) { return OPJ_FALSE; @@ -6716,6 +6765,38 @@ OPJ_BOOL opj_j2k_setup_encoder(opj_j2k_t *p_j2k, return OPJ_FALSE; } + if (parameters->cblockw_init < 4 || parameters->cblockw_init > 1024) { + opj_event_msg(p_manager, EVT_ERROR, + "Invalid value for cblockw_init: %d not a power of 2 in range [4,1024]\n", + parameters->cblockw_init); + return OPJ_FALSE; + } + if (parameters->cblockh_init < 4 || parameters->cblockh_init > 1024) { + opj_event_msg(p_manager, EVT_ERROR, + "Invalid value for cblockh_init: %d not a power of 2 not in range [4,1024]\n", + parameters->cblockh_init); + return OPJ_FALSE; + } + if (parameters->cblockw_init * parameters->cblockh_init > 4096) { + opj_event_msg(p_manager, EVT_ERROR, + "Invalid value for cblockw_init * cblockh_init: should be <= 4096\n"); + return OPJ_FALSE; + } + cblkw = (OPJ_UINT32)opj_int_floorlog2(parameters->cblockw_init); + cblkh = (OPJ_UINT32)opj_int_floorlog2(parameters->cblockh_init); + if (parameters->cblockw_init != (1 << cblkw)) { + opj_event_msg(p_manager, EVT_ERROR, + "Invalid value for cblockw_init: %d not a power of 2 in range [4,1024]\n", + parameters->cblockw_init); + return OPJ_FALSE; + } + if (parameters->cblockh_init != (1 << cblkh)) { + opj_event_msg(p_manager, EVT_ERROR, + "Invalid value for cblockw_init: %d not a power of 2 in range [4,1024]\n", + parameters->cblockh_init); + return OPJ_FALSE; + } + /* keep a link to cp so that we can destroy it later in j2k_destroy_compress */ cp = &(p_j2k->m_cp); @@ -6774,25 +6855,91 @@ OPJ_BOOL opj_j2k_setup_encoder(opj_j2k_t *p_j2k, } } + /* If no explicit layers are provided, use lossless settings */ + if (parameters->tcp_numlayers == 0) { + parameters->tcp_numlayers = 1; + parameters->cp_disto_alloc = 1; + parameters->tcp_rates[0] = 0; + } + + if (parameters->cp_disto_alloc) { + /* Emit warnings if tcp_rates are not decreasing */ + for (i = 1; i < (OPJ_UINT32) parameters->tcp_numlayers; i++) { + OPJ_FLOAT32 rate_i_corr = parameters->tcp_rates[i]; + OPJ_FLOAT32 rate_i_m_1_corr = parameters->tcp_rates[i - 1]; + if (rate_i_corr <= 1.0) { + rate_i_corr = 1.0; + } + if (rate_i_m_1_corr <= 1.0) { + rate_i_m_1_corr = 1.0; + } + if (rate_i_corr >= rate_i_m_1_corr) { + if (rate_i_corr != parameters->tcp_rates[i] && + rate_i_m_1_corr != parameters->tcp_rates[i - 1]) { + opj_event_msg(p_manager, EVT_WARNING, + "tcp_rates[%d]=%f (corrected as %f) should be strictly lesser " + "than tcp_rates[%d]=%f (corrected as %f)\n", + i, parameters->tcp_rates[i], rate_i_corr, + i - 1, parameters->tcp_rates[i - 1], rate_i_m_1_corr); + } else if (rate_i_corr != parameters->tcp_rates[i]) { + opj_event_msg(p_manager, EVT_WARNING, + "tcp_rates[%d]=%f (corrected as %f) should be strictly lesser " + "than tcp_rates[%d]=%f\n", + i, parameters->tcp_rates[i], rate_i_corr, + i - 1, parameters->tcp_rates[i - 1]); + } else if (rate_i_m_1_corr != parameters->tcp_rates[i - 1]) { + opj_event_msg(p_manager, EVT_WARNING, + "tcp_rates[%d]=%f should be strictly lesser " + "than tcp_rates[%d]=%f (corrected as %f)\n", + i, parameters->tcp_rates[i], + i - 1, parameters->tcp_rates[i - 1], rate_i_m_1_corr); + } else { + opj_event_msg(p_manager, EVT_WARNING, + "tcp_rates[%d]=%f should be strictly lesser " + "than tcp_rates[%d]=%f\n", + i, parameters->tcp_rates[i], + i - 1, parameters->tcp_rates[i - 1]); + } + } + } + } else if (parameters->cp_fixed_quality) { + /* Emit warnings if tcp_distoratio are not increasing */ + for (i = 1; i < (OPJ_UINT32) parameters->tcp_numlayers; i++) { + if (parameters->tcp_distoratio[i] < parameters->tcp_distoratio[i - 1] && + !(i == (OPJ_UINT32)parameters->tcp_numlayers - 1 && + parameters->tcp_distoratio[i] == 0)) { + opj_event_msg(p_manager, EVT_WARNING, + "tcp_distoratio[%d]=%f should be strictly greater " + "than tcp_distoratio[%d]=%f\n", + i, parameters->tcp_distoratio[i], i - 1, + parameters->tcp_distoratio[i - 1]); + } + } + } + /* see if max_codestream_size does limit input rate */ if (parameters->max_cs_size <= 0) { if (parameters->tcp_rates[parameters->tcp_numlayers - 1] > 0) { OPJ_FLOAT32 temp_size; - temp_size = (OPJ_FLOAT32)(image->numcomps * image->comps[0].w * - image->comps[0].h * image->comps[0].prec) / - (parameters->tcp_rates[parameters->tcp_numlayers - 1] * 8 * - (OPJ_FLOAT32)image->comps[0].dx * (OPJ_FLOAT32)image->comps[0].dy); - parameters->max_cs_size = (int) floor(temp_size); + temp_size = (OPJ_FLOAT32)(((double)image->numcomps * image->comps[0].w * + image->comps[0].h * image->comps[0].prec) / + ((double)parameters->tcp_rates[parameters->tcp_numlayers - 1] * 8 * + image->comps[0].dx * image->comps[0].dy)); + if (temp_size > INT_MAX) { + parameters->max_cs_size = INT_MAX; + } else { + parameters->max_cs_size = (int) floor(temp_size); + } } else { parameters->max_cs_size = 0; } } else { OPJ_FLOAT32 temp_rate; OPJ_BOOL cap = OPJ_FALSE; - temp_rate = (OPJ_FLOAT32)(image->numcomps * image->comps[0].w * - image->comps[0].h * image->comps[0].prec) / - (OPJ_FLOAT32)(((OPJ_UINT32)parameters->max_cs_size) * 8 * image->comps[0].dx * - image->comps[0].dy); + temp_rate = (OPJ_FLOAT32)(((double)image->numcomps * image->comps[0].w * + image->comps[0].h * image->comps[0].prec) / + (((double)parameters->max_cs_size) * 8 * image->comps[0].dx * + image->comps[0].dy)); for (i = 0; i < (OPJ_UINT32) parameters->tcp_numlayers; i++) { if (parameters->tcp_rates[i] < temp_rate) { parameters->tcp_rates[i] = temp_rate; @@ -7026,6 +7173,10 @@ OPJ_BOOL opj_j2k_setup_encoder(opj_j2k_t *p_j2k, tcp->rates[j] = parameters->tcp_rates[j]; } } + if (!cp->m_specific_param.m_enc.m_fixed_quality && + tcp->rates[j] <= 1.0) { + tcp->rates[j] = 0.0; /* force lossless */ + } } tcp->csty = (OPJ_UINT32)parameters->csty; @@ -8087,7 +8238,7 @@ static OPJ_BOOL opj_j2k_copy_default_tcp_and_create_tcd(opj_j2k_t * p_j2k, } /* Create the current tile decoder*/ - p_j2k->m_tcd = (opj_tcd_t*)opj_tcd_create(OPJ_TRUE); /* FIXME why a cast ? */ + p_j2k->m_tcd = opj_tcd_create(OPJ_TRUE); if (! p_j2k->m_tcd) { return OPJ_FALSE; } @@ -8133,6 +8284,11 @@ void opj_j2k_destroy(opj_j2k_t *p_j2k) p_j2k->m_specific_param.m_decoder.m_header_data = 00; p_j2k->m_specific_param.m_decoder.m_header_data_size = 0; } + + opj_free(p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode); + p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode = 00; + p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode = 0; + } else { if (p_j2k->m_specific_param.m_encoder.m_encoded_tile_data) { @@ -8418,7 +8574,7 @@ static OPJ_BOOL opj_j2k_need_nb_tile_parts_correction(opj_stream_private_t break; } - if ((l_tot_len == 0U) || (l_tot_len < 14U)) { + if (l_tot_len < 14U) { /* last SOT until EOC or invalid Psot value */ /* assume all is OK */ if (! opj_stream_seek(p_stream, l_stream_pos_backup, p_manager)) { @@ -8722,9 +8878,13 @@ OPJ_BOOL opj_j2k_read_tile_header(opj_j2k_t * p_j2k, *p_tile_index = p_j2k->m_current_tile_number; *p_go_on = OPJ_TRUE; - *p_data_size = opj_tcd_get_decoded_tile_size(p_j2k->m_tcd); - if (*p_data_size == UINT_MAX) { - return OPJ_FALSE; + if (p_data_size) { + /* For internal use in j2k.c, we don't need this */ + /* This is just needed for folks using the opj_read_tile_header() / opj_decode_tile_data() combo */ + *p_data_size = opj_tcd_get_decoded_tile_size(p_j2k->m_tcd, OPJ_FALSE); + if (*p_data_size == UINT_MAX) { + return OPJ_FALSE; + } } *p_tile_x0 = p_j2k->m_tcd->tcd_image->tiles->x0; *p_tile_y0 = p_j2k->m_tcd->tcd_image->tiles->y0; @@ -8747,6 +8907,7 @@ OPJ_BOOL opj_j2k_decode_tile(opj_j2k_t * p_j2k, OPJ_UINT32 l_current_marker; OPJ_BYTE l_data [2]; opj_tcp_t * l_tcp; + opj_image_t* l_image_for_bounds; /* preconditions */ assert(p_stream != 00); @@ -8764,7 +8925,20 @@ OPJ_BOOL opj_j2k_decode_tile(opj_j2k_t * p_j2k, return OPJ_FALSE; } + /* When using the opj_read_tile_header / opj_decode_tile_data API */ + /* such as in test_tile_decoder, m_output_image is NULL, so fall back */ + /* to the full image dimension. This is a bit surprising that */ + /* opj_set_decode_area() is only used to determinte intersecting tiles, */ + /* but full tile decoding is done */ + l_image_for_bounds = p_j2k->m_output_image ? p_j2k->m_output_image : + p_j2k->m_private_image; if (! opj_tcd_decode_tile(p_j2k->m_tcd, + l_image_for_bounds->x0, + l_image_for_bounds->y0, + l_image_for_bounds->x1, + l_image_for_bounds->y1, + p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode, + p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode, l_tcp->m_data, l_tcp->m_data_size, p_tile_index, @@ -8823,26 +8997,24 @@ OPJ_BOOL opj_j2k_decode_tile(opj_j2k_t * p_j2k, return OPJ_TRUE; } -static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd, OPJ_BYTE * p_data, +static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd, opj_image_t* p_output_image) { - OPJ_UINT32 i, j, k = 0; + OPJ_UINT32 i, j; OPJ_UINT32 l_width_src, l_height_src; OPJ_UINT32 l_width_dest, l_height_dest; OPJ_INT32 l_offset_x0_src, l_offset_y0_src, l_offset_x1_src, l_offset_y1_src; - OPJ_SIZE_T l_start_offset_src, l_line_offset_src, l_end_offset_src ; + OPJ_SIZE_T l_start_offset_src; OPJ_UINT32 l_start_x_dest, l_start_y_dest; OPJ_UINT32 l_x0_dest, l_y0_dest, l_x1_dest, l_y1_dest; - OPJ_SIZE_T l_start_offset_dest, l_line_offset_dest; + OPJ_SIZE_T l_start_offset_dest; opj_image_comp_t * l_img_comp_src = 00; opj_image_comp_t * l_img_comp_dest = 00; opj_tcd_tilecomp_t * l_tilec = 00; opj_image_t * l_image_src = 00; - OPJ_UINT32 l_size_comp, l_remaining; OPJ_INT32 * l_dest_ptr; - opj_tcd_resolution_t* l_res = 00; l_tilec = p_tcd->tcd_image->tiles->comps; l_image_src = p_tcd->image; @@ -8850,53 +9022,52 @@ static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd, OPJ_BYTE * p_data, l_img_comp_dest = p_output_image->comps; - for (i = 0; i < l_image_src->numcomps; i++) { - - /* Allocate output component buffer if necessary */ - if (!l_img_comp_dest->data) { - OPJ_SIZE_T l_width = l_img_comp_dest->w; - OPJ_SIZE_T l_height = l_img_comp_dest->h; - - if ((l_height == 0U) || (l_width > (SIZE_MAX / l_height)) || - l_width * l_height > SIZE_MAX / sizeof(OPJ_INT32)) { - /* would overflow */ - return OPJ_FALSE; - } - l_img_comp_dest->data = (OPJ_INT32*) opj_image_data_alloc(l_width * l_height * - sizeof(OPJ_INT32)); - if (! l_img_comp_dest->data) { - return OPJ_FALSE; - } - /* Do we really need this memset ? */ - memset(l_img_comp_dest->data, 0, l_width * l_height * sizeof(OPJ_INT32)); - } + for (i = 0; i < l_image_src->numcomps; + i++, ++l_img_comp_dest, ++l_img_comp_src, ++l_tilec) { + OPJ_INT32 res_x0, res_x1, res_y0, res_y1; + OPJ_UINT32 src_data_stride; + const OPJ_INT32* p_src_data; /* Copy info from decoded comp image to output image */ l_img_comp_dest->resno_decoded = l_img_comp_src->resno_decoded; - /*-----*/ - /* Compute the precision of the output buffer */ - l_size_comp = l_img_comp_src->prec >> 3; /*(/ 8)*/ - l_remaining = l_img_comp_src->prec & 7; /* (%8) */ - l_res = l_tilec->resolutions + l_img_comp_src->resno_decoded; - - if (l_remaining) { - ++l_size_comp; + if (p_tcd->whole_tile_decoding) { + opj_tcd_resolution_t* l_res = l_tilec->resolutions + + l_img_comp_src->resno_decoded; + res_x0 = l_res->x0; + res_y0 = l_res->y0; + res_x1 = l_res->x1; + res_y1 = l_res->y1; + src_data_stride = (OPJ_UINT32)( + l_tilec->resolutions[l_tilec->minimum_num_resolutions - 1].x1 - + l_tilec->resolutions[l_tilec->minimum_num_resolutions - 1].x0); + p_src_data = l_tilec->data; + } else { + opj_tcd_resolution_t* l_res = l_tilec->resolutions + + l_img_comp_src->resno_decoded; + res_x0 = (OPJ_INT32)l_res->win_x0; + res_y0 = (OPJ_INT32)l_res->win_y0; + res_x1 = (OPJ_INT32)l_res->win_x1; + res_y1 = (OPJ_INT32)l_res->win_y1; + src_data_stride = l_res->win_x1 - l_res->win_x0; + p_src_data = l_tilec->data_win; } - if (l_size_comp == 3) { - l_size_comp = 4; + if (p_src_data == NULL) { + /* Happens for partial component decoding */ + continue; } - /*-----*/ + + l_width_src = (OPJ_UINT32)(res_x1 - res_x0); + l_height_src = (OPJ_UINT32)(res_y1 - res_y0); + /* Current tile component size*/ /*if (i == 0) { fprintf(stdout, "SRC: l_res_x0=%d, l_res_x1=%d, l_res_y0=%d, l_res_y1=%d\n", - l_res->x0, l_res->x1, l_res->y0, l_res->y1); + res_x0, res_x1, res_y0, res_y1); }*/ - l_width_src = (OPJ_UINT32)(l_res->x1 - l_res->x0); - l_height_src = (OPJ_UINT32)(l_res->y1 - l_res->y0); /* Border of the current output component*/ l_x0_dest = opj_uint_ceildivpow2(l_img_comp_dest->x0, l_img_comp_dest->factor); @@ -8917,53 +9088,53 @@ static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd, OPJ_BYTE * p_data, * l_start_y_dest, l_width_dest, l_height_dest) which will be modified * by this input area. * */ - assert(l_res->x0 >= 0); - assert(l_res->x1 >= 0); - if (l_x0_dest < (OPJ_UINT32)l_res->x0) { - l_start_x_dest = (OPJ_UINT32)l_res->x0 - l_x0_dest; + assert(res_x0 >= 0); + assert(res_x1 >= 0); + if (l_x0_dest < (OPJ_UINT32)res_x0) { + l_start_x_dest = (OPJ_UINT32)res_x0 - l_x0_dest; l_offset_x0_src = 0; - if (l_x1_dest >= (OPJ_UINT32)l_res->x1) { + if (l_x1_dest >= (OPJ_UINT32)res_x1) { l_width_dest = l_width_src; l_offset_x1_src = 0; } else { - l_width_dest = l_x1_dest - (OPJ_UINT32)l_res->x0 ; + l_width_dest = l_x1_dest - (OPJ_UINT32)res_x0 ; l_offset_x1_src = (OPJ_INT32)(l_width_src - l_width_dest); } } else { l_start_x_dest = 0U; - l_offset_x0_src = (OPJ_INT32)l_x0_dest - l_res->x0; + l_offset_x0_src = (OPJ_INT32)l_x0_dest - res_x0; - if (l_x1_dest >= (OPJ_UINT32)l_res->x1) { + if (l_x1_dest >= (OPJ_UINT32)res_x1) { l_width_dest = l_width_src - (OPJ_UINT32)l_offset_x0_src; l_offset_x1_src = 0; } else { l_width_dest = l_img_comp_dest->w ; - l_offset_x1_src = l_res->x1 - (OPJ_INT32)l_x1_dest; + l_offset_x1_src = res_x1 - (OPJ_INT32)l_x1_dest; } } - if (l_y0_dest < (OPJ_UINT32)l_res->y0) { - l_start_y_dest = (OPJ_UINT32)l_res->y0 - l_y0_dest; + if (l_y0_dest < (OPJ_UINT32)res_y0) { + l_start_y_dest = (OPJ_UINT32)res_y0 - l_y0_dest; l_offset_y0_src = 0; - if (l_y1_dest >= (OPJ_UINT32)l_res->y1) { + if (l_y1_dest >= (OPJ_UINT32)res_y1) { l_height_dest = l_height_src; l_offset_y1_src = 0; } else { - l_height_dest = l_y1_dest - (OPJ_UINT32)l_res->y0 ; + l_height_dest = l_y1_dest - (OPJ_UINT32)res_y0 ; l_offset_y1_src = (OPJ_INT32)(l_height_src - l_height_dest); } } else { l_start_y_dest = 0U; - l_offset_y0_src = (OPJ_INT32)l_y0_dest - l_res->y0; + l_offset_y0_src = (OPJ_INT32)l_y0_dest - res_y0; - if (l_y1_dest >= (OPJ_UINT32)l_res->y1) { + if (l_y1_dest >= (OPJ_UINT32)res_y1) { l_height_dest = l_height_src - (OPJ_UINT32)l_offset_y0_src; l_offset_y1_src = 0; } else { l_height_dest = l_img_comp_dest->h ; - l_offset_y1_src = l_res->y1 - (OPJ_INT32)l_y1_dest; + l_offset_y1_src = res_y1 - (OPJ_INT32)l_y1_dest; } } @@ -8979,124 +9150,174 @@ static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd, OPJ_BYTE * p_data, /* Compute the input buffer offset */ l_start_offset_src = (OPJ_SIZE_T)l_offset_x0_src + (OPJ_SIZE_T)l_offset_y0_src - * (OPJ_SIZE_T)l_width_src; - l_line_offset_src = (OPJ_SIZE_T)l_offset_x1_src + (OPJ_SIZE_T)l_offset_x0_src; - l_end_offset_src = (OPJ_SIZE_T)l_offset_y1_src * (OPJ_SIZE_T)l_width_src - - (OPJ_SIZE_T)l_offset_x0_src; + * (OPJ_SIZE_T)src_data_stride; /* Compute the output buffer offset */ l_start_offset_dest = (OPJ_SIZE_T)l_start_x_dest + (OPJ_SIZE_T)l_start_y_dest * (OPJ_SIZE_T)l_img_comp_dest->w; - l_line_offset_dest = (OPJ_SIZE_T)l_img_comp_dest->w - (OPJ_SIZE_T)l_width_dest; + + /* Allocate output component buffer if necessary */ + if (l_img_comp_dest->data == NULL && + l_start_offset_src == 0 && l_start_offset_dest == 0 && + src_data_stride == l_img_comp_dest->w && + l_width_dest == l_img_comp_dest->w && + l_height_dest == l_img_comp_dest->h) { + /* If the final image matches the tile buffer, then borrow it */ + /* directly to save a copy */ + if (p_tcd->whole_tile_decoding) { + l_img_comp_dest->data = l_tilec->data; + l_tilec->data = NULL; + } else { + l_img_comp_dest->data = l_tilec->data_win; + l_tilec->data_win = NULL; + } + continue; + } else if (l_img_comp_dest->data == NULL) { + OPJ_SIZE_T l_width = l_img_comp_dest->w; + OPJ_SIZE_T l_height = l_img_comp_dest->h; + + if ((l_height == 0U) || (l_width > (SIZE_MAX / l_height)) || + l_width * l_height > SIZE_MAX / sizeof(OPJ_INT32)) { + /* would overflow */ + return OPJ_FALSE; + } + l_img_comp_dest->data = (OPJ_INT32*) opj_image_data_alloc(l_width * l_height * + sizeof(OPJ_INT32)); + if (! l_img_comp_dest->data) { + return OPJ_FALSE; + } + + if (l_img_comp_dest->w != l_width_dest || + l_img_comp_dest->h != l_height_dest) { + memset(l_img_comp_dest->data, 0, + (OPJ_SIZE_T)l_img_comp_dest->w * l_img_comp_dest->h * sizeof(OPJ_INT32)); + } + } /* Move the output buffer to the first place where we will write*/ l_dest_ptr = l_img_comp_dest->data + l_start_offset_dest; - /*if (i == 0) { - fprintf(stdout, "COMPO[%d]:\n",i); - fprintf(stdout, "SRC: l_start_x_src=%d, l_start_y_src=%d, l_width_src=%d, l_height_src=%d\n" - "\t tile offset:%d, %d, %d, %d\n" - "\t buffer offset: %d; %d, %d\n", - l_res->x0, l_res->y0, l_width_src, l_height_src, - l_offset_x0_src, l_offset_y0_src, l_offset_x1_src, l_offset_y1_src, - l_start_offset_src, l_line_offset_src, l_end_offset_src); - - fprintf(stdout, "DEST: l_start_x_dest=%d, l_start_y_dest=%d, l_width_dest=%d, l_height_dest=%d\n" - "\t start offset: %d, line offset= %d\n", - l_start_x_dest, l_start_y_dest, l_width_dest, l_height_dest, l_start_offset_dest, l_line_offset_dest); - }*/ + { + const OPJ_INT32 * l_src_ptr = p_src_data; + l_src_ptr += l_start_offset_src; - switch (l_size_comp) { - case 1: { - OPJ_CHAR * l_src_ptr = (OPJ_CHAR*) p_data; - l_src_ptr += l_start_offset_src; /* Move to the first place where we will read*/ - - if (l_img_comp_src->sgnd) { - for (j = 0 ; j < l_height_dest ; ++j) { - for (k = 0 ; k < l_width_dest ; ++k) { - *(l_dest_ptr++) = (OPJ_INT32)(* - (l_src_ptr++)); /* Copy only the data needed for the output image */ - } + for (j = 0; j < l_height_dest; ++j) { + memcpy(l_dest_ptr, l_src_ptr, l_width_dest * sizeof(OPJ_INT32)); + l_dest_ptr += l_img_comp_dest->w; + l_src_ptr += src_data_stride; + } + } - l_dest_ptr += - l_line_offset_dest; /* Move to the next place where we will write */ - l_src_ptr += l_line_offset_src ; /* Move to the next place where we will read */ - } - } else { - for (j = 0 ; j < l_height_dest ; ++j) { - for (k = 0 ; k < l_width_dest ; ++k) { - *(l_dest_ptr++) = (OPJ_INT32)((*(l_src_ptr++)) & 0xff); - } - l_dest_ptr += l_line_offset_dest; - l_src_ptr += l_line_offset_src; - } - } + } - l_src_ptr += - l_end_offset_src; /* Move to the end of this component-part of the input buffer */ - p_data = (OPJ_BYTE*) - l_src_ptr; /* Keep the current position for the next component-part */ - } - break; - case 2: { - OPJ_INT16 * l_src_ptr = (OPJ_INT16 *) p_data; - l_src_ptr += l_start_offset_src; + return OPJ_TRUE; +} - if (l_img_comp_src->sgnd) { - for (j = 0; j < l_height_dest; ++j) { - for (k = 0; k < l_width_dest; ++k) { - OPJ_INT16 val; - memcpy(&val, l_src_ptr, sizeof(val)); - l_src_ptr ++; - *(l_dest_ptr++) = val; - } +static OPJ_BOOL opj_j2k_update_image_dimensions(opj_image_t* p_image, + opj_event_mgr_t * p_manager) +{ + OPJ_UINT32 it_comp; + OPJ_INT32 l_comp_x1, l_comp_y1; + opj_image_comp_t* l_img_comp = NULL; - l_dest_ptr += l_line_offset_dest; - l_src_ptr += l_line_offset_src ; - } - } else { - for (j = 0; j < l_height_dest; ++j) { - for (k = 0; k < l_width_dest; ++k) { - OPJ_INT16 val; - memcpy(&val, l_src_ptr, sizeof(val)); - l_src_ptr ++; - *(l_dest_ptr++) = val & 0xffff; - } + l_img_comp = p_image->comps; + for (it_comp = 0; it_comp < p_image->numcomps; ++it_comp) { + OPJ_INT32 l_h, l_w; - l_dest_ptr += l_line_offset_dest; - l_src_ptr += l_line_offset_src ; - } - } + l_img_comp->x0 = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)p_image->x0, + (OPJ_INT32)l_img_comp->dx); + l_img_comp->y0 = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)p_image->y0, + (OPJ_INT32)l_img_comp->dy); + l_comp_x1 = opj_int_ceildiv((OPJ_INT32)p_image->x1, (OPJ_INT32)l_img_comp->dx); + l_comp_y1 = opj_int_ceildiv((OPJ_INT32)p_image->y1, (OPJ_INT32)l_img_comp->dy); - l_src_ptr += l_end_offset_src; - p_data = (OPJ_BYTE*) l_src_ptr; + l_w = opj_int_ceildivpow2(l_comp_x1, (OPJ_INT32)l_img_comp->factor) + - opj_int_ceildivpow2((OPJ_INT32)l_img_comp->x0, (OPJ_INT32)l_img_comp->factor); + if (l_w < 0) { + opj_event_msg(p_manager, EVT_ERROR, + "Size x of the decoded component image is incorrect (comp[%d].w=%d).\n", + it_comp, l_w); + return OPJ_FALSE; } - break; - case 4: { - OPJ_INT32 * l_src_ptr = (OPJ_INT32 *) p_data; - l_src_ptr += l_start_offset_src; + l_img_comp->w = (OPJ_UINT32)l_w; - for (j = 0; j < l_height_dest; ++j) { - memcpy(l_dest_ptr, l_src_ptr, l_width_dest * sizeof(OPJ_INT32)); - l_dest_ptr += l_width_dest + l_line_offset_dest; - l_src_ptr += l_width_dest + l_line_offset_src ; - } + l_h = opj_int_ceildivpow2(l_comp_y1, (OPJ_INT32)l_img_comp->factor) + - opj_int_ceildivpow2((OPJ_INT32)l_img_comp->y0, (OPJ_INT32)l_img_comp->factor); + if (l_h < 0) { + opj_event_msg(p_manager, EVT_ERROR, + "Size y of the decoded component image is incorrect (comp[%d].h=%d).\n", + it_comp, l_h); + return OPJ_FALSE; + } + l_img_comp->h = (OPJ_UINT32)l_h; + + l_img_comp++; + } + + return OPJ_TRUE; +} - l_src_ptr += l_end_offset_src; - p_data = (OPJ_BYTE*) l_src_ptr; +OPJ_BOOL opj_j2k_set_decoded_components(opj_j2k_t *p_j2k, + OPJ_UINT32 numcomps, + const OPJ_UINT32* comps_indices, + opj_event_mgr_t * p_manager) +{ + OPJ_UINT32 i; + OPJ_BOOL* already_mapped; + + if (p_j2k->m_private_image == NULL) { + opj_event_msg(p_manager, EVT_ERROR, + "opj_read_header() should be called before " + "opj_set_decoded_components().\n"); + return OPJ_FALSE; + } + + already_mapped = (OPJ_BOOL*) opj_calloc(sizeof(OPJ_BOOL), + p_j2k->m_private_image->numcomps); + if (already_mapped == NULL) { + return OPJ_FALSE; + } + + for (i = 0; i < numcomps; i++) { + if (comps_indices[i] >= p_j2k->m_private_image->numcomps) { + opj_event_msg(p_manager, EVT_ERROR, + "Invalid component index: %u\n", + comps_indices[i]); + opj_free(already_mapped); + return OPJ_FALSE; } - break; + if (already_mapped[comps_indices[i]]) { + opj_event_msg(p_manager, EVT_ERROR, + "Component index %u used several times\n", + comps_indices[i]); + opj_free(already_mapped); + return OPJ_FALSE; } + already_mapped[comps_indices[i]] = OPJ_TRUE; + } + opj_free(already_mapped); - ++l_img_comp_dest; - ++l_img_comp_src; - ++l_tilec; + opj_free(p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode); + if (numcomps) { + p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode = + (OPJ_UINT32*) opj_malloc(numcomps * sizeof(OPJ_UINT32)); + if (p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode == NULL) { + p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode = 0; + return OPJ_FALSE; + } + memcpy(p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode, + comps_indices, + numcomps * sizeof(OPJ_UINT32)); + } else { + p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode = NULL; } + p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode = numcomps; return OPJ_TRUE; } + OPJ_BOOL opj_j2k_set_decode_area(opj_j2k_t *p_j2k, opj_image_t* p_image, OPJ_INT32 p_start_x, OPJ_INT32 p_start_y, @@ -9105,18 +9326,27 @@ OPJ_BOOL opj_j2k_set_decode_area(opj_j2k_t *p_j2k, { opj_cp_t * l_cp = &(p_j2k->m_cp); opj_image_t * l_image = p_j2k->m_private_image; - + OPJ_BOOL ret; OPJ_UINT32 it_comp; - OPJ_INT32 l_comp_x1, l_comp_y1; - opj_image_comp_t* l_img_comp = NULL; + if (p_j2k->m_cp.tw == 1 && p_j2k->m_cp.th == 1 && + p_j2k->m_cp.tcps[0].m_data != NULL) { + /* In the case of a single-tiled image whose codestream we have already */ + /* ingested, go on */ + } /* Check if we are read the main header */ - if (p_j2k->m_specific_param.m_decoder.m_state != J2K_STATE_TPHSOT) { + else if (p_j2k->m_specific_param.m_decoder.m_state != J2K_STATE_TPHSOT) { opj_event_msg(p_manager, EVT_ERROR, - "Need to decode the main header before begin to decode the remaining codestream"); + "Need to decode the main header before begin to decode the remaining codestream.\n"); return OPJ_FALSE; } + /* Update the comps[].factor member of the output image with the one */ + /* of m_reduce */ + for (it_comp = 0; it_comp < p_image->numcomps; ++it_comp) { + p_image->comps[it_comp].factor = p_j2k->m_cp.m_specific_param.m_dec.m_reduce; + } + if (!p_start_x && !p_start_y && !p_end_x && !p_end_y) { opj_event_msg(p_manager, EVT_INFO, "No decoded area parameters, set the decoded area to the whole image\n"); @@ -9126,7 +9356,12 @@ OPJ_BOOL opj_j2k_set_decode_area(opj_j2k_t *p_j2k, p_j2k->m_specific_param.m_decoder.m_end_tile_x = l_cp->tw; p_j2k->m_specific_param.m_decoder.m_end_tile_y = l_cp->th; - return OPJ_TRUE; + p_image->x0 = l_image->x0; + p_image->y0 = l_image->y0; + p_image->x1 = l_image->x1; + p_image->y1 = l_image->y1; + + return opj_j2k_update_image_dimensions(p_image, p_manager); } /* ----- */ @@ -9156,7 +9391,7 @@ OPJ_BOOL opj_j2k_set_decode_area(opj_j2k_t *p_j2k, } /* Up */ - if (p_start_x < 0) { + if (p_start_y < 0) { opj_event_msg(p_manager, EVT_ERROR, "Up position of the decoded area (region_y0=%d) should be >= 0.\n", p_start_y); @@ -9228,44 +9463,14 @@ OPJ_BOOL opj_j2k_set_decode_area(opj_j2k_t *p_j2k, p_j2k->m_specific_param.m_decoder.m_discard_tiles = 1; - l_img_comp = p_image->comps; - for (it_comp = 0; it_comp < p_image->numcomps; ++it_comp) { - OPJ_INT32 l_h, l_w; - - l_img_comp->x0 = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)p_image->x0, - (OPJ_INT32)l_img_comp->dx); - l_img_comp->y0 = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)p_image->y0, - (OPJ_INT32)l_img_comp->dy); - l_comp_x1 = opj_int_ceildiv((OPJ_INT32)p_image->x1, (OPJ_INT32)l_img_comp->dx); - l_comp_y1 = opj_int_ceildiv((OPJ_INT32)p_image->y1, (OPJ_INT32)l_img_comp->dy); - - l_w = opj_int_ceildivpow2(l_comp_x1, (OPJ_INT32)l_img_comp->factor) - - opj_int_ceildivpow2((OPJ_INT32)l_img_comp->x0, (OPJ_INT32)l_img_comp->factor); - if (l_w < 0) { - opj_event_msg(p_manager, EVT_ERROR, - "Size x of the decoded component image is incorrect (comp[%d].w=%d).\n", - it_comp, l_w); - return OPJ_FALSE; - } - l_img_comp->w = (OPJ_UINT32)l_w; - - l_h = opj_int_ceildivpow2(l_comp_y1, (OPJ_INT32)l_img_comp->factor) - - opj_int_ceildivpow2((OPJ_INT32)l_img_comp->y0, (OPJ_INT32)l_img_comp->factor); - if (l_h < 0) { - opj_event_msg(p_manager, EVT_ERROR, - "Size y of the decoded component image is incorrect (comp[%d].h=%d).\n", - it_comp, l_h); - return OPJ_FALSE; - } - l_img_comp->h = (OPJ_UINT32)l_h; + ret = opj_j2k_update_image_dimensions(p_image, p_manager); - l_img_comp++; + if (ret) { + opj_event_msg(p_manager, EVT_INFO, "Setting decoding area to %d,%d,%d,%d\n", + p_image->x0, p_image->y0, p_image->x1, p_image->y1); } - opj_event_msg(p_manager, EVT_INFO, "Setting decoding area to %d,%d,%d,%d\n", - p_image->x0, p_image->y0, p_image->x1, p_image->y1); - - return OPJ_TRUE; + return ret; } opj_j2k_t* opj_j2k_create_decompress(void) @@ -9551,9 +9756,10 @@ static OPJ_BOOL opj_j2k_read_SPCod_SPCoc(opj_j2k_t *p_j2k, /* If user wants to remove more resolutions than the codestream contains, return error */ if (l_cp->m_specific_param.m_dec.m_reduce >= l_tccp->numresolutions) { opj_event_msg(p_manager, EVT_ERROR, - "Error decoding component %d.\nThe number of resolutions to remove is higher than the number " - "of resolutions of this component\nModify the cp_reduce parameter.\n\n", - compno); + "Error decoding component %d.\nThe number of resolutions " + "to remove (%d) is greater or equal than the number " + "of resolutions of this component (%d)\nModify the cp_reduce parameter.\n\n", + compno, l_cp->m_specific_param.m_dec.m_reduce, l_tccp->numresolutions); p_j2k->m_specific_param.m_decoder.m_state |= 0x8000;/* FIXME J2K_DEC_STATE_ERR;*/ return OPJ_FALSE; @@ -10445,10 +10651,8 @@ static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k, { OPJ_BOOL l_go_on = OPJ_TRUE; OPJ_UINT32 l_current_tile_no; - OPJ_UINT32 l_data_size, l_max_data_size; OPJ_INT32 l_tile_x0, l_tile_y0, l_tile_x1, l_tile_y1; OPJ_UINT32 l_nb_comps; - OPJ_BYTE * l_current_data; OPJ_UINT32 nr_tiles = 0; /* Particular case for whole single tile decoding */ @@ -10458,12 +10662,11 @@ static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k, p_j2k->m_output_image->x0 == 0 && p_j2k->m_output_image->y0 == 0 && p_j2k->m_output_image->x1 == p_j2k->m_cp.tdx && - p_j2k->m_output_image->y1 == p_j2k->m_cp.tdy && - p_j2k->m_output_image->comps[0].factor == 0) { + p_j2k->m_output_image->y1 == p_j2k->m_cp.tdy) { OPJ_UINT32 i; if (! opj_j2k_read_tile_header(p_j2k, &l_current_tile_no, - &l_data_size, + NULL, &l_tile_x0, &l_tile_y0, &l_tile_x1, &l_tile_y1, &l_nb_comps, @@ -10492,59 +10695,55 @@ static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k, return OPJ_TRUE; } - l_current_data = (OPJ_BYTE*)opj_malloc(1000); - if (! l_current_data) { - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to decode tiles\n"); - return OPJ_FALSE; - } - l_max_data_size = 1000; - for (;;) { - if (! opj_j2k_read_tile_header(p_j2k, - &l_current_tile_no, - &l_data_size, - &l_tile_x0, &l_tile_y0, - &l_tile_x1, &l_tile_y1, - &l_nb_comps, - &l_go_on, - p_stream, - p_manager)) { - opj_free(l_current_data); - return OPJ_FALSE; - } - - if (! l_go_on) { - break; - } - - if (l_data_size > l_max_data_size) { - OPJ_BYTE *l_new_current_data = (OPJ_BYTE *) opj_realloc(l_current_data, - l_data_size); - if (! l_new_current_data) { - opj_free(l_current_data); - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to decode tile %d/%d\n", - l_current_tile_no + 1, p_j2k->m_cp.th * p_j2k->m_cp.tw); + if (p_j2k->m_cp.tw == 1 && p_j2k->m_cp.th == 1 && + p_j2k->m_cp.tcps[0].m_data != NULL) { + l_current_tile_no = 0; + p_j2k->m_current_tile_number = 0; + p_j2k->m_specific_param.m_decoder.m_state |= J2K_STATE_DATA; + } else { + if (! opj_j2k_read_tile_header(p_j2k, + &l_current_tile_no, + NULL, + &l_tile_x0, &l_tile_y0, + &l_tile_x1, &l_tile_y1, + &l_nb_comps, + &l_go_on, + p_stream, + p_manager)) { return OPJ_FALSE; } - l_current_data = l_new_current_data; - l_max_data_size = l_data_size; + + if (! l_go_on) { + break; + } } - if (! opj_j2k_decode_tile(p_j2k, l_current_tile_no, l_current_data, l_data_size, + if (! opj_j2k_decode_tile(p_j2k, l_current_tile_no, NULL, 0, p_stream, p_manager)) { - opj_free(l_current_data); opj_event_msg(p_manager, EVT_ERROR, "Failed to decode tile %d/%d\n", l_current_tile_no + 1, p_j2k->m_cp.th * p_j2k->m_cp.tw); return OPJ_FALSE; } + opj_event_msg(p_manager, EVT_INFO, "Tile %d/%d has been decoded.\n", l_current_tile_no + 1, p_j2k->m_cp.th * p_j2k->m_cp.tw); - if (! opj_j2k_update_image_data(p_j2k->m_tcd, l_current_data, + if (! opj_j2k_update_image_data(p_j2k->m_tcd, p_j2k->m_output_image)) { - opj_free(l_current_data); return OPJ_FALSE; } + + if (p_j2k->m_cp.tw == 1 && p_j2k->m_cp.th == 1 && + !(p_j2k->m_output_image->x0 == p_j2k->m_private_image->x0 && + p_j2k->m_output_image->y0 == p_j2k->m_private_image->y0 && + p_j2k->m_output_image->x1 == p_j2k->m_private_image->x1 && + p_j2k->m_output_image->y1 == p_j2k->m_private_image->y1)) { + /* Keep current tcp data */ + } else { + opj_j2k_tcp_data_destroy(&p_j2k->m_cp.tcps[l_current_tile_no]); + } + opj_event_msg(p_manager, EVT_INFO, "Image data has been updated with tile %d.\n\n", l_current_tile_no + 1); @@ -10557,8 +10756,6 @@ static OPJ_BOOL opj_j2k_decode_tiles(opj_j2k_t *p_j2k, } } - opj_free(l_current_data); - return OPJ_TRUE; } @@ -10591,24 +10788,14 @@ static OPJ_BOOL opj_j2k_decode_one_tile(opj_j2k_t *p_j2k, OPJ_BOOL l_go_on = OPJ_TRUE; OPJ_UINT32 l_current_tile_no; OPJ_UINT32 l_tile_no_to_dec; - OPJ_UINT32 l_data_size, l_max_data_size; OPJ_INT32 l_tile_x0, l_tile_y0, l_tile_x1, l_tile_y1; OPJ_UINT32 l_nb_comps; - OPJ_BYTE * l_current_data; OPJ_UINT32 l_nb_tiles; OPJ_UINT32 i; - l_current_data = (OPJ_BYTE*)opj_malloc(1000); - if (! l_current_data) { - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to decode one tile\n"); - return OPJ_FALSE; - } - l_max_data_size = 1000; - /*Allocate and initialize some elements of codestrem index if not already done*/ if (!p_j2k->cstr_index->tile_index) { if (!opj_j2k_allocate_tile_element_cstr_index(p_j2k)) { - opj_free(l_current_data); return OPJ_FALSE; } } @@ -10623,7 +10810,6 @@ static OPJ_BOOL opj_j2k_decode_one_tile(opj_j2k_t *p_j2k, if (!(opj_stream_read_seek(p_stream, p_j2k->m_specific_param.m_decoder.m_last_sot_read_pos + 2, p_manager))) { opj_event_msg(p_manager, EVT_ERROR, "Problem with seek function\n"); - opj_free(l_current_data); return OPJ_FALSE; } } else { @@ -10631,7 +10817,6 @@ static OPJ_BOOL opj_j2k_decode_one_tile(opj_j2k_t *p_j2k, p_j2k->cstr_index->tile_index[l_tile_no_to_dec].tp_index[0].start_pos + 2, p_manager))) { opj_event_msg(p_manager, EVT_ERROR, "Problem with seek function\n"); - opj_free(l_current_data); return OPJ_FALSE; } } @@ -10653,14 +10838,13 @@ static OPJ_BOOL opj_j2k_decode_one_tile(opj_j2k_t *p_j2k, for (;;) { if (! opj_j2k_read_tile_header(p_j2k, &l_current_tile_no, - &l_data_size, + NULL, &l_tile_x0, &l_tile_y0, &l_tile_x1, &l_tile_y1, &l_nb_comps, &l_go_on, p_stream, p_manager)) { - opj_free(l_current_data); return OPJ_FALSE; } @@ -10668,33 +10852,19 @@ static OPJ_BOOL opj_j2k_decode_one_tile(opj_j2k_t *p_j2k, break; } - if (l_data_size > l_max_data_size) { - OPJ_BYTE *l_new_current_data = (OPJ_BYTE *) opj_realloc(l_current_data, - l_data_size); - if (! l_new_current_data) { - opj_free(l_current_data); - l_current_data = NULL; - opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to decode tile %d/%d\n", - l_current_tile_no + 1, p_j2k->m_cp.th * p_j2k->m_cp.tw); - return OPJ_FALSE; - } - l_current_data = l_new_current_data; - l_max_data_size = l_data_size; - } - - if (! opj_j2k_decode_tile(p_j2k, l_current_tile_no, l_current_data, l_data_size, + if (! opj_j2k_decode_tile(p_j2k, l_current_tile_no, NULL, 0, p_stream, p_manager)) { - opj_free(l_current_data); return OPJ_FALSE; } opj_event_msg(p_manager, EVT_INFO, "Tile %d/%d has been decoded.\n", l_current_tile_no + 1, p_j2k->m_cp.th * p_j2k->m_cp.tw); - if (! opj_j2k_update_image_data(p_j2k->m_tcd, l_current_data, + if (! opj_j2k_update_image_data(p_j2k->m_tcd, p_j2k->m_output_image)) { - opj_free(l_current_data); return OPJ_FALSE; } + opj_j2k_tcp_data_destroy(&p_j2k->m_cp.tcps[l_current_tile_no]); + opj_event_msg(p_manager, EVT_INFO, "Image data has been updated with tile %d.\n\n", l_current_tile_no + 1); @@ -10703,7 +10873,6 @@ static OPJ_BOOL opj_j2k_decode_one_tile(opj_j2k_t *p_j2k, if (!(opj_stream_read_seek(p_stream, p_j2k->cstr_index->main_head_end + 2, p_manager))) { opj_event_msg(p_manager, EVT_ERROR, "Problem with seek function\n"); - opj_free(l_current_data); return OPJ_FALSE; } break; @@ -10715,8 +10884,6 @@ static OPJ_BOOL opj_j2k_decode_one_tile(opj_j2k_t *p_j2k, } - opj_free(l_current_data); - return OPJ_TRUE; } @@ -10739,20 +10906,105 @@ static OPJ_BOOL opj_j2k_setup_decoding_tile(opj_j2k_t *p_j2k, return OPJ_TRUE; } +static OPJ_BOOL opj_j2k_move_data_from_codec_to_output_image(opj_j2k_t * p_j2k, + opj_image_t * p_image) +{ + OPJ_UINT32 compno; + + /* Move data and copy one information from codec to output image*/ + if (p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode > 0) { + opj_image_comp_t* newcomps = + (opj_image_comp_t*) opj_malloc( + p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode * + sizeof(opj_image_comp_t)); + if (newcomps == NULL) { + opj_image_destroy(p_j2k->m_private_image); + p_j2k->m_private_image = NULL; + return OPJ_FALSE; + } + for (compno = 0; compno < p_image->numcomps; compno++) { + opj_image_data_free(p_image->comps[compno].data); + p_image->comps[compno].data = NULL; + } + for (compno = 0; + compno < p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode; compno++) { + OPJ_UINT32 src_compno = + p_j2k->m_specific_param.m_decoder.m_comps_indices_to_decode[compno]; + memcpy(&(newcomps[compno]), + &(p_j2k->m_output_image->comps[src_compno]), + sizeof(opj_image_comp_t)); + newcomps[compno].resno_decoded = + p_j2k->m_output_image->comps[src_compno].resno_decoded; + newcomps[compno].data = p_j2k->m_output_image->comps[src_compno].data; + p_j2k->m_output_image->comps[src_compno].data = NULL; + } + for (compno = 0; compno < p_image->numcomps; compno++) { + assert(p_j2k->m_output_image->comps[compno].data == NULL); + opj_image_data_free(p_j2k->m_output_image->comps[compno].data); + p_j2k->m_output_image->comps[compno].data = NULL; + } + p_image->numcomps = p_j2k->m_specific_param.m_decoder.m_numcomps_to_decode; + opj_free(p_image->comps); + p_image->comps = newcomps; + } else { + for (compno = 0; compno < p_image->numcomps; compno++) { + p_image->comps[compno].resno_decoded = + p_j2k->m_output_image->comps[compno].resno_decoded; + opj_image_data_free(p_image->comps[compno].data); + p_image->comps[compno].data = p_j2k->m_output_image->comps[compno].data; +#if 0 + char fn[256]; + sprintf(fn, "/tmp/%d.raw", compno); + FILE *debug = fopen(fn, "wb"); + fwrite(p_image->comps[compno].data, sizeof(OPJ_INT32), + p_image->comps[compno].w * p_image->comps[compno].h, debug); + fclose(debug); +#endif + p_j2k->m_output_image->comps[compno].data = NULL; + } + } + return OPJ_TRUE; +} + OPJ_BOOL opj_j2k_decode(opj_j2k_t * p_j2k, opj_stream_private_t * p_stream, opj_image_t * p_image, opj_event_mgr_t * p_manager) { - OPJ_UINT32 compno; - if (!p_image) { return OPJ_FALSE; } - p_j2k->m_output_image = opj_image_create0(); - if (!(p_j2k->m_output_image)) { - return OPJ_FALSE; + /* Heuristics to detect sequence opj_read_header(), opj_set_decoded_resolution_factor() */ + /* and finally opj_decode_image() without manual setting of comps[].factor */ + /* We could potentially always execute it, if we don't allow people to do */ + /* opj_read_header(), modify x0,y0,x1,y1 of returned image an call opj_decode_image() */ + if (p_j2k->m_cp.m_specific_param.m_dec.m_reduce > 0 && + p_j2k->m_private_image != NULL && + p_j2k->m_private_image->numcomps > 0 && + p_j2k->m_private_image->comps[0].factor == + p_j2k->m_cp.m_specific_param.m_dec.m_reduce && + p_image->numcomps > 0 && + p_image->comps[0].factor == 0 && + /* Don't mess with image dimension if the user has allocated it */ + p_image->comps[0].data == NULL) { + OPJ_UINT32 it_comp; + + /* Update the comps[].factor member of the output image with the one */ + /* of m_reduce */ + for (it_comp = 0; it_comp < p_image->numcomps; ++it_comp) { + p_image->comps[it_comp].factor = p_j2k->m_cp.m_specific_param.m_dec.m_reduce; + } + if (!opj_j2k_update_image_dimensions(p_image, p_manager)) { + return OPJ_FALSE; + } + } + + if (p_j2k->m_output_image == NULL) { + p_j2k->m_output_image = opj_image_create0(); + if (!(p_j2k->m_output_image)) { + return OPJ_FALSE; + } } opj_copy_image_header(p_image, p_j2k->m_output_image); @@ -10769,22 +11021,7 @@ OPJ_BOOL opj_j2k_decode(opj_j2k_t * p_j2k, } /* Move data and copy one information from codec to output image*/ - for (compno = 0; compno < p_image->numcomps; compno++) { - p_image->comps[compno].resno_decoded = - p_j2k->m_output_image->comps[compno].resno_decoded; - p_image->comps[compno].data = p_j2k->m_output_image->comps[compno].data; -#if 0 - char fn[256]; - sprintf(fn, "/tmp/%d.raw", compno); - FILE *debug = fopen(fn, "wb"); - fwrite(p_image->comps[compno].data, sizeof(OPJ_INT32), - p_image->comps[compno].w * p_image->comps[compno].h, debug); - fclose(debug); -#endif - p_j2k->m_output_image->comps[compno].data = NULL; - } - - return OPJ_TRUE; + return opj_j2k_move_data_from_codec_to_output_image(p_j2k, p_image); } OPJ_BOOL opj_j2k_get_tile(opj_j2k_t *p_j2k, @@ -10802,6 +11039,12 @@ OPJ_BOOL opj_j2k_get_tile(opj_j2k_t *p_j2k, return OPJ_FALSE; } + if (p_image->numcomps < p_j2k->m_private_image->numcomps) { + opj_event_msg(p_manager, EVT_ERROR, + "Image has less components than codestream.\n"); + return OPJ_FALSE; + } + if (/*(tile_index < 0) &&*/ (tile_index >= p_j2k->m_cp.tw * p_j2k->m_cp.th)) { opj_event_msg(p_manager, EVT_ERROR, "Tile index provided by the user is incorrect %d (max = %d) \n", tile_index, @@ -10832,7 +11075,7 @@ OPJ_BOOL opj_j2k_get_tile(opj_j2k_t *p_j2k, } l_img_comp = p_image->comps; - for (compno = 0; compno < p_image->numcomps; ++compno) { + for (compno = 0; compno < p_j2k->m_private_image->numcomps; ++compno) { OPJ_INT32 l_comp_x1, l_comp_y1; l_img_comp->factor = p_j2k->m_private_image->comps[compno].factor; @@ -10854,6 +11097,18 @@ OPJ_BOOL opj_j2k_get_tile(opj_j2k_t *p_j2k, l_img_comp++; } + if (p_image->numcomps > p_j2k->m_private_image->numcomps) { + /* Can happen when calling repeatdly opj_get_decoded_tile() on an + * image with a color palette, where color palette expansion is done + * later in jp2.c */ + for (compno = p_j2k->m_private_image->numcomps; compno < p_image->numcomps; + ++compno) { + opj_image_data_free(p_image->comps[compno].data); + p_image->comps[compno].data = NULL; + } + p_image->numcomps = p_j2k->m_private_image->numcomps; + } + /* Destroy the previous output image*/ if (p_j2k->m_output_image) { opj_image_destroy(p_j2k->m_output_image); @@ -10881,20 +11136,7 @@ OPJ_BOOL opj_j2k_get_tile(opj_j2k_t *p_j2k, } /* Move data and copy one information from codec to output image*/ - for (compno = 0; compno < p_image->numcomps; compno++) { - p_image->comps[compno].resno_decoded = - p_j2k->m_output_image->comps[compno].resno_decoded; - - if (p_image->comps[compno].data) { - opj_image_data_free(p_image->comps[compno].data); - } - - p_image->comps[compno].data = p_j2k->m_output_image->comps[compno].data; - - p_j2k->m_output_image->comps[compno].data = NULL; - } - - return OPJ_TRUE; + return opj_j2k_move_data_from_codec_to_output_image(p_j2k, p_image); } OPJ_BOOL opj_j2k_set_decoded_resolution_factor(opj_j2k_t *p_j2k, @@ -10934,7 +11176,7 @@ OPJ_BOOL opj_j2k_encode(opj_j2k_t * p_j2k, { OPJ_UINT32 i, j; OPJ_UINT32 l_nb_tiles; - OPJ_UINT32 l_max_tile_size = 0, l_current_tile_size; + OPJ_SIZE_T l_max_tile_size = 0, l_current_tile_size; OPJ_BYTE * l_current_data = 00; OPJ_BOOL l_reuse_data = OPJ_FALSE; opj_tcd_t* p_tcd = 00; @@ -11000,6 +11242,12 @@ OPJ_BOOL opj_j2k_encode(opj_j2k_t * p_j2k, l_current_data = l_new_current_data; l_max_tile_size = l_current_tile_size; } + if (l_current_data == NULL) { + /* Should not happen in practice, but will avoid Coverity to */ + /* complain about a null pointer dereference */ + assert(0); + return OPJ_FALSE; + } /* copy image data (32 bit) to l_current_data as contiguous, all-component, zero offset buffer */ /* 32 bit components @ 8 bit precision get converted to 8 bit */ @@ -11471,7 +11719,8 @@ static OPJ_BOOL opj_j2k_write_first_tile_part(opj_j2k_t *p_j2k, l_current_nb_bytes_written = 0; l_begin_data = p_data; - if (! opj_j2k_write_sot(p_j2k, p_data, &l_current_nb_bytes_written, p_stream, + if (! opj_j2k_write_sot(p_j2k, p_data, p_total_data_size, + &l_current_nb_bytes_written, p_stream, p_manager)) { return OPJ_FALSE; } @@ -11563,7 +11812,10 @@ static OPJ_BOOL opj_j2k_write_all_tile_parts(opj_j2k_t *p_j2k, l_part_tile_size = 0; l_begin_data = p_data; - if (! opj_j2k_write_sot(p_j2k, p_data, &l_current_nb_bytes_written, p_stream, + if (! opj_j2k_write_sot(p_j2k, p_data, + p_total_data_size, + &l_current_nb_bytes_written, + p_stream, p_manager)) { return OPJ_FALSE; } @@ -11606,7 +11858,9 @@ static OPJ_BOOL opj_j2k_write_all_tile_parts(opj_j2k_t *p_j2k, l_part_tile_size = 0; l_begin_data = p_data; - if (! opj_j2k_write_sot(p_j2k, p_data, &l_current_nb_bytes_written, p_stream, + if (! opj_j2k_write_sot(p_j2k, p_data, + p_total_data_size, + &l_current_nb_bytes_written, p_stream, p_manager)) { return OPJ_FALSE; } @@ -11794,7 +12048,7 @@ static OPJ_BOOL opj_j2k_init_info(opj_j2k_t *p_j2k, } /** - * Creates a tile-coder decoder. + * Creates a tile-coder encoder. * * @param p_stream the stream to write data to. * @param p_j2k J2K codec. diff --git a/openjpeg/src/lib/openjp2/j2k.h b/openjpeg/src/lib/openjp2/j2k.h index d61c96dba..5d393c981 100644 --- a/openjpeg/src/lib/openjp2/j2k.h +++ b/openjpeg/src/lib/openjp2/j2k.h @@ -107,6 +107,8 @@ The functions in J2K.C have for goal to read/write the several parts of the code #endif /* USE_JPSEC */ /* <<UniPG */ +#define J2K_MAX_POCS 32 /**< Maximum number of POCs */ + /* ----------------------------------------------------------------------- */ /** @@ -251,7 +253,7 @@ typedef struct opj_tcp { /** number of progression order changes */ OPJ_UINT32 numpocs; /** progression order changes */ - opj_poc_t pocs[32]; + opj_poc_t pocs[J2K_MAX_POCS]; /** number of ppt markers (reserved size) */ OPJ_UINT32 ppt_markers_count; @@ -480,6 +482,10 @@ typedef struct opj_j2k_dec { * SOD reader function. FIXME NOT USED for the moment */ OPJ_BOOL m_last_tile_part; + + OPJ_UINT32 m_numcomps_to_decode; + OPJ_UINT32 *m_comps_indices_to_decode; + /** to tell that a tile can be decoded. */ OPJ_BITFIELD m_can_decode : 1; OPJ_BITFIELD m_discard_tiles : 1; @@ -617,7 +623,7 @@ OPJ_BOOL opj_j2k_setup_encoder(opj_j2k_t *p_j2k, /** Converts an enum type progression order to string type */ -char *opj_j2k_convert_progression_order(OPJ_PROG_ORDER prg_order); +const char *opj_j2k_convert_progression_order(OPJ_PROG_ORDER prg_order); /* ----------------------------------------------------------------------- */ /*@}*/ @@ -705,6 +711,21 @@ OPJ_BOOL opj_j2k_read_tile_header(opj_j2k_t * p_j2k, opj_event_mgr_t * p_manager); +/** Sets the indices of the components to decode. + * + * @param p_j2k the jpeg2000 codec. + * @param numcomps Number of components to decode. + * @param comps_indices Array of num_compts indices (numbering starting at 0) + * corresponding to the components to decode. + * @param p_manager Event manager + * + * @return OPJ_TRUE in case of success. + */ +OPJ_BOOL opj_j2k_set_decoded_components(opj_j2k_t *p_j2k, + OPJ_UINT32 numcomps, + const OPJ_UINT32* comps_indices, + opj_event_mgr_t * p_manager); + /** * Sets the given area to be decoded. This function should be called right after opj_read_header and before any tile header reading. * diff --git a/openjpeg/src/lib/openjp2/jp2.c b/openjpeg/src/lib/openjp2/jp2.c index f3ccb9974..c79ea7316 100644 --- a/openjpeg/src/lib/openjp2/jp2.c +++ b/openjpeg/src/lib/openjp2/jp2.c @@ -162,7 +162,7 @@ static OPJ_BOOL opj_jp2_read_ftyp(opj_jp2_t *jp2, opj_event_mgr_t * p_manager); static OPJ_BOOL opj_jp2_skip_jp2c(opj_jp2_t *jp2, - opj_stream_private_t *cio, + opj_stream_private_t *stream, opj_event_mgr_t * p_manager); /** @@ -958,26 +958,35 @@ static OPJ_BOOL opj_jp2_check_color(opj_image_t *image, opj_jp2_color_t *color, } /* verify that no component is targeted more than once */ for (i = 0; i < nr_channels; i++) { - OPJ_UINT16 pcol = cmap[i].pcol; + OPJ_BYTE mtyp = cmap[i].mtyp; + OPJ_BYTE pcol = cmap[i].pcol; /* See ISO 15444-1 Table I.14 – MTYPi field values */ - if (cmap[i].mtyp != 0 && cmap[i].mtyp != 1) { + if (mtyp != 0 && mtyp != 1) { opj_event_msg(p_manager, EVT_ERROR, "Invalid value for cmap[%d].mtyp = %d.\n", i, - cmap[i].mtyp); + mtyp); is_sane = OPJ_FALSE; } else if (pcol >= nr_channels) { opj_event_msg(p_manager, EVT_ERROR, "Invalid component/palette index for direct mapping %d.\n", pcol); is_sane = OPJ_FALSE; - } else if (pcol_usage[pcol] && cmap[i].mtyp == 1) { + } else if (pcol_usage[pcol] && mtyp == 1) { opj_event_msg(p_manager, EVT_ERROR, "Component %d is mapped twice.\n", pcol); is_sane = OPJ_FALSE; - } else if (cmap[i].mtyp == 0 && cmap[i].pcol != 0) { + } else if (mtyp == 0 && pcol != 0) { /* I.5.3.5 PCOL: If the value of the MTYP field for this channel is 0, then * the value of this field shall be 0. */ opj_event_msg(p_manager, EVT_ERROR, "Direct use at #%d however pcol=%d.\n", i, pcol); is_sane = OPJ_FALSE; + } else if (mtyp == 1 && pcol != i) { + /* OpenJPEG implementation limitation. See assert(i == pcol); */ + /* in opj_jp2_apply_pclr() */ + opj_event_msg(p_manager, EVT_ERROR, + "Implementation limitation: for palette mapping, " + "pcol[%d] should be equal to %d, but is equal " + "to %d.\n", i, i, pcol); + is_sane = OPJ_FALSE; } else { pcol_usage[pcol] = OPJ_TRUE; } @@ -1074,7 +1083,7 @@ static OPJ_BOOL opj_jp2_apply_pclr(opj_image_t *image, if (!new_comps[i].data) { while (i > 0) { -- i; - opj_free(new_comps[i].data); + opj_image_data_free(new_comps[i].data); } opj_free(new_comps); opj_event_msg(p_manager, EVT_ERROR, @@ -1132,8 +1141,6 @@ static OPJ_BOOL opj_jp2_apply_pclr(opj_image_t *image, image->comps = new_comps; image->numcomps = nr_channels; - opj_jp2_free_pclr(color); - return OPJ_TRUE; }/* apply_pclr() */ @@ -1600,6 +1607,11 @@ OPJ_BOOL opj_jp2_decode(opj_jp2_t *jp2, return OPJ_FALSE; } + if (jp2->j2k->m_specific_param.m_decoder.m_numcomps_to_decode) { + /* Bypass all JP2 component transforms */ + return OPJ_TRUE; + } + if (!jp2->ignore_pclr_cmap_cdef) { if (!opj_jp2_check_color(p_image, &(jp2->color), p_manager)) { return OPJ_FALSE; @@ -3062,6 +3074,16 @@ void opj_jp2_destroy(opj_jp2_t *jp2) } } +OPJ_BOOL opj_jp2_set_decoded_components(opj_jp2_t *p_jp2, + OPJ_UINT32 numcomps, + const OPJ_UINT32* comps_indices, + opj_event_mgr_t * p_manager) +{ + return opj_j2k_set_decoded_components(p_jp2->j2k, + numcomps, comps_indices, + p_manager); +} + OPJ_BOOL opj_jp2_set_decode_area(opj_jp2_t *p_jp2, opj_image_t* p_image, OPJ_INT32 p_start_x, OPJ_INT32 p_start_y, @@ -3093,6 +3115,11 @@ OPJ_BOOL opj_jp2_get_tile(opj_jp2_t *p_jp2, return OPJ_FALSE; } + if (p_jp2->j2k->m_specific_param.m_decoder.m_numcomps_to_decode) { + /* Bypass all JP2 component transforms */ + return OPJ_TRUE; + } + if (!opj_jp2_check_color(p_image, &(p_jp2->color), p_manager)) { return OPJ_FALSE; } diff --git a/openjpeg/src/lib/openjp2/jp2.h b/openjpeg/src/lib/openjp2/jp2.h index 3ff66ebec..34abd5118 100644 --- a/openjpeg/src/lib/openjp2/jp2.h +++ b/openjpeg/src/lib/openjp2/jp2.h @@ -235,6 +235,12 @@ Decoding parameters are returned in jp2->j2k->cp. */ void opj_jp2_setup_decoder(opj_jp2_t *jp2, opj_dparameters_t *parameters); +/** Allocates worker threads for the compressor/decompressor. + * + * @param jp2 JP2 decompressor handle + * @param num_threads Number of threads. + * @return OPJ_TRUE in case of success. + */ OPJ_BOOL opj_jp2_set_threads(opj_jp2_t *jp2, OPJ_UINT32 num_threads); /** @@ -327,6 +333,21 @@ OPJ_BOOL opj_jp2_read_header(opj_stream_private_t *p_stream, opj_image_t ** p_image, opj_event_mgr_t * p_manager); +/** Sets the indices of the components to decode. + * + * @param jp2 JP2 decompressor handle + * @param numcomps Number of components to decode. + * @param comps_indices Array of num_compts indices (numbering starting at 0) + * corresponding to the components to decode. + * @param p_manager Event manager; + * + * @return OPJ_TRUE in case of success. + */ +OPJ_BOOL opj_jp2_set_decoded_components(opj_jp2_t *jp2, + OPJ_UINT32 numcomps, + const OPJ_UINT32* comps_indices, + opj_event_mgr_t * p_manager); + /** * Reads a tile header. * @param p_jp2 the jpeg2000 codec. diff --git a/openjpeg/src/lib/openjp2/mct.c b/openjpeg/src/lib/openjp2/mct.c index 8c82ee20a..b79d4b87c 100644 --- a/openjpeg/src/lib/openjp2/mct.c +++ b/openjpeg/src/lib/openjp2/mct.c @@ -77,7 +77,7 @@ void opj_mct_encode( OPJ_INT32* OPJ_RESTRICT c0, OPJ_INT32* OPJ_RESTRICT c1, OPJ_INT32* OPJ_RESTRICT c2, - OPJ_UINT32 n) + OPJ_SIZE_T n) { OPJ_SIZE_T i; const OPJ_SIZE_T len = n; @@ -119,7 +119,7 @@ void opj_mct_encode( OPJ_INT32* OPJ_RESTRICT c0, OPJ_INT32* OPJ_RESTRICT c1, OPJ_INT32* OPJ_RESTRICT c2, - OPJ_UINT32 n) + OPJ_SIZE_T n) { OPJ_SIZE_T i; const OPJ_SIZE_T len = n; @@ -146,7 +146,7 @@ void opj_mct_decode( OPJ_INT32* OPJ_RESTRICT c0, OPJ_INT32* OPJ_RESTRICT c1, OPJ_INT32* OPJ_RESTRICT c2, - OPJ_UINT32 n) + OPJ_SIZE_T n) { OPJ_SIZE_T i; const OPJ_SIZE_T len = n; @@ -181,7 +181,7 @@ void opj_mct_decode( OPJ_INT32* OPJ_RESTRICT c0, OPJ_INT32* OPJ_RESTRICT c1, OPJ_INT32* OPJ_RESTRICT c2, - OPJ_UINT32 n) + OPJ_SIZE_T n) { OPJ_UINT32 i; for (i = 0; i < n; ++i) { @@ -214,7 +214,7 @@ void opj_mct_encode_real( OPJ_INT32* OPJ_RESTRICT c0, OPJ_INT32* OPJ_RESTRICT c1, OPJ_INT32* OPJ_RESTRICT c2, - OPJ_UINT32 n) + OPJ_SIZE_T n) { OPJ_SIZE_T i; const OPJ_SIZE_T len = n; @@ -359,7 +359,7 @@ void opj_mct_encode_real( OPJ_INT32* OPJ_RESTRICT c0, OPJ_INT32* OPJ_RESTRICT c1, OPJ_INT32* OPJ_RESTRICT c2, - OPJ_UINT32 n) + OPJ_SIZE_T n) { OPJ_UINT32 i; for (i = 0; i < n; ++i) { @@ -386,7 +386,7 @@ void opj_mct_decode_real( OPJ_FLOAT32* OPJ_RESTRICT c0, OPJ_FLOAT32* OPJ_RESTRICT c1, OPJ_FLOAT32* OPJ_RESTRICT c2, - OPJ_UINT32 n) + OPJ_SIZE_T n) { OPJ_UINT32 i; #ifdef __SSE__ @@ -451,13 +451,13 @@ OPJ_FLOAT64 opj_mct_getnorm_real(OPJ_UINT32 compno) OPJ_BOOL opj_mct_encode_custom( OPJ_BYTE * pCodingdata, - OPJ_UINT32 n, + OPJ_SIZE_T n, OPJ_BYTE ** pData, OPJ_UINT32 pNbComp, OPJ_UINT32 isSigned) { OPJ_FLOAT32 * lMct = (OPJ_FLOAT32 *) pCodingdata; - OPJ_UINT32 i; + OPJ_SIZE_T i; OPJ_UINT32 j; OPJ_UINT32 k; OPJ_UINT32 lNbMatCoeff = pNbComp * pNbComp; @@ -505,13 +505,13 @@ OPJ_BOOL opj_mct_encode_custom( OPJ_BOOL opj_mct_decode_custom( OPJ_BYTE * pDecodingData, - OPJ_UINT32 n, + OPJ_SIZE_T n, OPJ_BYTE ** pData, OPJ_UINT32 pNbComp, OPJ_UINT32 isSigned) { OPJ_FLOAT32 * lMct; - OPJ_UINT32 i; + OPJ_SIZE_T i; OPJ_UINT32 j; OPJ_UINT32 k; diff --git a/openjpeg/src/lib/openjp2/mct.h b/openjpeg/src/lib/openjp2/mct.h index 0ed980e89..2e37ce733 100644 --- a/openjpeg/src/lib/openjp2/mct.h +++ b/openjpeg/src/lib/openjp2/mct.h @@ -61,7 +61,7 @@ Apply a reversible multi-component transform to an image @param n Number of samples for each component */ void opj_mct_encode(OPJ_INT32* OPJ_RESTRICT c0, OPJ_INT32* OPJ_RESTRICT c1, - OPJ_INT32* OPJ_RESTRICT c2, OPJ_UINT32 n); + OPJ_INT32* OPJ_RESTRICT c2, OPJ_SIZE_T n); /** Apply a reversible multi-component inverse transform to an image @param c0 Samples for luminance component @@ -70,7 +70,7 @@ Apply a reversible multi-component inverse transform to an image @param n Number of samples for each component */ void opj_mct_decode(OPJ_INT32* OPJ_RESTRICT c0, OPJ_INT32* OPJ_RESTRICT c1, - OPJ_INT32* OPJ_RESTRICT c2, OPJ_UINT32 n); + OPJ_INT32* OPJ_RESTRICT c2, OPJ_SIZE_T n); /** Get norm of the basis function used for the reversible multi-component transform @param compno Number of the component (0->Y, 1->U, 2->V) @@ -86,7 +86,7 @@ Apply an irreversible multi-component transform to an image @param n Number of samples for each component */ void opj_mct_encode_real(OPJ_INT32* OPJ_RESTRICT c0, OPJ_INT32* OPJ_RESTRICT c1, - OPJ_INT32* OPJ_RESTRICT c2, OPJ_UINT32 n); + OPJ_INT32* OPJ_RESTRICT c2, OPJ_SIZE_T n); /** Apply an irreversible multi-component inverse transform to an image @param c0 Samples for luminance component @@ -95,7 +95,7 @@ Apply an irreversible multi-component inverse transform to an image @param n Number of samples for each component */ void opj_mct_decode_real(OPJ_FLOAT32* OPJ_RESTRICT c0, - OPJ_FLOAT32* OPJ_RESTRICT c1, OPJ_FLOAT32* OPJ_RESTRICT c2, OPJ_UINT32 n); + OPJ_FLOAT32* OPJ_RESTRICT c1, OPJ_FLOAT32* OPJ_RESTRICT c2, OPJ_SIZE_T n); /** Get norm of the basis function used for the irreversible multi-component transform @param compno Number of the component (0->Y, 1->U, 2->V) @@ -114,7 +114,7 @@ FIXME DOC */ OPJ_BOOL opj_mct_encode_custom( OPJ_BYTE * p_coding_data, - OPJ_UINT32 n, + OPJ_SIZE_T n, OPJ_BYTE ** p_data, OPJ_UINT32 p_nb_comp, OPJ_UINT32 is_signed); @@ -129,7 +129,7 @@ FIXME DOC */ OPJ_BOOL opj_mct_decode_custom( OPJ_BYTE * pDecodingData, - OPJ_UINT32 n, + OPJ_SIZE_T n, OPJ_BYTE ** pData, OPJ_UINT32 pNbComp, OPJ_UINT32 isSigned); diff --git a/openjpeg/src/lib/openjp2/mqc.c b/openjpeg/src/lib/openjp2/mqc.c index 8f69e29e3..6299b171d 100644 --- a/openjpeg/src/lib/openjp2/mqc.c +++ b/openjpeg/src/lib/openjp2/mqc.c @@ -79,7 +79,7 @@ static void opj_mqc_setbits(opj_mqc_t *mqc); /* <summary> */ /* This array defines all the possible states for a context. */ /* </summary> */ -static opj_mqc_state_t mqc_states[47 * 2] = { +static const opj_mqc_state_t mqc_states[47 * 2] = { {0x5601, 0, &mqc_states[2], &mqc_states[3]}, {0x5601, 1, &mqc_states[3], &mqc_states[2]}, {0x3401, 0, &mqc_states[4], &mqc_states[12]}, diff --git a/openjpeg/src/lib/openjp2/mqc.h b/openjpeg/src/lib/openjp2/mqc.h index ac3aff108..69a2a79dc 100644 --- a/openjpeg/src/lib/openjp2/mqc.h +++ b/openjpeg/src/lib/openjp2/mqc.h @@ -61,9 +61,9 @@ typedef struct opj_mqc_state { /** the Most Probable Symbol (0 or 1) */ OPJ_UINT32 mps; /** next state if the next encoded symbol is the MPS */ - struct opj_mqc_state *nmps; + const struct opj_mqc_state *nmps; /** next state if the next encoded symbol is the LPS */ - struct opj_mqc_state *nlps; + const struct opj_mqc_state *nlps; } opj_mqc_state_t; #define MQC_NUMCTXS 19 @@ -87,9 +87,9 @@ typedef struct opj_mqc { /** pointer to the end of the buffer */ OPJ_BYTE *end; /** Array of contexts */ - opj_mqc_state_t *ctxs[MQC_NUMCTXS]; + const opj_mqc_state_t *ctxs[MQC_NUMCTXS]; /** Active context */ - opj_mqc_state_t **curctx; + const opj_mqc_state_t **curctx; /* lut_ctxno_zc shifted by (1 << 9) * bandno */ const OPJ_BYTE* lut_ctxno_zc_orient; /** Original value of the 2 bytes at end[0] and end[1] */ diff --git a/openjpeg/src/lib/openjp2/mqc_inl.h b/openjpeg/src/lib/openjp2/mqc_inl.h index d95d9492a..310a3287f 100644 --- a/openjpeg/src/lib/openjp2/mqc_inl.h +++ b/openjpeg/src/lib/openjp2/mqc_inl.h @@ -157,7 +157,7 @@ static INLINE OPJ_UINT32 opj_mqc_raw_decode(opj_mqc_t *mqc) } #define DOWNLOAD_MQC_VARIABLES(mqc, curctx, c, a, ct) \ - register opj_mqc_state_t **curctx = mqc->curctx; \ + register const opj_mqc_state_t **curctx = mqc->curctx; \ register OPJ_UINT32 c = mqc->c; \ register OPJ_UINT32 a = mqc->a; \ register OPJ_UINT32 ct = mqc->ct diff --git a/openjpeg/src/lib/openjp2/openjpeg.c b/openjpeg/src/lib/openjp2/openjpeg.c index 4e649a74f..7b1230342 100644 --- a/openjpeg/src/lib/openjp2/openjpeg.c +++ b/openjpeg/src/lib/openjp2/openjpeg.c @@ -245,6 +245,12 @@ opj_codec_t* OPJ_CALLCONV opj_create_decompress(OPJ_CODEC_FORMAT p_format) OPJ_UINT32 res_factor, struct opj_event_mgr * p_manager)) opj_j2k_set_decoded_resolution_factor; + l_codec->m_codec_data.m_decompression.opj_set_decoded_components = + (OPJ_BOOL(*)(void * p_codec, + OPJ_UINT32 numcomps, + const OPJ_UINT32 * comps_indices, + struct opj_event_mgr * p_manager)) opj_j2k_set_decoded_components; + l_codec->opj_set_threads = (OPJ_BOOL(*)(void * p_codec, OPJ_UINT32 num_threads)) opj_j2k_set_threads; @@ -327,6 +333,12 @@ opj_codec_t* OPJ_CALLCONV opj_create_decompress(OPJ_CODEC_FORMAT p_format) OPJ_UINT32 res_factor, opj_event_mgr_t * p_manager)) opj_jp2_set_decoded_resolution_factor; + l_codec->m_codec_data.m_decompression.opj_set_decoded_components = + (OPJ_BOOL(*)(void * p_codec, + OPJ_UINT32 numcomps, + const OPJ_UINT32 * comps_indices, + struct opj_event_mgr * p_manager)) opj_jp2_set_decoded_components; + l_codec->opj_set_threads = (OPJ_BOOL(*)(void * p_codec, OPJ_UINT32 num_threads)) opj_jp2_set_threads; @@ -426,6 +438,36 @@ OPJ_BOOL OPJ_CALLCONV opj_read_header(opj_stream_t *p_stream, return OPJ_FALSE; } + +OPJ_BOOL OPJ_CALLCONV opj_set_decoded_components(opj_codec_t *p_codec, + OPJ_UINT32 numcomps, + const OPJ_UINT32* comps_indices, + OPJ_BOOL apply_color_transforms) +{ + if (p_codec) { + opj_codec_private_t * l_codec = (opj_codec_private_t *) p_codec; + + if (! l_codec->is_decompressor) { + opj_event_msg(&(l_codec->m_event_mgr), EVT_ERROR, + "Codec provided to the opj_set_decoded_components function is not a decompressor handler.\n"); + return OPJ_FALSE; + } + + if (apply_color_transforms) { + opj_event_msg(&(l_codec->m_event_mgr), EVT_ERROR, + "apply_color_transforms = OPJ_TRUE is not supported.\n"); + return OPJ_FALSE; + } + + return l_codec->m_codec_data.m_decompression.opj_set_decoded_components( + l_codec->m_codec, + numcomps, + comps_indices, + &(l_codec->m_event_mgr)); + } + return OPJ_FALSE; +} + OPJ_BOOL OPJ_CALLCONV opj_decode(opj_codec_t *p_codec, opj_stream_t *p_stream, opj_image_t* p_image) diff --git a/openjpeg/src/lib/openjp2/openjpeg.h b/openjpeg/src/lib/openjp2/openjpeg.h index d571c516e..f36286eb1 100644 --- a/openjpeg/src/lib/openjp2/openjpeg.h +++ b/openjpeg/src/lib/openjp2/openjpeg.h @@ -381,9 +381,12 @@ typedef struct opj_cparameters { OPJ_UINT32 numpocs; /** number of layers */ int tcp_numlayers; - /** rates of layers - might be subsequently limited by the max_cs_size field */ + /** rates of layers - might be subsequently limited by the max_cs_size field. + * Should be decreasing. 1 can be + * used as last value to indicate the last layer is lossless. */ float tcp_rates[100]; - /** different psnr for successive layers */ + /** different psnr for successive layers. Should be increasing. 0 can be + * used as last value to indicate the last layer is lossless. */ float tcp_distoratio[100]; /** number of resolutions */ int numresolution; @@ -867,9 +870,9 @@ typedef struct opj_tccp_info { OPJ_UINT32 csty; /** number of resolutions */ OPJ_UINT32 numresolutions; - /** code-blocks width */ + /** log2 of code-blocks width */ OPJ_UINT32 cblkw; - /** code-blocks height */ + /** log2 of code-blocks height */ OPJ_UINT32 cblkh; /** code-block coding style */ OPJ_UINT32 cblksty; @@ -1333,9 +1336,50 @@ OPJ_API OPJ_BOOL OPJ_CALLCONV opj_read_header(opj_stream_t *p_stream, opj_codec_t *p_codec, opj_image_t **p_image); + +/** Restrict the number of components to decode. + * + * This function should be called after opj_read_header(). + * + * This function enables to restrict the set of decoded components to the + * specified indices. + * Note that the current implementation (apply_color_transforms == OPJ_FALSE) + * is such that neither the multi-component transform at codestream level, + * nor JP2 channel transformations will be applied. + * Consequently the indices are relative to the codestream. + * + * Note: opj_decode_tile_data() should not be used together with opj_set_decoded_components(). + * + * @param p_codec the jpeg2000 codec to read. + * @param numcomps Size of the comps_indices array. + * @param comps_indices Array of numcomps values representing the indices + * of the components to decode (relative to the + * codestream, starting at 0) + * @param apply_color_transforms Whether multi-component transform at codestream level + * or JP2 channel transformations should be applied. + * Currently this parameter should be set to OPJ_FALSE. + * Setting it to OPJ_TRUE will result in an error. + * + * @return OPJ_TRUE in case of success. + */ +OPJ_API OPJ_BOOL OPJ_CALLCONV opj_set_decoded_components(opj_codec_t *p_codec, + OPJ_UINT32 numcomps, + const OPJ_UINT32* comps_indices, + OPJ_BOOL apply_color_transforms); + /** * Sets the given area to be decoded. This function should be called right after opj_read_header and before any tile header reading. * + * The coordinates passed to this function should be expressed in the reference grid, + * that is to say at the highest resolution level, even if requesting the image at lower + * resolution levels. + * + * Generally opj_set_decode_area() should be followed by opj_decode(), and the + * codec cannot be re-used. + * In the particular case of an image made of a single tile, several sequences of + * calls to opoj_set_decode_area() and opj_decode() are allowed, and will bring + * performance improvements when reading an image by chunks. + * * @param p_codec the jpeg2000 codec. * @param p_image the decoded image previously setted by opj_read_header * @param p_start_x the left position of the rectangle to decode (in image coordinates). @@ -1439,6 +1483,8 @@ OPJ_API OPJ_BOOL OPJ_CALLCONV opj_read_tile_header(opj_codec_t *p_codec, * Reads a tile data. This function is compulsory and allows one to decode tile data. opj_read_tile_header should be called before. * The user may need to refer to the image got by opj_read_header to understand the size being taken by the tile. * + * Note: opj_decode_tile_data() should not be used together with opj_set_decoded_components(). + * * @param p_codec the jpeg2000 codec. * @param p_tile_index the index of the tile being decoded, this should be the value set by opj_read_tile_header. * @param p_data pointer to a memory block that will hold the decoded data. diff --git a/openjpeg/src/lib/openjp2/opj_codec.h b/openjpeg/src/lib/openjp2/opj_codec.h index 2dbeac963..b962b1216 100644 --- a/openjpeg/src/lib/openjp2/opj_codec.h +++ b/openjpeg/src/lib/openjp2/opj_codec.h @@ -111,6 +111,11 @@ typedef struct opj_codec_private { OPJ_UINT32 res_factor, opj_event_mgr_t * p_manager); + /** Set the decoded components */ + OPJ_BOOL(*opj_set_decoded_components)(void * p_codec, + OPJ_UINT32 num_comps, + const OPJ_UINT32* comps_indices, + opj_event_mgr_t * p_manager); } m_decompression; /** diff --git a/openjpeg/src/lib/openjp2/opj_config.h b/openjpeg/src/lib/openjp2/opj_config.h index be4572409..e3785ad81 100644 --- a/openjpeg/src/lib/openjp2/opj_config.h +++ b/openjpeg/src/lib/openjp2/opj_config.h @@ -7,5 +7,5 @@ /* Version number. */ #define OPJ_VERSION_MAJOR 2 -#define OPJ_VERSION_MINOR 2 +#define OPJ_VERSION_MINOR 3 #define OPJ_VERSION_BUILD 0 diff --git a/openjpeg/src/lib/openjp2/opj_config_private.h b/openjpeg/src/lib/openjp2/opj_config_private.h index 8b8ae2a0a..bea925e37 100644 --- a/openjpeg/src/lib/openjp2/opj_config_private.h +++ b/openjpeg/src/lib/openjp2/opj_config_private.h @@ -1,4 +1,6 @@ /* create opj_config_private.h for CMake */ +/*** SET BY GS CONFIGURE SCRIPT ****/ +/* #define OPJ_HAVE_INTTYPES_H 1 */ /*** SET BY GS CONFIGURE SCRIPT ****/ /* #define OPJ_HAVE_INTTYPES_H 1 */ diff --git a/openjpeg/src/lib/openjp2/opj_includes.h b/openjpeg/src/lib/openjp2/opj_includes.h index b33e63cef..0a8628c96 100644 --- a/openjpeg/src/lib/openjp2/opj_includes.h +++ b/openjpeg/src/lib/openjp2/opj_includes.h @@ -216,6 +216,8 @@ static INLINE long opj_lrintf(float f) /* Type to use for bit-fields in internal headers */ typedef unsigned int OPJ_BITFIELD; +#define OPJ_UNUSED(x) (void)x + #include "opj_inttypes.h" #include "opj_clock.h" #include "opj_malloc.h" @@ -243,6 +245,7 @@ typedef unsigned int OPJ_BITFIELD; #include "t2.h" #include "mct.h" #include "opj_intmath.h" +#include "sparse_array.h" #ifdef USE_JPIP #include "cidx_manager.h" diff --git a/openjpeg/src/lib/openjp2/opj_intmath.h b/openjpeg/src/lib/openjp2/opj_intmath.h index cf97c15b1..ad1359766 100644 --- a/openjpeg/src/lib/openjp2/opj_intmath.h +++ b/openjpeg/src/lib/openjp2/opj_intmath.h @@ -96,6 +96,15 @@ static INLINE OPJ_UINT32 opj_uint_adds(OPJ_UINT32 a, OPJ_UINT32 b) } /** + Get the saturated difference of two unsigned integers + @return Returns saturated sum of a-b + */ +static INLINE OPJ_UINT32 opj_uint_subs(OPJ_UINT32 a, OPJ_UINT32 b) +{ + return (a >= b) ? a - b : 0; +} + +/** Clamp an integer inside an interval @return <ul> @@ -115,6 +124,28 @@ static INLINE OPJ_INT32 opj_int_clamp(OPJ_INT32 a, OPJ_INT32 min, } return a; } + +/** +Clamp an integer inside an interval +@return +<ul> +<li>Returns a if (min < a < max) +<li>Returns max if (a > max) +<li>Returns min if (a < min) +</ul> +*/ +static INLINE OPJ_INT64 opj_int64_clamp(OPJ_INT64 a, OPJ_INT64 min, + OPJ_INT64 max) +{ + if (a < min) { + return min; + } + if (a > max) { + return max; + } + return a; +} + /** @return Get absolute value of integer */ diff --git a/openjpeg/src/lib/openjp2/sparse_array.c b/openjpeg/src/lib/openjp2/sparse_array.c new file mode 100644 index 000000000..73192924e --- /dev/null +++ b/openjpeg/src/lib/openjp2/sparse_array.c @@ -0,0 +1,346 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2017, IntoPix SA <contact@intopix.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + + +struct opj_sparse_array_int32 { + OPJ_UINT32 width; + OPJ_UINT32 height; + OPJ_UINT32 block_width; + OPJ_UINT32 block_height; + OPJ_UINT32 block_count_hor; + OPJ_UINT32 block_count_ver; + OPJ_INT32** data_blocks; +}; + +opj_sparse_array_int32_t* opj_sparse_array_int32_create(OPJ_UINT32 width, + OPJ_UINT32 height, + OPJ_UINT32 block_width, + OPJ_UINT32 block_height) +{ + opj_sparse_array_int32_t* sa; + + if (width == 0 || height == 0 || block_width == 0 || block_height == 0) { + return NULL; + } + if (block_width > ((OPJ_UINT32)~0U) / block_height / sizeof(OPJ_INT32)) { + return NULL; + } + + sa = (opj_sparse_array_int32_t*) opj_calloc(1, + sizeof(opj_sparse_array_int32_t)); + sa->width = width; + sa->height = height; + sa->block_width = block_width; + sa->block_height = block_height; + sa->block_count_hor = opj_uint_ceildiv(width, block_width); + sa->block_count_ver = opj_uint_ceildiv(height, block_height); + if (sa->block_count_hor > ((OPJ_UINT32)~0U) / sa->block_count_ver) { + opj_free(sa); + return NULL; + } + sa->data_blocks = (OPJ_INT32**) opj_calloc(sizeof(OPJ_INT32*), + sa->block_count_hor * sa->block_count_ver); + if (sa->data_blocks == NULL) { + opj_free(sa); + return NULL; + } + + return sa; +} + +void opj_sparse_array_int32_free(opj_sparse_array_int32_t* sa) +{ + if (sa) { + OPJ_UINT32 i; + for (i = 0; i < sa->block_count_hor * sa->block_count_ver; i++) { + if (sa->data_blocks[i]) { + opj_free(sa->data_blocks[i]); + } + } + opj_free(sa->data_blocks); + opj_free(sa); + } +} + +OPJ_BOOL opj_sparse_array_is_region_valid(const opj_sparse_array_int32_t* sa, + OPJ_UINT32 x0, + OPJ_UINT32 y0, + OPJ_UINT32 x1, + OPJ_UINT32 y1) +{ + return !(x0 >= sa->width || x1 <= x0 || x1 > sa->width || + y0 >= sa->height || y1 <= y0 || y1 > sa->height); +} + +static OPJ_BOOL opj_sparse_array_int32_read_or_write( + const opj_sparse_array_int32_t* sa, + OPJ_UINT32 x0, + OPJ_UINT32 y0, + OPJ_UINT32 x1, + OPJ_UINT32 y1, + OPJ_INT32* buf, + OPJ_UINT32 buf_col_stride, + OPJ_UINT32 buf_line_stride, + OPJ_BOOL forgiving, + OPJ_BOOL is_read_op) +{ + OPJ_UINT32 y, block_y; + OPJ_UINT32 y_incr = 0; + const OPJ_UINT32 block_width = sa->block_width; + + if (!opj_sparse_array_is_region_valid(sa, x0, y0, x1, y1)) { + return forgiving; + } + + block_y = y0 / sa->block_height; + for (y = y0; y < y1; block_y ++, y += y_incr) { + OPJ_UINT32 x, block_x; + OPJ_UINT32 x_incr = 0; + OPJ_UINT32 block_y_offset; + y_incr = (y == y0) ? sa->block_height - (y0 % sa->block_height) : + sa->block_height; + block_y_offset = sa->block_height - y_incr; + y_incr = opj_uint_min(y_incr, y1 - y); + block_x = x0 / block_width; + for (x = x0; x < x1; block_x ++, x += x_incr) { + OPJ_UINT32 j; + OPJ_UINT32 block_x_offset; + OPJ_INT32* src_block; + x_incr = (x == x0) ? block_width - (x0 % block_width) : block_width; + block_x_offset = block_width - x_incr; + x_incr = opj_uint_min(x_incr, x1 - x); + src_block = sa->data_blocks[block_y * sa->block_count_hor + block_x]; + if (is_read_op) { + if (src_block == NULL) { + if (buf_col_stride == 1) { + OPJ_INT32* dest_ptr = buf + (y - y0) * (OPJ_SIZE_T)buf_line_stride + + (x - x0) * buf_col_stride; + for (j = 0; j < y_incr; j++) { + memset(dest_ptr, 0, sizeof(OPJ_INT32) * x_incr); + dest_ptr += buf_line_stride; + } + } else { + OPJ_INT32* dest_ptr = buf + (y - y0) * (OPJ_SIZE_T)buf_line_stride + + (x - x0) * buf_col_stride; + for (j = 0; j < y_incr; j++) { + OPJ_UINT32 k; + for (k = 0; k < x_incr; k++) { + dest_ptr[k * buf_col_stride] = 0; + } + dest_ptr += buf_line_stride; + } + } + } else { + const OPJ_INT32* OPJ_RESTRICT src_ptr = src_block + block_y_offset * + (OPJ_SIZE_T)block_width + block_x_offset; + if (buf_col_stride == 1) { + OPJ_INT32* OPJ_RESTRICT dest_ptr = buf + (y - y0) * (OPJ_SIZE_T)buf_line_stride + + + (x - x0) * buf_col_stride; + if (x_incr == 4) { + /* Same code as general branch, but the compiler */ + /* can have an efficient memcpy() */ + (void)(x_incr); /* trick to silent cppcheck duplicateBranch warning */ + for (j = 0; j < y_incr; j++) { + memcpy(dest_ptr, src_ptr, sizeof(OPJ_INT32) * x_incr); + dest_ptr += buf_line_stride; + src_ptr += block_width; + } + } else { + for (j = 0; j < y_incr; j++) { + memcpy(dest_ptr, src_ptr, sizeof(OPJ_INT32) * x_incr); + dest_ptr += buf_line_stride; + src_ptr += block_width; + } + } + } else { + OPJ_INT32* OPJ_RESTRICT dest_ptr = buf + (y - y0) * (OPJ_SIZE_T)buf_line_stride + + + (x - x0) * buf_col_stride; + if (x_incr == 1) { + for (j = 0; j < y_incr; j++) { + *dest_ptr = *src_ptr; + dest_ptr += buf_line_stride; + src_ptr += block_width; + } + } else if (y_incr == 1 && buf_col_stride == 2) { + OPJ_UINT32 k; + for (k = 0; k < (x_incr & ~3U); k += 4) { + dest_ptr[k * buf_col_stride] = src_ptr[k]; + dest_ptr[(k + 1) * buf_col_stride] = src_ptr[k + 1]; + dest_ptr[(k + 2) * buf_col_stride] = src_ptr[k + 2]; + dest_ptr[(k + 3) * buf_col_stride] = src_ptr[k + 3]; + } + for (; k < x_incr; k++) { + dest_ptr[k * buf_col_stride] = src_ptr[k]; + } + } else if (x_incr >= 8 && buf_col_stride == 8) { + for (j = 0; j < y_incr; j++) { + OPJ_UINT32 k; + for (k = 0; k < (x_incr & ~3U); k += 4) { + dest_ptr[k * buf_col_stride] = src_ptr[k]; + dest_ptr[(k + 1) * buf_col_stride] = src_ptr[k + 1]; + dest_ptr[(k + 2) * buf_col_stride] = src_ptr[k + 2]; + dest_ptr[(k + 3) * buf_col_stride] = src_ptr[k + 3]; + } + for (; k < x_incr; k++) { + dest_ptr[k * buf_col_stride] = src_ptr[k]; + } + dest_ptr += buf_line_stride; + src_ptr += block_width; + } + } else { + /* General case */ + for (j = 0; j < y_incr; j++) { + OPJ_UINT32 k; + for (k = 0; k < x_incr; k++) { + dest_ptr[k * buf_col_stride] = src_ptr[k]; + } + dest_ptr += buf_line_stride; + src_ptr += block_width; + } + } + } + } + } else { + if (src_block == NULL) { + src_block = (OPJ_INT32*) opj_calloc(1, + sa->block_width * sa->block_height * sizeof(OPJ_INT32)); + if (src_block == NULL) { + return OPJ_FALSE; + } + sa->data_blocks[block_y * sa->block_count_hor + block_x] = src_block; + } + + if (buf_col_stride == 1) { + OPJ_INT32* OPJ_RESTRICT dest_ptr = src_block + block_y_offset * + (OPJ_SIZE_T)block_width + block_x_offset; + const OPJ_INT32* OPJ_RESTRICT src_ptr = buf + (y - y0) * + (OPJ_SIZE_T)buf_line_stride + (x - x0) * buf_col_stride; + if (x_incr == 4) { + /* Same code as general branch, but the compiler */ + /* can have an efficient memcpy() */ + (void)(x_incr); /* trick to silent cppcheck duplicateBranch warning */ + for (j = 0; j < y_incr; j++) { + memcpy(dest_ptr, src_ptr, sizeof(OPJ_INT32) * x_incr); + dest_ptr += block_width; + src_ptr += buf_line_stride; + } + } else { + for (j = 0; j < y_incr; j++) { + memcpy(dest_ptr, src_ptr, sizeof(OPJ_INT32) * x_incr); + dest_ptr += block_width; + src_ptr += buf_line_stride; + } + } + } else { + OPJ_INT32* OPJ_RESTRICT dest_ptr = src_block + block_y_offset * + (OPJ_SIZE_T)block_width + block_x_offset; + const OPJ_INT32* OPJ_RESTRICT src_ptr = buf + (y - y0) * + (OPJ_SIZE_T)buf_line_stride + (x - x0) * buf_col_stride; + if (x_incr == 1) { + for (j = 0; j < y_incr; j++) { + *dest_ptr = *src_ptr; + src_ptr += buf_line_stride; + dest_ptr += block_width; + } + } else if (x_incr >= 8 && buf_col_stride == 8) { + for (j = 0; j < y_incr; j++) { + OPJ_UINT32 k; + for (k = 0; k < (x_incr & ~3U); k += 4) { + dest_ptr[k] = src_ptr[k * buf_col_stride]; + dest_ptr[k + 1] = src_ptr[(k + 1) * buf_col_stride]; + dest_ptr[k + 2] = src_ptr[(k + 2) * buf_col_stride]; + dest_ptr[k + 3] = src_ptr[(k + 3) * buf_col_stride]; + } + for (; k < x_incr; k++) { + dest_ptr[k] = src_ptr[k * buf_col_stride]; + } + src_ptr += buf_line_stride; + dest_ptr += block_width; + } + } else { + /* General case */ + for (j = 0; j < y_incr; j++) { + OPJ_UINT32 k; + for (k = 0; k < x_incr; k++) { + dest_ptr[k] = src_ptr[k * buf_col_stride]; + } + src_ptr += buf_line_stride; + dest_ptr += block_width; + } + } + } + } + } + } + + return OPJ_TRUE; +} + +OPJ_BOOL opj_sparse_array_int32_read(const opj_sparse_array_int32_t* sa, + OPJ_UINT32 x0, + OPJ_UINT32 y0, + OPJ_UINT32 x1, + OPJ_UINT32 y1, + OPJ_INT32* dest, + OPJ_UINT32 dest_col_stride, + OPJ_UINT32 dest_line_stride, + OPJ_BOOL forgiving) +{ + return opj_sparse_array_int32_read_or_write( + (opj_sparse_array_int32_t*)sa, x0, y0, x1, y1, + dest, + dest_col_stride, + dest_line_stride, + forgiving, + OPJ_TRUE); +} + +OPJ_BOOL opj_sparse_array_int32_write(opj_sparse_array_int32_t* sa, + OPJ_UINT32 x0, + OPJ_UINT32 y0, + OPJ_UINT32 x1, + OPJ_UINT32 y1, + const OPJ_INT32* src, + OPJ_UINT32 src_col_stride, + OPJ_UINT32 src_line_stride, + OPJ_BOOL forgiving) +{ + return opj_sparse_array_int32_read_or_write(sa, x0, y0, x1, y1, + (OPJ_INT32*)src, + src_col_stride, + src_line_stride, + forgiving, + OPJ_FALSE); +} diff --git a/openjpeg/src/lib/openjp2/sparse_array.h b/openjpeg/src/lib/openjp2/sparse_array.h new file mode 100644 index 000000000..fd927eaa0 --- /dev/null +++ b/openjpeg/src/lib/openjp2/sparse_array.h @@ -0,0 +1,141 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2017, IntoPix SA <contact@intopix.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opj_includes.h" + +#ifndef OPJ_SPARSE_ARRAY_H +#define OPJ_SPARSE_ARRAY_H +/** +@file sparse_array.h +@brief Sparse array management + +The functions in this file manage sparse arrays. Sparse arrays are arrays with +potential big dimensions, but with very few samples actually set. Such sparse +arrays require allocating a low amount of memory, by just allocating memory +for blocks of the array that are set. The minimum memory allocation unit is a +a block. There is a trade-off to pick up an appropriate dimension for blocks. +If it is too big, and pixels set are far from each other, too much memory will +be used. If blocks are too small, the book-keeping costs of blocks will raise. +*/ + +/** @defgroup SPARSE_ARRAY SPARSE ARRAYS - Sparse arrays */ +/*@{*/ + +/** Opaque type for sparse arrays that contain int32 values */ +typedef struct opj_sparse_array_int32 opj_sparse_array_int32_t; + +/** Creates a new sparse array. + * @param width total width of the array. + * @param height total height of the array + * @param block_width width of a block. + * @param block_height height of a block. + * @return a new sparse array instance, or NULL in case of failure. + */ +opj_sparse_array_int32_t* opj_sparse_array_int32_create(OPJ_UINT32 width, + OPJ_UINT32 height, + OPJ_UINT32 block_width, + OPJ_UINT32 block_height); + +/** Frees a sparse array. + * @param sa sparse array instance. + */ +void opj_sparse_array_int32_free(opj_sparse_array_int32_t* sa); + +/** Returns whether region bounds are valid (non empty and within array bounds) + * @param sa sparse array instance. + * @param x0 left x coordinate of the region. + * @param y0 top x coordinate of the region. + * @param x1 right x coordinate (not included) of the region. Must be greater than x0. + * @param y1 bottom y coordinate (not included) of the region. Must be greater than y0. + * @return OPJ_TRUE or OPJ_FALSE. + */ +OPJ_BOOL opj_sparse_array_is_region_valid(const opj_sparse_array_int32_t* sa, + OPJ_UINT32 x0, + OPJ_UINT32 y0, + OPJ_UINT32 x1, + OPJ_UINT32 y1); + +/** Read the content of a rectangular region of the sparse array into a + * user buffer. + * + * Regions not written with opj_sparse_array_int32_write() are read as 0. + * + * @param sa sparse array instance. + * @param x0 left x coordinate of the region to read in the sparse array. + * @param y0 top x coordinate of the region to read in the sparse array. + * @param x1 right x coordinate (not included) of the region to read in the sparse array. Must be greater than x0. + * @param y1 bottom y coordinate (not included) of the region to read in the sparse array. Must be greater than y0. + * @param dest user buffer to fill. Must be at least sizeof(int32) * ( (y1 - y0 - 1) * dest_line_stride + (x1 - x0 - 1) * dest_col_stride + 1) bytes large. + * @param dest_col_stride spacing (in elements, not in bytes) in x dimension between consecutive elements of the user buffer. + * @param dest_line_stride spacing (in elements, not in bytes) in y dimension between consecutive elements of the user buffer. + * @param forgiving if set to TRUE and the region is invalid, OPJ_TRUE will still be returned. + * @return OPJ_TRUE in case of success. + */ +OPJ_BOOL opj_sparse_array_int32_read(const opj_sparse_array_int32_t* sa, + OPJ_UINT32 x0, + OPJ_UINT32 y0, + OPJ_UINT32 x1, + OPJ_UINT32 y1, + OPJ_INT32* dest, + OPJ_UINT32 dest_col_stride, + OPJ_UINT32 dest_line_stride, + OPJ_BOOL forgiving); + + +/** Write the content of a rectangular region into the sparse array from a + * user buffer. + * + * Blocks intersecting the region are allocated, if not already done. + * + * @param sa sparse array instance. + * @param x0 left x coordinate of the region to write into the sparse array. + * @param y0 top x coordinate of the region to write into the sparse array. + * @param x1 right x coordinate (not included) of the region to write into the sparse array. Must be greater than x0. + * @param y1 bottom y coordinate (not included) of the region to write into the sparse array. Must be greater than y0. + * @param src user buffer to fill. Must be at least sizeof(int32) * ( (y1 - y0 - 1) * src_line_stride + (x1 - x0 - 1) * src_col_stride + 1) bytes large. + * @param src_col_stride spacing (in elements, not in bytes) in x dimension between consecutive elements of the user buffer. + * @param src_line_stride spacing (in elements, not in bytes) in y dimension between consecutive elements of the user buffer. + * @param forgiving if set to TRUE and the region is invalid, OPJ_TRUE will still be returned. + * @return OPJ_TRUE in case of success. + */ +OPJ_BOOL opj_sparse_array_int32_write(opj_sparse_array_int32_t* sa, + OPJ_UINT32 x0, + OPJ_UINT32 y0, + OPJ_UINT32 x1, + OPJ_UINT32 y1, + const OPJ_INT32* src, + OPJ_UINT32 src_col_stride, + OPJ_UINT32 src_line_stride, + OPJ_BOOL forgiving); + +/*@}*/ + +#endif /* OPJ_SPARSE_ARRAY_H */ diff --git a/openjpeg/src/lib/openjp2/t1.c b/openjpeg/src/lib/openjp2/t1.c index bd1a88002..76744380f 100644 --- a/openjpeg/src/lib/openjp2/t1.c +++ b/openjpeg/src/lib/openjp2/t1.c @@ -38,7 +38,20 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#define OPJ_SKIP_POISON #include "opj_includes.h" + +#ifdef __SSE__ +#include <xmmintrin.h> +#endif +#ifdef __SSE2__ +#include <emmintrin.h> +#endif + +#if defined(__GNUC__) +#pragma GCC poison malloc calloc realloc free +#endif + #include "t1_luts.h" /** @defgroup T1 T1 - Implementation of the tier-1 coding */ @@ -335,7 +348,7 @@ static INLINE void opj_t1_enc_sigpass_step(opj_t1_t *t1, if ((flags & ((T1_SIGMA_THIS | T1_PI_THIS) << (ci * 3U))) == 0U && (flags & (T1_SIGMA_NEIGHBOURS << (ci * 3U))) != 0U) { OPJ_UINT32 ctxt1 = opj_t1_getctxno_zc(mqc, flags >> (ci * 3U)); - v = opj_int_abs(*datap) & one ? 1 : 0; + v = (opj_int_abs(*datap) & one) ? 1 : 0; #ifdef DEBUG_ENC_SIG fprintf(stderr, " ctxt1=%d\n", ctxt1); #endif @@ -722,7 +735,7 @@ static INLINE void opj_t1_enc_refpass_step(opj_t1_t *t1, OPJ_UINT32 ctxt = opj_t1_getctxno_mag(shift_flags); *nmsedec += opj_t1_getnmsedec_ref((OPJ_UINT32)opj_int_abs(*datap), (OPJ_UINT32)bpno); - v = opj_int_abs(*datap) & one ? 1 : 0; + v = (opj_int_abs(*datap) & one) ? 1 : 0; #ifdef DEBUG_ENC_REF fprintf(stderr, " ctxt=%d\n", ctxt); #endif @@ -1052,6 +1065,7 @@ static void opj_t1_enc_clnpass_step( for (ci = runlen; ci < lim; ++ci) { OPJ_UINT32 vsc; opj_flag_t flags; + OPJ_UINT32 ctxt1; flags = *flagsp; @@ -1060,12 +1074,12 @@ static void opj_t1_enc_clnpass_step( } if (!(flags & ((T1_SIGMA_THIS | T1_PI_THIS) << (ci * 3U)))) { - OPJ_UINT32 ctxt1 = opj_t1_getctxno_zc(mqc, flags >> (ci * 3U)); + ctxt1 = opj_t1_getctxno_zc(mqc, flags >> (ci * 3U)); #ifdef DEBUG_ENC_CLN printf(" ctxt1=%d\n", ctxt1); #endif opj_mqc_setcurctx(mqc, ctxt1); - v = opj_int_abs(*datap) & one ? 1 : 0; + v = (opj_int_abs(*datap) & one) ? 1 : 0; opj_mqc_encode(mqc, v); if (v) { OPJ_UINT32 ctxt2, spb; @@ -1426,44 +1440,27 @@ static OPJ_BOOL opj_t1_allocate_buffers( OPJ_UINT32 w, OPJ_UINT32 h) { - size_t flagssize; + OPJ_UINT32 flagssize; OPJ_UINT32 flags_stride; + /* No risk of overflow. Prior checks ensure those assert are met */ + /* They are per the specification */ + assert(w <= 1024); + assert(h <= 1024); + assert(w * h <= 4096); + /* encoder uses tile buffer, so no need to allocate */ if (!t1->encoder) { - size_t datasize; - -#if (SIZE_MAX / 0xFFFFFFFFU) < 0xFFFFFFFFU /* UINT32_MAX */ - /* Overflow check */ - if ((w > 0U) && ((size_t)h > (SIZE_MAX / (size_t)w))) { - /* FIXME event manager error callback */ - return OPJ_FALSE; - } -#endif - datasize = (size_t)w * h; + OPJ_UINT32 datasize = w * h; - /* Overflow check */ - if (datasize > (SIZE_MAX / sizeof(OPJ_INT32))) { - /* FIXME event manager error callback */ - return OPJ_FALSE; - } - - if (datasize > (size_t)t1->datasize) { + if (datasize > t1->datasize) { opj_aligned_free(t1->data); t1->data = (OPJ_INT32*) opj_aligned_malloc(datasize * sizeof(OPJ_INT32)); if (!t1->data) { /* FIXME event manager error callback */ return OPJ_FALSE; } -#if SIZE_MAX > 0xFFFFFFFFU /* UINT32_MAX */ - /* TODO remove this if t1->datasize type changes to size_t */ - /* Overflow check */ - if (datasize > (size_t)0xFFFFFFFFU /* UINT32_MAX */) { - /* FIXME event manager error callback */ - return OPJ_FALSE; - } -#endif - t1->datasize = (OPJ_UINT32)datasize; + t1->datasize = datasize; } /* memset first arg is declared to never be null by gcc */ if (t1->data != NULL) { @@ -1471,40 +1468,18 @@ static OPJ_BOOL opj_t1_allocate_buffers( } } - /* Overflow check */ - if (w > (0xFFFFFFFFU /* UINT32_MAX */ - 2U)) { - /* FIXME event manager error callback */ - return OPJ_FALSE; - } flags_stride = w + 2U; /* can't be 0U */ -#if (SIZE_MAX - 3U) < 0xFFFFFFFFU /* UINT32_MAX */ - /* Overflow check */ - if (h > (0xFFFFFFFFU /* UINT32_MAX */ - 3U)) { - /* FIXME event manager error callback */ - return OPJ_FALSE; - } -#endif flagssize = (h + 3U) / 4U + 2U; - /* Overflow check */ - if (flagssize > (SIZE_MAX / (size_t)flags_stride)) { - /* FIXME event manager error callback */ - return OPJ_FALSE; - } - flagssize *= (size_t)flags_stride; + flagssize *= flags_stride; { - /* BIG FAT XXX */ opj_flag_t* p; OPJ_UINT32 x; OPJ_UINT32 flags_height = (h + 3U) / 4U; - if (flagssize > (size_t)t1->flagssize) { - /* Overflow check */ - if (flagssize > (SIZE_MAX / sizeof(opj_flag_t))) { - /* FIXME event manager error callback */ - return OPJ_FALSE; - } + if (flagssize > t1->flagssize) { + opj_aligned_free(t1->flags); t1->flags = (opj_flag_t*) opj_aligned_malloc(flagssize * sizeof( opj_flag_t)); @@ -1512,16 +1487,8 @@ static OPJ_BOOL opj_t1_allocate_buffers( /* FIXME event manager error callback */ return OPJ_FALSE; } -#if SIZE_MAX > 0xFFFFFFFFU /* UINT32_MAX */ - /* TODO remove this if t1->flagssize type changes to size_t */ - /* Overflow check */ - if (flagssize > (size_t)0xFFFFFFFFU /* UINT32_MAX */) { - /* FIXME event manager error callback */ - return OPJ_FALSE; - } -#endif } - t1->flagssize = (OPJ_UINT32)flagssize; + t1->flagssize = flagssize; memset(t1->flags, 0, flagssize * sizeof(opj_flag_t)); @@ -1610,6 +1577,7 @@ void opj_t1_destroy(opj_t1_t *p_t1) } typedef struct { + OPJ_BOOL whole_tile_decoding; OPJ_UINT32 resno; opj_tcd_cblk_dec_t* cblk; opj_tcd_band_t* band; @@ -1643,12 +1611,44 @@ static void opj_t1_clbl_decode_processor(void* user_data, opj_tls_t* tls) OPJ_UINT32 tile_w; job = (opj_t1_cblk_decode_processing_job_t*) user_data; - resno = job->resno; + cblk = job->cblk; + + if (!job->whole_tile_decoding) { + cblk_w = (OPJ_UINT32)(cblk->x1 - cblk->x0); + cblk_h = (OPJ_UINT32)(cblk->y1 - cblk->y0); + + cblk->decoded_data = (OPJ_INT32*)opj_aligned_malloc(cblk_w * cblk_h * sizeof( + OPJ_INT32)); + if (cblk->decoded_data == NULL) { + if (job->p_manager_mutex) { + opj_mutex_lock(job->p_manager_mutex); + } + opj_event_msg(job->p_manager, EVT_ERROR, + "Cannot allocate cblk->decoded_data\n"); + if (job->p_manager_mutex) { + opj_mutex_unlock(job->p_manager_mutex); + } + *(job->pret) = OPJ_FALSE; + opj_free(job); + return; + } + /* Zero-init required */ + memset(cblk->decoded_data, 0, cblk_w * cblk_h * sizeof(OPJ_INT32)); + } else if (cblk->decoded_data) { + /* Not sure if that code path can happen, but better be */ + /* safe than sorry */ + opj_aligned_free(cblk->decoded_data); + cblk->decoded_data = NULL; + } + + resno = job->resno; band = job->band; tilec = job->tilec; tccp = job->tccp; - tile_w = (OPJ_UINT32)(tilec->x1 - tilec->x0); + tile_w = (OPJ_UINT32)(tilec->resolutions[tilec->minimum_num_resolutions - 1].x1 + - + tilec->resolutions[tilec->minimum_num_resolutions - 1].x0); if (!*(job->pret)) { opj_free(job); @@ -1687,7 +1687,7 @@ static void opj_t1_clbl_decode_processor(void* user_data, opj_tls_t* tls) y += pres->y1 - pres->y0; } - datap = t1->data; + datap = cblk->decoded_data ? cblk->decoded_data : t1->data; cblk_w = t1->w; cblk_h = t1->h; @@ -1712,9 +1712,49 @@ static void opj_t1_clbl_decode_processor(void* user_data, opj_tls_t* tls) } } } - if (tccp->qmfbid == 1) { - OPJ_INT32* OPJ_RESTRICT tiledp = &tilec->data[(OPJ_UINT32)y * tile_w + - (OPJ_UINT32)x]; + + /* Both can be non NULL if for example decoding a full tile and then */ + /* partially a tile. In which case partial decoding should be the */ + /* priority */ + assert((cblk->decoded_data != NULL) || (tilec->data != NULL)); + + if (cblk->decoded_data) { + OPJ_UINT32 cblk_size = cblk_w * cblk_h; + if (tccp->qmfbid == 1) { + for (i = 0; i < cblk_size; ++i) { + datap[i] /= 2; + } + } else { /* if (tccp->qmfbid == 0) */ + i = 0; +#ifdef __SSE2__ + { + const __m128 xmm_stepsize = _mm_set1_ps(band->stepsize); + for (; i < (cblk_size & ~15U); i += 16) { + __m128 xmm0_data = _mm_cvtepi32_ps(_mm_load_si128((__m128i * const)( + datap + 0))); + __m128 xmm1_data = _mm_cvtepi32_ps(_mm_load_si128((__m128i * const)( + datap + 4))); + __m128 xmm2_data = _mm_cvtepi32_ps(_mm_load_si128((__m128i * const)( + datap + 8))); + __m128 xmm3_data = _mm_cvtepi32_ps(_mm_load_si128((__m128i * const)( + datap + 12))); + _mm_store_ps((float*)(datap + 0), _mm_mul_ps(xmm0_data, xmm_stepsize)); + _mm_store_ps((float*)(datap + 4), _mm_mul_ps(xmm1_data, xmm_stepsize)); + _mm_store_ps((float*)(datap + 8), _mm_mul_ps(xmm2_data, xmm_stepsize)); + _mm_store_ps((float*)(datap + 12), _mm_mul_ps(xmm3_data, xmm_stepsize)); + datap += 16; + } + } +#endif + for (; i < cblk_size; ++i) { + OPJ_FLOAT32 tmp = ((OPJ_FLOAT32)(*datap)) * band->stepsize; + memcpy(datap, &tmp, sizeof(tmp)); + datap++; + } + } + } else if (tccp->qmfbid == 1) { + OPJ_INT32* OPJ_RESTRICT tiledp = &tilec->data[(OPJ_SIZE_T)y * tile_w + + (OPJ_SIZE_T)x]; for (j = 0; j < cblk_h; ++j) { i = 0; for (; i < (cblk_w & ~(OPJ_UINT32)3U); i += 4U) { @@ -1722,19 +1762,19 @@ static void opj_t1_clbl_decode_processor(void* user_data, opj_tls_t* tls) OPJ_INT32 tmp1 = datap[(j * cblk_w) + i + 1U]; OPJ_INT32 tmp2 = datap[(j * cblk_w) + i + 2U]; OPJ_INT32 tmp3 = datap[(j * cblk_w) + i + 3U]; - ((OPJ_INT32*)tiledp)[(j * tile_w) + i + 0U] = tmp0 / 2; - ((OPJ_INT32*)tiledp)[(j * tile_w) + i + 1U] = tmp1 / 2; - ((OPJ_INT32*)tiledp)[(j * tile_w) + i + 2U] = tmp2 / 2; - ((OPJ_INT32*)tiledp)[(j * tile_w) + i + 3U] = tmp3 / 2; + ((OPJ_INT32*)tiledp)[(j * (OPJ_SIZE_T)tile_w) + i + 0U] = tmp0 / 2; + ((OPJ_INT32*)tiledp)[(j * (OPJ_SIZE_T)tile_w) + i + 1U] = tmp1 / 2; + ((OPJ_INT32*)tiledp)[(j * (OPJ_SIZE_T)tile_w) + i + 2U] = tmp2 / 2; + ((OPJ_INT32*)tiledp)[(j * (OPJ_SIZE_T)tile_w) + i + 3U] = tmp3 / 2; } for (; i < cblk_w; ++i) { OPJ_INT32 tmp = datap[(j * cblk_w) + i]; - ((OPJ_INT32*)tiledp)[(j * tile_w) + i] = tmp / 2; + ((OPJ_INT32*)tiledp)[(j * (OPJ_SIZE_T)tile_w) + i] = tmp / 2; } } } else { /* if (tccp->qmfbid == 0) */ - OPJ_FLOAT32* OPJ_RESTRICT tiledp = (OPJ_FLOAT32*) &tilec->data[(OPJ_UINT32)y * - tile_w + (OPJ_UINT32)x]; + OPJ_FLOAT32* OPJ_RESTRICT tiledp = (OPJ_FLOAT32*) &tilec->data[(OPJ_SIZE_T)y * + tile_w + (OPJ_SIZE_T)x]; for (j = 0; j < cblk_h; ++j) { OPJ_FLOAT32* OPJ_RESTRICT tiledp2 = tiledp; for (i = 0; i < cblk_w; ++i) { @@ -1751,7 +1791,7 @@ static void opj_t1_clbl_decode_processor(void* user_data, opj_tls_t* tls) } -void opj_t1_decode_cblks(opj_thread_pool_t* tp, +void opj_t1_decode_cblks(opj_tcd_t* tcd, volatile OPJ_BOOL* pret, opj_tcd_tilecomp_t* tilec, opj_tccp_t* tccp, @@ -1760,8 +1800,14 @@ void opj_t1_decode_cblks(opj_thread_pool_t* tp, OPJ_BOOL check_pterm ) { + opj_thread_pool_t* tp = tcd->thread_pool; OPJ_UINT32 resno, bandno, precno, cblkno; +#ifdef DEBUG_VERBOSE + OPJ_UINT32 codeblocks_decoded = 0; + printf("Enter opj_t1_decode_cblks()\n"); +#endif + for (resno = 0; resno < tilec->minimum_num_resolutions; ++resno) { opj_tcd_resolution_t* res = &tilec->resolutions[resno]; @@ -1771,16 +1817,77 @@ void opj_t1_decode_cblks(opj_thread_pool_t* tp, for (precno = 0; precno < res->pw * res->ph; ++precno) { opj_tcd_precinct_t* precinct = &band->precincts[precno]; + if (!opj_tcd_is_subband_area_of_interest(tcd, + tilec->compno, + resno, + band->bandno, + (OPJ_UINT32)precinct->x0, + (OPJ_UINT32)precinct->y0, + (OPJ_UINT32)precinct->x1, + (OPJ_UINT32)precinct->y1)) { + for (cblkno = 0; cblkno < precinct->cw * precinct->ch; ++cblkno) { + opj_tcd_cblk_dec_t* cblk = &precinct->cblks.dec[cblkno]; + if (cblk->decoded_data) { +#ifdef DEBUG_VERBOSE + printf("Discarding codeblock %d,%d at resno=%d, bandno=%d\n", + cblk->x0, cblk->y0, resno, bandno); +#endif + opj_aligned_free(cblk->decoded_data); + cblk->decoded_data = NULL; + } + } + continue; + } + for (cblkno = 0; cblkno < precinct->cw * precinct->ch; ++cblkno) { opj_tcd_cblk_dec_t* cblk = &precinct->cblks.dec[cblkno]; opj_t1_cblk_decode_processing_job_t* job; + if (!opj_tcd_is_subband_area_of_interest(tcd, + tilec->compno, + resno, + band->bandno, + (OPJ_UINT32)cblk->x0, + (OPJ_UINT32)cblk->y0, + (OPJ_UINT32)cblk->x1, + (OPJ_UINT32)cblk->y1)) { + if (cblk->decoded_data) { +#ifdef DEBUG_VERBOSE + printf("Discarding codeblock %d,%d at resno=%d, bandno=%d\n", + cblk->x0, cblk->y0, resno, bandno); +#endif + opj_aligned_free(cblk->decoded_data); + cblk->decoded_data = NULL; + } + continue; + } + + if (!tcd->whole_tile_decoding) { + OPJ_UINT32 cblk_w = (OPJ_UINT32)(cblk->x1 - cblk->x0); + OPJ_UINT32 cblk_h = (OPJ_UINT32)(cblk->y1 - cblk->y0); + if (cblk->decoded_data != NULL) { +#ifdef DEBUG_VERBOSE + printf("Reusing codeblock %d,%d at resno=%d, bandno=%d\n", + cblk->x0, cblk->y0, resno, bandno); +#endif + continue; + } + if (cblk_w == 0 || cblk_h == 0) { + continue; + } +#ifdef DEBUG_VERBOSE + printf("Decoding codeblock %d,%d at resno=%d, bandno=%d\n", + cblk->x0, cblk->y0, resno, bandno); +#endif + } + job = (opj_t1_cblk_decode_processing_job_t*) opj_calloc(1, sizeof(opj_t1_cblk_decode_processing_job_t)); if (!job) { *pret = OPJ_FALSE; return; } + job->whole_tile_decoding = tcd->whole_tile_decoding; job->resno = resno; job->cblk = cblk; job->band = band; @@ -1792,6 +1899,9 @@ void opj_t1_decode_cblks(opj_thread_pool_t* tp, job->check_pterm = check_pterm; job->mustuse_cblkdatabuffer = opj_thread_pool_get_thread_count(tp) > 1; opj_thread_pool_submit_job(tp, opj_t1_clbl_decode_processor, job); +#ifdef DEBUG_VERBOSE + codeblocks_decoded ++; +#endif if (!(*pret)) { return; } @@ -1800,6 +1910,9 @@ void opj_t1_decode_cblks(opj_thread_pool_t* tp, } /* bandno */ } /* resno */ +#ifdef DEBUG_VERBOSE + printf("Leave opj_t1_decode_cblks(). Number decoded: %d\n", codeblocks_decoded); +#endif return; } @@ -1821,6 +1934,7 @@ static OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1, OPJ_BYTE* cblkdata = NULL; OPJ_UINT32 cblkdataindex = 0; OPJ_BYTE type = T1_TYPE_MQ; /* BYPASS mode */ + OPJ_INT32* original_t1_data = NULL; mqc->lut_ctxno_zc_orient = lut_ctxno_zc + (orient << 9); @@ -1885,6 +1999,17 @@ static OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1, } } else if (cblk->numchunks == 1) { cblkdata = cblk->chunks[0].data; + } else { + /* Not sure if that can happen in practice, but avoid Coverity to */ + /* think we will dereference a null cblkdta pointer */ + return OPJ_TRUE; + } + + /* For subtile decoding, directly decode in the decoded_data buffer of */ + /* the code-block. Hack t1->data to point to it, and restore it later */ + if (cblk->decoded_data) { + original_t1_data = t1->data; + t1->data = cblk->decoded_data; } for (segno = 0; segno < cblk->real_num_segs; ++segno) { @@ -1966,6 +2091,11 @@ static OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1, } } + /* Restore original t1->data is needed */ + if (cblk->decoded_data) { + t1->data = original_t1_data; + } + return OPJ_TRUE; } @@ -2009,7 +2139,8 @@ OPJ_BOOL opj_t1_encode_cblks(opj_t1_t *t1, OPJ_INT32* OPJ_RESTRICT tiledp; OPJ_UINT32 cblk_w; OPJ_UINT32 cblk_h; - OPJ_UINT32 i, j, tileIndex = 0, tileLineAdvance; + OPJ_UINT32 i, j, tileLineAdvance; + OPJ_SIZE_T tileIndex = 0; OPJ_INT32 x = cblk->x0 - band->x0; OPJ_INT32 y = cblk->y0 - band->y0; @@ -2033,7 +2164,7 @@ OPJ_BOOL opj_t1_encode_cblks(opj_t1_t *t1, cblk_h = t1->h; tileLineAdvance = tile_w - cblk_w; - tiledp = &tilec->data[(OPJ_UINT32)y * tile_w + (OPJ_UINT32)x]; + tiledp = &tilec->data[(OPJ_SIZE_T)y * tile_w + (OPJ_SIZE_T)x]; t1->data = tiledp; t1->data_stride = tile_w; if (tccp->qmfbid == 1) { @@ -2155,6 +2286,10 @@ static void opj_t1_encode_cblk(opj_t1_t *t1, cblk->numbps = max ? (OPJ_UINT32)((opj_int_floorlog2(max) + 1) - T1_NMSEDEC_FRACBITS) : 0; + if (cblk->numbps == 0) { + cblk->totalpasses = 0; + return; + } bpno = (OPJ_INT32)(cblk->numbps - 1); passtype = 2; diff --git a/openjpeg/src/lib/openjp2/t1.h b/openjpeg/src/lib/openjp2/t1.h index 5aa6a07bf..171dfb0a7 100644 --- a/openjpeg/src/lib/openjp2/t1.h +++ b/openjpeg/src/lib/openjp2/t1.h @@ -230,7 +230,7 @@ OPJ_BOOL opj_t1_encode_cblks(opj_t1_t *t1, /** Decode the code-blocks of a tile -@param tp Thread pool +@param tcd TCD handle @param pret Pointer to return value @param tilec The tile to decode @param tccp Tile coding parameters @@ -238,7 +238,7 @@ Decode the code-blocks of a tile @param p_manager_mutex mutex for the event manager @param check_pterm whether PTERM correct termination should be checked */ -void opj_t1_decode_cblks(opj_thread_pool_t* tp, +void opj_t1_decode_cblks(opj_tcd_t* tcd, volatile OPJ_BOOL* pret, opj_tcd_tilecomp_t* tilec, opj_tccp_t* tccp, diff --git a/openjpeg/src/lib/openjp2/t2.c b/openjpeg/src/lib/openjp2/t2.c index 1cc60dec2..c7a3ceed1 100644 --- a/openjpeg/src/lib/openjp2/t2.c +++ b/openjpeg/src/lib/openjp2/t2.c @@ -13,6 +13,7 @@ * Copyright (c) 2005, Herve Drolon, FreeImage Team * Copyright (c) 2008, 2011-2012, Centre National d'Etudes Spatiales (CNES), FR * Copyright (c) 2012, CS Systemes d'Information, France + * Copyright (c) 2017, IntoPIX SA <support@intopix.com> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -68,6 +69,8 @@ Encode a packet of a tile to a destination buffer @param p_data_written FIXME DOC @param len Length of the destination buffer @param cstr_info Codestream information structure +@param p_t2_mode If == THRESH_CALC In Threshold calculation ,If == FINAL_PASS Final pass +@param p_manager the user event manager @return */ static OPJ_BOOL opj_t2_encode_packet(OPJ_UINT32 tileno, @@ -77,7 +80,9 @@ static OPJ_BOOL opj_t2_encode_packet(OPJ_UINT32 tileno, OPJ_BYTE *dest, OPJ_UINT32 * p_data_written, OPJ_UINT32 len, - opj_codestream_info_t *cstr_info); + opj_codestream_info_t *cstr_info, + J2K_T2_MODE p_t2_mode, + opj_event_mgr_t *p_manager); /** Decode a packet of a tile from a source buffer @@ -222,7 +227,8 @@ OPJ_BOOL opj_t2_encode_packets(opj_t2_t* p_t2, OPJ_UINT32 p_tp_num, OPJ_INT32 p_tp_pos, OPJ_UINT32 p_pino, - J2K_T2_MODE p_t2_mode) + J2K_T2_MODE p_t2_mode, + opj_event_mgr_t *p_manager) { OPJ_BYTE *l_current_data = p_dest; OPJ_UINT32 l_nb_bytes = 0; @@ -268,7 +274,10 @@ OPJ_BOOL opj_t2_encode_packets(opj_t2_t* p_t2, l_nb_bytes = 0; if (! opj_t2_encode_packet(p_tile_no, p_tile, l_tcp, l_current_pi, - l_current_data, &l_nb_bytes, p_max_len, cstr_info)) { + l_current_data, &l_nb_bytes, + p_max_len, cstr_info, + p_t2_mode, + p_manager)) { opj_pi_destroy(l_pi, l_nb_pocs); return OPJ_FALSE; } @@ -306,7 +315,8 @@ OPJ_BOOL opj_t2_encode_packets(opj_t2_t* p_t2, l_nb_bytes = 0; if (! opj_t2_encode_packet(p_tile_no, p_tile, l_tcp, l_current_pi, - l_current_data, &l_nb_bytes, p_max_len, cstr_info)) { + l_current_data, &l_nb_bytes, p_max_len, + cstr_info, p_t2_mode, p_manager)) { opj_pi_destroy(l_pi, l_nb_pocs); return OPJ_FALSE; } @@ -360,7 +370,8 @@ static void opj_null_jas_fprintf(FILE* file, const char * format, ...) #define JAS_FPRINTF opj_null_jas_fprintf #endif -OPJ_BOOL opj_t2_decode_packets(opj_t2_t *p_t2, +OPJ_BOOL opj_t2_decode_packets(opj_tcd_t* tcd, + opj_t2_t *p_t2, OPJ_UINT32 p_tile_no, opj_tcd_tile_t *p_tile, OPJ_BYTE *p_src, @@ -425,14 +436,54 @@ OPJ_BOOL opj_t2_decode_packets(opj_t2_t *p_t2, memset(first_pass_failed, OPJ_TRUE, l_image->numcomps * sizeof(OPJ_BOOL)); while (opj_pi_next(l_current_pi)) { + OPJ_BOOL skip_packet = OPJ_FALSE; JAS_FPRINTF(stderr, "packet offset=00000166 prg=%d cmptno=%02d rlvlno=%02d prcno=%03d lyrno=%02d\n\n", l_current_pi->poc.prg1, l_current_pi->compno, l_current_pi->resno, l_current_pi->precno, l_current_pi->layno); - if (l_tcp->num_layers_to_decode > l_current_pi->layno - && l_current_pi->resno < - p_tile->comps[l_current_pi->compno].minimum_num_resolutions) { + /* If the packet layer is greater or equal than the maximum */ + /* number of layers, skip the packet */ + if (l_current_pi->layno >= l_tcp->num_layers_to_decode) { + skip_packet = OPJ_TRUE; + } + /* If the packet resolution number is greater than the minimum */ + /* number of resolution allowed, skip the packet */ + else if (l_current_pi->resno >= + p_tile->comps[l_current_pi->compno].minimum_num_resolutions) { + skip_packet = OPJ_TRUE; + } else { + /* If no precincts of any band intersects the area of interest, */ + /* skip the packet */ + OPJ_UINT32 bandno; + opj_tcd_tilecomp_t *tilec = &p_tile->comps[l_current_pi->compno]; + opj_tcd_resolution_t *res = &tilec->resolutions[l_current_pi->resno]; + + skip_packet = OPJ_TRUE; + for (bandno = 0; bandno < res->numbands; ++bandno) { + opj_tcd_band_t* band = &res->bands[bandno]; + opj_tcd_precinct_t* prec = &band->precincts[l_current_pi->precno]; + + if (opj_tcd_is_subband_area_of_interest(tcd, + l_current_pi->compno, + l_current_pi->resno, + band->bandno, + (OPJ_UINT32)prec->x0, + (OPJ_UINT32)prec->y0, + (OPJ_UINT32)prec->x1, + (OPJ_UINT32)prec->y1)) { + skip_packet = OPJ_FALSE; + break; + } + } + /* + printf("packet cmptno=%02d rlvlno=%02d prcno=%03d lyrno=%02d -> %s\n", + l_current_pi->compno, l_current_pi->resno, + l_current_pi->precno, l_current_pi->layno, skip_packet ? "skipped" : "kept"); + */ + } + + if (!skip_packet) { l_nb_bytes_read = 0; first_pass_failed[l_current_pi->compno] = OPJ_FALSE; @@ -596,7 +647,9 @@ static OPJ_BOOL opj_t2_encode_packet(OPJ_UINT32 tileno, OPJ_BYTE *dest, OPJ_UINT32 * p_data_written, OPJ_UINT32 length, - opj_codestream_info_t *cstr_info) + opj_codestream_info_t *cstr_info, + J2K_T2_MODE p_t2_mode, + opj_event_mgr_t *p_manager) { OPJ_UINT32 bandno, cblkno; OPJ_BYTE* c = dest; @@ -618,6 +671,15 @@ static OPJ_BOOL opj_t2_encode_packet(OPJ_UINT32 tileno, /* <SOP 0xff91> */ if (tcp->csty & J2K_CP_CSTY_SOP) { + if (length < 6) { + if (p_t2_mode == FINAL_PASS) { + opj_event_msg(p_manager, EVT_ERROR, + "opj_t2_encode_packet(): only %u bytes remaining in " + "output buffer. %u needed.\n", + length, 6); + } + return OPJ_FALSE; + } c[0] = 255; c[1] = 145; c[2] = 0; @@ -806,6 +868,15 @@ static OPJ_BOOL opj_t2_encode_packet(OPJ_UINT32 tileno, /* <EPH 0xff92> */ if (tcp->csty & J2K_CP_CSTY_EPH) { + if (length < 2) { + if (p_t2_mode == FINAL_PASS) { + opj_event_msg(p_manager, EVT_ERROR, + "opj_t2_encode_packet(): only %u bytes remaining in " + "output buffer. %u needed.\n", + length, 2); + } + return OPJ_FALSE; + } c[0] = 255; c[1] = 146; c += 2; @@ -845,6 +916,12 @@ static OPJ_BOOL opj_t2_encode_packet(OPJ_UINT32 tileno, } if (layer->len > length) { + if (p_t2_mode == FINAL_PASS) { + opj_event_msg(p_manager, EVT_ERROR, + "opj_t2_encode_packet(): only %u bytes remaining in " + "output buffer. %u needed.\n", + length, layer->len); + } return OPJ_FALSE; } diff --git a/openjpeg/src/lib/openjp2/t2.h b/openjpeg/src/lib/openjp2/t2.h index 4013b9dbb..66500b169 100644 --- a/openjpeg/src/lib/openjp2/t2.h +++ b/openjpeg/src/lib/openjp2/t2.h @@ -13,6 +13,7 @@ * Copyright (c) 2005, Herve Drolon, FreeImage Team * Copyright (c) 2008, 2011-2012, Centre National d'Etudes Spatiales (CNES), FR * Copyright (c) 2012, CS Systemes d'Information, France + * Copyright (c) 2017, IntoPIX SA <support@intopix.com> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -75,7 +76,8 @@ Encode the packets of a tile to a destination buffer @param tpnum Tile part number of the current tile @param tppos The position of the tile part flag in the progression order @param pino FIXME DOC -@param t2_mode If == 0 In Threshold calculation ,If == 1 Final pass +@param t2_mode If == THRESH_CALC In Threshold calculation ,If == FINAL_PASS Final pass +@param p_manager the user event manager */ OPJ_BOOL opj_t2_encode_packets(opj_t2_t* t2, OPJ_UINT32 tileno, @@ -88,10 +90,12 @@ OPJ_BOOL opj_t2_encode_packets(opj_t2_t* t2, OPJ_UINT32 tpnum, OPJ_INT32 tppos, OPJ_UINT32 pino, - J2K_T2_MODE t2_mode); + J2K_T2_MODE t2_mode, + opj_event_mgr_t *p_manager); /** Decode the packets of a tile from a source buffer +@param tcd TCD handle @param t2 T2 handle @param tileno number that identifies the tile for which to decode the packets @param tile tile for which to decode the packets @@ -103,7 +107,8 @@ Decode the packets of a tile from a source buffer @return FIXME DOC */ -OPJ_BOOL opj_t2_decode_packets(opj_t2_t *t2, +OPJ_BOOL opj_t2_decode_packets(opj_tcd_t* tcd, + opj_t2_t *t2, OPJ_UINT32 tileno, opj_tcd_tile_t *tile, OPJ_BYTE *src, diff --git a/openjpeg/src/lib/openjp2/tcd.c b/openjpeg/src/lib/openjp2/tcd.c index dd9faced5..1dd15405d 100644 --- a/openjpeg/src/lib/openjp2/tcd.c +++ b/openjpeg/src/lib/openjp2/tcd.c @@ -14,6 +14,7 @@ * Copyright (c) 2006-2007, Parvatha Elangovan * Copyright (c) 2008, 2011-2012, Centre National d'Etudes Spatiales (CNES), FR * Copyright (c) 2012, CS Systemes d'Information, France + * Copyright (c) 2017, IntoPIX SA <support@intopix.com> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -180,12 +181,18 @@ static OPJ_BOOL opj_tcd_t2_encode(opj_tcd_t *p_tcd, OPJ_BYTE * p_dest_data, OPJ_UINT32 * p_data_written, OPJ_UINT32 p_max_dest_size, - opj_codestream_info_t *p_cstr_info); + opj_codestream_info_t *p_cstr_info, + opj_event_mgr_t *p_manager); static OPJ_BOOL opj_tcd_rate_allocate_encode(opj_tcd_t *p_tcd, OPJ_BYTE * p_dest_data, OPJ_UINT32 p_max_dest_size, - opj_codestream_info_t *p_cstr_info); + opj_codestream_info_t *p_cstr_info, + opj_event_mgr_t *p_manager); + + +static OPJ_BOOL opj_tcd_is_whole_tilecomp_decoding(opj_tcd_t *tcd, + OPJ_UINT32 compno); /* ----------------------------------------------------------------------- */ @@ -266,28 +273,33 @@ void opj_tcd_makelayer(opj_tcd_t *tcd, n = cblk->numpassesinlayers; - for (passno = cblk->numpassesinlayers; passno < cblk->totalpasses; passno++) { - OPJ_UINT32 dr; - OPJ_FLOAT64 dd; - opj_tcd_pass_t *pass = &cblk->passes[passno]; - - if (n == 0) { - dr = pass->rate; - dd = pass->distortiondec; - } else { - dr = pass->rate - cblk->passes[n - 1].rate; - dd = pass->distortiondec - cblk->passes[n - 1].distortiondec; - } + if (thresh < 0) { + /* Special value to indicate to use all passes */ + n = cblk->totalpasses; + } else { + for (passno = cblk->numpassesinlayers; passno < cblk->totalpasses; passno++) { + OPJ_UINT32 dr; + OPJ_FLOAT64 dd; + opj_tcd_pass_t *pass = &cblk->passes[passno]; + + if (n == 0) { + dr = pass->rate; + dd = pass->distortiondec; + } else { + dr = pass->rate - cblk->passes[n - 1].rate; + dd = pass->distortiondec - cblk->passes[n - 1].distortiondec; + } - if (!dr) { - if (dd != 0) { + if (!dr) { + if (dd != 0) { + n = passno + 1; + } + continue; + } + if (thresh - (dd / dr) < + DBL_EPSILON) { /* do not rely on float equality, check with DBL_EPSILON margin */ n = passno + 1; } - continue; - } - if (thresh - (dd / dr) < - DBL_EPSILON) { /* do not rely on float equality, check with DBL_EPSILON margin */ - n = passno + 1; } } @@ -431,7 +443,8 @@ OPJ_BOOL opj_tcd_rateallocate(opj_tcd_t *tcd, OPJ_BYTE *dest, OPJ_UINT32 * p_data_written, OPJ_UINT32 len, - opj_codestream_info_t *cstr_info) + opj_codestream_info_t *cstr_info, + opj_event_mgr_t *p_manager) { OPJ_UINT32 compno, resno, bandno, precno, cblkno, layno; OPJ_UINT32 passno; @@ -563,7 +576,7 @@ OPJ_BOOL opj_tcd_rateallocate(opj_tcd_t *tcd, if (OPJ_IS_CINEMA(cp->rsiz)) { if (! opj_t2_encode_packets(t2, tcd->tcd_tileno, tcd_tile, layno + 1, dest, p_data_written, maxlen, cstr_info, tcd->cur_tp_num, tcd->tp_pos, tcd->cur_pino, - THRESH_CALC)) { + THRESH_CALC, p_manager)) { lo = thresh; continue; @@ -593,7 +606,7 @@ OPJ_BOOL opj_tcd_rateallocate(opj_tcd_t *tcd, } else { if (! opj_t2_encode_packets(t2, tcd->tcd_tileno, tcd_tile, layno + 1, dest, p_data_written, maxlen, cstr_info, tcd->cur_tp_num, tcd->tp_pos, tcd->cur_pino, - THRESH_CALC)) { + THRESH_CALC, p_manager)) { /* TODO: what to do with l ??? seek / tell ??? */ /* opj_event_msg(tcd->cinfo, EVT_INFO, "rate alloc: len=%d, max=%d\n", l, maxlen); */ lo = thresh; @@ -609,7 +622,8 @@ OPJ_BOOL opj_tcd_rateallocate(opj_tcd_t *tcd, opj_t2_destroy(t2); } else { - goodthresh = min; + /* Special value to indicate to use all passes */ + goodthresh = -1; } if (cstr_info) { /* Threshold for Marcela Index */ @@ -665,6 +679,9 @@ void opj_tcd_destroy(opj_tcd_t *tcd) opj_free(tcd->tcd_image); tcd->tcd_image = 00; } + + opj_free(tcd->used_component); + opj_free(tcd); } } @@ -675,7 +692,7 @@ OPJ_BOOL opj_alloc_tile_component_data(opj_tcd_tilecomp_t *l_tilec) ((l_tilec->data_size_needed > l_tilec->data_size) && (l_tilec->ownsData == OPJ_FALSE))) { l_tilec->data = (OPJ_INT32 *) opj_image_data_alloc(l_tilec->data_size_needed); - if (! l_tilec->data) { + if (!l_tilec->data && l_tilec->data_size_needed != 0) { return OPJ_FALSE; } /*fprintf(stderr, "tAllocate data of tilec (int): %d x OPJ_UINT32n",l_data_size);*/ @@ -787,24 +804,9 @@ static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no, l_tilec->y0 = opj_int_ceildiv(l_tile->y0, (OPJ_INT32)l_image_comp->dy); l_tilec->x1 = opj_int_ceildiv(l_tile->x1, (OPJ_INT32)l_image_comp->dx); l_tilec->y1 = opj_int_ceildiv(l_tile->y1, (OPJ_INT32)l_image_comp->dy); + l_tilec->compno = compno; /*fprintf(stderr, "\tTile compo border = %d,%d,%d,%d\n", l_tilec->x0, l_tilec->y0,l_tilec->x1,l_tilec->y1);*/ - /* compute l_data_size with overflow check */ - l_data_size = (OPJ_UINT32)(l_tilec->x1 - l_tilec->x0); - /* issue 733, l_data_size == 0U, probably something wrong should be checked before getting here */ - if ((l_data_size > 0U) && - ((((OPJ_UINT32) - 1) / l_data_size) < (OPJ_UINT32)(l_tilec->y1 - - l_tilec->y0))) { - opj_event_msg(manager, EVT_ERROR, "Not enough memory for tile data\n"); - return OPJ_FALSE; - } - l_data_size = l_data_size * (OPJ_UINT32)(l_tilec->y1 - l_tilec->y0); - - if ((((OPJ_UINT32) - 1) / (OPJ_UINT32)sizeof(OPJ_UINT32)) < l_data_size) { - opj_event_msg(manager, EVT_ERROR, "Not enough memory for tile data\n"); - return OPJ_FALSE; - } - l_data_size = l_data_size * (OPJ_UINT32)sizeof(OPJ_UINT32); l_tilec->numresolutions = l_tccp->numresolutions; if (l_tccp->numresolutions < l_cp->m_specific_param.m_dec.m_reduce) { l_tilec->minimum_num_resolutions = 1; @@ -813,15 +815,39 @@ static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no, l_cp->m_specific_param.m_dec.m_reduce; } - l_tilec->data_size_needed = l_data_size; - if (p_tcd->m_is_decoder && !opj_alloc_tile_component_data(l_tilec)) { - opj_event_msg(manager, EVT_ERROR, "Not enough memory for tile data\n"); - return OPJ_FALSE; + if (isEncoder) { + OPJ_SIZE_T l_tile_data_size; + + /* compute l_data_size with overflow check */ + OPJ_SIZE_T w = (OPJ_SIZE_T)(l_tilec->x1 - l_tilec->x0); + OPJ_SIZE_T h = (OPJ_SIZE_T)(l_tilec->y1 - l_tilec->y0); + + /* issue 733, l_data_size == 0U, probably something wrong should be checked before getting here */ + if (h > 0 && w > SIZE_MAX / h) { + opj_event_msg(manager, EVT_ERROR, "Size of tile data exceeds system limits\n"); + return OPJ_FALSE; + } + l_tile_data_size = w * h; + + if (SIZE_MAX / sizeof(OPJ_UINT32) < l_tile_data_size) { + opj_event_msg(manager, EVT_ERROR, "Size of tile data exceeds system limits\n"); + return OPJ_FALSE; + } + l_tile_data_size = l_tile_data_size * sizeof(OPJ_UINT32); + + l_tilec->data_size_needed = l_tile_data_size; } l_data_size = l_tilec->numresolutions * (OPJ_UINT32)sizeof( opj_tcd_resolution_t); + opj_image_data_free(l_tilec->data_win); + l_tilec->data_win = NULL; + l_tilec->win_x0 = 0; + l_tilec->win_y0 = 0; + l_tilec->win_x1 = 0; + l_tilec->win_y1 = 0; + if (l_tilec->resolutions == 00) { l_tilec->resolutions = (opj_tcd_resolution_t *) opj_malloc(l_data_size); if (! l_tilec->resolutions) { @@ -870,6 +896,7 @@ static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no, l_res->y0 = opj_int_ceildivpow2(l_tilec->y0, (OPJ_INT32)l_level_no); l_res->x1 = opj_int_ceildivpow2(l_tilec->x1, (OPJ_INT32)l_level_no); l_res->y1 = opj_int_ceildivpow2(l_tilec->y1, (OPJ_INT32)l_level_no); + /*fprintf(stderr, "\t\t\tres_x0= %d, res_y0 =%d, res_x1=%d, res_y1=%d\n", l_res->x0, l_res->y0, l_res->x1, l_res->y1);*/ /* p. 35, table A-23, ISO/IEC FDIS154444-1 : 2000 (18 august 2000) */ l_pdx = l_tccp->prcw[resno]; @@ -889,14 +916,14 @@ static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no, /*fprintf(stderr, "\t\t\tres_pw=%d, res_ph=%d\n", l_res->pw, l_res->ph );*/ if ((l_res->pw != 0U) && ((((OPJ_UINT32) - 1) / l_res->pw) < l_res->ph)) { - opj_event_msg(manager, EVT_ERROR, "Not enough memory for tile data\n"); + opj_event_msg(manager, EVT_ERROR, "Size of tile data exceeds system limits\n"); return OPJ_FALSE; } l_nb_precincts = l_res->pw * l_res->ph; if ((((OPJ_UINT32) - 1) / (OPJ_UINT32)sizeof(opj_tcd_precinct_t)) < l_nb_precincts) { - opj_event_msg(manager, EVT_ERROR, "Not enough memory for tile data\n"); + opj_event_msg(manager, EVT_ERROR, "Size of tile data exceeds system limits\n"); return OPJ_FALSE; } l_nb_precinct_size = l_nb_precincts * (OPJ_UINT32)sizeof(opj_tcd_precinct_t); @@ -1184,8 +1211,11 @@ static OPJ_BOOL opj_tcd_code_block_enc_allocate_data(opj_tcd_cblk_enc_t * { OPJ_UINT32 l_data_size; - /* The +1 is needed for https://github.com/uclouvain/openjpeg/issues/835 */ - l_data_size = 1 + (OPJ_UINT32)((p_code_block->x1 - p_code_block->x0) * + /* +1 is needed for https://github.com/uclouvain/openjpeg/issues/835 */ + /* and actually +2 required for https://github.com/uclouvain/openjpeg/issues/982 */ + /* TODO: is there a theoretical upper-bound for the compressed code */ + /* block size ? */ + l_data_size = 2 + (OPJ_UINT32)((p_code_block->x1 - p_code_block->x0) * (p_code_block->y1 - p_code_block->y0) * (OPJ_INT32)sizeof(OPJ_UINT32)); if (l_data_size > p_code_block->data_size) { @@ -1241,6 +1271,9 @@ static OPJ_BOOL opj_tcd_code_block_dec_allocate(opj_tcd_cblk_dec_t * OPJ_UINT32 l_numchunksalloc = p_code_block->numchunksalloc; OPJ_UINT32 i; + opj_aligned_free(p_code_block->decoded_data); + p_code_block->decoded_data = 00; + memset(p_code_block, 0, sizeof(opj_tcd_cblk_dec_t)); p_code_block->segs = l_segs; p_code_block->m_current_max_segs = l_current_max_segs; @@ -1254,7 +1287,8 @@ static OPJ_BOOL opj_tcd_code_block_dec_allocate(opj_tcd_cblk_dec_t * return OPJ_TRUE; } -OPJ_UINT32 opj_tcd_get_decoded_tile_size(opj_tcd_t *p_tcd) +OPJ_UINT32 opj_tcd_get_decoded_tile_size(opj_tcd_t *p_tcd, + OPJ_BOOL take_into_account_partial_decoding) { OPJ_UINT32 i; OPJ_UINT32 l_data_size = 0; @@ -1268,6 +1302,7 @@ OPJ_UINT32 opj_tcd_get_decoded_tile_size(opj_tcd_t *p_tcd) l_img_comp = p_tcd->image->comps; for (i = 0; i < p_tcd->image->numcomps; ++i) { + OPJ_UINT32 w, h; l_size_comp = l_img_comp->prec >> 3; /*(/ 8)*/ l_remaining = l_img_comp->prec & 7; /* (%8) */ @@ -1280,8 +1315,17 @@ OPJ_UINT32 opj_tcd_get_decoded_tile_size(opj_tcd_t *p_tcd) } l_res = l_tile_comp->resolutions + l_tile_comp->minimum_num_resolutions - 1; - l_temp = (OPJ_UINT32)((l_res->x1 - l_res->x0) * (l_res->y1 - - l_res->y0)); /* x1*y1 can't overflow */ + if (take_into_account_partial_decoding && !p_tcd->whole_tile_decoding) { + w = l_res->win_x1 - l_res->win_x0; + h = l_res->win_y1 - l_res->win_y0; + } else { + w = (OPJ_UINT32)(l_res->x1 - l_res->x0); + h = (OPJ_UINT32)(l_res->y1 - l_res->y0); + } + if (h > 0 && UINT_MAX / w < h) { + return UINT_MAX; + } + l_temp = w * h; if (l_size_comp && UINT_MAX / l_size_comp < l_temp) { return UINT_MAX; } @@ -1303,7 +1347,8 @@ OPJ_BOOL opj_tcd_encode_tile(opj_tcd_t *p_tcd, OPJ_BYTE *p_dest, OPJ_UINT32 * p_data_written, OPJ_UINT32 p_max_length, - opj_codestream_info_t *p_cstr_info) + opj_codestream_info_t *p_cstr_info, + opj_event_mgr_t *p_manager) { if (p_tcd->cur_tp_num == 0) { @@ -1330,7 +1375,8 @@ OPJ_BOOL opj_tcd_encode_tile(opj_tcd_t *p_tcd, p_cstr_info->tile[p_tile_no].pdy[i] = (int)l_tccp->prch[i]; } p_cstr_info->tile[p_tile_no].packet = (opj_packet_info_t*) opj_calloc(( - size_t)p_cstr_info->numcomps * (size_t)p_cstr_info->numlayers * l_num_packs, + OPJ_SIZE_T)p_cstr_info->numcomps * (OPJ_SIZE_T)p_cstr_info->numlayers * + l_num_packs, sizeof(opj_packet_info_t)); if (!p_cstr_info->tile[p_tile_no].packet) { /* FIXME event manager error callback */ @@ -1365,7 +1411,8 @@ OPJ_BOOL opj_tcd_encode_tile(opj_tcd_t *p_tcd, /* FIXME _ProfStop(PGROUP_T1); */ /* FIXME _ProfStart(PGROUP_RATE); */ - if (! opj_tcd_rate_allocate_encode(p_tcd, p_dest, p_max_length, p_cstr_info)) { + if (! opj_tcd_rate_allocate_encode(p_tcd, p_dest, p_max_length, + p_cstr_info, p_manager)) { return OPJ_FALSE; } /* FIXME _ProfStop(PGROUP_RATE); */ @@ -1380,7 +1427,7 @@ OPJ_BOOL opj_tcd_encode_tile(opj_tcd_t *p_tcd, /* FIXME _ProfStart(PGROUP_T2); */ if (! opj_tcd_t2_encode(p_tcd, p_dest, p_data_written, p_max_length, - p_cstr_info)) { + p_cstr_info, p_manager)) { return OPJ_FALSE; } /* FIXME _ProfStop(PGROUP_T2); */ @@ -1391,6 +1438,12 @@ OPJ_BOOL opj_tcd_encode_tile(opj_tcd_t *p_tcd, } OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *p_tcd, + OPJ_UINT32 win_x0, + OPJ_UINT32 win_y0, + OPJ_UINT32 win_x1, + OPJ_UINT32 win_y1, + OPJ_UINT32 numcomps_to_decode, + const OPJ_UINT32 *comps_indices, OPJ_BYTE *p_src, OPJ_UINT32 p_max_length, OPJ_UINT32 p_tile_no, @@ -1399,8 +1452,131 @@ OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *p_tcd, ) { OPJ_UINT32 l_data_read; + OPJ_UINT32 compno; + p_tcd->tcd_tileno = p_tile_no; p_tcd->tcp = &(p_tcd->cp->tcps[p_tile_no]); + p_tcd->win_x0 = win_x0; + p_tcd->win_y0 = win_y0; + p_tcd->win_x1 = win_x1; + p_tcd->win_y1 = win_y1; + p_tcd->whole_tile_decoding = OPJ_TRUE; + + opj_free(p_tcd->used_component); + p_tcd->used_component = NULL; + + if (numcomps_to_decode) { + OPJ_BOOL* used_component = (OPJ_BOOL*) opj_calloc(sizeof(OPJ_BOOL), + p_tcd->image->numcomps); + if (used_component == NULL) { + return OPJ_FALSE; + } + for (compno = 0; compno < numcomps_to_decode; compno++) { + used_component[ comps_indices[compno] ] = OPJ_TRUE; + } + + p_tcd->used_component = used_component; + } + + for (compno = 0; compno < p_tcd->image->numcomps; compno++) { + if (p_tcd->used_component != NULL && !p_tcd->used_component[compno]) { + continue; + } + + if (!opj_tcd_is_whole_tilecomp_decoding(p_tcd, compno)) { + p_tcd->whole_tile_decoding = OPJ_FALSE; + break; + } + } + + if (p_tcd->whole_tile_decoding) { + for (compno = 0; compno < p_tcd->image->numcomps; compno++) { + opj_tcd_tilecomp_t* tilec = &(p_tcd->tcd_image->tiles->comps[compno]); + opj_tcd_resolution_t *l_res = & + (tilec->resolutions[tilec->minimum_num_resolutions - 1]); + OPJ_SIZE_T l_data_size; + + /* compute l_data_size with overflow check */ + OPJ_SIZE_T res_w = (OPJ_SIZE_T)(l_res->x1 - l_res->x0); + OPJ_SIZE_T res_h = (OPJ_SIZE_T)(l_res->y1 - l_res->y0); + + if (p_tcd->used_component != NULL && !p_tcd->used_component[compno]) { + continue; + } + + /* issue 733, l_data_size == 0U, probably something wrong should be checked before getting here */ + if (res_h > 0 && res_w > SIZE_MAX / res_h) { + opj_event_msg(p_manager, EVT_ERROR, + "Size of tile data exceeds system limits\n"); + return OPJ_FALSE; + } + l_data_size = res_w * res_h; + + if (SIZE_MAX / sizeof(OPJ_UINT32) < l_data_size) { + opj_event_msg(p_manager, EVT_ERROR, + "Size of tile data exceeds system limits\n"); + return OPJ_FALSE; + } + l_data_size *= sizeof(OPJ_UINT32); + + tilec->data_size_needed = l_data_size; + + if (!opj_alloc_tile_component_data(tilec)) { + opj_event_msg(p_manager, EVT_ERROR, + "Size of tile data exceeds system limits\n"); + return OPJ_FALSE; + } + } + } else { + /* Compute restricted tile-component and tile-resolution coordinates */ + /* of the window of interest, but defer the memory allocation until */ + /* we know the resno_decoded */ + for (compno = 0; compno < p_tcd->image->numcomps; compno++) { + OPJ_UINT32 resno; + opj_tcd_tilecomp_t* tilec = &(p_tcd->tcd_image->tiles->comps[compno]); + opj_image_comp_t* image_comp = &(p_tcd->image->comps[compno]); + + if (p_tcd->used_component != NULL && !p_tcd->used_component[compno]) { + continue; + } + + /* Compute the intersection of the area of interest, expressed in tile coordinates */ + /* with the tile coordinates */ + tilec->win_x0 = opj_uint_max( + (OPJ_UINT32)tilec->x0, + opj_uint_ceildiv(p_tcd->win_x0, image_comp->dx)); + tilec->win_y0 = opj_uint_max( + (OPJ_UINT32)tilec->y0, + opj_uint_ceildiv(p_tcd->win_y0, image_comp->dy)); + tilec->win_x1 = opj_uint_min( + (OPJ_UINT32)tilec->x1, + opj_uint_ceildiv(p_tcd->win_x1, image_comp->dx)); + tilec->win_y1 = opj_uint_min( + (OPJ_UINT32)tilec->y1, + opj_uint_ceildiv(p_tcd->win_y1, image_comp->dy)); + if (tilec->win_x1 < tilec->win_x0 || + tilec->win_y1 < tilec->win_y0) { + /* We should not normally go there. The circumstance is when */ + /* the tile coordinates do not intersect the area of interest */ + /* Upper level logic should not even try to decode that tile */ + opj_event_msg(p_manager, EVT_ERROR, + "Invalid tilec->win_xxx values\n"); + return OPJ_FALSE; + } + + for (resno = 0; resno < tilec->numresolutions; ++resno) { + opj_tcd_resolution_t *res = tilec->resolutions + resno; + res->win_x0 = opj_uint_ceildivpow2(tilec->win_x0, + tilec->numresolutions - 1 - resno); + res->win_y0 = opj_uint_ceildivpow2(tilec->win_y0, + tilec->numresolutions - 1 - resno); + res->win_x1 = opj_uint_ceildivpow2(tilec->win_x1, + tilec->numresolutions - 1 - resno); + res->win_y1 = opj_uint_ceildivpow2(tilec->win_y1, + tilec->numresolutions - 1 - resno); + } + } + } #ifdef TODO_MSD /* FIXME */ /* INDEX >> */ @@ -1443,6 +1619,49 @@ OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *p_tcd, } /* FIXME _ProfStop(PGROUP_T1); */ + + /* For subtile decoding, now we know the resno_decoded, we can allocate */ + /* the tile data buffer */ + if (!p_tcd->whole_tile_decoding) { + for (compno = 0; compno < p_tcd->image->numcomps; compno++) { + opj_tcd_tilecomp_t* tilec = &(p_tcd->tcd_image->tiles->comps[compno]); + opj_image_comp_t* image_comp = &(p_tcd->image->comps[compno]); + opj_tcd_resolution_t *res = tilec->resolutions + image_comp->resno_decoded; + OPJ_SIZE_T w = res->win_x1 - res->win_x0; + OPJ_SIZE_T h = res->win_y1 - res->win_y0; + OPJ_SIZE_T l_data_size; + + opj_image_data_free(tilec->data_win); + tilec->data_win = NULL; + + if (p_tcd->used_component != NULL && !p_tcd->used_component[compno]) { + continue; + } + + if (w > 0 && h > 0) { + if (w > SIZE_MAX / h) { + opj_event_msg(p_manager, EVT_ERROR, + "Size of tile data exceeds system limits\n"); + return OPJ_FALSE; + } + l_data_size = w * h; + if (l_data_size > SIZE_MAX / sizeof(OPJ_INT32)) { + opj_event_msg(p_manager, EVT_ERROR, + "Size of tile data exceeds system limits\n"); + return OPJ_FALSE; + } + l_data_size *= sizeof(OPJ_INT32); + + tilec->data_win = (OPJ_INT32*) opj_image_data_alloc(l_data_size); + if (tilec->data_win == NULL) { + opj_event_msg(p_manager, EVT_ERROR, + "Size of tile data exceeds system limits\n"); + return OPJ_FALSE; + } + } + } + } + /*----------------DWT---------------------*/ /* FIXME _ProfStart(PGROUP_DWT); */ @@ -1484,7 +1703,7 @@ OPJ_BOOL opj_tcd_update_tile_data(opj_tcd_t *p_tcd, OPJ_UINT32 l_size_comp, l_remaining; OPJ_UINT32 l_stride, l_width, l_height; - l_data_size = opj_tcd_get_decoded_tile_size(p_tcd); + l_data_size = opj_tcd_get_decoded_tile_size(p_tcd, OPJ_TRUE); if (l_data_size == UINT_MAX || l_data_size > p_dest_length) { return OPJ_FALSE; } @@ -1493,12 +1712,23 @@ OPJ_BOOL opj_tcd_update_tile_data(opj_tcd_t *p_tcd, l_img_comp = p_tcd->image->comps; for (i = 0; i < p_tcd->image->numcomps; ++i) { + const OPJ_INT32* l_src_data; l_size_comp = l_img_comp->prec >> 3; /*(/ 8)*/ l_remaining = l_img_comp->prec & 7; /* (%8) */ l_res = l_tilec->resolutions + l_img_comp->resno_decoded; - l_width = (OPJ_UINT32)(l_res->x1 - l_res->x0); - l_height = (OPJ_UINT32)(l_res->y1 - l_res->y0); - l_stride = (OPJ_UINT32)(l_tilec->x1 - l_tilec->x0) - l_width; + if (p_tcd->whole_tile_decoding) { + l_width = (OPJ_UINT32)(l_res->x1 - l_res->x0); + l_height = (OPJ_UINT32)(l_res->y1 - l_res->y0); + l_stride = (OPJ_UINT32)(l_tilec->resolutions[l_tilec->minimum_num_resolutions - + 1].x1 - + l_tilec->resolutions[l_tilec->minimum_num_resolutions - 1].x0) - l_width; + l_src_data = l_tilec->data; + } else { + l_width = l_res->win_x1 - l_res->win_x0; + l_height = l_res->win_y1 - l_res->win_y0; + l_stride = 0; + l_src_data = l_tilec->data_win; + } if (l_remaining) { ++l_size_comp; @@ -1511,7 +1741,7 @@ OPJ_BOOL opj_tcd_update_tile_data(opj_tcd_t *p_tcd, switch (l_size_comp) { case 1: { OPJ_CHAR * l_dest_ptr = (OPJ_CHAR *) p_dest; - const OPJ_INT32 * l_src_ptr = l_tilec->data; + const OPJ_INT32 * l_src_ptr = l_src_data; if (l_img_comp->sgnd) { for (j = 0; j < l_height; ++j) { @@ -1533,7 +1763,7 @@ OPJ_BOOL opj_tcd_update_tile_data(opj_tcd_t *p_tcd, } break; case 2: { - const OPJ_INT32 * l_src_ptr = l_tilec->data; + const OPJ_INT32 * l_src_ptr = l_src_data; OPJ_INT16 * l_dest_ptr = (OPJ_INT16 *) p_dest; if (l_img_comp->sgnd) { @@ -1561,7 +1791,7 @@ OPJ_BOOL opj_tcd_update_tile_data(opj_tcd_t *p_tcd, break; case 4: { OPJ_INT32 * l_dest_ptr = (OPJ_INT32 *) p_dest; - OPJ_INT32 * l_src_ptr = l_tilec->data; + const OPJ_INT32 * l_src_ptr = l_src_data; for (j = 0; j < l_height; ++j) { memcpy(l_dest_ptr, l_src_ptr, l_width * sizeof(OPJ_INT32)); @@ -1620,14 +1850,16 @@ static void opj_tcd_free_tile(opj_tcd_t *p_tcd) l_res = l_tile_comp->resolutions; if (l_res) { - l_nb_resolutions = l_tile_comp->resolutions_size / sizeof(opj_tcd_resolution_t); + l_nb_resolutions = l_tile_comp->resolutions_size / (OPJ_UINT32)sizeof( + opj_tcd_resolution_t); for (resno = 0; resno < l_nb_resolutions; ++resno) { l_band = l_res->bands; for (bandno = 0; bandno < 3; ++bandno) { l_precinct = l_band->precincts; if (l_precinct) { - l_nb_precincts = l_band->precincts_data_size / sizeof(opj_tcd_precinct_t); + l_nb_precincts = l_band->precincts_data_size / (OPJ_UINT32)sizeof( + opj_tcd_precinct_t); for (precno = 0; precno < l_nb_precincts; ++precno) { opj_tgt_destroy(l_precinct->incltree); l_precinct->incltree = 00; @@ -1656,6 +1888,9 @@ static void opj_tcd_free_tile(opj_tcd_t *p_tcd) l_tile_comp->data_size = 0; l_tile_comp->data_size_needed = 0; } + + opj_image_data_free(l_tile_comp->data_win); + ++l_tile_comp; } @@ -1682,6 +1917,7 @@ static OPJ_BOOL opj_tcd_t2_decode(opj_tcd_t *p_tcd, } if (! opj_t2_decode_packets( + p_tcd, l_t2, p_tcd->tcd_tileno, p_tcd->tcd_image->tiles, @@ -1718,14 +1954,17 @@ static OPJ_BOOL opj_tcd_t1_decode(opj_tcd_t *p_tcd, opj_event_mgr_t *p_manager) check_pterm = OPJ_TRUE; } - for (compno = 0; compno < l_tile->numcomps; ++compno) { - opj_t1_decode_cblks(p_tcd->thread_pool, &ret, l_tile_comp, l_tccp, + for (compno = 0; compno < l_tile->numcomps; + ++compno, ++l_tile_comp, ++l_tccp) { + if (p_tcd->used_component != NULL && !p_tcd->used_component[compno]) { + continue; + } + + opj_t1_decode_cblks(p_tcd, &ret, l_tile_comp, l_tccp, p_manager, p_manager_mutex, check_pterm); if (!ret) { break; } - ++l_tile_comp; - ++l_tccp; } opj_thread_pool_wait_completion(p_tcd->thread_pool, 0); @@ -1744,38 +1983,29 @@ static OPJ_BOOL opj_tcd_dwt_decode(opj_tcd_t *p_tcd) opj_tccp_t * l_tccp = p_tcd->tcp->tccps; opj_image_comp_t * l_img_comp = p_tcd->image->comps; - for (compno = 0; compno < l_tile->numcomps; compno++) { - /* - if (tcd->cp->reduce != 0) { - tcd->image->comps[compno].resno_decoded = - tile->comps[compno].numresolutions - tcd->cp->reduce - 1; - if (tcd->image->comps[compno].resno_decoded < 0) - { - return false; - } + for (compno = 0; compno < l_tile->numcomps; + compno++, ++l_tile_comp, ++l_img_comp, ++l_tccp) { + if (p_tcd->used_component != NULL && !p_tcd->used_component[compno]) { + continue; } - numres2decode = tcd->image->comps[compno].resno_decoded + 1; - if(numres2decode > 0){ - */ if (l_tccp->qmfbid == 1) { - if (! opj_dwt_decode(p_tcd->thread_pool, l_tile_comp, + if (! opj_dwt_decode(p_tcd, l_tile_comp, l_img_comp->resno_decoded + 1)) { return OPJ_FALSE; } } else { - if (! opj_dwt_decode_real(l_tile_comp, l_img_comp->resno_decoded + 1)) { + if (! opj_dwt_decode_real(p_tcd, l_tile_comp, + l_img_comp->resno_decoded + 1)) { return OPJ_FALSE; } } - ++l_tile_comp; - ++l_img_comp; - ++l_tccp; } return OPJ_TRUE; } + static OPJ_BOOL opj_tcd_mct_decode(opj_tcd_t *p_tcd, opj_event_mgr_t *p_manager) { opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles; @@ -1783,25 +2013,77 @@ static OPJ_BOOL opj_tcd_mct_decode(opj_tcd_t *p_tcd, opj_event_mgr_t *p_manager) opj_tcd_tilecomp_t * l_tile_comp = l_tile->comps; OPJ_UINT32 l_samples, i; - if (! l_tcp->mct) { + if (l_tcp->mct == 0 || p_tcd->used_component != NULL) { return OPJ_TRUE; } - l_samples = (OPJ_UINT32)((l_tile_comp->x1 - l_tile_comp->x0) * - (l_tile_comp->y1 - l_tile_comp->y0)); + if (p_tcd->whole_tile_decoding) { + opj_tcd_resolution_t* res_comp0 = l_tile->comps[0].resolutions + + l_tile_comp->minimum_num_resolutions - 1; + + /* A bit inefficient: we process more data than needed if */ + /* resno_decoded < l_tile_comp->minimum_num_resolutions-1, */ + /* but we would need to take into account a stride then */ + l_samples = (OPJ_UINT32)((res_comp0->x1 - res_comp0->x0) * + (res_comp0->y1 - res_comp0->y0)); + if (l_tile->numcomps >= 3) { + if (l_tile_comp->minimum_num_resolutions != + l_tile->comps[1].minimum_num_resolutions || + l_tile_comp->minimum_num_resolutions != + l_tile->comps[2].minimum_num_resolutions) { + opj_event_msg(p_manager, EVT_ERROR, + "Tiles don't all have the same dimension. Skip the MCT step.\n"); + return OPJ_FALSE; + } + } + if (l_tile->numcomps >= 3) { + opj_tcd_resolution_t* res_comp1 = l_tile->comps[1].resolutions + + l_tile_comp->minimum_num_resolutions - 1; + opj_tcd_resolution_t* res_comp2 = l_tile->comps[2].resolutions + + l_tile_comp->minimum_num_resolutions - 1; + /* testcase 1336.pdf.asan.47.376 */ + if (p_tcd->image->comps[0].resno_decoded != + p_tcd->image->comps[1].resno_decoded || + p_tcd->image->comps[0].resno_decoded != + p_tcd->image->comps[2].resno_decoded || + (OPJ_SIZE_T)(res_comp1->x1 - res_comp1->x0) * + (OPJ_SIZE_T)(res_comp1->y1 - res_comp1->y0) != l_samples || + (OPJ_SIZE_T)(res_comp2->x1 - res_comp2->x0) * + (OPJ_SIZE_T)(res_comp2->y1 - res_comp2->y0) != l_samples) { + opj_event_msg(p_manager, EVT_ERROR, + "Tiles don't all have the same dimension. Skip the MCT step.\n"); + return OPJ_FALSE; + } + } + } else { + opj_tcd_resolution_t* res_comp0 = l_tile->comps[0].resolutions + + p_tcd->image->comps[0].resno_decoded; + + l_samples = (res_comp0->win_x1 - res_comp0->win_x0) * + (res_comp0->win_y1 - res_comp0->win_y0); + if (l_tile->numcomps >= 3) { + opj_tcd_resolution_t* res_comp1 = l_tile->comps[1].resolutions + + p_tcd->image->comps[1].resno_decoded; + opj_tcd_resolution_t* res_comp2 = l_tile->comps[2].resolutions + + p_tcd->image->comps[2].resno_decoded; + /* testcase 1336.pdf.asan.47.376 */ + if (p_tcd->image->comps[0].resno_decoded != + p_tcd->image->comps[1].resno_decoded || + p_tcd->image->comps[0].resno_decoded != + p_tcd->image->comps[2].resno_decoded || + (OPJ_SIZE_T)(res_comp1->win_x1 - res_comp1->win_x0) * + (OPJ_SIZE_T)(res_comp1->win_y1 - res_comp1->win_y0) != l_samples || + (OPJ_SIZE_T)(res_comp2->win_x1 - res_comp2->win_x0) * + (OPJ_SIZE_T)(res_comp2->win_y1 - res_comp2->win_y0) != l_samples) { + opj_event_msg(p_manager, EVT_ERROR, + "Tiles don't all have the same dimension. Skip the MCT step.\n"); + return OPJ_FALSE; + } + } + } if (l_tile->numcomps >= 3) { - /* testcase 1336.pdf.asan.47.376 */ - if ((l_tile->comps[0].x1 - l_tile->comps[0].x0) * (l_tile->comps[0].y1 - - l_tile->comps[0].y0) < (OPJ_INT32)l_samples || - (l_tile->comps[1].x1 - l_tile->comps[1].x0) * (l_tile->comps[1].y1 - - l_tile->comps[1].y0) < (OPJ_INT32)l_samples || - (l_tile->comps[2].x1 - l_tile->comps[2].x0) * (l_tile->comps[2].y1 - - l_tile->comps[2].y0) < (OPJ_INT32)l_samples) { - opj_event_msg(p_manager, EVT_ERROR, - "Tiles don't all have the same dimension. Skip the MCT step.\n"); - return OPJ_FALSE; - } else if (l_tcp->mct == 2) { + if (l_tcp->mct == 2) { OPJ_BYTE ** l_data; if (! l_tcp->m_mct_decoding_matrix) { @@ -1814,7 +2096,11 @@ static OPJ_BOOL opj_tcd_mct_decode(opj_tcd_t *p_tcd, opj_event_mgr_t *p_manager) } for (i = 0; i < l_tile->numcomps; ++i) { - l_data[i] = (OPJ_BYTE*) l_tile_comp->data; + if (p_tcd->whole_tile_decoding) { + l_data[i] = (OPJ_BYTE*) l_tile_comp->data; + } else { + l_data[i] = (OPJ_BYTE*) l_tile_comp->data_win; + } ++l_tile_comp; } @@ -1835,15 +2121,29 @@ static OPJ_BOOL opj_tcd_mct_decode(opj_tcd_t *p_tcd, opj_event_mgr_t *p_manager) opj_free(l_data); } else { if (l_tcp->tccps->qmfbid == 1) { - opj_mct_decode(l_tile->comps[0].data, - l_tile->comps[1].data, - l_tile->comps[2].data, - l_samples); + if (p_tcd->whole_tile_decoding) { + opj_mct_decode(l_tile->comps[0].data, + l_tile->comps[1].data, + l_tile->comps[2].data, + l_samples); + } else { + opj_mct_decode(l_tile->comps[0].data_win, + l_tile->comps[1].data_win, + l_tile->comps[2].data_win, + l_samples); + } } else { - opj_mct_decode_real((OPJ_FLOAT32*)l_tile->comps[0].data, - (OPJ_FLOAT32*)l_tile->comps[1].data, - (OPJ_FLOAT32*)l_tile->comps[2].data, - l_samples); + if (p_tcd->whole_tile_decoding) { + opj_mct_decode_real((OPJ_FLOAT32*)l_tile->comps[0].data, + (OPJ_FLOAT32*)l_tile->comps[1].data, + (OPJ_FLOAT32*)l_tile->comps[2].data, + l_samples); + } else { + opj_mct_decode_real((OPJ_FLOAT32*)l_tile->comps[0].data_win, + (OPJ_FLOAT32*)l_tile->comps[1].data_win, + (OPJ_FLOAT32*)l_tile->comps[2].data_win, + l_samples); + } } } } else { @@ -1874,14 +2174,32 @@ static OPJ_BOOL opj_tcd_dc_level_shift_decode(opj_tcd_t *p_tcd) l_tccp = p_tcd->tcp->tccps; l_img_comp = p_tcd->image->comps; - for (compno = 0; compno < l_tile->numcomps; compno++) { + for (compno = 0; compno < l_tile->numcomps; + compno++, ++l_img_comp, ++l_tccp, ++l_tile_comp) { + + if (p_tcd->used_component != NULL && !p_tcd->used_component[compno]) { + continue; + } + l_res = l_tile_comp->resolutions + l_img_comp->resno_decoded; - l_width = (OPJ_UINT32)(l_res->x1 - l_res->x0); - l_height = (OPJ_UINT32)(l_res->y1 - l_res->y0); - l_stride = (OPJ_UINT32)(l_tile_comp->x1 - l_tile_comp->x0) - l_width; - assert(l_height == 0 || - l_width + l_stride <= l_tile_comp->data_size / l_height); /*MUPDF*/ + if (!p_tcd->whole_tile_decoding) { + l_width = l_res->win_x1 - l_res->win_x0; + l_height = l_res->win_y1 - l_res->win_y0; + l_stride = 0; + l_current_ptr = l_tile_comp->data_win; + } else { + l_width = (OPJ_UINT32)(l_res->x1 - l_res->x0); + l_height = (OPJ_UINT32)(l_res->y1 - l_res->y0); + l_stride = (OPJ_UINT32)( + l_tile_comp->resolutions[l_tile_comp->minimum_num_resolutions - 1].x1 - + l_tile_comp->resolutions[l_tile_comp->minimum_num_resolutions - 1].x0) + - l_width; + l_current_ptr = l_tile_comp->data; + + assert(l_height == 0 || + l_width + l_stride <= l_tile_comp->data_size / l_height); /*MUPDF*/ + } if (l_img_comp->sgnd) { l_min = -(1 << (l_img_comp->prec - 1)); @@ -1891,11 +2209,11 @@ static OPJ_BOOL opj_tcd_dc_level_shift_decode(opj_tcd_t *p_tcd) l_max = (OPJ_INT32)((1U << l_img_comp->prec) - 1); } - l_current_ptr = l_tile_comp->data; if (l_tccp->qmfbid == 1) { for (j = 0; j < l_height; ++j) { for (i = 0; i < l_width; ++i) { + /* TODO: do addition on int64 ? */ *l_current_ptr = opj_int_clamp(*l_current_ptr + l_tccp->m_dc_level_shift, l_min, l_max); ++l_current_ptr; @@ -1906,13 +2224,14 @@ static OPJ_BOOL opj_tcd_dc_level_shift_decode(opj_tcd_t *p_tcd) for (j = 0; j < l_height; ++j) { for (i = 0; i < l_width; ++i) { OPJ_FLOAT32 l_value = *((OPJ_FLOAT32 *) l_current_ptr); - OPJ_INT32 l_value_int = (OPJ_INT32)opj_lrintf(l_value); - if (l_value > INT_MAX || - (l_value_int > 0 && l_tccp->m_dc_level_shift > 0 && - l_value_int > INT_MAX - l_tccp->m_dc_level_shift)) { + if (l_value > INT_MAX) { *l_current_ptr = l_max; + } else if (l_value < INT_MIN) { + *l_current_ptr = l_min; } else { - *l_current_ptr = opj_int_clamp( + /* Do addition on int64 to avoid overflows */ + OPJ_INT64 l_value_int = (OPJ_INT64)opj_lrintf(l_value); + *l_current_ptr = (OPJ_INT32)opj_int64_clamp( l_value_int + l_tccp->m_dc_level_shift, l_min, l_max); } ++l_current_ptr; @@ -1920,10 +2239,6 @@ static OPJ_BOOL opj_tcd_dc_level_shift_decode(opj_tcd_t *p_tcd) l_current_ptr += l_stride; } } - - ++l_img_comp; - ++l_tccp; - ++l_tile_comp; } return OPJ_TRUE; @@ -1946,7 +2261,8 @@ static void opj_tcd_code_block_dec_deallocate(opj_tcd_precinct_t * p_precinct) l_code_block->numbps, l_code_block->numlenbits, l_code_block->len, l_code_block->numnewpasses, l_code_block->real_num_segs, l_code_block->m_current_max_segs );*/ - l_nb_code_blocks = p_precinct->block_size / sizeof(opj_tcd_cblk_dec_t); + l_nb_code_blocks = p_precinct->block_size / (OPJ_UINT32)sizeof( + opj_tcd_cblk_dec_t); /*fprintf(stderr,"nb_code_blocks =%d\t}\n", l_nb_code_blocks);*/ for (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno) { @@ -1961,6 +2277,9 @@ static void opj_tcd_code_block_dec_deallocate(opj_tcd_precinct_t * p_precinct) l_code_block->chunks = 00; } + opj_aligned_free(l_code_block->decoded_data); + l_code_block->decoded_data = NULL; + ++l_code_block; } @@ -1978,7 +2297,8 @@ static void opj_tcd_code_block_enc_deallocate(opj_tcd_precinct_t * p_precinct) opj_tcd_cblk_enc_t * l_code_block = p_precinct->cblks.enc; if (l_code_block) { - l_nb_code_blocks = p_precinct->block_size / sizeof(opj_tcd_cblk_enc_t); + l_nb_code_blocks = p_precinct->block_size / (OPJ_UINT32)sizeof( + opj_tcd_cblk_enc_t); for (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno) { if (l_code_block->data) { @@ -2006,9 +2326,10 @@ static void opj_tcd_code_block_enc_deallocate(opj_tcd_precinct_t * p_precinct) } } -OPJ_UINT32 opj_tcd_get_encoded_tile_size(opj_tcd_t *p_tcd) +OPJ_SIZE_T opj_tcd_get_encoded_tile_size(opj_tcd_t *p_tcd) { - OPJ_UINT32 i, l_data_size = 0; + OPJ_UINT32 i; + OPJ_SIZE_T l_data_size = 0; opj_image_comp_t * l_img_comp = 00; opj_tcd_tilecomp_t * l_tilec = 00; OPJ_UINT32 l_size_comp, l_remaining; @@ -2027,8 +2348,8 @@ OPJ_UINT32 opj_tcd_get_encoded_tile_size(opj_tcd_t *p_tcd) l_size_comp = 4; } - l_data_size += l_size_comp * (OPJ_UINT32)((l_tilec->x1 - l_tilec->x0) * - (l_tilec->y1 - l_tilec->y0)); + l_data_size += l_size_comp * ((OPJ_SIZE_T)(l_tilec->x1 - l_tilec->x0) * + (OPJ_SIZE_T)(l_tilec->y1 - l_tilec->y0)); ++l_img_comp; ++l_tilec; } @@ -2043,7 +2364,7 @@ static OPJ_BOOL opj_tcd_dc_level_shift_encode(opj_tcd_t *p_tcd) opj_tccp_t * l_tccp = 00; opj_image_comp_t * l_img_comp = 00; opj_tcd_tile_t * l_tile; - OPJ_UINT32 l_nb_elem, i; + OPJ_SIZE_T l_nb_elem, i; OPJ_INT32 * l_current_ptr; l_tile = p_tcd->tcd_image->tiles; @@ -2053,8 +2374,8 @@ static OPJ_BOOL opj_tcd_dc_level_shift_encode(opj_tcd_t *p_tcd) for (compno = 0; compno < l_tile->numcomps; compno++) { l_current_ptr = l_tile_comp->data; - l_nb_elem = (OPJ_UINT32)((l_tile_comp->x1 - l_tile_comp->x0) * - (l_tile_comp->y1 - l_tile_comp->y0)); + l_nb_elem = (OPJ_SIZE_T)(l_tile_comp->x1 - l_tile_comp->x0) * + (OPJ_SIZE_T)(l_tile_comp->y1 - l_tile_comp->y0); if (l_tccp->qmfbid == 1) { for (i = 0; i < l_nb_elem; ++i) { @@ -2080,8 +2401,8 @@ static OPJ_BOOL opj_tcd_mct_encode(opj_tcd_t *p_tcd) { opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles; opj_tcd_tilecomp_t * l_tile_comp = p_tcd->tcd_image->tiles->comps; - OPJ_UINT32 samples = (OPJ_UINT32)((l_tile_comp->x1 - l_tile_comp->x0) * - (l_tile_comp->y1 - l_tile_comp->y0)); + OPJ_SIZE_T samples = (OPJ_SIZE_T)(l_tile_comp->x1 - l_tile_comp->x0) * + (OPJ_SIZE_T)(l_tile_comp->y1 - l_tile_comp->y0); OPJ_UINT32 i; OPJ_BYTE ** l_data = 00; opj_tcp_t * l_tcp = p_tcd->tcp; @@ -2196,7 +2517,8 @@ static OPJ_BOOL opj_tcd_t2_encode(opj_tcd_t *p_tcd, OPJ_BYTE * p_dest_data, OPJ_UINT32 * p_data_written, OPJ_UINT32 p_max_dest_size, - opj_codestream_info_t *p_cstr_info) + opj_codestream_info_t *p_cstr_info, + opj_event_mgr_t *p_manager) { opj_t2_t * l_t2; @@ -2217,7 +2539,8 @@ static OPJ_BOOL opj_tcd_t2_encode(opj_tcd_t *p_tcd, p_tcd->tp_num, p_tcd->tp_pos, p_tcd->cur_pino, - FINAL_PASS)) { + FINAL_PASS, + p_manager)) { opj_t2_destroy(l_t2); return OPJ_FALSE; } @@ -2232,7 +2555,8 @@ static OPJ_BOOL opj_tcd_t2_encode(opj_tcd_t *p_tcd, static OPJ_BOOL opj_tcd_rate_allocate_encode(opj_tcd_t *p_tcd, OPJ_BYTE * p_dest_data, OPJ_UINT32 p_max_dest_size, - opj_codestream_info_t *p_cstr_info) + opj_codestream_info_t *p_cstr_info, + opj_event_mgr_t *p_manager) { opj_cp_t * l_cp = p_tcd->cp; OPJ_UINT32 l_nb_written = 0; @@ -2246,7 +2570,7 @@ static OPJ_BOOL opj_tcd_rate_allocate_encode(opj_tcd_t *p_tcd, /* fixed_quality */ /* Normal Rate/distortion allocation */ if (! opj_tcd_rateallocate(p_tcd, p_dest_data, &l_nb_written, p_max_dest_size, - p_cstr_info)) { + p_cstr_info, p_manager)) { return OPJ_FALSE; } } else { @@ -2260,13 +2584,15 @@ static OPJ_BOOL opj_tcd_rate_allocate_encode(opj_tcd_t *p_tcd, OPJ_BOOL opj_tcd_copy_tile_data(opj_tcd_t *p_tcd, OPJ_BYTE * p_src, - OPJ_UINT32 p_src_length) + OPJ_SIZE_T p_src_length) { - OPJ_UINT32 i, j, l_data_size = 0; + OPJ_UINT32 i; + OPJ_SIZE_T j; + OPJ_SIZE_T l_data_size = 0; opj_image_comp_t * l_img_comp = 00; opj_tcd_tilecomp_t * l_tilec = 00; OPJ_UINT32 l_size_comp, l_remaining; - OPJ_UINT32 l_nb_elem; + OPJ_SIZE_T l_nb_elem; l_data_size = opj_tcd_get_encoded_tile_size(p_tcd); if (l_data_size != p_src_length) { @@ -2278,8 +2604,8 @@ OPJ_BOOL opj_tcd_copy_tile_data(opj_tcd_t *p_tcd, for (i = 0; i < p_tcd->image->numcomps; ++i) { l_size_comp = l_img_comp->prec >> 3; /*(/ 8)*/ l_remaining = l_img_comp->prec & 7; /* (%8) */ - l_nb_elem = (OPJ_UINT32)((l_tilec->x1 - l_tilec->x0) * (l_tilec->y1 - - l_tilec->y0)); + l_nb_elem = (OPJ_SIZE_T)(l_tilec->x1 - l_tilec->x0) * + (OPJ_SIZE_T)(l_tilec->y1 - l_tilec->y0); if (l_remaining) { ++l_size_comp; @@ -2348,3 +2674,125 @@ OPJ_BOOL opj_tcd_is_band_empty(opj_tcd_band_t* band) { return (band->x1 - band->x0 == 0) || (band->y1 - band->y0 == 0); } + +OPJ_BOOL opj_tcd_is_subband_area_of_interest(opj_tcd_t *tcd, + OPJ_UINT32 compno, + OPJ_UINT32 resno, + OPJ_UINT32 bandno, + OPJ_UINT32 band_x0, + OPJ_UINT32 band_y0, + OPJ_UINT32 band_x1, + OPJ_UINT32 band_y1) +{ + /* Note: those values for filter_margin are in part the result of */ + /* experimentation. The value 2 for QMFBID=1 (5x3 filter) can be linked */ + /* to the maximum left/right extension given in tables F.2 and F.3 of the */ + /* standard. The value 3 for QMFBID=0 (9x7 filter) is more suspicious, */ + /* since F.2 and F.3 would lead to 4 instead, so the current 3 might be */ + /* needed to be bumped to 4, in case inconsistencies are found while */ + /* decoding parts of irreversible coded images. */ + /* See opj_dwt_decode_partial_53 and opj_dwt_decode_partial_97 as well */ + OPJ_UINT32 filter_margin = (tcd->tcp->tccps[compno].qmfbid == 1) ? 2 : 3; + opj_tcd_tilecomp_t *tilec = &(tcd->tcd_image->tiles->comps[compno]); + opj_image_comp_t* image_comp = &(tcd->image->comps[compno]); + /* Compute the intersection of the area of interest, expressed in tile coordinates */ + /* with the tile coordinates */ + OPJ_UINT32 tcx0 = opj_uint_max( + (OPJ_UINT32)tilec->x0, + opj_uint_ceildiv(tcd->win_x0, image_comp->dx)); + OPJ_UINT32 tcy0 = opj_uint_max( + (OPJ_UINT32)tilec->y0, + opj_uint_ceildiv(tcd->win_y0, image_comp->dy)); + OPJ_UINT32 tcx1 = opj_uint_min( + (OPJ_UINT32)tilec->x1, + opj_uint_ceildiv(tcd->win_x1, image_comp->dx)); + OPJ_UINT32 tcy1 = opj_uint_min( + (OPJ_UINT32)tilec->y1, + opj_uint_ceildiv(tcd->win_y1, image_comp->dy)); + /* Compute number of decomposition for this band. See table F-1 */ + OPJ_UINT32 nb = (resno == 0) ? + tilec->numresolutions - 1 : + tilec->numresolutions - resno; + /* Map above tile-based coordinates to sub-band-based coordinates per */ + /* equation B-15 of the standard */ + OPJ_UINT32 x0b = bandno & 1; + OPJ_UINT32 y0b = bandno >> 1; + OPJ_UINT32 tbx0 = (nb == 0) ? tcx0 : + (tcx0 <= (1U << (nb - 1)) * x0b) ? 0 : + opj_uint_ceildivpow2(tcx0 - (1U << (nb - 1)) * x0b, nb); + OPJ_UINT32 tby0 = (nb == 0) ? tcy0 : + (tcy0 <= (1U << (nb - 1)) * y0b) ? 0 : + opj_uint_ceildivpow2(tcy0 - (1U << (nb - 1)) * y0b, nb); + OPJ_UINT32 tbx1 = (nb == 0) ? tcx1 : + (tcx1 <= (1U << (nb - 1)) * x0b) ? 0 : + opj_uint_ceildivpow2(tcx1 - (1U << (nb - 1)) * x0b, nb); + OPJ_UINT32 tby1 = (nb == 0) ? tcy1 : + (tcy1 <= (1U << (nb - 1)) * y0b) ? 0 : + opj_uint_ceildivpow2(tcy1 - (1U << (nb - 1)) * y0b, nb); + OPJ_BOOL intersects; + + if (tbx0 < filter_margin) { + tbx0 = 0; + } else { + tbx0 -= filter_margin; + } + if (tby0 < filter_margin) { + tby0 = 0; + } else { + tby0 -= filter_margin; + } + tbx1 = opj_uint_adds(tbx1, filter_margin); + tby1 = opj_uint_adds(tby1, filter_margin); + + intersects = band_x0 < tbx1 && band_y0 < tby1 && band_x1 > tbx0 && + band_y1 > tby0; + +#ifdef DEBUG_VERBOSE + printf("compno=%u resno=%u nb=%u bandno=%u x0b=%u y0b=%u band=%u,%u,%u,%u tb=%u,%u,%u,%u -> %u\n", + compno, resno, nb, bandno, x0b, y0b, + band_x0, band_y0, band_x1, band_y1, + tbx0, tby0, tbx1, tby1, intersects); +#endif + return intersects; +} + +/** Returns whether a tile componenent is fully decoded, taking into account + * p_tcd->win_* members. + * + * @param p_tcd TCD handle. + * @param compno Component number + * @return OPJ_TRUE whether the tile componenent is fully decoded + */ +static OPJ_BOOL opj_tcd_is_whole_tilecomp_decoding(opj_tcd_t *p_tcd, + OPJ_UINT32 compno) +{ + opj_tcd_tilecomp_t* tilec = &(p_tcd->tcd_image->tiles->comps[compno]); + opj_image_comp_t* image_comp = &(p_tcd->image->comps[compno]); + /* Compute the intersection of the area of interest, expressed in tile coordinates */ + /* with the tile coordinates */ + OPJ_UINT32 tcx0 = opj_uint_max( + (OPJ_UINT32)tilec->x0, + opj_uint_ceildiv(p_tcd->win_x0, image_comp->dx)); + OPJ_UINT32 tcy0 = opj_uint_max( + (OPJ_UINT32)tilec->y0, + opj_uint_ceildiv(p_tcd->win_y0, image_comp->dy)); + OPJ_UINT32 tcx1 = opj_uint_min( + (OPJ_UINT32)tilec->x1, + opj_uint_ceildiv(p_tcd->win_x1, image_comp->dx)); + OPJ_UINT32 tcy1 = opj_uint_min( + (OPJ_UINT32)tilec->y1, + opj_uint_ceildiv(p_tcd->win_y1, image_comp->dy)); + + OPJ_UINT32 shift = tilec->numresolutions - tilec->minimum_num_resolutions; + /* Tolerate small margin within the reduced resolution factor to consider if */ + /* the whole tile path must be taken */ + return (tcx0 >= (OPJ_UINT32)tilec->x0 && + tcy0 >= (OPJ_UINT32)tilec->y0 && + tcx1 <= (OPJ_UINT32)tilec->x1 && + tcy1 <= (OPJ_UINT32)tilec->y1 && + (shift >= 32 || + (((tcx0 - (OPJ_UINT32)tilec->x0) >> shift) == 0 && + ((tcy0 - (OPJ_UINT32)tilec->y0) >> shift) == 0 && + (((OPJ_UINT32)tilec->x1 - tcx1) >> shift) == 0 && + (((OPJ_UINT32)tilec->y1 - tcy1) >> shift) == 0))); +} diff --git a/openjpeg/src/lib/openjp2/tcd.h b/openjpeg/src/lib/openjp2/tcd.h index 3f40b3595..e3214c1d9 100644 --- a/openjpeg/src/lib/openjp2/tcd.h +++ b/openjpeg/src/lib/openjp2/tcd.h @@ -13,6 +13,7 @@ * Copyright (c) 2005, Herve Drolon, FreeImage Team * Copyright (c) 2008, 2011-2012, Centre National d'Etudes Spatiales (CNES), FR * Copyright (c) 2012, CS Systemes d'Information, France + * Copyright (c) 2017, IntoPIX SA <support@intopix.com> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -133,6 +134,8 @@ typedef struct opj_tcd_cblk_dec { OPJ_UINT32 m_current_max_segs; /* allocated number of segs[] items */ OPJ_UINT32 numchunks; /* Number of valid chunks items */ OPJ_UINT32 numchunksalloc; /* Number of chunks item allocated */ + /* Decoded code-block. Only used for subtile decoding. Otherwise tilec->data is directly updated */ + OPJ_INT32* decoded_data; } opj_tcd_cblk_dec_t; /** Precinct structure */ @@ -174,12 +177,20 @@ typedef struct opj_tcd_resolution { OPJ_UINT32 numbands; /* subband information */ opj_tcd_band_t bands[3]; + + /* dimension of the resolution limited to window of interest. Only valid if tcd->whole_tile_decoding is set */ + OPJ_UINT32 win_x0; + OPJ_UINT32 win_y0; + OPJ_UINT32 win_x1; + OPJ_UINT32 win_y1; } opj_tcd_resolution_t; /** Tile-component structure */ typedef struct opj_tcd_tilecomp { /* dimension of component : left upper corner (x0, y0) right low corner (x1,y1) */ OPJ_INT32 x0, y0, x1, y1; + /* component number */ + OPJ_UINT32 compno; /* number of resolutions level */ OPJ_UINT32 numresolutions; /* number of resolutions level to decode (at max)*/ @@ -188,14 +199,24 @@ typedef struct opj_tcd_tilecomp { opj_tcd_resolution_t *resolutions; /* size of data for resolutions (in bytes) */ OPJ_UINT32 resolutions_size; - /* data of the component */ + + /* data of the component. For decoding, only valid if tcd->whole_tile_decoding is set (so exclusive of data_win member) */ OPJ_INT32 *data; /* if true, then need to free after usage, otherwise do not free */ OPJ_BOOL ownsData; /* we may either need to allocate this amount of data, or re-use image data and ignore this value */ - OPJ_UINT32 data_size_needed; + size_t data_size_needed; /* size of the data of the component */ - OPJ_UINT32 data_size; + size_t data_size; + + /** data of the component limited to window of interest. Only valid for decoding and if tcd->whole_tile_decoding is NOT set (so exclusive of data member) */ + OPJ_INT32 *data_win; + /* dimension of the component limited to window of interest. Only valid for decoding and if tcd->whole_tile_decoding is NOT set */ + OPJ_UINT32 win_x0; + OPJ_UINT32 win_y0; + OPJ_UINT32 win_x1; + OPJ_UINT32 win_y1; + /* add fixed_quality */ OPJ_INT32 numpix; } opj_tcd_tilecomp_t; @@ -252,6 +273,15 @@ typedef struct opj_tcd { OPJ_BITFIELD m_is_decoder : 1; /** Thread pool */ opj_thread_pool_t* thread_pool; + /** Coordinates of the window of interest, in grid reference space */ + OPJ_UINT32 win_x0; + OPJ_UINT32 win_y0; + OPJ_UINT32 win_x1; + OPJ_UINT32 win_y1; + /** Only valid for decoding. Whether the whole tile is decoded, or just the region in win_x0/win_y0/win_x1/win_y1 */ + OPJ_BOOL whole_tile_decoding; + /* Array of size image->numcomps indicating if a component must be decoded. NULL if all components must be decoded */ + OPJ_BOOL* used_component; } opj_tcd_t; /** @name Exported functions */ @@ -317,12 +347,14 @@ OPJ_BOOL opj_tcd_rateallocate(opj_tcd_t *tcd, OPJ_BYTE *dest, OPJ_UINT32 * p_data_written, OPJ_UINT32 len, - opj_codestream_info_t *cstr_info); + opj_codestream_info_t *cstr_info, + opj_event_mgr_t *p_manager); /** * Gets the maximum tile size that will be taken by the tile once decoded. */ -OPJ_UINT32 opj_tcd_get_decoded_tile_size(opj_tcd_t *p_tcd); +OPJ_UINT32 opj_tcd_get_decoded_tile_size(opj_tcd_t *p_tcd, + OPJ_BOOL take_into_account_partial_decoding); /** * Encodes a tile from the raw image into the given buffer. @@ -332,6 +364,7 @@ OPJ_UINT32 opj_tcd_get_decoded_tile_size(opj_tcd_t *p_tcd); * @param p_data_written pointer to an int that is incremented by the number of bytes really written on p_dest * @param p_len Maximum length of the destination buffer * @param p_cstr_info Codestream information structure + * @param p_manager the user event manager * @return true if the coding is successful. */ OPJ_BOOL opj_tcd_encode_tile(opj_tcd_t *p_tcd, @@ -339,12 +372,21 @@ OPJ_BOOL opj_tcd_encode_tile(opj_tcd_t *p_tcd, OPJ_BYTE *p_dest, OPJ_UINT32 * p_data_written, OPJ_UINT32 p_len, - struct opj_codestream_info *p_cstr_info); + struct opj_codestream_info *p_cstr_info, + opj_event_mgr_t *p_manager); /** Decode a tile from a buffer into a raw image @param tcd TCD handle +@param win_x0 Upper left x of region to decode (in grid coordinates) +@param win_y0 Upper left y of region to decode (in grid coordinates) +@param win_x1 Lower right x of region to decode (in grid coordinates) +@param win_y1 Lower right y of region to decode (in grid coordinates) +@param numcomps_to_decode Size of the comps_indices array, or 0 if decoding all components. +@param comps_indices Array of numcomps values representing the indices + of the components to decode (relative to the + codestream, starting at 0). Or NULL if decoding all components. @param src Source buffer @param len Length of source buffer @param tileno Number that identifies one of the tiles to be decoded @@ -352,6 +394,12 @@ Decode a tile from a buffer into a raw image @param manager the event manager. */ OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *tcd, + OPJ_UINT32 win_x0, + OPJ_UINT32 win_y0, + OPJ_UINT32 win_x1, + OPJ_UINT32 win_y1, + OPJ_UINT32 numcomps_to_decode, + const OPJ_UINT32 *comps_indices, OPJ_BYTE *src, OPJ_UINT32 len, OPJ_UINT32 tileno, @@ -369,7 +417,7 @@ OPJ_BOOL opj_tcd_update_tile_data(opj_tcd_t *p_tcd, /** * */ -OPJ_UINT32 opj_tcd_get_encoded_tile_size(opj_tcd_t *p_tcd); +OPJ_SIZE_T opj_tcd_get_encoded_tile_size(opj_tcd_t *p_tcd); /** * Initialize the tile coder and may reuse some meory. @@ -388,7 +436,7 @@ OPJ_BOOL opj_tcd_init_encode_tile(opj_tcd_t *p_tcd, */ OPJ_BOOL opj_tcd_copy_tile_data(opj_tcd_t *p_tcd, OPJ_BYTE * p_src, - OPJ_UINT32 p_src_length); + OPJ_SIZE_T p_src_length); /** * Allocates tile component data @@ -406,6 +454,30 @@ OPJ_BOOL opj_tcd_is_band_empty(opj_tcd_band_t* band); /** Reinitialize a segment */ void opj_tcd_reinit_segment(opj_tcd_seg_t* seg); + +/** Returns whether a sub-band region contributes to the area of interest + * tcd->win_x0,tcd->win_y0,tcd->win_x1,tcd->win_y1. + * + * @param tcd TCD handle. + * @param compno Component number + * @param resno Resolution number + * @param bandno Band number (*not* band index, ie 0, 1, 2 or 3) + * @param x0 Upper left x in subband coordinates + * @param y0 Upper left y in subband coordinates + * @param x1 Lower right x in subband coordinates + * @param y1 Lower right y in subband coordinates + * @return OPJ_TRUE whether the sub-band region contributs to the area of + * interest. + */ +OPJ_BOOL opj_tcd_is_subband_area_of_interest(opj_tcd_t *tcd, + OPJ_UINT32 compno, + OPJ_UINT32 resno, + OPJ_UINT32 bandno, + OPJ_UINT32 x0, + OPJ_UINT32 y0, + OPJ_UINT32 x1, + OPJ_UINT32 y1); + /* ----------------------------------------------------------------------- */ /*@}*/ diff --git a/openjpeg/src/lib/openjp2/test_sparse_array.c b/openjpeg/src/lib/openjp2/test_sparse_array.c new file mode 100644 index 000000000..8e1364515 --- /dev/null +++ b/openjpeg/src/lib/openjp2/test_sparse_array.c @@ -0,0 +1,174 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2017, IntoPix SA <contact@intopix.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#undef NDEBUG + +#include "opj_includes.h" + +int main() +{ + OPJ_UINT32 i, j, w, h; + OPJ_INT32 buffer[ 99 * 101 ]; + OPJ_BOOL ret; + opj_sparse_array_int32_t* sa; + + sa = opj_sparse_array_int32_create(0, 1, 1, 1); + assert(sa == NULL); + opj_sparse_array_int32_free(sa); + + sa = opj_sparse_array_int32_create(1, 0, 1, 1); + assert(sa == NULL); + + sa = opj_sparse_array_int32_create(1, 1, 0, 1); + assert(sa == NULL); + + sa = opj_sparse_array_int32_create(1, 1, 1, 0); + assert(sa == NULL); + + sa = opj_sparse_array_int32_create(99, 101, ~0U, ~0U); + assert(sa == NULL); + + sa = opj_sparse_array_int32_create(99, 101, 15, 17); + opj_sparse_array_int32_free(sa); + + sa = opj_sparse_array_int32_create(99, 101, 15, 17); + ret = opj_sparse_array_int32_read(sa, 0, 0, 0, 1, buffer, 1, 1, OPJ_FALSE); + assert(!ret); + ret = opj_sparse_array_int32_read(sa, 0, 0, 1, 0, buffer, 1, 1, OPJ_FALSE); + assert(!ret); + ret = opj_sparse_array_int32_read(sa, 0, 0, 100, 1, buffer, 1, 1, OPJ_FALSE); + assert(!ret); + ret = opj_sparse_array_int32_read(sa, 0, 0, 1, 102, buffer, 1, 1, OPJ_FALSE); + assert(!ret); + ret = opj_sparse_array_int32_read(sa, 1, 0, 0, 1, buffer, 1, 1, OPJ_FALSE); + assert(!ret); + ret = opj_sparse_array_int32_read(sa, 0, 1, 1, 0, buffer, 1, 1, OPJ_FALSE); + assert(!ret); + ret = opj_sparse_array_int32_read(sa, 99, 101, 99, 101, buffer, 1, 1, + OPJ_FALSE); + assert(!ret); + + buffer[0] = 1; + ret = opj_sparse_array_int32_read(sa, 0, 0, 1, 1, buffer, 1, 1, OPJ_FALSE); + assert(ret); + assert(buffer[0] == 0); + + memset(buffer, 0xFF, sizeof(buffer)); + ret = opj_sparse_array_int32_read(sa, 0, 0, 99, 101, buffer, 1, 99, OPJ_FALSE); + assert(ret); + for (i = 0; i < 99 * 101; i++) { + assert(buffer[i] == 0); + } + + buffer[0] = 1; + ret = opj_sparse_array_int32_write(sa, 4, 5, 4 + 1, 5 + 1, buffer, 1, 1, + OPJ_FALSE); + assert(ret); + + buffer[0] = 2; + ret = opj_sparse_array_int32_write(sa, 4, 5, 4 + 1, 5 + 1, buffer, 1, 1, + OPJ_FALSE); + assert(ret); + + buffer[0] = 0; + buffer[1] = 0xFF; + ret = opj_sparse_array_int32_read(sa, 4, 5, 4 + 1, 5 + 1, buffer, 1, 1, + OPJ_FALSE); + assert(ret); + assert(buffer[0] == 2); + assert(buffer[1] == 0xFF); + + buffer[0] = 0xFF; + buffer[1] = 0xFF; + buffer[2] = 0xFF; + ret = opj_sparse_array_int32_read(sa, 4, 5, 4 + 1, 5 + 2, buffer, 0, 1, + OPJ_FALSE); + assert(ret); + assert(buffer[0] == 2); + assert(buffer[1] == 0); + assert(buffer[2] == 0xFF); + + buffer[0] = 3; + ret = opj_sparse_array_int32_write(sa, 4, 5, 4 + 1, 5 + 1, buffer, 0, 1, + OPJ_FALSE); + assert(ret); + + buffer[0] = 0; + buffer[1] = 0xFF; + ret = opj_sparse_array_int32_read(sa, 4, 5, 4 + 1, 5 + 1, buffer, 1, 1, + OPJ_FALSE); + assert(ret); + assert(buffer[0] == 3); + assert(buffer[1] == 0xFF); + + w = 15 + 1; + h = 17 + 1; + memset(buffer, 0xFF, sizeof(buffer)); + ret = opj_sparse_array_int32_read(sa, 2, 1, 2 + w, 1 + h, buffer, 1, w, + OPJ_FALSE); + assert(ret); + for (j = 0; j < h; j++) { + for (i = 0; i < w; i++) { + if (i == 4 - 2 && j == 5 - 1) { + assert(buffer[ j * w + i ] == 3); + } else { + assert(buffer[ j * w + i ] == 0); + } + } + } + + opj_sparse_array_int32_free(sa); + + + sa = opj_sparse_array_int32_create(99, 101, 15, 17); + memset(buffer, 0xFF, sizeof(buffer)); + ret = opj_sparse_array_int32_read(sa, 0, 0, 2, 1, buffer, 2, 4, OPJ_FALSE); + assert(ret); + assert(buffer[0] == 0); + assert(buffer[1] == -1); + assert(buffer[2] == 0); + + buffer[0] = 1; + buffer[2] = 3; + ret = opj_sparse_array_int32_write(sa, 0, 0, 2, 1, buffer, 2, 4, OPJ_FALSE); + assert(ret); + + memset(buffer, 0xFF, sizeof(buffer)); + ret = opj_sparse_array_int32_read(sa, 0, 0, 2, 1, buffer, 2, 4, OPJ_FALSE); + assert(ret); + assert(buffer[0] == 1); + assert(buffer[1] == -1); + assert(buffer[2] == 3); + + opj_sparse_array_int32_free(sa); + + return 0; +} diff --git a/openjpeg/src/lib/openjp2/thread.c b/openjpeg/src/lib/openjp2/thread.c index 8b56aa4d5..af33c2c80 100644 --- a/openjpeg/src/lib/openjp2/thread.c +++ b/openjpeg/src/lib/openjp2/thread.c @@ -29,9 +29,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "opj_includes.h" - -#include "thread.h" #include <assert.h> #ifdef MUTEX_win32 @@ -46,6 +43,8 @@ #include <windows.h> #include <process.h> +#include "opj_includes.h" + OPJ_BOOL OPJ_CALLCONV opj_has_thread_support(void) { return OPJ_TRUE; @@ -289,6 +288,10 @@ void opj_thread_join(opj_thread_t* thread) #include <stdlib.h> #include <unistd.h> +/* Moved after all system includes, and in particular pthread.h, so as to */ +/* avoid poisoning issuing with malloc() use in pthread.h with ulibc (#1013) */ +#include "opj_includes.h" + OPJ_BOOL OPJ_CALLCONV opj_has_thread_support(void) { return OPJ_TRUE; @@ -425,6 +428,8 @@ void opj_thread_join(opj_thread_t* thread) #else /* Stub implementation */ +#include "opj_includes.h" + OPJ_BOOL OPJ_CALLCONV opj_has_thread_support(void) { return OPJ_FALSE; |