Skip to content

Commit

Permalink
Merge pull request #1022 from rouault/partial_component_decoding
Browse files Browse the repository at this point in the history
Add capability to decode only a subset of all components of an image.
  • Loading branch information
detonin authored Sep 26, 2017
2 parents 3f0de88 + e17bbde commit d45ccb0
Show file tree
Hide file tree
Showing 12 changed files with 408 additions and 47 deletions.
47 changes: 46 additions & 1 deletion src/bin/jp2/opj_decompress.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ typedef struct opj_decompress_params {
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;

/* -------------------------------------------------------------------------- */
Expand Down Expand Up @@ -227,6 +231,10 @@ static void decode_help_display(void)
" 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"
Expand Down Expand Up @@ -560,7 +568,7 @@ int parse_cmdline_decoder(int argc, char **argv,
{"quiet", NO_ARG, NULL, 1},
};

const char optlist[] = "i:o:r:l:x:d:t:p:"
const char optlist[] = "i:o:r:l:x:d:t:p:c:"

/* UniPG>> */
#ifdef USE_JPWL
Expand Down Expand Up @@ -770,6 +778,25 @@ int parse_cmdline_decoder(int argc, char **argv,
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;
/* ----------------------------------------------------- */

Expand Down Expand Up @@ -1015,6 +1042,9 @@ static void destroy_parameters(opj_decompress_parameters* parameters)
free(parameters->precision);
parameters->precision = NULL;
}

free(parameters->comps_indices);
parameters->comps_indices = NULL;
}
}

Expand Down Expand Up @@ -1455,6 +1485,21 @@ int main(int argc, char **argv)
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 */
Expand Down
166 changes: 133 additions & 33 deletions src/lib/openjp2/j2k.c
Original file line number Diff line number Diff line change
Expand Up @@ -8280,6 +8280,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) {
Expand Down Expand Up @@ -8928,6 +8933,8 @@ OPJ_BOOL opj_j2k_decode_tile(opj_j2k_t * p_j2k,
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,
Expand Down Expand Up @@ -9042,6 +9049,11 @@ static OPJ_BOOL opj_j2k_update_image_data(opj_tcd_t * p_tcd,
p_src_data = l_tilec->data_win;
}

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);

Expand Down Expand Up @@ -9242,6 +9254,65 @@ static OPJ_BOOL opj_j2k_update_image_dimensions(opj_image_t* p_image,
return OPJ_TRUE;
}

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;
}
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);

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,
Expand Down Expand Up @@ -10831,13 +10902,71 @@ 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;
}
Expand Down Expand Up @@ -10888,23 +11017,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;
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;
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,
Expand Down Expand Up @@ -11019,20 +11132,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,
Expand Down
19 changes: 19 additions & 0 deletions src/lib/openjp2/j2k.h
Original file line number Diff line number Diff line change
Expand Up @@ -482,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;
Expand Down Expand Up @@ -707,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.
*
Expand Down
20 changes: 20 additions & 0 deletions src/lib/openjp2/jp2.c
Original file line number Diff line number Diff line change
Expand Up @@ -1607,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;
Expand Down Expand Up @@ -3069,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,
Expand Down Expand Up @@ -3100,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;
}
Expand Down
Loading

0 comments on commit d45ccb0

Please sign in to comment.