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