/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 | | } |