Merge pull request #1022 from rouault/partial_component_decoding
Add capability to decode only a subset of all components of an image.
This commit is contained in:
commit
d45ccb048b
|
@ -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;
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
/* ----------------------------------------------------- */
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
|
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -235,6 +235,12 @@ Decoding parameters are returned in jp2->j2k->cp.
|
|||
*/
|
||||
void opj_jp2_setup_decoder(opj_jp2_t *jp2, opj_dparameters_t *parameters);
|
||||
|
||||
/** Allocates worker threads for the compressor/decompressor.
|
||||
*
|
||||
* @param jp2 JP2 decompressor handle
|
||||
* @param num_threads Number of threads.
|
||||
* @return OPJ_TRUE in case of success.
|
||||
*/
|
||||
OPJ_BOOL opj_jp2_set_threads(opj_jp2_t *jp2, OPJ_UINT32 num_threads);
|
||||
|
||||
/**
|
||||
|
@ -327,6 +333,21 @@ OPJ_BOOL opj_jp2_read_header(opj_stream_private_t *p_stream,
|
|||
opj_image_t ** p_image,
|
||||
opj_event_mgr_t * p_manager);
|
||||
|
||||
/** Sets the indices of the components to decode.
|
||||
*
|
||||
* @param jp2 JP2 decompressor handle
|
||||
* @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_jp2_set_decoded_components(opj_jp2_t *jp2,
|
||||
OPJ_UINT32 numcomps,
|
||||
const OPJ_UINT32* comps_indices,
|
||||
opj_event_mgr_t * p_manager);
|
||||
|
||||
/**
|
||||
* Reads a tile header.
|
||||
* @param p_jp2 the jpeg2000 codec.
|
||||
|
|
|
@ -245,6 +245,12 @@ opj_codec_t* OPJ_CALLCONV opj_create_decompress(OPJ_CODEC_FORMAT p_format)
|
|||
OPJ_UINT32 res_factor,
|
||||
struct opj_event_mgr * p_manager)) opj_j2k_set_decoded_resolution_factor;
|
||||
|
||||
l_codec->m_codec_data.m_decompression.opj_set_decoded_components =
|
||||
(OPJ_BOOL(*)(void * p_codec,
|
||||
OPJ_UINT32 numcomps,
|
||||
const OPJ_UINT32 * comps_indices,
|
||||
struct opj_event_mgr * p_manager)) opj_j2k_set_decoded_components;
|
||||
|
||||
l_codec->opj_set_threads =
|
||||
(OPJ_BOOL(*)(void * p_codec, OPJ_UINT32 num_threads)) opj_j2k_set_threads;
|
||||
|
||||
|
@ -327,6 +333,12 @@ opj_codec_t* OPJ_CALLCONV opj_create_decompress(OPJ_CODEC_FORMAT p_format)
|
|||
OPJ_UINT32 res_factor,
|
||||
opj_event_mgr_t * p_manager)) opj_jp2_set_decoded_resolution_factor;
|
||||
|
||||
l_codec->m_codec_data.m_decompression.opj_set_decoded_components =
|
||||
(OPJ_BOOL(*)(void * p_codec,
|
||||
OPJ_UINT32 numcomps,
|
||||
const OPJ_UINT32 * comps_indices,
|
||||
struct opj_event_mgr * p_manager)) opj_jp2_set_decoded_components;
|
||||
|
||||
l_codec->opj_set_threads =
|
||||
(OPJ_BOOL(*)(void * p_codec, OPJ_UINT32 num_threads)) opj_jp2_set_threads;
|
||||
|
||||
|
@ -426,6 +438,36 @@ OPJ_BOOL OPJ_CALLCONV opj_read_header(opj_stream_t *p_stream,
|
|||
return OPJ_FALSE;
|
||||
}
|
||||
|
||||
|
||||
OPJ_BOOL OPJ_CALLCONV opj_set_decoded_components(opj_codec_t *p_codec,
|
||||
OPJ_UINT32 numcomps,
|
||||
const OPJ_UINT32* comps_indices,
|
||||
OPJ_BOOL apply_color_transforms)
|
||||
{
|
||||
if (p_codec) {
|
||||
opj_codec_private_t * l_codec = (opj_codec_private_t *) p_codec;
|
||||
|
||||
if (! l_codec->is_decompressor) {
|
||||
opj_event_msg(&(l_codec->m_event_mgr), EVT_ERROR,
|
||||
"Codec provided to the opj_set_decoded_components function is not a decompressor handler.\n");
|
||||
return OPJ_FALSE;
|
||||
}
|
||||
|
||||
if (apply_color_transforms) {
|
||||
opj_event_msg(&(l_codec->m_event_mgr), EVT_ERROR,
|
||||
"apply_color_transforms = OPJ_TRUE is not supported.\n");
|
||||
return OPJ_FALSE;
|
||||
}
|
||||
|
||||
return l_codec->m_codec_data.m_decompression.opj_set_decoded_components(
|
||||
l_codec->m_codec,
|
||||
numcomps,
|
||||
comps_indices,
|
||||
&(l_codec->m_event_mgr));
|
||||
}
|
||||
return OPJ_FALSE;
|
||||
}
|
||||
|
||||
OPJ_BOOL OPJ_CALLCONV opj_decode(opj_codec_t *p_codec,
|
||||
opj_stream_t *p_stream,
|
||||
opj_image_t* p_image)
|
||||
|
|
|
@ -1336,6 +1336,37 @@ OPJ_API OPJ_BOOL OPJ_CALLCONV opj_read_header(opj_stream_t *p_stream,
|
|||
opj_codec_t *p_codec,
|
||||
opj_image_t **p_image);
|
||||
|
||||
|
||||
/** Restrict the number of components to decode.
|
||||
*
|
||||
* This function should be called after opj_read_header().
|
||||
*
|
||||
* This function enables to restrict the set of decoded components to the
|
||||
* specified indices.
|
||||
* Note that the current implementation (apply_color_transforms == OPJ_FALSE)
|
||||
* is such that neither the multi-component transform at codestream level,
|
||||
* nor JP2 channel transformations will be applied.
|
||||
* Consequently the indices are relative to the codestream.
|
||||
*
|
||||
* Note: opj_decode_tile_data() should not be used together with opj_set_decoded_components().
|
||||
*
|
||||
* @param p_codec the jpeg2000 codec to read.
|
||||
* @param numcomps Size of the comps_indices array.
|
||||
* @param comps_indices Array of numcomps values representing the indices
|
||||
* of the components to decode (relative to the
|
||||
* codestream, starting at 0)
|
||||
* @param apply_color_transforms Whether multi-component transform at codestream level
|
||||
* or JP2 channel transformations should be applied.
|
||||
* Currently this parameter should be set to OPJ_FALSE.
|
||||
* Setting it to OPJ_TRUE will result in an error.
|
||||
*
|
||||
* @return OPJ_TRUE in case of success.
|
||||
*/
|
||||
OPJ_API OPJ_BOOL OPJ_CALLCONV opj_set_decoded_components(opj_codec_t *p_codec,
|
||||
OPJ_UINT32 numcomps,
|
||||
const OPJ_UINT32* comps_indices,
|
||||
OPJ_BOOL apply_color_transforms);
|
||||
|
||||
/**
|
||||
* Sets the given area to be decoded. This function should be called right after opj_read_header and before any tile header reading.
|
||||
*
|
||||
|
@ -1452,6 +1483,8 @@ OPJ_API OPJ_BOOL OPJ_CALLCONV opj_read_tile_header(opj_codec_t *p_codec,
|
|||
* Reads a tile data. This function is compulsory and allows one to decode tile data. opj_read_tile_header should be called before.
|
||||
* The user may need to refer to the image got by opj_read_header to understand the size being taken by the tile.
|
||||
*
|
||||
* Note: opj_decode_tile_data() should not be used together with opj_set_decoded_components().
|
||||
*
|
||||
* @param p_codec the jpeg2000 codec.
|
||||
* @param p_tile_index the index of the tile being decoded, this should be the value set by opj_read_tile_header.
|
||||
* @param p_data pointer to a memory block that will hold the decoded data.
|
||||
|
|
|
@ -111,6 +111,11 @@ typedef struct opj_codec_private {
|
|||
OPJ_UINT32 res_factor,
|
||||
opj_event_mgr_t * p_manager);
|
||||
|
||||
/** Set the decoded components */
|
||||
OPJ_BOOL(*opj_set_decoded_components)(void * p_codec,
|
||||
OPJ_UINT32 num_comps,
|
||||
const OPJ_UINT32* comps_indices,
|
||||
opj_event_mgr_t * p_manager);
|
||||
} m_decompression;
|
||||
|
||||
/**
|
||||
|
|
|
@ -679,6 +679,9 @@ void opj_tcd_destroy(opj_tcd_t *tcd)
|
|||
opj_free(tcd->tcd_image);
|
||||
tcd->tcd_image = 00;
|
||||
}
|
||||
|
||||
opj_free(tcd->used_component);
|
||||
|
||||
opj_free(tcd);
|
||||
}
|
||||
}
|
||||
|
@ -1439,6 +1442,8 @@ OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *p_tcd,
|
|||
OPJ_UINT32 win_y0,
|
||||
OPJ_UINT32 win_x1,
|
||||
OPJ_UINT32 win_y1,
|
||||
OPJ_UINT32 numcomps_to_decode,
|
||||
const OPJ_UINT32 *comps_indices,
|
||||
OPJ_BYTE *p_src,
|
||||
OPJ_UINT32 p_max_length,
|
||||
OPJ_UINT32 p_tile_no,
|
||||
|
@ -1457,7 +1462,27 @@ OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *p_tcd,
|
|||
p_tcd->win_y1 = win_y1;
|
||||
p_tcd->whole_tile_decoding = OPJ_TRUE;
|
||||
|
||||
opj_free(p_tcd->used_component);
|
||||
p_tcd->used_component = NULL;
|
||||
|
||||
if (numcomps_to_decode) {
|
||||
OPJ_BOOL* used_component = (OPJ_BOOL*) opj_calloc(sizeof(OPJ_BOOL),
|
||||
p_tcd->image->numcomps);
|
||||
if (used_component == NULL) {
|
||||
return OPJ_FALSE;
|
||||
}
|
||||
for (compno = 0; compno < numcomps_to_decode; compno++) {
|
||||
used_component[ comps_indices[compno] ] = OPJ_TRUE;
|
||||
}
|
||||
|
||||
p_tcd->used_component = used_component;
|
||||
}
|
||||
|
||||
for (compno = 0; compno < p_tcd->image->numcomps; compno++) {
|
||||
if (p_tcd->used_component != NULL && !p_tcd->used_component[compno]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!opj_tcd_is_whole_tilecomp_decoding(p_tcd, compno)) {
|
||||
p_tcd->whole_tile_decoding = OPJ_FALSE;
|
||||
break;
|
||||
|
@ -1475,6 +1500,10 @@ OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *p_tcd,
|
|||
OPJ_SIZE_T res_w = (OPJ_SIZE_T)(l_res->x1 - l_res->x0);
|
||||
OPJ_SIZE_T res_h = (OPJ_SIZE_T)(l_res->y1 - l_res->y0);
|
||||
|
||||
if (p_tcd->used_component != NULL && !p_tcd->used_component[compno]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* issue 733, l_data_size == 0U, probably something wrong should be checked before getting here */
|
||||
if (res_h > 0 && res_w > SIZE_MAX / res_h) {
|
||||
opj_event_msg(p_manager, EVT_ERROR,
|
||||
|
@ -1506,6 +1535,11 @@ OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *p_tcd,
|
|||
OPJ_UINT32 resno;
|
||||
opj_tcd_tilecomp_t* tilec = &(p_tcd->tcd_image->tiles->comps[compno]);
|
||||
opj_image_comp_t* image_comp = &(p_tcd->image->comps[compno]);
|
||||
|
||||
if (p_tcd->used_component != NULL && !p_tcd->used_component[compno]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Compute the intersection of the area of interest, expressed in tile coordinates */
|
||||
/* with the tile coordinates */
|
||||
tilec->win_x0 = opj_uint_max(
|
||||
|
@ -1600,6 +1634,10 @@ OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *p_tcd,
|
|||
opj_image_data_free(tilec->data_win);
|
||||
tilec->data_win = NULL;
|
||||
|
||||
if (p_tcd->used_component != NULL && !p_tcd->used_component[compno]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (w > 0 && h > 0) {
|
||||
if (w > SIZE_MAX / h) {
|
||||
opj_event_msg(p_manager, EVT_ERROR,
|
||||
|
@ -1916,14 +1954,17 @@ static OPJ_BOOL opj_tcd_t1_decode(opj_tcd_t *p_tcd, opj_event_mgr_t *p_manager)
|
|||
check_pterm = OPJ_TRUE;
|
||||
}
|
||||
|
||||
for (compno = 0; compno < l_tile->numcomps; ++compno) {
|
||||
for (compno = 0; compno < l_tile->numcomps;
|
||||
++compno, ++l_tile_comp, ++l_tccp) {
|
||||
if (p_tcd->used_component != NULL && !p_tcd->used_component[compno]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
opj_t1_decode_cblks(p_tcd, &ret, l_tile_comp, l_tccp,
|
||||
p_manager, p_manager_mutex, check_pterm);
|
||||
if (!ret) {
|
||||
break;
|
||||
}
|
||||
++l_tile_comp;
|
||||
++l_tccp;
|
||||
}
|
||||
|
||||
opj_thread_pool_wait_completion(p_tcd->thread_pool, 0);
|
||||
|
@ -1942,7 +1983,11 @@ static OPJ_BOOL opj_tcd_dwt_decode(opj_tcd_t *p_tcd)
|
|||
opj_tccp_t * l_tccp = p_tcd->tcp->tccps;
|
||||
opj_image_comp_t * l_img_comp = p_tcd->image->comps;
|
||||
|
||||
for (compno = 0; compno < l_tile->numcomps; compno++) {
|
||||
for (compno = 0; compno < l_tile->numcomps;
|
||||
compno++, ++l_tile_comp, ++l_img_comp, ++l_tccp) {
|
||||
if (p_tcd->used_component != NULL && !p_tcd->used_component[compno]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (l_tccp->qmfbid == 1) {
|
||||
if (! opj_dwt_decode(p_tcd, l_tile_comp,
|
||||
|
@ -1956,9 +2001,6 @@ static OPJ_BOOL opj_tcd_dwt_decode(opj_tcd_t *p_tcd)
|
|||
}
|
||||
}
|
||||
|
||||
++l_tile_comp;
|
||||
++l_img_comp;
|
||||
++l_tccp;
|
||||
}
|
||||
|
||||
return OPJ_TRUE;
|
||||
|
@ -1971,7 +2013,7 @@ static OPJ_BOOL opj_tcd_mct_decode(opj_tcd_t *p_tcd, opj_event_mgr_t *p_manager)
|
|||
opj_tcd_tilecomp_t * l_tile_comp = l_tile->comps;
|
||||
OPJ_UINT32 l_samples, i;
|
||||
|
||||
if (! l_tcp->mct) {
|
||||
if (l_tcp->mct == 0 || p_tcd->used_component != NULL) {
|
||||
return OPJ_TRUE;
|
||||
}
|
||||
|
||||
|
@ -2132,7 +2174,13 @@ static OPJ_BOOL opj_tcd_dc_level_shift_decode(opj_tcd_t *p_tcd)
|
|||
l_tccp = p_tcd->tcp->tccps;
|
||||
l_img_comp = p_tcd->image->comps;
|
||||
|
||||
for (compno = 0; compno < l_tile->numcomps; compno++) {
|
||||
for (compno = 0; compno < l_tile->numcomps;
|
||||
compno++, ++l_img_comp, ++l_tccp, ++l_tile_comp) {
|
||||
|
||||
if (p_tcd->used_component != NULL && !p_tcd->used_component[compno]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
l_res = l_tile_comp->resolutions + l_img_comp->resno_decoded;
|
||||
|
||||
if (!p_tcd->whole_tile_decoding) {
|
||||
|
@ -2191,10 +2239,6 @@ static OPJ_BOOL opj_tcd_dc_level_shift_decode(opj_tcd_t *p_tcd)
|
|||
l_current_ptr += l_stride;
|
||||
}
|
||||
}
|
||||
|
||||
++l_img_comp;
|
||||
++l_tccp;
|
||||
++l_tile_comp;
|
||||
}
|
||||
|
||||
return OPJ_TRUE;
|
||||
|
|
|
@ -280,6 +280,8 @@ typedef struct opj_tcd {
|
|||
OPJ_UINT32 win_y1;
|
||||
/** Only valid for decoding. Whether the whole tile is decoded, or just the region in win_x0/win_y0/win_x1/win_y1 */
|
||||
OPJ_BOOL whole_tile_decoding;
|
||||
/* Array of size image->numcomps indicating if a component must be decoded. NULL if all components must be decoded */
|
||||
OPJ_BOOL* used_component;
|
||||
} opj_tcd_t;
|
||||
|
||||
/** @name Exported functions */
|
||||
|
@ -381,6 +383,10 @@ Decode a tile from a buffer into a raw image
|
|||
@param win_y0 Upper left y of region to decode (in grid coordinates)
|
||||
@param win_x1 Lower right x of region to decode (in grid coordinates)
|
||||
@param win_y1 Lower right y of region to decode (in grid coordinates)
|
||||
@param numcomps_to_decode Size of the comps_indices array, or 0 if decoding all components.
|
||||
@param comps_indices Array of numcomps values representing the indices
|
||||
of the components to decode (relative to the
|
||||
codestream, starting at 0). Or NULL if decoding all components.
|
||||
@param src Source buffer
|
||||
@param len Length of source buffer
|
||||
@param tileno Number that identifies one of the tiles to be decoded
|
||||
|
@ -392,6 +398,8 @@ OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *tcd,
|
|||
OPJ_UINT32 win_y0,
|
||||
OPJ_UINT32 win_x1,
|
||||
OPJ_UINT32 win_y1,
|
||||
OPJ_UINT32 numcomps_to_decode,
|
||||
const OPJ_UINT32 *comps_indices,
|
||||
OPJ_BYTE *src,
|
||||
OPJ_UINT32 len,
|
||||
OPJ_UINT32 tileno,
|
||||
|
|
|
@ -310,3 +310,9 @@ d1bb7f93f4c0eb984b2e9c54e544b7e9 broken.jpc_1.pgx
|
|||
b704ad4c0cfefffd78c20a54f5541265 dwt_interleave_h.gsr105.jp2_d_1_1_33_33_0.pgx
|
||||
9d7fe43cd7a50b7bbaf712926ee11980 dwt_interleave_h.gsr105.jp2_d_1_1_33_33_1.pgx
|
||||
0960b580f991ff10f693b24aa41ad58b dwt_interleave_h.gsr105.jp2_d_1_1_33_33_2.pgx
|
||||
fa7382fd8b2e788b28b807e200dd95b9 file1.jp2-c0.tif
|
||||
ed79b7fe443955cdefba2b039ddc846a file1.jp2-c0_1_2.tif
|
||||
ac8f6ab3acc9c692ed7c41bd62a0e1e8 file1.jp2-c0-r1.tif
|
||||
fbfcf662b6f7549574b2885490fbcf12 file1.jp2-c0-d10_20_30_40.tif
|
||||
fa7382fd8b2e788b28b807e200dd95b9 file1.jp2-c0-t0.tif
|
||||
ac8f6ab3acc9c692ed7c41bd62a0e1e8 file1.jp2-c0-t0-r1.tif
|
||||
|
|
|
@ -605,3 +605,21 @@ opj_decompress -i @INPUT_NR_PATH@/issue979.j2k -o @TEMP_PATH@/issue979.j2k.pgx
|
|||
|
||||
# https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=3115
|
||||
opj_decompress -i @INPUT_NR_PATH@/dwt_interleave_h.gsr105.jp2 -o @TEMP_PATH@/dwt_interleave_h.gsr105.jp2_d_1_1_33_33.pgx -d 1,1,33,33
|
||||
|
||||
# partial component decoding with opj_decode(): one component
|
||||
opj_decompress -i @INPUT_CONF_PATH@/file1.jp2 -o @TEMP_PATH@/file1.jp2-c0.tif -c 0
|
||||
# partial component decoding with opj_decode(): 3 components without MCT
|
||||
opj_decompress -i @INPUT_CONF_PATH@/file1.jp2 -o @TEMP_PATH@/file1.jp2-c0_1_2.tif -c 0,1,2
|
||||
# partial component decoding with opj_decode() and opj_set_decode_area()
|
||||
opj_decompress -i @INPUT_CONF_PATH@/file1.jp2 -o @TEMP_PATH@/file1.jp2-c0-d10_20_30_40.tif -c 0 -d 10,20,30,40
|
||||
# partial component decoding with opj_decode() and reduced resolution
|
||||
opj_decompress -i @INPUT_CONF_PATH@/file1.jp2 -o @TEMP_PATH@/file1.jp2-c0-r1.tif -c 0 -r 1
|
||||
# partial component decoding with opj_get_decoded_tile()
|
||||
opj_decompress -i @INPUT_CONF_PATH@/file1.jp2 -o @TEMP_PATH@/file1.jp2-c0-t0.tif -c 0 -t 0
|
||||
# partial component decoding with opj_get_decoded_tile() and reduced resolution
|
||||
opj_decompress -i @INPUT_CONF_PATH@/file1.jp2 -o @TEMP_PATH@/file1.jp2-c0-t0-r1.tif -c 0 -t 0 -r 1
|
||||
|
||||
# try to map the same component several times
|
||||
!opj_decompress -i @INPUT_CONF_PATH@/file1.jp2 -o @TEMP_PATH@/file1.jp2-c0_0.tif -c 0,0
|
||||
# try to map an invalid component
|
||||
!opj_decompress -i @INPUT_CONF_PATH@/file1.jp2 -o @TEMP_PATH@/file1.jp2-c10.tif -c 10
|
||||
|
|
Loading…
Reference in New Issue