/rust/registry/src/index.crates.io-6f17d22bba15001f/exr-1.73.0/src/block/chunk.rs
Line | Count | Source (jump to first uncovered line) |
1 | | |
2 | | //! Read and write already compressed pixel data blocks. |
3 | | //! Does not include the process of compression and decompression. |
4 | | |
5 | | use crate::meta::attribute::{IntegerBounds}; |
6 | | |
7 | | /// A generic block of pixel information. |
8 | | /// Contains pixel data and an index to the corresponding header. |
9 | | /// All pixel data in a file is split into a list of chunks. |
10 | | /// Also contains positioning information that locates this |
11 | | /// data block in the referenced layer. |
12 | | #[derive(Debug, Clone)] |
13 | | pub struct Chunk { |
14 | | |
15 | | /// The index of the layer that the block belongs to. |
16 | | /// This is required as the pixel data can appear in any order in a file. |
17 | | // PDF says u64, but source code seems to be i32 |
18 | | pub layer_index: usize, |
19 | | |
20 | | /// The compressed pixel contents. |
21 | | pub compressed_block: CompressedBlock, |
22 | | } |
23 | | |
24 | | /// The raw, possibly compressed pixel data of a file. |
25 | | /// Each layer in a file can have a different type. |
26 | | /// Also contains positioning information that locates this |
27 | | /// data block in the corresponding layer. |
28 | | /// Exists inside a `Chunk`. |
29 | | #[derive(Debug, Clone)] |
30 | | pub enum CompressedBlock { |
31 | | |
32 | | /// Scan line blocks of flat data. |
33 | | ScanLine(CompressedScanLineBlock), |
34 | | |
35 | | /// Tiles of flat data. |
36 | | Tile(CompressedTileBlock), |
37 | | |
38 | | /// Scan line blocks of deep data. |
39 | | DeepScanLine(CompressedDeepScanLineBlock), |
40 | | |
41 | | /// Tiles of deep data. |
42 | | DeepTile(CompressedDeepTileBlock), |
43 | | } |
44 | | |
45 | | /// A `Block` of possibly compressed flat scan lines. |
46 | | /// Corresponds to type attribute `scanlineimage`. |
47 | | #[derive(Debug, Clone)] |
48 | | pub struct CompressedScanLineBlock { |
49 | | |
50 | | /// The block's y coordinate is the pixel space y coordinate of the top scan line in the block. |
51 | | /// The top scan line block in the image is aligned with the top edge of the data window. |
52 | | pub y_coordinate: i32, |
53 | | |
54 | | /// One or more scan lines may be stored together as a scan line block. |
55 | | /// The number of scan lines per block depends on how the pixel data are compressed. |
56 | | /// For each line in the tile, for each channel, the row values are contiguous. |
57 | | pub compressed_pixels: Vec<u8>, |
58 | | } |
59 | | |
60 | | /// This `Block` is a tile of flat (non-deep) data. |
61 | | /// Corresponds to type attribute `tiledimage`. |
62 | | #[derive(Debug, Clone)] |
63 | | pub struct CompressedTileBlock { |
64 | | |
65 | | /// The tile location. |
66 | | pub coordinates: TileCoordinates, |
67 | | |
68 | | /// One or more scan lines may be stored together as a scan line block. |
69 | | /// The number of scan lines per block depends on how the pixel data are compressed. |
70 | | /// For each line in the tile, for each channel, the row values are contiguous. |
71 | | pub compressed_pixels: Vec<u8>, |
72 | | } |
73 | | |
74 | | /// Indicates the position and resolution level of a `TileBlock` or `DeepTileBlock`. |
75 | | #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] |
76 | | pub struct TileCoordinates { |
77 | | |
78 | | /// Index of the tile, not pixel position. |
79 | | pub tile_index: Vec2<usize>, |
80 | | |
81 | | /// Index of the Mip/Rip level. |
82 | | pub level_index: Vec2<usize>, |
83 | | } |
84 | | |
85 | | /// This `Block` consists of one or more deep scan lines. |
86 | | /// Corresponds to type attribute `deepscanline`. |
87 | | #[derive(Debug, Clone)] |
88 | | pub struct CompressedDeepScanLineBlock { |
89 | | |
90 | | /// The block's y coordinate is the pixel space y coordinate of the top scan line in the block. |
91 | | /// The top scan line block in the image is aligned with the top edge of the data window. |
92 | | pub y_coordinate: i32, |
93 | | |
94 | | /// Count of samples. |
95 | | pub decompressed_sample_data_size: usize, |
96 | | |
97 | | /// The pixel offset table is a list of integers, one for each pixel column within the data window. |
98 | | /// Each entry in the table indicates the total number of samples required |
99 | | /// to store the pixel in it as well as all pixels to the left of it. |
100 | | pub compressed_pixel_offset_table: Vec<i8>, |
101 | | |
102 | | /// One or more scan lines may be stored together as a scan line block. |
103 | | /// The number of scan lines per block depends on how the pixel data are compressed. |
104 | | /// For each line in the tile, for each channel, the row values are contiguous. |
105 | | pub compressed_sample_data: Vec<u8>, |
106 | | } |
107 | | |
108 | | /// This `Block` is a tile of deep data. |
109 | | /// Corresponds to type attribute `deeptile`. |
110 | | #[derive(Debug, Clone)] |
111 | | pub struct CompressedDeepTileBlock { |
112 | | |
113 | | /// The tile location. |
114 | | pub coordinates: TileCoordinates, |
115 | | |
116 | | /// Count of samples. |
117 | | pub decompressed_sample_data_size: usize, |
118 | | |
119 | | /// The pixel offset table is a list of integers, one for each pixel column within the data window. |
120 | | /// Each entry in the table indicates the total number of samples required |
121 | | /// to store the pixel in it as well as all pixels to the left of it. |
122 | | pub compressed_pixel_offset_table: Vec<i8>, |
123 | | |
124 | | /// One or more scan lines may be stored together as a scan line block. |
125 | | /// The number of scan lines per block depends on how the pixel data are compressed. |
126 | | /// For each line in the tile, for each channel, the row values are contiguous. |
127 | | pub compressed_sample_data: Vec<u8>, |
128 | | } |
129 | | |
130 | | |
131 | | use crate::io::*; |
132 | | |
133 | | impl TileCoordinates { |
134 | | |
135 | | /// Without validation, write this instance to the byte stream. |
136 | 913 | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { |
137 | 913 | i32::write(usize_to_i32(self.tile_index.x()), write)?; |
138 | 913 | i32::write(usize_to_i32(self.tile_index.y()), write)?; |
139 | 913 | i32::write(usize_to_i32(self.level_index.x()), write)?; |
140 | 913 | i32::write(usize_to_i32(self.level_index.y()), write)?; |
141 | 913 | Ok(()) |
142 | 913 | } Unexecuted instantiation: <exr::block::chunk::TileCoordinates>::write::<_> Unexecuted instantiation: <exr::block::chunk::TileCoordinates>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> <exr::block::chunk::TileCoordinates>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> Line | Count | Source | 136 | 913 | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { | 137 | 913 | i32::write(usize_to_i32(self.tile_index.x()), write)?; | 138 | 913 | i32::write(usize_to_i32(self.tile_index.y()), write)?; | 139 | 913 | i32::write(usize_to_i32(self.level_index.x()), write)?; | 140 | 913 | i32::write(usize_to_i32(self.level_index.y()), write)?; | 141 | 913 | Ok(()) | 142 | 913 | } |
|
143 | | |
144 | | /// Read the value without validating. |
145 | 2.21k | pub fn read(read: &mut impl Read) -> Result<Self> { |
146 | 2.21k | let tile_x = i32::read(read)?; |
147 | 2.00k | let tile_y = i32::read(read)?; |
148 | | |
149 | 2.00k | let level_x = i32::read(read)?; |
150 | 2.00k | let level_y = i32::read(read)?; |
151 | | |
152 | 2.00k | if level_x > 31 || level_y > 31 { |
153 | | // there can be at most 31 levels, because the largest level would have a size of 2^31, |
154 | | // which exceeds the maximum 32-bit integer value. |
155 | 861 | return Err(Error::invalid("level index exceeding integer maximum")); |
156 | 1.14k | } |
157 | 1.14k | |
158 | 1.14k | Ok(TileCoordinates { |
159 | 1.14k | tile_index: Vec2(tile_x, tile_y).to_usize("tile coordinate index")?, |
160 | 1.10k | level_index: Vec2(level_x, level_y).to_usize("tile coordinate level")? |
161 | | }) |
162 | 2.21k | } Unexecuted instantiation: <exr::block::chunk::TileCoordinates>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::TileCoordinates>::read::<_> Unexecuted instantiation: <exr::block::chunk::TileCoordinates>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::TileCoordinates>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::TileCoordinates>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::TileCoordinates>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::TileCoordinates>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::TileCoordinates>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::TileCoordinates>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::TileCoordinates>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::TileCoordinates>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> <exr::block::chunk::TileCoordinates>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Line | Count | Source | 145 | 1.29k | pub fn read(read: &mut impl Read) -> Result<Self> { | 146 | 1.29k | let tile_x = i32::read(read)?; | 147 | 1.09k | let tile_y = i32::read(read)?; | 148 | | | 149 | 1.09k | let level_x = i32::read(read)?; | 150 | 1.09k | let level_y = i32::read(read)?; | 151 | | | 152 | 1.09k | if level_x > 31 || level_y > 31 { | 153 | | // there can be at most 31 levels, because the largest level would have a size of 2^31, | 154 | | // which exceeds the maximum 32-bit integer value. | 155 | 861 | return Err(Error::invalid("level index exceeding integer maximum")); | 156 | 230 | } | 157 | 230 | | 158 | 230 | Ok(TileCoordinates { | 159 | 230 | tile_index: Vec2(tile_x, tile_y).to_usize("tile coordinate index")?, | 160 | 195 | level_index: Vec2(level_x, level_y).to_usize("tile coordinate level")? | 161 | | }) | 162 | 1.29k | } |
<exr::block::chunk::TileCoordinates>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>> Line | Count | Source | 145 | 913 | pub fn read(read: &mut impl Read) -> Result<Self> { | 146 | 913 | let tile_x = i32::read(read)?; | 147 | 913 | let tile_y = i32::read(read)?; | 148 | | | 149 | 913 | let level_x = i32::read(read)?; | 150 | 913 | let level_y = i32::read(read)?; | 151 | | | 152 | 913 | if level_x > 31 || level_y > 31 { | 153 | | // there can be at most 31 levels, because the largest level would have a size of 2^31, | 154 | | // which exceeds the maximum 32-bit integer value. | 155 | 0 | return Err(Error::invalid("level index exceeding integer maximum")); | 156 | 913 | } | 157 | 913 | | 158 | 913 | Ok(TileCoordinates { | 159 | 913 | tile_index: Vec2(tile_x, tile_y).to_usize("tile coordinate index")?, | 160 | 913 | level_index: Vec2(level_x, level_y).to_usize("tile coordinate level")? | 161 | | }) | 162 | 913 | } |
Unexecuted instantiation: <exr::block::chunk::TileCoordinates>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> |
163 | | |
164 | | /// The indices which can be used to index into the arrays of a data window. |
165 | | /// These coordinates are only valid inside the corresponding one header. |
166 | | /// Will start at 0 and always be positive. |
167 | 416k | pub fn to_data_indices(&self, tile_size: Vec2<usize>, max: Vec2<usize>) -> Result<IntegerBounds> { |
168 | 416k | let x = self.tile_index.x() * tile_size.width(); |
169 | 416k | let y = self.tile_index.y() * tile_size.height(); |
170 | 416k | |
171 | 416k | if x >= max.x() || y >= max.y() { |
172 | 86 | Err(Error::invalid("tile index")) |
173 | | } |
174 | | else { |
175 | | Ok(IntegerBounds { |
176 | 416k | position: Vec2(usize_to_i32(x), usize_to_i32(y)), |
177 | 416k | size: Vec2( |
178 | 416k | calculate_block_size(max.x(), tile_size.width(), x)?, |
179 | 416k | calculate_block_size(max.y(), tile_size.height(), y)?, |
180 | | ), |
181 | | }) |
182 | | } |
183 | 416k | } |
184 | | |
185 | | /// Absolute coordinates inside the global 2D space of a file, may be negative. |
186 | 0 | pub fn to_absolute_indices(&self, tile_size: Vec2<usize>, data_window: IntegerBounds) -> Result<IntegerBounds> { |
187 | 0 | let data = self.to_data_indices(tile_size, data_window.size)?; |
188 | 0 | Ok(data.with_origin(data_window.position)) |
189 | 0 | } |
190 | | |
191 | | /// Returns if this is the original resolution or a smaller copy. |
192 | 654k | pub fn is_largest_resolution_level(&self) -> bool { |
193 | 654k | self.level_index == Vec2(0, 0) |
194 | 654k | } |
195 | | } |
196 | | |
197 | | |
198 | | |
199 | | use crate::meta::{MetaData, BlockDescription, calculate_block_size}; |
200 | | |
201 | | impl CompressedScanLineBlock { |
202 | | |
203 | | /// Without validation, write this instance to the byte stream. |
204 | 0 | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { |
205 | 0 | debug_assert_ne!(self.compressed_pixels.len(), 0, "empty blocks should not be put in the file bug"); |
206 | | |
207 | 0 | i32::write(self.y_coordinate, write)?; |
208 | 0 | u8::write_i32_sized_slice(write, &self.compressed_pixels)?; |
209 | 0 | Ok(()) |
210 | 0 | } Unexecuted instantiation: <exr::block::chunk::CompressedScanLineBlock>::write::<_> Unexecuted instantiation: <exr::block::chunk::CompressedScanLineBlock>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> Unexecuted instantiation: <exr::block::chunk::CompressedScanLineBlock>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> |
211 | | |
212 | | /// Read the value without validating. |
213 | 1.59k | pub fn read(read: &mut impl Read, max_block_byte_size: usize) -> Result<Self> { |
214 | 1.59k | let y_coordinate = i32::read(read)?; |
215 | 1.52k | let compressed_pixels = u8::read_i32_sized_vec(read, max_block_byte_size, Some(max_block_byte_size), "scan line block sample count")?; |
216 | 1.42k | Ok(CompressedScanLineBlock { y_coordinate, compressed_pixels }) |
217 | 1.59k | } Unexecuted instantiation: <exr::block::chunk::CompressedScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedScanLineBlock>::read::<_> Unexecuted instantiation: <exr::block::chunk::CompressedScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> <exr::block::chunk::CompressedScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Line | Count | Source | 213 | 1.06k | pub fn read(read: &mut impl Read, max_block_byte_size: usize) -> Result<Self> { | 214 | 1.06k | let y_coordinate = i32::read(read)?; | 215 | 990 | let compressed_pixels = u8::read_i32_sized_vec(read, max_block_byte_size, Some(max_block_byte_size), "scan line block sample count")?; | 216 | 892 | Ok(CompressedScanLineBlock { y_coordinate, compressed_pixels }) | 217 | 1.06k | } |
Unexecuted instantiation: <exr::block::chunk::CompressedScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>> <exr::block::chunk::CompressedScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Line | Count | Source | 213 | 533 | pub fn read(read: &mut impl Read, max_block_byte_size: usize) -> Result<Self> { | 214 | 533 | let y_coordinate = i32::read(read)?; | 215 | 533 | let compressed_pixels = u8::read_i32_sized_vec(read, max_block_byte_size, Some(max_block_byte_size), "scan line block sample count")?; | 216 | 529 | Ok(CompressedScanLineBlock { y_coordinate, compressed_pixels }) | 217 | 533 | } |
|
218 | | } |
219 | | |
220 | | impl CompressedTileBlock { |
221 | | |
222 | | /// Without validation, write this instance to the byte stream. |
223 | 913 | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { |
224 | 913 | debug_assert_ne!(self.compressed_pixels.len(), 0, "empty blocks should not be put in the file bug"); |
225 | | |
226 | 913 | self.coordinates.write(write)?; |
227 | 913 | u8::write_i32_sized_slice(write, &self.compressed_pixels)?; |
228 | 913 | Ok(()) |
229 | 913 | } Unexecuted instantiation: <exr::block::chunk::CompressedTileBlock>::write::<_> Unexecuted instantiation: <exr::block::chunk::CompressedTileBlock>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> <exr::block::chunk::CompressedTileBlock>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> Line | Count | Source | 223 | 913 | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { | 224 | 913 | debug_assert_ne!(self.compressed_pixels.len(), 0, "empty blocks should not be put in the file bug"); | 225 | | | 226 | 913 | self.coordinates.write(write)?; | 227 | 913 | u8::write_i32_sized_slice(write, &self.compressed_pixels)?; | 228 | 913 | Ok(()) | 229 | 913 | } |
|
230 | | |
231 | | /// Read the value without validating. |
232 | 2.21k | pub fn read(read: &mut impl Read, max_block_byte_size: usize) -> Result<Self> { |
233 | 2.21k | let coordinates = TileCoordinates::read(read)?; |
234 | 1.06k | let compressed_pixels = u8::read_i32_sized_vec(read, max_block_byte_size, Some(max_block_byte_size), "tile block sample count")?; |
235 | 1.04k | Ok(CompressedTileBlock { coordinates, compressed_pixels }) |
236 | 2.21k | } Unexecuted instantiation: <exr::block::chunk::CompressedTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedTileBlock>::read::<_> Unexecuted instantiation: <exr::block::chunk::CompressedTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> <exr::block::chunk::CompressedTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Line | Count | Source | 232 | 1.29k | pub fn read(read: &mut impl Read, max_block_byte_size: usize) -> Result<Self> { | 233 | 1.29k | let coordinates = TileCoordinates::read(read)?; | 234 | 155 | let compressed_pixels = u8::read_i32_sized_vec(read, max_block_byte_size, Some(max_block_byte_size), "tile block sample count")?; | 235 | 133 | Ok(CompressedTileBlock { coordinates, compressed_pixels }) | 236 | 1.29k | } |
<exr::block::chunk::CompressedTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>> Line | Count | Source | 232 | 913 | pub fn read(read: &mut impl Read, max_block_byte_size: usize) -> Result<Self> { | 233 | 913 | let coordinates = TileCoordinates::read(read)?; | 234 | 913 | let compressed_pixels = u8::read_i32_sized_vec(read, max_block_byte_size, Some(max_block_byte_size), "tile block sample count")?; | 235 | 913 | Ok(CompressedTileBlock { coordinates, compressed_pixels }) | 236 | 913 | } |
Unexecuted instantiation: <exr::block::chunk::CompressedTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> |
237 | | } |
238 | | |
239 | | impl CompressedDeepScanLineBlock { |
240 | | |
241 | | /// Without validation, write this instance to the byte stream. |
242 | 0 | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { |
243 | 0 | debug_assert_ne!(self.compressed_sample_data.len(), 0, "empty blocks should not be put in the file bug"); |
244 | | |
245 | 0 | i32::write(self.y_coordinate, write)?; |
246 | 0 | u64::write(self.compressed_pixel_offset_table.len() as u64, write)?; |
247 | 0 | u64::write(self.compressed_sample_data.len() as u64, write)?; // TODO just guessed |
248 | 0 | u64::write(self.decompressed_sample_data_size as u64, write)?; |
249 | 0 | i8::write_slice(write, &self.compressed_pixel_offset_table)?; |
250 | 0 | u8::write_slice(write, &self.compressed_sample_data)?; |
251 | 0 | Ok(()) |
252 | 0 | } Unexecuted instantiation: <exr::block::chunk::CompressedDeepScanLineBlock>::write::<_> Unexecuted instantiation: <exr::block::chunk::CompressedDeepScanLineBlock>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepScanLineBlock>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> |
253 | | |
254 | | /// Read the value without validating. |
255 | 0 | pub fn read(read: &mut impl Read, max_block_byte_size: usize) -> Result<Self> { |
256 | 0 | let y_coordinate = i32::read(read)?; |
257 | 0 | let compressed_pixel_offset_table_size = u64_to_usize(u64::read(read)?); |
258 | 0 | let compressed_sample_data_size = u64_to_usize(u64::read(read)?); |
259 | 0 | let decompressed_sample_data_size = u64_to_usize(u64::read(read)?); |
260 | | |
261 | | // doc said i32, try u8 |
262 | 0 | let compressed_pixel_offset_table = i8::read_vec( |
263 | 0 | read, compressed_pixel_offset_table_size, |
264 | 0 | 6 * u16::MAX as usize, Some(max_block_byte_size), |
265 | 0 | "deep scan line block table size" |
266 | 0 | )?; |
267 | | |
268 | 0 | let compressed_sample_data = u8::read_vec( |
269 | 0 | read, compressed_sample_data_size, |
270 | 0 | 6 * u16::MAX as usize, Some(max_block_byte_size), |
271 | 0 | "deep scan line block sample count" |
272 | 0 | )?; |
273 | | |
274 | 0 | Ok(CompressedDeepScanLineBlock { |
275 | 0 | y_coordinate, |
276 | 0 | decompressed_sample_data_size, |
277 | 0 | compressed_pixel_offset_table, |
278 | 0 | compressed_sample_data, |
279 | 0 | }) |
280 | 0 | } Unexecuted instantiation: <exr::block::chunk::CompressedDeepScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepScanLineBlock>::read::<_> Unexecuted instantiation: <exr::block::chunk::CompressedDeepScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> |
281 | | } |
282 | | |
283 | | |
284 | | impl CompressedDeepTileBlock { |
285 | | |
286 | | /// Without validation, write this instance to the byte stream. |
287 | 0 | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { |
288 | 0 | debug_assert_ne!(self.compressed_sample_data.len(), 0, "empty blocks should not be put in the file bug"); |
289 | | |
290 | 0 | self.coordinates.write(write)?; |
291 | 0 | u64::write(self.compressed_pixel_offset_table.len() as u64, write)?; |
292 | 0 | u64::write(self.compressed_sample_data.len() as u64, write)?; // TODO just guessed |
293 | 0 | u64::write(self.decompressed_sample_data_size as u64, write)?; |
294 | 0 | i8::write_slice(write, &self.compressed_pixel_offset_table)?; |
295 | 0 | u8::write_slice(write, &self.compressed_sample_data)?; |
296 | 0 | Ok(()) |
297 | 0 | } Unexecuted instantiation: <exr::block::chunk::CompressedDeepTileBlock>::write::<_> Unexecuted instantiation: <exr::block::chunk::CompressedDeepTileBlock>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepTileBlock>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> |
298 | | |
299 | | /// Read the value without validating. |
300 | 0 | pub fn read(read: &mut impl Read, hard_max_block_byte_size: usize) -> Result<Self> { |
301 | 0 | let coordinates = TileCoordinates::read(read)?; |
302 | 0 | let compressed_pixel_offset_table_size = u64_to_usize(u64::read(read)?); |
303 | 0 | let compressed_sample_data_size = u64_to_usize(u64::read(read)?); // TODO u64 just guessed |
304 | 0 | let decompressed_sample_data_size = u64_to_usize(u64::read(read)?); |
305 | | |
306 | 0 | let compressed_pixel_offset_table = i8::read_vec( |
307 | 0 | read, compressed_pixel_offset_table_size, |
308 | 0 | 6 * u16::MAX as usize, Some(hard_max_block_byte_size), |
309 | 0 | "deep tile block table size" |
310 | 0 | )?; |
311 | | |
312 | 0 | let compressed_sample_data = u8::read_vec( |
313 | 0 | read, compressed_sample_data_size, |
314 | 0 | 6 * u16::MAX as usize, Some(hard_max_block_byte_size), |
315 | 0 | "deep tile block sample count" |
316 | 0 | )?; |
317 | | |
318 | 0 | Ok(CompressedDeepTileBlock { |
319 | 0 | coordinates, |
320 | 0 | decompressed_sample_data_size, |
321 | 0 | compressed_pixel_offset_table, |
322 | 0 | compressed_sample_data, |
323 | 0 | }) |
324 | 0 | } Unexecuted instantiation: <exr::block::chunk::CompressedDeepTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepTileBlock>::read::<_> Unexecuted instantiation: <exr::block::chunk::CompressedDeepTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>> Unexecuted instantiation: <exr::block::chunk::CompressedDeepTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> |
325 | | } |
326 | | |
327 | | use crate::error::{UnitResult, Result, Error, u64_to_usize, usize_to_i32, i32_to_usize}; |
328 | | use crate::math::Vec2; |
329 | | |
330 | | /// Validation of chunks is done while reading and writing the actual data. (For example in exr::full_image) |
331 | | impl Chunk { |
332 | | |
333 | | /// Without validation, write this instance to the byte stream. |
334 | 913 | pub fn write(&self, write: &mut impl Write, header_count: usize) -> UnitResult { |
335 | 913 | debug_assert!(self.layer_index < header_count, "layer index bug"); // validation is done in full_image or simple_image |
336 | | |
337 | 913 | if header_count != 1 { usize_to_i32(self.layer_index).write(write)?; } |
338 | 913 | else { assert_eq!(self.layer_index, 0, "invalid header index for single layer file"); } |
339 | | |
340 | 913 | match self.compressed_block { |
341 | 0 | CompressedBlock::ScanLine (ref value) => value.write(write), |
342 | 913 | CompressedBlock::Tile (ref value) => value.write(write), |
343 | 0 | CompressedBlock::DeepScanLine (ref value) => value.write(write), |
344 | 0 | CompressedBlock::DeepTile (ref value) => value.write(write), |
345 | | } |
346 | 913 | } Unexecuted instantiation: <exr::block::chunk::Chunk>::write::<_> Unexecuted instantiation: <exr::block::chunk::Chunk>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> <exr::block::chunk::Chunk>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> Line | Count | Source | 334 | 913 | pub fn write(&self, write: &mut impl Write, header_count: usize) -> UnitResult { | 335 | 913 | debug_assert!(self.layer_index < header_count, "layer index bug"); // validation is done in full_image or simple_image | 336 | | | 337 | 913 | if header_count != 1 { usize_to_i32(self.layer_index).write(write)?; } | 338 | 913 | else { assert_eq!(self.layer_index, 0, "invalid header index for single layer file"); } | 339 | | | 340 | 913 | match self.compressed_block { | 341 | 0 | CompressedBlock::ScanLine (ref value) => value.write(write), | 342 | 913 | CompressedBlock::Tile (ref value) => value.write(write), | 343 | 0 | CompressedBlock::DeepScanLine (ref value) => value.write(write), | 344 | 0 | CompressedBlock::DeepTile (ref value) => value.write(write), | 345 | | } | 346 | 913 | } |
|
347 | | |
348 | | /// Read the value without validating. |
349 | 3.81k | pub fn read(read: &mut impl Read, meta_data: &MetaData) -> Result<Self> { |
350 | 3.81k | let layer_number = i32_to_usize( |
351 | 3.81k | if meta_data.requirements.is_multilayer() { i32::read(read)? } // documentation says u64, but is i32 |
352 | 3.80k | else { 0_i32 }, // reference the first header for single-layer images |
353 | | "chunk data part number" |
354 | 0 | )?; |
355 | | |
356 | 3.81k | if layer_number >= meta_data.headers.len() { |
357 | 1 | return Err(Error::invalid("chunk data part number")); |
358 | 3.80k | } |
359 | 3.80k | |
360 | 3.80k | let header = &meta_data.headers[layer_number]; |
361 | 3.80k | let max_block_byte_size = header.max_block_byte_size(); |
362 | | |
363 | 2.46k | let chunk = Chunk { |
364 | 3.80k | layer_index: layer_number, |
365 | 1.59k | compressed_block: match header.blocks { |
366 | | // flat data |
367 | 1.59k | BlockDescription::ScanLines if !header.deep => CompressedBlock::ScanLine(CompressedScanLineBlock::read(read, max_block_byte_size)?), |
368 | 2.21k | BlockDescription::Tiles(_) if !header.deep => CompressedBlock::Tile(CompressedTileBlock::read(read, max_block_byte_size)?), |
369 | | |
370 | | // deep data |
371 | 0 | BlockDescription::ScanLines => CompressedBlock::DeepScanLine(CompressedDeepScanLineBlock::read(read, max_block_byte_size)?), |
372 | 0 | BlockDescription::Tiles(_) => CompressedBlock::DeepTile(CompressedDeepTileBlock::read(read, max_block_byte_size)?), |
373 | | }, |
374 | | }; |
375 | | |
376 | 2.46k | Ok(chunk) |
377 | 3.81k | } Unexecuted instantiation: <exr::block::chunk::Chunk>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::Chunk>::read::<_> Unexecuted instantiation: <exr::block::chunk::Chunk>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::Chunk>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::Chunk>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::Chunk>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::Chunk>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::Chunk>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::Chunk>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::Chunk>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Unexecuted instantiation: <exr::block::chunk::Chunk>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> <exr::block::chunk::Chunk>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Line | Count | Source | 349 | 2.36k | pub fn read(read: &mut impl Read, meta_data: &MetaData) -> Result<Self> { | 350 | 2.36k | let layer_number = i32_to_usize( | 351 | 2.36k | if meta_data.requirements.is_multilayer() { i32::read(read)? } // documentation says u64, but is i32 | 352 | 2.36k | else { 0_i32 }, // reference the first header for single-layer images | 353 | | "chunk data part number" | 354 | 0 | )?; | 355 | | | 356 | 2.36k | if layer_number >= meta_data.headers.len() { | 357 | 1 | return Err(Error::invalid("chunk data part number")); | 358 | 2.36k | } | 359 | 2.36k | | 360 | 2.36k | let header = &meta_data.headers[layer_number]; | 361 | 2.36k | let max_block_byte_size = header.max_block_byte_size(); | 362 | | | 363 | 1.02k | let chunk = Chunk { | 364 | 2.36k | layer_index: layer_number, | 365 | 1.06k | compressed_block: match header.blocks { | 366 | | // flat data | 367 | 1.06k | BlockDescription::ScanLines if !header.deep => CompressedBlock::ScanLine(CompressedScanLineBlock::read(read, max_block_byte_size)?), | 368 | 1.29k | BlockDescription::Tiles(_) if !header.deep => CompressedBlock::Tile(CompressedTileBlock::read(read, max_block_byte_size)?), | 369 | | | 370 | | // deep data | 371 | 0 | BlockDescription::ScanLines => CompressedBlock::DeepScanLine(CompressedDeepScanLineBlock::read(read, max_block_byte_size)?), | 372 | 0 | BlockDescription::Tiles(_) => CompressedBlock::DeepTile(CompressedDeepTileBlock::read(read, max_block_byte_size)?), | 373 | | }, | 374 | | }; | 375 | | | 376 | 1.02k | Ok(chunk) | 377 | 2.36k | } |
<exr::block::chunk::Chunk>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>> Line | Count | Source | 349 | 913 | pub fn read(read: &mut impl Read, meta_data: &MetaData) -> Result<Self> { | 350 | 913 | let layer_number = i32_to_usize( | 351 | 913 | if meta_data.requirements.is_multilayer() { i32::read(read)? } // documentation says u64, but is i32 | 352 | 913 | else { 0_i32 }, // reference the first header for single-layer images | 353 | | "chunk data part number" | 354 | 0 | )?; | 355 | | | 356 | 913 | if layer_number >= meta_data.headers.len() { | 357 | 0 | return Err(Error::invalid("chunk data part number")); | 358 | 913 | } | 359 | 913 | | 360 | 913 | let header = &meta_data.headers[layer_number]; | 361 | 913 | let max_block_byte_size = header.max_block_byte_size(); | 362 | | | 363 | 913 | let chunk = Chunk { | 364 | 913 | layer_index: layer_number, | 365 | 0 | compressed_block: match header.blocks { | 366 | | // flat data | 367 | 0 | BlockDescription::ScanLines if !header.deep => CompressedBlock::ScanLine(CompressedScanLineBlock::read(read, max_block_byte_size)?), | 368 | 913 | BlockDescription::Tiles(_) if !header.deep => CompressedBlock::Tile(CompressedTileBlock::read(read, max_block_byte_size)?), | 369 | | | 370 | | // deep data | 371 | 0 | BlockDescription::ScanLines => CompressedBlock::DeepScanLine(CompressedDeepScanLineBlock::read(read, max_block_byte_size)?), | 372 | 0 | BlockDescription::Tiles(_) => CompressedBlock::DeepTile(CompressedDeepTileBlock::read(read, max_block_byte_size)?), | 373 | | }, | 374 | | }; | 375 | | | 376 | 913 | Ok(chunk) | 377 | 913 | } |
<exr::block::chunk::Chunk>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Line | Count | Source | 349 | 533 | pub fn read(read: &mut impl Read, meta_data: &MetaData) -> Result<Self> { | 350 | 533 | let layer_number = i32_to_usize( | 351 | 533 | if meta_data.requirements.is_multilayer() { i32::read(read)? } // documentation says u64, but is i32 | 352 | 533 | else { 0_i32 }, // reference the first header for single-layer images | 353 | | "chunk data part number" | 354 | 0 | )?; | 355 | | | 356 | 533 | if layer_number >= meta_data.headers.len() { | 357 | 0 | return Err(Error::invalid("chunk data part number")); | 358 | 533 | } | 359 | 533 | | 360 | 533 | let header = &meta_data.headers[layer_number]; | 361 | 533 | let max_block_byte_size = header.max_block_byte_size(); | 362 | | | 363 | 529 | let chunk = Chunk { | 364 | 533 | layer_index: layer_number, | 365 | 533 | compressed_block: match header.blocks { | 366 | | // flat data | 367 | 533 | BlockDescription::ScanLines if !header.deep => CompressedBlock::ScanLine(CompressedScanLineBlock::read(read, max_block_byte_size)?), | 368 | 0 | BlockDescription::Tiles(_) if !header.deep => CompressedBlock::Tile(CompressedTileBlock::read(read, max_block_byte_size)?), | 369 | | | 370 | | // deep data | 371 | 0 | BlockDescription::ScanLines => CompressedBlock::DeepScanLine(CompressedDeepScanLineBlock::read(read, max_block_byte_size)?), | 372 | 0 | BlockDescription::Tiles(_) => CompressedBlock::DeepTile(CompressedDeepTileBlock::read(read, max_block_byte_size)?), | 373 | | }, | 374 | | }; | 375 | | | 376 | 529 | Ok(chunk) | 377 | 533 | } |
|
378 | | } |
379 | | |