/src/libheif/libheif/image-items/unc_image.cc
Line | Count | Source |
1 | | /* |
2 | | * HEIF codec. |
3 | | * Copyright (c) 2023 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 | | #include <cstdint> |
22 | | #include <cstring> |
23 | | #include <algorithm> |
24 | | #include <map> |
25 | | #include <iostream> |
26 | | #include <cassert> |
27 | | #include <utility> |
28 | | |
29 | | #include "common_utils.h" |
30 | | #include "context.h" |
31 | | #include "compression.h" |
32 | | #include "error.h" |
33 | | #include "libheif/heif.h" |
34 | | #include "codecs/uncompressed/unc_types.h" |
35 | | #include "codecs/uncompressed/unc_boxes.h" |
36 | | #include "unc_image.h" |
37 | | #include "codecs/uncompressed/unc_dec.h" |
38 | | #include "codecs/uncompressed/unc_enc.h" |
39 | | #include "codecs/uncompressed/unc_codec.h" |
40 | | #include "image_item.h" |
41 | | |
42 | | |
43 | | |
44 | | static void maybe_make_minimised_uncC(std::shared_ptr<Box_uncC>& uncC, const std::shared_ptr<const HeifPixelImage>& image) |
45 | 0 | { |
46 | 0 | uncC->set_version(0); |
47 | 0 | if (image->get_colorspace() != heif_colorspace_RGB) { |
48 | 0 | return; |
49 | 0 | } |
50 | 0 | if (!((image->get_chroma_format() == heif_chroma_interleaved_RGB) || (image->get_chroma_format() == heif_chroma_interleaved_RGBA))) { |
51 | 0 | return; |
52 | 0 | } |
53 | 0 | if (image->get_bits_per_pixel(heif_channel_interleaved) != 8) { |
54 | 0 | return; |
55 | 0 | } |
56 | 0 | if (image->get_chroma_format() == heif_chroma_interleaved_RGBA) { |
57 | 0 | uncC->set_profile(fourcc("rgba")); |
58 | 0 | } else { |
59 | 0 | uncC->set_profile(fourcc("rgb3")); |
60 | 0 | } |
61 | 0 | uncC->set_version(1); |
62 | 0 | } |
63 | | |
64 | | |
65 | | ImageItem_uncompressed::ImageItem_uncompressed(HeifContext* ctx, heif_item_id id) |
66 | 58 | : ImageItem(ctx, id) |
67 | 58 | { |
68 | 58 | m_encoder = std::make_shared<Encoder_uncompressed>(); |
69 | 58 | } |
70 | | |
71 | | ImageItem_uncompressed::ImageItem_uncompressed(HeifContext* ctx) |
72 | 0 | : ImageItem(ctx) |
73 | 0 | { |
74 | 0 | m_encoder = std::make_shared<Encoder_uncompressed>(); |
75 | 0 | } |
76 | | |
77 | | |
78 | | Result<std::shared_ptr<HeifPixelImage>> ImageItem_uncompressed::decode_compressed_image(const heif_decoding_options& options, |
79 | | bool decode_tile_only, uint32_t tile_x0, uint32_t tile_y0) const |
80 | 2 | { |
81 | 2 | std::shared_ptr<HeifPixelImage> img; |
82 | | |
83 | 2 | std::vector<uint8_t> data; |
84 | | |
85 | 2 | Error err; |
86 | | |
87 | 2 | if (decode_tile_only) { |
88 | 0 | err = UncompressedImageCodec::decode_uncompressed_image_tile(get_context(), |
89 | 0 | get_id(), |
90 | 0 | img, |
91 | 0 | tile_x0, tile_y0); |
92 | 0 | } |
93 | 2 | else { |
94 | 2 | err = UncompressedImageCodec::decode_uncompressed_image(get_context(), |
95 | 2 | get_id(), |
96 | 2 | img); |
97 | 2 | } |
98 | | |
99 | 2 | if (err) { |
100 | 2 | return err; |
101 | 2 | } |
102 | 0 | else { |
103 | 0 | return img; |
104 | 0 | } |
105 | 2 | } |
106 | | |
107 | | |
108 | | struct unciHeaders |
109 | | { |
110 | | std::shared_ptr<Box_uncC> uncC; |
111 | | std::shared_ptr<Box_cmpd> cmpd; |
112 | | }; |
113 | | |
114 | | |
115 | | static Result<unciHeaders> generate_headers(const std::shared_ptr<const HeifPixelImage>& src_image, |
116 | | const heif_unci_image_parameters* parameters, |
117 | | const heif_encoding_options* options) |
118 | 0 | { |
119 | 0 | unciHeaders headers; |
120 | |
|
121 | 0 | bool uses_tiles = (parameters->tile_width != parameters->image_width || |
122 | 0 | parameters->tile_height != parameters->image_height); |
123 | |
|
124 | 0 | std::shared_ptr<Box_uncC> uncC = std::make_shared<Box_uncC>(); |
125 | 0 | if (options && options->prefer_uncC_short_form && !uses_tiles) { |
126 | 0 | maybe_make_minimised_uncC(uncC, src_image); |
127 | 0 | } |
128 | |
|
129 | 0 | if (uncC->get_version() == 1) { |
130 | 0 | headers.uncC = std::move(uncC); |
131 | 0 | } else { |
132 | 0 | std::shared_ptr<Box_cmpd> cmpd = std::make_shared<Box_cmpd>(); |
133 | |
|
134 | 0 | Error error = fill_cmpd_and_uncC(cmpd, uncC, src_image, parameters); |
135 | 0 | if (error) { |
136 | 0 | return error; |
137 | 0 | } |
138 | | |
139 | 0 | headers.cmpd = std::move(cmpd); |
140 | 0 | headers.uncC = std::move(uncC); |
141 | 0 | } |
142 | | |
143 | 0 | return headers; |
144 | 0 | } |
145 | | |
146 | | |
147 | | Result<std::vector<uint8_t>> encode_image_tile(const std::shared_ptr<const HeifPixelImage>& src_image) |
148 | 0 | { |
149 | 0 | std::vector<uint8_t> data; |
150 | |
|
151 | 0 | if (src_image->get_colorspace() == heif_colorspace_YCbCr) |
152 | 0 | { |
153 | 0 | uint64_t offset = 0; |
154 | 0 | for (heif_channel channel : {heif_channel_Y, heif_channel_Cb, heif_channel_Cr}) |
155 | 0 | { |
156 | 0 | size_t src_stride; |
157 | 0 | uint32_t src_width = src_image->get_width(channel); |
158 | 0 | uint32_t src_height = src_image->get_height(channel); |
159 | 0 | const uint8_t* src_data = src_image->get_plane(channel, &src_stride); |
160 | 0 | uint64_t out_size = src_width * uint64_t{src_height}; |
161 | 0 | data.resize(data.size() + out_size); |
162 | 0 | for (uint32_t y = 0; y < src_height; y++) { |
163 | 0 | memcpy(data.data() + offset + y * src_width, src_data + src_stride * y, src_width); |
164 | 0 | } |
165 | 0 | offset += out_size; |
166 | 0 | } |
167 | |
|
168 | 0 | return data; |
169 | 0 | } |
170 | 0 | else if (src_image->get_colorspace() == heif_colorspace_RGB) |
171 | 0 | { |
172 | 0 | if (src_image->get_chroma_format() == heif_chroma_444) |
173 | 0 | { |
174 | 0 | uint64_t offset = 0; |
175 | 0 | std::vector<heif_channel> channels = {heif_channel_R, heif_channel_G, heif_channel_B}; |
176 | 0 | if (src_image->has_channel(heif_channel_Alpha)) |
177 | 0 | { |
178 | 0 | channels.push_back(heif_channel_Alpha); |
179 | 0 | } |
180 | 0 | for (heif_channel channel : channels) |
181 | 0 | { |
182 | 0 | size_t src_stride; |
183 | 0 | const uint8_t* src_data = src_image->get_plane(channel, &src_stride); |
184 | 0 | uint64_t out_size = static_cast<uint64_t>(src_image->get_height()) * src_image->get_width(); |
185 | |
|
186 | 0 | data.resize(data.size() + out_size); |
187 | 0 | for (uint32_t y = 0; y < src_image->get_height(); y++) { |
188 | 0 | memcpy(data.data() + offset + y * src_image->get_width(), src_data + y * src_stride, src_image->get_width()); |
189 | 0 | } |
190 | |
|
191 | 0 | offset += out_size; |
192 | 0 | } |
193 | |
|
194 | 0 | return data; |
195 | 0 | } |
196 | 0 | else if ((src_image->get_chroma_format() == heif_chroma_interleaved_RGB) || |
197 | 0 | (src_image->get_chroma_format() == heif_chroma_interleaved_RGBA) || |
198 | 0 | (src_image->get_chroma_format() == heif_chroma_interleaved_RRGGBB_BE) || |
199 | 0 | (src_image->get_chroma_format() == heif_chroma_interleaved_RRGGBB_LE) || |
200 | 0 | (src_image->get_chroma_format() == heif_chroma_interleaved_RRGGBBAA_BE) || |
201 | 0 | (src_image->get_chroma_format() == heif_chroma_interleaved_RRGGBBAA_LE)) |
202 | 0 | { |
203 | 0 | int bytes_per_pixel = 0; |
204 | 0 | switch (src_image->get_chroma_format()) { |
205 | 0 | case heif_chroma_interleaved_RGB: |
206 | 0 | bytes_per_pixel=3; |
207 | 0 | break; |
208 | 0 | case heif_chroma_interleaved_RGBA: |
209 | 0 | bytes_per_pixel=4; |
210 | 0 | break; |
211 | 0 | case heif_chroma_interleaved_RRGGBB_BE: |
212 | 0 | case heif_chroma_interleaved_RRGGBB_LE: |
213 | 0 | bytes_per_pixel=6; |
214 | 0 | break; |
215 | 0 | case heif_chroma_interleaved_RRGGBBAA_BE: |
216 | 0 | case heif_chroma_interleaved_RRGGBBAA_LE: |
217 | 0 | bytes_per_pixel=8; |
218 | 0 | break; |
219 | 0 | default: |
220 | 0 | assert(false); |
221 | 0 | } |
222 | | |
223 | 0 | size_t src_stride; |
224 | 0 | const uint8_t* src_data = src_image->get_plane(heif_channel_interleaved, &src_stride); |
225 | 0 | uint64_t out_size = static_cast<uint64_t>(src_image->get_height()) * src_image->get_width() * bytes_per_pixel; |
226 | 0 | data.resize(out_size); |
227 | 0 | for (uint32_t y = 0; y < src_image->get_height(); y++) { |
228 | 0 | memcpy(data.data() + y * src_image->get_width() * bytes_per_pixel, src_data + src_stride * y, src_image->get_width() * bytes_per_pixel); |
229 | 0 | } |
230 | |
|
231 | 0 | return data; |
232 | 0 | } |
233 | 0 | else |
234 | 0 | { |
235 | 0 | return Error(heif_error_Unsupported_feature, |
236 | 0 | heif_suberror_Unsupported_data_version, |
237 | 0 | "Unsupported RGB chroma"); |
238 | 0 | } |
239 | 0 | } |
240 | 0 | else if (src_image->get_colorspace() == heif_colorspace_monochrome) |
241 | 0 | { |
242 | 0 | uint64_t offset = 0; |
243 | 0 | std::vector<heif_channel> channels; |
244 | 0 | if (src_image->has_channel(heif_channel_Alpha)) |
245 | 0 | { |
246 | 0 | channels = {heif_channel_Y, heif_channel_Alpha}; |
247 | 0 | } |
248 | 0 | else |
249 | 0 | { |
250 | 0 | channels = {heif_channel_Y}; |
251 | 0 | } |
252 | 0 | for (heif_channel channel : channels) |
253 | 0 | { |
254 | 0 | size_t src_stride; |
255 | 0 | const uint8_t* src_data = src_image->get_plane(channel, &src_stride); |
256 | 0 | uint64_t out_size = static_cast<uint64_t>(src_image->get_height()) * src_stride; |
257 | 0 | data.resize(data.size() + out_size); |
258 | 0 | memcpy(data.data() + offset, src_data, out_size); |
259 | 0 | offset += out_size; |
260 | 0 | } |
261 | |
|
262 | 0 | return data; |
263 | 0 | } |
264 | 0 | else |
265 | 0 | { |
266 | 0 | return Error(heif_error_Unsupported_feature, |
267 | 0 | heif_suberror_Unsupported_data_version, |
268 | 0 | "Unsupported colourspace"); |
269 | 0 | } |
270 | |
|
271 | 0 | } |
272 | | |
273 | | |
274 | | Result<Encoder::CodedImageData> ImageItem_uncompressed::encode(const std::shared_ptr<HeifPixelImage>& src_image, |
275 | | heif_encoder* encoder, |
276 | | const heif_encoding_options& options, |
277 | | heif_image_input_class input_class) |
278 | 0 | { |
279 | 0 | return encode_static(src_image, options); |
280 | 0 | } |
281 | | |
282 | | |
283 | | Result<Encoder::CodedImageData> ImageItem_uncompressed::encode_static(const std::shared_ptr<HeifPixelImage>& src_image, |
284 | | const heif_encoding_options& options) |
285 | 0 | { |
286 | 0 | auto parameters = std::unique_ptr<heif_unci_image_parameters, |
287 | 0 | void (*)(heif_unci_image_parameters*)>(heif_unci_image_parameters_alloc(), |
288 | 0 | heif_unci_image_parameters_release); |
289 | |
|
290 | 0 | parameters->image_width = src_image->get_width(); |
291 | 0 | parameters->image_height = src_image->get_height(); |
292 | 0 | parameters->tile_width = parameters->image_width; |
293 | 0 | parameters->tile_height = parameters->image_height; |
294 | | |
295 | | |
296 | | // --- generate configuration property boxes |
297 | |
|
298 | 0 | Result<unciHeaders> genHeadersResult = generate_headers(src_image, parameters.get(), &options); |
299 | 0 | if (!genHeadersResult) { |
300 | 0 | return genHeadersResult.error(); |
301 | 0 | } |
302 | | |
303 | 0 | const unciHeaders& headers = *genHeadersResult; |
304 | |
|
305 | 0 | Encoder::CodedImageData codedImageData; |
306 | 0 | if (headers.uncC) { |
307 | 0 | codedImageData.properties.push_back(headers.uncC); |
308 | 0 | } |
309 | 0 | if (headers.cmpd) { |
310 | 0 | codedImageData.properties.push_back(headers.cmpd); |
311 | 0 | } |
312 | | |
313 | | |
314 | | // --- encode image |
315 | |
|
316 | 0 | Result<std::vector<uint8_t>> codedBitstreamResult = encode_image_tile(src_image); |
317 | 0 | if (!codedBitstreamResult) { |
318 | 0 | return codedBitstreamResult.error(); |
319 | 0 | } |
320 | | |
321 | 0 | codedImageData.bitstream = *codedBitstreamResult; |
322 | |
|
323 | 0 | return codedImageData; |
324 | 0 | } |
325 | | |
326 | | |
327 | | Result<std::shared_ptr<ImageItem_uncompressed>> ImageItem_uncompressed::add_unci_item(HeifContext* ctx, |
328 | | const heif_unci_image_parameters* parameters, |
329 | | const heif_encoding_options* encoding_options, |
330 | | const std::shared_ptr<const HeifPixelImage>& prototype) |
331 | 0 | { |
332 | | // Check input parameters |
333 | |
|
334 | 0 | if (parameters->image_width % parameters->tile_width != 0 || |
335 | 0 | parameters->image_height % parameters->tile_height != 0) { |
336 | 0 | return Error{heif_error_Invalid_input, |
337 | 0 | heif_suberror_Invalid_parameter_value, |
338 | 0 | "ISO 23001-17 image size must be an integer multiple of the tile size."}; |
339 | 0 | } |
340 | | |
341 | | // Create 'unci' Item |
342 | | |
343 | 0 | auto file = ctx->get_heif_file(); |
344 | |
|
345 | 0 | heif_item_id unci_id = ctx->get_heif_file()->add_new_image(fourcc("unci")); |
346 | 0 | auto unci_image = std::make_shared<ImageItem_uncompressed>(ctx, unci_id); |
347 | 0 | unci_image->set_resolution(parameters->image_width, parameters->image_height); |
348 | 0 | ctx->insert_image_item(unci_id, unci_image); |
349 | | |
350 | | |
351 | | // Generate headers |
352 | |
|
353 | 0 | Result<unciHeaders> genHeadersResult = generate_headers(prototype, parameters, encoding_options); |
354 | 0 | if (!genHeadersResult) { |
355 | 0 | return genHeadersResult.error(); |
356 | 0 | } |
357 | | |
358 | 0 | const unciHeaders& headers = *genHeadersResult; |
359 | |
|
360 | 0 | assert(headers.uncC); |
361 | | |
362 | 0 | if (headers.uncC) { |
363 | 0 | unci_image->add_property(headers.uncC, true); |
364 | 0 | } |
365 | |
|
366 | 0 | if (headers.cmpd) { |
367 | 0 | unci_image->add_property(headers.cmpd, true); |
368 | 0 | } |
369 | | |
370 | | // Add `ispe` property |
371 | |
|
372 | 0 | auto ispe = std::make_shared<Box_ispe>(); |
373 | 0 | ispe->set_size(static_cast<uint32_t>(parameters->image_width), |
374 | 0 | static_cast<uint32_t>(parameters->image_height)); |
375 | 0 | unci_image->add_property(ispe, true); |
376 | |
|
377 | 0 | if (parameters->compression != heif_unci_compression_off) { |
378 | 0 | auto icef = std::make_shared<Box_icef>(); |
379 | 0 | auto cmpC = std::make_shared<Box_cmpC>(); |
380 | 0 | cmpC->set_compressed_unit_type(heif_cmpC_compressed_unit_type_image_tile); |
381 | |
|
382 | 0 | if (false) { |
383 | 0 | } |
384 | 0 | #if HAVE_ZLIB |
385 | 0 | else if (parameters->compression == heif_unci_compression_deflate) { |
386 | 0 | cmpC->set_compression_type(fourcc("defl")); |
387 | 0 | } |
388 | 0 | else if (parameters->compression == heif_unci_compression_zlib) { |
389 | 0 | cmpC->set_compression_type(fourcc("zlib")); |
390 | 0 | } |
391 | 0 | #endif |
392 | 0 | #if HAVE_BROTLI |
393 | 0 | else if (parameters->compression == heif_unci_compression_brotli) { |
394 | 0 | cmpC->set_compression_type(fourcc("brot")); |
395 | 0 | } |
396 | 0 | #endif |
397 | 0 | else { |
398 | 0 | assert(false); |
399 | 0 | } |
400 | | |
401 | 0 | unci_image->add_property(cmpC, true); |
402 | 0 | unci_image->add_property_without_deduplication(icef, true); // icef is empty. A normal add_property() would lead to a wrong deduplication. |
403 | 0 | } |
404 | | |
405 | | // Create empty image. If we use compression, we append the data piece by piece. |
406 | | |
407 | 0 | if (parameters->compression == heif_unci_compression_off) { |
408 | 0 | uint64_t tile_size = headers.uncC->compute_tile_data_size_bytes(parameters->image_width / headers.uncC->get_number_of_tile_columns(), |
409 | 0 | parameters->image_height / headers.uncC->get_number_of_tile_rows()); |
410 | |
|
411 | 0 | std::vector<uint8_t> dummydata; |
412 | 0 | dummydata.resize(tile_size); |
413 | |
|
414 | 0 | uint32_t nTiles = (parameters->image_width / parameters->tile_width) * (parameters->image_height / parameters->tile_height); |
415 | |
|
416 | 0 | for (uint64_t i = 0; i < nTiles; i++) { |
417 | 0 | const int construction_method = 0; // 0=mdat 1=idat |
418 | 0 | file->append_iloc_data(unci_id, dummydata, construction_method); |
419 | 0 | } |
420 | 0 | } |
421 | | |
422 | | // Set Brands |
423 | | //ctx->get_heif_file()->set_brand(heif_compression_uncompressed, unci_image->is_miaf_compatible()); |
424 | |
|
425 | 0 | return {unci_image}; |
426 | 0 | } |
427 | | |
428 | | |
429 | | Error ImageItem_uncompressed::add_image_tile(uint32_t tile_x, uint32_t tile_y, const std::shared_ptr<const HeifPixelImage>& image) |
430 | 0 | { |
431 | 0 | std::shared_ptr<Box_uncC> uncC = get_property<Box_uncC>(); |
432 | 0 | assert(uncC); |
433 | | |
434 | 0 | uint32_t tile_width = image->get_width(); |
435 | 0 | uint32_t tile_height = image->get_height(); |
436 | |
|
437 | 0 | uint32_t tile_idx = tile_y * uncC->get_number_of_tile_columns() + tile_x; |
438 | |
|
439 | 0 | Result<std::vector<uint8_t>> codedBitstreamResult = encode_image_tile(image); |
440 | 0 | if (!codedBitstreamResult) { |
441 | 0 | return codedBitstreamResult.error(); |
442 | 0 | } |
443 | | |
444 | 0 | std::shared_ptr<Box_cmpC> cmpC = get_property<Box_cmpC>(); |
445 | 0 | std::shared_ptr<Box_icef> icef = get_property<Box_icef>(); |
446 | |
|
447 | 0 | if (!icef || !cmpC) { |
448 | 0 | assert(!icef); |
449 | 0 | assert(!cmpC); |
450 | | |
451 | | // uncompressed |
452 | | |
453 | 0 | uint64_t tile_data_size = uncC->compute_tile_data_size_bytes(tile_width, tile_height); |
454 | |
|
455 | 0 | get_file()->replace_iloc_data(get_id(), tile_idx * tile_data_size, *codedBitstreamResult, 0); |
456 | 0 | } |
457 | 0 | else { |
458 | 0 | std::vector<uint8_t> compressed_data; |
459 | 0 | const std::vector<uint8_t>& raw_data = std::move(*codedBitstreamResult); |
460 | 0 | (void)raw_data; |
461 | |
|
462 | 0 | uint32_t compr = cmpC->get_compression_type(); |
463 | 0 | switch (compr) { |
464 | 0 | #if HAVE_ZLIB |
465 | 0 | case fourcc("defl"): |
466 | 0 | compressed_data = compress_deflate(raw_data.data(), raw_data.size()); |
467 | 0 | break; |
468 | 0 | case fourcc("zlib"): |
469 | 0 | compressed_data = compress_zlib(raw_data.data(), raw_data.size()); |
470 | 0 | break; |
471 | 0 | #endif |
472 | 0 | #if HAVE_BROTLI |
473 | 0 | case fourcc("brot"): |
474 | 0 | compressed_data = compress_brotli(raw_data.data(), raw_data.size()); |
475 | 0 | break; |
476 | 0 | #endif |
477 | 0 | default: |
478 | 0 | assert(false); |
479 | 0 | break; |
480 | 0 | } |
481 | | |
482 | 0 | get_file()->append_iloc_data(get_id(), compressed_data, 0); |
483 | |
|
484 | 0 | Box_icef::CompressedUnitInfo unit_info; |
485 | 0 | unit_info.unit_offset = m_next_tile_write_pos; |
486 | 0 | unit_info.unit_size = compressed_data.size(); |
487 | 0 | icef->set_component(tile_idx, unit_info); |
488 | |
|
489 | 0 | m_next_tile_write_pos += compressed_data.size(); |
490 | 0 | } |
491 | | |
492 | 0 | return Error::Ok; |
493 | 0 | } |
494 | | |
495 | | |
496 | | void ImageItem_uncompressed::get_tile_size(uint32_t& w, uint32_t& h) const |
497 | 0 | { |
498 | 0 | auto ispe = get_property<Box_ispe>(); |
499 | 0 | auto uncC = get_property<Box_uncC>(); |
500 | |
|
501 | 0 | if (!ispe || !uncC) { |
502 | 0 | w = h = 0; |
503 | 0 | } |
504 | 0 | else { |
505 | 0 | w = ispe->get_width() / uncC->get_number_of_tile_columns(); |
506 | 0 | h = ispe->get_height() / uncC->get_number_of_tile_rows(); |
507 | 0 | } |
508 | 0 | } |
509 | | |
510 | | |
511 | | heif_image_tiling ImageItem_uncompressed::get_heif_image_tiling() const |
512 | 0 | { |
513 | 0 | heif_image_tiling tiling{}; |
514 | |
|
515 | 0 | auto ispe = get_property<Box_ispe>(); |
516 | 0 | auto uncC = get_property<Box_uncC>(); |
517 | 0 | assert(ispe && uncC); |
518 | | |
519 | 0 | tiling.num_columns = uncC->get_number_of_tile_columns(); |
520 | 0 | tiling.num_rows = uncC->get_number_of_tile_rows(); |
521 | |
|
522 | 0 | tiling.tile_width = ispe->get_width() / tiling.num_columns; |
523 | 0 | tiling.tile_height = ispe->get_height() / tiling.num_rows; |
524 | |
|
525 | 0 | tiling.image_width = ispe->get_width(); |
526 | 0 | tiling.image_height = ispe->get_height(); |
527 | 0 | tiling.number_of_extra_dimensions = 0; |
528 | |
|
529 | 0 | return tiling; |
530 | 0 | } |
531 | | |
532 | | Result<std::shared_ptr<Decoder>> ImageItem_uncompressed::get_decoder() const |
533 | 5 | { |
534 | 5 | return {m_decoder}; |
535 | 5 | } |
536 | | |
537 | | std::shared_ptr<Encoder> ImageItem_uncompressed::get_encoder() const |
538 | 0 | { |
539 | 0 | return m_encoder; |
540 | 0 | } |
541 | | |
542 | | Error ImageItem_uncompressed::initialize_decoder() |
543 | 43 | { |
544 | 43 | std::shared_ptr<Box_cmpd> cmpd = get_property<Box_cmpd>(); |
545 | 43 | std::shared_ptr<Box_uncC> uncC = get_property<Box_uncC>(); |
546 | 43 | std::shared_ptr<Box_ispe> ispe = get_property<Box_ispe>(); |
547 | | |
548 | 43 | if (!uncC) { |
549 | 40 | return Error{heif_error_Invalid_input, |
550 | 40 | heif_suberror_Unspecified, |
551 | 40 | "No 'uncC' box found."}; |
552 | 40 | } |
553 | | |
554 | 3 | m_decoder = std::make_shared<Decoder_uncompressed>(uncC, cmpd, ispe); |
555 | | |
556 | 3 | return Error::Ok; |
557 | 43 | } |
558 | | |
559 | | void ImageItem_uncompressed::set_decoder_input_data() |
560 | 3 | { |
561 | 3 | DataExtent extent; |
562 | 3 | extent.set_from_image_item(get_context()->get_heif_file(), get_id()); |
563 | | |
564 | 3 | m_decoder->set_data_extent(std::move(extent)); |
565 | 3 | } |
566 | | |
567 | | |
568 | | bool ImageItem_uncompressed::has_coded_alpha_channel() const |
569 | 3 | { |
570 | 3 | return m_decoder->has_alpha_component(); |
571 | 3 | } |
572 | | |
573 | | heif_brand2 ImageItem_uncompressed::get_compatible_brand() const |
574 | 0 | { |
575 | 0 | return 0; // TODO: not clear to me what to use |
576 | 0 | } |