[trunk] added an option to upsample image components in opj_decompress
authorMatthieu Darbois <mayeut@users.noreply.github.com>
Sat, 22 Nov 2014 17:59:07 +0000 (17:59 +0000)
committerMatthieu Darbois <mayeut@users.noreply.github.com>
Sat, 22 Nov 2014 17:59:07 +0000 (17:59 +0000)
Update  issue 289

Issue is left open since there's still one image failing the tests.

src/bin/jp2/opj_decompress.c
tests/conformance/CMakeLists.txt

index c97835a89312017d1adabd367d0b8deabfd4eae2..e1ce8a1accb83cfa31b13e08bcc7bccaf63a3632 100644 (file)
@@ -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(&parameters);
+                               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(&parameters);
                                opj_destroy_codec(l_codec);
-                               opj_stream_destroy(l_stream);
                                return EXIT_FAILURE;
                        }
                }
index 157c46d1e6b1a9b322f26ba4ecd6fc3bdd4730a9..c4d1bb6636169c994dbd8934c84b2d8f3ac95499 100644 (file)
@@ -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")