diff options
author | Valentin Popov <valentin@popov.link> | 2024-07-19 15:37:58 +0300 |
---|---|---|
committer | Valentin Popov <valentin@popov.link> | 2024-07-19 15:37:58 +0300 |
commit | a990de90fe41456a23e58bd087d2f107d321f3a1 (patch) | |
tree | 15afc392522a9e85dc3332235e311b7d39352ea9 /vendor/exr/src/image/write | |
parent | 3d48cd3f81164bbfc1a755dc1d4a9a02f98c8ddd (diff) | |
download | fparkan-a990de90fe41456a23e58bd087d2f107d321f3a1.tar.xz fparkan-a990de90fe41456a23e58bd087d2f107d321f3a1.zip |
Deleted vendor folder
Diffstat (limited to 'vendor/exr/src/image/write')
-rw-r--r-- | vendor/exr/src/image/write/channels.rs | 407 | ||||
-rw-r--r-- | vendor/exr/src/image/write/layers.rs | 188 | ||||
-rw-r--r-- | vendor/exr/src/image/write/mod.rs | 184 | ||||
-rw-r--r-- | vendor/exr/src/image/write/samples.rs | 205 |
4 files changed, 0 insertions, 984 deletions
diff --git a/vendor/exr/src/image/write/channels.rs b/vendor/exr/src/image/write/channels.rs deleted file mode 100644 index 2450f09..0000000 --- a/vendor/exr/src/image/write/channels.rs +++ /dev/null @@ -1,407 +0,0 @@ -//! How to read arbitrary channels and rgb channels. - -use crate::prelude::*; -use crate::io::*; -use crate::math::*; -use crate::meta::{header::*, attribute::*}; -use crate::block::*; -use crate::image::recursive::*; -use crate::block::samples::*; -use crate::image::write::samples::*; - -use std::marker::PhantomData; - - -/// Enables an image containing this list of channels to be written to a file. -pub trait WritableChannels<'slf> { - - /// Generate the file meta data for this list of channel - fn infer_channel_list(&self) -> ChannelList; - - /// Generate the file meta data of whether and how resolution levels should be stored in the file - fn infer_level_modes(&self) -> (LevelMode, RoundingMode); - - /// The type of temporary writer - type Writer: ChannelsWriter; - - /// Create a temporary writer for this list of channels - fn create_writer(&'slf self, header: &Header) -> Self::Writer; -} - -/// A temporary writer for a list of channels -pub trait ChannelsWriter: Sync { - - /// Deliver a block of pixels, containing all channel data, to be stored in the file - fn extract_uncompressed_block(&self, header: &Header, block: BlockIndex) -> Vec<u8>; // TODO return uncompressed block? -} - - -/// Define how to get a pixel from your custom pixel storage. -/// Can be a closure of type [`Sync + Fn(Vec2<usize>) -> YourPixel`]. -pub trait GetPixel: Sync { - - /// The pixel tuple containing `f32`, `f16`, `u32` and `Sample` values. - /// The length of the tuple must match the number of channels in the image. - type Pixel; - - /// Inspect a single pixel at the requested position. - /// Will be called exactly once for each pixel in the image. - /// The position will not exceed the image dimensions. - /// Might be called from multiple threads at the same time. - fn get_pixel(&self, position: Vec2<usize>) -> Self::Pixel; -} - -impl<F, P> GetPixel for F where F: Sync + Fn(Vec2<usize>) -> P { - type Pixel = P; - fn get_pixel(&self, position: Vec2<usize>) -> P { self(position) } -} - -impl<'samples, Samples> WritableChannels<'samples> for AnyChannels<Samples> - where Samples: 'samples + WritableSamples<'samples> -{ - fn infer_channel_list(&self) -> ChannelList { - ChannelList::new(self.list.iter().map(|channel| ChannelDescription { - name: channel.name.clone(), - sample_type: channel.sample_data.sample_type(), - quantize_linearly: channel.quantize_linearly, - sampling: channel.sampling - }).collect()) - } - - fn infer_level_modes(&self) -> (LevelMode, RoundingMode) { - let mode = self.list.iter().next().expect("zero channels in list").sample_data.infer_level_modes(); - - debug_assert!( - std::iter::repeat(mode).zip(self.list.iter().skip(1)) - .all(|(first, other)| other.sample_data.infer_level_modes() == first), - - "level mode must be the same across all levels (do not nest resolution levels!)" - ); - - mode - } - - type Writer = AnyChannelsWriter<Samples::Writer>; - fn create_writer(&'samples self, header: &Header) -> Self::Writer { - let channels = self.list.iter() - .map(|chan| chan.sample_data.create_samples_writer(header)) - .collect(); - - AnyChannelsWriter { channels } - } -} - -/// A temporary writer for an arbitrary list of channels -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct AnyChannelsWriter<SamplesWriter> { - channels: SmallVec<[SamplesWriter; 4]> -} - -impl<Samples> ChannelsWriter for AnyChannelsWriter<Samples> where Samples: SamplesWriter { - fn extract_uncompressed_block(&self, header: &Header, block_index: BlockIndex) -> Vec<u8> { - UncompressedBlock::collect_block_data_from_lines(&header.channels, block_index, |line_ref| { - self.channels[line_ref.location.channel].extract_line(line_ref) - }) - } -} - - - - - - -impl<'c, Channels, Storage> -WritableChannels<'c> for SpecificChannels<Storage, Channels> -where - Storage: 'c + GetPixel, - Storage::Pixel: IntoRecursive, - Channels: 'c + Sync + Clone + IntoRecursive, - <Channels as IntoRecursive>::Recursive: WritableChannelsDescription<<Storage::Pixel as IntoRecursive>::Recursive>, -{ - fn infer_channel_list(&self) -> ChannelList { - let mut vec = self.channels.clone().into_recursive().channel_descriptions_list(); - vec.sort_unstable_by_key(|channel:&ChannelDescription| channel.name.clone()); // TODO no clone? - - debug_assert!( - // check for equal neighbors in sorted vec - vec.iter().zip(vec.iter().skip(1)).all(|(prev, next)| prev.name != next.name), - "specific channels contain duplicate channel names" - ); - - ChannelList::new(vec) - } - - fn infer_level_modes(&self) -> (LevelMode, RoundingMode) { - (LevelMode::Singular, RoundingMode::Down) // TODO - } - - type Writer = SpecificChannelsWriter< - 'c, - <<Channels as IntoRecursive>::Recursive as WritableChannelsDescription<<Storage::Pixel as IntoRecursive>::Recursive>>::RecursiveWriter, - Storage, - Channels - >; - - fn create_writer(&'c self, header: &Header) -> Self::Writer { - SpecificChannelsWriter { - channels: self, - recursive_channel_writer: self.channels.clone().into_recursive().create_recursive_writer(&header.channels), - } - } -} - - - -/// A temporary writer for a layer of channels, alpha being optional -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct SpecificChannelsWriter<'channels, PixelWriter, Storage, Channels> { - channels: &'channels SpecificChannels<Storage, Channels>, // TODO this need not be a reference?? impl writer for specific_channels directly? - recursive_channel_writer: PixelWriter, -} - - -impl<'channels, PxWriter, Storage, Channels> ChannelsWriter -for SpecificChannelsWriter<'channels, PxWriter, Storage, Channels> - where - Channels: Sync, - Storage: GetPixel, - Storage::Pixel: IntoRecursive, - PxWriter: Sync + RecursivePixelWriter<<Storage::Pixel as IntoRecursive>::Recursive>, -{ - fn extract_uncompressed_block(&self, header: &Header, block_index: BlockIndex) -> Vec<u8> { - let block_bytes = block_index.pixel_size.area() * header.channels.bytes_per_pixel; - let mut block_bytes = vec![0_u8; block_bytes]; - - let width = block_index.pixel_size.0; - let line_bytes = width * header.channels.bytes_per_pixel; - let byte_lines = block_bytes.chunks_exact_mut(line_bytes); - assert_eq!(byte_lines.len(), block_index.pixel_size.height(), "invalid block line splits"); - - //dbg!(width, line_bytes, header.channels.bytes_per_pixel, byte_lines.len()); - - let mut pixel_line = Vec::with_capacity(width); - - for (y, line_bytes) in byte_lines.enumerate() { - pixel_line.clear(); - pixel_line.extend((0 .. width).map(|x| - self.channels.pixels.get_pixel(block_index.pixel_position + Vec2(x, y)).into_recursive() - )); - - self.recursive_channel_writer.write_pixels(line_bytes, pixel_line.as_slice(), |px| px); - } - - block_bytes - } -} - -/// A tuple containing either `ChannelsDescription` or `Option<ChannelsDescription>` entries. -/// Use an `Option` if you want to dynamically omit a single channel (probably only for roundtrip tests). -/// The number of entries must match the number of channels. -pub trait WritableChannelsDescription<Pixel>: Sync { - - /// A type that has a recursive entry for each channel in the image, - /// which must accept the desired pixel type. - type RecursiveWriter: RecursivePixelWriter<Pixel>; - - /// Create the temporary writer, accepting the sorted list of channels from `channel_descriptions_list`. - fn create_recursive_writer(&self, channels: &ChannelList) -> Self::RecursiveWriter; - - /// Return all the channels that should actually end up in the image, in any order. - fn channel_descriptions_list(&self) -> SmallVec<[ChannelDescription; 5]>; -} - -impl WritableChannelsDescription<NoneMore> for NoneMore { - type RecursiveWriter = NoneMore; - fn create_recursive_writer(&self, _: &ChannelList) -> Self::RecursiveWriter { NoneMore } - fn channel_descriptions_list(&self) -> SmallVec<[ChannelDescription; 5]> { SmallVec::new() } -} - -impl<InnerDescriptions, InnerPixel, Sample: IntoNativeSample> - WritableChannelsDescription<Recursive<InnerPixel, Sample>> - for Recursive<InnerDescriptions, ChannelDescription> - where InnerDescriptions: WritableChannelsDescription<InnerPixel> -{ - type RecursiveWriter = RecursiveWriter<InnerDescriptions::RecursiveWriter, Sample>; - - fn create_recursive_writer(&self, channels: &ChannelList) -> Self::RecursiveWriter { - // this linear lookup is required because the order of the channels changed, due to alphabetical sorting - let (start_byte_offset, target_sample_type) = channels.channels_with_byte_offset() - .find(|(_offset, channel)| channel.name == self.value.name) - .map(|(offset, channel)| (offset, channel.sample_type)) - .expect("a channel has not been put into channel list"); - - Recursive::new(self.inner.create_recursive_writer(channels), SampleWriter { - start_byte_offset, target_sample_type, - px: PhantomData::default() - }) - } - - fn channel_descriptions_list(&self) -> SmallVec<[ChannelDescription; 5]> { - let mut inner_list = self.inner.channel_descriptions_list(); - inner_list.push(self.value.clone()); - inner_list - } -} - -impl<InnerDescriptions, InnerPixel, Sample: IntoNativeSample> -WritableChannelsDescription<Recursive<InnerPixel, Sample>> -for Recursive<InnerDescriptions, Option<ChannelDescription>> - where InnerDescriptions: WritableChannelsDescription<InnerPixel> -{ - type RecursiveWriter = OptionalRecursiveWriter<InnerDescriptions::RecursiveWriter, Sample>; - - fn create_recursive_writer(&self, channels: &ChannelList) -> Self::RecursiveWriter { - // this linear lookup is required because the order of the channels changed, due to alphabetical sorting - - let channel = self.value.as_ref().map(|required_channel| - channels.channels_with_byte_offset() - .find(|(_offset, channel)| channel == &required_channel) - .map(|(offset, channel)| (offset, channel.sample_type)) - .expect("a channel has not been put into channel list") - ); - - Recursive::new( - self.inner.create_recursive_writer(channels), - channel.map(|(start_byte_offset, target_sample_type)| SampleWriter { - start_byte_offset, target_sample_type, - px: PhantomData::default(), - }) - ) - } - - fn channel_descriptions_list(&self) -> SmallVec<[ChannelDescription; 5]> { - let mut inner_list = self.inner.channel_descriptions_list(); - if let Some(value) = &self.value { inner_list.push(value.clone()); } - inner_list - } -} - -/// Write pixels to a slice of bytes. The top level writer contains all the other channels, -/// the most inner channel is `NoneMore`. -pub trait RecursivePixelWriter<Pixel>: Sync { - - /// Write pixels to a slice of bytes. Recursively do this for all channels. - fn write_pixels<FullPixel>(&self, bytes: &mut [u8], pixels: &[FullPixel], get_pixel: impl Fn(&FullPixel) -> &Pixel); -} - -type RecursiveWriter<Inner, Sample> = Recursive<Inner, SampleWriter<Sample>>; -type OptionalRecursiveWriter<Inner, Sample> = Recursive<Inner, Option<SampleWriter<Sample>>>; - -/// Write the pixels of a single channel, unconditionally. Generic over the concrete sample type (f16, f32, u32). -#[derive(Debug, Clone)] -pub struct SampleWriter<Sample> { - target_sample_type: SampleType, - start_byte_offset: usize, - px: PhantomData<Sample>, -} - -impl<Sample> SampleWriter<Sample> where Sample: IntoNativeSample { - fn write_own_samples(&self, bytes: &mut [u8], samples: impl ExactSizeIterator<Item=Sample>) { - let byte_start_index = samples.len() * self.start_byte_offset; - let byte_count = samples.len() * self.target_sample_type.bytes_per_sample(); - let ref mut byte_writer = &mut bytes[byte_start_index..byte_start_index + byte_count]; - - let write_error_msg = "invalid memory buffer length when writing"; - - // match outside the loop to avoid matching on every single sample - match self.target_sample_type { - // TODO does this boil down to a `memcpy` where the sample type equals the type parameter? - SampleType::F16 => for sample in samples { sample.to_f16().write(byte_writer).expect(write_error_msg); }, - SampleType::F32 => for sample in samples { sample.to_f32().write(byte_writer).expect(write_error_msg); }, - SampleType::U32 => for sample in samples { sample.to_u32().write(byte_writer).expect(write_error_msg); }, - }; - - debug_assert!(byte_writer.is_empty(), "all samples are written, but more were expected"); - } -} - -impl RecursivePixelWriter<NoneMore> for NoneMore { - fn write_pixels<FullPixel>(&self, _: &mut [u8], _: &[FullPixel], _: impl Fn(&FullPixel) -> &NoneMore) {} -} - -impl<Inner, InnerPixel, Sample: IntoNativeSample> - RecursivePixelWriter<Recursive<InnerPixel, Sample>> - for RecursiveWriter<Inner, Sample> - where Inner: RecursivePixelWriter<InnerPixel> -{ - // TODO impl exact size iterator <item = Self::Pixel> - fn write_pixels<FullPixel>(&self, bytes: &mut [u8], pixels: &[FullPixel], get_pixel: impl Fn(&FullPixel) -> &Recursive<InnerPixel, Sample>){ - self.value.write_own_samples(bytes, pixels.iter().map(|px| get_pixel(px).value)); - self.inner.write_pixels(bytes, pixels, |px| &get_pixel(px).inner); - } -} - -impl<Inner, InnerPixel, Sample> RecursivePixelWriter<Recursive<InnerPixel, Sample>> - for OptionalRecursiveWriter<Inner, Sample> - where Inner: RecursivePixelWriter<InnerPixel>, - Sample: IntoNativeSample -{ - fn write_pixels<FullPixel>(&self, bytes: &mut [u8], pixels: &[FullPixel], get_pixel: impl Fn(&FullPixel) -> &Recursive<InnerPixel, Sample>) { - if let Some(writer) = &self.value { - writer.write_own_samples(bytes, pixels.iter().map(|px| get_pixel(px).value)); - } - - self.inner.write_pixels(bytes, pixels, |px| &get_pixel(px).inner); - } -} - - - - - - - -#[cfg(test)] -pub mod test { - use crate::image::write::channels::WritableChannels; - use crate::image::SpecificChannels; - use crate::prelude::{f16}; - use crate::meta::attribute::{ChannelDescription, SampleType}; - use crate::image::pixel_vec::PixelVec; - - #[test] - fn compiles(){ - let x = 3_f32; - let y = f16::from_f32(4.0); - let z = 2_u32; - let s = 1.3_f32; - let px = (x,y,z,s); - - assert_is_writable_channels( - SpecificChannels::rgba(|_pos| px) - ); - - assert_is_writable_channels(SpecificChannels::rgba( - PixelVec::new((3, 2), vec![px, px, px, px, px, px]) - )); - - let px = (2333_u32, 4_f32); - assert_is_writable_channels( - SpecificChannels::build() - .with_channel("A") - .with_channel("C") - .with_pixels(PixelVec::new((3, 2), vec![px, px, px, px, px, px])) - ); - - let px = (3_f32, f16::ONE, 2333_u32, 4_f32); - assert_is_writable_channels(SpecificChannels::new( - ( - ChannelDescription::named("x", SampleType::F32), - ChannelDescription::named("y", SampleType::F16), - Some(ChannelDescription::named("z", SampleType::U32)), - Some(ChannelDescription::named("p", SampleType::F32)), - ), - - PixelVec::new((3, 2), vec![px, px, px, px, px, px]) - )); - - - - fn assert_is_writable_channels<'s>(_channels: impl WritableChannels<'s>){} - - } -} - - - - diff --git a/vendor/exr/src/image/write/layers.rs b/vendor/exr/src/image/write/layers.rs deleted file mode 100644 index 85648ff..0000000 --- a/vendor/exr/src/image/write/layers.rs +++ /dev/null @@ -1,188 +0,0 @@ -//! How to write either a single or a list of layers. - -use crate::meta::header::{ImageAttributes, Header}; -use crate::meta::{Headers, compute_chunk_count}; -use crate::block::BlockIndex; -use crate::image::{Layers, Layer}; -use crate::meta::attribute::{TileDescription}; -use crate::prelude::{SmallVec}; -use crate::image::write::channels::{WritableChannels, ChannelsWriter}; -use crate::image::recursive::{Recursive, NoneMore}; - -/// Enables an image containing this list of layers to be written to a file. -pub trait WritableLayers<'slf> { - - /// Generate the file meta data for this list of layers - fn infer_headers(&self, image_attributes: &ImageAttributes) -> Headers; - - /// The type of temporary writer - type Writer: LayersWriter; - - /// Create a temporary writer for this list of layers - fn create_writer(&'slf self, headers: &[Header]) -> Self::Writer; -} - -/// A temporary writer for a list of channels -pub trait LayersWriter: Sync { - - /// Deliver a block of pixels from a single layer to be stored in the file - fn extract_uncompressed_block(&self, headers: &[Header], block: BlockIndex) -> Vec<u8>; -} - -/// A temporary writer for an arbitrary list of layers -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct AllLayersWriter<ChannelsWriter> { - layers: SmallVec<[LayerWriter<ChannelsWriter>; 2]> -} - -/// A temporary writer for a single layer -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct LayerWriter<ChannelsWriter> { - channels: ChannelsWriter, // impl ChannelsWriter -} - -// impl for smallvec -impl<'slf, Channels: 'slf> WritableLayers<'slf> for Layers<Channels> where Channels: WritableChannels<'slf> { - fn infer_headers(&self, image_attributes: &ImageAttributes) -> Headers { - slice_infer_headers(self.as_slice(), image_attributes) - } - - type Writer = AllLayersWriter<Channels::Writer>; - fn create_writer(&'slf self, headers: &[Header]) -> Self::Writer { - slice_create_writer(self.as_slice(), headers) - } -} - -fn slice_infer_headers<'slf, Channels:'slf + WritableChannels<'slf>>( - slice: &[Layer<Channels>], image_attributes: &ImageAttributes -) -> Headers -{ - slice.iter().map(|layer| layer.infer_headers(image_attributes).remove(0)).collect() // TODO no array-vs-first -} - -fn slice_create_writer<'slf, Channels:'slf + WritableChannels<'slf>>( - slice: &'slf [Layer<Channels>], headers: &[Header] -) -> AllLayersWriter<Channels::Writer> -{ - AllLayersWriter { - layers: slice.iter().zip(headers.chunks_exact(1)) // TODO no array-vs-first - .map(|(layer, header)| layer.create_writer(header)) - .collect() - } -} - - -impl<'slf, Channels: WritableChannels<'slf>> WritableLayers<'slf> for Layer<Channels> { - fn infer_headers(&self, image_attributes: &ImageAttributes) -> Headers { - let blocks = match self.encoding.blocks { - crate::image::Blocks::ScanLines => crate::meta::BlockDescription::ScanLines, - crate::image::Blocks::Tiles(tile_size) => { - let (level_mode, rounding_mode) = self.channel_data.infer_level_modes(); - crate::meta::BlockDescription::Tiles(TileDescription { level_mode, rounding_mode, tile_size, }) - }, - }; - - let chunk_count = compute_chunk_count( - self.encoding.compression, self.size, blocks - ); - - let header = Header { - channels: self.channel_data.infer_channel_list(), - compression: self.encoding.compression, - - blocks, - chunk_count, - - line_order: self.encoding.line_order, - layer_size: self.size, - shared_attributes: image_attributes.clone(), - own_attributes: self.attributes.clone(), - - - deep: false, // TODO deep data - deep_data_version: None, - max_samples_per_pixel: None, - }; - - smallvec![ header ]// TODO no array-vs-first - } - - type Writer = LayerWriter</*'l,*/ Channels::Writer>; - fn create_writer(&'slf self, headers: &[Header]) -> Self::Writer { - let channels = self.channel_data - .create_writer(headers.first().expect("inferred header error")); // TODO no array-vs-first - - LayerWriter { channels } - } -} - -impl<C> LayersWriter for AllLayersWriter<C> where C: ChannelsWriter { - fn extract_uncompressed_block(&self, headers: &[Header], block: BlockIndex) -> Vec<u8> { - self.layers[block.layer].extract_uncompressed_block(std::slice::from_ref(&headers[block.layer]), block) // TODO no array-vs-first - } -} - -impl<C> LayersWriter for LayerWriter<C> where C: ChannelsWriter { - fn extract_uncompressed_block(&self, headers: &[Header], block: BlockIndex) -> Vec<u8> { - self.channels.extract_uncompressed_block(headers.first().expect("invalid inferred header"), block) // TODO no array-vs-first - } -} - - - - - -impl<'slf> WritableLayers<'slf> for NoneMore { - fn infer_headers(&self, _: &ImageAttributes) -> Headers { SmallVec::new() } - - type Writer = NoneMore; - fn create_writer(&'slf self, _: &[Header]) -> Self::Writer { NoneMore } -} - -impl<'slf, InnerLayers, Channels> WritableLayers<'slf> for Recursive<InnerLayers, Layer<Channels>> - where InnerLayers: WritableLayers<'slf>, Channels: WritableChannels<'slf> -{ - fn infer_headers(&self, image_attributes: &ImageAttributes) -> Headers { - let mut headers = self.inner.infer_headers(image_attributes); - headers.push(self.value.infer_headers(image_attributes).remove(0)); // TODO no unwrap - headers - } - - type Writer = RecursiveLayersWriter<InnerLayers::Writer, Channels::Writer>; - - fn create_writer(&'slf self, headers: &[Header]) -> Self::Writer { - let (own_header, inner_headers) = headers.split_last() - .expect("header has not been inferred correctly"); - - let layer_index = inner_headers.len(); - RecursiveLayersWriter { - inner: self.inner.create_writer(inner_headers), - value: (layer_index, self.value.create_writer(std::slice::from_ref(own_header))) // TODO no slice - } - } -} - -type RecursiveLayersWriter<InnerLayersWriter, ChannelsWriter> = Recursive<InnerLayersWriter, (usize, LayerWriter<ChannelsWriter>)>; - -impl LayersWriter for NoneMore { - fn extract_uncompressed_block(&self, _: &[Header], _: BlockIndex) -> Vec<u8> { - panic!("recursive length mismatch bug"); - } -} - -impl<InnerLayersWriter, Channels> LayersWriter for RecursiveLayersWriter<InnerLayersWriter, Channels> - where InnerLayersWriter: LayersWriter, Channels: ChannelsWriter -{ - fn extract_uncompressed_block(&self, headers: &[Header], block: BlockIndex) -> Vec<u8> { - let (layer_index, layer) = &self.value; - if *layer_index == block.layer { - let header = headers.get(*layer_index).expect("layer index bug"); - layer.extract_uncompressed_block(std::slice::from_ref(header), block) // TODO no slice? - } - else { - self.inner.extract_uncompressed_block(headers, block) - } - } -} - - diff --git a/vendor/exr/src/image/write/mod.rs b/vendor/exr/src/image/write/mod.rs deleted file mode 100644 index 3c20060..0000000 --- a/vendor/exr/src/image/write/mod.rs +++ /dev/null @@ -1,184 +0,0 @@ - -//! Write an exr image to a file. -//! -//! First, call `my_image.write()`. The resulting value can be customized, like this: -//! ```no_run -//! use exr::prelude::*; -//! # let my_image: FlatImage = unimplemented!(); -//! -//! my_image.write() -//! .on_progress(|progress| println!("progress: {:.1}", progress*100.0)) -//! .to_file("image.exr").unwrap(); -//! ``` -//! - -pub mod layers; -pub mod samples; -pub mod channels; - - - -use crate::meta::Headers; -use crate::error::UnitResult; -use std::io::{Seek, BufWriter}; -use crate::io::Write; -use crate::image::{Image, ignore_progress, SpecificChannels, IntoSample}; -use crate::image::write::layers::{WritableLayers, LayersWriter}; -use crate::math::Vec2; -use crate::block::writer::ChunksWriter; - -/// An oversimplified function for "just write the damn file already" use cases. -/// Have a look at the examples to see how you can write an image with more flexibility (it's not that hard). -/// Use `write_rgb_file` if you do not need an alpha channel. -/// -/// Each of `R`, `G`, `B` and `A` can be either `f16`, `f32`, `u32`, or `Sample`. -// TODO explain pixel tuple f32,f16,u32 -pub fn write_rgba_file<R,G,B,A>( - path: impl AsRef<std::path::Path>, width: usize, height: usize, - colors: impl Sync + Fn(usize, usize) -> (R, G, B, A) -) -> UnitResult - where R: IntoSample, G: IntoSample, B: IntoSample, A: IntoSample, -{ - let channels = SpecificChannels::rgba(|Vec2(x,y)| colors(x,y)); - Image::from_channels((width, height), channels).write().to_file(path) -} - -/// An oversimplified function for "just write the damn file already" use cases. -/// Have a look at the examples to see how you can write an image with more flexibility (it's not that hard). -/// Use `write_rgb_file` if you do not need an alpha channel. -/// -/// Each of `R`, `G`, and `B` can be either `f16`, `f32`, `u32`, or `Sample`. -// TODO explain pixel tuple f32,f16,u32 -pub fn write_rgb_file<R,G,B>( - path: impl AsRef<std::path::Path>, width: usize, height: usize, - colors: impl Sync + Fn(usize, usize) -> (R, G, B) -) -> UnitResult - where R: IntoSample, G: IntoSample, B: IntoSample -{ - let channels = SpecificChannels::rgb(|Vec2(x,y)| colors(x,y)); - Image::from_channels((width, height), channels).write().to_file(path) -} - - - -/// Enables an image to be written to a file. Call `image.write()` where this trait is implemented. -pub trait WritableImage<'img, WritableLayers>: Sized { - - /// Create a temporary writer which can be configured and used to write the image to a file. - fn write(self) -> WriteImageWithOptions<'img, WritableLayers, fn(f64)>; -} - -impl<'img, WritableLayers> WritableImage<'img, WritableLayers> for &'img Image<WritableLayers> { - fn write(self) -> WriteImageWithOptions<'img, WritableLayers, fn(f64)> { - WriteImageWithOptions { - image: self, - check_compatibility: true, - parallel: true, - on_progress: ignore_progress - } - } -} - -/// A temporary writer which can be configured and used to write an image to a file. -// temporary writer with options -#[derive(Debug, Clone, PartialEq)] -pub struct WriteImageWithOptions<'img, Layers, OnProgress> { - image: &'img Image<Layers>, - on_progress: OnProgress, - check_compatibility: bool, - parallel: bool, -} - - -impl<'img, L, F> WriteImageWithOptions<'img, L, F> - where L: WritableLayers<'img>, F: FnMut(f64) -{ - /// Generate file meta data for this image. The meta data structure is close to the data in the file. - pub fn infer_meta_data(&self) -> Headers { // TODO this should perform all validity checks? and none after that? - self.image.layer_data.infer_headers(&self.image.attributes) - } - - /// Do not compress multiple pixel blocks on multiple threads at once. - /// Might use less memory and synchronization, but will be slower in most situations. - pub fn non_parallel(self) -> Self { Self { parallel: false, ..self } } - - /// Skip some checks that ensure a file can be opened by other exr software. - /// For example, it is no longer checked that no two headers or two attributes have the same name, - /// which might be an expensive check for images with an exorbitant number of headers. - /// - /// If you write an uncompressed file and need maximum speed, it might save a millisecond to disable the checks, - /// if you know that your file is not invalid any ways. I do not recommend this though, - /// as the file might not be readably by any other exr library after that. - /// __You must care for not producing an invalid file yourself.__ - pub fn skip_compatibility_checks(self) -> Self { Self { check_compatibility: false, ..self } } - - /// Specify a function to be called regularly throughout the writing process. - /// Replaces all previously specified progress functions in this reader. - pub fn on_progress<OnProgress>(self, on_progress: OnProgress) -> WriteImageWithOptions<'img, L, OnProgress> - where OnProgress: FnMut(f64) - { - WriteImageWithOptions { - on_progress, - image: self.image, - check_compatibility: self.check_compatibility, - parallel: self.parallel - } - } - - /// Write the exr image to a file. - /// Use `to_unbuffered` instead, if you do not have a file. - /// If an error occurs, attempts to delete the partially written file. - #[inline] - #[must_use] - pub fn to_file(self, path: impl AsRef<std::path::Path>) -> UnitResult { - crate::io::attempt_delete_file_on_write_error(path.as_ref(), move |write| - self.to_unbuffered(write) - ) - } - - /// Buffer the writer and then write the exr image to it. - /// Use `to_buffered` instead, if your writer is an in-memory buffer. - /// Use `to_file` instead, if you have a file path. - /// If your writer cannot seek, you can write to an in-memory vector of bytes first, using `to_buffered`. - #[inline] - #[must_use] - pub fn to_unbuffered(self, unbuffered: impl Write + Seek) -> UnitResult { - self.to_buffered(BufWriter::new(unbuffered)) - } - - /// Write the exr image to a writer. - /// Use `to_file` instead, if you have a file path. - /// Use `to_unbuffered` instead, if this is not an in-memory writer. - /// If your writer cannot seek, you can write to an in-memory vector of bytes first. - #[must_use] - pub fn to_buffered(self, write: impl Write + Seek) -> UnitResult { - let headers = self.infer_meta_data(); - let layers = self.image.layer_data.create_writer(&headers); - - crate::block::write( - write, headers, self.check_compatibility, - move |meta, chunk_writer|{ - - let blocks = meta.collect_ordered_block_data(|block_index| - layers.extract_uncompressed_block(&meta.headers, block_index) - ); - - let chunk_writer = chunk_writer.on_progress(self.on_progress); - if self.parallel { chunk_writer.compress_all_blocks_parallel(&meta, blocks)?; } - else { chunk_writer.compress_all_blocks_sequential(&meta, blocks)?; } - /*let blocks_writer = chunk_writer.as_blocks_writer(&meta); - - // TODO propagate send requirement further upwards - if self.parallel { - blocks_writer.compress_all_blocks_parallel(blocks)?; - } - else { - blocks_writer.compress_all_blocks_sequential(blocks)?; - }*/ - - Ok(()) - } - ) - } -} - diff --git a/vendor/exr/src/image/write/samples.rs b/vendor/exr/src/image/write/samples.rs deleted file mode 100644 index e74105b..0000000 --- a/vendor/exr/src/image/write/samples.rs +++ /dev/null @@ -1,205 +0,0 @@ -//! How to write samples (a grid of `f32`, `f16` or `u32` values). - -use crate::meta::attribute::{LevelMode, SampleType, TileDescription}; -use crate::meta::header::Header; -use crate::block::lines::LineRefMut; -use crate::image::{FlatSamples, Levels, RipMaps}; -use crate::math::{Vec2, RoundingMode}; -use crate::meta::{rip_map_levels, mip_map_levels, rip_map_indices, mip_map_indices, BlockDescription}; - -/// Enable an image with this sample grid to be written to a file. -/// Also can contain multiple resolution levels. -/// Usually contained within `Channels`. -pub trait WritableSamples<'slf> { - // fn is_deep(&self) -> bool; - - /// Generate the file meta data regarding the number type of this storage - fn sample_type(&self) -> SampleType; - - /// Generate the file meta data regarding resolution levels - fn infer_level_modes(&self) -> (LevelMode, RoundingMode); - - /// The type of the temporary writer for this sample storage - type Writer: SamplesWriter; - - /// Create a temporary writer for this sample storage - fn create_samples_writer(&'slf self, header: &Header) -> Self::Writer; -} - -/// Enable an image with this single level sample grid to be written to a file. -/// Only contained within `Levels`. -pub trait WritableLevel<'slf> { - - /// Generate the file meta data regarding the number type of these samples - fn sample_type(&self) -> SampleType; - - /// The type of the temporary writer for this single level of samples - type Writer: SamplesWriter; - - /// Create a temporary writer for this single level of samples - fn create_level_writer(&'slf self, size: Vec2<usize>) -> Self::Writer; -} - -/// A temporary writer for one or more resolution levels containing samples -pub trait SamplesWriter: Sync { - - /// Deliver a single short horizontal list of samples for a specific channel. - fn extract_line(&self, line: LineRefMut<'_>); -} - -/// A temporary writer for a predefined non-deep sample storage -#[derive(Debug, Copy, Clone, PartialEq)] -pub struct FlatSamplesWriter<'samples> { - resolution: Vec2<usize>, // respects resolution level - samples: &'samples FlatSamples -} - - - -// used if no layers are used and the flat samples are directly inside the channels -impl<'samples> WritableSamples<'samples> for FlatSamples { - fn sample_type(&self) -> SampleType { - match self { - FlatSamples::F16(_) => SampleType::F16, - FlatSamples::F32(_) => SampleType::F32, - FlatSamples::U32(_) => SampleType::U32, - } - } - - fn infer_level_modes(&self) -> (LevelMode, RoundingMode) { (LevelMode::Singular, RoundingMode::Down) } - - type Writer = FlatSamplesWriter<'samples>; //&'s FlatSamples; - fn create_samples_writer(&'samples self, header: &Header) -> Self::Writer { - FlatSamplesWriter { - resolution: header.layer_size, - samples: self - } - } -} - -// used if layers are used and the flat samples are inside the levels -impl<'samples> WritableLevel<'samples> for FlatSamples { - fn sample_type(&self) -> SampleType { - match self { - FlatSamples::F16(_) => SampleType::F16, - FlatSamples::F32(_) => SampleType::F32, - FlatSamples::U32(_) => SampleType::U32, - } - } - - type Writer = FlatSamplesWriter<'samples>; - fn create_level_writer(&'samples self, size: Vec2<usize>) -> Self::Writer { - FlatSamplesWriter { - resolution: size, - samples: self - } - } -} - -impl<'samples> SamplesWriter for FlatSamplesWriter<'samples> { - fn extract_line(&self, line: LineRefMut<'_>) { - let image_width = self.resolution.width(); // header.layer_size.width(); - debug_assert_ne!(image_width, 0, "image width calculation bug"); - - let start_index = line.location.position.y() * image_width + line.location.position.x(); - let end_index = start_index + line.location.sample_count; - - debug_assert!( - start_index < end_index && end_index <= self.samples.len(), - "for resolution {:?}, this is an invalid line: {:?}", - self.resolution, line.location - ); - - match self.samples { - FlatSamples::F16(samples) => line.write_samples_from_slice(&samples[start_index .. end_index]), - FlatSamples::F32(samples) => line.write_samples_from_slice(&samples[start_index .. end_index]), - FlatSamples::U32(samples) => line.write_samples_from_slice(&samples[start_index .. end_index]), - }.expect("writing line bytes failed"); - } -} - - -impl<'samples, LevelSamples> WritableSamples<'samples> for Levels<LevelSamples> - where LevelSamples: WritableLevel<'samples> -{ - fn sample_type(&self) -> SampleType { - let sample_type = self.levels_as_slice().first().expect("no levels found").sample_type(); - - debug_assert!( - self.levels_as_slice().iter().skip(1).all(|ty| ty.sample_type() == sample_type), - "sample types must be the same across all levels" - ); - - sample_type - } - - fn infer_level_modes(&self) -> (LevelMode, RoundingMode) { - match self { - Levels::Singular(_) => (LevelMode::Singular, RoundingMode::Down), - Levels::Mip { rounding_mode, .. } => (LevelMode::MipMap, *rounding_mode), - Levels::Rip { rounding_mode, .. } => (LevelMode::RipMap, *rounding_mode), - } - } - - type Writer = LevelsWriter<LevelSamples::Writer>; - fn create_samples_writer(&'samples self, header: &Header) -> Self::Writer { - let rounding = match header.blocks { - BlockDescription::Tiles(TileDescription { rounding_mode, .. }) => Some(rounding_mode), - BlockDescription::ScanLines => None, - }; - - LevelsWriter { - levels: match self { - Levels::Singular(level) => Levels::Singular(level.create_level_writer(header.layer_size)), - Levels::Mip { level_data, rounding_mode } => { - debug_assert_eq!( - level_data.len(), - mip_map_indices(rounding.expect("mip maps only with tiles"), header.layer_size).count(), - "invalid mip map count" - ); - - Levels::Mip { // TODO store level size in image?? - rounding_mode: *rounding_mode, - level_data: level_data.iter() - .zip(mip_map_levels(rounding.expect("mip maps only with tiles"), header.layer_size)) - // .map(|level| level.create_samples_writer(header)) - .map(|(level, (_level_index, level_size))| level.create_level_writer(level_size)) - .collect() - } - }, - Levels::Rip { level_data, rounding_mode } => { - debug_assert_eq!(level_data.map_data.len(), level_data.level_count.area(), "invalid rip level count"); - debug_assert_eq!( - level_data.map_data.len(), - rip_map_indices(rounding.expect("rip maps only with tiles"), header.layer_size).count(), - "invalid rip map count" - ); - - Levels::Rip { - rounding_mode: *rounding_mode, - level_data: RipMaps { - level_count: level_data.level_count, - map_data: level_data.map_data.iter() - .zip(rip_map_levels(rounding.expect("rip maps only with tiles"), header.layer_size)) - .map(|(level, (_level_index, level_size))| level.create_level_writer(level_size)) - .collect(), - } - } - } - } - } - } -} - -/// A temporary writer for multiple resolution levels -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct LevelsWriter<SamplesWriter> { - levels: Levels<SamplesWriter>, -} - -impl<Samples> SamplesWriter for LevelsWriter<Samples> where Samples: SamplesWriter { - fn extract_line(&self, line: LineRefMut<'_>) { - self.levels.get_level(line.location.level).expect("invalid level index") // TODO compute level size from line index?? - .extract_line(line) - } -} |