From 131cc98491eff5136dac4415928174387ef3e613 Mon Sep 17 00:00:00 2001 From: Matthieu Darbois Date: Sat, 22 Nov 2014 17:59:07 +0000 Subject: [PATCH] [trunk] added an option to upsample image components in opj_decompress Update issue 289 Issue is left open since there's still one image failing the tests. --- src/bin/jp2/opj_decompress.c | 181 ++++++++++++++++++++++++++++++- tests/conformance/CMakeLists.txt | 1 + 2 files changed, 180 insertions(+), 2 deletions(-) diff --git a/src/bin/jp2/opj_decompress.c b/src/bin/jp2/opj_decompress.c index c97835a8..e1ce8a1a 100644 --- a/src/bin/jp2/opj_decompress.c +++ b/src/bin/jp2/opj_decompress.c @@ -140,6 +140,8 @@ typedef struct opj_decompress_params /* force output colorspace to RGB */ int force_rgb; + /* upsample components according to their dx/dy values */ + int upsample; }opj_decompress_parameters; /* -------------------------------------------------------------------------- */ @@ -211,6 +213,8 @@ static void decode_help_display(void) { " A 0 value can be specified (meaning original bit depth).\n" " -force-rgb\n" " Force output image colorspace to RGB\n" + " -upsample\n" + " Downsampled components will be upsampled to image size\n" "\n"); /* UniPG>> */ #ifdef USE_JPWL @@ -492,7 +496,8 @@ int parse_cmdline_decoder(int argc, char **argv, opj_decompress_parameters *para opj_option_t long_option[]={ {"ImgDir", REQ_ARG, NULL ,'y'}, {"OutFor", REQ_ARG, NULL ,'O'}, - {"force-rgb", NO_ARG, &(parameters->force_rgb), 1} + {"force-rgb", NO_ARG, &(parameters->force_rgb), 1}, + {"upsample", NO_ARG, &(parameters->upsample), 1} }; const char optlist[] = "i:o:r:l:x:d:t:p:" @@ -945,6 +950,166 @@ static opj_image_t* convert_gray_to_rgb(opj_image_t* 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 substraction 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 substraction 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 substraction 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 @@ -1187,6 +1352,19 @@ int main(int argc, char **argv) } } + /* Upsample components */ + /* ------------------- */ + if (parameters.upsample) + { + image = upsample_image_components(image); + if (image == NULL) { + fprintf(stderr, "ERROR -> opj_decompress: failed to upsample image components!\n"); + destroy_parameters(¶meters); + opj_destroy_codec(l_codec); + return EXIT_FAILURE; + } + } + /* Force RGB output */ /* ---------------- */ if (parameters.force_rgb) @@ -1207,7 +1385,6 @@ int main(int argc, char **argv) fprintf(stderr, "ERROR -> opj_decompress: failed to convert to RGB image!\n"); destroy_parameters(¶meters); opj_destroy_codec(l_codec); - opj_stream_destroy(l_stream); return EXIT_FAILURE; } } diff --git a/tests/conformance/CMakeLists.txt b/tests/conformance/CMakeLists.txt index 157c46d1..c4d1bb66 100644 --- a/tests/conformance/CMakeLists.txt +++ b/tests/conformance/CMakeLists.txt @@ -514,6 +514,7 @@ foreach(kdu_file ${kdu_j2k_conf_files}) COMMAND opj_decompress -i ${INPUT_CONF}/${filenameInput} -o ${TEMP}/${filenameInput}.ppm + -upsample ) if("${kdu_file}" STREQUAL "a6_mono_colr")