1717#include " openexr_encode.h"
1818#include " internal_ht_common.h"
1919
20+ /* **********************************
21+
22+ Structure of the HT256 chunk
23+ - MAGIC = 0x4854: magic number
24+ - PLEN: length of header payload (big endian uint32_t)
25+ - header payload
26+ - NCH: number of channels in channel map (big endian uint16_t)
27+ - for(i = 0; i < NCH; i++)
28+ - CS_TO_F[i]: OpenEXR channel index corresponding to J2K component index i (big endian uint16_t)
29+ - any number of opaque bytes
30+ - CS: JPEG 2000 Codestream
31+
32+ ***********************************/
33+
34+ class MemoryReader
35+ {
36+ public:
37+ MemoryReader (uint8_t * buffer, size_t max_sz)
38+ : buffer (buffer), cur (buffer), end (buffer + max_sz){};
39+
40+ uint32_t pull_uint32 ()
41+ {
42+ if (this ->end - this ->cur < 4 )
43+ throw std::out_of_range (" Insufficient data to pull uint32_t" );
44+
45+ uint32_t v = *this ->cur ++;
46+ v = (v << 8 ) + *this ->cur ++;
47+ v = (v << 8 ) + *this ->cur ++;
48+ return (v << 8 ) + *cur++;
49+ }
50+
51+ uint16_t pull_uint16 ()
52+ {
53+ if (this ->end - this ->cur < 2 )
54+ throw std::out_of_range (" Insufficient data to pull uint16_t" );
55+
56+ uint32_t v = *cur++;
57+ return (v << 8 ) + *cur++;
58+ }
59+
60+ protected:
61+ uint8_t * buffer;
62+ uint8_t * cur;
63+ uint8_t * end;
64+ };
65+
66+ class MemoryWriter
67+ {
68+ public:
69+ MemoryWriter (uint8_t * buffer, size_t max_sz)
70+ : buffer (buffer), cur (buffer), end (buffer + max_sz){};
71+
72+ void push_uint32 (uint32_t value)
73+ {
74+ if (this ->end - this ->cur < 4 )
75+ throw std::out_of_range (" Insufficient data to push uint32_t" );
76+
77+ *this ->cur ++ = (value >> 24 ) & 0xFF ;
78+ *this ->cur ++ = (value >> 16 ) & 0xFF ;
79+ *this ->cur ++ = (value >> 8 ) & 0xFF ;
80+ *this ->cur ++ = value & 0xFF ;
81+ }
82+
83+ void push_uint16 (uint16_t value)
84+ {
85+ if (this ->end - this ->cur < 2 )
86+ throw std::out_of_range (" Insufficient data to push uint32_t" );
87+
88+ *this ->cur ++ = (value >> 8 ) & 0xFF ;
89+ *this ->cur ++ = value & 0xFF ;
90+ }
91+
92+ size_t get_size () { return this ->cur - this ->buffer ; }
93+
94+ uint8_t * get_buffer () { return this ->buffer ; }
95+
96+ uint8_t * get_cur () { return this ->cur ; }
97+
98+ protected:
99+ uint8_t * buffer;
100+ uint8_t * cur;
101+ uint8_t * end;
102+ };
103+
104+ constexpr uint16_t HEADER_MARKER = ' H' * 256 + ' T' ;
105+
106+ size_t
107+ write_header (
108+ uint8_t * buffer,
109+ size_t max_sz,
110+ const std::vector<CodestreamChannelInfo>& map)
111+ {
112+ constexpr uint16_t HEADER_SZ = 6 ;
113+ MemoryWriter payload (buffer + HEADER_SZ, max_sz - HEADER_SZ);
114+ payload.push_uint16 (map.size ());
115+ for (size_t i = 0 ; i < map.size (); i++)
116+ {
117+ payload.push_uint16 (map.at (i).file_index );
118+ }
119+
120+ MemoryWriter header (buffer, max_sz);
121+ header.push_uint16 (HEADER_MARKER);
122+ header.push_uint32 (payload.get_size ());
123+
124+ return header.get_size () + payload.get_size ();
125+ }
126+
127+ void
128+ read_header (
129+ void * buffer,
130+ size_t max_sz,
131+ size_t & length,
132+ std::vector<CodestreamChannelInfo>& map)
133+ {
134+ MemoryReader header ((uint8_t *) buffer, max_sz);
135+ if (header.pull_uint16 () != HEADER_MARKER)
136+ throw std::runtime_error (
137+ " HT256 chunk header missing does not start with magic number." );
138+
139+ length = header.pull_uint32 ();
140+
141+ if (length < 2 )
142+ throw std::runtime_error (" Error while reading the channel map" );
143+
144+ map.resize (header.pull_uint16 ());
145+ for (size_t i = 0 ; i < map.size (); i++)
146+ {
147+ map.at (i).file_index = header.pull_uint16 ();
148+ }
149+ }
150+
20151extern " C" exr_result_t
21152internal_exr_undo_ht (
22153 exr_decode_pipeline_t * decode,
@@ -28,12 +159,33 @@ internal_exr_undo_ht (
28159 exr_result_t rv = EXR_ERR_SUCCESS;
29160
30161 std::vector<CodestreamChannelInfo> cs_to_file_ch (decode->channel_count );
31- bool isRGB = make_channel_map (
32- decode->channel_count , decode->channels , cs_to_file_ch);
162+
163+ /* read the channel map */
164+
165+ size_t header_sz;
166+ read_header (
167+ (uint8_t *) compressed_data, comp_buf_size, header_sz, cs_to_file_ch);
168+ if (decode->channel_count != cs_to_file_ch.size ())
169+ throw std::runtime_error (" Unexpected number of channels" );
170+
171+ std::vector<size_t > offsets (decode->channel_count );
172+ offsets[0 ] = 0 ;
173+ for (int file_i = 1 ; file_i < decode->channel_count ; file_i++)
174+ {
175+ offsets[file_i] = offsets[file_i - 1 ] +
176+ decode->channels [file_i - 1 ].width *
177+ decode->channels [file_i - 1 ].bytes_per_element ;
178+ }
179+ for (int cs_i = 0 ; cs_i < decode->channel_count ; cs_i++)
180+ {
181+ cs_to_file_ch[cs_i].raster_line_offset =
182+ offsets[cs_to_file_ch[cs_i].file_index ];
183+ }
33184
34185 ojph::mem_infile infile;
35186 infile.open (
36- reinterpret_cast <const ojph::ui8*> (compressed_data), comp_buf_size);
187+ reinterpret_cast <const ojph::ui8*> (compressed_data) + header_sz,
188+ comp_buf_size - header_sz);
37189
38190 ojph::codestream cs;
39191 cs.read_headers (&infile);
@@ -192,7 +344,8 @@ internal_exr_apply_ht (exr_encode_pipeline_t* encode)
192344 int file_c = cs_to_file_ch[c].file_index ;
193345 if (encode->channels [file_c].data_type != EXR_PIXEL_UINT)
194346 nlt.set_nonlinear_transform (
195- c, ojph::param_nlt::nonlinearity::OJPH_NLT_BINARY_COMPLEMENT_NLT);
347+ c,
348+ ojph::param_nlt::nonlinearity::OJPH_NLT_BINARY_COMPLEMENT_NLT);
196349 siz.set_component (
197350 c,
198351 ojph::point (
@@ -326,13 +479,20 @@ internal_exr_apply_ht (exr_encode_pipeline_t* encode)
326479
327480 cs.flush ();
328481
329- assert (output.tell () >= 0 );
482+ size_t header_sz = write_header (
483+ (uint8_t *) encode->compressed_buffer ,
484+ encode->packed_bytes ,
485+ cs_to_file_ch);
330486
487+ assert (output.tell () >= 0 );
331488 int compressed_sz = static_cast <size_t > (output.tell ());
332- if (compressed_sz < encode->packed_bytes )
489+ if (compressed_sz + header_sz < encode->packed_bytes )
333490 {
334- memcpy (encode->compressed_buffer , output.get_data (), compressed_sz);
335- encode->compressed_bytes = compressed_sz;
491+ memcpy (
492+ ((uint8_t *) encode->compressed_buffer ) + header_sz,
493+ output.get_data (),
494+ compressed_sz);
495+ encode->compressed_bytes = compressed_sz + header_sz;
336496 }
337497 else
338498 {
0 commit comments