/src/libheif/libheif/codecs/uncompressed/decoder_pixel_interleave.cc
Line | Count | Source (jump to first uncovered line) |
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 "decoder_pixel_interleave.h" |
22 | | #include "context.h" |
23 | | #include "error.h" |
24 | | |
25 | | #include <cassert> |
26 | | #include <vector> |
27 | | |
28 | | |
29 | | Error PixelInterleaveDecoder::decode_tile(const DataExtent& dataExtent, |
30 | | const UncompressedImageCodec::unci_properties& properties, |
31 | | std::shared_ptr<HeifPixelImage>& img, |
32 | | uint32_t out_x0, uint32_t out_y0, |
33 | | uint32_t image_width, uint32_t image_height, |
34 | | uint32_t tile_x, uint32_t tile_y) |
35 | 0 | { |
36 | 0 | if (m_tile_width == 0) { |
37 | 0 | return {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "Internal error: PixelInterleaveDecoder tile_width=0"}; |
38 | 0 | } |
39 | | |
40 | | // --- compute which file range we need to read for the tile |
41 | | |
42 | 0 | uint32_t bits_per_row = 0; |
43 | 0 | for (uint32_t x = 0; x < m_tile_width; x++) { |
44 | 0 | uint32_t bits_per_pixel = 0; |
45 | |
|
46 | 0 | for (ChannelListEntry& entry : channelList) { |
47 | 0 | uint32_t bits_per_component = entry.bits_per_component_sample; |
48 | 0 | if (entry.component_alignment > 0) { |
49 | | // start at byte boundary |
50 | 0 | bits_per_row = (bits_per_row + 7) & ~7U; |
51 | |
|
52 | 0 | uint32_t bytes_per_component = (bits_per_component + 7) / 8; |
53 | 0 | skip_to_alignment(bytes_per_component, entry.component_alignment); |
54 | 0 | bits_per_component = bytes_per_component * 8; |
55 | 0 | } |
56 | |
|
57 | 0 | bits_per_pixel += bits_per_component; |
58 | 0 | } |
59 | |
|
60 | 0 | if (m_uncC->get_pixel_size() != 0) { |
61 | 0 | uint32_t bytes_per_pixel = (bits_per_pixel + 7) / 8; |
62 | 0 | skip_to_alignment(bytes_per_pixel, m_uncC->get_pixel_size()); |
63 | 0 | bits_per_pixel = bytes_per_pixel * 8; |
64 | 0 | } |
65 | |
|
66 | 0 | bits_per_row += bits_per_pixel; |
67 | 0 | } |
68 | |
|
69 | 0 | uint32_t bytes_per_row = (bits_per_row + 7) / 8; |
70 | 0 | skip_to_alignment(bytes_per_row, m_uncC->get_row_align_size()); |
71 | |
|
72 | 0 | uint64_t total_tile_size = bytes_per_row * static_cast<uint64_t>(m_tile_height); |
73 | 0 | if (m_uncC->get_tile_align_size() != 0) { |
74 | 0 | skip_to_alignment(total_tile_size, m_uncC->get_tile_align_size()); |
75 | 0 | } |
76 | |
|
77 | 0 | assert(m_tile_width > 0); |
78 | 0 | uint32_t tileIdx = tile_x + tile_y * (image_width / m_tile_width); |
79 | 0 | uint64_t tile_start_offset = total_tile_size * tileIdx; |
80 | | |
81 | | |
82 | | // --- read required file range |
83 | |
|
84 | 0 | std::vector<uint8_t> src_data; |
85 | 0 | Error err = get_compressed_image_data_uncompressed(dataExtent, properties, &src_data, tile_start_offset, total_tile_size, tileIdx, nullptr); |
86 | | //Error err = context->get_heif_file()->append_data_from_iloc(image_id, src_data, tile_start_offset, total_tile_size); |
87 | 0 | if (err) { |
88 | 0 | return err; |
89 | 0 | } |
90 | | |
91 | 0 | UncompressedBitReader srcBits(src_data); |
92 | |
|
93 | 0 | processTile(srcBits, tile_y, tile_x, out_x0, out_y0); |
94 | |
|
95 | 0 | return Error::Ok; |
96 | 0 | } |
97 | | |
98 | | |
99 | | void PixelInterleaveDecoder::processTile(UncompressedBitReader& srcBits, uint32_t tile_row, uint32_t tile_column, uint32_t out_x0, uint32_t out_y0) |
100 | 0 | { |
101 | 0 | for (uint32_t tile_y = 0; tile_y < m_tile_height; tile_y++) { |
102 | 0 | srcBits.markRowStart(); |
103 | 0 | for (uint32_t tile_x = 0; tile_x < m_tile_width; tile_x++) { |
104 | 0 | srcBits.markPixelStart(); |
105 | 0 | for (ChannelListEntry& entry : channelList) { |
106 | 0 | if (entry.use_channel) { |
107 | 0 | uint64_t dst_row_offset = entry.getDestinationRowOffset(0, tile_y + out_y0); |
108 | 0 | if (entry.component_alignment != 0) { |
109 | 0 | srcBits.skip_to_byte_boundary(); |
110 | 0 | int numPadBits = (entry.component_alignment * 8) - entry.bits_per_component_sample; |
111 | 0 | srcBits.skip_bits(numPadBits); |
112 | 0 | } |
113 | 0 | processComponentSample(srcBits, entry, dst_row_offset, 0, out_x0 + tile_x); |
114 | 0 | } |
115 | 0 | else { |
116 | 0 | srcBits.skip_bytes(entry.bytes_per_component_sample); |
117 | 0 | } |
118 | 0 | } |
119 | 0 | srcBits.handlePixelAlignment(m_uncC->get_pixel_size()); |
120 | 0 | } |
121 | 0 | srcBits.handleRowAlignment(m_uncC->get_row_align_size()); |
122 | 0 | } |
123 | 0 | } |