use std::marker::PhantomData;
use crate::{
block::{samples::*, *},
image::{recursive::*, write::samples::*},
io::*,
math::*,
meta::{attribute::*, header::*},
prelude::*,
};
pub trait WritableChannels<'slf> {
fn infer_channel_list(&self) -> ChannelList;
fn infer_level_modes(&self) -> (LevelMode, RoundingMode);
type Writer: ChannelsWriter;
fn create_writer(&'slf self, header: &Header) -> Self::Writer;
}
pub trait ChannelsWriter: Sync {
fn extract_uncompressed_block(&self, header: &Header, block: BlockIndex) -> Vec<u8>; }
pub trait GetPixel: Sync {
type Pixel;
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>,
{
type Writer = AnyChannelsWriter<Samples::Writer>;
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
}
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,
}
}
}
#[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>,
{
type Writer = SpecificChannelsWriter<
'c,
<<Channels as IntoRecursive>::Recursive as WritableChannelsDescription<
<Storage::Pixel as IntoRecursive>::Recursive,
>>::RecursiveWriter,
Storage,
Channels,
>;
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());
debug_assert!(
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) }
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),
}
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct SpecificChannelsWriter<'channels, PixelWriter, Storage, Channels> {
channels: &'channels SpecificChannels<Storage, Channels>,
recursive_channel_writer: PixelWriter,
}
impl<PxWriter, Storage, Channels> ChannelsWriter
for SpecificChannelsWriter<'_, 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");
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
}
}
pub trait WritableChannelsDescription<Pixel>: Sync {
type RecursiveWriter: RecursivePixelWriter<Pixel>;
fn create_recursive_writer(&self, channels: &ChannelList) -> Self::RecursiveWriter;
fn channel_descriptions_list(&self) -> SmallVec<[ChannelDescription; 5]>;
}
impl WritableChannelsDescription<Self> for NoneMore {
type RecursiveWriter = Self;
fn create_recursive_writer(&self, _: &ChannelList) -> Self::RecursiveWriter {
Self
}
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 {
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,
},
)
}
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 {
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,
}),
)
}
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
}
}
pub trait RecursivePixelWriter<Pixel>: Sync {
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>>>;
#[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 byte_writer = &mut &mut bytes[byte_start_index..byte_start_index + byte_count];
let write_error_msg = "invalid memory buffer length when writing";
match self.target_sample_type {
SampleType::F16 => {
for sample in samples {
sample.to_f16().write_ne(byte_writer).expect(write_error_msg);
}
}
SampleType::F32 => {
for sample in samples {
sample.to_f32().write_ne(byte_writer).expect(write_error_msg);
}
}
SampleType::U32 => {
for sample in samples {
sample.to_u32().write_ne(byte_writer).expect(write_error_msg);
}
}
}
debug_assert!(byte_writer.is_empty(), "all samples are written, but more were expected");
}
}
impl RecursivePixelWriter<Self> for NoneMore {
fn write_pixels<FullPixel>(
&self,
_: &mut [u8],
_: &[FullPixel],
_: impl Fn(&FullPixel) -> &Self,
) {
}
}
impl<Inner, InnerPixel, Sample: IntoNativeSample>
RecursivePixelWriter<Recursive<InnerPixel, Sample>> for RecursiveWriter<Inner, Sample>
where
Inner: RecursivePixelWriter<InnerPixel>,
{
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)]
mod test {
use crate::{
image::{pixel_vec::PixelVec, write::channels::WritableChannels, SpecificChannels},
meta::attribute::{ChannelDescription, SampleType},
prelude::f16,
};
#[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>) {}
}
}