/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 | 391k | 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 | 1 | 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 | 91.3k | { |
102 | 91.3k | m_thumbnails.clear(); |
103 | 91.3k | m_alpha_channel.reset(); |
104 | 91.3k | m_depth_channel.reset(); |
105 | 91.3k | m_aux_images.clear(); |
106 | 91.3k | } |
107 | | |
108 | 80.7k | HeifContext* get_context() { return m_heif_context; } |
109 | | |
110 | 179k | const HeifContext* get_context() const { return m_heif_context; } |
111 | | |
112 | | std::shared_ptr<class HeifFile> get_file() const; |
113 | | |
114 | 96.2k | void set_properties(std::vector<std::shared_ptr<Box>> properties) { |
115 | 96.2k | 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 | 96.2k | populate_component_descriptions(); |
122 | 96.2k | } |
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 | 840k | { |
149 | 2.46M | for (auto& property : m_properties) { |
150 | 2.46M | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { |
151 | 381k | return box; |
152 | 381k | } |
153 | 2.46M | } |
154 | | |
155 | 459k | return nullptr; |
156 | 840k | } std::__1::shared_ptr<Box_clli> ImageItem::get_property<Box_clli>() const Line | Count | Source | 148 | 22.0k | { | 149 | 84.6k | for (auto& property : m_properties) { | 150 | 84.6k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 1 | return box; | 152 | 1 | } | 153 | 84.6k | } | 154 | | | 155 | 22.0k | return nullptr; | 156 | 22.0k | } |
std::__1::shared_ptr<Box_mdcv> ImageItem::get_property<Box_mdcv>() const Line | Count | Source | 148 | 22.0k | { | 149 | 84.6k | for (auto& property : m_properties) { | 150 | 84.6k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 0 | return box; | 152 | 0 | } | 153 | 84.6k | } | 154 | | | 155 | 22.0k | return nullptr; | 156 | 22.0k | } |
std::__1::shared_ptr<Box_amve> ImageItem::get_property<Box_amve>() const Line | Count | Source | 148 | 22.0k | { | 149 | 84.6k | for (auto& property : m_properties) { | 150 | 84.6k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 3 | return box; | 152 | 3 | } | 153 | 84.6k | } | 154 | | | 155 | 22.0k | return nullptr; | 156 | 22.0k | } |
std::__1::shared_ptr<Box_ndwt> ImageItem::get_property<Box_ndwt>() const Line | Count | Source | 148 | 22.0k | { | 149 | 84.6k | for (auto& property : m_properties) { | 150 | 84.6k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 0 | return box; | 152 | 0 | } | 153 | 84.6k | } | 154 | | | 155 | 22.0k | return nullptr; | 156 | 22.0k | } |
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 | 22.0k | { | 149 | 84.6k | for (auto& property : m_properties) { | 150 | 84.6k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 0 | return box; | 152 | 0 | } | 153 | 84.6k | } | 154 | | | 155 | 22.0k | return nullptr; | 156 | 22.0k | } |
std::__1::shared_ptr<Box_cmpd> ImageItem::get_property<Box_cmpd>() const Line | Count | Source | 148 | 3.21k | { | 149 | 5.61k | for (auto& property : m_properties) { | 150 | 5.61k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 3.16k | return box; | 152 | 3.16k | } | 153 | 5.61k | } | 154 | | | 155 | 55 | return nullptr; | 156 | 3.21k | } |
std::__1::shared_ptr<Box_uncC> ImageItem::get_property<Box_uncC>() const Line | Count | Source | 148 | 3.26k | { | 149 | 8.37k | for (auto& property : m_properties) { | 150 | 8.37k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 3.16k | return box; | 152 | 3.16k | } | 153 | 8.37k | } | 154 | | | 155 | 102 | return nullptr; | 156 | 3.26k | } |
std::__1::shared_ptr<Box_pasp> ImageItem::get_property<Box_pasp>() const Line | Count | Source | 148 | 22.0k | { | 149 | 83.7k | for (auto& property : m_properties) { | 150 | 83.7k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 255 | return box; | 152 | 255 | } | 153 | 83.7k | } | 154 | | | 155 | 21.7k | return nullptr; | 156 | 22.0k | } |
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 | 415k | { | 149 | 957k | for (auto& property : m_properties) { | 150 | 957k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 299k | return box; | 152 | 299k | } | 153 | 957k | } | 154 | | | 155 | 115k | return nullptr; | 156 | 415k | } |
std::__1::shared_ptr<Box_gimi_content_id> ImageItem::get_property<Box_gimi_content_id>() const Line | Count | Source | 148 | 100k | { | 149 | 387k | for (auto& property : m_properties) { | 150 | 387k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 0 | return box; | 152 | 0 | } | 153 | 387k | } | 154 | | | 155 | 100k | return nullptr; | 156 | 100k | } |
std::__1::shared_ptr<Box_prfr> ImageItem::get_property<Box_prfr>() const Line | Count | Source | 148 | 100k | { | 149 | 387k | for (auto& property : m_properties) { | 150 | 387k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 0 | return box; | 152 | 0 | } | 153 | 387k | } | 154 | | | 155 | 100k | return nullptr; | 156 | 100k | } |
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 std::__1::shared_ptr<Box_cpat> ImageItem::get_property<Box_cpat>() const Line | Count | Source | 148 | 2.09k | { | 149 | 8.93k | for (auto& property : m_properties) { | 150 | 8.93k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 0 | return box; | 152 | 0 | } | 153 | 8.93k | } | 154 | | | 155 | 2.09k | return nullptr; | 156 | 2.09k | } |
std::__1::shared_ptr<Box_cmpC> ImageItem::get_property<Box_cmpC>() const Line | Count | Source | 148 | 1.03k | { | 149 | 4.02k | for (auto& property : m_properties) { | 150 | 4.02k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 724 | return box; | 152 | 724 | } | 153 | 4.02k | } | 154 | | | 155 | 309 | return nullptr; | 156 | 1.03k | } |
std::__1::shared_ptr<Box_icef> ImageItem::get_property<Box_icef>() const Line | Count | Source | 148 | 1.03k | { | 149 | 4.45k | for (auto& property : m_properties) { | 150 | 4.45k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 0 | return box; | 152 | 0 | } | 153 | 4.45k | } | 154 | | | 155 | 1.03k | return nullptr; | 156 | 1.03k | } |
std::__1::shared_ptr<Box_cloc> ImageItem::get_property<Box_cloc>() const Line | Count | Source | 148 | 1.03k | { | 149 | 4.45k | for (auto& property : m_properties) { | 150 | 4.45k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 0 | return box; | 152 | 0 | } | 153 | 4.45k | } | 154 | | | 155 | 1.03k | return nullptr; | 156 | 1.03k | } |
std::__1::shared_ptr<Box_auxC> ImageItem::get_property<Box_auxC>() const Line | Count | Source | 148 | 1.02k | { | 149 | 3.62k | for (auto& property : m_properties) { | 150 | 3.62k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 957 | return box; | 152 | 957 | } | 153 | 3.62k | } | 154 | | | 155 | 71 | return nullptr; | 156 | 1.02k | } |
std::__1::shared_ptr<Box_hvcC> ImageItem::get_property<Box_hvcC>() const Line | Count | Source | 148 | 30.3k | { | 149 | 50.2k | for (auto& property : m_properties) { | 150 | 50.2k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 28.4k | return box; | 152 | 28.4k | } | 153 | 50.2k | } | 154 | | | 155 | 1.87k | return nullptr; | 156 | 30.3k | } |
std::__1::shared_ptr<Box_av1C> ImageItem::get_property<Box_av1C>() const Line | Count | Source | 148 | 43.4k | { | 149 | 122k | for (auto& property : m_properties) { | 150 | 122k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 41.5k | return box; | 152 | 41.5k | } | 153 | 122k | } | 154 | | | 155 | 1.89k | return nullptr; | 156 | 43.4k | } |
std::__1::shared_ptr<Box_avcC> ImageItem::get_property<Box_avcC>() const Line | Count | Source | 148 | 1.30k | { | 149 | 1.40k | for (auto& property : m_properties) { | 150 | 1.40k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 1.26k | return box; | 152 | 1.26k | } | 153 | 1.40k | } | 154 | | | 155 | 48 | return nullptr; | 156 | 1.30k | } |
std::__1::shared_ptr<Box_j2kH> ImageItem::get_property<Box_j2kH>() const Line | Count | Source | 148 | 2.12k | { | 149 | 2.27k | for (auto& property : m_properties) { | 150 | 2.27k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 2.04k | return box; | 152 | 2.04k | } | 153 | 2.27k | } | 154 | | | 155 | 84 | return nullptr; | 156 | 2.12k | } |
std::__1::shared_ptr<Box_vvcC> ImageItem::get_property<Box_vvcC>() const Line | Count | Source | 148 | 64 | { | 149 | 141 | for (auto& property : m_properties) { | 150 | 141 | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 14 | return box; | 152 | 14 | } | 153 | 141 | } | 154 | | | 155 | 50 | return nullptr; | 156 | 64 | } |
std::__1::shared_ptr<Box_jpgC> ImageItem::get_property<Box_jpgC>() const Line | Count | Source | 148 | 2.85k | { | 149 | 7.38k | for (auto& property : m_properties) { | 150 | 7.38k | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 0 | return box; | 152 | 0 | } | 153 | 7.38k | } | 154 | | | 155 | 2.85k | return nullptr; | 156 | 2.85k | } |
std::__1::shared_ptr<Box_mskC> ImageItem::get_property<Box_mskC>() const Line | Count | Source | 148 | 9 | { | 149 | 70 | for (auto& property : m_properties) { | 150 | 70 | if (auto box = std::dynamic_pointer_cast<BoxType>(property)) { | 151 | 0 | return box; | 152 | 0 | } | 153 | 70 | } | 154 | | | 155 | 9 | return nullptr; | 156 | 9 | } |
|
157 | | |
158 | | template<class BoxType> |
159 | | std::vector<std::shared_ptr<const BoxType>> get_all_properties() const |
160 | 3.09k | { |
161 | 3.09k | std::vector<std::shared_ptr<const BoxType>> result; |
162 | 13.3k | for (auto& property : m_properties) { |
163 | 13.3k | if (auto box = std::dynamic_pointer_cast<const BoxType>(property)) { |
164 | 0 | result.push_back(box); |
165 | 0 | } |
166 | 13.3k | } |
167 | 3.09k | return result; |
168 | 3.09k | } 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 | 1.03k | { | 161 | 1.03k | std::vector<std::shared_ptr<const BoxType>> result; | 162 | 4.45k | for (auto& property : m_properties) { | 163 | 4.45k | if (auto box = std::dynamic_pointer_cast<const BoxType>(property)) { | 164 | 0 | result.push_back(box); | 165 | 0 | } | 166 | 4.45k | } | 167 | 1.03k | return result; | 168 | 1.03k | } |
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 | 1.03k | { | 161 | 1.03k | std::vector<std::shared_ptr<const BoxType>> result; | 162 | 4.45k | for (auto& property : m_properties) { | 163 | 4.45k | if (auto box = std::dynamic_pointer_cast<const BoxType>(property)) { | 164 | 0 | result.push_back(box); | 165 | 0 | } | 166 | 4.45k | } | 167 | 1.03k | return result; | 168 | 1.03k | } |
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 | 1.03k | { | 161 | 1.03k | std::vector<std::shared_ptr<const BoxType>> result; | 162 | 4.45k | for (auto& property : m_properties) { | 163 | 4.45k | if (auto box = std::dynamic_pointer_cast<const BoxType>(property)) { | 164 | 0 | result.push_back(box); | 165 | 0 | } | 166 | 4.45k | } | 167 | 1.03k | return result; | 168 | 1.03k | } |
|
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 | 62.6k | { |
176 | 62.6k | m_width = w; |
177 | 62.6k | m_height = h; |
178 | 62.6k | } |
179 | | |
180 | 682k | heif_item_id get_id() const { return m_id; } |
181 | | |
182 | 0 | void set_id(heif_item_id id) { m_id = id; } |
183 | | |
184 | 60.2k | 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 | 65.1k | uint32_t get_width() const { return m_width; } |
190 | | |
191 | 65.1k | 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 | 1.65k | { |
223 | 1.65k | m_is_thumbnail = true; |
224 | 1.65k | } |
225 | | |
226 | 1.62k | void add_thumbnail(const std::shared_ptr<ImageItem>& img) { m_thumbnails.push_back(img); } |
227 | | |
228 | 1.63k | 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 | 429 | { |
237 | 429 | m_is_alpha_channel = true; |
238 | 429 | } |
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 | 152k | const std::shared_ptr<ImageItem>& get_alpha_channel() const { return m_alpha_channel; } |
247 | | |
248 | 20 | void set_is_premultiplied_alpha(bool flag) { m_premultiplied_alpha = flag; } |
249 | | |
250 | 121 | 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 | 57.2k | virtual bool has_coded_alpha_channel() const { return false; } |
254 | | |
255 | | // --- depth channel |
256 | | |
257 | | void set_is_depth_channel() |
258 | 95 | { |
259 | 95 | m_is_depth_channel = true; |
260 | 95 | } |
261 | | |
262 | 47 | void set_depth_channel(std::shared_ptr<ImageItem> img) { m_depth_channel = std::move(img); } |
263 | | |
264 | 0 | bool is_depth_channel() const { return m_is_depth_channel; } |
265 | | |
266 | 0 | 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 | 0 | { |
277 | 0 | return m_has_depth_representation_info; |
278 | 0 | } |
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 | 874 | { |
290 | 874 | m_is_aux_image = true; |
291 | 874 | m_aux_image_type = aux_type; |
292 | 874 | } |
293 | | |
294 | 709 | 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 | 0 | 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 | 0 | { |
302 | 0 | if (aux_image_filter == 0) { |
303 | 0 | return m_aux_images; |
304 | 0 | } |
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 | 0 |
|
312 | 0 | if ((aux_image_filter & LIBHEIF_AUX_IMAGE_FILTER_OMIT_DEPTH) && |
313 | 0 | aux->is_depth_channel()) { |
314 | 0 | continue; |
315 | 0 | } |
316 | 0 |
|
317 | 0 | auxImgs.push_back(aux); |
318 | 0 | } |
319 | 0 |
|
320 | 0 | return auxImgs; |
321 | 0 | } |
322 | 0 | } |
323 | | |
324 | | |
325 | | // --- metadata |
326 | | |
327 | | void add_metadata(std::shared_ptr<ImageMetadata> metadata) |
328 | 7.12k | { |
329 | 7.12k | m_metadata.push_back(std::move(metadata)); |
330 | 7.12k | } |
331 | | |
332 | 82.6k | 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; } |
360 | | |
361 | | // return 0 if we don't know the brand |
362 | 0 | virtual heif_brand2 get_compatible_brand() const { return 0; } |
363 | | |
364 | | // === decoding === |
365 | | |
366 | 7.22k | virtual Error initialize_decoder() { return Error::Ok; } |
367 | | |
368 | 9.24k | virtual void set_decoder_input_data() { } |
369 | | |
370 | | virtual Result<std::shared_ptr<HeifPixelImage>> decode_image(const heif_decoding_options& options, |
371 | | bool decode_tile_only, uint32_t tile_x0, |
372 | | uint32_t tile_y0, |
373 | | DecodeTraversalState decode_state) const; |
374 | | |
375 | | // Validate, before any decoding starts, that this item can be safely decoded: |
376 | | // the graph of items reached by the decode recursion (derived-image 'dimg' |
377 | | // inputs and the alpha 'auxl' auxiliary) must be acyclic. A reference cycle |
378 | | // would otherwise let two parallel grid-tile workers take two item mutexes in |
379 | | // opposite order and deadlock (GHSA-prgh-72vc-3xmc). Cycles are not rejected |
380 | | // at file load, so that a file's independently valid items stay decodable; |
381 | | // this per-item decode-time check is what makes a cyclic item safe. Called |
382 | | // once per top-level decode in HeifContext::decode_image(). This is the single |
383 | | // place to add further |
384 | | // decodability constraints (e.g. no alpha auxiliary on an alpha image, MIAF |
385 | | // derivation-chain limits). |
386 | | Error verify_decodable() const; |
387 | | |
388 | | virtual Result<std::shared_ptr<HeifPixelImage>> decode_compressed_image(const heif_decoding_options& options, |
389 | | bool decode_tile_only, uint32_t tile_x0, |
390 | | uint32_t tile_y0, |
391 | | DecodeTraversalState decode_state) const; |
392 | | |
393 | | // Validate the just-decoded pixel image against the size signaled for this item. |
394 | | // Called by decode_image() right after decode_compressed_image(), BEFORE transforms, |
395 | | // so the reference is the pre-transform coded size (ispe), or the signaled tile size |
396 | | // for a tile decode -- NOT get_width()/get_height() (which are post-transform). |
397 | | // Default impl handles plain coded codecs (HEVC/AVC/VVC/AVIF/JPEG). Subclasses |
398 | | // override where the size source or component layout differs. |
399 | | virtual Error check_decoded_image_size(const HeifPixelImage& img, |
400 | | bool decode_tile_only, |
401 | | uint32_t tile_x0, uint32_t tile_y0) const; |
402 | | |
403 | | Result<std::vector<std::shared_ptr<Box>>> get_properties() const; |
404 | | |
405 | | bool has_essential_property_other_than(const std::set<uint32_t>&) const; |
406 | | |
407 | | // === encoding === |
408 | | |
409 | | Result<Encoder::CodedImageData> encode_to_bitstream_and_boxes(const std::shared_ptr<HeifPixelImage>& image, |
410 | | heif_encoder* encoder, |
411 | | const heif_encoding_options& options, |
412 | | heif_image_input_class input_class); |
413 | | |
414 | | // Entry point for encoding pixel images. |
415 | | Error encode_to_item(HeifContext* ctx, |
416 | | const std::shared_ptr<HeifPixelImage>& image, |
417 | | heif_encoder* encoder, |
418 | | const heif_encoding_options& options, |
419 | | heif_image_input_class input_class); |
420 | | |
421 | 0 | void set_intrinsic_matrix(const Box_cmin::RelativeIntrinsicMatrix& cmin) { |
422 | 0 | m_has_intrinsic_matrix = true; |
423 | 0 | m_intrinsic_matrix = cmin.to_absolute(get_ispe_width(), get_ispe_height()); |
424 | 0 | } |
425 | | |
426 | 2.02k | bool has_intrinsic_matrix() const { return m_has_intrinsic_matrix; } |
427 | | |
428 | 682 | Box_cmin::AbsoluteIntrinsicMatrix& get_intrinsic_matrix() { return m_intrinsic_matrix; } |
429 | | |
430 | 0 | const Box_cmin::AbsoluteIntrinsicMatrix& get_intrinsic_matrix() const { return m_intrinsic_matrix; } |
431 | | |
432 | | |
433 | 8 | void set_extrinsic_matrix(const Box_cmex::ExtrinsicMatrix& cmex) { |
434 | 8 | m_has_extrinsic_matrix = true; |
435 | 8 | m_extrinsic_matrix = cmex; |
436 | 8 | } |
437 | | |
438 | 0 | bool has_extrinsic_matrix() const { return m_has_extrinsic_matrix; } |
439 | | |
440 | 0 | Box_cmex::ExtrinsicMatrix& get_extrinsic_matrix() { return m_extrinsic_matrix; } |
441 | | |
442 | 0 | const Box_cmex::ExtrinsicMatrix& get_extrinsic_matrix() const { return m_extrinsic_matrix; } |
443 | | |
444 | | |
445 | 119 | void add_region_item_id(heif_item_id id) { m_region_item_ids.push_back(id); } |
446 | | |
447 | 0 | const std::vector<heif_item_id>& get_region_item_ids() const { return m_region_item_ids; } |
448 | | |
449 | | |
450 | 25.8k | void add_decoding_warning(Error err) const { m_decoding_warnings.emplace_back(std::move(err)); } |
451 | | |
452 | 19.5k | const std::vector<Error>& get_decoding_warnings() const { return m_decoding_warnings; } |
453 | | |
454 | | virtual heif_image_tiling get_heif_image_tiling() const; |
455 | | |
456 | | Error process_image_transformations_on_tiling(heif_image_tiling&) const; |
457 | | |
458 | | Error transform_requested_tile_position_to_original_tile_position(uint32_t& tile_x, uint32_t& tile_y) const; |
459 | | |
460 | | virtual Result<std::shared_ptr<class Decoder>> get_decoder() const |
461 | 19.2k | { |
462 | 19.2k | return Error{ |
463 | 19.2k | heif_error_Unsupported_feature, |
464 | 19.2k | heif_suberror_No_matching_decoder_installed, |
465 | 19.2k | "No decoder for this image format" |
466 | 19.2k | }; |
467 | 19.2k | } |
468 | | |
469 | 0 | virtual std::shared_ptr<class Encoder> get_encoder() const { return nullptr; } |
470 | | |
471 | 0 | void add_text_item_id(heif_item_id id) { |
472 | 0 | m_text_item_ids.push_back(id); |
473 | 0 | } |
474 | | |
475 | 0 | const std::vector<heif_item_id>& get_text_item_ids() const { return m_text_item_ids; } |
476 | | |
477 | | private: |
478 | | HeifContext* m_heif_context; |
479 | | std::vector<std::shared_ptr<Box>> m_properties; |
480 | | |
481 | | Error m_item_error; // if set, this item cannot be decoded (e.g. unsupported required reference types) |
482 | | |
483 | | heif_item_id m_id = 0; |
484 | | uint32_t m_width = 0, m_height = 0; // after all transformations have been applied |
485 | | bool m_is_primary = false; |
486 | | |
487 | | bool m_is_thumbnail = false; |
488 | | |
489 | | std::vector<std::shared_ptr<ImageItem>> m_thumbnails; |
490 | | |
491 | | bool m_is_alpha_channel = false; |
492 | | bool m_premultiplied_alpha = false; |
493 | | std::shared_ptr<ImageItem> m_alpha_channel; |
494 | | |
495 | | bool m_is_depth_channel = false; |
496 | | std::shared_ptr<ImageItem> m_depth_channel; |
497 | | |
498 | | bool m_has_depth_representation_info = false; |
499 | | heif_depth_representation_info m_depth_representation_info; |
500 | | |
501 | | bool m_is_aux_image = false; |
502 | | std::string m_aux_image_type; |
503 | | std::vector<std::shared_ptr<ImageItem>> m_aux_images; |
504 | | |
505 | | std::vector<std::shared_ptr<ImageMetadata>> m_metadata; |
506 | | |
507 | | bool m_miaf_compatible = true; |
508 | | |
509 | | std::vector<heif_item_id> m_region_item_ids; |
510 | | |
511 | | bool m_has_intrinsic_matrix = false; |
512 | | Box_cmin::AbsoluteIntrinsicMatrix m_intrinsic_matrix{}; |
513 | | |
514 | | bool m_has_extrinsic_matrix = false; |
515 | | Box_cmex::ExtrinsicMatrix m_extrinsic_matrix{}; |
516 | | |
517 | | mutable std::vector<Error> m_decoding_warnings; |
518 | | |
519 | | mutable std::mutex m_decode_mutex; |
520 | | |
521 | | std::vector<heif_item_id> m_text_item_ids; |
522 | | |
523 | | void generate_property_boxes_for_ImageDescription(); |
524 | | |
525 | | protected: |
526 | | // Result<std::vector<uint8_t>> read_bitstream_configuration_data_override(heif_item_id itemId, heif_compression_format format) const; |
527 | | |
528 | | virtual Result<Encoder::CodedImageData> encode(const std::shared_ptr<HeifPixelImage>& image, |
529 | | heif_encoder* encoder, |
530 | | const heif_encoding_options& options, |
531 | | heif_image_input_class input_class); |
532 | | |
533 | | // --- encoding utility functions |
534 | | |
535 | | static std::vector<std::shared_ptr<Box_colr> > |
536 | | add_color_profile(const std::shared_ptr<HeifPixelImage>& image, |
537 | | const heif_encoding_options& options, |
538 | | heif_image_input_class input_class, |
539 | | const heif_color_profile_nclx* target_heif_nclx); |
540 | | }; |
541 | | |
542 | | |
543 | | class ImageItem_Error : public ImageItem |
544 | | { |
545 | | public: |
546 | | // dummy ImageItem class that is a placeholder for unsupported item types |
547 | | |
548 | | // Carry the real context, like every other ImageItem. Error items used to be |
549 | | // constructed with a null context, which made get_context()/get_file() a |
550 | | // null-deref hazard for any code that reaches an error item (e.g. an error |
551 | | // item attached as a depth/aux image, then handed to verify_decodable()). |
552 | | ImageItem_Error(HeifContext* context, uint32_t item_type, heif_item_id id, Error err) |
553 | 12.0k | : ImageItem(context, id), m_item_type(item_type), m_item_error(std::move(err)) {} |
554 | | |
555 | | uint32_t get_infe_type() const override |
556 | 68 | { |
557 | 68 | return m_item_type; |
558 | 68 | } |
559 | | |
560 | 36.4k | Error get_item_error() const override { return m_item_error; } |
561 | | |
562 | | Result<std::shared_ptr<HeifPixelImage>> decode_image(const heif_decoding_options& options, |
563 | | bool decode_tile_only, uint32_t tile_x0, |
564 | | uint32_t tile_y0, |
565 | | DecodeTraversalState decode_state) const override |
566 | 0 | { |
567 | 0 | return m_item_error; |
568 | 0 | } |
569 | | |
570 | | Result<std::shared_ptr<HeifPixelImage>> decode_compressed_image(const heif_decoding_options& options, |
571 | | bool decode_tile_only, uint32_t tile_x0, |
572 | | uint32_t tile_y0, DecodeTraversalState decode_state) const override |
573 | 0 | { |
574 | 0 | return m_item_error; |
575 | 0 | } |
576 | | |
577 | 136 | [[nodiscard]] int get_luma_bits_per_pixel() const override { return -1; } |
578 | | |
579 | 0 | [[nodiscard]] int get_chroma_bits_per_pixel() const override { return -1; } |
580 | | |
581 | | private: |
582 | | uint32_t m_item_type; |
583 | | Error m_item_error; |
584 | | }; |
585 | | |
586 | | #endif //LIBHEIF_IMAGEITEM_H |