Coverage Report

Created: 2026-04-01 07:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libheif/libheif/pixelimage.h
Line
Count
Source
1
/*
2
 * HEIF codec.
3
 * Copyright (c) 2017 Dirk Farin <dirk.farin@gmail.com>
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
22
#ifndef LIBHEIF_IMAGE_H
23
#define LIBHEIF_IMAGE_H
24
25
//#include "heif.h"
26
#include "error.h"
27
#include "nclx.h"
28
#include <libheif/heif_experimental.h>
29
#include <libheif/heif_uncompressed.h>
30
#if HEIF_WITH_OMAF
31
#include "omaf_boxes.h"
32
#endif
33
#include "security_limits.h"
34
35
#include <vector>
36
#include <memory>
37
#include <map>
38
#include <optional>
39
#include <set>
40
#include <utility>
41
#include <cassert>
42
#include <string>
43
44
struct BayerPattern
45
{
46
  uint16_t pattern_width = 0;
47
  uint16_t pattern_height = 0;
48
  std::vector<heif_bayer_pattern_pixel> pixels;
49
};
50
51
struct PolarizationPattern
52
{
53
  std::vector<uint32_t> component_indices;  // empty = applies to all components
54
  uint16_t pattern_width = 0;
55
  uint16_t pattern_height = 0;
56
  std::vector<float> polarization_angles;   // pattern_width * pattern_height entries
57
                                            // 0xFFFFFFFF bit-pattern (NaN) = no polarization filter
58
};
59
60
struct SensorBadPixelsMap
61
{
62
  std::vector<uint32_t> component_indices;  // empty = applies to all components
63
  bool correction_applied = false;
64
  std::vector<uint32_t> bad_rows;
65
  std::vector<uint32_t> bad_columns;
66
  struct BadPixel { uint32_t row; uint32_t column; };
67
  std::vector<BadPixel> bad_pixels;
68
};
69
70
struct SensorNonUniformityCorrection
71
{
72
  std::vector<uint32_t> component_indices;  // empty = applies to all components
73
  bool nuc_is_applied = false;
74
  uint32_t image_width = 0;
75
  uint32_t image_height = 0;
76
  std::vector<float> nuc_gains;    // image_width * image_height entries
77
  std::vector<float> nuc_offsets;  // image_width * image_height entries
78
};
79
80
heif_chroma chroma_from_subsampling(int h, int v);
81
82
uint32_t chroma_width(uint32_t w, heif_chroma chroma);
83
84
uint32_t chroma_height(uint32_t h, heif_chroma chroma);
85
86
uint32_t channel_width(uint32_t w, heif_chroma chroma, heif_channel channel);
87
88
uint32_t channel_height(uint32_t h, heif_chroma chroma, heif_channel channel);
89
90
bool is_interleaved_with_alpha(heif_chroma chroma);
91
92
int num_interleaved_components_per_plane(heif_chroma chroma);
93
94
bool is_integer_multiple_of_chroma_size(uint32_t width,
95
                                        uint32_t height,
96
                                        heif_chroma chroma);
97
98
// Returns the list of valid heif_chroma values for a given colorspace.
99
std::vector<heif_chroma> get_valid_chroma_values_for_colorspace(heif_colorspace colorspace);
100
101
class ImageExtraData
102
{
103
public:
104
  virtual ~ImageExtraData();
105
106
  // TODO: Decide who is responsible for writing the colr boxes.
107
  //       Currently it is distributed over various places.
108
  //       Either here, in image_item.cc or in grid.cc.
109
  std::vector<std::shared_ptr<Box>> generate_property_boxes(bool generate_colr_boxes) const;
110
111
112
  // --- color profile
113
114
  bool has_nclx_color_profile() const;
115
116
12.8k
  virtual void set_color_profile_nclx(const nclx_profile& profile) { m_color_profile_nclx = profile; }
117
118
23.2k
  nclx_profile get_color_profile_nclx() const { return m_color_profile_nclx; }
119
120
  // get the stored nclx fallback or return the default nclx if none is stored
121
  nclx_profile get_color_profile_nclx_with_fallback() const;
122
123
8.13k
  virtual void set_color_profile_icc(const std::shared_ptr<const color_profile_raw>& profile) { m_color_profile_icc = profile; }
124
125
3.06k
  bool has_icc_color_profile() const { return m_color_profile_icc != nullptr; }
126
127
15.2k
  const std::shared_ptr<const color_profile_raw>& get_color_profile_icc() const { return m_color_profile_icc; }
128
129
  void set_color_profile(const std::shared_ptr<const color_profile>& profile)
130
3.57k
  {
131
3.57k
    auto icc = std::dynamic_pointer_cast<const color_profile_raw>(profile);
132
3.57k
    if (icc) {
133
3.06k
      set_color_profile_icc(icc);
134
3.06k
    }
135
136
3.57k
    auto nclx = std::dynamic_pointer_cast<const color_profile_nclx>(profile);
137
3.57k
    if (nclx) {
138
512
      set_color_profile_nclx(nclx->get_nclx_color_profile());
139
512
    }
140
3.57k
  }
141
142
143
  // --- premultiplied alpha
144
145
3.83k
  bool is_premultiplied_alpha() const { return m_premultiplied_alpha; }
146
147
3.83k
  virtual void set_premultiplied_alpha(bool flag) { m_premultiplied_alpha = flag; }
148
149
150
  // --- pixel aspect ratio
151
152
3.83k
  bool has_nonsquare_pixel_ratio() const { return m_PixelAspectRatio_h != m_PixelAspectRatio_v; }
153
154
  void get_pixel_ratio(uint32_t* h, uint32_t* v) const
155
0
  {
156
0
    *h = m_PixelAspectRatio_h;
157
0
    *v = m_PixelAspectRatio_v;
158
0
  }
159
160
  virtual void set_pixel_ratio(uint32_t h, uint32_t v)
161
10
  {
162
10
    m_PixelAspectRatio_h = h;
163
10
    m_PixelAspectRatio_v = v;
164
10
  }
165
166
  // --- clli
167
168
3.83k
  bool has_clli() const { return m_clli.max_content_light_level != 0 || m_clli.max_pic_average_light_level != 0; }
169
170
0
  heif_content_light_level get_clli() const { return m_clli; }
171
172
0
  virtual void set_clli(const heif_content_light_level& clli) { m_clli = clli; }
173
174
  // --- mdcv
175
176
3.83k
  bool has_mdcv() const { return m_mdcv.has_value(); }
177
178
0
  heif_mastering_display_colour_volume get_mdcv() const { return *m_mdcv; }
179
180
  virtual void set_mdcv(const heif_mastering_display_colour_volume& mdcv)
181
0
  {
182
0
    m_mdcv = mdcv;
183
0
  }
184
185
0
  void unset_mdcv() { m_mdcv.reset(); }
186
187
0
  virtual Error set_tai_timestamp(const heif_tai_timestamp_packet* tai) {
188
0
    delete m_tai_timestamp;
189
190
0
    m_tai_timestamp = heif_tai_timestamp_packet_alloc();
191
0
    heif_tai_timestamp_packet_copy(m_tai_timestamp, tai);
192
0
    return Error::Ok;
193
0
  }
194
195
3.83k
  const heif_tai_timestamp_packet* get_tai_timestamp() const {
196
3.83k
    return m_tai_timestamp;
197
3.83k
  }
198
199
200
0
  virtual void set_gimi_sample_content_id(std::string id) { m_gimi_sample_content_id = id; }
201
202
3.83k
  bool has_gimi_sample_content_id() const { return m_gimi_sample_content_id.has_value(); }
203
204
0
  std::string get_gimi_sample_content_id() const { assert(has_gimi_sample_content_id()); return *m_gimi_sample_content_id; }
205
206
207
0
  void set_component_content_ids(const std::vector<std::string>& ids) { m_component_content_ids = ids; }
208
209
0
  bool has_component_content_ids() const { return !m_component_content_ids.empty(); }
210
211
0
  const std::vector<std::string>& get_component_content_ids() const { return m_component_content_ids; }
212
213
214
  // --- bayer pattern
215
216
0
  bool has_bayer_pattern() const { return m_bayer_pattern.has_value(); }
217
218
0
  const BayerPattern& get_bayer_pattern() const { assert(has_bayer_pattern()); return *m_bayer_pattern; }
219
220
0
  virtual void set_bayer_pattern(const BayerPattern& pattern) { m_bayer_pattern = pattern; }
221
222
223
  // --- polarization pattern
224
225
0
  bool has_polarization_patterns() const { return !m_polarization_patterns.empty(); }
226
227
0
  const std::vector<PolarizationPattern>& get_polarization_patterns() const { return m_polarization_patterns; }
228
229
0
  virtual void set_polarization_patterns(const std::vector<PolarizationPattern>& p) { m_polarization_patterns = p; }
230
231
0
  virtual void add_polarization_pattern(const PolarizationPattern& p) { m_polarization_patterns.push_back(p); }
232
233
234
  // --- sensor bad pixels map
235
236
0
  bool has_sensor_bad_pixels_maps() const { return !m_sensor_bad_pixels_maps.empty(); }
237
238
0
  const std::vector<SensorBadPixelsMap>& get_sensor_bad_pixels_maps() const { return m_sensor_bad_pixels_maps; }
239
240
0
  virtual void set_sensor_bad_pixels_maps(const std::vector<SensorBadPixelsMap>& m) { m_sensor_bad_pixels_maps = m; }
241
242
0
  virtual void add_sensor_bad_pixels_map(const SensorBadPixelsMap& m) { m_sensor_bad_pixels_maps.push_back(m); }
243
244
245
  // --- sensor non-uniformity correction
246
247
0
  bool has_sensor_nuc() const { return !m_sensor_nuc.empty(); }
248
249
0
  const std::vector<SensorNonUniformityCorrection>& get_sensor_nuc() const { return m_sensor_nuc; }
250
251
0
  virtual void set_sensor_nuc(const std::vector<SensorNonUniformityCorrection>& n) { m_sensor_nuc = n; }
252
253
0
  virtual void add_sensor_nuc(const SensorNonUniformityCorrection& n) { m_sensor_nuc.push_back(n); }
254
255
256
  // --- chroma sample location (ISO 23001-17, Section 6.1.4)
257
258
0
  bool has_chroma_location() const { return m_chroma_location.has_value(); }
259
260
0
  uint8_t get_chroma_location() const { return m_chroma_location.value_or(0); }
261
262
0
  virtual void set_chroma_location(uint8_t loc) { m_chroma_location = loc; }
263
264
265
#if HEIF_WITH_OMAF
266
0
  bool has_omaf_image_projection() const {
267
0
    return (m_omaf_image_projection != heif_omaf_image_projection_flat);
268
0
  }
269
270
7.67k
  const heif_omaf_image_projection get_omaf_image_projection() const {
271
7.67k
    return m_omaf_image_projection;
272
7.67k
  }
273
274
7.68k
  virtual void set_omaf_image_projection(const heif_omaf_image_projection projection) {
275
7.68k
    m_omaf_image_projection = projection;
276
7.68k
  }
277
#endif
278
279
private:
280
  bool m_premultiplied_alpha = false;
281
  nclx_profile m_color_profile_nclx = nclx_profile::undefined();
282
  std::shared_ptr<const color_profile_raw> m_color_profile_icc;
283
284
  uint32_t m_PixelAspectRatio_h = 1;
285
  uint32_t m_PixelAspectRatio_v = 1;
286
  heif_content_light_level m_clli{};
287
  std::optional<heif_mastering_display_colour_volume> m_mdcv;
288
289
  heif_tai_timestamp_packet* m_tai_timestamp = nullptr;
290
291
  std::optional<std::string> m_gimi_sample_content_id;
292
293
  std::vector<std::string> m_component_content_ids;
294
295
  std::optional<BayerPattern> m_bayer_pattern;
296
297
  std::vector<PolarizationPattern> m_polarization_patterns;
298
299
  std::vector<SensorBadPixelsMap> m_sensor_bad_pixels_maps;
300
301
  std::vector<SensorNonUniformityCorrection> m_sensor_nuc;
302
303
  std::optional<uint8_t> m_chroma_location;
304
305
#if HEIF_WITH_OMAF
306
  heif_omaf_image_projection m_omaf_image_projection = heif_omaf_image_projection::heif_omaf_image_projection_flat;
307
#endif
308
309
protected:
310
  std::shared_ptr<Box_clli> get_clli_box() const;
311
312
  std::shared_ptr<Box_mdcv> get_mdcv_box() const;
313
314
  std::shared_ptr<Box_pasp> get_pasp_box() const;
315
316
  std::shared_ptr<Box_colr> get_colr_box_nclx() const;
317
318
  std::shared_ptr<Box_colr> get_colr_box_icc() const;
319
320
#if HEIF_WITH_OMAF
321
  std::shared_ptr<Box_prfr> get_prfr_box() const;
322
#endif
323
};
324
325
326
heif_channel map_uncompressed_component_to_channel(uint16_t component_type);
327
328
329
class HeifPixelImage : public std::enable_shared_from_this<HeifPixelImage>,
330
                       public ImageExtraData,
331
                       public ErrorBuffer
332
{
333
public:
334
9.51k
  explicit HeifPixelImage() = default;
335
336
  ~HeifPixelImage() override;
337
338
  void create(uint32_t width, uint32_t height, heif_colorspace colorspace, heif_chroma chroma);
339
340
  Error create_clone_image_at_new_size(const std::shared_ptr<const HeifPixelImage>& source, uint32_t w, uint32_t h,
341
                                       const heif_security_limits* limits);
342
343
  Error add_plane(heif_channel channel, uint32_t width, uint32_t height, int bit_depth, const heif_security_limits* limits);
344
345
  Error add_channel(heif_channel channel, uint32_t width, uint32_t height, heif_channel_datatype datatype, int bit_depth,
346
                    const heif_security_limits* limits);
347
348
  bool has_channel(heif_channel channel) const;
349
350
  // Has alpha information either as a separate channel or in the interleaved format.
351
  bool has_alpha() const;
352
353
6.08k
  uint32_t get_width() const { return m_width; }
354
355
5.99k
  uint32_t get_height() const { return m_height; }
356
357
  uint32_t get_width(heif_channel channel) const;
358
359
  uint32_t get_height(heif_channel channel) const;
360
361
  uint32_t get_width(uint32_t component_idx) const;
362
363
  uint32_t get_height(uint32_t component_idx) const;
364
365
0
  bool has_odd_width() const { return !!(m_width & 1); }
366
367
0
  bool has_odd_height() const { return !!(m_height & 1); }
368
369
  // TODO: currently only defined for colorspace RGB, YCbCr, Monochrome
370
  //uint32_t get_primary_width() const;
371
372
  // TODO: currently only defined for colorspace RGB, YCbCr, Monochrome
373
  //uint32_t get_primary_height() const;
374
375
  uint32_t get_primary_component() const;
376
377
9.32k
  heif_chroma get_chroma_format() const { return m_chroma; }
378
379
4.00k
  heif_colorspace get_colorspace() const { return m_colorspace; }
380
381
  std::set<heif_channel> get_channel_set() const;
382
383
  uint8_t get_storage_bits_per_pixel(heif_channel channel) const;
384
385
  uint8_t get_bits_per_pixel(heif_channel channel) const;
386
387
  // Get the maximum bit depth of a visual channel (YCbCr or RGB).
388
  uint8_t get_visual_image_bits_per_pixel() const;
389
390
  heif_channel_datatype get_datatype(heif_channel channel) const;
391
392
  int get_number_of_interleaved_components(heif_channel channel) const;
393
394
  // Note: we are using size_t as stride type since the stride is usually involved in a multiplication with the line number.
395
  //       For very large images (e.g. >2 GB), this can result in an integer overflow and corresponding illegal memory access.
396
  //       (see https://github.com/strukturag/libheif/issues/1419)
397
21.9k
  uint8_t* get_plane(heif_channel channel, size_t* out_stride) { return get_channel<uint8_t>(channel, out_stride); }
398
399
10.7k
  const uint8_t* get_plane(heif_channel channel, size_t* out_stride) const { return get_channel<uint8_t>(channel, out_stride); }
400
401
  template <typename T>
402
  T* get_channel(heif_channel channel, size_t* out_stride)
403
32.7k
  {
404
32.7k
    auto* comp = find_component_for_channel(channel);
405
32.7k
    if (!comp) {
406
0
      if (out_stride)
407
0
        *out_stride = 0;
408
409
0
      return nullptr;
410
0
    }
411
412
32.7k
    if (out_stride) {
413
32.7k
      *out_stride = static_cast<int>(comp->stride / sizeof(T));
414
32.7k
    }
415
416
32.7k
    return static_cast<T*>(comp->mem);
417
32.7k
  }
unsigned char* HeifPixelImage::get_channel<unsigned char>(heif_channel, unsigned long*)
Line
Count
Source
403
32.7k
  {
404
32.7k
    auto* comp = find_component_for_channel(channel);
405
32.7k
    if (!comp) {
406
0
      if (out_stride)
407
0
        *out_stride = 0;
408
409
0
      return nullptr;
410
0
    }
411
412
32.7k
    if (out_stride) {
413
32.7k
      *out_stride = static_cast<int>(comp->stride / sizeof(T));
414
32.7k
    }
415
416
32.7k
    return static_cast<T*>(comp->mem);
417
32.7k
  }
unsigned short* HeifPixelImage::get_channel<unsigned short>(heif_channel, unsigned long*)
Line
Count
Source
403
9
  {
404
9
    auto* comp = find_component_for_channel(channel);
405
9
    if (!comp) {
406
0
      if (out_stride)
407
0
        *out_stride = 0;
408
409
0
      return nullptr;
410
0
    }
411
412
9
    if (out_stride) {
413
9
      *out_stride = static_cast<int>(comp->stride / sizeof(T));
414
9
    }
415
416
9
    return static_cast<T*>(comp->mem);
417
9
  }
418
419
  template <typename T>
420
  const T* get_channel(heif_channel channel, size_t* out_stride) const
421
10.7k
  {
422
10.7k
    return const_cast<HeifPixelImage*>(this)->get_channel<T>(channel, out_stride);
423
10.7k
  }
424
425
426
  // --- index-based component access (for ISO 23001-17 multi-component images)
427
428
0
  uint32_t get_number_of_used_components() const { return static_cast<uint32_t>(m_planes.size()); }
429
430
0
  uint32_t get_total_number_of_cmpd_components() const { return static_cast<uint32_t>(m_cmpd_component_types.size()); }
431
432
  heif_channel get_component_channel(uint32_t component_idx) const;
433
434
  uint32_t get_component_width(uint32_t component_idx) const;
435
  uint32_t get_component_height(uint32_t component_idx) const;
436
  uint8_t get_component_bits_per_pixel(uint32_t component_idx) const;
437
  uint8_t get_component_storage_bits_per_pixel(uint32_t component_idx) const;
438
  heif_channel_datatype get_component_datatype(uint32_t component_idx) const;
439
440
  // Look up the component type from the cmpd table. Works for any cmpd index,
441
  // even those that have no image plane (e.g. bayer reference components).
442
  uint16_t get_component_type(uint32_t component_idx) const;
443
444
0
  std::vector<uint16_t> get_cmpd_component_types() const { return m_cmpd_component_types; }
445
446
  std::vector<uint32_t> get_component_cmpd_indices_interleaved() const;
447
448
0
  uint32_t get_component_cmpd_index() const { assert(m_cmpd_component_types.size()==1); return m_cmpd_component_types[0]; }
449
450
  // Encoder path: auto-generates component_index by appending to cmpd table.
451
  Result<uint32_t> add_component(uint32_t width, uint32_t height,
452
                                 uint16_t component_type,
453
                                 heif_channel_datatype datatype, int bit_depth,
454
                                 const heif_security_limits* limits);
455
456
  // Decoder path: uses a pre-populated cmpd table to look up the component type.
457
  Result<uint32_t> add_component_for_index(uint32_t component_index,
458
                                            uint32_t width, uint32_t height,
459
                                            heif_channel_datatype datatype, int bit_depth,
460
                                            const heif_security_limits* limits);
461
462
  // Populate the cmpd component types table (decoder path).
463
0
  void set_cmpd_component_types(std::vector<uint16_t> types) { m_cmpd_component_types = std::move(types); }
464
465
0
  const std::vector<uint16_t>& get_cmpd_component_types() { return m_cmpd_component_types; }
466
467
  // Returns the sorted list of component_indices of all planes that have pixel data.
468
  std::vector<uint32_t> get_used_component_indices() const;
469
470
  uint8_t* get_component(uint32_t component_idx, size_t* out_stride);
471
  const uint8_t* get_component(uint32_t component_idx, size_t* out_stride) const;
472
473
  template <typename T>
474
  T* get_component_data(uint32_t component_idx, size_t* out_stride)
475
0
  {
476
0
    auto* comp = find_component_by_index(component_idx);
477
0
    if (!comp) {
478
0
      if (out_stride) *out_stride = 0;
479
0
      return nullptr;
480
0
    }
481
482
0
    if (out_stride) {
483
0
      *out_stride = comp->stride / sizeof(T);
484
0
    }
485
0
    return static_cast<T*>(comp->mem);
486
0
  }
487
488
  template <typename T>
489
  const T* get_component_data(uint32_t component_idx, size_t* out_stride) const
490
0
  {
491
0
    return const_cast<HeifPixelImage*>(this)->get_component_data<T>(component_idx, out_stride);
492
0
  }
493
494
  Error copy_new_plane_from(const std::shared_ptr<const HeifPixelImage>& src_image,
495
                            heif_channel src_channel,
496
                            heif_channel dst_channel,
497
                            const heif_security_limits* limits);
498
499
  Error extract_alpha_from_RGBA(const std::shared_ptr<const HeifPixelImage>& srcimage, const heif_security_limits* limits);
500
501
  void fill_plane(heif_channel dst_channel, uint16_t value);
502
503
  Error fill_new_plane(heif_channel dst_channel, uint16_t value, int width, int height, int bpp, const heif_security_limits* limits);
504
505
  void transfer_plane_from_image_as(const std::shared_ptr<HeifPixelImage>& source,
506
                                    heif_channel src_channel,
507
                                    heif_channel dst_channel);
508
509
  Error copy_image_to(const std::shared_ptr<const HeifPixelImage>& source, uint32_t x0, uint32_t y0);
510
511
  void zero_region(uint32_t x0, uint32_t y0, uint32_t w, uint32_t h);
512
513
  Result<std::shared_ptr<HeifPixelImage>> rotate_ccw(int angle_degrees, const heif_security_limits* limits);
514
515
  Result<std::shared_ptr<HeifPixelImage>> mirror_inplace(heif_transform_mirror_direction, const heif_security_limits* limits);
516
517
  Result<std::shared_ptr<HeifPixelImage>> crop(uint32_t left, uint32_t right, uint32_t top, uint32_t bottom,
518
                                               const heif_security_limits* limits) const;
519
520
  Error fill_RGB_16bit(uint16_t r, uint16_t g, uint16_t b, uint16_t a);
521
522
  Error overlay(std::shared_ptr<HeifPixelImage>& overlay, int32_t dx, int32_t dy);
523
524
  Error scale_nearest_neighbor(std::shared_ptr<HeifPixelImage>& output, uint32_t width, uint32_t height,
525
                               const heif_security_limits* limits) const;
526
527
  void forward_all_metadata_from(const std::shared_ptr<const HeifPixelImage>& src_image);
528
529
  void debug_dump() const;
530
531
  Error extend_padding_to_size(uint32_t width, uint32_t height, bool adjust_size,
532
                               const heif_security_limits* limits);
533
534
  Error extend_to_size_with_zero(uint32_t width, uint32_t height, const heif_security_limits* limits);
535
536
  Result<std::shared_ptr<HeifPixelImage>> extract_image_area(uint32_t x0, uint32_t y0, uint32_t w, uint32_t h,
537
                                                             const heif_security_limits* limits) const;
538
539
540
  // --- sequences
541
542
3.83k
  void set_sample_duration(uint32_t d) { m_sample_duration = d; }
543
544
3.83k
  uint32_t get_sample_duration() const { return m_sample_duration; }
545
546
  // --- warnings
547
548
941
  void add_warning(Error warning) { m_warnings.emplace_back(std::move(warning)); }
549
550
2.10k
  void add_warnings(const std::vector<Error>& warning) { for (const auto& err : warning) m_warnings.emplace_back(err); }
551
552
4.30k
  const std::vector<Error>& get_warnings() const { return m_warnings; }
553
554
private:
555
  struct ImageComponent
556
  {
557
    heif_channel m_channel = heif_channel_Y;
558
559
    // index into the cmpd component definition table
560
    // Interleaved channels will have a list of indices in the order R,G,B,A
561
    std::vector<uint32_t> m_component_index;
562
563
    // limits=nullptr disables the limits
564
    Error alloc(uint32_t width, uint32_t height, heif_channel_datatype datatype, int bit_depth,
565
                int num_interleaved_components,
566
                const heif_security_limits* limits,
567
                MemoryHandle& memory_handle);
568
569
    heif_channel_datatype m_datatype = heif_channel_datatype_unsigned_integer;
570
571
    // logical bit depth per component
572
    // For interleaved formats, it is the number of bits for one component.
573
    // It is not the storage width.
574
    uint8_t m_bit_depth = 0;
575
    uint8_t m_num_interleaved_components = 1;
576
577
    // the "visible" area of the plane
578
    uint32_t m_width = 0;
579
    uint32_t m_height = 0;
580
581
    // the allocated memory size
582
    uint32_t m_mem_width = 0;
583
    uint32_t m_mem_height = 0;
584
585
    void* mem = nullptr; // aligned memory start
586
    uint8_t* allocated_mem = nullptr; // unaligned memory we allocated
587
    size_t   allocation_size = 0;
588
    size_t   stride = 0; // bytes per line
589
590
    int get_bytes_per_pixel() const;
591
592
    template <typename T> void mirror_inplace(heif_transform_mirror_direction);
593
594
    template<typename T>
595
    void rotate_ccw(int angle_degrees, ImageComponent& out_plane) const;
596
597
    void crop(uint32_t left, uint32_t right, uint32_t top, uint32_t bottom, int bytes_per_pixel, ImageComponent& out_plane) const;
598
  };
599
600
  ImageComponent* find_component_for_channel(heif_channel channel);
601
  const ImageComponent* find_component_for_channel(heif_channel channel) const;
602
603
  ImageComponent* find_component_by_index(uint32_t component_index);
604
  const ImageComponent* find_component_by_index(uint32_t component_index) const;
605
606
  ImageComponent new_image_plane_for_channel(heif_channel channel);
607
608
  uint32_t m_width = 0;
609
  uint32_t m_height = 0;
610
  heif_colorspace m_colorspace = heif_colorspace_undefined;
611
  heif_chroma m_chroma = heif_chroma_undefined;
612
613
  std::vector<ImageComponent> m_planes;
614
  std::vector<uint16_t> m_cmpd_component_types;  // indexed by cmpd index
615
  MemoryHandle m_memory_handle;
616
617
  uint32_t m_sample_duration = 0; // duration of a sequence frame
618
619
  std::vector<Error> m_warnings;
620
};
621
622
#endif