Coverage Report

Created: 2025-07-23 08:18

/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