/src/libheif/libheif/image-items/image_item.h
Line | Count | Source |
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 "security_limits.h" |
27 | | #include "nclx.h" |
28 | | #include <string> |
29 | | #include <utility> |
30 | | #include <vector> |
31 | | #include <memory> |
32 | | #include <mutex> |
33 | | #include <utility> |
34 | | #include <set> |
35 | | |
36 | | #include "image/pixelimage.h" |
37 | | #include "api/libheif/heif_plugin.h" |
38 | | #include "codecs/encoder.h" |
39 | | |
40 | | |
41 | | class HeifContext; |
42 | | |
43 | | class HeifPixelImage; |
44 | | |
45 | | |
46 | | class ImageMetadata |
47 | | { |
48 | | public: |
49 | | heif_item_id item_id; |
50 | | std::string item_type; // e.g. "Exif" |
51 | | std::string content_type; |
52 | | std::string item_uri_type; |
53 | | std::vector<uint8_t> m_data; |
54 | | |
55 | | // Accounts m_data against the context's total-memory budget for the lifetime of |
56 | | // this metadata object. Metadata items may be (brotli/zlib) compressed and are |
57 | | // held until the context is destroyed, so up to max_items of them accumulate. |
58 | | // Without persistent accounting this cumulative decompressed memory bypasses the |
59 | | // security limits (GHSA-24wx-9w62-c96w). MemoryHandle is move-only, which makes |
60 | | // ImageMetadata move-only; it is only ever held via shared_ptr, so that is fine. |
61 | | MemoryHandle m_memory_handle; |
62 | | }; |
63 | | |
64 | | |
65 | | class ImageItem : public ImageDescription, |
66 | | public ErrorBuffer |
67 | | { |
68 | | public: |
69 | | ImageItem(HeifContext* ctx); |
70 | | |
71 | | ImageItem(HeifContext* ctx, heif_item_id id); |
72 | | |
73 | | static std::shared_ptr<ImageItem> alloc_for_infe_box(HeifContext*, const std::shared_ptr<Box_infe>&); |
74 | | |
75 | | static std::shared_ptr<ImageItem> alloc_for_compression_format(HeifContext*, heif_compression_format); |
76 | | |
77 | | static heif_compression_format compression_format_from_fourcc_infe_type(uint32_t type); |
78 | | |
79 | | static uint32_t compression_format_to_fourcc_infe_type(heif_compression_format); |
80 | | |
81 | 0 | virtual uint32_t get_infe_type() const { return 0; } |
82 | | |
83 | 0 | virtual const char* get_auxC_alpha_channel_type() const { return "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha"; } |
84 | | |
85 | 0 | virtual bool is_ispe_essential() const { return false; } |
86 | | |
87 | | bool is_property_essential(const std::shared_ptr<Box>& property) const; |
88 | | |
89 | 316k | virtual Error get_item_error() const { return m_item_error; } |
90 | | |
91 | | // Mark this item as undecodable. The file still loads and other items remain |
92 | | // usable, but decoding this item (or listing it as a non-error image) will |
93 | | // surface this error. |
94 | 0 | void set_item_error(const Error& err) { m_item_error = err; } |
95 | | |
96 | 0 | virtual heif_compression_format get_compression_format() const { return heif_compression_undefined; } |
97 | | |
98 | 0 | virtual Result<std::vector<uint8_t>> read_bitstream_configuration_data() const { return std::vector<uint8_t>{}; } |
99 | | |
100 | | void clear() |
101 | 56.5k | { |
102 | 56.5k | m_thumbnails.clear(); |
103 | 56.5k | m_alpha_channel.reset(); |
104 | 56.5k | m_depth_channel.reset(); |
105 | 56.5k | m_aux_images.clear(); |
106 | 56.5k | } |
107 | | |
108 | 53.4k | HeifContext* get_context() { return m_heif_context; } |
109 | | |
110 | 106k | const HeifContext* get_context() const { return m_heif_context; } |
111 | | |
112 | | std::shared_ptr<class HeifFile> get_file() const; |
113 | | |
114 | 57.7k | void set_properties(std::vector<std::shared_ptr<Box>> properties) { |
115 | 57.7k | m_properties = std::move(properties); |
116 | | // Codec-config-independent populate (e.g. unci, which reads cmpd/uncC |
117 | | // directly off the just-set property boxes). Visual codecs leave |
118 | | // m_components empty here; their populate runs after initialize_decoder() |
119 | | // because they need codec config (colorspace, bit depth) which only the |
120 | | // decoder can read. |
121 | 57.7k | populate_component_descriptions(); |
122 | 57.7k | } |
123 | | |
124 | | // Populate the inherited ImageDescription::m_components from the just-set |
125 | | // property boxes / codec config. The unci subclass overrides this and |
126 | | // reads cmpd/uncC directly. The base implementation handles visual codecs |
127 | | // (HEVC/AVC/AVIF/JPEG/JPEG2000/VVC) by querying get_coded_image_colorspace() |
128 | | // + get_luma_bits_per_pixel() + get_chroma_bits_per_pixel() and emitting |
129 | | // Y/Cb/Cr or R/G/B / monochrome descriptions in canonical order. |
130 | | // Idempotent: skips work if m_components is already populated. |
131 | | // Alpha-from-aux (separate alpha item linked via auxl) is *not* emitted |
132 | | // here; the alpha plane is attached at decode time via |
133 | | // transfer_channel_from_image_as, which mints its own component on the |
134 | | // destination. |
135 | | virtual void populate_component_descriptions(); |
136 | | |
137 | | // Populate this item's m_components by cloning descriptions from a child |
138 | | // item (e.g. tili's tile item, grid/iden/iovl's first child) and rescaling |
139 | | // per-component dims from the child's logical size to this item's full |
140 | | // image (ispe) size. Returns true on success. Returns false (and leaves |
141 | | // m_components untouched) if the child has no descriptions or sizes are |
142 | | // unusable, so the caller can fall back to the base populate. |
143 | | bool populate_descriptions_from_child(const class ImageItem& child, |
144 | | uint32_t child_w, uint32_t child_h); |
145 | | |
146 | | template<class BoxType> |
147 | | std::shared_ptr<BoxType> get_property() const |
148 | 812k | { |
149 | 2.04M | for (auto& property : m_properties) { |
150 | 2.04M | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { |
151 | 628k | return box; |
152 | 628k | } |
153 | 2.04M | } |
154 | | |
155 | 183k | return nullptr; |
156 | 812k | } std::__1::shared_ptr<Box_clli> ImageItem::get_property<Box_clli>() const Line | Count | Source | 148 | 3.45k | { | 149 | 15.0k | for (auto& property : m_properties) { | 150 | 15.0k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 8 | return box; | 152 | 8 | } | 153 | 15.0k | } | 154 | | | 155 | 3.44k | return nullptr; | 156 | 3.45k | } |
std::__1::shared_ptr<Box_mdcv> ImageItem::get_property<Box_mdcv>() const Line | Count | Source | 148 | 3.45k | { | 149 | 15.0k | for (auto& property : m_properties) { | 150 | 15.0k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 1 | return box; | 152 | 1 | } | 153 | 15.0k | } | 154 | | | 155 | 3.45k | return nullptr; | 156 | 3.45k | } |
std::__1::shared_ptr<Box_amve> ImageItem::get_property<Box_amve>() const Line | Count | Source | 148 | 3.45k | { | 149 | 14.6k | for (auto& property : m_properties) { | 150 | 14.6k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 209 | return box; | 152 | 209 | } | 153 | 14.6k | } | 154 | | | 155 | 3.24k | return nullptr; | 156 | 3.45k | } |
std::__1::shared_ptr<Box_ndwt> ImageItem::get_property<Box_ndwt>() const Line | Count | Source | 148 | 3.45k | { | 149 | 14.9k | for (auto& property : m_properties) { | 150 | 14.9k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 16 | return box; | 152 | 16 | } | 153 | 14.9k | } | 154 | | | 155 | 3.44k | return nullptr; | 156 | 3.45k | } |
Unexecuted instantiation: std::__1::shared_ptr<Box_taic> ImageItem::get_property<Box_taic>() const std::__1::shared_ptr<Box_itai> ImageItem::get_property<Box_itai>() const Line | Count | Source | 148 | 3.45k | { | 149 | 15.0k | for (auto& property : m_properties) { | 150 | 15.0k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 0 | return box; | 152 | 0 | } | 153 | 15.0k | } | 154 | | | 155 | 3.45k | return nullptr; | 156 | 3.45k | } |
std::__1::shared_ptr<Box_cmpd> ImageItem::get_property<Box_cmpd>() const Line | Count | Source | 148 | 4.59k | { | 149 | 12.4k | for (auto& property : m_properties) { | 150 | 12.4k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 4.43k | return box; | 152 | 4.43k | } | 153 | 12.4k | } | 154 | | | 155 | 160 | return nullptr; | 156 | 4.59k | } |
std::__1::shared_ptr<Box_uncC> ImageItem::get_property<Box_uncC>() const Line | Count | Source | 148 | 15.3k | { | 149 | 57.9k | for (auto& property : m_properties) { | 150 | 57.9k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 15.3k | return box; | 152 | 15.3k | } | 153 | 57.9k | } | 154 | | | 155 | 16 | return nullptr; | 156 | 15.3k | } |
std::__1::shared_ptr<Box_pasp> ImageItem::get_property<Box_pasp>() const Line | Count | Source | 148 | 3.45k | { | 149 | 14.5k | for (auto& property : m_properties) { | 150 | 14.5k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 233 | return box; | 152 | 233 | } | 153 | 14.5k | } | 154 | | | 155 | 3.22k | return nullptr; | 156 | 3.45k | } |
Unexecuted instantiation: std::__1::shared_ptr<Box_gimi_component_content_ids> ImageItem::get_property<Box_gimi_component_content_ids>() const std::__1::shared_ptr<Box_ispe> ImageItem::get_property<Box_ispe>() const Line | Count | Source | 148 | 570k | { | 149 | 1.11M | for (auto& property : m_properties) { | 150 | 1.11M | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 544k | return box; | 152 | 544k | } | 153 | 1.11M | } | 154 | | | 155 | 26.1k | return nullptr; | 156 | 570k | } |
std::__1::shared_ptr<Box_gimi_content_id> ImageItem::get_property<Box_gimi_content_id>() const Line | Count | Source | 148 | 55.8k | { | 149 | 278k | for (auto& property : m_properties) { | 150 | 278k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 0 | return box; | 152 | 0 | } | 153 | 278k | } | 154 | | | 155 | 55.8k | return nullptr; | 156 | 55.8k | } |
std::__1::shared_ptr<Box_prfr> ImageItem::get_property<Box_prfr>() const Line | Count | Source | 148 | 55.8k | { | 149 | 278k | for (auto& property : m_properties) { | 150 | 278k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 5 | return box; | 152 | 5 | } | 153 | 278k | } | 154 | | | 155 | 55.8k | return nullptr; | 156 | 55.8k | } |
Unexecuted instantiation: std::__1::shared_ptr<Box_pixi> ImageItem::get_property<Box_pixi>() const std::__1::shared_ptr<Box_tilC> ImageItem::get_property<Box_tilC>() const Line | Count | Source | 148 | 10 | { | 149 | 10 | for (auto& property : m_properties) { | 150 | 10 | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 0 | return box; | 152 | 0 | } | 153 | 10 | } | 154 | | | 155 | 10 | return nullptr; | 156 | 10 | } |
std::__1::shared_ptr<Box_cpat> ImageItem::get_property<Box_cpat>() const Line | Count | Source | 148 | 3.49k | { | 149 | 13.7k | for (auto& property : m_properties) { | 150 | 13.7k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 0 | return box; | 152 | 0 | } | 153 | 13.7k | } | 154 | | | 155 | 3.49k | return nullptr; | 156 | 3.49k | } |
std::__1::shared_ptr<Box_cmpC> ImageItem::get_property<Box_cmpC>() const Line | Count | Source | 148 | 9.08k | { | 149 | 35.5k | for (auto& property : m_properties) { | 150 | 35.5k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 223 | return box; | 152 | 223 | } | 153 | 35.5k | } | 154 | | | 155 | 8.86k | return nullptr; | 156 | 9.08k | } |
std::__1::shared_ptr<Box_icef> ImageItem::get_property<Box_icef>() const Line | Count | Source | 148 | 9.08k | { | 149 | 35.7k | for (auto& property : m_properties) { | 150 | 35.7k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 0 | return box; | 152 | 0 | } | 153 | 35.7k | } | 154 | | | 155 | 9.08k | return nullptr; | 156 | 9.08k | } |
std::__1::shared_ptr<Box_cloc> ImageItem::get_property<Box_cloc>() const Line | Count | Source | 148 | 2.46k | { | 149 | 9.68k | for (auto& property : m_properties) { | 150 | 9.68k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 0 | return box; | 152 | 0 | } | 153 | 9.68k | } | 154 | | | 155 | 2.46k | return nullptr; | 156 | 2.46k | } |
std::__1::shared_ptr<Box_auxC> ImageItem::get_property<Box_auxC>() const Line | Count | Source | 148 | 12.8k | { | 149 | 38.6k | for (auto& property : m_properties) { | 150 | 38.6k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 12.8k | return box; | 152 | 12.8k | } | 153 | 38.6k | } | 154 | | | 155 | 18 | return nullptr; | 156 | 12.8k | } |
std::__1::shared_ptr<Box_hvcC> ImageItem::get_property<Box_hvcC>() const Line | Count | Source | 148 | 17.7k | { | 149 | 40.7k | for (auto& property : m_properties) { | 150 | 40.7k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 17.1k | return box; | 152 | 17.1k | } | 153 | 40.7k | } | 154 | | | 155 | 615 | return nullptr; | 156 | 17.7k | } |
std::__1::shared_ptr<Box_av1C> ImageItem::get_property<Box_av1C>() const Line | Count | Source | 148 | 33.4k | { | 149 | 35.5k | for (auto& property : m_properties) { | 150 | 35.5k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 33.0k | return box; | 152 | 33.0k | } | 153 | 35.5k | } | 154 | | | 155 | 377 | return nullptr; | 156 | 33.4k | } |
std::__1::shared_ptr<Box_avcC> ImageItem::get_property<Box_avcC>() const Line | Count | Source | 148 | 481 | { | 149 | 491 | for (auto& property : m_properties) { | 150 | 491 | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 473 | return box; | 152 | 473 | } | 153 | 491 | } | 154 | | | 155 | 8 | return nullptr; | 156 | 481 | } |
Unexecuted instantiation: std::__1::shared_ptr<Box_j2kH> ImageItem::get_property<Box_j2kH>() const std::__1::shared_ptr<Box_vvcC> ImageItem::get_property<Box_vvcC>() const Line | Count | Source | 148 | 228 | { | 149 | 255 | for (auto& property : m_properties) { | 150 | 255 | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 213 | return box; | 152 | 213 | } | 153 | 255 | } | 154 | | | 155 | 15 | return nullptr; | 156 | 228 | } |
std::__1::shared_ptr<Box_jpgC> ImageItem::get_property<Box_jpgC>() const Line | Count | Source | 148 | 378 | { | 149 | 1.11k | for (auto& property : m_properties) { | 150 | 1.11k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 0 | return box; | 152 | 0 | } | 153 | 1.11k | } | 154 | | | 155 | 378 | return nullptr; | 156 | 378 | } |
std::__1::shared_ptr<Box_mskC> ImageItem::get_property<Box_mskC>() const Line | Count | Source | 148 | 3 | { | 149 | 4 | for (auto& property : m_properties) { | 150 | 4 | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 0 | return box; | 152 | 0 | } | 153 | 4 | } | 154 | | | 155 | 3 | return nullptr; | 156 | 3 | } |
|
157 | | |
158 | | template<class BoxType> |
159 | | std::vector<std::shared_ptr<const BoxType>> get_all_properties() const |
160 | 7.38k | { |
161 | 7.38k | std::vector<std::shared_ptr<const BoxType>> result; |
162 | 29.0k | for (auto& property : m_properties) { |
163 | 29.0k | if (auto box = std::dynamic_pointer_cast<const BoxType>(property)) { |
164 | 0 | result.push_back(box); |
165 | 0 | } |
166 | 29.0k | } |
167 | 7.38k | return result; |
168 | 7.38k | } std::__1::vector<std::__1::shared_ptr<Box_splz const>, std::__1::allocator<std::__1::shared_ptr<Box_splz const> > > ImageItem::get_all_properties<Box_splz>() const Line | Count | Source | 160 | 2.46k | { | 161 | 2.46k | std::vector<std::shared_ptr<const BoxType>> result; | 162 | 9.68k | for (auto& property : m_properties) { | 163 | 9.68k | if (auto box = std::dynamic_pointer_cast<const BoxType>(property)) { | 164 | 0 | result.push_back(box); | 165 | 0 | } | 166 | 9.68k | } | 167 | 2.46k | return result; | 168 | 2.46k | } |
std::__1::vector<std::__1::shared_ptr<Box_sbpm const>, std::__1::allocator<std::__1::shared_ptr<Box_sbpm const> > > ImageItem::get_all_properties<Box_sbpm>() const Line | Count | Source | 160 | 2.46k | { | 161 | 2.46k | std::vector<std::shared_ptr<const BoxType>> result; | 162 | 9.68k | for (auto& property : m_properties) { | 163 | 9.68k | if (auto box = std::dynamic_pointer_cast<const BoxType>(property)) { | 164 | 0 | result.push_back(box); | 165 | 0 | } | 166 | 9.68k | } | 167 | 2.46k | return result; | 168 | 2.46k | } |
std::__1::vector<std::__1::shared_ptr<Box_snuc const>, std::__1::allocator<std::__1::shared_ptr<Box_snuc const> > > ImageItem::get_all_properties<Box_snuc>() const Line | Count | Source | 160 | 2.46k | { | 161 | 2.46k | std::vector<std::shared_ptr<const BoxType>> result; | 162 | 9.68k | for (auto& property : m_properties) { | 163 | 9.68k | if (auto box = std::dynamic_pointer_cast<const BoxType>(property)) { | 164 | 0 | result.push_back(box); | 165 | 0 | } | 166 | 9.68k | } | 167 | 2.46k | return result; | 168 | 2.46k | } |
|
169 | | |
170 | | heif_property_id add_property(const std::shared_ptr<Box>& property, bool essential); |
171 | | |
172 | | heif_property_id add_property_without_deduplication(const std::shared_ptr<Box>& property, bool essential); |
173 | | |
174 | | void set_resolution(uint32_t w, uint32_t h) |
175 | 50.7k | { |
176 | 50.7k | m_width = w; |
177 | 50.7k | m_height = h; |
178 | 50.7k | } |
179 | | |
180 | 617k | heif_item_id get_id() const { return m_id; } |
181 | | |
182 | 0 | void set_id(heif_item_id id) { m_id = id; } |
183 | | |
184 | 28.9k | void set_primary(bool flag = true) { m_is_primary = flag; } |
185 | | |
186 | 0 | bool is_primary() const { return m_is_primary; } |
187 | | |
188 | | // 32bit limitation from `ispe` |
189 | 7.48k | uint32_t get_width() const { return m_width; } |
190 | | |
191 | 7.48k | uint32_t get_height() const { return m_height; } |
192 | | |
193 | | bool has_ispe_resolution() const; |
194 | | |
195 | | uint32_t get_ispe_width() const; |
196 | | |
197 | | uint32_t get_ispe_height() const; |
198 | | |
199 | | // Default behavior: forward call to Decoder |
200 | | [[nodiscard]] virtual int get_luma_bits_per_pixel() const; |
201 | | |
202 | | // Default behavior: forward call to Decoder |
203 | | [[nodiscard]] virtual int get_chroma_bits_per_pixel() const; |
204 | | |
205 | | void set_size(uint32_t w, uint32_t h) |
206 | 0 | { |
207 | 0 | m_width = w; |
208 | 0 | m_height = h; |
209 | 0 | } |
210 | | |
211 | | virtual void get_tile_size(uint32_t& w, uint32_t& h) const; |
212 | | |
213 | | virtual Error get_coded_image_colorspace(heif_colorspace* out_colorspace, heif_chroma* out_chroma) const; |
214 | | |
215 | | Error postprocess_coded_image_colorspace(heif_colorspace* inout_colorspace, heif_chroma* inout_chroma) const; |
216 | | |
217 | 0 | virtual Error process_before_write() { return {}; } |
218 | | |
219 | | // -- thumbnails |
220 | | |
221 | | void set_is_thumbnail() |
222 | 104 | { |
223 | 104 | m_is_thumbnail = true; |
224 | 104 | } |
225 | | |
226 | 100 | void add_thumbnail(const std::shared_ptr<ImageItem>& img) { m_thumbnails.push_back(img); } |
227 | | |
228 | 101 | bool is_thumbnail() const { return m_is_thumbnail; } |
229 | | |
230 | 0 | const std::vector<std::shared_ptr<ImageItem>>& get_thumbnails() const { return m_thumbnails; } |
231 | | |
232 | | |
233 | | // --- alpha channel |
234 | | |
235 | | void set_is_alpha_channel() |
236 | 12.4k | { |
237 | 12.4k | m_is_alpha_channel = true; |
238 | 12.4k | } |
239 | | |
240 | | // Attach an alpha aux ImageItem and append a corresponding Alpha |
241 | | // ComponentDescription to this item's m_components. Idempotent. |
242 | | void set_alpha_channel(std::shared_ptr<ImageItem> img); |
243 | | |
244 | 0 | bool is_alpha_channel() const { return m_is_alpha_channel; } |
245 | | |
246 | 153k | const std::shared_ptr<ImageItem>& get_alpha_channel() const { return m_alpha_channel; } |
247 | | |
248 | 49 | void set_is_premultiplied_alpha(bool flag) { m_premultiplied_alpha = flag; } |
249 | | |
250 | 307 | bool is_premultiplied_alpha() const { return m_premultiplied_alpha; } |
251 | | |
252 | | // Whether the image has an alpha channel coded in the main image (not as an auxiliary image) |
253 | 0 | virtual bool has_coded_alpha_channel() const { return false; } |
254 | | |
255 | | // --- depth channel |
256 | | |
257 | | void set_is_depth_channel() |
258 | 285 | { |
259 | 285 | m_is_depth_channel = true; |
260 | 285 | } |
261 | | |
262 | 288 | void set_depth_channel(std::shared_ptr<ImageItem> img) { m_depth_channel = std::move(img); } |
263 | | |
264 | 262 | bool is_depth_channel() const { return m_is_depth_channel; } |
265 | | |
266 | 29.3k | const std::shared_ptr<ImageItem>& get_depth_channel() const { return m_depth_channel; } |
267 | | |
268 | | |
269 | | void set_depth_representation_info(heif_depth_representation_info& info) |
270 | 0 | { |
271 | 0 | m_has_depth_representation_info = true; |
272 | 0 | m_depth_representation_info = info; |
273 | 0 | } |
274 | | |
275 | | bool has_depth_representation_info() const |
276 | 262 | { |
277 | 262 | return m_has_depth_representation_info; |
278 | 262 | } |
279 | | |
280 | | const heif_depth_representation_info& get_depth_representation_info() const |
281 | 0 | { |
282 | 0 | return m_depth_representation_info; |
283 | 0 | } |
284 | | |
285 | | |
286 | | // --- generic aux image |
287 | | |
288 | | void set_is_aux_image(const std::string& aux_type) |
289 | 12.8k | { |
290 | 12.8k | m_is_aux_image = true; |
291 | 12.8k | m_aux_image_type = aux_type; |
292 | 12.8k | } |
293 | | |
294 | 12.8k | void add_aux_image(std::shared_ptr<ImageItem> img) { m_aux_images.push_back(std::move(img)); } |
295 | | |
296 | 0 | bool is_aux_image() const { return m_is_aux_image; } |
297 | | |
298 | 12.6k | const std::string& get_aux_type() const { return m_aux_image_type; } |
299 | | |
300 | | std::vector<std::shared_ptr<ImageItem>> get_aux_images(int aux_image_filter = 0) const |
301 | 53.5k | { |
302 | 53.5k | if (aux_image_filter == 0) { |
303 | 53.5k | return m_aux_images; |
304 | 53.5k | } |
305 | 0 | else { |
306 | 0 | std::vector<std::shared_ptr<ImageItem>> auxImgs; |
307 | 0 | for (const auto& aux : m_aux_images) { |
308 | 0 | if ((aux_image_filter & LIBHEIF_AUX_IMAGE_FILTER_OMIT_ALPHA) && aux->is_alpha_channel()) { |
309 | 0 | continue; |
310 | 0 | } |
311 | | |
312 | 0 | if ((aux_image_filter & LIBHEIF_AUX_IMAGE_FILTER_OMIT_DEPTH) && |
313 | 0 | aux->is_depth_channel()) { |
314 | 0 | continue; |
315 | 0 | } |
316 | | |
317 | 0 | auxImgs.push_back(aux); |
318 | 0 | } |
319 | |
|
320 | 0 | return auxImgs; |
321 | 0 | } |
322 | 53.5k | } |
323 | | |
324 | | |
325 | | // --- metadata |
326 | | |
327 | | void add_metadata(std::shared_ptr<ImageMetadata> metadata) |
328 | 614 | { |
329 | 614 | m_metadata.push_back(std::move(metadata)); |
330 | 614 | } |
331 | | |
332 | 0 | const std::vector<std::shared_ptr<ImageMetadata>>& get_metadata() const { return m_metadata; } |
333 | | |
334 | | |
335 | | |
336 | | // --- ImageDescription |
337 | | |
338 | | void set_clli(const heif_content_light_level& clli) override; |
339 | | |
340 | | void set_mdcv(const heif_mastering_display_colour_volume& mdcv) override; |
341 | | |
342 | | void set_amve(const heif_ambient_viewing_environment& amve) override; |
343 | | |
344 | | void set_nominal_diffuse_white_luminance(uint32_t luminance) override; |
345 | | |
346 | | void set_pixel_ratio(uint32_t h, uint32_t v) override; |
347 | | |
348 | | void set_color_profile_nclx(const nclx_profile& profile) override; |
349 | | |
350 | | void set_color_profile_icc(const std::shared_ptr<const color_profile_raw>& profile) override; |
351 | | |
352 | | void set_omaf_image_projection(heif_omaf_image_projection image_projection) override; |
353 | | |
354 | | // --- miaf |
355 | | |
356 | | // TODO: we should have a function that checks all MIAF constraints and sets the compatibility flag. |
357 | 0 | void mark_not_miaf_compatible() { m_miaf_compatible = false; } |
358 | | |
359 | 0 | bool is_miaf_compatible() const { return m_miaf_compatible && is_coded_in_miaf_profile(); } |
360 | | |
361 | | // A MIAF image item has to conform to a MIAF codec profile (ISO/IEC 23000-22, 6.3). |
362 | | // Whether the coded data of this image does. An image that is derived from other |
363 | | // images answers for them. |
364 | 0 | virtual bool is_coded_in_miaf_profile() const { return true; } |
365 | | |
366 | | // return 0 if we don't know the brand |
367 | 0 | virtual heif_brand2 get_compatible_brand() const { return 0; } |
368 | | |
369 | | // === decoding === |
370 | | |
371 | 2.72k | virtual Error initialize_decoder() { return Error::Ok; } |
372 | | |
373 | 3.05k | virtual void set_decoder_input_data() { } |
374 | | |
375 | | // With 'decode_tile_only', the tile position refers to get_image_tiling_with_alpha(). |
376 | | // 'decode_as_single_tile' is used for the alpha image of an image that is exposed as |
377 | | // a single tile: the whole image is decoded, but processed like a tile (not cropped). |
378 | | virtual Result<std::shared_ptr<HeifPixelImage>> decode_image(const heif_decoding_options& options, |
379 | | bool decode_tile_only, uint32_t tile_x0, |
380 | | uint32_t tile_y0, |
381 | | DecodeTraversalState decode_state, |
382 | | bool decode_as_single_tile = false) const; |
383 | | |
384 | | // Validate, before any decoding starts, that this item can be safely decoded: |
385 | | // the graph of items reached by the decode recursion (derived-image 'dimg' |
386 | | // inputs and the alpha 'auxl' auxiliary) must be acyclic. A reference cycle |
387 | | // would otherwise let two parallel grid-tile workers take two item mutexes in |
388 | | // opposite order and deadlock (GHSA-prgh-72vc-3xmc). Cycles are not rejected |
389 | | // at file load, so that a file's independently valid items stay decodable; |
390 | | // this per-item decode-time check is what makes a cyclic item safe. Called |
391 | | // once per top-level decode in HeifContext::decode_image(). This is the single |
392 | | // place to add further |
393 | | // decodability constraints (e.g. no alpha auxiliary on an alpha image, MIAF |
394 | | // derivation-chain limits). |
395 | | Error verify_decodable() const; |
396 | | |
397 | | virtual Result<std::shared_ptr<HeifPixelImage>> decode_compressed_image(const heif_decoding_options& options, |
398 | | bool decode_tile_only, uint32_t tile_x0, |
399 | | uint32_t tile_y0, |
400 | | DecodeTraversalState decode_state) const; |
401 | | |
402 | | // Validate the just-decoded pixel image against the size signaled for this item. |
403 | | // Called by decode_image() right after decode_compressed_image(), BEFORE transforms, |
404 | | // so the reference is the pre-transform coded size (ispe), or the signaled tile size |
405 | | // for a tile decode -- NOT get_width()/get_height() (which are post-transform). |
406 | | // Default impl handles plain coded codecs (HEVC/AVC/VVC/AVIF/JPEG). Subclasses |
407 | | // override where the size source or component layout differs. |
408 | | virtual Error check_decoded_image_size(const HeifPixelImage& img, |
409 | | bool decode_tile_only, |
410 | | uint32_t tile_x0, uint32_t tile_y0) const; |
411 | | |
412 | | // Checks that the decoded image has the bit depths that the image handle reports |
413 | | // (get_luma_bits_per_pixel() and get_chroma_bits_per_pixel()). |
414 | | Error check_decoded_image_bit_depth(const HeifPixelImage& img) const; |
415 | | |
416 | | Result<std::vector<std::shared_ptr<Box>>> get_properties() const; |
417 | | |
418 | | bool has_essential_property_other_than(const std::set<uint32_t>&) const; |
419 | | |
420 | | // === encoding === |
421 | | |
422 | | Result<Encoder::CodedImageData> encode_to_bitstream_and_boxes(const std::shared_ptr<HeifPixelImage>& image, |
423 | | heif_encoder* encoder, |
424 | | const heif_encoding_options& options, |
425 | | heif_image_input_class input_class); |
426 | | |
427 | | // Entry point for encoding pixel images. |
428 | | Error encode_to_item(HeifContext* ctx, |
429 | | const std::shared_ptr<HeifPixelImage>& image, |
430 | | heif_encoder* encoder, |
431 | | const heif_encoding_options& options, |
432 | | heif_image_input_class input_class); |
433 | | |
434 | 0 | void set_intrinsic_matrix(const Box_cmin::RelativeIntrinsicMatrix& cmin) { |
435 | 0 | m_has_intrinsic_matrix = true; |
436 | 0 | m_intrinsic_matrix = cmin.to_absolute(get_ispe_width(), get_ispe_height()); |
437 | 0 | } |
438 | | |
439 | 69 | bool has_intrinsic_matrix() const { return m_has_intrinsic_matrix; } |
440 | | |
441 | 3.83k | Box_cmin::AbsoluteIntrinsicMatrix& get_intrinsic_matrix() { return m_intrinsic_matrix; } |
442 | | |
443 | 0 | const Box_cmin::AbsoluteIntrinsicMatrix& get_intrinsic_matrix() const { return m_intrinsic_matrix; } |
444 | | |
445 | | |
446 | 43 | void set_extrinsic_matrix(const Box_cmex::ExtrinsicMatrix& cmex) { |
447 | 43 | m_has_extrinsic_matrix = true; |
448 | 43 | m_extrinsic_matrix = cmex; |
449 | 43 | } |
450 | | |
451 | 0 | bool has_extrinsic_matrix() const { return m_has_extrinsic_matrix; } |
452 | | |
453 | 0 | Box_cmex::ExtrinsicMatrix& get_extrinsic_matrix() { return m_extrinsic_matrix; } |
454 | | |
455 | 0 | const Box_cmex::ExtrinsicMatrix& get_extrinsic_matrix() const { return m_extrinsic_matrix; } |
456 | | |
457 | | |
458 | 2 | void add_region_item_id(heif_item_id id) { m_region_item_ids.push_back(id); } |
459 | | |
460 | 28.2k | const std::vector<heif_item_id>& get_region_item_ids() const { return m_region_item_ids; } |
461 | | |
462 | | |
463 | 5.30k | void add_decoding_warning(Error err) const { m_decoding_warnings.emplace_back(std::move(err)); } |
464 | | |
465 | 2.69k | const std::vector<Error>& get_decoding_warnings() const { return m_decoding_warnings; } |
466 | | |
467 | | // The tiling of this image item alone. |
468 | | virtual heif_image_tiling get_heif_image_tiling() const; |
469 | | |
470 | | // The tiling in which the image can be decoded. When a tile is decoded, the same tile |
471 | | // of the alpha image is decoded and attached to it. This requires that both images |
472 | | // have the same tiling. Otherwise, the image is exposed as a single tile. |
473 | | heif_image_tiling get_image_tiling_with_alpha() const; |
474 | | |
475 | | bool has_alpha_with_different_tiling() const; |
476 | | |
477 | | Error process_image_transformations_on_tiling(heif_image_tiling&) const; |
478 | | |
479 | | Error transform_requested_tile_position_to_original_tile_position(uint32_t& tile_x, uint32_t& tile_y) const; |
480 | | |
481 | | // The decoder of an image item is created when the item is read from a file |
482 | | // (initialize_decoder()). An item that was added by encoding an image has none. |
483 | | // This turns a missing decoder into an error, so that the functions that need the |
484 | | // decoder fail instead of dereferencing a null pointer. |
485 | | static Result<std::shared_ptr<class Decoder>> decoder_or_error(std::shared_ptr<class Decoder> decoder); |
486 | | |
487 | | virtual Result<std::shared_ptr<class Decoder>> get_decoder() const |
488 | 6.42k | { |
489 | 6.42k | return Error{ |
490 | 6.42k | heif_error_Unsupported_feature, |
491 | 6.42k | heif_suberror_No_matching_decoder_installed, |
492 | 6.42k | "No decoder for this image format" |
493 | 6.42k | }; |
494 | 6.42k | } |
495 | | |
496 | 0 | virtual std::shared_ptr<class Encoder> get_encoder() const { return nullptr; } |
497 | | |
498 | 12 | void add_text_item_id(heif_item_id id) { |
499 | 12 | m_text_item_ids.push_back(id); |
500 | 12 | } |
501 | | |
502 | 0 | const std::vector<heif_item_id>& get_text_item_ids() const { return m_text_item_ids; } |
503 | | |
504 | | private: |
505 | | HeifContext* m_heif_context; |
506 | | std::vector<std::shared_ptr<Box>> m_properties; |
507 | | |
508 | | Error m_item_error; // if set, this item cannot be decoded (e.g. unsupported required reference types) |
509 | | |
510 | | heif_item_id m_id = 0; |
511 | | uint32_t m_width = 0, m_height = 0; // after all transformations have been applied |
512 | | bool m_is_primary = false; |
513 | | |
514 | | bool m_is_thumbnail = false; |
515 | | |
516 | | std::vector<std::shared_ptr<ImageItem>> m_thumbnails; |
517 | | |
518 | | bool m_is_alpha_channel = false; |
519 | | bool m_premultiplied_alpha = false; |
520 | | std::shared_ptr<ImageItem> m_alpha_channel; |
521 | | |
522 | | bool m_is_depth_channel = false; |
523 | | std::shared_ptr<ImageItem> m_depth_channel; |
524 | | |
525 | | bool m_has_depth_representation_info = false; |
526 | | heif_depth_representation_info m_depth_representation_info; |
527 | | |
528 | | bool m_is_aux_image = false; |
529 | | std::string m_aux_image_type; |
530 | | std::vector<std::shared_ptr<ImageItem>> m_aux_images; |
531 | | |
532 | | std::vector<std::shared_ptr<ImageMetadata>> m_metadata; |
533 | | |
534 | | bool m_miaf_compatible = true; |
535 | | |
536 | | std::vector<heif_item_id> m_region_item_ids; |
537 | | |
538 | | bool m_has_intrinsic_matrix = false; |
539 | | Box_cmin::AbsoluteIntrinsicMatrix m_intrinsic_matrix{}; |
540 | | |
541 | | bool m_has_extrinsic_matrix = false; |
542 | | Box_cmex::ExtrinsicMatrix m_extrinsic_matrix{}; |
543 | | |
544 | | mutable std::vector<Error> m_decoding_warnings; |
545 | | |
546 | | mutable std::mutex m_decode_mutex; |
547 | | |
548 | | std::vector<heif_item_id> m_text_item_ids; |
549 | | |
550 | | void generate_property_boxes_for_ImageDescription(); |
551 | | |
552 | | protected: |
553 | | // Result<std::vector<uint8_t>> read_bitstream_configuration_data_override(heif_item_id itemId, heif_compression_format format) const; |
554 | | |
555 | | virtual Result<Encoder::CodedImageData> encode(const std::shared_ptr<HeifPixelImage>& image, |
556 | | heif_encoder* encoder, |
557 | | const heif_encoding_options& options, |
558 | | heif_image_input_class input_class); |
559 | | |
560 | | // --- encoding utility functions |
561 | | |
562 | | static std::vector<std::shared_ptr<Box_colr> > |
563 | | add_color_profile(const std::shared_ptr<HeifPixelImage>& image, |
564 | | const heif_encoding_options& options, |
565 | | heif_image_input_class input_class, |
566 | | const heif_color_profile_nclx* target_heif_nclx); |
567 | | }; |
568 | | |
569 | | |
570 | | class ImageItem_Error : public ImageItem |
571 | | { |
572 | | public: |
573 | | // dummy ImageItem class that is a placeholder for unsupported item types |
574 | | |
575 | | // Carry the real context, like every other ImageItem. Error items used to be |
576 | | // constructed with a null context, which made get_context()/get_file() a |
577 | | // null-deref hazard for any code that reaches an error item (e.g. an error |
578 | | // item attached as a depth/aux image, then handed to verify_decodable()). |
579 | | ImageItem_Error(HeifContext* context, uint32_t item_type, heif_item_id id, Error err) |
580 | 3.80k | : ImageItem(context, id), m_item_type(item_type), m_item_error(std::move(err)) {} |
581 | | |
582 | | uint32_t get_infe_type() const override |
583 | 142 | { |
584 | 142 | return m_item_type; |
585 | 142 | } |
586 | | |
587 | 19.2k | Error get_item_error() const override { return m_item_error; } |
588 | | |
589 | | Result<std::shared_ptr<HeifPixelImage>> decode_image(const heif_decoding_options& options, |
590 | | bool decode_tile_only, uint32_t tile_x0, |
591 | | uint32_t tile_y0, |
592 | | DecodeTraversalState decode_state, |
593 | | bool decode_as_single_tile) const override |
594 | 0 | { |
595 | 0 | return m_item_error; |
596 | 0 | } |
597 | | |
598 | | Result<std::shared_ptr<HeifPixelImage>> decode_compressed_image(const heif_decoding_options& options, |
599 | | bool decode_tile_only, uint32_t tile_x0, |
600 | | uint32_t tile_y0, DecodeTraversalState decode_state) const override |
601 | 0 | { |
602 | 0 | return m_item_error; |
603 | 0 | } |
604 | | |
605 | 53 | [[nodiscard]] int get_luma_bits_per_pixel() const override { return -1; } |
606 | | |
607 | 8 | [[nodiscard]] int get_chroma_bits_per_pixel() const override { return -1; } |
608 | | |
609 | | private: |
610 | | uint32_t m_item_type; |
611 | | Error m_item_error; |
612 | | }; |
613 | | |
614 | | #endif //LIBHEIF_IMAGEITEM_H |