/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 | 757k | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { |
153 | 757k | i32::write_le(usize_to_i32(self.tile_index.x(), "tile x")?, write)?; |
154 | 757k | i32::write_le(usize_to_i32(self.tile_index.y(), "tile y")?, write)?; |
155 | 757k | i32::write_le(usize_to_i32(self.level_index.x(), "level x")?, write)?; |
156 | 757k | i32::write_le(usize_to_i32(self.level_index.y(), "level y")?, write)?; |
157 | 757k | Ok(()) |
158 | 757k | } 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 | 152 | 757k | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { | 153 | 757k | i32::write_le(usize_to_i32(self.tile_index.x(), "tile x")?, write)?; | 154 | 757k | i32::write_le(usize_to_i32(self.tile_index.y(), "tile y")?, write)?; | 155 | 757k | i32::write_le(usize_to_i32(self.level_index.x(), "level x")?, write)?; | 156 | 757k | i32::write_le(usize_to_i32(self.level_index.y(), "level y")?, write)?; | 157 | 757k | Ok(()) | 158 | 757k | } |
|
159 | | |
160 | | /// Read the value without validating. |
161 | 759k | pub fn read(read: &mut impl Read) -> Result<Self> { |
162 | 759k | let tile_x = i32::read_le(read)?; |
163 | 758k | let tile_y = i32::read_le(read)?; |
164 | | |
165 | 758k | let level_x = i32::read_le(read)?; |
166 | 758k | let level_y = i32::read_le(read)?; |
167 | | |
168 | 758k | 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 | 701 | return Err(Error::invalid("level index exceeding integer maximum")); |
172 | 758k | } |
173 | | |
174 | | Ok(Self { |
175 | 758k | tile_index: Vec2(tile_x, tile_y).to_usize("tile coordinate index")?, |
176 | 758k | level_index: Vec2(level_x, level_y).to_usize("tile coordinate level")?, |
177 | | }) |
178 | 759k | } <exr::block::chunk::TileCoordinates>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Line | Count | Source | 161 | 1.41k | pub fn read(read: &mut impl Read) -> Result<Self> { | 162 | 1.41k | let tile_x = i32::read_le(read)?; | 163 | 1.13k | let tile_y = i32::read_le(read)?; | 164 | | | 165 | 1.12k | let level_x = i32::read_le(read)?; | 166 | 1.12k | let level_y = i32::read_le(read)?; | 167 | | | 168 | 1.12k | 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 | 701 | return Err(Error::invalid("level index exceeding integer maximum")); | 172 | 425 | } | 173 | | | 174 | | Ok(Self { | 175 | 425 | tile_index: Vec2(tile_x, tile_y).to_usize("tile coordinate index")?, | 176 | 386 | level_index: Vec2(level_x, level_y).to_usize("tile coordinate level")?, | 177 | | }) | 178 | 1.41k | } |
Unexecuted instantiation: <exr::block::chunk::TileCoordinates>::read::<_> <exr::block::chunk::TileCoordinates>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>> Line | Count | Source | 161 | 757k | pub fn read(read: &mut impl Read) -> Result<Self> { | 162 | 757k | let tile_x = i32::read_le(read)?; | 163 | 757k | let tile_y = i32::read_le(read)?; | 164 | | | 165 | 757k | let level_x = i32::read_le(read)?; | 166 | 757k | let level_y = i32::read_le(read)?; | 167 | | | 168 | 757k | 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 | 757k | } | 173 | | | 174 | | Ok(Self { | 175 | 757k | tile_index: Vec2(tile_x, tile_y).to_usize("tile coordinate index")?, | 176 | 757k | level_index: Vec2(level_x, level_y).to_usize("tile coordinate level")?, | 177 | | }) | 178 | 757k | } |
|
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 | 3.47M | pub fn to_data_indices( |
184 | 3.47M | &self, |
185 | 3.47M | tile_size: Vec2<usize>, |
186 | 3.47M | max: Vec2<usize>, |
187 | 3.47M | ) -> Result<IntegerBounds> { |
188 | 3.47M | let x = self.tile_index.x() * tile_size.width(); |
189 | 3.47M | let y = self.tile_index.y() * tile_size.height(); |
190 | | |
191 | 3.47M | if x >= max.x() || y >= max.y() { |
192 | 126 | Err(Error::invalid("tile index")) |
193 | | } else { |
194 | | Ok(IntegerBounds { |
195 | 3.47M | position: Vec2(usize_to_i32(x, "tile x")?, usize_to_i32(y, "tile y")?), |
196 | | size: Vec2( |
197 | 3.47M | calculate_block_size(max.x(), tile_size.width(), x)?, |
198 | 3.47M | calculate_block_size(max.y(), tile_size.height(), y)?, |
199 | | ), |
200 | | }) |
201 | | } |
202 | 3.47M | } |
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 | 1.67M | pub fn is_largest_resolution_level(&self) -> bool { |
217 | 1.67M | self.level_index == Vec2(0, 0) |
218 | 1.67M | } |
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 | 6.71k | pub fn read(read: &mut impl Read, max_block_byte_size: usize) -> Result<Self> { |
239 | 6.71k | let y_coordinate = i32::read_le(read)?; |
240 | 6.42k | let compressed_pixels_le = u8::read_i32_sized_vec_le( |
241 | 6.42k | read, |
242 | 6.42k | max_block_byte_size, |
243 | 6.42k | Some(max_block_byte_size), |
244 | | "scan line block sample count", |
245 | 327 | )?; |
246 | 6.09k | Ok(Self { |
247 | 6.09k | y_coordinate, |
248 | 6.09k | compressed_pixels_le, |
249 | 6.09k | }) |
250 | 6.71k | } <exr::block::chunk::CompressedScanLineBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Line | Count | Source | 238 | 6.71k | pub fn read(read: &mut impl Read, max_block_byte_size: usize) -> Result<Self> { | 239 | 6.71k | let y_coordinate = i32::read_le(read)?; | 240 | 6.42k | let compressed_pixels_le = u8::read_i32_sized_vec_le( | 241 | 6.42k | read, | 242 | 6.42k | max_block_byte_size, | 243 | 6.42k | Some(max_block_byte_size), | 244 | | "scan line block sample count", | 245 | 327 | )?; | 246 | 6.09k | Ok(Self { | 247 | 6.09k | y_coordinate, | 248 | 6.09k | compressed_pixels_le, | 249 | 6.09k | }) | 250 | 6.71k | } |
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 | 757k | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { |
256 | 757k | 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 | 757k | self.coordinates.write(write)?; |
263 | 757k | u8::write_i32_sized_slice_le(write, &self.compressed_pixels_le)?; |
264 | 757k | Ok(()) |
265 | 757k | } 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 | 255 | 757k | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { | 256 | 757k | 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 | 757k | self.coordinates.write(write)?; | 263 | 757k | u8::write_i32_sized_slice_le(write, &self.compressed_pixels_le)?; | 264 | 757k | Ok(()) | 265 | 757k | } |
|
266 | | |
267 | | /// Read the value without validating. |
268 | 759k | pub fn read(read: &mut impl Read, max_block_byte_size: usize) -> Result<Self> { |
269 | 759k | let coordinates = TileCoordinates::read(read)?; |
270 | 757k | let compressed_pixels_le = u8::read_i32_sized_vec_le( |
271 | 757k | read, |
272 | 757k | max_block_byte_size, |
273 | 757k | Some(max_block_byte_size), |
274 | | "tile block sample count", |
275 | 14 | )?; |
276 | 757k | Ok(Self { |
277 | 757k | coordinates, |
278 | 757k | compressed_pixels_le, |
279 | 757k | }) |
280 | 759k | } <exr::block::chunk::CompressedTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Line | Count | Source | 268 | 1.41k | pub fn read(read: &mut impl Read, max_block_byte_size: usize) -> Result<Self> { | 269 | 1.41k | let coordinates = TileCoordinates::read(read)?; | 270 | 352 | let compressed_pixels_le = u8::read_i32_sized_vec_le( | 271 | 352 | read, | 272 | 352 | max_block_byte_size, | 273 | 352 | Some(max_block_byte_size), | 274 | | "tile block sample count", | 275 | 14 | )?; | 276 | 338 | Ok(Self { | 277 | 338 | coordinates, | 278 | 338 | compressed_pixels_le, | 279 | 338 | }) | 280 | 1.41k | } |
Unexecuted instantiation: <exr::block::chunk::CompressedTileBlock>::read::<_> <exr::block::chunk::CompressedTileBlock>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>> Line | Count | Source | 268 | 757k | pub fn read(read: &mut impl Read, max_block_byte_size: usize) -> Result<Self> { | 269 | 757k | let coordinates = TileCoordinates::read(read)?; | 270 | 757k | let compressed_pixels_le = u8::read_i32_sized_vec_le( | 271 | 757k | read, | 272 | 757k | max_block_byte_size, | 273 | 757k | Some(max_block_byte_size), | 274 | | "tile block sample count", | 275 | 0 | )?; | 276 | 757k | Ok(Self { | 277 | 757k | coordinates, | 278 | 757k | compressed_pixels_le, | 279 | 757k | }) | 280 | 757k | } |
|
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 | 757k | pub fn write(&self, write: &mut impl Write, header_count: usize) -> UnitResult { |
396 | 757k | debug_assert!(self.layer_index < header_count, "layer index bug"); // validation is done in full_image or simple_image |
397 | | |
398 | 757k | if header_count == 1 { |
399 | 757k | 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 | 757k | match self.compressed_block { |
405 | 0 | CompressedBlock::ScanLine(ref value) => value.write(write), |
406 | 757k | 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 | 757k | } 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 | 395 | 757k | pub fn write(&self, write: &mut impl Write, header_count: usize) -> UnitResult { | 396 | 757k | debug_assert!(self.layer_index < header_count, "layer index bug"); // validation is done in full_image or simple_image | 397 | | | 398 | 757k | if header_count == 1 { | 399 | 757k | 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 | 757k | match self.compressed_block { | 405 | 0 | CompressedBlock::ScanLine(ref value) => value.write(write), | 406 | 757k | 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 | 757k | } |
|
411 | | |
412 | | /// Read the value without validating. |
413 | 766k | pub fn read(read: &mut impl Read, meta_data: &MetaData) -> Result<Self> { |
414 | 765k | let layer_number = i32_to_usize( |
415 | 766k | if meta_data.requirements.is_multilayer() { |
416 | 530 | i32::read_le(read)? |
417 | | } |
418 | | // documentation says u64, but is i32 |
419 | | else { |
420 | 765k | 0_i32 |
421 | | }, // reference the first header for single-layer images |
422 | | "chunk data part number", |
423 | 19 | )?; |
424 | | |
425 | 765k | if layer_number >= meta_data.headers.len() { |
426 | 159 | return Err(Error::invalid("chunk data part number")); |
427 | 765k | } |
428 | | |
429 | 765k | let header = &meta_data.headers[layer_number]; |
430 | 765k | let max_block_byte_size = header.max_block_byte_size(); |
431 | | |
432 | 764k | let chunk = Self { |
433 | 765k | layer_index: layer_number, |
434 | 6.71k | compressed_block: match header.blocks { |
435 | | // flat data |
436 | 6.71k | BlockDescription::ScanLines if !header.deep => CompressedBlock::ScanLine( |
437 | 6.71k | CompressedScanLineBlock::read(read, max_block_byte_size)?, |
438 | | ), |
439 | 759k | BlockDescription::Tiles(_) if !header.deep => { |
440 | 759k | 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 | 764k | Ok(chunk) |
454 | 766k | } <exr::block::chunk::Chunk>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Line | Count | Source | 413 | 8.58k | pub fn read(read: &mut impl Read, meta_data: &MetaData) -> Result<Self> { | 414 | 8.30k | let layer_number = i32_to_usize( | 415 | 8.58k | if meta_data.requirements.is_multilayer() { | 416 | 530 | i32::read_le(read)? | 417 | | } | 418 | | // documentation says u64, but is i32 | 419 | | else { | 420 | 8.05k | 0_i32 | 421 | | }, // reference the first header for single-layer images | 422 | | "chunk data part number", | 423 | 19 | )?; | 424 | | | 425 | 8.28k | if layer_number >= meta_data.headers.len() { | 426 | 159 | return Err(Error::invalid("chunk data part number")); | 427 | 8.12k | } | 428 | | | 429 | 8.12k | let header = &meta_data.headers[layer_number]; | 430 | 8.12k | let max_block_byte_size = header.max_block_byte_size(); | 431 | | | 432 | 6.43k | let chunk = Self { | 433 | 8.12k | layer_index: layer_number, | 434 | 6.71k | compressed_block: match header.blocks { | 435 | | // flat data | 436 | 6.71k | BlockDescription::ScanLines if !header.deep => CompressedBlock::ScanLine( | 437 | 6.71k | CompressedScanLineBlock::read(read, max_block_byte_size)?, | 438 | | ), | 439 | 1.41k | BlockDescription::Tiles(_) if !header.deep => { | 440 | 1.41k | 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 | 6.43k | Ok(chunk) | 454 | 8.58k | } |
Unexecuted instantiation: <exr::block::chunk::Chunk>::read::<_> <exr::block::chunk::Chunk>::read::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>> Line | Count | Source | 413 | 757k | pub fn read(read: &mut impl Read, meta_data: &MetaData) -> Result<Self> { | 414 | 757k | let layer_number = i32_to_usize( | 415 | 757k | if meta_data.requirements.is_multilayer() { | 416 | 0 | i32::read_le(read)? | 417 | | } | 418 | | // documentation says u64, but is i32 | 419 | | else { | 420 | 757k | 0_i32 | 421 | | }, // reference the first header for single-layer images | 422 | | "chunk data part number", | 423 | 0 | )?; | 424 | | | 425 | 757k | if layer_number >= meta_data.headers.len() { | 426 | 0 | return Err(Error::invalid("chunk data part number")); | 427 | 757k | } | 428 | | | 429 | 757k | let header = &meta_data.headers[layer_number]; | 430 | 757k | let max_block_byte_size = header.max_block_byte_size(); | 431 | | | 432 | 757k | let chunk = Self { | 433 | 757k | 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 | 757k | BlockDescription::Tiles(_) if !header.deep => { | 440 | 757k | 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 | 757k | Ok(chunk) | 454 | 757k | } |
|
455 | | } |