diff options
author | Valentin Popov <valentin@popov.link> | 2024-01-08 00:21:28 +0300 |
---|---|---|
committer | Valentin Popov <valentin@popov.link> | 2024-01-08 00:21:28 +0300 |
commit | 1b6a04ca5504955c571d1c97504fb45ea0befee4 (patch) | |
tree | 7579f518b23313e8a9748a88ab6173d5e030b227 /vendor/exr/src/image/channel_groups.rs | |
parent | 5ecd8cf2cba827454317368b68571df0d13d7842 (diff) | |
download | fparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.tar.xz fparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.zip |
Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
Diffstat (limited to 'vendor/exr/src/image/channel_groups.rs')
-rw-r--r-- | vendor/exr/src/image/channel_groups.rs | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/vendor/exr/src/image/channel_groups.rs b/vendor/exr/src/image/channel_groups.rs new file mode 100644 index 0000000..7d74375 --- /dev/null +++ b/vendor/exr/src/image/channel_groups.rs @@ -0,0 +1,267 @@ + +use std::collections::HashMap; +use crate::image::write::channels::{WritableChannels, ChannelsWriter}; +use crate::meta::attribute::{LevelMode, ChannelList, Text, TextSlice, ChannelInfo}; +use crate::meta::header::Header; +use crate::image::read::layers::{ReadChannels, ChannelsReader}; +use crate::block::{BlockIndex, UncompressedBlock}; +use crate::block::lines::{collect_uncompressed_block_from_lines, LineIndex}; +use std::io::{Cursor, Read}; +use crate::error::{Result, UnitResult}; +use crate::block::chunk::TileCoordinates; +use crate::prelude::SmallVec; + + + + + +pub struct ChannelGroups<ChannelGroup> { + channel_group: Option<ChannelGroup>, + children: HashMap<Text, Self> +} + + +impl<ChannelGroup> ChannelGroups<ChannelGroup> { + + + // pub fn visit_groups_mut(&mut self, visitor: impl Fn(&mut Channels)) { + // } + + + + pub fn groups(&self) -> SmallVec<[&ChannelGroup; 12]> { + let children = self.children.iter().flat_map(|group| group.groups()); + self.channel_group.iter().chain(children).collect() + } + + pub fn lookup_group(&self, group_name: &TextSlice) -> Option<&ChannelGroup> { + let dot_index = group_name.iter().position('.'); + if let Some(dot_index) = dot_index { + let group_name = &group_name[.. dot_index]; + let child_name = &group_name[dot_index + 1 ..]; + self.children.get(group_name) + .and_then(|child| child.lookup(child_name)) + } + else { + self.channel_group.lookup(name) + } + } + + + /*pub fn insert_group(&mut self, full_name: &TextSlice, value: ChannelGroup) { + let dot_index = full_name.iter().position('.'); + if let Some(dot_index) = dot_index { + let group_name = &group_name[.. dot_index]; + let name_rest = &group_name[dot_index + 1 ..]; + + self.children.entry(Text::from_slice_unchecked(group_name)) + .or_insert(|| ); + + // self.children.insert(Text::from_slice_unchecked(group_name), value) + // .and_then(|child| child.lookup(name_rest)); + } + else { + self.channel_group.lookup(name); + } + }*/ + + pub fn map<T>(self, mapper: impl FnMut(ChannelGroup) -> T) -> ChannelGroups<T> { + ChannelGroups { + children: self.channel_group.iter().map(&mapper).collect(), + channel_group: self.channel_group.map(mapper), + } + } +} + + +pub fn parse_channel_list_groups<T>(channels: impl Iterator<Item=(Text, T)>) + -> ChannelGroups<SmallVec<(Text, T)>> +{ + fn insert_into_groups(groups: &mut ChannelGroups<SmallVec<(Text, T)>>, name: Text, value: T) { + let dot_index = name.as_slice().iter().position('.'); + + if let Some(dot_index) = dot_index { + // insert into child group + + let group_name = Text::from_slice_unchecked(&name.as_slice()[.. dot_index]); + let child_channel = Text::from_slice_unchecked(&name.as_slice()[dot_index + 1 ..]); + + let child_group = groups.children.entry(group_name) + .or_insert(ChannelGroups { channel_group: None, children: Default::default() }); + + insert_into_groups(child_group, child_channel, value); + } + + else { + // insert directly into group + + if groups.channel_group.is_none() { + groups.channel_group = Some(SmallVec::new()); + } + + groups.channel_group.unwrap().push(value); + } + } + + let mut result = ChannelGroups { channel_group: None, children: HashMap::default() }; + for (name, value) in channels { insert_into_groups(&mut result, name, value); } + result +} + + +impl<'slf, ChannelGroup> WritableChannels<'slf> for ChannelGroups<ChannelGroup> + where ChannelGroup: WritableChannels<'slf> +{ + fn infer_channel_list(&self) -> ChannelList { + // TODO what about empty groups with NO channels?? + + let child_channels = self.children.iter().flat_map(|(group_name, child)| { + let mut child_channels = child.infer_channel_list().list; + for channel in &mut child_channels { channel.name.push_front(group_name) }; + child_channels + }); + + let mut own_channels = self.channel_group + .map(|chans| chans.infer_channel_list().list) + .unwrap_or_default(); + + own_channels.extend(child_channels); + own_channels.sort_unstable(); // TODO only once at end + ChannelList::new(own_channels) // might be empty, but will be checked in MetaData::validate() + } + + fn level_mode(&self) -> LevelMode { + fn find_mode_or_none(channels: &Self) -> Option<LevelMode> { + channels.channel_group.map(WritableChannels::level_mode).or_else(|| { + channels.children.iter().map(find_mode_or_none).next() + }) + } + + let mode = find_mode_or_none(self) + .expect("empty channel groups (check failed)"); // TODO only happens for empty channels, right? panic maybe? + + if let Some(chans) = self.channel_group.as_ref() { + debug_assert_eq!(chans.level_mode(), mode, "level mode must be equal for all legacy channel groups") + } + + debug_assert!( + self.children.values() + .flat_map(find_mode_or_none) + .all(|child_mode| child_mode == mode), + + "level mode must be equal for all legacy channel groups" + ); + + mode + } + + type Writer = GroupChannelsWriter<'slf, ChannelGroup>; + + fn create_writer(&'slf self, header: &Header) -> Self::Writer { + let channels = header.channels.list.iter() + .map(|channel_info|{ + // hashmap order is not guaranteed? so look up each channel group manually instead of generating new + let channels = self.lookup_group(channel_info.name.as_slice()) + .expect("channels not found bug"); + + channels.create_writer(header) // channel_info.name.clone() + }) + .collect(); + + GroupChannelsWriter { channels_list: channels } + } +} + +struct GroupChannelsWriter<'c, ChannelGroupWriter> { + channels_list: Vec<&'c ChannelGroupWriter>, +} + +impl<'c, Channels> ChannelsWriter for GroupChannelsWriter<'c, Channels> where Channels: ChannelsWriter { + fn extract_uncompressed_block(&self, header: &Header, block: BlockIndex) -> Vec<u8> { + let mut blocks_per_channel: Vec<Cursor<Vec<u8>>> = self + .channels_list.iter() + .map(|channels| Cursor::new(channels.extract_uncompressed_block(header, block))) + .collect(); + + UncompressedBlock::uncompressed_block_from_lines(header, block, |line|{ + let channel_reader = &mut blocks_per_channel[line.location.channel]; // TODO subsampling + + // read from specific channel into total byte block + // this assumes that the lines in the callback are iterated in strictly increasing order + // because each channel reader is consumed + channel_reader.read_exact(line.value) + .expect("collecting grouped channel byte block failed"); + }) + } +} + + +struct ReadChannelGroups<ReadChannelGroup> { + read_channels: ReadChannelGroup +} + +struct ChannelGroupsReader<ChannelGroupReader> { + channels: ChannelGroups<usize>, + indexed_channels: Vec<ChannelGroupReader>, +} + +impl<'s, ReadChannelGroup> ReadChannels<'s> for ReadChannelGroups<ReadChannelGroup> + where ReadChannelGroup: ReadChannels<'s> +{ + type Reader = ChannelGroupsReader<ReadChannelGroup::Reader>; + + fn create_channels_reader(&'s self, header: &Header) -> Result<Self::Reader> { + let swap = |(a,b)| (b,a); + let channel_groups = parse_channel_list_groups( + header.channels.list.iter().enumerate().map(swap) + ); + + let mut indexed_channels = Vec::new(); + let channel_groups = channel_groups.map(|channels| { + + let mut channels_header = header.clone(); // TODO no clone? + channels_header.channels = ChannelList::new(channels.iter().map(|(name, index)|{ + let mut channel_info = header.channels.list[index].clone(); + channel_info.name = name; + channel_info + }).collect()); // FIXME does not comply to `header.chunk_count` and that stuff?? change ReadChannels fn signature? + + indexed_channels.push(self.read_channels.create_channels_reader(&channels_header)); + + // FIXME this is not the original order indexed_channels.len() - 1 + indexed_channels[] + }); + + Ok(ChannelGroupsReader { + channels: channel_groups, + indexed_channels, + }) + + /*Ok(ChannelGroupsReader { + channels: header.channels.list.iter().map(|channel| { + let mut channels_header = header.clone(); + + let reader = self.read_channels.create_channels_reader(&channels_header); + (channels_header, reader) + }).collect(), + })*/ + } +} + +impl<ChannelGroupReader> ChannelsReader for ChannelGroupsReader<ChannelGroupReader> where ChannelGroupReader: ChannelsReader { + type Channels = ChannelGroups<ChannelGroupReader::Channels>; + + fn filter_block(&self, tile: (usize, &TileCoordinates)) -> bool { + self.indexed_channels.iter().any(|channel| channel.filter_block(tile)) + } + + fn read_block(&mut self, header: &Header, block: UncompressedBlock) -> UnitResult { + block.for_lines(|line|{ + + }) + } + + fn into_channels(self) -> Self::Channels { + + } +}
\ No newline at end of file |