Coverage Report

Created: 2026-07-16 07:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}