17
17
#include " openexr_encode.h"
18
18
#include " internal_ht_common.h"
19
19
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
+
20
151
extern " C" exr_result_t
21
152
internal_exr_undo_ht (
22
153
exr_decode_pipeline_t * decode,
@@ -28,12 +159,33 @@ internal_exr_undo_ht (
28
159
exr_result_t rv = EXR_ERR_SUCCESS;
29
160
30
161
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
+ }
33
184
34
185
ojph::mem_infile infile;
35
186
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);
37
189
38
190
ojph::codestream cs;
39
191
cs.read_headers (&infile);
@@ -192,7 +344,8 @@ internal_exr_apply_ht (exr_encode_pipeline_t* encode)
192
344
int file_c = cs_to_file_ch[c].file_index ;
193
345
if (encode->channels [file_c].data_type != EXR_PIXEL_UINT)
194
346
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);
196
349
siz.set_component (
197
350
c,
198
351
ojph::point (
@@ -326,13 +479,20 @@ internal_exr_apply_ht (exr_encode_pipeline_t* encode)
326
479
327
480
cs.flush ();
328
481
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);
330
486
487
+ assert (output.tell () >= 0 );
331
488
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 )
333
490
{
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;
336
496
}
337
497
else
338
498
{
0 commit comments