Coverage Report

Created: 2025-06-16 07:00

/src/libheif/libheif/pixelimage.h
Line
Count
Source (jump to first uncovered line)
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 "security_limits.h"
30
31
#include <vector>
32
#include <memory>
33
#include <map>
34
#include <set>
35
#include <utility>
36
#include <cassert>
37
#include <string>
38
39
heif_chroma chroma_from_subsampling(int h, int v);
40
41
uint32_t chroma_width(uint32_t w, heif_chroma chroma);
42
43
uint32_t chroma_height(uint32_t h, heif_chroma chroma);
44
45
uint32_t channel_width(uint32_t w, heif_chroma chroma, heif_channel channel);
46
47
uint32_t channel_height(uint32_t h, heif_chroma chroma, heif_channel channel);
48
49
bool is_interleaved_with_alpha(heif_chroma chroma);
50
51
int num_interleaved_pixels_per_plane(heif_chroma chroma);
52
53
bool is_integer_multiple_of_chroma_size(uint32_t width,
54
                                        uint32_t height,
55
                                        heif_chroma chroma);
56
57
// Returns the list of valid heif_chroma values for a given colorspace.
58
std::vector<heif_chroma> get_valid_chroma_values_for_colorspace(heif_colorspace colorspace);
59
60
// TODO: move to public API when used
61
enum heif_chroma420_sample_position {
62
  // values 0-5 according to ISO 23091-2 / ITU-T H.273
63
  heif_chroma420_sample_position_00_05 = 0,
64
  heif_chroma420_sample_position_05_05 = 1,
65
  heif_chroma420_sample_position_00_00 = 2,
66
  heif_chroma420_sample_position_05_00 = 3,
67
  heif_chroma420_sample_position_00_10 = 4,
68
  heif_chroma420_sample_position_05_10 = 5,
69
70
  // values 6 according to ISO 23001-17
71
  heif_chroma420_sample_position_00_00_01_00 = 6
72
};
73
74
75
class HeifPixelImage : public std::enable_shared_from_this<HeifPixelImage>,
76
                       public ErrorBuffer
77
{
78
public:
79
5.52k
  explicit HeifPixelImage() = default;
80
81
  ~HeifPixelImage();
82
83
  void create(uint32_t width, uint32_t height, heif_colorspace colorspace, heif_chroma chroma);
84
85
  Error create_clone_image_at_new_size(const std::shared_ptr<const HeifPixelImage>& source, uint32_t w, uint32_t h,
86
                                       const heif_security_limits* limits);
87
88
  Error add_plane(heif_channel channel, uint32_t width, uint32_t height, int bit_depth, const heif_security_limits* limits);
89
90
  Error add_channel(heif_channel channel, uint32_t width, uint32_t height, heif_channel_datatype datatype, int bit_depth,
91
                    const heif_security_limits* limits);
92
93
  bool has_channel(heif_channel channel) const;
94
95
  // Has alpha information either as a separate channel or in the interleaved format.
96
  bool has_alpha() const;
97
98
3.39k
  bool is_premultiplied_alpha() const { return m_premultiplied_alpha; }
99
100
3.39k
  void set_premultiplied_alpha(bool flag) { m_premultiplied_alpha = flag; }
101
102
4.65k
  uint32_t get_width() const { return m_width; }
103
104
4.65k
  uint32_t get_height() const { return m_height; }
105
106
  uint32_t get_width(enum heif_channel channel) const;
107
108
  uint32_t get_height(enum heif_channel channel) const;
109
110
0
  bool has_odd_width() const { return !!(m_width & 1); }
111
112
0
  bool has_odd_height() const { return !!(m_height & 1); }
113
114
5.82k
  heif_chroma get_chroma_format() const { return m_chroma; }
115
116
3.26k
  heif_colorspace get_colorspace() const { return m_colorspace; }
117
118
  std::set<enum heif_channel> get_channel_set() const;
119
120
  uint8_t get_storage_bits_per_pixel(enum heif_channel channel) const;
121
122
  uint8_t get_bits_per_pixel(enum heif_channel channel) const;
123
124
  // Get the maximum bit depth of a visual channel (YCbCr or RGB).
125
  uint8_t get_visual_image_bits_per_pixel() const;
126
127
  heif_channel_datatype get_datatype(enum heif_channel channel) const;
128
129
  int get_number_of_interleaved_components(heif_channel channel) const;
130
131
  // Note: we are using size_t as stride type since the stride is usually involved in a multiplication with the line number.
132
  //       For very large images (e.g. >2 GB), this can result in an integer overflow and corresponding illegal memory access.
133
  //       (see https://github.com/strukturag/libheif/issues/1419)
134
12.0k
  uint8_t* get_plane(enum heif_channel channel, size_t* out_stride) { return get_channel<uint8_t>(channel, out_stride); }
135
136
8.97k
  const uint8_t* get_plane(enum heif_channel channel, size_t* out_stride) const { return get_channel<uint8_t>(channel, out_stride); }
137
138
  template <typename T>
139
  T* get_channel(enum heif_channel channel, size_t* out_stride)
140
20.9k
  {
141
20.9k
    auto iter = m_planes.find(channel);
142
20.9k
    if (iter == m_planes.end()) {
143
0
      if (out_stride)
144
0
        *out_stride = 0;
145
146
0
      return nullptr;
147
0
    }
148
149
20.9k
    if (out_stride) {
150
20.9k
      *out_stride = static_cast<int>(iter->second.stride / sizeof(T));
151
20.9k
    }
152
153
    //assert(sizeof(T) == iter->second.get_bytes_per_pixel());
154
155
20.9k
    return static_cast<T*>(iter->second.mem);
156
20.9k
  }
unsigned char* HeifPixelImage::get_channel<unsigned char>(heif_channel, unsigned long*)
Line
Count
Source
140
20.9k
  {
141
20.9k
    auto iter = m_planes.find(channel);
142
20.9k
    if (iter == m_planes.end()) {
143
0
      if (out_stride)
144
0
        *out_stride = 0;
145
146
0
      return nullptr;
147
0
    }
148
149
20.9k
    if (out_stride) {
150
20.9k
      *out_stride = static_cast<int>(iter->second.stride / sizeof(T));
151
20.9k
    }
152
153
    //assert(sizeof(T) == iter->second.get_bytes_per_pixel());
154
155
20.9k
    return static_cast<T*>(iter->second.mem);
156
20.9k
  }
Unexecuted instantiation: unsigned short* HeifPixelImage::get_channel<unsigned short>(heif_channel, unsigned long*)
157
158
  template <typename T>
159
  const T* get_channel(enum heif_channel channel, size_t* out_stride) const
160
8.97k
  {
161
8.97k
    return const_cast<HeifPixelImage*>(this)->get_channel<T>(channel, out_stride);
162
8.97k
  }
163
164
  Error copy_new_plane_from(const std::shared_ptr<const HeifPixelImage>& src_image,
165
                            heif_channel src_channel,
166
                            heif_channel dst_channel,
167
                            const heif_security_limits* limits);
168
169
  Error extract_alpha_from_RGBA(const std::shared_ptr<const HeifPixelImage>& srcimage, const heif_security_limits* limits);
170
171
  void fill_plane(heif_channel dst_channel, uint16_t value);
172
173
  Error fill_new_plane(heif_channel dst_channel, uint16_t value, int width, int height, int bpp, const heif_security_limits* limits);
174
175
  void transfer_plane_from_image_as(const std::shared_ptr<HeifPixelImage>& source,
176
                                    heif_channel src_channel,
177
                                    heif_channel dst_channel);
178
179
  Error copy_image_to(const std::shared_ptr<const HeifPixelImage>& source, uint32_t x0, uint32_t y0);
180
181
  Result<std::shared_ptr<HeifPixelImage>> rotate_ccw(int angle_degrees, const heif_security_limits* limits);
182
183
  Result<std::shared_ptr<HeifPixelImage>> mirror_inplace(heif_transform_mirror_direction, const heif_security_limits* limits);
184
185
  Result<std::shared_ptr<HeifPixelImage>> crop(uint32_t left, uint32_t right, uint32_t top, uint32_t bottom,
186
                                               const heif_security_limits* limits) const;
187
188
  Error fill_RGB_16bit(uint16_t r, uint16_t g, uint16_t b, uint16_t a);
189
190
  Error overlay(std::shared_ptr<HeifPixelImage>& overlay, int32_t dx, int32_t dy);
191
192
  Error scale_nearest_neighbor(std::shared_ptr<HeifPixelImage>& output, uint32_t width, uint32_t height,
193
                               const heif_security_limits* limits) const;
194
195
4.61k
  void set_color_profile_nclx(const std::shared_ptr<const color_profile_nclx>& profile) { m_color_profile_nclx = profile; }
196
197
3.59k
  const std::shared_ptr<const color_profile_nclx>& get_color_profile_nclx() const { return m_color_profile_nclx; }
198
199
3.39k
  void set_color_profile_icc(const std::shared_ptr<const color_profile_raw>& profile) { m_color_profile_icc = profile; }
200
201
3.39k
  const std::shared_ptr<const color_profile_raw>& get_color_profile_icc() const { return m_color_profile_icc; }
202
203
  void forward_all_metadata_from(const std::shared_ptr<const HeifPixelImage>& src_image);
204
205
  void debug_dump() const;
206
207
  Error extend_padding_to_size(uint32_t width, uint32_t height, bool adjust_size,
208
                               const heif_security_limits* limits);
209
210
  Error extend_to_size_with_zero(uint32_t width, uint32_t height, const heif_security_limits* limits);
211
212
  Result<std::shared_ptr<HeifPixelImage>> extract_image_area(uint32_t x0, uint32_t y0, uint32_t w, uint32_t h,
213
                                                             const heif_security_limits* limits) const;
214
215
216
  // --- pixel aspect ratio
217
218
3.39k
  bool has_nonsquare_pixel_ratio() const { return m_PixelAspectRatio_h != m_PixelAspectRatio_v; }
219
220
  void get_pixel_ratio(uint32_t* h, uint32_t* v) const
221
0
  {
222
0
    *h = m_PixelAspectRatio_h;
223
0
    *v = m_PixelAspectRatio_v;
224
0
  }
225
226
  void set_pixel_ratio(uint32_t h, uint32_t v)
227
0
  {
228
0
    m_PixelAspectRatio_h = h;
229
0
    m_PixelAspectRatio_v = v;
230
0
  }
231
232
  // --- clli
233
234
3.39k
  bool has_clli() const { return m_clli.max_content_light_level != 0 || m_clli.max_pic_average_light_level != 0; }
235
236
0
  heif_content_light_level get_clli() const { return m_clli; }
237
238
0
  void set_clli(const heif_content_light_level& clli) { m_clli = clli; }
239
240
  // --- mdcv
241
242
3.39k
  bool has_mdcv() const { return m_mdcv.has_value(); }
243
244
0
  heif_mastering_display_colour_volume get_mdcv() const { return *m_mdcv; }
245
246
  void set_mdcv(const heif_mastering_display_colour_volume& mdcv)
247
0
  {
248
0
    m_mdcv = mdcv;
249
0
  }
250
251
0
  void unset_mdcv() { m_mdcv.reset(); }
252
253
0
  Error set_tai_timestamp(const heif_tai_timestamp_packet* tai) {
254
0
    delete m_tai_timestamp;
255
256
0
    m_tai_timestamp = heif_tai_timestamp_packet_alloc();
257
0
    heif_tai_timestamp_packet_copy(m_tai_timestamp, tai);
258
0
    return Error::Ok;
259
0
  }
260
261
3.39k
  const heif_tai_timestamp_packet* get_tai_timestamp() const {
262
3.39k
    return m_tai_timestamp;
263
3.39k
  }
264
265
266
0
  void set_gimi_sample_content_id(std::string id) { m_gimi_sample_content_id = id; }
267
268
0
  bool has_gimi_sample_content_id() const { return m_gimi_sample_content_id.has_value(); }
269
270
0
  std::string get_gimi_sample_content_id() const { assert(has_gimi_sample_content_id()); return *m_gimi_sample_content_id; }
271
272
273
  // --- sequences
274
275
3.39k
  void set_sample_duration(uint32_t d) { m_sample_duration = d; }
276
277
3.39k
  uint32_t get_sample_duration() const { return m_sample_duration; }
278
279
  // --- warnings
280
281
100
  void add_warning(Error warning) { m_warnings.emplace_back(std::move(warning)); }
282
283
1.25k
  void add_warnings(const std::vector<Error>& warning) { for (const auto& err : warning) m_warnings.emplace_back(err); }
284
285
3.39k
  const std::vector<Error>& get_warnings() const { return m_warnings; }
286
287
private:
288
  struct ImagePlane
289
  {
290
    // limits=nullptr disables the limits
291
    Error alloc(uint32_t width, uint32_t height, heif_channel_datatype datatype, int bit_depth,
292
                int num_interleaved_components,
293
                const heif_security_limits* limits,
294
                MemoryHandle& memory_handle);
295
296
    heif_channel_datatype m_datatype = heif_channel_datatype_unsigned_integer;
297
    uint8_t m_bit_depth = 0;
298
    uint8_t m_num_interleaved_components = 1;
299
300
    // the "visible" area of the plane
301
    uint32_t m_width = 0;
302
    uint32_t m_height = 0;
303
304
    // the allocated memory size
305
    uint32_t m_mem_width = 0;
306
    uint32_t m_mem_height = 0;
307
308
    void* mem = nullptr; // aligned memory start
309
    uint8_t* allocated_mem = nullptr; // unaligned memory we allocated
310
    size_t   allocation_size = 0;
311
    uint32_t stride = 0; // bytes per line
312
313
    int get_bytes_per_pixel() const;
314
315
    template <typename T> void mirror_inplace(heif_transform_mirror_direction);
316
317
    template<typename T>
318
    void rotate_ccw(int angle_degrees, ImagePlane& out_plane) const;
319
320
    void crop(uint32_t left, uint32_t right, uint32_t top, uint32_t bottom, int bytes_per_pixel, ImagePlane& out_plane) const;
321
  };
322
323
  uint32_t m_width = 0;
324
  uint32_t m_height = 0;
325
  heif_colorspace m_colorspace = heif_colorspace_undefined;
326
  heif_chroma m_chroma = heif_chroma_undefined;
327
  bool m_premultiplied_alpha = false;
328
  std::shared_ptr<const color_profile_nclx> m_color_profile_nclx;
329
  std::shared_ptr<const color_profile_raw> m_color_profile_icc;
330
331
  std::map<heif_channel, ImagePlane> m_planes;
332
  MemoryHandle m_memory_handle;
333
334
  uint32_t m_PixelAspectRatio_h = 1;
335
  uint32_t m_PixelAspectRatio_v = 1;
336
  heif_content_light_level m_clli{};
337
  std::optional<heif_mastering_display_colour_volume> m_mdcv;
338
339
  uint32_t m_sample_duration = 0; // duration of a sequence frame
340
341
  heif_tai_timestamp_packet* m_tai_timestamp = nullptr;
342
343
  std::optional<std::string> m_gimi_sample_content_id;
344
345
  std::vector<Error> m_warnings;
346
};
347
348
#endif