Skip to content

Commit 1ee6d11

Browse files
authored
Merge pull request #1463 from rouault/fix_570
opj_jp2_read_header(): move setting color_space here instead in opj_jp2_decode()/get_tile() (fixes #570)
2 parents 15c0dca + 59ec1f0 commit 1ee6d11

File tree

3 files changed

+201
-87
lines changed

3 files changed

+201
-87
lines changed

src/lib/openjp2/jp2.c

+53-87
Original file line numberDiff line numberDiff line change
@@ -1594,22 +1594,10 @@ static OPJ_BOOL opj_jp2_read_colr(opj_jp2_t *jp2,
15941594
return OPJ_TRUE;
15951595
}
15961596

1597-
OPJ_BOOL opj_jp2_decode(opj_jp2_t *jp2,
1598-
opj_stream_private_t *p_stream,
1599-
opj_image_t* p_image,
1600-
opj_event_mgr_t * p_manager)
1597+
static OPJ_BOOL opj_jp2_apply_color_postprocessing(opj_jp2_t *jp2,
1598+
opj_image_t* p_image,
1599+
opj_event_mgr_t * p_manager)
16011600
{
1602-
if (!p_image) {
1603-
return OPJ_FALSE;
1604-
}
1605-
1606-
/* J2K decoding */
1607-
if (! opj_j2k_decode(jp2->j2k, p_stream, p_image, p_manager)) {
1608-
opj_event_msg(p_manager, EVT_ERROR,
1609-
"Failed to decode the codestream in the JP2 file\n");
1610-
return OPJ_FALSE;
1611-
}
1612-
16131601
if (jp2->j2k->m_specific_param.m_decoder.m_numcomps_to_decode) {
16141602
/* Bypass all JP2 component transforms */
16151603
return OPJ_TRUE;
@@ -1620,21 +1608,6 @@ OPJ_BOOL opj_jp2_decode(opj_jp2_t *jp2,
16201608
return OPJ_FALSE;
16211609
}
16221610

1623-
/* Set Image Color Space */
1624-
if (jp2->enumcs == 16) {
1625-
p_image->color_space = OPJ_CLRSPC_SRGB;
1626-
} else if (jp2->enumcs == 17) {
1627-
p_image->color_space = OPJ_CLRSPC_GRAY;
1628-
} else if (jp2->enumcs == 18) {
1629-
p_image->color_space = OPJ_CLRSPC_SYCC;
1630-
} else if (jp2->enumcs == 24) {
1631-
p_image->color_space = OPJ_CLRSPC_EYCC;
1632-
} else if (jp2->enumcs == 12) {
1633-
p_image->color_space = OPJ_CLRSPC_CMYK;
1634-
} else {
1635-
p_image->color_space = OPJ_CLRSPC_UNKNOWN;
1636-
}
1637-
16381611
if (jp2->color.jp2_pclr) {
16391612
/* Part 1, I.5.3.4: Either both or none : */
16401613
if (!jp2->color.jp2_pclr->cmap) {
@@ -1650,17 +1623,30 @@ OPJ_BOOL opj_jp2_decode(opj_jp2_t *jp2,
16501623
if (jp2->color.jp2_cdef) {
16511624
opj_jp2_apply_cdef(p_image, &(jp2->color), p_manager);
16521625
}
1653-
1654-
if (jp2->color.icc_profile_buf) {
1655-
p_image->icc_profile_buf = jp2->color.icc_profile_buf;
1656-
p_image->icc_profile_len = jp2->color.icc_profile_len;
1657-
jp2->color.icc_profile_buf = NULL;
1658-
}
16591626
}
16601627

16611628
return OPJ_TRUE;
16621629
}
16631630

1631+
OPJ_BOOL opj_jp2_decode(opj_jp2_t *jp2,
1632+
opj_stream_private_t *p_stream,
1633+
opj_image_t* p_image,
1634+
opj_event_mgr_t * p_manager)
1635+
{
1636+
if (!p_image) {
1637+
return OPJ_FALSE;
1638+
}
1639+
1640+
/* J2K decoding */
1641+
if (! opj_j2k_decode(jp2->j2k, p_stream, p_image, p_manager)) {
1642+
opj_event_msg(p_manager, EVT_ERROR,
1643+
"Failed to decode the codestream in the JP2 file\n");
1644+
return OPJ_FALSE;
1645+
}
1646+
1647+
return opj_jp2_apply_color_postprocessing(jp2, p_image, p_manager);
1648+
}
1649+
16641650
static OPJ_BOOL opj_jp2_write_jp2h(opj_jp2_t *jp2,
16651651
opj_stream_private_t *stream,
16661652
opj_event_mgr_t * p_manager
@@ -2843,6 +2829,8 @@ OPJ_BOOL opj_jp2_read_header(opj_stream_private_t *p_stream,
28432829
opj_event_mgr_t * p_manager
28442830
)
28452831
{
2832+
int ret;
2833+
28462834
/* preconditions */
28472835
assert(jp2 != 00);
28482836
assert(p_stream != 00);
@@ -2876,10 +2864,34 @@ OPJ_BOOL opj_jp2_read_header(opj_stream_private_t *p_stream,
28762864
return OPJ_FALSE;
28772865
}
28782866

2879-
return opj_j2k_read_header(p_stream,
2880-
jp2->j2k,
2881-
p_image,
2882-
p_manager);
2867+
ret = opj_j2k_read_header(p_stream,
2868+
jp2->j2k,
2869+
p_image,
2870+
p_manager);
2871+
2872+
if (p_image && *p_image) {
2873+
/* Set Image Color Space */
2874+
if (jp2->enumcs == 16) {
2875+
(*p_image)->color_space = OPJ_CLRSPC_SRGB;
2876+
} else if (jp2->enumcs == 17) {
2877+
(*p_image)->color_space = OPJ_CLRSPC_GRAY;
2878+
} else if (jp2->enumcs == 18) {
2879+
(*p_image)->color_space = OPJ_CLRSPC_SYCC;
2880+
} else if (jp2->enumcs == 24) {
2881+
(*p_image)->color_space = OPJ_CLRSPC_EYCC;
2882+
} else if (jp2->enumcs == 12) {
2883+
(*p_image)->color_space = OPJ_CLRSPC_CMYK;
2884+
} else {
2885+
(*p_image)->color_space = OPJ_CLRSPC_UNKNOWN;
2886+
}
2887+
2888+
if (jp2->color.icc_profile_buf) {
2889+
(*p_image)->icc_profile_buf = jp2->color.icc_profile_buf;
2890+
(*p_image)->icc_profile_len = jp2->color.icc_profile_len;
2891+
jp2->color.icc_profile_buf = NULL;
2892+
}
2893+
}
2894+
return ret;
28832895
}
28842896

28852897
static OPJ_BOOL opj_jp2_setup_encoding_validation(opj_jp2_t *jp2,
@@ -3123,53 +3135,7 @@ OPJ_BOOL opj_jp2_get_tile(opj_jp2_t *p_jp2,
31233135
return OPJ_FALSE;
31243136
}
31253137

3126-
if (p_jp2->j2k->m_specific_param.m_decoder.m_numcomps_to_decode) {
3127-
/* Bypass all JP2 component transforms */
3128-
return OPJ_TRUE;
3129-
}
3130-
3131-
if (!opj_jp2_check_color(p_image, &(p_jp2->color), p_manager)) {
3132-
return OPJ_FALSE;
3133-
}
3134-
3135-
/* Set Image Color Space */
3136-
if (p_jp2->enumcs == 16) {
3137-
p_image->color_space = OPJ_CLRSPC_SRGB;
3138-
} else if (p_jp2->enumcs == 17) {
3139-
p_image->color_space = OPJ_CLRSPC_GRAY;
3140-
} else if (p_jp2->enumcs == 18) {
3141-
p_image->color_space = OPJ_CLRSPC_SYCC;
3142-
} else if (p_jp2->enumcs == 24) {
3143-
p_image->color_space = OPJ_CLRSPC_EYCC;
3144-
} else if (p_jp2->enumcs == 12) {
3145-
p_image->color_space = OPJ_CLRSPC_CMYK;
3146-
} else {
3147-
p_image->color_space = OPJ_CLRSPC_UNKNOWN;
3148-
}
3149-
3150-
if (p_jp2->color.jp2_pclr) {
3151-
/* Part 1, I.5.3.4: Either both or none : */
3152-
if (!p_jp2->color.jp2_pclr->cmap) {
3153-
opj_jp2_free_pclr(&(p_jp2->color));
3154-
} else {
3155-
if (!opj_jp2_apply_pclr(p_image, &(p_jp2->color), p_manager)) {
3156-
return OPJ_FALSE;
3157-
}
3158-
}
3159-
}
3160-
3161-
/* Apply the color space if needed */
3162-
if (p_jp2->color.jp2_cdef) {
3163-
opj_jp2_apply_cdef(p_image, &(p_jp2->color), p_manager);
3164-
}
3165-
3166-
if (p_jp2->color.icc_profile_buf) {
3167-
p_image->icc_profile_buf = p_jp2->color.icc_profile_buf;
3168-
p_image->icc_profile_len = p_jp2->color.icc_profile_len;
3169-
p_jp2->color.icc_profile_buf = NULL;
3170-
}
3171-
3172-
return OPJ_TRUE;
3138+
return opj_jp2_apply_color_postprocessing(p_jp2, p_image, p_manager);
31733139
}
31743140

31753141
/* ----------------------------------------------------------------------- */

tests/unit/CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,7 @@ foreach(ut ${unit_test})
1515
target_link_libraries(${ut} openjp2)
1616
add_test(NAME ${ut} COMMAND ${ut})
1717
endforeach()
18+
19+
add_executable(testjp2 testjp2.c)
20+
target_link_libraries(testjp2 openjp2)
21+
add_test(NAME testjp2 COMMAND testjp2 ${OPJ_DATA_ROOT})

tests/unit/testjp2.c

+144
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/*
2+
* Copyright (c) 2023, Even Rouault
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions
7+
* are met:
8+
* 1. Redistributions of source code must retain the above copyright
9+
* notice, this list of conditions and the following disclaimer.
10+
* 2. Redistributions in binary form must reproduce the above copyright
11+
* notice, this list of conditions and the following disclaimer in the
12+
* documentation and/or other materials provided with the distribution.
13+
*
14+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
15+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24+
* POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
27+
#include <stdlib.h>
28+
29+
#include "openjpeg.h"
30+
31+
static void test_colorspace(const char* pszDirectory)
32+
{
33+
char szFile[2048];
34+
opj_image_t* image = NULL;
35+
opj_stream_t *l_stream = NULL; /* Stream */
36+
opj_codec_t* l_codec = NULL; /* Handle to a decompressor */
37+
opj_dparameters_t parameters; /* decompression parameters */
38+
39+
snprintf(szFile, sizeof(szFile), "%s/input/conformance/file1.jp2",
40+
pszDirectory);
41+
l_stream = opj_stream_create_default_file_stream(szFile, 1);
42+
if (!l_stream) {
43+
fprintf(stderr, "ERROR -> failed to create the stream from the file %s\n",
44+
szFile);
45+
exit(1);
46+
}
47+
l_codec = opj_create_decompress(OPJ_CODEC_JP2);
48+
49+
/* Setup the decoder */
50+
opj_set_default_decoder_parameters(&parameters);
51+
if (!opj_setup_decoder(l_codec, &parameters)) {
52+
fprintf(stderr, "ERROR -> opj_decompress: failed to setup the decoder\n");
53+
opj_stream_destroy(l_stream);
54+
opj_destroy_codec(l_codec);
55+
exit(1);
56+
}
57+
58+
/* Read the main header of the codestream and if necessary the JP2 boxes*/
59+
if (! opj_read_header(l_stream, l_codec, &image)) {
60+
fprintf(stderr, "ERROR -> opj_decompress: failed to read the header\n");
61+
opj_stream_destroy(l_stream);
62+
opj_destroy_codec(l_codec);
63+
opj_image_destroy(image);
64+
exit(1);
65+
}
66+
67+
/* Check that color_space is set after opj_read_header() */
68+
if (image->color_space != OPJ_CLRSPC_SRGB) {
69+
fprintf(stderr, "ERROR -> image->color_space (=%d) != OPJ_CLRSPC_SRGB\n",
70+
image->color_space);
71+
opj_stream_destroy(l_stream);
72+
opj_destroy_codec(l_codec);
73+
opj_image_destroy(image);
74+
exit(1);
75+
}
76+
77+
opj_destroy_codec(l_codec);
78+
opj_stream_destroy(l_stream);
79+
opj_image_destroy(image);
80+
}
81+
82+
static void test_iccprofile(const char* pszDirectory)
83+
{
84+
char szFile[2048];
85+
opj_image_t* image = NULL;
86+
opj_stream_t *l_stream = NULL; /* Stream */
87+
opj_codec_t* l_codec = NULL; /* Handle to a decompressor */
88+
opj_dparameters_t parameters; /* decompression parameters */
89+
90+
snprintf(szFile, sizeof(szFile), "%s/input/nonregression/relax.jp2",
91+
pszDirectory);
92+
l_stream = opj_stream_create_default_file_stream(szFile, 1);
93+
if (!l_stream) {
94+
fprintf(stderr, "ERROR -> failed to create the stream from the file %s\n",
95+
szFile);
96+
exit(1);
97+
}
98+
l_codec = opj_create_decompress(OPJ_CODEC_JP2);
99+
100+
/* Setup the decoder */
101+
opj_set_default_decoder_parameters(&parameters);
102+
if (!opj_setup_decoder(l_codec, &parameters)) {
103+
fprintf(stderr, "ERROR -> opj_decompress: failed to setup the decoder\n");
104+
opj_stream_destroy(l_stream);
105+
opj_destroy_codec(l_codec);
106+
exit(1);
107+
}
108+
109+
/* Read the main header of the codestream and if necessary the JP2 boxes*/
110+
if (! opj_read_header(l_stream, l_codec, &image)) {
111+
fprintf(stderr, "ERROR -> opj_decompress: failed to read the header\n");
112+
opj_stream_destroy(l_stream);
113+
opj_destroy_codec(l_codec);
114+
opj_image_destroy(image);
115+
exit(1);
116+
}
117+
118+
/* Check that icc_profile_len is set after opj_read_header() */
119+
if (image->icc_profile_len != 278) {
120+
fprintf(stderr, "ERROR -> image->icc_profile_len (=%d) != 278\n",
121+
image->icc_profile_len);
122+
opj_stream_destroy(l_stream);
123+
opj_destroy_codec(l_codec);
124+
opj_image_destroy(image);
125+
exit(1);
126+
}
127+
128+
opj_destroy_codec(l_codec);
129+
opj_stream_destroy(l_stream);
130+
opj_image_destroy(image);
131+
}
132+
133+
int main(int argc, char* argv[])
134+
{
135+
if (argc != 2) {
136+
fprintf(stderr, "usage: testjp2 /path/to/opj_data_root\n");
137+
exit(1);
138+
}
139+
140+
test_colorspace(argv[1]);
141+
test_iccprofile(argv[1]);
142+
143+
return 0;
144+
}

0 commit comments

Comments
 (0)