Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add capability to decode only a subset of all components of an image. #1022

Merged
merged 2 commits into from
Sep 26, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -8266,6 +8266,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 @@ -8914,6 +8919,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 @@ -9028,6 +9035,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 @@ -9228,6 +9240,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 @@ -10817,13 +10888,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 @@ -10874,23 +11003,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 @@ -11005,20 +11118,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 @@ -480,6 +480,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 @@ -705,6 +709,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