Skip to content

Commit

Permalink
Merge pull request #1463 from rouault/fix_570
Browse files Browse the repository at this point in the history
opj_jp2_read_header(): move setting color_space here instead in opj_jp2_decode()/get_tile() (fixes #570)
  • Loading branch information
rouault authored Mar 26, 2023
2 parents 15c0dca + 59ec1f0 commit 1ee6d11
Show file tree
Hide file tree
Showing 3 changed files with 201 additions and 87 deletions.
140 changes: 53 additions & 87 deletions src/lib/openjp2/jp2.c
Original file line number Diff line number Diff line change
Expand Up @@ -1594,22 +1594,10 @@ static OPJ_BOOL opj_jp2_read_colr(opj_jp2_t *jp2,
return OPJ_TRUE;
}

OPJ_BOOL opj_jp2_decode(opj_jp2_t *jp2,
opj_stream_private_t *p_stream,
opj_image_t* p_image,
opj_event_mgr_t * p_manager)
static OPJ_BOOL opj_jp2_apply_color_postprocessing(opj_jp2_t *jp2,
opj_image_t* p_image,
opj_event_mgr_t * p_manager)
{
if (!p_image) {
return OPJ_FALSE;
}

/* J2K decoding */
if (! opj_j2k_decode(jp2->j2k, p_stream, p_image, p_manager)) {
opj_event_msg(p_manager, EVT_ERROR,
"Failed to decode the codestream in the JP2 file\n");
return OPJ_FALSE;
}

if (jp2->j2k->m_specific_param.m_decoder.m_numcomps_to_decode) {
/* Bypass all JP2 component transforms */
return OPJ_TRUE;
Expand All @@ -1620,21 +1608,6 @@ OPJ_BOOL opj_jp2_decode(opj_jp2_t *jp2,
return OPJ_FALSE;
}

/* Set Image Color Space */
if (jp2->enumcs == 16) {
p_image->color_space = OPJ_CLRSPC_SRGB;
} else if (jp2->enumcs == 17) {
p_image->color_space = OPJ_CLRSPC_GRAY;
} else if (jp2->enumcs == 18) {
p_image->color_space = OPJ_CLRSPC_SYCC;
} else if (jp2->enumcs == 24) {
p_image->color_space = OPJ_CLRSPC_EYCC;
} else if (jp2->enumcs == 12) {
p_image->color_space = OPJ_CLRSPC_CMYK;
} else {
p_image->color_space = OPJ_CLRSPC_UNKNOWN;
}

if (jp2->color.jp2_pclr) {
/* Part 1, I.5.3.4: Either both or none : */
if (!jp2->color.jp2_pclr->cmap) {
Expand All @@ -1650,17 +1623,30 @@ OPJ_BOOL opj_jp2_decode(opj_jp2_t *jp2,
if (jp2->color.jp2_cdef) {
opj_jp2_apply_cdef(p_image, &(jp2->color), p_manager);
}

if (jp2->color.icc_profile_buf) {
p_image->icc_profile_buf = jp2->color.icc_profile_buf;
p_image->icc_profile_len = jp2->color.icc_profile_len;
jp2->color.icc_profile_buf = NULL;
}
}

return OPJ_TRUE;
}

OPJ_BOOL opj_jp2_decode(opj_jp2_t *jp2,
opj_stream_private_t *p_stream,
opj_image_t* p_image,
opj_event_mgr_t * p_manager)
{
if (!p_image) {
return OPJ_FALSE;
}

/* J2K decoding */
if (! opj_j2k_decode(jp2->j2k, p_stream, p_image, p_manager)) {
opj_event_msg(p_manager, EVT_ERROR,
"Failed to decode the codestream in the JP2 file\n");
return OPJ_FALSE;
}

return opj_jp2_apply_color_postprocessing(jp2, p_image, p_manager);
}

static OPJ_BOOL opj_jp2_write_jp2h(opj_jp2_t *jp2,
opj_stream_private_t *stream,
opj_event_mgr_t * p_manager
Expand Down Expand Up @@ -2843,6 +2829,8 @@ OPJ_BOOL opj_jp2_read_header(opj_stream_private_t *p_stream,
opj_event_mgr_t * p_manager
)
{
int ret;

/* preconditions */
assert(jp2 != 00);
assert(p_stream != 00);
Expand Down Expand Up @@ -2876,10 +2864,34 @@ OPJ_BOOL opj_jp2_read_header(opj_stream_private_t *p_stream,
return OPJ_FALSE;
}

return opj_j2k_read_header(p_stream,
jp2->j2k,
p_image,
p_manager);
ret = opj_j2k_read_header(p_stream,
jp2->j2k,
p_image,
p_manager);

if (p_image && *p_image) {
/* Set Image Color Space */
if (jp2->enumcs == 16) {
(*p_image)->color_space = OPJ_CLRSPC_SRGB;
} else if (jp2->enumcs == 17) {
(*p_image)->color_space = OPJ_CLRSPC_GRAY;
} else if (jp2->enumcs == 18) {
(*p_image)->color_space = OPJ_CLRSPC_SYCC;
} else if (jp2->enumcs == 24) {
(*p_image)->color_space = OPJ_CLRSPC_EYCC;
} else if (jp2->enumcs == 12) {
(*p_image)->color_space = OPJ_CLRSPC_CMYK;
} else {
(*p_image)->color_space = OPJ_CLRSPC_UNKNOWN;
}

if (jp2->color.icc_profile_buf) {
(*p_image)->icc_profile_buf = jp2->color.icc_profile_buf;
(*p_image)->icc_profile_len = jp2->color.icc_profile_len;
jp2->color.icc_profile_buf = NULL;
}
}
return ret;
}

static OPJ_BOOL opj_jp2_setup_encoding_validation(opj_jp2_t *jp2,
Expand Down Expand Up @@ -3123,53 +3135,7 @@ 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;
}

/* Set Image Color Space */
if (p_jp2->enumcs == 16) {
p_image->color_space = OPJ_CLRSPC_SRGB;
} else if (p_jp2->enumcs == 17) {
p_image->color_space = OPJ_CLRSPC_GRAY;
} else if (p_jp2->enumcs == 18) {
p_image->color_space = OPJ_CLRSPC_SYCC;
} else if (p_jp2->enumcs == 24) {
p_image->color_space = OPJ_CLRSPC_EYCC;
} else if (p_jp2->enumcs == 12) {
p_image->color_space = OPJ_CLRSPC_CMYK;
} else {
p_image->color_space = OPJ_CLRSPC_UNKNOWN;
}

if (p_jp2->color.jp2_pclr) {
/* Part 1, I.5.3.4: Either both or none : */
if (!p_jp2->color.jp2_pclr->cmap) {
opj_jp2_free_pclr(&(p_jp2->color));
} else {
if (!opj_jp2_apply_pclr(p_image, &(p_jp2->color), p_manager)) {
return OPJ_FALSE;
}
}
}

/* Apply the color space if needed */
if (p_jp2->color.jp2_cdef) {
opj_jp2_apply_cdef(p_image, &(p_jp2->color), p_manager);
}

if (p_jp2->color.icc_profile_buf) {
p_image->icc_profile_buf = p_jp2->color.icc_profile_buf;
p_image->icc_profile_len = p_jp2->color.icc_profile_len;
p_jp2->color.icc_profile_buf = NULL;
}

return OPJ_TRUE;
return opj_jp2_apply_color_postprocessing(p_jp2, p_image, p_manager);
}

/* ----------------------------------------------------------------------- */
Expand Down
4 changes: 4 additions & 0 deletions tests/unit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ foreach(ut ${unit_test})
target_link_libraries(${ut} openjp2)
add_test(NAME ${ut} COMMAND ${ut})
endforeach()

add_executable(testjp2 testjp2.c)
target_link_libraries(testjp2 openjp2)
add_test(NAME testjp2 COMMAND testjp2 ${OPJ_DATA_ROOT})
144 changes: 144 additions & 0 deletions tests/unit/testjp2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
* Copyright (c) 2023, Even Rouault
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

#include <stdlib.h>

#include "openjpeg.h"

static void test_colorspace(const char* pszDirectory)
{
char szFile[2048];
opj_image_t* image = NULL;
opj_stream_t *l_stream = NULL; /* Stream */
opj_codec_t* l_codec = NULL; /* Handle to a decompressor */
opj_dparameters_t parameters; /* decompression parameters */

snprintf(szFile, sizeof(szFile), "%s/input/conformance/file1.jp2",
pszDirectory);
l_stream = opj_stream_create_default_file_stream(szFile, 1);
if (!l_stream) {
fprintf(stderr, "ERROR -> failed to create the stream from the file %s\n",
szFile);
exit(1);
}
l_codec = opj_create_decompress(OPJ_CODEC_JP2);

/* Setup the decoder */
opj_set_default_decoder_parameters(&parameters);
if (!opj_setup_decoder(l_codec, &parameters)) {
fprintf(stderr, "ERROR -> opj_decompress: failed to setup the decoder\n");
opj_stream_destroy(l_stream);
opj_destroy_codec(l_codec);
exit(1);
}

/* Read the main header of the codestream and if necessary the JP2 boxes*/
if (! opj_read_header(l_stream, l_codec, &image)) {
fprintf(stderr, "ERROR -> opj_decompress: failed to read the header\n");
opj_stream_destroy(l_stream);
opj_destroy_codec(l_codec);
opj_image_destroy(image);
exit(1);
}

/* Check that color_space is set after opj_read_header() */
if (image->color_space != OPJ_CLRSPC_SRGB) {
fprintf(stderr, "ERROR -> image->color_space (=%d) != OPJ_CLRSPC_SRGB\n",
image->color_space);
opj_stream_destroy(l_stream);
opj_destroy_codec(l_codec);
opj_image_destroy(image);
exit(1);
}

opj_destroy_codec(l_codec);
opj_stream_destroy(l_stream);
opj_image_destroy(image);
}

static void test_iccprofile(const char* pszDirectory)
{
char szFile[2048];
opj_image_t* image = NULL;
opj_stream_t *l_stream = NULL; /* Stream */
opj_codec_t* l_codec = NULL; /* Handle to a decompressor */
opj_dparameters_t parameters; /* decompression parameters */

snprintf(szFile, sizeof(szFile), "%s/input/nonregression/relax.jp2",
pszDirectory);
l_stream = opj_stream_create_default_file_stream(szFile, 1);
if (!l_stream) {
fprintf(stderr, "ERROR -> failed to create the stream from the file %s\n",
szFile);
exit(1);
}
l_codec = opj_create_decompress(OPJ_CODEC_JP2);

/* Setup the decoder */
opj_set_default_decoder_parameters(&parameters);
if (!opj_setup_decoder(l_codec, &parameters)) {
fprintf(stderr, "ERROR -> opj_decompress: failed to setup the decoder\n");
opj_stream_destroy(l_stream);
opj_destroy_codec(l_codec);
exit(1);
}

/* Read the main header of the codestream and if necessary the JP2 boxes*/
if (! opj_read_header(l_stream, l_codec, &image)) {
fprintf(stderr, "ERROR -> opj_decompress: failed to read the header\n");
opj_stream_destroy(l_stream);
opj_destroy_codec(l_codec);
opj_image_destroy(image);
exit(1);
}

/* Check that icc_profile_len is set after opj_read_header() */
if (image->icc_profile_len != 278) {
fprintf(stderr, "ERROR -> image->icc_profile_len (=%d) != 278\n",
image->icc_profile_len);
opj_stream_destroy(l_stream);
opj_destroy_codec(l_codec);
opj_image_destroy(image);
exit(1);
}

opj_destroy_codec(l_codec);
opj_stream_destroy(l_stream);
opj_image_destroy(image);
}

int main(int argc, char* argv[])
{
if (argc != 2) {
fprintf(stderr, "usage: testjp2 /path/to/opj_data_root\n");
exit(1);
}

test_colorspace(argv[1]);
test_iccprofile(argv[1]);

return 0;
}

0 comments on commit 1ee6d11

Please sign in to comment.