/src/libheif/libheif/image-items/image_item.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * HEIF image base codec. |
3 | | * Copyright (c) 2024 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 | | #ifndef LIBHEIF_IMAGEITEM_H |
22 | | #define LIBHEIF_IMAGEITEM_H |
23 | | |
24 | | #include "api/libheif/heif.h" |
25 | | #include "error.h" |
26 | | #include "nclx.h" |
27 | | #include <string> |
28 | | #include <vector> |
29 | | #include <memory> |
30 | | #include <utility> |
31 | | #include <set> |
32 | | #include "api/libheif/heif_plugin.h" |
33 | | #include "codecs/encoder.h" |
34 | | |
35 | | |
36 | | class HeifContext; |
37 | | |
38 | | class HeifPixelImage; |
39 | | |
40 | | |
41 | | class ImageMetadata |
42 | | { |
43 | | public: |
44 | | heif_item_id item_id; |
45 | | std::string item_type; // e.g. "Exif" |
46 | | std::string content_type; |
47 | | std::string item_uri_type; |
48 | | std::vector<uint8_t> m_data; |
49 | | }; |
50 | | |
51 | | |
52 | | class ImageItem : public ErrorBuffer |
53 | | { |
54 | | public: |
55 | | ImageItem(HeifContext* ctx); |
56 | | |
57 | | ImageItem(HeifContext* ctx, heif_item_id id); |
58 | | |
59 | 0 | virtual ~ImageItem() = default; |
60 | | |
61 | | static std::shared_ptr<ImageItem> alloc_for_infe_box(HeifContext*, const std::shared_ptr<Box_infe>&); |
62 | | |
63 | | static std::shared_ptr<ImageItem> alloc_for_compression_format(HeifContext*, heif_compression_format); |
64 | | |
65 | | static heif_compression_format compression_format_from_fourcc_infe_type(uint32_t type); |
66 | | |
67 | | static uint32_t compression_format_to_fourcc_infe_type(heif_compression_format); |
68 | | |
69 | 0 | virtual uint32_t get_infe_type() const { return 0; } |
70 | | |
71 | 0 | virtual const char* get_auxC_alpha_channel_type() const { return "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha"; } |
72 | | |
73 | 0 | virtual bool is_ispe_essential() const { return false; } |
74 | | |
75 | 0 | virtual Error get_item_error() const { return Error::Ok; } |
76 | | |
77 | 0 | virtual heif_compression_format get_compression_format() const { return heif_compression_undefined; } |
78 | | |
79 | 0 | virtual Result<std::vector<uint8_t>> read_bitstream_configuration_data() const { return std::vector<uint8_t>{}; } |
80 | | |
81 | | void clear() |
82 | 0 | { |
83 | 0 | m_thumbnails.clear(); |
84 | 0 | m_alpha_channel.reset(); |
85 | 0 | m_depth_channel.reset(); |
86 | 0 | m_aux_images.clear(); |
87 | 0 | } |
88 | | |
89 | 0 | HeifContext* get_context() { return m_heif_context; } |
90 | | |
91 | 0 | const HeifContext* get_context() const { return m_heif_context; } |
92 | | |
93 | | std::shared_ptr<class HeifFile> get_file() const; |
94 | | |
95 | 0 | void set_properties(std::vector<std::shared_ptr<Box>> properties) { |
96 | 0 | m_properties = std::move(properties); |
97 | 0 | } |
98 | | |
99 | | template<class BoxType> |
100 | | std::shared_ptr<BoxType> get_property() const |
101 | 0 | { |
102 | 0 | for (auto& property : m_properties) { |
103 | 0 | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { |
104 | 0 | return box; |
105 | 0 | } |
106 | 0 | } |
107 | | |
108 | 0 | return nullptr; |
109 | 0 | } Unexecuted instantiation: std::__1::shared_ptr<Box_pasp> ImageItem::get_property<Box_pasp>() const Unexecuted instantiation: std::__1::shared_ptr<Box_ispe> ImageItem::get_property<Box_ispe>() const Unexecuted instantiation: std::__1::shared_ptr<Box_clli> ImageItem::get_property<Box_clli>() const Unexecuted instantiation: std::__1::shared_ptr<Box_mdcv> ImageItem::get_property<Box_mdcv>() const Unexecuted instantiation: std::__1::shared_ptr<Box_itai> ImageItem::get_property<Box_itai>() const Unexecuted instantiation: std::__1::shared_ptr<Box_pixi> ImageItem::get_property<Box_pixi>() const Unexecuted instantiation: std::__1::shared_ptr<Box_tilC> ImageItem::get_property<Box_tilC>() const Unexecuted instantiation: std::__1::shared_ptr<Box_uncC> ImageItem::get_property<Box_uncC>() const Unexecuted instantiation: std::__1::shared_ptr<Box_cmpC> ImageItem::get_property<Box_cmpC>() const Unexecuted instantiation: std::__1::shared_ptr<Box_icef> ImageItem::get_property<Box_icef>() const Unexecuted instantiation: std::__1::shared_ptr<Box_cmpd> ImageItem::get_property<Box_cmpd>() const Unexecuted instantiation: std::__1::shared_ptr<Box_auxC> ImageItem::get_property<Box_auxC>() const Unexecuted instantiation: std::__1::shared_ptr<Box_taic> ImageItem::get_property<Box_taic>() const Unexecuted instantiation: std::__1::shared_ptr<Box_hvcC> ImageItem::get_property<Box_hvcC>() const Unexecuted instantiation: std::__1::shared_ptr<Box_av1C> ImageItem::get_property<Box_av1C>() const Unexecuted instantiation: std::__1::shared_ptr<Box_avcC> ImageItem::get_property<Box_avcC>() const Unexecuted instantiation: std::__1::shared_ptr<Box_j2kH> ImageItem::get_property<Box_j2kH>() const Unexecuted instantiation: std::__1::shared_ptr<Box_vvcC> ImageItem::get_property<Box_vvcC>() const Unexecuted instantiation: std::__1::shared_ptr<Box_jpgC> ImageItem::get_property<Box_jpgC>() const Unexecuted instantiation: std::__1::shared_ptr<Box_mskC> ImageItem::get_property<Box_mskC>() const |
110 | | |
111 | | heif_property_id add_property(std::shared_ptr<Box> property, bool essential); |
112 | | |
113 | | heif_property_id add_property_without_deduplication(std::shared_ptr<Box> property, bool essential); |
114 | | |
115 | | void set_resolution(uint32_t w, uint32_t h) |
116 | 0 | { |
117 | 0 | m_width = w; |
118 | 0 | m_height = h; |
119 | 0 | } |
120 | | |
121 | 0 | heif_item_id get_id() const { return m_id; } |
122 | | |
123 | 0 | void set_id(heif_item_id id) { m_id = id; } |
124 | | |
125 | 0 | void set_primary(bool flag = true) { m_is_primary = flag; } |
126 | | |
127 | 0 | bool is_primary() const { return m_is_primary; } |
128 | | |
129 | | // 32bit limitation from `ispe` |
130 | 0 | uint32_t get_width() const { return m_width; } |
131 | | |
132 | 0 | uint32_t get_height() const { return m_height; } |
133 | | |
134 | | bool has_ispe_resolution() const; |
135 | | |
136 | | uint32_t get_ispe_width() const; |
137 | | |
138 | | uint32_t get_ispe_height() const; |
139 | | |
140 | | // Default behavior: forward call to Decoder |
141 | | [[nodiscard]] virtual int get_luma_bits_per_pixel() const; |
142 | | |
143 | | // Default behavior: forward call to Decoder |
144 | | [[nodiscard]] virtual int get_chroma_bits_per_pixel() const; |
145 | | |
146 | | void set_size(uint32_t w, uint32_t h) |
147 | 0 | { |
148 | 0 | m_width = w; |
149 | 0 | m_height = h; |
150 | 0 | } |
151 | | |
152 | | virtual void get_tile_size(uint32_t& w, uint32_t& h) const; |
153 | | |
154 | | virtual Error get_coded_image_colorspace(heif_colorspace* out_colorspace, heif_chroma* out_chroma) const; |
155 | | |
156 | | Error postprocess_coded_image_colorspace(heif_colorspace* inout_colorspace, heif_chroma* inout_chroma) const; |
157 | | |
158 | 0 | virtual void process_before_write() { } |
159 | | |
160 | | // -- thumbnails |
161 | | |
162 | | void set_is_thumbnail() |
163 | 0 | { |
164 | 0 | m_is_thumbnail = true; |
165 | 0 | } |
166 | | |
167 | 0 | void add_thumbnail(const std::shared_ptr<ImageItem>& img) { m_thumbnails.push_back(img); } |
168 | | |
169 | 0 | bool is_thumbnail() const { return m_is_thumbnail; } |
170 | | |
171 | 0 | const std::vector<std::shared_ptr<ImageItem>>& get_thumbnails() const { return m_thumbnails; } |
172 | | |
173 | | |
174 | | // --- alpha channel |
175 | | |
176 | | void set_is_alpha_channel() |
177 | 0 | { |
178 | 0 | m_is_alpha_channel = true; |
179 | 0 | } |
180 | | |
181 | 0 | void set_alpha_channel(std::shared_ptr<ImageItem> img) { m_alpha_channel = std::move(img); } |
182 | | |
183 | 0 | bool is_alpha_channel() const { return m_is_alpha_channel; } |
184 | | |
185 | 0 | const std::shared_ptr<ImageItem>& get_alpha_channel() const { return m_alpha_channel; } |
186 | | |
187 | 0 | void set_is_premultiplied_alpha(bool flag) { m_premultiplied_alpha = flag; } |
188 | | |
189 | 0 | bool is_premultiplied_alpha() const { return m_premultiplied_alpha; } |
190 | | |
191 | | // Whether the image has an alpha channel coded in the main image (not as an auxiliary image) |
192 | 0 | virtual bool has_coded_alpha_channel() const { return false; } |
193 | | |
194 | | // --- depth channel |
195 | | |
196 | | void set_is_depth_channel() |
197 | 0 | { |
198 | 0 | m_is_depth_channel = true; |
199 | 0 | } |
200 | | |
201 | 0 | void set_depth_channel(std::shared_ptr<ImageItem> img) { m_depth_channel = std::move(img); } |
202 | | |
203 | 0 | bool is_depth_channel() const { return m_is_depth_channel; } |
204 | | |
205 | 0 | const std::shared_ptr<ImageItem>& get_depth_channel() const { return m_depth_channel; } |
206 | | |
207 | | |
208 | | void set_depth_representation_info(struct heif_depth_representation_info& info) |
209 | 0 | { |
210 | 0 | m_has_depth_representation_info = true; |
211 | 0 | m_depth_representation_info = info; |
212 | 0 | } |
213 | | |
214 | | bool has_depth_representation_info() const |
215 | 0 | { |
216 | 0 | return m_has_depth_representation_info; |
217 | 0 | } |
218 | | |
219 | | const struct heif_depth_representation_info& get_depth_representation_info() const |
220 | 0 | { |
221 | 0 | return m_depth_representation_info; |
222 | 0 | } |
223 | | |
224 | | |
225 | | // --- generic aux image |
226 | | |
227 | | void set_is_aux_image(const std::string& aux_type) |
228 | 0 | { |
229 | 0 | m_is_aux_image = true; |
230 | 0 | m_aux_image_type = aux_type; |
231 | 0 | } |
232 | | |
233 | 0 | void add_aux_image(std::shared_ptr<ImageItem> img) { m_aux_images.push_back(std::move(img)); } |
234 | | |
235 | 0 | bool is_aux_image() const { return m_is_aux_image; } |
236 | | |
237 | 0 | const std::string& get_aux_type() const { return m_aux_image_type; } |
238 | | |
239 | | std::vector<std::shared_ptr<ImageItem>> get_aux_images(int aux_image_filter = 0) const |
240 | 0 | { |
241 | 0 | if (aux_image_filter == 0) { |
242 | 0 | return m_aux_images; |
243 | 0 | } |
244 | 0 | else { |
245 | 0 | std::vector<std::shared_ptr<ImageItem>> auxImgs; |
246 | 0 | for (const auto& aux : m_aux_images) { |
247 | 0 | if ((aux_image_filter & LIBHEIF_AUX_IMAGE_FILTER_OMIT_ALPHA) && aux->is_alpha_channel()) { |
248 | 0 | continue; |
249 | 0 | } |
250 | 0 |
|
251 | 0 | if ((aux_image_filter & LIBHEIF_AUX_IMAGE_FILTER_OMIT_DEPTH) && |
252 | 0 | aux->is_depth_channel()) { |
253 | 0 | continue; |
254 | 0 | } |
255 | 0 |
|
256 | 0 | auxImgs.push_back(aux); |
257 | 0 | } |
258 | 0 |
|
259 | 0 | return auxImgs; |
260 | 0 | } |
261 | 0 | } |
262 | | |
263 | | |
264 | | // --- metadata |
265 | | |
266 | | void add_metadata(std::shared_ptr<ImageMetadata> metadata) |
267 | 0 | { |
268 | 0 | m_metadata.push_back(std::move(metadata)); |
269 | 0 | } |
270 | | |
271 | 0 | const std::vector<std::shared_ptr<ImageMetadata>>& get_metadata() const { return m_metadata; } |
272 | | |
273 | | |
274 | | // --- miaf |
275 | | |
276 | | // TODO: we should have a function that checks all MIAF constraints and sets the compatibility flag. |
277 | 0 | void mark_not_miaf_compatible() { m_miaf_compatible = false; } |
278 | | |
279 | 0 | bool is_miaf_compatible() const { return m_miaf_compatible; } |
280 | | |
281 | | // return 0 if we don't know the brand |
282 | 0 | virtual heif_brand2 get_compatible_brand() const { return 0; } |
283 | | |
284 | | // === decoding === |
285 | | |
286 | 0 | virtual Error initialize_decoder() { return Error::Ok; } |
287 | | |
288 | 0 | virtual void set_decoder_input_data() { } |
289 | | |
290 | | Result<std::shared_ptr<HeifPixelImage>> decode_image(const struct heif_decoding_options& options, |
291 | | bool decode_tile_only, uint32_t tile_x0, uint32_t tile_y0) const; |
292 | | |
293 | | virtual Result<std::shared_ptr<HeifPixelImage>> decode_compressed_image(const struct heif_decoding_options& options, |
294 | | bool decode_tile_only, uint32_t tile_x0, uint32_t tile_y0) const; |
295 | | |
296 | | Result<std::vector<std::shared_ptr<Box>>> get_properties() const; |
297 | | |
298 | | bool has_essential_property_other_than(const std::set<uint32_t>&) const; |
299 | | |
300 | | // === encoding === |
301 | | |
302 | | Result<Encoder::CodedImageData> encode_to_bitstream_and_boxes(const std::shared_ptr<HeifPixelImage>& image, |
303 | | struct heif_encoder* encoder, |
304 | | const struct heif_encoding_options& options, |
305 | | enum heif_image_input_class input_class); |
306 | | |
307 | | Error encode_to_item(HeifContext* ctx, |
308 | | const std::shared_ptr<HeifPixelImage>& image, |
309 | | struct heif_encoder* encoder, |
310 | | const struct heif_encoding_options& options, |
311 | | enum heif_image_input_class input_class); |
312 | | |
313 | 0 | const std::shared_ptr<const color_profile_nclx>& get_color_profile_nclx() const { return m_color_profile_nclx; } |
314 | | |
315 | 0 | const std::shared_ptr<const color_profile_raw>& get_color_profile_icc() const { return m_color_profile_icc; } |
316 | | |
317 | | void set_color_profile(const std::shared_ptr<const color_profile>& profile) |
318 | 0 | { |
319 | 0 | auto icc = std::dynamic_pointer_cast<const color_profile_raw>(profile); |
320 | 0 | if (icc) { |
321 | 0 | m_color_profile_icc = std::move(icc); |
322 | 0 | } |
323 | |
|
324 | 0 | auto nclx = std::dynamic_pointer_cast<const color_profile_nclx>(profile); |
325 | 0 | if (nclx) { |
326 | 0 | m_color_profile_nclx = std::move(nclx); |
327 | 0 | } |
328 | 0 | }; |
329 | | |
330 | 0 | void set_intrinsic_matrix(const Box_cmin::RelativeIntrinsicMatrix& cmin) { |
331 | 0 | m_has_intrinsic_matrix = true; |
332 | 0 | m_intrinsic_matrix = cmin.to_absolute(get_ispe_width(), get_ispe_height()); |
333 | 0 | } |
334 | | |
335 | 0 | bool has_intrinsic_matrix() const { return m_has_intrinsic_matrix; } |
336 | | |
337 | 0 | Box_cmin::AbsoluteIntrinsicMatrix& get_intrinsic_matrix() { return m_intrinsic_matrix; } |
338 | | |
339 | 0 | const Box_cmin::AbsoluteIntrinsicMatrix& get_intrinsic_matrix() const { return m_intrinsic_matrix; } |
340 | | |
341 | | |
342 | 0 | void set_extrinsic_matrix(const Box_cmex::ExtrinsicMatrix& cmex) { |
343 | 0 | m_has_extrinsic_matrix = true; |
344 | 0 | m_extrinsic_matrix = cmex; |
345 | 0 | } |
346 | | |
347 | 0 | bool has_extrinsic_matrix() const { return m_has_extrinsic_matrix; } |
348 | | |
349 | 0 | Box_cmex::ExtrinsicMatrix& get_extrinsic_matrix() { return m_extrinsic_matrix; } |
350 | | |
351 | 0 | const Box_cmex::ExtrinsicMatrix& get_extrinsic_matrix() const { return m_extrinsic_matrix; } |
352 | | |
353 | | |
354 | 0 | void add_region_item_id(heif_item_id id) { m_region_item_ids.push_back(id); } |
355 | | |
356 | 0 | const std::vector<heif_item_id>& get_region_item_ids() const { return m_region_item_ids; } |
357 | | |
358 | | |
359 | 0 | void add_decoding_warning(Error err) { m_decoding_warnings.emplace_back(std::move(err)); } |
360 | | |
361 | 0 | const std::vector<Error>& get_decoding_warnings() const { return m_decoding_warnings; } |
362 | | |
363 | | virtual heif_image_tiling get_heif_image_tiling() const; |
364 | | |
365 | | Error process_image_transformations_on_tiling(heif_image_tiling&) const; |
366 | | |
367 | | Error transform_requested_tile_position_to_original_tile_position(uint32_t& tile_x, uint32_t& tile_y) const; |
368 | | |
369 | | virtual Result<std::shared_ptr<class Decoder>> get_decoder() const |
370 | 0 | { |
371 | 0 | return Error{ |
372 | 0 | heif_error_Unsupported_feature, |
373 | 0 | heif_suberror_No_matching_decoder_installed, |
374 | 0 | "No decoder for this image format" |
375 | 0 | }; |
376 | 0 | } |
377 | | |
378 | 0 | virtual std::shared_ptr<class Encoder> get_encoder() const { return nullptr; } |
379 | | |
380 | | private: |
381 | | HeifContext* m_heif_context; |
382 | | std::vector<std::shared_ptr<Box>> m_properties; |
383 | | |
384 | | heif_item_id m_id = 0; |
385 | | uint32_t m_width = 0, m_height = 0; // after all transformations have been applied |
386 | | bool m_is_primary = false; |
387 | | |
388 | | bool m_is_thumbnail = false; |
389 | | |
390 | | std::vector<std::shared_ptr<ImageItem>> m_thumbnails; |
391 | | |
392 | | bool m_is_alpha_channel = false; |
393 | | bool m_premultiplied_alpha = false; |
394 | | std::shared_ptr<ImageItem> m_alpha_channel; |
395 | | |
396 | | bool m_is_depth_channel = false; |
397 | | std::shared_ptr<ImageItem> m_depth_channel; |
398 | | |
399 | | bool m_has_depth_representation_info = false; |
400 | | struct heif_depth_representation_info m_depth_representation_info; |
401 | | |
402 | | bool m_is_aux_image = false; |
403 | | std::string m_aux_image_type; |
404 | | std::vector<std::shared_ptr<ImageItem>> m_aux_images; |
405 | | |
406 | | std::vector<std::shared_ptr<ImageMetadata>> m_metadata; |
407 | | |
408 | | std::shared_ptr<const color_profile_nclx> m_color_profile_nclx; |
409 | | std::shared_ptr<const color_profile_raw> m_color_profile_icc; |
410 | | |
411 | | bool m_miaf_compatible = true; |
412 | | |
413 | | std::vector<heif_item_id> m_region_item_ids; |
414 | | |
415 | | bool m_has_intrinsic_matrix = false; |
416 | | Box_cmin::AbsoluteIntrinsicMatrix m_intrinsic_matrix{}; |
417 | | |
418 | | bool m_has_extrinsic_matrix = false; |
419 | | Box_cmex::ExtrinsicMatrix m_extrinsic_matrix{}; |
420 | | |
421 | | std::vector<Error> m_decoding_warnings; |
422 | | |
423 | | protected: |
424 | | // Result<std::vector<uint8_t>> read_bitstream_configuration_data_override(heif_item_id itemId, heif_compression_format format) const; |
425 | | |
426 | | virtual Result<Encoder::CodedImageData> encode(const std::shared_ptr<HeifPixelImage>& image, |
427 | | struct heif_encoder* encoder, |
428 | | const struct heif_encoding_options& options, |
429 | | enum heif_image_input_class input_class); |
430 | | |
431 | | // --- encoding utility functions |
432 | | |
433 | | static void add_color_profile(const std::shared_ptr<HeifPixelImage>& image, |
434 | | const struct heif_encoding_options& options, |
435 | | enum heif_image_input_class input_class, |
436 | | const heif_color_profile_nclx* target_heif_nclx, |
437 | | Encoder::CodedImageData& inout_codedImage); |
438 | | }; |
439 | | |
440 | | |
441 | | class ImageItem_Error : public ImageItem |
442 | | { |
443 | | public: |
444 | | // dummy ImageItem class that is a placeholder for unsupported item types |
445 | | |
446 | | ImageItem_Error(uint32_t item_type, heif_item_id id, Error err) |
447 | 0 | : ImageItem(nullptr, id), m_item_type(item_type), m_item_error(err) {} |
448 | | |
449 | | uint32_t get_infe_type() const override |
450 | 0 | { |
451 | 0 | return m_item_type; |
452 | 0 | } |
453 | | |
454 | 0 | Error get_item_error() const override { return m_item_error; } |
455 | | |
456 | 0 | [[nodiscard]] int get_luma_bits_per_pixel() const override { return -1; } |
457 | | |
458 | 0 | [[nodiscard]] int get_chroma_bits_per_pixel() const override { return -1; } |
459 | | |
460 | | private: |
461 | | uint32_t m_item_type; |
462 | | Error m_item_error; |
463 | | }; |
464 | | |
465 | | #endif //LIBHEIF_IMAGEITEM_H |