[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.
This commit is contained in:
Matthieu Darbois 2014-11-22 17:59:07 +00:00
parent 13bcb63b73
commit 131cc98491
2 changed files with 180 additions and 2 deletions

View File

@ -140,6 +140,8 @@ typedef struct opj_decompress_params
/* force output colorspace to RGB */ /* force output colorspace to RGB */
int force_rgb; int force_rgb;
/* upsample components according to their dx/dy values */
int upsample;
}opj_decompress_parameters; }opj_decompress_parameters;
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
@ -211,6 +213,8 @@ static void decode_help_display(void) {
" A 0 value can be specified (meaning original bit depth).\n" " A 0 value can be specified (meaning original bit depth).\n"
" -force-rgb\n" " -force-rgb\n"
" Force output image colorspace to RGB\n" " Force output image colorspace to RGB\n"
" -upsample\n"
" Downsampled components will be upsampled to image size\n"
"\n"); "\n");
/* UniPG>> */ /* UniPG>> */
#ifdef USE_JPWL #ifdef USE_JPWL
@ -492,7 +496,8 @@ int parse_cmdline_decoder(int argc, char **argv, opj_decompress_parameters *para
opj_option_t long_option[]={ opj_option_t long_option[]={
{"ImgDir", REQ_ARG, NULL ,'y'}, {"ImgDir", REQ_ARG, NULL ,'y'},
{"OutFor", REQ_ARG, NULL ,'O'}, {"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:" 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; 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 * 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 */ /* Force RGB output */
/* ---------------- */ /* ---------------- */
if (parameters.force_rgb) 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"); fprintf(stderr, "ERROR -> opj_decompress: failed to convert to RGB image!\n");
destroy_parameters(&parameters); destroy_parameters(&parameters);
opj_destroy_codec(l_codec); opj_destroy_codec(l_codec);
opj_stream_destroy(l_stream);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} }

View File

@ -514,6 +514,7 @@ foreach(kdu_file ${kdu_j2k_conf_files})
COMMAND opj_decompress COMMAND opj_decompress
-i ${INPUT_CONF}/${filenameInput} -i ${INPUT_CONF}/${filenameInput}
-o ${TEMP}/${filenameInput}.ppm -o ${TEMP}/${filenameInput}.ppm
-upsample
) )
if("${kdu_file}" STREQUAL "a6_mono_colr") if("${kdu_file}" STREQUAL "a6_mono_colr")