1
2pub mod read;
27pub mod write;
28pub mod crop;
29pub mod pixel_vec;
30pub mod recursive;
31use crate::meta::header::{ImageAttributes, LayerAttributes};
35use crate::meta::attribute::{Text, LineOrder};
36use half::f16;
37use crate::math::{Vec2, RoundingMode};
38use crate::compression::Compression;
39use smallvec::{SmallVec};
40use crate::error::Error;
41
42pub(crate) fn ignore_progress(_progress: f64){}
44
45pub type AnyImage = Image<Layers<AnyChannels<Levels<FlatSamples>>>>;
48
49pub type FlatImage = Image<Layers<AnyChannels<FlatSamples>>>;
52
53pub type PixelLayersImage<Storage, Channels> = Image<Layers<SpecificChannels<Storage, Channels>>>;
55
56pub type PixelImage<Storage, Channels> = Image<Layer<SpecificChannels<Storage, Channels>>>;
58
59pub type RgbaLayersImage<Storage> = PixelLayersImage<Storage, RgbaChannels>;
61
62pub type RgbaImage<Storage> = PixelImage<Storage, RgbaChannels>;
64
65pub type RgbaChannels = (ChannelDescription, ChannelDescription, ChannelDescription, Option<ChannelDescription>);
68
69pub type RgbChannels = (ChannelDescription, ChannelDescription, ChannelDescription);
71
72#[derive(Debug, Clone, PartialEq)]
75pub struct Image<Layers> {
76
77 pub attributes: ImageAttributes,
82
83 pub layer_data: Layers,
86}
87
88pub type Layers<Channels> = SmallVec<[Layer<Channels>; 2]>;
90
91#[derive(Debug, Clone, PartialEq)]
94pub struct Layer<Channels> {
95
96 pub channel_data: Channels,
98
99 pub attributes: LayerAttributes,
104
105 pub size: Vec2<usize>,
108
109 pub encoding: Encoding
111}
112
113#[derive(Copy, Clone, Debug, PartialEq)]
115pub struct Encoding {
116
117 pub compression: Compression,
120
121 pub blocks: Blocks,
125
126 pub line_order: LineOrder,
130}
131
132#[derive(Copy, Clone, Debug, PartialEq, Eq)]
134pub enum Blocks {
135
136 ScanLines,
139
140 Tiles (Vec2<usize>)
147}
148
149
150#[derive(Debug, Clone, PartialEq, Eq)]
154pub struct SpecificChannels<Pixels, ChannelsDescription> {
155
156 pub channels: ChannelsDescription, pub pixels: Pixels, }
164
165
166#[derive(Debug, Clone, PartialEq)]
169pub struct AnyChannels<Samples> {
170
171 pub list: SmallVec<[AnyChannel<Samples>; 4]>
174}
175
176#[derive(Debug, Clone, PartialEq)]
179pub struct AnyChannel<Samples> {
180
181 pub name: Text,
183
184 pub sample_data: Samples,
187
188 pub quantize_linearly: bool,
194
195 pub sampling: Vec2<usize>,
201}
202
203#[derive(Debug, Clone, PartialEq, Eq)]
206pub enum Levels<Samples> {
207
208 Singular(Samples),
211
212 Mip
214 {
215 rounding_mode: RoundingMode,
217
218 level_data: LevelMaps<Samples>
220 },
221
222 Rip
224 {
225 rounding_mode: RoundingMode,
227
228 level_data: RipMaps<Samples>
230 },
231}
232
233pub type LevelMaps<Samples> = Vec<Samples>;
236
237#[derive(Debug, Clone, PartialEq, Eq)]
242pub struct RipMaps<Samples> {
243
244 pub map_data: LevelMaps<Samples>,
246
247 pub level_count: Vec2<usize>,
249}
250
251
252#[derive(Clone, PartialEq)] pub enum FlatSamples {
269
270 F16(Vec<f16>),
272
273 F32(Vec<f32>),
275
276 U32(Vec<u32>),
278}
279
280
281use crate::block::samples::*;
289use crate::meta::attribute::*;
290use crate::error::Result;
291use crate::block::samples::Sample;
292use crate::image::write::channels::*;
293use crate::image::write::layers::WritableLayers;
294use crate::image::write::samples::{WritableSamples};
295use crate::meta::{mip_map_levels, rip_map_levels};
296use crate::io::Data;
297use crate::image::recursive::{NoneMore, Recursive, IntoRecursive};
298use std::marker::PhantomData;
299use std::ops::Not;
300use crate::image::validate_results::{ValidationOptions};
301
302
303impl<Channels> Layer<Channels> {
304 pub fn absolute_bounds(&self) -> IntegerBounds {
306 IntegerBounds::new(self.attributes.layer_position, self.size)
307 }
308}
309
310
311impl<SampleStorage, Channels> SpecificChannels<SampleStorage, Channels> {
312 pub fn new(channels: Channels, source_samples: SampleStorage) -> Self
316 where
317 SampleStorage: GetPixel,
318 SampleStorage::Pixel: IntoRecursive,
319 Channels: Sync + Clone + IntoRecursive,
320 <Channels as IntoRecursive>::Recursive: WritableChannelsDescription<<SampleStorage::Pixel as IntoRecursive>::Recursive>,
321 {
322 SpecificChannels { channels, pixels: source_samples }
323 }
324}
325
326pub trait IntoSample: IntoNativeSample {
329
330 const PREFERRED_SAMPLE_TYPE: SampleType;
332}
333
334impl IntoSample for f16 { const PREFERRED_SAMPLE_TYPE: SampleType = SampleType::F16; }
335impl IntoSample for f32 { const PREFERRED_SAMPLE_TYPE: SampleType = SampleType::F32; }
336impl IntoSample for u32 { const PREFERRED_SAMPLE_TYPE: SampleType = SampleType::U32; }
337
338#[derive(Debug)]
342pub struct SpecificChannelsBuilder<RecursiveChannels, RecursivePixel> {
343 channels: RecursiveChannels,
344 px: PhantomData<RecursivePixel>
345}
346
347pub trait CheckDuplicates {
350
351 fn already_contains(&self, name: &Text) -> bool;
353}
354
355impl CheckDuplicates for NoneMore {
356 fn already_contains(&self, _: &Text) -> bool { false }
357}
358
359impl<Inner: CheckDuplicates> CheckDuplicates for Recursive<Inner, ChannelDescription> {
360 fn already_contains(&self, name: &Text) -> bool {
361 &self.value.name == name || self.inner.already_contains(name)
362 }
363}
364
365impl SpecificChannels<(),()>
366{
367 pub fn build() -> SpecificChannelsBuilder<NoneMore, NoneMore> {
371 SpecificChannelsBuilder { channels: NoneMore, px: Default::default() }
372 }
373}
374
375impl<RecursiveChannels: CheckDuplicates, RecursivePixel> SpecificChannelsBuilder<RecursiveChannels, RecursivePixel>
376{
377 pub fn with_channel<Sample: IntoSample>(self, name: impl Into<Text>)
385 -> SpecificChannelsBuilder<Recursive<RecursiveChannels, ChannelDescription>, Recursive<RecursivePixel, Sample>>
386 {
387 self.with_channel_details::<Sample>(ChannelDescription::named(name, Sample::PREFERRED_SAMPLE_TYPE))
388 }
389
390 pub fn with_channel_details<Sample: Into<Sample>>(self, channel: ChannelDescription)
396 -> SpecificChannelsBuilder<Recursive<RecursiveChannels, ChannelDescription>, Recursive<RecursivePixel, Sample>>
397 {
398 assert!(self.channels.already_contains(&channel.name).not(), "channel name `{}` is duplicate", channel.name);
400
401 SpecificChannelsBuilder {
402 channels: Recursive::new(self.channels, channel),
403 px: PhantomData::default()
404 }
405 }
406
407 pub fn with_pixels<Pixels>(self, get_pixel: Pixels) -> SpecificChannels<Pixels, RecursiveChannels>
414 where Pixels: GetPixel, <Pixels as GetPixel>::Pixel: IntoRecursive<Recursive=RecursivePixel>,
415 {
416 SpecificChannels {
417 channels: self.channels,
418 pixels: get_pixel
419 }
420 }
421
422 pub fn with_pixel_fn<Pixel, Pixels>(self, get_pixel: Pixels) -> SpecificChannels<Pixels, RecursiveChannels>
431 where Pixels: Sync + Fn(Vec2<usize>) -> Pixel, Pixel: IntoRecursive<Recursive=RecursivePixel>,
432 {
433 SpecificChannels {
434 channels: self.channels,
435 pixels: get_pixel
436 }
437 }
438}
439
440impl<SampleStorage> SpecificChannels<
441 SampleStorage, (ChannelDescription, ChannelDescription, ChannelDescription, ChannelDescription)
442>
443{
444
445 pub fn rgba<R, G, B, A>(source_samples: SampleStorage) -> Self
450 where R: IntoSample, G: IntoSample,
451 B: IntoSample, A: IntoSample,
452 SampleStorage: GetPixel<Pixel=(R, G, B, A)>
453 {
454 SpecificChannels {
455 channels: (
456 ChannelDescription::named("R", R::PREFERRED_SAMPLE_TYPE),
457 ChannelDescription::named("G", G::PREFERRED_SAMPLE_TYPE),
458 ChannelDescription::named("B", B::PREFERRED_SAMPLE_TYPE),
459 ChannelDescription::named("A", A::PREFERRED_SAMPLE_TYPE),
460 ),
461 pixels: source_samples
462 }
463 }
464}
465
466impl<SampleStorage> SpecificChannels<
467 SampleStorage, (ChannelDescription, ChannelDescription, ChannelDescription)
468>
469{
470
471 pub fn rgb<R, G, B>(source_samples: SampleStorage) -> Self
476 where R: IntoSample, G: IntoSample, B: IntoSample,
477 SampleStorage: GetPixel<Pixel=(R, G, B)>
478 {
479 SpecificChannels {
480 channels: (
481 ChannelDescription::named("R", R::PREFERRED_SAMPLE_TYPE),
482 ChannelDescription::named("G", G::PREFERRED_SAMPLE_TYPE),
483 ChannelDescription::named("B", B::PREFERRED_SAMPLE_TYPE),
484 ),
485 pixels: source_samples
486 }
487 }
488}
489
490
491pub type FlatSamplesPixel = SmallVec<[Sample; 8]>;
494
495impl Layer<AnyChannels<FlatSamples>> {
497
498 pub fn sample_vec_at(&self, position: Vec2<usize>) -> FlatSamplesPixel {
500 self.samples_at(position).collect()
501 }
502
503 pub fn samples_at(&self, position: Vec2<usize>) -> FlatSampleIterator<'_> {
505 FlatSampleIterator {
506 layer: self,
507 channel_index: 0,
508 position
509 }
510 }
511}
512
513#[derive(Debug, Copy, Clone, PartialEq)]
515pub struct FlatSampleIterator<'s> {
516 layer: &'s Layer<AnyChannels<FlatSamples>>,
517 channel_index: usize,
518 position: Vec2<usize>,
519}
520
521impl Iterator for FlatSampleIterator<'_> {
522 type Item = Sample;
523
524 fn next(&mut self) -> Option<Self::Item> {
525 if self.channel_index < self.layer.channel_data.list.len() {
526 let channel = &self.layer.channel_data.list[self.channel_index];
527 let sample = channel.sample_data.value_by_flat_index(self.position.flat_index_for_size(self.layer.size));
528 self.channel_index += 1;
529 Some(sample)
530 }
531 else { None }
532 }
533
534 fn nth(&mut self, pos: usize) -> Option<Self::Item> {
535 self.channel_index += pos;
536 self.next()
537 }
538
539 fn size_hint(&self) -> (usize, Option<usize>) {
540 let remaining = self.layer.channel_data.list.len().saturating_sub(self.channel_index);
541 (remaining, Some(remaining))
542 }
543}
544
545impl ExactSizeIterator for FlatSampleIterator<'_> {}
546
547impl<SampleData> AnyChannels<SampleData>{
548
549 pub fn sort(mut list: SmallVec<[AnyChannel<SampleData>; 4]>) -> Self {
551 list.sort_unstable_by_key(|channel| channel.name.clone()); Self { list }
553 }
554}
555
556impl<LevelSamples> Levels<LevelSamples> {
558
559 pub fn get_level(&self, level: Vec2<usize>) -> Result<&LevelSamples> {
561 match self {
562 Levels::Singular(block) => {
563 debug_assert_eq!(level, Vec2(0,0), "singular image cannot write leveled blocks bug");
564 Ok(block)
565 },
566
567 Levels::Mip { level_data, .. } => {
568 debug_assert_eq!(level.x(), level.y(), "mip map levels must be equal on x and y bug");
569 level_data.get(level.x()).ok_or(Error::invalid("block mip level index"))
570 },
571
572 Levels::Rip { level_data, .. } => {
573 level_data.get_by_level(level).ok_or(Error::invalid("block rip level index"))
574 }
575 }
576 }
577
578 pub fn get_level_mut(&mut self, level: Vec2<usize>) -> Result<&mut LevelSamples> {
581 match self {
582 Levels::Singular(ref mut block) => {
583 debug_assert_eq!(level, Vec2(0,0), "singular image cannot write leveled blocks bug");
584 Ok(block)
585 },
586
587 Levels::Mip { level_data, .. } => {
588 debug_assert_eq!(level.x(), level.y(), "mip map levels must be equal on x and y bug");
589 level_data.get_mut(level.x()).ok_or(Error::invalid("block mip level index"))
590 },
591
592 Levels::Rip { level_data, .. } => {
593 level_data.get_by_level_mut(level).ok_or(Error::invalid("block rip level index"))
594 }
595 }
596 }
597
598 pub fn levels_as_slice(&self) -> &[LevelSamples] {
600 match self {
601 Levels::Singular(data) => std::slice::from_ref(data),
602 Levels::Mip { level_data, .. } => level_data,
603 Levels::Rip { level_data, .. } => &level_data.map_data,
604 }
605 }
606
607 pub fn levels_as_slice_mut(&mut self) -> &mut [LevelSamples] {
609 match self {
610 Levels::Singular(data) => std::slice::from_mut(data),
611 Levels::Mip { level_data, .. } => level_data,
612 Levels::Rip { level_data, .. } => &mut level_data.map_data,
613 }
614 }
615
616 pub fn level_mode(&self) -> LevelMode {
628 match self {
629 Levels::Singular(_) => LevelMode::Singular,
630 Levels::Mip { .. } => LevelMode::MipMap,
631 Levels::Rip { .. } => LevelMode::RipMap,
632 }
633 }
634}
635
636impl<Samples> RipMaps<Samples> {
637
638 pub fn get_level_index(&self, level: Vec2<usize>) -> usize {
640 level.flat_index_for_size(self.level_count)
641 }
642
643 pub fn get_by_level(&self, level: Vec2<usize>) -> Option<&Samples> {
645 self.map_data.get(self.get_level_index(level))
646 }
647
648 pub fn get_by_level_mut(&mut self, level: Vec2<usize>) -> Option<&mut Samples> {
650 let index = self.get_level_index(level);
651 self.map_data.get_mut(index)
652 }
653}
654
655impl FlatSamples {
656
657 pub fn len(&self) -> usize {
660 match self {
661 FlatSamples::F16(vec) => vec.len(),
662 FlatSamples::F32(vec) => vec.len(),
663 FlatSamples::U32(vec) => vec.len(),
664 }
665 }
666
667 pub fn values_as_f32<'s>(&'s self) -> impl 's + Iterator<Item = f32> {
671 self.values().map(|sample| sample.to_f32())
672 }
673
674 pub fn values<'s>(&'s self) -> impl 's + Iterator<Item = Sample> {
678 (0..self.len()).map(move |index| self.value_by_flat_index(index))
679 }
680
681 pub fn value_by_flat_index(&self, index: usize) -> Sample {
685 match self {
686 FlatSamples::F16(vec) => Sample::F16(vec[index]),
687 FlatSamples::F32(vec) => Sample::F32(vec[index]),
688 FlatSamples::U32(vec) => Sample::U32(vec[index]),
689 }
690 }
691}
692
693
694impl<'s, ChannelData:'s> Layer<ChannelData> {
695
696 pub fn new(
699 dimensions: impl Into<Vec2<usize>>,
700 attributes: LayerAttributes,
701 encoding: Encoding,
702 channels: ChannelData
703 ) -> Self
704 where ChannelData: WritableChannels<'s>
705 {
706 Layer { channel_data: channels, attributes, size: dimensions.into(), encoding }
707 }
708
709 pub fn levels_with_resolution<'l, L>(&self, levels: &'l Levels<L>) -> Box<dyn 'l + Iterator<Item=(&'l L, Vec2<usize>)>> {
712 match levels {
713 Levels::Singular(level) => Box::new(std::iter::once((level, self.size))),
714
715 Levels::Mip { rounding_mode, level_data } => Box::new(level_data.iter().zip(
716 mip_map_levels(*rounding_mode, self.size)
717 .map(|(_index, size)| size)
718 )),
719
720 Levels::Rip { rounding_mode, level_data } => Box::new(level_data.map_data.iter().zip(
721 rip_map_levels(*rounding_mode, self.size)
722 .map(|(_index, size)| size)
723 )),
724 }
725 }
726}
727
728impl Encoding {
729
730 pub const UNCOMPRESSED: Encoding = Encoding {
733 compression: Compression::Uncompressed,
734 blocks: Blocks::ScanLines, line_order: LineOrder::Increasing };
737
738 pub const FAST_LOSSLESS: Encoding = Encoding {
741 compression: Compression::RLE,
742 blocks: Blocks::Tiles(Vec2(64, 64)), line_order: LineOrder::Unspecified
744 };
745
746 pub const SMALL_LOSSLESS: Encoding = Encoding {
748 compression: Compression::ZIP16,
749 blocks: Blocks::ScanLines, line_order: LineOrder::Increasing
751 };
752
753 pub const SMALL_FAST_LOSSLESS: Encoding = Encoding {
755 compression: Compression::PIZ,
756 blocks: Blocks::Tiles(Vec2(256, 256)),
757 line_order: LineOrder::Unspecified
758 };
759}
760
761impl Default for Encoding {
762 fn default() -> Self { Encoding::FAST_LOSSLESS }
763}
764
765impl<'s, LayerData: 's> Image<LayerData> where LayerData: WritableLayers<'s> {
766 pub fn new(image_attributes: ImageAttributes, layer_data: LayerData) -> Self {
768 Image { attributes: image_attributes, layer_data }
769 }
770}
771
772impl<'s, Channels: 's> Image<Layers<Channels>> where Channels: WritableChannels<'s> {
774 pub fn from_layers(image_attributes: ImageAttributes, layer_data: impl Into<Layers<Channels>>) -> Self {
776 Self::new(image_attributes, layer_data.into())
777 }
778}
779
780
781impl<'s, ChannelData:'s> Image<Layer<ChannelData>> where ChannelData: WritableChannels<'s> {
782
783 pub fn from_layer(layer: Layer<ChannelData>) -> Self {
785 let bounds = IntegerBounds::new(layer.attributes.layer_position, layer.size);
786 Self::new(ImageAttributes::new(bounds), layer)
787 }
788
789 pub fn from_encoded_channels(size: impl Into<Vec2<usize>>, encoding: Encoding, channels: ChannelData) -> Self {
791 Self::from_layer(Layer::new(size, LayerAttributes::default(), encoding, channels))
793 }
794
795 pub fn from_channels(size: impl Into<Vec2<usize>>, channels: ChannelData) -> Self {
797 Self::from_encoded_channels(size, Encoding::default(), channels)
798 }
799}
800
801
802impl Image<NoneMore> {
803
804 pub fn empty(attributes: ImageAttributes) -> Self { Self { attributes, layer_data: NoneMore } }
807}
808
809impl<'s, InnerLayers: 's> Image<InnerLayers> where
810 InnerLayers: WritableLayers<'s>,
811{
812 pub fn with_layer<NewChannels>(self, layer: Layer<NewChannels>)
815 -> Image<Recursive<InnerLayers, Layer<NewChannels>>>
816 where NewChannels: 's + WritableChannels<'s>
817 {
818 Image {
819 attributes: self.attributes,
820 layer_data: Recursive::new(self.layer_data, layer)
821 }
822 }
823}
824
825
826impl<'s, SampleData: 's> AnyChannel<SampleData> {
827
828 pub fn new(name: impl Into<Text>, sample_data: SampleData) -> Self where SampleData: WritableSamples<'s> {
835 let name: Text = name.into();
836
837 AnyChannel {
838 quantize_linearly: ChannelDescription::guess_quantization_linearity(&name),
839 name, sample_data,
840 sampling: Vec2(1, 1),
841 }
842 }
843
844 }
851
852impl std::fmt::Debug for FlatSamples {
853 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
854 if self.len() <= 6 {
855 match self {
856 FlatSamples::F16(vec) => vec.fmt(formatter),
857 FlatSamples::F32(vec) => vec.fmt(formatter),
858 FlatSamples::U32(vec) => vec.fmt(formatter),
859 }
860 }
861 else {
862 match self {
863 FlatSamples::F16(vec) => write!(formatter, "[f16; {}]", vec.len()),
864 FlatSamples::F32(vec) => write!(formatter, "[f32; {}]", vec.len()),
865 FlatSamples::U32(vec) => write!(formatter, "[u32; {}]", vec.len()),
866 }
867 }
868 }
869}
870
871
872
873pub mod validate_results {
877 use crate::prelude::*;
878 use smallvec::Array;
879 use crate::prelude::recursive::*;
880 use crate::image::write::samples::WritableSamples;
881 use std::ops::Not;
882 use crate::block::samples::IntoNativeSample;
883
884 pub trait ValidateResult {
887
888 fn assert_equals_result(&self, result: &Self) {
899 self.validate_result(result, ValidationOptions::default(), || String::new()).unwrap();
900 }
901
902 fn validate_result(
911 &self, lossy_result: &Self,
912 options: ValidationOptions,
913 context: impl Fn() -> String
916 ) -> ValidationResult;
917 }
918
919 #[derive(Default, Debug, Eq, PartialEq, Hash, Copy, Clone)]
921 pub struct ValidationOptions {
922 allow_lossy: bool,
923 nan_converted_to_zero: bool,
924 }
925
926 pub type ValidationResult = std::result::Result<(), String>;
928
929
930 impl<C> ValidateResult for Image<C> where C: ValidateResult {
931 fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
932 if self.attributes != other.attributes { Err(location() + "| image > attributes") }
933 else { self.layer_data.validate_result(&other.layer_data, options, || location() + "| image > layer data") }
934 }
935 }
936
937 impl<S> ValidateResult for Layer<AnyChannels<S>>
938 where AnyChannel<S>: ValidateResult, S: for<'a> WritableSamples<'a>
939 {
940 fn validate_result(&self, other: &Self, _overridden: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
941 let location = || format!("{} (layer `{:?}`)", location(), self.attributes.layer_name);
942 if self.attributes != other.attributes { Err(location() + " > attributes") }
943 else if self.encoding != other.encoding { Err(location() + " > encoding") }
944 else if self.size != other.size { Err(location() + " > size") }
945 else if self.channel_data.list.len() != other.channel_data.list.len() { Err(location() + " > channel count") }
946 else {
947 for (own_chan, other_chan) in self.channel_data.list.iter().zip(other.channel_data.list.iter()) {
948 own_chan.validate_result(
949 other_chan,
950
951 ValidationOptions {
952 allow_lossy: other.encoding.compression
954 .is_lossless_for(other_chan.sample_data.sample_type()).not(),
955
956 nan_converted_to_zero: other.encoding.compression.supports_nan().not()
958 },
959
960 || format!("{} > channel `{}`", location(), own_chan.name)
961 )?;
962 }
963 Ok(())
964 }
965 }
966 }
967
968 impl<Px, Desc> ValidateResult for Layer<SpecificChannels<Px, Desc>>
969 where SpecificChannels<Px, Desc>: ValidateResult
970 {
971 fn validate_result(&self, other: &Self, _overridden: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
974 let location = || format!("{} (layer `{:?}`)", location(), self.attributes.layer_name);
975
976 if self.attributes != other.attributes { Err(location() + " > attributes") }
978 else if self.encoding != other.encoding { Err(location() + " > encoding") }
979 else if self.size != other.size { Err(location() + " > size") }
980 else {
981 let options = ValidationOptions {
982 allow_lossy: other.encoding.compression.may_loose_data(),nan_converted_to_zero: other.encoding.compression.supports_nan().not()
988 };
989
990 self.channel_data.validate_result(&other.channel_data, options, || location() + " > channel_data")?;
991 Ok(())
992 }
993 }
994 }
995
996 impl<S> ValidateResult for AnyChannels<S> where S: ValidateResult {
997 fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
998 self.list.validate_result(&other.list, options, location)
999 }
1000 }
1001
1002 impl<S> ValidateResult for AnyChannel<S> where S: ValidateResult {
1003 fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1004 if self.name != other.name { Err(location() + " > name") }
1005 else if self.quantize_linearly != other.quantize_linearly { Err(location() + " > quantize_linearly") }
1006 else if self.sampling != other.sampling { Err(location() + " > sampling") }
1007 else {
1008 self.sample_data.validate_result(&other.sample_data, options, || location() + " > sample_data")
1009 }
1010 }
1011 }
1012
1013 impl<Pxs, Chans> ValidateResult for SpecificChannels<Pxs, Chans> where Pxs: ValidateResult, Chans: Eq {
1014 fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1015 if self.channels != other.channels { Err(location() + " > specific channels") }
1016 else { self.pixels.validate_result(&other.pixels, options, || location() + " > specific pixels") }
1017 }
1018 }
1019
1020 impl<S> ValidateResult for Levels<S> where S: ValidateResult {
1021 fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1022 self.levels_as_slice().validate_result(&other.levels_as_slice(), options, || location() + " > levels")
1023 }
1024 }
1025
1026 impl ValidateResult for FlatSamples {
1027 fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1028 use FlatSamples::*;
1029 match (self, other) {
1030 (F16(values), F16(other_values)) => values.as_slice().validate_result(&other_values.as_slice(), options, ||location() + " > f16 samples"),
1031 (F32(values), F32(other_values)) => values.as_slice().validate_result(&other_values.as_slice(), options, ||location() + " > f32 samples"),
1032 (U32(values), U32(other_values)) => values.as_slice().validate_result(&other_values.as_slice(), options, ||location() + " > u32 samples"),
1033 (own, other) => Err(format!("{}: samples type mismatch. expected {:?}, found {:?}", location(), own.sample_type(), other.sample_type()))
1034 }
1035 }
1036 }
1037
1038 impl<T> ValidateResult for &[T] where T: ValidateResult {
1039 fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1040 if self.len() != other.len() { Err(location() + " count") }
1041 else {
1042 for (index, (slf, other)) in self.iter().zip(other.iter()).enumerate() {
1043 slf.validate_result(other, options, ||format!("{} element [{}] of {}", location(), index, self.len()))?;
1044 }
1045 Ok(())
1046 }
1047 }
1048 }
1049
1050 impl<A: Array> ValidateResult for SmallVec<A> where A::Item: ValidateResult {
1051 fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1052 self.as_slice().validate_result(&other.as_slice(), options, location)
1053 }
1054 }
1055
1056 impl<A> ValidateResult for Vec<A> where A: ValidateResult {
1057 fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1058 self.as_slice().validate_result(&other.as_slice(), options, location)
1059 }
1060 }
1061
1062 impl<A,B,C,D> ValidateResult for (A, B, C, D) where A: Clone+ ValidateResult, B: Clone+ ValidateResult, C: Clone+ ValidateResult, D: Clone+ ValidateResult {
1063 fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1064 self.clone().into_recursive().validate_result(&other.clone().into_recursive(), options, location)
1065 }
1066 }
1067
1068 impl<A,B,C> ValidateResult for (A, B, C) where A: Clone+ ValidateResult, B: Clone+ ValidateResult, C: Clone+ ValidateResult {
1069 fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1070 self.clone().into_recursive().validate_result(&other.clone().into_recursive(), options, location)
1071 }
1072 }
1073
1074 impl ValidateResult for NoneMore {
1088 fn validate_result(&self, _: &Self, _: ValidationOptions, _: impl Fn()->String) -> ValidationResult { Ok(()) }
1089 }
1090
1091 impl<Inner, T> ValidateResult for Recursive<Inner, T> where Inner: ValidateResult, T: ValidateResult {
1092 fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1093 self.value.validate_result(&other.value, options, &location).and_then(|()|
1094 self.inner.validate_result(&other.inner, options, &location)
1095 )
1096 }
1097 }
1098
1099 impl<S> ValidateResult for Option<S> where S: ValidateResult {
1100 fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1101 match (self, other) {
1102 (None, None) => Ok(()),
1103 (Some(value), Some(other)) => value.validate_result(other, options, location),
1104 _ => Err(location() + ": option mismatch")
1105 }
1106 }
1107 }
1108
1109 impl ValidateResult for f32 {
1110 fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1111 if self == other || (self.is_nan() && other.is_nan()) || (options.nan_converted_to_zero && !self.is_normal() && *other == 0.0) {
1112 return Ok(());
1113 }
1114
1115 if options.allow_lossy {
1116 let epsilon = 0.06;
1117 let max_difference = 0.1;
1118
1119 let adaptive_threshold = epsilon * (self.abs() + other.abs());
1120 let tolerance = adaptive_threshold.max(max_difference);
1121 let difference = (self - other).abs();
1122
1123 return if difference <= tolerance { Ok(()) }
1124 else { Err(format!("{}: expected ~{}, found {} (adaptive tolerance {})", location(), self, other, tolerance)) };
1125 }
1126
1127 Err(format!("{}: expected exactly {}, found {}", location(), self, other))
1128 }
1129 }
1130
1131 impl ValidateResult for f16 {
1132 fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1133 if self.to_bits() == other.to_bits() { Ok(()) } else {
1134 self.to_f32().validate_result(&other.to_f32(), options, location)
1135 }
1136 }
1137 }
1138
1139 impl ValidateResult for u32 {
1140 fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1141 if self == other { Ok(()) } else { self.to_f32().validate_result(&other.to_f32(), options, location)
1143 }
1144 }
1145 }
1146
1147 impl ValidateResult for Sample {
1148 fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1149 use Sample::*;
1150 match (self, other) {
1151 (F16(a), F16(b)) => a.validate_result(b, options, ||location() + " (f16)"),
1152 (F32(a), F32(b)) => a.validate_result(b, options, ||location() + " (f32)"),
1153 (U32(a), U32(b)) => a.validate_result(b, options, ||location() + " (u32)"),
1154 (_,_) => Err(location() + ": sample type mismatch")
1155 }
1156 }
1157 }
1158
1159
1160 #[cfg(test)]
1161 mod test_value_result {
1162 use std::f32::consts::*;
1163 use std::io::Cursor;
1164 use crate::image::pixel_vec::PixelVec;
1165 use crate::image::validate_results::{ValidateResult, ValidationOptions};
1166 use crate::meta::attribute::LineOrder::Increasing;
1167 use crate::image::{FlatSamples};
1168
1169 fn expect_valid<T>(original: &T, result: &T, allow_lossy: bool, nan_converted_to_zero: bool) where T: ValidateResult {
1170 original.validate_result(
1171 result,
1172 ValidationOptions { allow_lossy, nan_converted_to_zero },
1173 || String::new()
1174 ).unwrap();
1175 }
1176
1177 fn expect_invalid<T>(original: &T, result: &T, allow_lossy: bool, nan_converted_to_zero: bool) where T: ValidateResult {
1178 assert!(original.validate_result(
1179 result,
1180 ValidationOptions { allow_lossy, nan_converted_to_zero },
1181 || String::new()
1182 ).is_err());
1183 }
1184
1185 #[test]
1186 fn test_f32(){
1187 let original:&[f32] = &[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, -20.4, f32::NAN];
1188 let lossy:&[f32] = &[0.0, 0.2, 0.2, 0.3, 0.4, 0.5, -20.5, f32::NAN];
1189
1190 expect_valid(&original, &original, true, true);
1191 expect_valid(&original, &original, true, false);
1192 expect_valid(&original, &original, false, true);
1193 expect_valid(&original, &original, false, false);
1194
1195 expect_invalid(&original, &lossy, false, false);
1196 expect_valid(&original, &lossy, true, false);
1197
1198 expect_invalid(&original, &&original[..original.len()-2], true, true);
1199
1200 expect_valid(&1_000_f32, &1_001_f32, true, false);
1202 expect_invalid(&1_000_f32, &1_200_f32, true, false);
1203
1204 expect_valid(&10_000_f32, &10_100_f32, true, false);
1205 expect_invalid(&10_000_f32, &12_000_f32, true, false);
1206
1207 expect_valid(&33_120_f32, &30_120_f32, true, false);
1208 expect_invalid(&33_120_f32, &20_120_f32, true, false);
1209 }
1210
1211 #[test]
1212 fn test_nan(){
1213 let original:&[f32] = &[ 0.0, f32::NAN, f32::NAN ];
1214 let lossy:&[f32] = &[ 0.0, f32::NAN, 0.0 ];
1215
1216 expect_valid(&original, &lossy, true, true);
1217 expect_invalid(&lossy, &original, true, true);
1218
1219 expect_valid(&lossy, &lossy, true, true);
1220 expect_valid(&lossy, &lossy, false, true);
1221 }
1222
1223 #[test]
1224 fn test_error(){
1225
1226 fn print_error<T: ValidateResult>(original: &T, lossy: &T, allow_lossy: bool){
1227 let message = original
1228 .validate_result(
1229 &lossy,
1230 ValidationOptions { allow_lossy, .. Default::default() },
1231 || String::new() )
1233 .unwrap_err();
1234
1235 println!("message: {}", message);
1236 }
1237
1238 let original:&[f32] = &[ 0.0, f32::NAN, f32::NAN ];
1239 let lossy:&[f32] = &[ 0.0, f32::NAN, 0.0 ];
1240 print_error(&original, &lossy, false);
1241
1242 print_error(&2.0, &1.0, true);
1243 print_error(&2.0, &1.0, false);
1244
1245 print_error(&FlatSamples::F32(vec![0.1,0.1]), &FlatSamples::F32(vec![0.1,0.2]), false);
1246 print_error(&FlatSamples::U32(vec![0,0]), &FlatSamples::F32(vec![0.1,0.2]), false);
1247
1248 {
1249 let image = crate::prelude::read_all_data_from_file("tests/images/valid/openexr/MultiResolution/Kapaa.exr").unwrap();
1250
1251 let mut mutated = image.clone();
1252 let samples = mutated.layer_data.first_mut().unwrap()
1253 .channel_data.list.first_mut().unwrap().sample_data.levels_as_slice_mut().first_mut().unwrap();
1254
1255 match samples {
1256 FlatSamples::F16(vals) => vals[100] = vals[1],
1257 FlatSamples::F32(vals) => vals[100] = vals[1],
1258 FlatSamples::U32(vals) => vals[100] = vals[1],
1259 }
1260
1261 print_error(&image, &mutated, false);
1262 }
1263
1264 }
1266
1267 #[test]
1268 fn test_uncompressed(){
1269 use crate::prelude::*;
1270
1271 let original_pixels: [(f32,f32,f32); 4] = [
1272 (0.0, -1.1, PI),
1273 (0.0, -1.1, TAU),
1274 (0.0, -1.1, f32::EPSILON),
1275 (f32::NAN, 10000.1, -1024.009),
1276 ];
1277
1278 let mut file_bytes = Vec::new();
1279 let original_image = Image::from_encoded_channels(
1280 (2,2),
1281 Encoding {
1282 compression: Compression::Uncompressed,
1283 line_order: Increasing, .. Encoding::default()
1285 },
1286 SpecificChannels::rgb(PixelVec::new(Vec2(2,2), original_pixels.to_vec()))
1287 );
1288
1289 original_image.write().to_buffered(Cursor::new(&mut file_bytes)).unwrap();
1290
1291 let lossy_image = read().no_deep_data().largest_resolution_level()
1292 .rgb_channels(PixelVec::<(f32,f32,f32)>::constructor, PixelVec::set_pixel)
1293 .first_valid_layer().all_attributes().from_buffered(Cursor::new(&file_bytes)).unwrap();
1294
1295 original_image.assert_equals_result(&original_image);
1296 lossy_image.assert_equals_result(&lossy_image);
1297 original_image.assert_equals_result(&lossy_image);
1298 lossy_image.assert_equals_result(&original_image);
1299 }
1300
1301 #[test]
1302 fn test_compiles(){
1303 use crate::prelude::*;
1304
1305 fn accepts_validatable_value(_: &impl ValidateResult){}
1306
1307 let object: Levels<FlatSamples> = Levels::Singular(FlatSamples::F32(Vec::default()));
1308 accepts_validatable_value(&object);
1309
1310 let object: AnyChannels<Levels<FlatSamples>> = AnyChannels::sort(SmallVec::default());
1311 accepts_validatable_value(&object);
1312
1313 let layer: Layer<AnyChannels<Levels<FlatSamples>>> = Layer::new((0,0), Default::default(), Default::default(), object);
1314 accepts_validatable_value(&layer);
1315
1316 let layers: Layers<AnyChannels<Levels<FlatSamples>>> = Default::default();
1317 accepts_validatable_value(&layers);
1318
1319 let object: Image<Layer<AnyChannels<Levels<FlatSamples>>>> = Image::from_layer(layer);
1320 object.assert_equals_result(&object);
1321 }
1322 }
1323
1324
1325 #[test]
1326 fn test_nan_compression_attribute(){
1327 use crate::prelude::*;
1328 use crate::prelude::Compression::*;
1329 use std::io::Cursor;
1330 use crate::image::pixel_vec::PixelVec;
1331 use crate::prelude::LineOrder::Increasing;
1332
1333 let all_compression_methods = [
1334 Uncompressed, RLE, ZIP1, ZIP16, PXR24, PIZ, B44, B44A,
1335 ];
1336
1337 let original_pixels: [(f32,f32,f16); 4] = [
1338 (f32::NAN, f32::from_bits(0x7fc01234), f16::from_bits(0x7E01)),
1339 (f32::NAN, f32::from_bits(0xffcabcde), f16::from_bits(0x7FFF)),
1340 (f32::NAN, f32::from_bits(0x7f800001), f16::from_bits(0xFE01)),
1341 (f32::NAN, f32::NAN, f16::NAN),
1342 ];
1343
1344 assert!(
1345 original_pixels.iter()
1346 .all(|&(a,b,c)| a.is_nan() && b.is_nan() && c.is_nan()),
1347 "test case has a bug"
1348 );
1349
1350 for compression in all_compression_methods {
1351 let mut file_bytes = Vec::new();
1352
1353 let original_image = Image::from_encoded_channels(
1354 (2, 2),
1355 Encoding {
1356 compression,
1357 line_order: Increasing,
1358 ..Encoding::default()
1359 },
1360 SpecificChannels::rgb(PixelVec::new((2, 2), original_pixels.to_vec()))
1361 );
1362
1363 let result = original_image.write().to_buffered(Cursor::new(&mut file_bytes));
1364 if let Err(Error::NotSupported(_)) = result { continue; }
1365
1366 let reconstructed_image =
1367 read().no_deep_data().largest_resolution_level()
1368 .rgb_channels(PixelVec::<(f32, f32, f16)>::constructor, PixelVec::set_pixel)
1369 .first_valid_layer().all_attributes().from_buffered(Cursor::new(&file_bytes)).unwrap();
1370
1371 assert_eq!(
1372 original_image.layer_data.channel_data.pixels.pixels.len(),
1373 reconstructed_image.layer_data.channel_data.pixels.pixels.len()
1374 );
1375
1376 let was_nanness_preserved = reconstructed_image.layer_data.channel_data.pixels.pixels
1377 .iter().all(|(r,g,b)| r.is_nan() && g.is_nan() && b.is_nan());
1378
1379 assert_eq!(
1380 was_nanness_preserved, compression.supports_nan(),
1381 "{} nanness claims do not match real output", compression
1382 );
1383
1384 let was_nan_pattern_preserved = reconstructed_image.layer_data.channel_data.pixels.pixels
1385 .iter().zip(original_pixels.iter())
1386 .all(|((r2, g2, b2), (r1, g1, b1))|
1387 r2.to_bits() == r1.to_bits() &&
1388 g2.to_bits() == g1.to_bits() &&
1389 b2.to_bits() == b1.to_bits()
1390 );
1391
1392 assert_eq!(
1393 was_nan_pattern_preserved, compression.preserves_nan_bits(),
1394 "{} nan bit claims do not match real output", compression
1395 );
1396 }
1397 }
1398}
1399
1400