Coverage Report

Created: 2025-10-10 07:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/exr-1.73.0/src/block/lines.rs
Line
Count
Source
1
//! Extract lines from a block of pixel bytes.
2
3
use crate::math::*;
4
use std::io::{Cursor};
5
use crate::error::{Result, UnitResult};
6
use smallvec::SmallVec;
7
use std::ops::Range;
8
use crate::block::{BlockIndex};
9
use crate::meta::attribute::ChannelList;
10
11
12
/// A single line of pixels.
13
/// Use [LineRef] or [LineRefMut] for easier type names.
14
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
15
pub struct LineSlice<T> {
16
17
    // TODO also store enum SampleType, as it would always be matched in every place it is used
18
19
    /// Where this line is located inside the image.
20
    pub location: LineIndex,
21
22
    /// The raw bytes of the pixel line, either `&[u8]` or `&mut [u8]`.
23
    /// Must be re-interpreted as slice of f16, f32, or u32,
24
    /// according to the channel data type.
25
    pub value: T,
26
}
27
28
29
/// An reference to a single line of pixels.
30
/// May go across the whole image or just a tile section of it.
31
///
32
/// This line contains an immutable slice that all samples will be read from.
33
pub type LineRef<'s> = LineSlice<&'s [u8]>;
34
35
/// A reference to a single mutable line of pixels.
36
/// May go across the whole image or just a tile section of it.
37
///
38
/// This line contains a mutable slice that all samples will be written to.
39
pub type LineRefMut<'s> = LineSlice<&'s mut [u8]>;
40
41
42
/// Specifies where a row of pixels lies inside an image.
43
/// This is a globally unique identifier which includes
44
/// the layer, channel index, and pixel location.
45
#[derive(Clone, Copy, Eq, PartialEq, Debug, Hash)]
46
pub struct LineIndex {
47
48
    /// Index of the layer.
49
    pub layer: usize,
50
51
    /// The channel index of the layer.
52
    pub channel: usize,
53
54
    /// Index of the mip or rip level in the image.
55
    pub level: Vec2<usize>,
56
57
    /// Position of the most left pixel of the row.
58
    pub position: Vec2<usize>,
59
60
    /// The width of the line; the number of samples in this row,
61
    /// that is, the number of f16, f32, or u32 values.
62
    pub sample_count: usize,
63
}
64
65
66
impl LineIndex {
67
68
    /// Iterates the lines of this block index in interleaved fashion:
69
    /// For each line in this block, this iterator steps once through each channel.
70
    /// This is how lines are stored in a pixel data block.
71
    ///
72
    /// Does not check whether `self.layer_index`, `self.level`, `self.size` and `self.position` are valid indices.__
73
    // TODO be sure this cannot produce incorrect data, as this is not further checked but only handled with panics
74
    #[inline]
75
    #[must_use]
76
0
    pub fn lines_in_block(block: BlockIndex, channels: &ChannelList) -> impl Iterator<Item=(Range<usize>, LineIndex)> {
77
        struct LineIter {
78
            layer: usize, level: Vec2<usize>, width: usize,
79
            end_y: usize, x: usize, channel_sizes: SmallVec<[usize; 8]>,
80
            byte: usize, channel: usize, y: usize,
81
        }
82
83
        // FIXME what about sub sampling??
84
85
        impl Iterator for LineIter {
86
            type Item = (Range<usize>, LineIndex);
87
            // TODO size hint?
88
89
0
            fn next(&mut self) -> Option<Self::Item> {
90
0
                if self.y < self.end_y {
91
92
                    // compute return value before incrementing
93
0
                    let byte_len = self.channel_sizes[self.channel];
94
0
                    let return_value = (
95
0
                        (self.byte .. self.byte + byte_len),
96
0
                        LineIndex {
97
0
                            channel: self.channel,
98
0
                            layer: self.layer,
99
0
                            level: self.level,
100
0
                            position: Vec2(self.x, self.y),
101
0
                            sample_count: self.width,
102
0
                        }
103
0
                    );
104
105
                    { // increment indices
106
0
                        self.byte += byte_len;
107
0
                        self.channel += 1;
108
109
0
                        if self.channel == self.channel_sizes.len() {
110
0
                            self.channel = 0;
111
0
                            self.y += 1;
112
0
                        }
113
                    }
114
115
0
                    Some(return_value)
116
                }
117
118
                else {
119
0
                    None
120
                }
121
0
            }
122
        }
123
124
0
        let channel_line_sizes: SmallVec<[usize; 8]> = channels.list.iter()
125
0
            .map(move |channel| block.pixel_size.0 * channel.sample_type.bytes_per_sample()) // FIXME is it fewer samples per tile or just fewer tiles for sampled images???
126
0
            .collect();
127
128
0
        LineIter {
129
0
            layer: block.layer,
130
0
            level: block.level,
131
0
            width: block.pixel_size.0,
132
0
            x: block.pixel_position.0,
133
0
            end_y: block.pixel_position.y() + block.pixel_size.height(),
134
0
            channel_sizes: channel_line_sizes,
135
0
136
0
            byte: 0,
137
0
            channel: 0,
138
0
            y: block.pixel_position.y()
139
0
        }
140
0
    }
141
}
142
143
144
145
impl<'s> LineRefMut<'s> {
146
147
    /// Writes the samples (f16, f32, u32 values) into this line value reference.
148
    /// Use `write_samples` if there is not slice available.
149
    #[inline]
150
    #[must_use]
151
0
    pub fn write_samples_from_slice<T: crate::io::Data>(self, slice: &[T]) -> UnitResult {
152
0
        debug_assert_eq!(slice.len(), self.location.sample_count, "slice size does not match the line width");
153
0
        debug_assert_eq!(self.value.len(), self.location.sample_count * T::BYTE_SIZE, "sample type size does not match line byte size");
154
155
0
        T::write_slice(&mut Cursor::new(self.value), slice)
156
0
    }
Unexecuted instantiation: <exr::block::lines::LineSlice<&mut [u8]>>::write_samples_from_slice::<half::binary16::f16>
Unexecuted instantiation: <exr::block::lines::LineSlice<&mut [u8]>>::write_samples_from_slice::<f32>
Unexecuted instantiation: <exr::block::lines::LineSlice<&mut [u8]>>::write_samples_from_slice::<u32>
157
158
    /// Iterate over all samples in this line, from left to right.
159
    /// The supplied `get_line` function returns the sample value
160
    /// for a given sample index within the line,
161
    /// which starts at zero for each individual line.
162
    /// Use `write_samples_from_slice` if you already have a slice of samples.
163
    #[inline]
164
    #[must_use]
165
0
    pub fn write_samples<T: crate::io::Data>(self, mut get_sample: impl FnMut(usize) -> T) -> UnitResult {
166
0
        debug_assert_eq!(self.value.len(), self.location.sample_count * T::BYTE_SIZE, "sample type size does not match line byte size");
167
168
0
        let mut write = Cursor::new(self.value);
169
170
0
        for index in 0..self.location.sample_count {
171
0
            T::write(get_sample(index), &mut write)?;
172
        }
173
174
0
        Ok(())
175
0
    }
176
}
177
178
impl LineRef<'_> {
179
180
    /// Read the samples (f16, f32, u32 values) from this line value reference.
181
    /// Use `read_samples` if there is not slice available.
182
0
    pub fn read_samples_into_slice<T: crate::io::Data>(self, slice: &mut [T]) -> UnitResult {
183
0
        debug_assert_eq!(slice.len(), self.location.sample_count, "slice size does not match the line width");
184
0
        debug_assert_eq!(self.value.len(), self.location.sample_count * T::BYTE_SIZE, "sample type size does not match line byte size");
185
186
0
        T::read_slice(&mut Cursor::new(self.value), slice)
187
0
    }
Unexecuted instantiation: <exr::block::lines::LineSlice<&[u8]>>::read_samples_into_slice::<half::binary16::f16>
Unexecuted instantiation: <exr::block::lines::LineSlice<&[u8]>>::read_samples_into_slice::<f32>
Unexecuted instantiation: <exr::block::lines::LineSlice<&[u8]>>::read_samples_into_slice::<u32>
188
189
    /// Iterate over all samples in this line, from left to right.
190
    /// Use `read_sample_into_slice` if you already have a slice of samples.
191
0
    pub fn read_samples<T: crate::io::Data>(&self) -> impl Iterator<Item = Result<T>> + '_ {
192
0
        debug_assert_eq!(self.value.len(), self.location.sample_count * T::BYTE_SIZE, "sample type size does not match line byte size");
193
194
0
        let mut read = self.value; // FIXME deep data
195
0
        (0..self.location.sample_count).map(move |_| T::read(&mut read))
196
0
    }
197
}