Make opj_set_decode_area() and opj_decode() take into account opj_set_decoded_resolution_factor() (#1006, affect API use)

* Better document usage of opj_set_decode_area(), ie expecting coordinates
  in full resolution/reference grid even if requesting at a lower resolution
  factor
* Make sure that image->comps[].factor is set by opj_set_decode_area() and
  opj_decode() from the value specified in opj_set_decoded_resolution_factor()
* opj_decompress: add 2 environmenet variables to test alternate ways of
  using the API, namely USE_OPJ_SET_DECODED_RESOLUTION_FACTOR=YES to use
  opj_set_decoded_resolution_factor() instead of parameters.cp_reduce, and
  SKIP_OPJ_SET_DECODE_AREA=YES to not call opj_set_decode_area() if -d is
  not specified.
This commit is contained in:
Even Rouault 2017-08-28 14:57:49 +02:00
parent 5a4a10120a
commit 8f92fc9791
3 changed files with 128 additions and 51 deletions

View File

@ -1297,6 +1297,7 @@ int main(int argc, char **argv)
int failed = 0; int failed = 0;
OPJ_FLOAT64 t, tCumulative = 0; OPJ_FLOAT64 t, tCumulative = 0;
OPJ_UINT32 numDecompressedImages = 0; OPJ_UINT32 numDecompressedImages = 0;
OPJ_UINT32 cp_reduce;
/* set decoding parameters to default values */ /* set decoding parameters to default values */
set_default_parameters(&parameters); set_default_parameters(&parameters);
@ -1310,6 +1311,14 @@ int main(int argc, char **argv)
goto fin; 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 */ /* Initialize reading of directory */
if (img_fol.set_imgdir == 1) { if (img_fol.set_imgdir == 1) {
@ -1446,9 +1455,33 @@ int main(int argc, char **argv)
goto fin; 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 (!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 */ /* Optional if you want decode the entire image */
if (!opj_set_decode_area(l_codec, image, (OPJ_INT32)parameters.DA_x0, 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_y0, (OPJ_INT32)parameters.DA_x1,
(OPJ_INT32)parameters.DA_y1)) { (OPJ_INT32)parameters.DA_y1)) {
fprintf(stderr, "ERROR -> opj_decompress: failed to set the decoded area\n"); fprintf(stderr, "ERROR -> opj_decompress: failed to set the decoded area\n");
@ -1471,15 +1504,6 @@ int main(int argc, char **argv)
} }
} else { } else {
/* It is just here to illustrate how to use the resolution after set parameters */
/*if (!opj_set_decoded_resolution_factor(l_codec, 5)) {
fprintf(stderr, "ERROR -> opj_decompress: failed to set the resolution factor tile!\n");
opj_destroy_codec(l_codec);
opj_stream_destroy(l_stream);
opj_image_destroy(image);
failed = 1; goto fin;
}*/
if (!opj_get_decoded_tile(l_codec, l_stream, image, parameters.tile_index)) { if (!opj_get_decoded_tile(l_codec, l_stream, image, parameters.tile_index)) {
fprintf(stderr, "ERROR -> opj_decompress: failed to decode tile!\n"); fprintf(stderr, "ERROR -> opj_decompress: failed to decode tile!\n");
opj_destroy_codec(l_codec); opj_destroy_codec(l_codec);

View File

@ -9143,6 +9143,51 @@ static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd, OPJ_BYTE * p_data,
return OPJ_TRUE; return OPJ_TRUE;
} }
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_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;
l_img_comp++;
}
return OPJ_TRUE;
}
OPJ_BOOL opj_j2k_set_decode_area(opj_j2k_t *p_j2k, OPJ_BOOL opj_j2k_set_decode_area(opj_j2k_t *p_j2k,
opj_image_t* p_image, opj_image_t* p_image,
OPJ_INT32 p_start_x, OPJ_INT32 p_start_y, OPJ_INT32 p_start_x, OPJ_INT32 p_start_y,
@ -9151,10 +9196,8 @@ OPJ_BOOL opj_j2k_set_decode_area(opj_j2k_t *p_j2k,
{ {
opj_cp_t * l_cp = &(p_j2k->m_cp); opj_cp_t * l_cp = &(p_j2k->m_cp);
opj_image_t * l_image = p_j2k->m_private_image; opj_image_t * l_image = p_j2k->m_private_image;
OPJ_BOOL ret;
OPJ_UINT32 it_comp; OPJ_UINT32 it_comp;
OPJ_INT32 l_comp_x1, l_comp_y1;
opj_image_comp_t* l_img_comp = NULL;
/* Check if we are read the main header */ /* Check if we are read the main header */
if (p_j2k->m_specific_param.m_decoder.m_state != J2K_STATE_TPHSOT) { if (p_j2k->m_specific_param.m_decoder.m_state != J2K_STATE_TPHSOT) {
@ -9163,6 +9206,12 @@ OPJ_BOOL opj_j2k_set_decode_area(opj_j2k_t *p_j2k,
return OPJ_FALSE; 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) { if (!p_start_x && !p_start_y && !p_end_x && !p_end_y) {
opj_event_msg(p_manager, EVT_INFO, opj_event_msg(p_manager, EVT_INFO,
"No decoded area parameters, set the decoded area to the whole image\n"); "No decoded area parameters, set the decoded area to the whole image\n");
@ -9172,7 +9221,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_x = l_cp->tw;
p_j2k->m_specific_param.m_decoder.m_end_tile_y = l_cp->th; 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);
} }
/* ----- */ /* ----- */
@ -9274,44 +9328,14 @@ OPJ_BOOL opj_j2k_set_decode_area(opj_j2k_t *p_j2k,
p_j2k->m_specific_param.m_decoder.m_discard_tiles = 1; p_j2k->m_specific_param.m_decoder.m_discard_tiles = 1;
l_img_comp = p_image->comps; ret = opj_j2k_update_image_dimensions(p_image, p_manager);
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;
l_img_comp++;
}
if (ret) {
opj_event_msg(p_manager, EVT_INFO, "Setting decoding area to %d,%d,%d,%d\n", 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); 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) opj_j2k_t* opj_j2k_create_decompress(void)
@ -10796,6 +10820,31 @@ OPJ_BOOL opj_j2k_decode(opj_j2k_t * p_j2k,
return OPJ_FALSE; 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;
}
}
p_j2k->m_output_image = opj_image_create0(); p_j2k->m_output_image = opj_image_create0();
if (!(p_j2k->m_output_image)) { if (!(p_j2k->m_output_image)) {
return OPJ_FALSE; return OPJ_FALSE;

View File

@ -1336,6 +1336,10 @@ OPJ_API OPJ_BOOL OPJ_CALLCONV opj_read_header(opj_stream_t *p_stream,
/** /**
* Sets the given area to be decoded. This function should be called right after opj_read_header and before any tile header reading. * 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.
*
* @param p_codec the jpeg2000 codec. * @param p_codec the jpeg2000 codec.
* @param p_image the decoded image previously setted by opj_read_header * @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). * @param p_start_x the left position of the rectangle to decode (in image coordinates).