diff options
Diffstat (limited to 'vendor/exr/src/image/read/levels.rs')
-rw-r--r-- | vendor/exr/src/image/read/levels.rs | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/vendor/exr/src/image/read/levels.rs b/vendor/exr/src/image/read/levels.rs new file mode 100644 index 0000000..5705903 --- /dev/null +++ b/vendor/exr/src/image/read/levels.rs @@ -0,0 +1,219 @@ +//! How to read a set of resolution levels. + +use crate::meta::*; +use crate::image::*; +use crate::error::*; +use crate::meta::attribute::*; +use crate::image::read::any_channels::*; +use crate::block::chunk::TileCoordinates; +use crate::image::read::specific_channels::*; +use crate::image::recursive::*; +use crate::math::Vec2; +use crate::block::lines::LineRef; +use crate::block::samples::*; +use crate::meta::header::{Header}; + + +// Note: In the resulting image, the `FlatSamples` are placed +// directly inside the channels, without `LargestLevel<>` indirection +/// Specify to read only the highest resolution level, skipping all smaller variations. +/// The sample storage can be [`ReadFlatSamples`]. +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct ReadLargestLevel<DeepOrFlatSamples> { + + /// The sample reading specification + pub read_samples: DeepOrFlatSamples +} + + +// FIXME rgba levels??? + +// Read the largest level, directly, without intermediate structs +impl<DeepOrFlatSamples> ReadLargestLevel<DeepOrFlatSamples> { + + /// Read all arbitrary channels in each layer. + pub fn all_channels(self) -> ReadAnyChannels<DeepOrFlatSamples> { ReadAnyChannels { read_samples: self.read_samples } } // Instead of Self, the `FlatSamples` are used directly + + /// Read only layers that contain rgba channels. Skips any other channels in the layer. + /// The alpha channel will contain the value `1.0` if no alpha channel can be found in the image. + /// + /// Using two closures, define how to store the pixels. + /// The first closure creates an image, and the second closure inserts a single pixel. + /// The type of the pixel can be defined by the second closure; + /// it must be a tuple containing four values, each being either `f16`, `f32`, `u32` or `Sample`. + /// + /// Throws an error for images with deep data or subsampling. + /// Use `specific_channels` or `all_channels` if you want to read something other than rgba. + pub fn rgba_channels<R,G,B,A, Create, Set, Pixels>( + self, create_pixels: Create, set_pixel: Set + ) -> CollectPixels< + ReadOptionalChannel<ReadRequiredChannel<ReadRequiredChannel<ReadRequiredChannel<NoneMore, R>, G>, B>, A>, + (R, G, B, A), Pixels, Create, Set + > + where + R: FromNativeSample, G: FromNativeSample, B: FromNativeSample, A: FromNativeSample, + Create: Fn(Vec2<usize>, &RgbaChannels) -> Pixels, + Set: Fn(&mut Pixels, Vec2<usize>, (R,G,B,A)), + { + self.specific_channels() + .required("R").required("G").required("B") + .optional("A", A::from_f32(1.0)) + .collect_pixels(create_pixels, set_pixel) + } + + /// Read only layers that contain rgb channels. Skips any other channels in the layer. + /// + /// Using two closures, define how to store the pixels. + /// The first closure creates an image, and the second closure inserts a single pixel. + /// The type of the pixel can be defined by the second closure; + /// it must be a tuple containing three values, each being either `f16`, `f32`, `u32` or `Sample`. + /// + /// Throws an error for images with deep data or subsampling. + /// Use `specific_channels` or `all_channels` if you want to read something other than rgb. + pub fn rgb_channels<R,G,B, Create, Set, Pixels>( + self, create_pixels: Create, set_pixel: Set + ) -> CollectPixels< + ReadRequiredChannel<ReadRequiredChannel<ReadRequiredChannel<NoneMore, R>, G>, B>, + (R, G, B), Pixels, Create, Set + > + where + R: FromNativeSample, G: FromNativeSample, B: FromNativeSample, + Create: Fn(Vec2<usize>, &RgbChannels) -> Pixels, + Set: Fn(&mut Pixels, Vec2<usize>, (R,G,B)), + { + self.specific_channels() + .required("R").required("G").required("B") + .collect_pixels(create_pixels, set_pixel) + } + + /// Read only layers that contain the specified channels, skipping any other channels in the layer. + /// Further specify which channels should be included by calling `.required("ChannelName")` + /// or `.optional("ChannelName", default_value)` on the result of this function. + /// Call `collect_pixels` afterwards to define the pixel container for your set of channels. + /// + /// Throws an error for images with deep data or subsampling. + pub fn specific_channels(self) -> ReadZeroChannels { + ReadZeroChannels { } + } +} + +/// Specify to read all contained resolution levels from the image, if any. +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct ReadAllLevels<DeepOrFlatSamples> { + + /// The sample reading specification + pub read_samples: DeepOrFlatSamples +} + +impl<ReadDeepOrFlatSamples> ReadAllLevels<ReadDeepOrFlatSamples> { + + /// Read all arbitrary channels in each layer. + pub fn all_channels(self) -> ReadAnyChannels<Self> { ReadAnyChannels { read_samples: self } } + + // TODO specific channels for multiple resolution levels + +} + +/*pub struct ReadLevels<S> { + read_samples: S, +}*/ + +/// Processes pixel blocks from a file and accumulates them into multiple levels per channel. +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct AllLevelsReader<SamplesReader> { + levels: Levels<SamplesReader>, +} + +/// A template that creates a [`SamplesReader`] once for each resolution level. +pub trait ReadSamplesLevel { + + /// The type of the temporary level reader + type Reader: SamplesReader; + + /// Create a single reader for a single resolution level + fn create_samples_level_reader(&self, header: &Header, channel: &ChannelDescription, level: Vec2<usize>, resolution: Vec2<usize>) -> Result<Self::Reader>; +} + + +impl<S: ReadSamplesLevel> ReadSamples for ReadAllLevels<S> { + type Reader = AllLevelsReader<S::Reader>; + + fn create_sample_reader(&self, header: &Header, channel: &ChannelDescription) -> Result<Self::Reader> { + let data_size = header.layer_size / channel.sampling; + + let levels = { + if let crate::meta::BlockDescription::Tiles(tiles) = &header.blocks { + match tiles.level_mode { + LevelMode::Singular => Levels::Singular(self.read_samples.create_samples_level_reader(header, channel, Vec2(0,0), header.layer_size)?), + + LevelMode::MipMap => Levels::Mip { + rounding_mode: tiles.rounding_mode, + level_data: { + let round = tiles.rounding_mode; + let maps: Result<LevelMaps<S::Reader>> = mip_map_levels(round, data_size) + .map(|(index, level_size)| self.read_samples.create_samples_level_reader(header, channel, Vec2(index, index), level_size)) + .collect(); + + maps? + }, + }, + + // TODO put this into Levels::new(..) ? + LevelMode::RipMap => Levels::Rip { + rounding_mode: tiles.rounding_mode, + level_data: { + let round = tiles.rounding_mode; + let level_count_x = compute_level_count(round, data_size.width()); + let level_count_y = compute_level_count(round, data_size.height()); + let maps: Result<LevelMaps<S::Reader>> = rip_map_levels(round, data_size) + .map(|(index, level_size)| self.read_samples.create_samples_level_reader(header, channel, index, level_size)) + .collect(); + + RipMaps { + map_data: maps?, + level_count: Vec2(level_count_x, level_count_y) + } + }, + }, + } + } + + // scan line blocks never have mip maps + else { + Levels::Singular(self.read_samples.create_samples_level_reader(header, channel, Vec2(0, 0), data_size)?) + } + }; + + Ok(AllLevelsReader { levels }) + } +} + + +impl<S: SamplesReader> SamplesReader for AllLevelsReader<S> { + type Samples = Levels<S::Samples>; + + fn filter_block(&self, _: TileCoordinates) -> bool { + true + } + + fn read_line(&mut self, line: LineRef<'_>) -> UnitResult { + self.levels.get_level_mut(line.location.level)?.read_line(line) + } + + fn into_samples(self) -> Self::Samples { + match self.levels { + Levels::Singular(level) => Levels::Singular(level.into_samples()), + Levels::Mip { rounding_mode, level_data } => Levels::Mip { + rounding_mode, level_data: level_data.into_iter().map(|s| s.into_samples()).collect(), + }, + + Levels::Rip { rounding_mode, level_data } => Levels::Rip { + rounding_mode, + level_data: RipMaps { + level_count: level_data.level_count, + map_data: level_data.map_data.into_iter().map(|s| s.into_samples()).collect(), + } + }, + } + } +} |