/src/libheif/libheif/codecs/jpeg2000_boxes.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * HEIF JPEG 2000 codec. |
3 | | * Copyright (c) 2023 Brad Hards <bradh@frogmouth.net> |
4 | | * |
5 | | * This file is part of libheif. |
6 | | * |
7 | | * libheif is free software: you can redistribute it and/or modify |
8 | | * it under the terms of the GNU Lesser General Public License as |
9 | | * published by the Free Software Foundation, either version 3 of |
10 | | * the License, or (at your option) any later version. |
11 | | * |
12 | | * libheif is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | * GNU Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public License |
18 | | * along with libheif. If not, see <http://www.gnu.org/licenses/>. |
19 | | */ |
20 | | |
21 | | #ifndef LIBHEIF_JPEG2000_BOXES_H |
22 | | #define LIBHEIF_JPEG2000_BOXES_H |
23 | | |
24 | | #include "box.h" |
25 | | #include "file.h" |
26 | | #include "context.h" |
27 | | #include <cstdint> |
28 | | #include <string> |
29 | | #include <vector> |
30 | | #include <memory> |
31 | | #include <utility> |
32 | | |
33 | | /** |
34 | | * JPEG 2000 Channel Definition box. |
35 | | * |
36 | | * This is defined in ITU-800 / IEC 15444-1. |
37 | | * |
38 | | * The Channel Definition box provides the type and ordering of the components |
39 | | * within the codestream. The mapping between actual components from the |
40 | | * codestream to channels is specified in the Component Mapping box. If the |
41 | | * header does not contain a Component Mapping box, then a reader shall map |
42 | | * component |
43 | | * @code{i} to channel @code{i}, for all components in the codestream. |
44 | | * |
45 | | * This box contains an array of channel descriptions. For each description, |
46 | | * three values are specified: the index of the channel described by that |
47 | | * association, the type of that channel, and the association of that channel |
48 | | * with particular colours. This box may specify multiple descriptions for a |
49 | | * single channel. If a multiple component transform is specified within the |
50 | | * codestream, the image must be in an RGB colourspace and the red, green and |
51 | | * blue colours as channels 0, 1 and 2 in the codestream, respectively. |
52 | | * |
53 | | * This box is required within the JPEG 2000 header item property (`j2kH`). |
54 | | */ |
55 | | class Box_cdef : public Box { |
56 | | public: |
57 | 64 | Box_cdef() { set_short_type(fourcc("cdef")); } |
58 | | |
59 | | std::string dump(Indent &) const override; |
60 | | |
61 | | Error write(StreamWriter &writer) const override; |
62 | | |
63 | | struct Channel { |
64 | | /** |
65 | | * Channel index (`Cn`). |
66 | | * |
67 | | * This field specifies the index of the channel for this description. |
68 | | * The value of this field represents the index of the channel as |
69 | | * defined within the Component Mapping box (or the actual component |
70 | | * from the codestream if the file does not contain a Component Mapping |
71 | | * box). |
72 | | */ |
73 | | uint16_t channel_index; |
74 | | /** |
75 | | * Channel type (`Typ`). |
76 | | * |
77 | | * Each channel type value shall be equal to 0 (colour), 1 (alpha) |
78 | | * or 2 (pre-multiplied alpha). |
79 | | * |
80 | | * At most one channel type value shall be equal to 1 or 2 (i.e. a |
81 | | * single alpha channel), and the corresponding association field |
82 | | * value shall be 0. |
83 | | */ |
84 | | uint16_t channel_type; |
85 | | /** |
86 | | * Channel association (`Asoc`). |
87 | | * |
88 | | * If the channel type value is 0 (colour), then the channel association |
89 | | * value shall be in the range [1, 2<sup>16</sup> -2]. |
90 | | * Interpretation of this depends on the colourspace. |
91 | | */ |
92 | | uint16_t channel_association; |
93 | | }; |
94 | | |
95 | | /** |
96 | | * Get the channels in this channel definition box. |
97 | | * |
98 | | * @return the channels as a read-only vector. |
99 | | */ |
100 | 0 | const std::vector<Channel> &get_channels() const { return m_channels; } |
101 | | |
102 | | /** |
103 | | * Add a channel to this channel definition box. |
104 | | * |
105 | | * @param channel the channel to add |
106 | | */ |
107 | 0 | void add_channel(Channel channel) { m_channels.push_back(channel); } |
108 | | |
109 | | void set_channels(heif_colorspace colorspace); |
110 | | |
111 | | protected: |
112 | | Error parse(BitstreamRange &range, const heif_security_limits* limits) override; |
113 | | |
114 | | private: |
115 | | std::vector<Channel> m_channels; |
116 | | }; |
117 | | |
118 | | /** |
119 | | * JPEG 2000 Component Mapping box. |
120 | | * |
121 | | * The Component Mapping box defines how image channels are identified from the |
122 | | * actual components decoded from the codestream. This abstraction allows a |
123 | | * single structure (the Channel Definition box) to specify the colour or type |
124 | | * of both palettised images and non-palettised images. This box contains an |
125 | | * array of CMP<sup>i</sup>, MTYP<sup>i</sup> and PCOL<sup>i</sup> fields. Each |
126 | | * group of these fields represents the definition of one channel in the image. |
127 | | * The channels are numbered in order starting with zero, and the number of |
128 | | * channels specified in the Component Mapping box is determined by the length |
129 | | * of the box. |
130 | | * |
131 | | * There shall be at most one Component Mapping box inside a JP2 Header box. |
132 | | * If the JP2 Header box contains a Palette box, then the JP2 Header box |
133 | | * shall also contain a Component Mapping box. If the JP2 Header box does |
134 | | * not contain a Component Mapping box, the components shall be mapped |
135 | | * directly to channels, such that component @code{i} is mapped to channel |
136 | | * @code {i}. |
137 | | */ |
138 | | class Box_cmap : public Box |
139 | | { |
140 | | public: |
141 | 192 | Box_cmap() { set_short_type(fourcc("cmap")); } |
142 | | |
143 | | std::string dump(Indent &) const override; |
144 | | |
145 | | Error write(StreamWriter &writer) const override; |
146 | | |
147 | | struct Component |
148 | | { |
149 | | uint16_t component_index; |
150 | | uint8_t mapping_type; |
151 | | uint8_t palette_colour; |
152 | | }; |
153 | | |
154 | | /** |
155 | | * Get the components in this component mapping box. |
156 | | * |
157 | | * @return the components as a read-only vector. |
158 | | */ |
159 | 0 | const std::vector<Component> &get_components() const { return m_components; } |
160 | | |
161 | | /** |
162 | | * Add a component to this component mapping box. |
163 | | * |
164 | | * @param component the component to add |
165 | | */ |
166 | 0 | void add_component(Component component) { m_components.push_back(component); } |
167 | | |
168 | | protected: |
169 | | Error parse(BitstreamRange &range, const heif_security_limits* limits) override; |
170 | | |
171 | | private: |
172 | | std::vector<Component> m_components; |
173 | | }; |
174 | | |
175 | | |
176 | | /** |
177 | | * JPEG 2000 Palette box. |
178 | | * |
179 | | * This box defines the palette to be used to create multiple components |
180 | | * from a single component. |
181 | | */ |
182 | | class Box_pclr : public Box |
183 | | { |
184 | | public: |
185 | | Box_pclr() |
186 | 155 | { |
187 | 155 | set_short_type(fourcc("pclr")); |
188 | 155 | } |
189 | | |
190 | | std::string dump(Indent &) const override; |
191 | | |
192 | | Error write(StreamWriter &writer) const override; |
193 | | |
194 | | struct PaletteEntry |
195 | | { |
196 | | // JPEG 2000 supports 38 bits and signed/unsigned, but we only |
197 | | // do up to 16 bit unsigned. |
198 | | std::vector<uint16_t> columns; |
199 | | }; |
200 | | |
201 | | /** |
202 | | * Get the entries in this palette box. |
203 | | * |
204 | | * @return the entries as a read-only vector. |
205 | | */ |
206 | | const std::vector<PaletteEntry>& get_entries() const |
207 | 0 | { |
208 | 0 | return m_entries; |
209 | 0 | } |
210 | | |
211 | | /** |
212 | | * Get the bit depths for the columns in this palette box. |
213 | | * |
214 | | * @return the bit depths as a read-only vector. |
215 | | */ |
216 | | const std::vector<uint8_t>& get_bit_depths() const |
217 | 0 | { |
218 | 0 | return m_bitDepths; |
219 | 0 | } |
220 | | |
221 | | const uint8_t get_num_entries() const |
222 | 0 | { |
223 | 0 | return (uint8_t)(m_entries.size()); |
224 | 0 | } |
225 | | |
226 | | const uint8_t get_num_columns() const |
227 | 0 | { |
228 | 0 | return (uint8_t)(m_bitDepths.size()); |
229 | 0 | } |
230 | | |
231 | | void add_entry(const PaletteEntry entry) |
232 | 0 | { |
233 | 0 | m_entries.push_back(entry); |
234 | 0 | } |
235 | | |
236 | | /** |
237 | | * Set columns for the palette mapping. |
238 | | * |
239 | | * Each column has the same bit depth. |
240 | | * |
241 | | * This will reset any existing columns and entries. |
242 | | * |
243 | | * @param num_columns the number of columns (e.g. 3 for RGB) |
244 | | * @param bit_depth the bit depth for each column (e.g. 8 for 24-bit RGB) |
245 | | */ |
246 | | void set_columns(uint8_t num_columns, uint8_t bit_depth); |
247 | | |
248 | | protected: |
249 | | Error parse(BitstreamRange &range, const heif_security_limits* limits) override; |
250 | | |
251 | | private: |
252 | | std::vector<uint8_t> m_bitDepths; |
253 | | std::vector<PaletteEntry> m_entries; |
254 | | }; |
255 | | |
256 | | |
257 | | /** |
258 | | * JPEG 2000 layers box. |
259 | | * |
260 | | * The JPEG 2000 layers box declares a list of quality and resolution layers |
261 | | * for a JPEG 2000 codestream. |
262 | | * |
263 | | * @note the JPEG 2000 codestream can contain layers not listed in the JPEG 2000 |
264 | | * layers box. |
265 | | */ |
266 | | class Box_j2kL : public FullBox |
267 | | { |
268 | | public: |
269 | 137 | Box_j2kL() { set_short_type(fourcc("j2kL")); } |
270 | | |
271 | | std::string dump(Indent &) const override; |
272 | | |
273 | | Error write(StreamWriter &writer) const override; |
274 | | |
275 | | struct Layer { |
276 | | /** |
277 | | * Unique identifier for the layer. |
278 | | */ |
279 | | uint16_t layer_id; |
280 | | /** |
281 | | * Number of resolution levels of the codestream that can be discarded. |
282 | | */ |
283 | | uint8_t discard_levels; |
284 | | /** |
285 | | * Minimum number of quality layers of the codestream to be decoded. |
286 | | */ |
287 | | uint16_t decode_layers; |
288 | | }; |
289 | | |
290 | | /** |
291 | | * Get the layers in this layer box. |
292 | | * |
293 | | * @return the layers as a read-only vector. |
294 | | */ |
295 | 0 | const std::vector<Layer> &get_layers() const { return m_layers; } |
296 | | |
297 | | /** |
298 | | * Add a layer to the layers box. |
299 | | * |
300 | | * @param layer the layer to add |
301 | | */ |
302 | 0 | void add_layer(Layer layer) { m_layers.push_back(layer); } |
303 | | |
304 | | protected: |
305 | | Error parse(BitstreamRange &range, const heif_security_limits* limits) override; |
306 | | |
307 | | private: |
308 | | std::vector<Layer> m_layers; |
309 | | }; |
310 | | |
311 | | class Box_j2kH : public Box |
312 | | { |
313 | | public: |
314 | 33 | Box_j2kH() { set_short_type(fourcc("j2kH")); } |
315 | | |
316 | 0 | bool is_essential() const override { return true; } |
317 | | |
318 | | std::string dump(Indent &) const override; |
319 | | |
320 | | // Default write behaviour for a container is to write children |
321 | | |
322 | | protected: |
323 | | Error parse(BitstreamRange &range, const heif_security_limits* limits) override; |
324 | | }; |
325 | | |
326 | | class Jpeg2000ImageCodec |
327 | | { |
328 | | public: |
329 | | |
330 | | // static Error decode_jpeg2000_image(const HeifContext* context, |
331 | | // heif_item_id ID, |
332 | | // std::shared_ptr<HeifPixelImage>& img, |
333 | | // const std::vector<uint8_t>& uncompressed_data); |
334 | | |
335 | | static Error encode_jpeg2000_image(const std::shared_ptr<HeifFile>& heif_file, |
336 | | const std::shared_ptr<HeifPixelImage>& src_image, |
337 | | void* encoder_struct, |
338 | | const struct heif_encoding_options& options, |
339 | | std::shared_ptr<ImageItem>& out_image); |
340 | | }; |
341 | | |
342 | | struct JPEG2000_SIZ_segment |
343 | | { |
344 | | /** |
345 | | * Decoder capabilities bitmap (Rsiz). |
346 | | */ |
347 | | uint16_t decoder_capabilities = 0; |
348 | | /** |
349 | | * Width of the reference grid (Xsiz). |
350 | | */ |
351 | | uint32_t reference_grid_width = 0; |
352 | | /** |
353 | | * Height of the reference grid (Ysiz). |
354 | | */ |
355 | | uint32_t reference_grid_height = 0; |
356 | | /** |
357 | | * Horizontal offset from reference grid origin to image left side (XOsiz). |
358 | | */ |
359 | | uint32_t image_horizontal_offset = 0; |
360 | | /** |
361 | | * Vertical offset from reference grid origin to image top size (YOsiz). |
362 | | */ |
363 | | uint32_t image_vertical_offset = 0; |
364 | | /** |
365 | | * Width of one reference tile with respect to the reference grid (XTsiz). |
366 | | */ |
367 | | uint32_t tile_width = 0; |
368 | | /** |
369 | | * Height of one reference tile with respect to the reference grid (YTsiz). |
370 | | */ |
371 | | uint32_t tile_height = 0; |
372 | | /** |
373 | | * Horizontal offset from the origin of the reference grid to left side of first tile (XTOsiz). |
374 | | */ |
375 | | uint32_t tile_offset_x = 0; |
376 | | /** |
377 | | * Vertical offset from the origin of the reference grid to top side of first tile (YTOsiz). |
378 | | */ |
379 | | uint32_t tile_offset_y = 0; |
380 | | |
381 | | struct component |
382 | | { |
383 | | uint8_t h_separation, v_separation; |
384 | | uint8_t precision; |
385 | | bool is_signed; |
386 | | }; |
387 | | |
388 | | std::vector<component> components; |
389 | | }; |
390 | | |
391 | | class JPEG2000_Extension_Capability { |
392 | | public: |
393 | 0 | JPEG2000_Extension_Capability(const uint8_t i) : ident(i) {} |
394 | | |
395 | 0 | uint8_t getIdent() const { |
396 | 0 | return ident; |
397 | 0 | } |
398 | | |
399 | 0 | uint16_t getValue() const { |
400 | 0 | return value; |
401 | 0 | } |
402 | | |
403 | 0 | void setValue(uint16_t val) { |
404 | 0 | value = val; |
405 | 0 | } |
406 | | |
407 | | private: |
408 | | const uint8_t ident; |
409 | | uint16_t value = 0; |
410 | | }; |
411 | | |
412 | | class JPEG2000_Extension_Capability_HT : public JPEG2000_Extension_Capability |
413 | | { |
414 | | public: |
415 | | static const int IDENT = 15; |
416 | 0 | JPEG2000_Extension_Capability_HT(): JPEG2000_Extension_Capability(IDENT) |
417 | 0 | {}; |
418 | | }; |
419 | | |
420 | | class JPEG2000_CAP_segment |
421 | | { |
422 | | public: |
423 | 0 | void push_back(JPEG2000_Extension_Capability ccap) { |
424 | 0 | extensions.push_back(ccap); |
425 | 0 | } |
426 | 0 | bool hasHighThroughputExtension() const { |
427 | 0 | for (auto &extension : extensions) { |
428 | 0 | if (extension.getIdent() == 15) { |
429 | 0 | return true; |
430 | 0 | } |
431 | 0 | } |
432 | 0 | return false; |
433 | 0 | } |
434 | | private: |
435 | | std::vector<JPEG2000_Extension_Capability> extensions; |
436 | | |
437 | | }; |
438 | | |
439 | | struct JPEG2000MainHeader |
440 | | { |
441 | | public: |
442 | 0 | JPEG2000MainHeader() = default; |
443 | | |
444 | | Error parseHeader(const std::vector<uint8_t>& compressedImageData); |
445 | | |
446 | | // Use parseHeader instead - these are mainly for unit testing |
447 | | Error doParse(); |
448 | | void setHeaderData(std::vector<uint8_t> data) |
449 | 0 | { |
450 | 0 | headerData = std::move(data); |
451 | 0 | } |
452 | | |
453 | | heif_chroma get_chroma_format() const; |
454 | | |
455 | | int get_precision(uint32_t index) const |
456 | 0 | { |
457 | 0 | if (index >= siz.components.size()) { |
458 | 0 | return -1; |
459 | 0 | } |
460 | | // TODO: this is a quick hack. It is more complicated for JPEG2000 because these can be any kind of colorspace (e.g. RGB). |
461 | 0 | return siz.components[index].precision; |
462 | 0 | } |
463 | | |
464 | 0 | bool hasHighThroughputExtension() { |
465 | 0 | return cap.hasHighThroughputExtension(); |
466 | 0 | } |
467 | | |
468 | | uint32_t getXSize() const |
469 | 0 | { |
470 | 0 | return siz.reference_grid_width; |
471 | 0 | } |
472 | | |
473 | | uint32_t getYSize() const |
474 | 0 | { |
475 | 0 | return siz.reference_grid_height; |
476 | 0 | } |
477 | | |
478 | | const JPEG2000_SIZ_segment get_SIZ() |
479 | 0 | { |
480 | 0 | return siz; |
481 | 0 | } |
482 | | |
483 | | private: |
484 | | Error parse_SOC_segment(); |
485 | | Error parse_SIZ_segment(); |
486 | | Error parse_CAP_segment_body(); |
487 | | void parse_Ccap15(); |
488 | | |
489 | | static const int MARKER_LEN = 2; |
490 | | |
491 | | JPEG2000_SIZ_segment siz; |
492 | | JPEG2000_CAP_segment cap; |
493 | | |
494 | | uint8_t read8() |
495 | 0 | { |
496 | 0 | uint8_t res = headerData[cursor]; |
497 | 0 | cursor += 1; |
498 | 0 | return res; |
499 | 0 | } |
500 | | |
501 | | uint16_t read16() |
502 | 0 | { |
503 | 0 | uint16_t res = (uint16_t)((headerData[cursor] << 8) | headerData[cursor + 1]); |
504 | 0 | cursor += 2; |
505 | 0 | return res; |
506 | 0 | } |
507 | | |
508 | | uint32_t read32() |
509 | 0 | { |
510 | 0 | uint32_t res = (headerData[cursor] << 24) | (headerData[cursor + 1] << 16) | (headerData[cursor + 2] << 8) | headerData[cursor + 3]; |
511 | 0 | cursor += 4; |
512 | 0 | return res; |
513 | 0 | } |
514 | | |
515 | | std::vector<uint8_t> headerData; |
516 | | size_t cursor = 0; |
517 | | }; |
518 | | |
519 | | |
520 | | class Box_j2ki : public Box_VisualSampleEntry |
521 | | { |
522 | | public: |
523 | | Box_j2ki() |
524 | 7 | { |
525 | 7 | set_short_type(fourcc("j2ki")); |
526 | 7 | } |
527 | | }; |
528 | | |
529 | | #endif // LIBHEIF_JPEG2000_BOXES_H |