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