1
2use smallvec::SmallVec;
6
7
8#[derive(Debug, Clone, PartialEq)]
11pub enum AttributeValue {
12
13 ChannelList(ChannelList),
15
16 Chromaticities(Chromaticities),
18
19 Compression(Compression),
21
22 EnvironmentMap(EnvironmentMap),
24
25 KeyCode(KeyCode),
27
28 LineOrder(LineOrder),
30
31 Matrix3x3(Matrix3x3),
33
34 Matrix4x4(Matrix4x4),
36
37 Preview(Preview),
39
40 Rational(Rational),
42
43 BlockType(BlockType),
45
46 TextVector(Vec<Text>),
48
49 TileDescription(TileDescription),
51
52 TimeCode(TimeCode),
54
55 Text(Text),
57
58 F64(f64),
60
61 F32(f32),
63
64 I32(i32),
66
67 IntegerBounds(IntegerBounds),
69
70 FloatRect(FloatRect),
72
73 IntVec2(Vec2<i32>),
75
76 FloatVec2(Vec2<f32>),
78
79 IntVec3((i32, i32, i32)),
81
82 FloatVec3((f32, f32, f32)),
84
85 Bytes {
90
91 type_hint: Text,
93
94 bytes: SmallVec<[u8; 16]>
97 },
98
99 Custom {
102
103 kind: Text,
105
106 bytes: SmallVec<[u8; 16]>
109 },
110}
111
112#[derive(Clone, PartialEq, Ord, PartialOrd, Default)] pub struct Text {
117 bytes: TextBytes,
118}
119
120#[derive(Copy, Debug, Clone, Eq, PartialEq, Hash, Default)]
127pub struct TimeCode {
128
129 pub hours: u8,
131
132 pub minutes: u8,
134
135 pub seconds: u8,
137
138 pub frame: u8,
140
141 pub drop_frame: bool,
143
144 pub color_frame: bool,
146
147 pub field_phase: bool,
149
150 pub binary_group_flags: [bool; 3],
152
153 pub binary_groups: [u8; 8]
157}
158
159#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
161pub enum BlockType {
162
163 ScanLine,
165
166 Tile,
168
169 DeepScanLine,
171
172 DeepTile,
174}
175
176pub mod block_type_strings {
178
179 pub const SCAN_LINE: &'static [u8] = b"scanlineimage";
181
182 pub const TILE: &'static [u8] = b"tiledimage";
184
185 pub const DEEP_SCAN_LINE: &'static [u8] = b"deepscanline";
187
188 pub const DEEP_TILE: &'static [u8] = b"deeptile";
190}
191
192
193pub use crate::compression::Compression;
194
195pub type DataWindow = IntegerBounds;
197
198pub type DisplayWindow = IntegerBounds;
200
201pub type Rational = (i32, u32);
203
204pub type Matrix4x4 = [f32; 4*4];
206
207pub type Matrix3x3 = [f32; 3*3];
209
210#[derive(Clone, Copy, Debug, Eq, PartialEq, Default, Hash)]
214pub struct IntegerBounds {
215
216 pub position: Vec2<i32>,
219
220 pub size: Vec2<usize>,
224}
225
226#[derive(Clone, Copy, Debug, PartialEq)]
228pub struct FloatRect {
229
230 pub min: Vec2<f32>,
232
233 pub max: Vec2<f32>
235}
236
237#[derive(Clone, Debug, Eq, PartialEq, Hash)]
239pub struct ChannelList {
240
241 pub list: SmallVec<[ChannelDescription; 5]>,
243
244 pub bytes_per_pixel: usize, pub uniform_sample_type: Option<SampleType>,
250}
251
252#[derive(Clone, Debug, Eq, PartialEq, Hash)]
256pub struct ChannelDescription {
257
258 pub name: Text,
260
261 pub sample_type: SampleType,
263
264 pub quantize_linearly: bool,
270
271 pub sampling: Vec2<usize>,
277}
278
279#[derive(Clone, Debug, Eq, PartialEq, Copy, Hash)]
281pub enum SampleType {
282
283 U32,
285
286 F16,
288
289 F32,
291}
292
293#[derive(Debug, Clone, Copy, PartialEq)]
298pub struct Chromaticities {
299
300 pub red: Vec2<f32>,
302
303 pub green: Vec2<f32>,
305
306 pub blue: Vec2<f32>,
308
309 pub white: Vec2<f32>
311}
312
313#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
316pub enum EnvironmentMap {
317
318 LatitudeLongitude,
320
321 Cube,
323}
324
325#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
327pub struct KeyCode {
328
329 pub film_manufacturer_code: i32,
331
332 pub film_type: i32,
334
335 pub film_roll_prefix: i32,
337
338 pub count: i32,
340
341 pub perforation_offset: i32,
343
344 pub perforations_per_frame: i32,
346
347 pub perforations_per_count: i32,
349}
350
351#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
353pub enum LineOrder {
354
355 Increasing,
359
360 Decreasing,
364
365 Unspecified,
368}
369
370#[derive(Clone, Eq, PartialEq)]
373pub struct Preview {
374
375 pub size: Vec2<usize>,
377
378 pub pixel_data: Vec<i8>,
382}
383
384#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
388pub struct TileDescription {
389
390 pub tile_size: Vec2<usize>,
393
394 pub level_mode: LevelMode,
396
397 pub rounding_mode: RoundingMode,
399}
400
401#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
403pub enum LevelMode {
404
405 Singular,
407
408 MipMap,
410
411 RipMap,
413}
414
415
416pub type TextBytes = SmallVec<[u8; 24]>;
420
421pub type TextSlice = [u8];
423
424
425use crate::io::*;
426use crate::meta::{sequence_end};
427use crate::error::*;
428use crate::math::{RoundingMode, Vec2};
429use half::f16;
430use std::convert::{TryFrom};
431use std::borrow::Borrow;
432use std::hash::{Hash, Hasher};
433use bit_field::BitField;
434
435
436fn invalid_type() -> Error {
437 Error::invalid("attribute type mismatch")
438}
439
440
441impl Text {
442
443 pub fn new_or_none(string: impl AsRef<str>) -> Option<Self> {
446 let vec : Option<TextBytes> = string.as_ref().chars()
447 .map(|character| u8::try_from(character as u64).ok())
448 .collect();
449
450 vec.map(Self::from_bytes_unchecked)
451 }
452
453 pub fn new_or_panic(string: impl AsRef<str>) -> Self {
456 Self::new_or_none(string).expect("exr::Text contains unsupported characters")
457 }
458
459 pub fn from_slice_unchecked(text: &TextSlice) -> Self {
462 Self::from_bytes_unchecked(SmallVec::from_slice(text))
463 }
464
465 pub fn from_bytes_unchecked(bytes: TextBytes) -> Self {
468 Text { bytes }
469 }
470
471 pub fn as_slice(&self) -> &TextSlice {
473 self.bytes.as_slice()
474 }
475
476 pub fn validate(&self, null_terminated: bool, long_names: Option<&mut bool>) -> UnitResult {
479 Self::validate_bytes(self.as_slice(), null_terminated, long_names)
480 }
481
482 pub fn validate_bytes(text: &TextSlice, null_terminated: bool, long_names: Option<&mut bool>) -> UnitResult {
485 if null_terminated && text.is_empty() {
486 return Err(Error::invalid("text must not be empty"));
487 }
488
489 if let Some(long) = long_names {
490 if text.len() >= 256 { return Err(Error::invalid("text must not be longer than 255")); }
491 if text.len() >= 32 { *long = true; }
492 }
493
494 Ok(())
495 }
496
497 pub fn null_terminated_byte_size(&self) -> usize {
499 self.bytes.len() + sequence_end::byte_size()
500 }
501
502 pub fn i32_sized_byte_size(&self) -> usize {
504 self.bytes.len() + i32::BYTE_SIZE
505 }
506
507 pub fn u32_sized_byte_size(&self) -> usize {
509 self.bytes.len() + u32::BYTE_SIZE
510 }
511
512 pub fn write_i32_sized_le<W: Write>(&self, write: &mut W) -> UnitResult {
514 debug_assert!(self.validate( false, None).is_ok(), "text size bug");
515 i32::write_le(usize_to_i32(self.bytes.len(), "text length")?, write)?;
516 Self::write_unsized_bytes(self.bytes.as_slice(), write)
517 }
518
519 pub fn write_u32_sized_le<W: Write>(&self, write: &mut W) -> UnitResult {
521 debug_assert!(self.validate( false, None).is_ok(), "text size bug");
522 u32::write_le(usize_to_u32(self.bytes.len(), "text length")?, write)?;
523 Self::write_unsized_bytes(self.bytes.as_slice(), write)
524 }
525
526 fn write_unsized_bytes<W: Write>(bytes: &[u8], write: &mut W) -> UnitResult {
528 u8::write_slice_le(write, bytes)?;
529 Ok(())
530 }
531
532 pub fn read_i32_sized_le<R: Read>(read: &mut R, max_size: usize) -> Result<Self> {
534 let size = i32_to_usize(i32::read_le(read)?, "vector size")?;
535 Ok(Text::from_bytes_unchecked(SmallVec::from_vec(u8::read_vec_le(read, size, 1024, Some(max_size), "text attribute length")?)))
536 }
537
538 pub fn read_u32_sized_le<R: Read>(read: &mut R, max_size: usize) -> Result<Self> {
540 let size = u32_to_usize(u32::read_le(read)?, "text length")?;
541 Ok(Text::from_bytes_unchecked(SmallVec::from_vec(u8::read_vec_le(read, size, 1024, Some(max_size), "text attribute length")?)))
542 }
543
544 pub fn read_sized<R: Read>(read: &mut R, size: usize) -> Result<Self> {
546 const SMALL_SIZE: usize = 24;
547
548 if size <= SMALL_SIZE {
550 let mut buffer = [0_u8; SMALL_SIZE];
551 let data = &mut buffer[..size];
552
553 read.read_exact(data)?;
554 Ok(Text::from_bytes_unchecked(SmallVec::from_slice(data)))
555 }
556
557 else {
559 Ok(Text::from_bytes_unchecked(SmallVec::from_vec(u8::read_vec_le(read, size, 1024, None, "text attribute length")?)))
560 }
561 }
562
563 pub fn write_null_terminated<W: Write>(&self, write: &mut W) -> UnitResult {
565 Self::write_null_terminated_bytes(self.as_slice(), write)
566 }
567
568 fn write_null_terminated_bytes<W: Write>(bytes: &[u8], write: &mut W) -> UnitResult {
570 debug_assert!(!bytes.is_empty(), "text is empty bug"); Text::write_unsized_bytes(bytes, write)?;
573 sequence_end::write(write)?;
574 Ok(())
575 }
576
577 pub fn read_null_terminated<R: Read>(read: &mut R, max_len: usize) -> Result<Self> {
579 let mut bytes = smallvec![ u8::read_le(read)? ]; loop {
582 match u8::read_le(read)? {
583 0 => break,
584 non_terminator => bytes.push(non_terminator),
585 }
586
587 if bytes.len() > max_len {
588 return Err(Error::invalid("text too long"))
589 }
590 }
591
592 Ok(Text { bytes })
593 }
594
595 fn read_vec_of_i32_sized_texts_le(
598 read: &mut PeekRead<impl Read>,
599 total_byte_size: usize
600 ) -> Result<Vec<Text>>
601 {
602 let mut result = Vec::with_capacity(2);
603
604 let mut processed_bytes = 0;
606
607 while processed_bytes < total_byte_size {
608 let text = Text::read_i32_sized_le(read, total_byte_size)?;
609 processed_bytes += ::std::mem::size_of::<i32>(); processed_bytes += text.bytes.len();
611 result.push(text);
612 }
613
614 if processed_bytes != total_byte_size {
616 return Err(Error::invalid("text array byte size"))
617 }
618
619 Ok(result)
620 }
621
622 fn write_vec_of_i32_sized_texts_le<W: Write>(write: &mut W, texts: &[Text]) -> UnitResult {
625 for text in texts {
627 text.write_i32_sized_le(write)?;
628 }
629
630 Ok(())
631 }
632
633 pub fn bytes(&self) -> &[u8] {
635 self.bytes.as_slice()
636 }
637
638 pub fn chars(&self) -> impl '_ + Iterator<Item = char> {
641 self.bytes.iter().map(|&byte| byte as char)
642 }
643
644 pub fn eq(&self, string: &str) -> bool {
646 string.chars().eq(self.chars())
647 }
648
649 pub fn eq_case_insensitive(&self, string: &str) -> bool {
651 let self_chars = self.chars().map(|char| char.to_ascii_lowercase());
653 let string_chars = string.chars().flat_map(|ch| ch.to_lowercase());
654
655 string_chars.eq(self_chars)
656 }
657}
658
659impl PartialEq<str> for Text {
660 fn eq(&self, other: &str) -> bool {
661 self.eq(other)
662 }
663}
664
665impl PartialEq<Text> for str {
666 fn eq(&self, other: &Text) -> bool {
667 other.eq(self)
668 }
669}
670
671impl Eq for Text {}
672
673impl Borrow<TextSlice> for Text {
674 fn borrow(&self) -> &TextSlice {
675 self.as_slice()
676 }
677}
678
679impl Hash for Text {
681 fn hash<H: Hasher>(&self, state: &mut H) {
682 self.bytes.hash(state)
683 }
684}
685
686impl Into<String> for Text {
687 fn into(self) -> String {
688 self.to_string()
689 }
690}
691
692impl<'s> From<&'s str> for Text {
693
694 fn from(str: &'s str) -> Self {
696 Self::new_or_panic(str)
697 }
698}
699
700
701impl ::std::fmt::Debug for Text {
716 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
717 write!(f, "exr::Text(\"{}\")", self)
718 }
719}
720
721impl ::std::fmt::Display for Text {
723 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
724 use std::fmt::Write;
725
726 for &byte in self.bytes.iter() {
727 f.write_char(byte as char)?;
728 }
729
730 Ok(())
731 }
732}
733
734
735impl ChannelList {
736
737 pub fn new(channels: SmallVec<[ChannelDescription; 5]>) -> Self {
739 let uniform_sample_type = {
740 if let Some(first) = channels.first() {
741 let has_uniform_types = channels.iter().skip(1)
742 .all(|chan| chan.sample_type == first.sample_type);
743
744 if has_uniform_types { Some(first.sample_type) } else { None }
745 }
746 else { None }
747 };
748
749 ChannelList {
750 bytes_per_pixel: channels.iter().map(|channel| channel.sample_type.bytes_per_sample()).sum(),
751 list: channels, uniform_sample_type,
752 }
753 }
754
755 pub fn channels_with_byte_offset(&self) -> impl Iterator<Item=(usize, &ChannelDescription)> {
758 self.list.iter().scan(0, |byte_position, channel|{
759 let previous_position = *byte_position;
760 *byte_position += channel.sample_type.bytes_per_sample();
761 Some((previous_position, channel))
762 })
763 }
764
765 pub fn find_index_of_channel(&self, exact_name: &Text) -> Option<usize> {
768 self.list.binary_search_by_key(&exact_name.bytes(), |chan| chan.name.bytes()).ok()
769 }
770
771 }
784
785impl BlockType {
786
787 const TYPE_NAME: &'static [u8] = type_names::TEXT;
789
790 pub fn parse(text: Text) -> Result<Self> {
792 match text.as_slice() {
793 block_type_strings::SCAN_LINE => Ok(BlockType::ScanLine),
794 block_type_strings::TILE => Ok(BlockType::Tile),
795
796 block_type_strings::DEEP_SCAN_LINE => Ok(BlockType::DeepScanLine),
797 block_type_strings::DEEP_TILE => Ok(BlockType::DeepTile),
798
799 _ => Err(Error::invalid("block type attribute value")),
800 }
801 }
802
803 pub fn write(&self, write: &mut impl Write) -> UnitResult {
805 u8::write_slice_le(write, self.to_text_bytes())?;
806 Ok(())
807 }
808
809 pub fn to_text_bytes(&self) -> &[u8] {
811 match self {
812 BlockType::ScanLine => block_type_strings::SCAN_LINE,
813 BlockType::Tile => block_type_strings::TILE,
814 BlockType::DeepScanLine => block_type_strings::DEEP_SCAN_LINE,
815 BlockType::DeepTile => block_type_strings::DEEP_TILE,
816 }
817 }
818
819 pub fn byte_size(&self) -> usize {
821 self.to_text_bytes().len()
822 }
823}
824
825
826impl IntegerBounds {
827
828 pub fn zero() -> Self {
830 Self::from_dimensions(Vec2(0, 0))
831 }
832
833 pub fn from_dimensions(size: impl Into<Vec2<usize>>) -> Self {
835 Self::new(Vec2(0,0), size)
836 }
837
838 pub fn new(start: impl Into<Vec2<i32>>, size: impl Into<Vec2<usize>>) -> Self {
840 Self { position: start.into(), size: size.into() }
841 }
842
843 pub fn end(self) -> Vec2<i32> {
847 self.position + self.size.to_i32() }
849
850 pub fn max(self) -> Vec2<i32> {
852 self.end() - Vec2(1,1)
853 }
854
855 pub fn validate(&self, max_size: Option<Vec2<usize>>) -> UnitResult {
857 if let Some(max_size) = max_size {
858 if self.size.width() > max_size.width() || self.size.height() > max_size.height() {
859 return Err(Error::invalid("window attribute dimension value"));
860 }
861 }
862
863 let min_i64 = Vec2(self.position.x() as i64, self.position.y() as i64);
864
865 let max_i64 = Vec2(
866 self.position.x() as i64 + self.size.width() as i64,
867 self.position.y() as i64 + self.size.height() as i64,
868 );
869
870 Self::validate_min_max_u64(min_i64, max_i64)
871 }
872
873 fn validate_min_max_u64(min: Vec2<i64>, max: Vec2<i64>) -> UnitResult {
874 let max_box_size_as_i64 = (i32::MAX / 2) as i64; if max.x() >= max_box_size_as_i64
877 || max.y() >= max_box_size_as_i64
878 || min.x() <= -max_box_size_as_i64
879 || min.y() <= -max_box_size_as_i64
880 {
881 return Err(Error::invalid("window size exceeding integer maximum"));
882 }
883
884 Ok(())
885 }
886
887 pub fn byte_size() -> usize {
889 4 * i32::BYTE_SIZE
890 }
891
892 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
894 let Vec2(x_min, y_min) = self.position;
895 let Vec2(x_max, y_max) = self.max();
896
897 x_min.write_le(write)?;
898 y_min.write_le(write)?;
899 x_max.write_le(write)?;
900 y_max.write_le(write)?;
901 Ok(())
902 }
903
904 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
906 let x_min = i32::read_le(read)?;
907 let y_min = i32::read_le(read)?;
908 let x_max = i32::read_le(read)?;
909 let y_max = i32::read_le(read)?;
910
911 let min = Vec2(x_min.min(x_max), y_min.min(y_max));
912 let max = Vec2(x_min.max(x_max), y_min.max(y_max));
913
914 Self::validate_min_max_u64(
916 Vec2(min.x() as i64, min.y() as i64),
917 Vec2(max.x() as i64, max.y() as i64),
918 )?;
919
920 let size = Vec2(max.x() + 1 - min.x(), max.y() + 1 - min.y());
922 let size = size.to_usize("box coordinates")?;
923
924 Ok(IntegerBounds { position: min, size })
925 }
926
927 pub fn with_origin(self, origin: Vec2<i32>) -> Self { IntegerBounds { position: self.position + origin, .. self }
930 }
931
932 pub fn contains(self, subset: Self) -> bool {
934 subset.position.x() >= self.position.x()
935 && subset.position.y() >= self.position.y()
936 && subset.end().x() <= self.end().x()
937 && subset.end().y() <= self.end().y()
938 }
939}
940
941
942impl FloatRect {
943
944 pub fn byte_size() -> usize {
946 4 * f32::BYTE_SIZE
947 }
948
949 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
951 self.min.x().write_le(write)?;
952 self.min.y().write_le(write)?;
953 self.max.x().write_le(write)?;
954 self.max.y().write_le(write)?;
955 Ok(())
956 }
957
958 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
960 let x_min = f32::read_le(read)?;
961 let y_min = f32::read_le(read)?;
962 let x_max = f32::read_le(read)?;
963 let y_max = f32::read_le(read)?;
964
965 Ok(FloatRect {
966 min: Vec2(x_min, y_min),
967 max: Vec2(x_max, y_max)
968 })
969 }
970}
971
972impl SampleType {
973
974 pub fn bytes_per_sample(&self) -> usize {
976 match self {
977 SampleType::F16 => f16::BYTE_SIZE,
978 SampleType::F32 => f32::BYTE_SIZE,
979 SampleType::U32 => u32::BYTE_SIZE,
980 }
981 }
982
983 pub fn byte_size() -> usize {
985 i32::BYTE_SIZE
986 }
987
988 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
990 match *self {
991 SampleType::U32 => 0_i32,
992 SampleType::F16 => 1_i32,
993 SampleType::F32 => 2_i32,
994 }.write_le(write)?;
995
996 Ok(())
997 }
998
999 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1001 Ok(match i32::read_le(read)? {
1003 0 => SampleType::U32,
1004 1 => SampleType::F16,
1005 2 => SampleType::F32,
1006 _ => return Err(Error::invalid("pixel type attribute value")),
1007 })
1008 }
1009}
1010
1011impl ChannelDescription {
1012 pub fn guess_quantization_linearity(name: &Text) -> bool {
1015 !(
1016 name.eq_case_insensitive("R") || name.eq_case_insensitive("G") ||
1017 name.eq_case_insensitive("B") || name.eq_case_insensitive("L") ||
1018 name.eq_case_insensitive("Y") || name.eq_case_insensitive("X") ||
1019 name.eq_case_insensitive("Z")
1020 )
1021 }
1022
1023 pub fn named(name: impl Into<Text>, sample_type: SampleType) -> Self {
1026 let name = name.into();
1027 let linearity = Self::guess_quantization_linearity(&name);
1028 Self::new(name, sample_type, linearity)
1029 }
1030
1031 pub fn new(name: impl Into<Text>, sample_type: SampleType, quantize_linearly: bool) -> Self {
1037 Self { name: name.into(), sample_type, quantize_linearly, sampling: Vec2(1, 1) }
1038 }
1039
1040 pub fn subsampled_pixels(&self, dimensions: Vec2<usize>) -> usize {
1043 self.subsampled_resolution(dimensions).area()
1044 }
1045
1046 pub fn subsampled_resolution(&self, dimensions: Vec2<usize>) -> Vec2<usize> {
1048 dimensions / self.sampling
1049 }
1050
1051 pub fn byte_size(&self) -> usize {
1053 self.name.null_terminated_byte_size()
1054 + SampleType::byte_size()
1055 + 1 + 3 + 2 * u32::BYTE_SIZE }
1059
1060 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1062 Text::write_null_terminated(&self.name, write)?;
1063 self.sample_type.write(write)?;
1064
1065 match self.quantize_linearly {
1066 false => 0_u8,
1067 true => 1_u8,
1068 }.write_le(write)?;
1069
1070 i8::write_slice_le(write, &[0_i8, 0_i8, 0_i8])?;
1071 i32::write_le(usize_to_i32(self.sampling.x(), "text length")?, write)?;
1072 i32::write_le(usize_to_i32(self.sampling.y(), "text length")?, write)?;
1073 Ok(())
1074 }
1075
1076 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1078 let name = Text::read_null_terminated(read, 256)?;
1079 let sample_type = SampleType::read(read)?;
1080
1081 let is_linear = match u8::read_le(read)? {
1082 1 => true,
1083 0 => false,
1084 _ => return Err(Error::invalid("channel linearity attribute value")),
1085 };
1086
1087 let mut reserved = [0_i8; 3];
1088 i8::read_slice_le(read, &mut reserved)?;
1089
1090 let x_sampling = i32_to_usize(i32::read_le(read)?, "x channel sampling")?;
1091 let y_sampling = i32_to_usize(i32::read_le(read)?, "y channel sampling")?;
1092
1093 Ok(ChannelDescription {
1094 name, sample_type,
1095 quantize_linearly: is_linear,
1096 sampling: Vec2(x_sampling, y_sampling),
1097 })
1098 }
1099
1100 pub fn validate(&self, allow_sampling: bool, data_window: IntegerBounds, strict: bool) -> UnitResult {
1102 self.name.validate(true, None)?; if self.sampling.x() == 0 || self.sampling.y() == 0 {
1105 return Err(Error::invalid("zero sampling factor"));
1106 }
1107
1108 if strict && !allow_sampling && self.sampling != Vec2(1,1) {
1109 return Err(Error::invalid("subsampling is only allowed in flat scan line images"));
1110 }
1111
1112 if data_window.position.x() % self.sampling.x() as i32 != 0 || data_window.position.y() % self.sampling.y() as i32 != 0 {
1113 return Err(Error::invalid("channel sampling factor not dividing data window position"));
1114 }
1115
1116 if data_window.size.x() % self.sampling.x() != 0 || data_window.size.y() % self.sampling.y() != 0 {
1117 return Err(Error::invalid("channel sampling factor not dividing data window size"));
1118 }
1119
1120 if self.sampling != Vec2(1,1) {
1121 return Err(Error::unsupported("channel subsampling not supported yet"));
1125 }
1126
1127 Ok(())
1128 }
1129}
1130
1131impl ChannelList {
1132
1133 pub fn byte_size(&self) -> usize {
1135 self.list.iter().map(ChannelDescription::byte_size).sum::<usize>() + sequence_end::byte_size()
1136 }
1137
1138 pub fn write(&self, write: &mut impl Write) -> UnitResult {
1141 for channel in &self.list {
1142 channel.write(write)?;
1143 }
1144
1145 sequence_end::write(write)?;
1146 Ok(())
1147 }
1148
1149 pub fn read(read: &mut PeekRead<impl Read>) -> Result<Self> {
1151 let mut channels = SmallVec::new();
1152 while !sequence_end::has_come(read)? {
1153 channels.push(ChannelDescription::read(read)?);
1154 }
1155
1156 Ok(ChannelList::new(channels))
1157 }
1158
1159 pub fn validate(&self, allow_sampling: bool, data_window: IntegerBounds, strict: bool) -> UnitResult {
1161 let mut iter = self.list.iter().map(|chan| chan.validate(allow_sampling, data_window, strict).map(|_| &chan.name));
1162 let mut previous = iter.next().ok_or(Error::invalid("at least one channel is required"))??;
1163
1164 for result in iter {
1165 let value = result?;
1166 if strict && previous == value { return Err(Error::invalid("channel names are not unique")); }
1167 else if previous > value { return Err(Error::invalid("channel names are not sorted alphabetically")); }
1168 else { previous = value; }
1169 }
1170
1171 Ok(())
1172 }
1173}
1174
1175fn u8_to_decimal32(binary: u8) -> u32 {
1176 let units = binary as u32 % 10;
1177 let tens = (binary as u32 / 10) % 10;
1178 units | (tens << 4)
1179}
1180
1181fn u8_from_decimal32(coded: u32) -> u8 {
1183 ((coded & 0x0f) + 10 * ((coded >> 4) & 0x0f)) as u8
1184}
1185
1186impl TimeCode {
1188
1189 pub const BYTE_SIZE: usize = 2 * u32::BYTE_SIZE;
1191
1192 pub fn validate(&self, strict: bool) -> UnitResult {
1194 if strict {
1195 if self.frame > 29 { Err(Error::invalid("time code frame larger than 29")) }
1196 else if self.seconds > 59 { Err(Error::invalid("time code seconds larger than 59")) }
1197 else if self.minutes > 59 { Err(Error::invalid("time code minutes larger than 59")) }
1198 else if self.hours > 23 { Err(Error::invalid("time code hours larger than 23")) }
1199 else if self.binary_groups.iter().any(|&group| group > 15) {
1200 Err(Error::invalid("time code binary group value too large for 3 bits"))
1201 }
1202 else { Ok(()) }
1203 }
1204 else { Ok(()) }
1205 }
1206
1207
1208 pub fn pack_time_as_tv60_u32(&self) -> Result<u32> {
1211 self.validate(true)?;
1213
1214 Ok(*0_u32
1215 .set_bits(0..6, u8_to_decimal32(self.frame))
1216 .set_bit(6, self.drop_frame)
1217 .set_bit(7, self.color_frame)
1218 .set_bits(8..15, u8_to_decimal32(self.seconds))
1219 .set_bit(15, self.field_phase)
1220 .set_bits(16..23, u8_to_decimal32(self.minutes))
1221 .set_bit(23, self.binary_group_flags[0])
1222 .set_bits(24..30, u8_to_decimal32(self.hours))
1223 .set_bit(30, self.binary_group_flags[1])
1224 .set_bit(31, self.binary_group_flags[2])
1225 )
1226 }
1227
1228 pub fn from_tv60_time(tv60_time: u32, user_data: u32) -> Self {
1231 Self {
1232 frame: u8_from_decimal32(tv60_time.get_bits(0..6)), drop_frame: tv60_time.get_bit(6),
1234 color_frame: tv60_time.get_bit(7),
1235 seconds: u8_from_decimal32(tv60_time.get_bits(8..15)), field_phase: tv60_time.get_bit(15),
1237 minutes: u8_from_decimal32(tv60_time.get_bits(16..23)), hours: u8_from_decimal32(tv60_time.get_bits(24..30)), binary_group_flags: [
1240 tv60_time.get_bit(23),
1241 tv60_time.get_bit(30),
1242 tv60_time.get_bit(31),
1243 ],
1244
1245 binary_groups: Self::unpack_user_data_from_u32(user_data)
1246 }
1247 }
1248
1249 pub fn pack_time_as_tv50_u32(&self) -> Result<u32> {
1252 Ok(*self.pack_time_as_tv60_u32()?
1253
1254 .set_bit(6, false)
1256 .set_bit(15, self.binary_group_flags[0])
1257 .set_bit(30, self.binary_group_flags[1])
1258 .set_bit(23, self.binary_group_flags[2])
1259 .set_bit(31, self.field_phase)
1260 )
1261 }
1262
1263 pub fn from_tv50_time(tv50_time: u32, user_data: u32) -> Self {
1266 Self {
1267 drop_frame: false, field_phase: tv50_time.get_bit(31),
1271 binary_group_flags: [
1272 tv50_time.get_bit(15),
1273 tv50_time.get_bit(30),
1274 tv50_time.get_bit(23),
1275 ],
1276
1277 .. Self::from_tv60_time(tv50_time, user_data)
1278 }
1279 }
1280
1281
1282 pub fn pack_time_as_film24_u32(&self) -> Result<u32> {
1285 Ok(*self.pack_time_as_tv60_u32()?
1286 .set_bit(6, false)
1287 .set_bit(7, false)
1288 )
1289 }
1290
1291 pub fn from_film24_time(film24_time: u32, user_data: u32) -> Self {
1294 Self {
1295 drop_frame: false, color_frame: false, .. Self::from_tv60_time(film24_time, user_data)
1298 }
1299 }
1300
1301
1302 fn user_data_bit_indices(group_index: usize) -> std::ops::Range<usize> {
1304 let min_bit = 4 * group_index;
1305 min_bit .. min_bit + 4 }
1307
1308 pub fn pack_user_data_as_u32(&self) -> u32 {
1311 let packed = self.binary_groups.iter().enumerate().fold(0_u32, |mut packed, (group_index, group_value)|
1312 *packed.set_bits(Self::user_data_bit_indices(group_index), *group_value.min(&15) as u32)
1313 );
1314
1315 debug_assert_eq!(Self::unpack_user_data_from_u32(packed), self.binary_groups, "round trip user data encoding");
1316 packed
1317 }
1318
1319 fn unpack_user_data_from_u32(user_data: u32) -> [u8; 8] {
1321 (0..8).map(|group_index| user_data.get_bits(Self::user_data_bit_indices(group_index)) as u8)
1322 .collect::<SmallVec<[u8;8]>>().into_inner().expect("array index bug")
1323 }
1324
1325
1326 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1329 self.pack_time_as_tv60_u32()?.write_le(write)?; self.pack_user_data_as_u32().write_le(write)?;
1331 Ok(())
1332 }
1333
1334 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1336 let time_and_flags = u32::read_le(read)?;
1337 let user_data = u32::read_le(read)?;
1338 Ok(Self::from_tv60_time(time_and_flags, user_data))
1339 }
1340}
1341
1342impl Chromaticities {
1343
1344 pub fn byte_size() -> usize {
1346 8 * f32::BYTE_SIZE
1347 }
1348
1349 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1351 self.red.x().write_le(write)?;
1352 self.red.y().write_le(write)?;
1353
1354 self.green.x().write_le(write)?;
1355 self.green.y().write_le(write)?;
1356
1357 self.blue.x().write_le(write)?;
1358 self.blue.y().write_le(write)?;
1359
1360 self.white.x().write_le(write)?;
1361 self.white.y().write_le(write)?;
1362 Ok(())
1363 }
1364
1365 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1367 Ok(Chromaticities {
1368 red: Vec2(f32::read_le(read)?, f32::read_le(read)?),
1369 green: Vec2(f32::read_le(read)?, f32::read_le(read)?),
1370 blue: Vec2(f32::read_le(read)?, f32::read_le(read)?),
1371 white: Vec2(f32::read_le(read)?, f32::read_le(read)?),
1372 })
1373 }
1374}
1375
1376impl Compression {
1377
1378 pub fn byte_size() -> usize { u8::BYTE_SIZE }
1380
1381 pub fn write<W: Write>(self, write: &mut W) -> UnitResult {
1383 use self::Compression::*;
1384 match self {
1385 Uncompressed => 0_u8,
1386 RLE => 1_u8,
1387 ZIP1 => 2_u8,
1388 ZIP16 => 3_u8,
1389 PIZ => 4_u8,
1390 PXR24 => 5_u8,
1391 B44 => 6_u8,
1392 B44A => 7_u8,
1393 DWAA(_) => 8_u8,
1394 DWAB(_) => 9_u8,
1395 HTJ2K256 => 10_u8,
1396 HTJ2K32 => 11_u8,
1397 }.write_le(write)?;
1398 Ok(())
1399 }
1400
1401 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1403 use self::Compression::*;
1404 Ok(match u8::read_le(read)? {
1405 0 => Uncompressed,
1406 1 => RLE,
1407 2 => ZIP1,
1408 3 => ZIP16,
1409 4 => PIZ,
1410 5 => PXR24,
1411 6 => B44,
1412 7 => B44A,
1413 8 => DWAA(None),
1414 9 => DWAB(None),
1415 10 => HTJ2K256,
1416 11 => HTJ2K32,
1417 _ => return Err(Error::unsupported("unknown compression method")),
1418 })
1419 }
1420}
1421
1422impl EnvironmentMap {
1423
1424 pub fn byte_size() -> usize {
1426 u8::BYTE_SIZE
1427 }
1428
1429 pub fn write<W: Write>(self, write: &mut W) -> UnitResult {
1431 use self::EnvironmentMap::*;
1432 match self {
1433 LatitudeLongitude => 0_u8,
1434 Cube => 1_u8
1435 }.write_le(write)?;
1436
1437 Ok(())
1438 }
1439
1440 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1442 use self::EnvironmentMap::*;
1443 Ok(match u8::read_le(read)? {
1444 0 => LatitudeLongitude,
1445 1 => Cube,
1446 _ => return Err(Error::invalid("environment map attribute value")),
1447 })
1448 }
1449}
1450
1451impl KeyCode {
1452
1453 pub fn byte_size() -> usize {
1455 6 * i32::BYTE_SIZE
1456 }
1457
1458 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1460 self.film_manufacturer_code.write_le(write)?;
1461 self.film_type.write_le(write)?;
1462 self.film_roll_prefix.write_le(write)?;
1463 self.count.write_le(write)?;
1464 self.perforation_offset.write_le(write)?;
1465 self.perforations_per_count.write_le(write)?;
1466 Ok(())
1467 }
1468
1469 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1471 Ok(KeyCode {
1472 film_manufacturer_code: i32::read_le(read)?,
1473 film_type: i32::read_le(read)?,
1474 film_roll_prefix: i32::read_le(read)?,
1475 count: i32::read_le(read)?,
1476 perforation_offset: i32::read_le(read)?,
1477 perforations_per_frame: i32::read_le(read)?,
1478 perforations_per_count: i32::read_le(read)?,
1479 })
1480 }
1481}
1482
1483impl LineOrder {
1484
1485 pub fn byte_size() -> usize {
1487 u8::BYTE_SIZE
1488 }
1489
1490 pub fn write<W: Write>(self, write: &mut W) -> UnitResult {
1492 use self::LineOrder::*;
1493 match self {
1494 Increasing => 0_u8,
1495 Decreasing => 1_u8,
1496 Unspecified => 2_u8,
1497 }.write_le(write)?;
1498
1499 Ok(())
1500 }
1501
1502 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1504 use self::LineOrder::*;
1505 Ok(match u8::read_le(read)? {
1506 0 => Increasing,
1507 1 => Decreasing,
1508 2 => Unspecified,
1509 _ => return Err(Error::invalid("line order attribute value")),
1510 })
1511 }
1512}
1513
1514
1515
1516
1517impl Preview {
1518
1519 pub fn byte_size(&self) -> usize {
1521 2 * u32::BYTE_SIZE + self.pixel_data.len()
1522 }
1523
1524 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1526 u32::write_le(self.size.width() as u32, write)?;
1527 u32::write_le(self.size.height() as u32, write)?;
1528
1529 i8::write_slice_le(write, &self.pixel_data)?;
1530 Ok(())
1531 }
1532
1533 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1535 let width = u32::read_le(read)? as usize;
1536 let height = u32::read_le(read)? as usize;
1537
1538 if let Some(pixel_count) = width.checked_mul(height) {
1539 if let Some(byte_count) = pixel_count.checked_mul(4) {
1541 let pixel_data = i8::read_vec_le(
1542 read,
1543 byte_count,
1544 1024 * 1024 * 4,
1545 None,
1546 "preview attribute pixel count",
1547 )?;
1548
1549 let preview = Preview {
1550 size: Vec2(width, height),
1551 pixel_data,
1552 };
1553
1554 return Ok(preview);
1555 }
1556 }
1557
1558 return Err(Error::invalid(
1559 format!("Overflow while calculating preview image Attribute size \
1560 (width: {}, height: {}).",
1561 width,
1562 height)));
1563 }
1564
1565 pub fn validate(&self, strict: bool) -> UnitResult {
1567 if strict && (self.size.area() * 4 != self.pixel_data.len()) {
1568 return Err(Error::invalid("preview dimensions do not match content length"))
1569 }
1570
1571 Ok(())
1572 }
1573}
1574
1575impl ::std::fmt::Debug for Preview {
1576 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
1577 write!(f, "Preview ({}x{} px)", self.size.width(), self.size.height())
1578 }
1579}
1580
1581impl TileDescription {
1582
1583 pub fn byte_size() -> usize {
1585 2 * u32::BYTE_SIZE + 1 }
1587
1588 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1590 u32::write_le(self.tile_size.width() as u32, write)?;
1591 u32::write_le(self.tile_size.height() as u32, write)?;
1592
1593 let level_mode = match self.level_mode {
1594 LevelMode::Singular => 0_u8,
1595 LevelMode::MipMap => 1_u8,
1596 LevelMode::RipMap => 2_u8,
1597 };
1598
1599 let rounding_mode = match self.rounding_mode {
1600 RoundingMode::Down => 0_u8,
1601 RoundingMode::Up => 1_u8,
1602 };
1603
1604 let mode: u8 = level_mode + (rounding_mode * 16);
1605 mode.write_le(write)?;
1606 Ok(())
1607 }
1608
1609 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1611 let x_size = u32::read_le(read)? as usize;
1612 let y_size = u32::read_le(read)? as usize;
1613
1614 let mode = u8::read_le(read)?;
1615
1616 let level_mode = mode & 0b00001111; let rounding_mode = mode >> 4; let level_mode = match level_mode {
1622 0 => LevelMode::Singular,
1623 1 => LevelMode::MipMap,
1624 2 => LevelMode::RipMap,
1625 _ => return Err(Error::invalid("tile description level mode")),
1626 };
1627
1628 let rounding_mode = match rounding_mode {
1629 0 => RoundingMode::Down,
1630 1 => RoundingMode::Up,
1631 _ => return Err(Error::invalid("tile description rounding mode")),
1632 };
1633
1634 Ok(TileDescription { tile_size: Vec2(x_size, y_size), level_mode, rounding_mode, })
1635 }
1636
1637 pub fn validate(&self) -> UnitResult {
1639 let max = i32::MAX as i64 / 2;
1640
1641 if self.tile_size.width() == 0 || self.tile_size.height() == 0
1642 || self.tile_size.width() as i64 >= max || self.tile_size.height() as i64 >= max
1643 {
1644 return Err(Error::invalid("tile size"))
1645 }
1646
1647 Ok(())
1648 }
1649}
1650
1651
1652pub fn byte_size(name: &Text, value: &AttributeValue) -> usize {
1655 name.null_terminated_byte_size()
1656 + value.kind_name().len() + sequence_end::byte_size()
1657 + i32::BYTE_SIZE + value.byte_size()
1659}
1660
1661pub fn write<W: Write>(name: &TextSlice, value: &AttributeValue, write: &mut W) -> UnitResult {
1663 Text::write_null_terminated_bytes(name, write)?;
1664 Text::write_null_terminated_bytes(value.kind_name(), write)?;
1665 i32::write_le(value.byte_size() as i32, write)?;
1666 value.write(write)
1667}
1668
1669pub fn read(read: &mut PeekRead<impl Read>, max_size: usize) -> Result<(Text, Result<AttributeValue>)> {
1671 let name = Text::read_null_terminated(read, max_size)?;
1672 let kind = Text::read_null_terminated(read, max_size)?;
1673 let size = i32_to_usize(i32::read_le(read)?, "attribute size")?;
1674 let value = AttributeValue::read(read, kind, size)?;
1675 Ok((name, value))
1676}
1677
1678pub fn validate(name: &Text, value: &AttributeValue, long_names: &mut bool, allow_sampling: bool, data_window: IntegerBounds, strict: bool) -> UnitResult {
1680 name.validate(true, Some(long_names))?; value.validate(allow_sampling, data_window, strict) }
1683
1684
1685impl AttributeValue {
1686
1687 pub fn byte_size(&self) -> usize {
1689 use self::AttributeValue::*;
1690
1691 match *self {
1692 IntegerBounds(_) => self::IntegerBounds::byte_size(),
1693 FloatRect(_) => self::FloatRect::byte_size(),
1694
1695 I32(_) => i32::BYTE_SIZE,
1696 F32(_) => f32::BYTE_SIZE,
1697 F64(_) => f64::BYTE_SIZE,
1698
1699 Rational(_) => { i32::BYTE_SIZE + u32::BYTE_SIZE },
1700 TimeCode(_) => self::TimeCode::BYTE_SIZE,
1701
1702 IntVec2(_) => { 2 * i32::BYTE_SIZE },
1703 FloatVec2(_) => { 2 * f32::BYTE_SIZE },
1704 IntVec3(_) => { 3 * i32::BYTE_SIZE },
1705 FloatVec3(_) => { 3 * f32::BYTE_SIZE },
1706
1707 ChannelList(ref channels) => channels.byte_size(),
1708 Chromaticities(_) => self::Chromaticities::byte_size(),
1709 Compression(_) => self::Compression::byte_size(),
1710 EnvironmentMap(_) => self::EnvironmentMap::byte_size(),
1711
1712 KeyCode(_) => self::KeyCode::byte_size(),
1713 LineOrder(_) => self::LineOrder::byte_size(),
1714
1715 Matrix3x3(ref value) => value.len() * f32::BYTE_SIZE,
1716 Matrix4x4(ref value) => value.len() * f32::BYTE_SIZE,
1717
1718 Preview(ref value) => value.byte_size(),
1719
1720 Text(ref value) => value.bytes.len(),
1723
1724 TextVector(ref value) => value.iter().map(self::Text::i32_sized_byte_size).sum(),
1725 TileDescription(_) => self::TileDescription::byte_size(),
1726 Custom { ref bytes, .. } => bytes.len(),
1727 BlockType(ref kind) => kind.byte_size(),
1728
1729 Bytes { ref bytes, ref type_hint } =>
1730 type_hint.u32_sized_byte_size() + bytes.len(),
1731 }
1732 }
1733
1734 pub fn kind_name(&self) -> &TextSlice {
1736 use self::AttributeValue::*;
1737 use self::type_names as ty;
1738
1739 match *self {
1740 IntegerBounds(_) => ty::I32BOX2,
1741 FloatRect(_) => ty::F32BOX2,
1742 I32(_) => ty::I32,
1743 F32(_) => ty::F32,
1744 F64(_) => ty::F64,
1745 Rational(_) => ty::RATIONAL,
1746 TimeCode(_) => ty::TIME_CODE,
1747 IntVec2(_) => ty::I32VEC2,
1748 FloatVec2(_) => ty::F32VEC2,
1749 IntVec3(_) => ty::I32VEC3,
1750 FloatVec3(_) => ty::F32VEC3,
1751 ChannelList(_) => ty::CHANNEL_LIST,
1752 Chromaticities(_) => ty::CHROMATICITIES,
1753 Compression(_) => ty::COMPRESSION,
1754 EnvironmentMap(_) => ty::ENVIRONMENT_MAP,
1755 KeyCode(_) => ty::KEY_CODE,
1756 LineOrder(_) => ty::LINE_ORDER,
1757 Matrix3x3(_) => ty::F32MATRIX3X3,
1758 Matrix4x4(_) => ty::F32MATRIX4X4,
1759 Preview(_) => ty::PREVIEW,
1760 Text(_) => ty::TEXT,
1761 TextVector(_) => ty::TEXT_VECTOR,
1762 TileDescription(_) => ty::TILES,
1763 BlockType(_) => super::BlockType::TYPE_NAME,
1764 Bytes{ .. } => ty::BYTES,
1765 Custom { ref kind, .. } => kind.as_slice(),
1766 }
1767 }
1768
1769 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1771 use self::AttributeValue::*;
1772 match *self {
1773 IntegerBounds(value) => value.write(write)?,
1774 FloatRect(value) => value.write(write)?,
1775
1776 I32(value) => value.write_le(write)?,
1777 F32(value) => value.write_le(write)?,
1778 F64(value) => value.write_le(write)?,
1779
1780 Rational((a, b)) => { a.write_le(write)?; b.write_le(write)?; },
1781 TimeCode(codes) => codes.write(write)?,
1782
1783 IntVec2(Vec2(x, y)) => { x.write_le(write)?; y.write_le(write)?; },
1784 FloatVec2(Vec2(x, y)) => { x.write_le(write)?; y.write_le(write)?; },
1785 IntVec3((x, y, z)) => { x.write_le(write)?; y.write_le(write)?; z.write_le(write)?; },
1786 FloatVec3((x, y, z)) => { x.write_le(write)?; y.write_le(write)?; z.write_le(write)?; },
1787
1788 ChannelList(ref channels) => channels.write(write)?,
1789 Chromaticities(ref value) => value.write(write)?,
1790 Compression(value) => value.write(write)?,
1791 EnvironmentMap(value) => value.write(write)?,
1792
1793 KeyCode(value) => value.write(write)?,
1794 LineOrder(value) => value.write(write)?,
1795
1796 Matrix3x3(mut value) => f32::write_slice_le(write, &mut value)?,
1797 Matrix4x4(mut value) => f32::write_slice_le(write, &mut value)?,
1798
1799 Preview(ref value) => value.write(write)?,
1800
1801 Text(ref value) => u8::write_slice_le(write, value.bytes.as_slice())?,
1804
1805 TextVector(ref value) => self::Text::write_vec_of_i32_sized_texts_le(write, value)?,
1806 TileDescription(ref value) => value.write(write)?,
1807 BlockType(kind) => kind.write(write)?,
1808
1809 Bytes { ref type_hint, ref bytes } => {
1810 type_hint.write_u32_sized_le(write)?; u8::write_slice_le(write, bytes.as_slice())?
1812 }
1813
1814 Custom { ref bytes, .. } => u8::write_slice_le(write, &bytes)?, };
1816
1817 Ok(())
1818 }
1819
1820 pub fn read(read: &mut PeekRead<impl Read>, kind: Text, byte_size: usize) -> Result<Result<Self>> {
1825 use self::AttributeValue::*;
1826 use self::type_names as ty;
1827
1828 let mut attribute_bytes = SmallVec::<[u8; 64]>::new();
1831 u8::read_into_vec_le(read, &mut attribute_bytes, byte_size, 64, None, "attribute value size")?;
1832 let parse_attribute = move || {
1835 let reader = &mut attribute_bytes.as_slice();
1836
1837 Ok(match kind.bytes.as_slice() {
1838 ty::I32BOX2 => IntegerBounds(self::IntegerBounds::read(reader)?),
1839 ty::F32BOX2 => FloatRect(self::FloatRect::read(reader)?),
1840
1841 ty::I32 => I32(i32::read_le(reader)?),
1842 ty::F32 => F32(f32::read_le(reader)?),
1843 ty::F64 => F64(f64::read_le(reader)?),
1844
1845 ty::RATIONAL => Rational({
1846 let a = i32::read_le(reader)?;
1847 let b = u32::read_le(reader)?;
1848 (a, b)
1849 }),
1850
1851 ty::TIME_CODE => TimeCode(self::TimeCode::read(reader)?),
1852
1853 ty::I32VEC2 => IntVec2({
1854 let a = i32::read_le(reader)?;
1855 let b = i32::read_le(reader)?;
1856 Vec2(a, b)
1857 }),
1858
1859 ty::F32VEC2 => FloatVec2({
1860 let a = f32::read_le(reader)?;
1861 let b = f32::read_le(reader)?;
1862 Vec2(a, b)
1863 }),
1864
1865 ty::I32VEC3 => IntVec3({
1866 let a = i32::read_le(reader)?;
1867 let b = i32::read_le(reader)?;
1868 let c = i32::read_le(reader)?;
1869 (a, b, c)
1870 }),
1871
1872 ty::F32VEC3 => FloatVec3({
1873 let a = f32::read_le(reader)?;
1874 let b = f32::read_le(reader)?;
1875 let c = f32::read_le(reader)?;
1876 (a, b, c)
1877 }),
1878
1879 ty::CHANNEL_LIST => ChannelList(self::ChannelList::read(&mut PeekRead::new(attribute_bytes.as_slice()))?),
1880 ty::CHROMATICITIES => Chromaticities(self::Chromaticities::read(reader)?),
1881 ty::COMPRESSION => Compression(self::Compression::read(reader)?),
1882 ty::ENVIRONMENT_MAP => EnvironmentMap(self::EnvironmentMap::read(reader)?),
1883
1884 ty::KEY_CODE => KeyCode(self::KeyCode::read(reader)?),
1885 ty::LINE_ORDER => LineOrder(self::LineOrder::read(reader)?),
1886
1887 ty::F32MATRIX3X3 => Matrix3x3({
1888 let mut result = [0.0_f32; 9];
1889 f32::read_slice_le(reader, &mut result)?;
1890 result
1891 }),
1892
1893 ty::F32MATRIX4X4 => Matrix4x4({
1894 let mut result = [0.0_f32; 16];
1895 f32::read_slice_le(reader, &mut result)?;
1896 result
1897 }),
1898
1899 ty::PREVIEW => Preview(self::Preview::read(reader)?),
1900 ty::TEXT => Text(self::Text::read_sized(reader, byte_size)?),
1901
1902 ty::TEXT_VECTOR => TextVector(self::Text::read_vec_of_i32_sized_texts_le(
1904 &mut PeekRead::new(attribute_bytes.as_slice()),
1905 byte_size
1906 )?),
1907
1908 ty::TILES => TileDescription(self::TileDescription::read(reader)?),
1909
1910 ty::BYTES => {
1911 let type_hint = self::Text::read_u32_sized_le(reader, reader.len())?;
1913 let bytes = SmallVec::from(*reader);
1914 Bytes { type_hint, bytes }
1915 }
1916
1917 _ => Custom { kind: kind.clone(), bytes: SmallVec::from(*reader) }
1918 })
1919 };
1920
1921 Ok(parse_attribute())
1922 }
1923
1924 pub fn validate(&self, allow_sampling: bool, data_window: IntegerBounds, strict: bool) -> UnitResult {
1926 use self::AttributeValue::*;
1927
1928 match *self {
1929 ChannelList(ref channels) => channels.validate(allow_sampling, data_window, strict)?,
1930 TileDescription(ref value) => value.validate()?,
1931 Preview(ref value) => value.validate(strict)?,
1932 TimeCode(ref time_code) => time_code.validate(strict)?,
1933
1934 TextVector(ref vec) => if strict && vec.is_empty() {
1935 return Err(Error::invalid("text vector may not be empty"))
1936 },
1937
1938 _ => {}
1939 };
1940
1941 Ok(())
1942 }
1943
1944
1945 pub fn to_i32(&self) -> Result<i32> {
1947 match *self {
1948 AttributeValue::I32(value) => Ok(value),
1949 _ => Err(invalid_type())
1950 }
1951 }
1952
1953 pub fn to_f32(&self) -> Result<f32> {
1955 match *self {
1956 AttributeValue::F32(value) => Ok(value),
1957 _ => Err(invalid_type())
1958 }
1959 }
1960
1961 pub fn into_text(self) -> Result<Text> {
1963 match self {
1964 AttributeValue::Text(value) => Ok(value),
1965 _ => Err(invalid_type())
1966 }
1967 }
1968
1969 pub fn to_text(&self) -> Result<&Text> {
1971 match self {
1972 AttributeValue::Text(value) => Ok(value),
1973 _ => Err(invalid_type())
1974 }
1975 }
1976
1977 pub fn to_chromaticities(&self) -> Result<Chromaticities> {
1979 match *self {
1980 AttributeValue::Chromaticities(value) => Ok(value),
1981 _ => Err(invalid_type())
1982 }
1983 }
1984
1985 pub fn to_time_code(&self) -> Result<TimeCode> {
1987 match *self {
1988 AttributeValue::TimeCode(value) => Ok(value),
1989 _ => Err(invalid_type())
1990 }
1991 }
1992}
1993
1994
1995
1996pub mod type_names {
1998 macro_rules! define_attribute_type_names {
1999 ( $($name: ident : $value: expr),* ) => {
2000 $(
2001 pub const $name: &'static [u8] = $value;
2003 )*
2004 };
2005 }
2006
2007 define_attribute_type_names! {
2008 I32BOX2: b"box2i",
2009 F32BOX2: b"box2f",
2010 I32: b"int",
2011 F32: b"float",
2012 F64: b"double",
2013 RATIONAL: b"rational",
2014 TIME_CODE: b"timecode",
2015 I32VEC2: b"v2i",
2016 F32VEC2: b"v2f",
2017 I32VEC3: b"v3i",
2018 F32VEC3: b"v3f",
2019 CHANNEL_LIST: b"chlist",
2020 CHROMATICITIES: b"chromaticities",
2021 COMPRESSION: b"compression",
2022 ENVIRONMENT_MAP:b"envmap",
2023 KEY_CODE: b"keycode",
2024 LINE_ORDER: b"lineOrder",
2025 F32MATRIX3X3: b"m33f",
2026 F32MATRIX4X4: b"m44f",
2027 PREVIEW: b"preview",
2028 TEXT: b"string",
2029 TEXT_VECTOR: b"stringvector",
2030 TILES: b"tiledesc",
2031 BYTES: b"bytes"
2032 }
2033}
2034
2035
2036#[cfg(test)]
2037mod test {
2038 use super::*;
2039 use ::std::io::Cursor;
2040 use rand::{random, thread_rng, Rng};
2041
2042 #[test]
2043 fn text_ord() {
2044 for _ in 0..1024 {
2045 let text1 = Text::from_bytes_unchecked((0..4).map(|_| rand::random::<u8>()).collect());
2046 let text2 = Text::from_bytes_unchecked((0..4).map(|_| rand::random::<u8>()).collect());
2047
2048 assert_eq!(text1.to_string().cmp(&text2.to_string()), text1.cmp(&text2), "in text {:?} vs {:?}", text1, text2);
2049 }
2050 }
2051
2052 #[test]
2053 fn rounding_up(){
2054 let round_up = RoundingMode::Up;
2055 assert_eq!(round_up.divide(10, 10), 1, "divide equal");
2056 assert_eq!(round_up.divide(10, 2), 5, "divide even");
2057 assert_eq!(round_up.divide(10, 5), 2, "divide even");
2058
2059 assert_eq!(round_up.divide(8, 5), 2, "round up");
2060 assert_eq!(round_up.divide(10, 3), 4, "round up");
2061 assert_eq!(round_up.divide(100, 50), 2, "divide even");
2062 assert_eq!(round_up.divide(100, 49), 3, "round up");
2063 }
2064
2065 #[test]
2066 fn rounding_down(){
2067 let round_down = RoundingMode::Down;
2068 assert_eq!(round_down.divide(8, 5), 1, "round down");
2069 assert_eq!(round_down.divide(10, 3), 3, "round down");
2070 assert_eq!(round_down.divide(100, 50), 2, "divide even");
2071 assert_eq!(round_down.divide(100, 49), 2, "round down");
2072 assert_eq!(round_down.divide(100, 51), 1, "round down");
2073 }
2074
2075 #[test]
2076 fn tile_description_write_read_roundtrip(){
2077 let tiles = [
2078 TileDescription {
2079 tile_size: Vec2(31, 7),
2080 level_mode: LevelMode::MipMap,
2081 rounding_mode: RoundingMode::Down,
2082 },
2083
2084 TileDescription {
2085 tile_size: Vec2(0, 0),
2086 level_mode: LevelMode::Singular,
2087 rounding_mode: RoundingMode::Up,
2088 },
2089
2090 TileDescription {
2091 tile_size: Vec2(4294967294, 4294967295),
2092 level_mode: LevelMode::RipMap,
2093 rounding_mode: RoundingMode::Down,
2094 },
2095 ];
2096
2097 for tile in &tiles {
2098 let mut bytes = Vec::new();
2099 tile.write(&mut bytes).unwrap();
2100
2101 let new_tile = TileDescription::read(&mut Cursor::new(bytes)).unwrap();
2102 assert_eq!(*tile, new_tile, "tile round trip");
2103 }
2104 }
2105
2106 #[test]
2107 fn attribute_write_read_roundtrip_and_byte_size(){
2108 let attributes = [
2109 (
2110 Text::from("greeting"),
2111 AttributeValue::Text(Text::from("hello")),
2112 ),
2113 (
2114 Text::from("age"),
2115 AttributeValue::I32(923),
2116 ),
2117 (
2118 Text::from("leg count"),
2119 AttributeValue::F64(9.114939599234),
2120 ),
2121 (
2122 Text::from("rabbit area"),
2123 AttributeValue::FloatRect(FloatRect {
2124 min: Vec2(23.4234, 345.23),
2125 max: Vec2(68623.0, 3.12425926538),
2126 }),
2127 ),
2128 (
2129 Text::from("rabbit area int"),
2130 AttributeValue::IntegerBounds(IntegerBounds {
2131 position: Vec2(23, 345),
2132 size: Vec2(68623, 3),
2133 }),
2134 ),
2135 (
2136 Text::from("rabbit area int"),
2137 AttributeValue::IntegerBounds(IntegerBounds {
2138 position: Vec2(-(i32::MAX / 2 - 1), -(i32::MAX / 2 - 1)),
2139 size: Vec2(i32::MAX as usize - 2, i32::MAX as usize - 2),
2140 }),
2141 ),
2142 (
2143 Text::from("rabbit area int 2"),
2144 AttributeValue::IntegerBounds(IntegerBounds {
2145 position: Vec2(0, 0),
2146 size: Vec2(i32::MAX as usize / 2 - 1, i32::MAX as usize / 2 - 1),
2147 }),
2148 ),
2149 (
2150 Text::from("tests are difficult"),
2151 AttributeValue::TextVector(vec![
2152 Text::from("sdoifjpsdv"),
2153 Text::from("sdoifjpsdvxxxx"),
2154 Text::from("sdoifjasd"),
2155 Text::from("sdoifj"),
2156 Text::from("sdoifjddddddddasdasd"),
2157 ]),
2158 ),
2159 (
2160 Text::from("what should we eat tonight"),
2161 AttributeValue::Preview(Preview {
2162 size: Vec2(10, 30),
2163 pixel_data: vec![31; 10 * 30 * 4],
2164 }),
2165 ),
2166 (
2167 Text::from("custom byte sequence: prime numbers single byte"),
2168 AttributeValue::Bytes{
2169 type_hint: Text::from("byte-primes"),
2170 bytes: smallvec![2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73],
2171 },
2172 ),
2173 (
2174 Text::from("leg count, again"),
2175 AttributeValue::ChannelList(ChannelList::new(smallvec![
2176 ChannelDescription {
2177 name: Text::from("Green"),
2178 sample_type: SampleType::F16,
2179 quantize_linearly: false,
2180 sampling: Vec2(1,2)
2181 },
2182 ChannelDescription {
2183 name: Text::from("Red"),
2184 sample_type: SampleType::F32,
2185 quantize_linearly: true,
2186 sampling: Vec2(1,2)
2187 },
2188 ChannelDescription {
2189 name: Text::from("Purple"),
2190 sample_type: SampleType::U32,
2191 quantize_linearly: false,
2192 sampling: Vec2(0,0)
2193 }
2194 ],
2195 )),
2196 ),
2197 ];
2198
2199 for (name, value) in &attributes {
2200 let mut bytes = Vec::new();
2201 super::write(name.as_slice(), value, &mut bytes).unwrap();
2202 assert_eq!(super::byte_size(name, value), bytes.len(), "attribute.byte_size() for {:?}", (name, value));
2203
2204 let new_attribute = super::read(&mut PeekRead::new(Cursor::new(bytes)), 300).unwrap();
2205 assert_eq!((name.clone(), value.clone()), (new_attribute.0, new_attribute.1.unwrap()), "attribute round trip");
2206 }
2207
2208
2209 {
2210 let (name, value) = (
2211 Text::from("asdkaspfokpaosdkfpaokswdpoakpsfokaposdkf"),
2212 AttributeValue::I32(0),
2213 );
2214
2215 let mut long_names = false;
2216 super::validate(&name, &value, &mut long_names, false, IntegerBounds::zero(), false).unwrap();
2217 assert!(long_names);
2218 }
2219
2220 {
2221 let (name, value) = (
2222 Text::from("sdöksadöofkaspdolkpöasolfkcöalsod,kfcöaslodkcpöasolkfposdöksadöofkaspdolkpöasolfkcöalsod,kfcöaslodkcpöasolkfposdöksadöofkaspdolkpöasolfkcöalsod,kfcöaslodkcpöasolkfposdöksadöofkaspdolkpöasolfkcöalsod,kfcöaslodkcpöasolkfposdöksadöofkaspdolkpöasolfkcöalsod,kfcöaslodkcpöasolkfposdöksadöofkaspdolkpöasolfkcöalsod,kfcöaslodkcpöasolkfpo"),
2223 AttributeValue::I32(0),
2224 );
2225
2226 super::validate(&name, &value, &mut false, false, IntegerBounds::zero(), false).expect_err("name length check failed");
2227 }
2228 }
2229
2230 #[test]
2231 fn time_code_pack(){
2232 let mut rng = thread_rng();
2233
2234 let codes = std::iter::repeat_with(|| TimeCode {
2235 hours: rng.gen_range(0 .. 24),
2236 minutes: rng.gen_range(0 .. 60),
2237 seconds: rng.gen_range(0 .. 60),
2238 frame: rng.gen_range(0 .. 29),
2239 drop_frame: random(),
2240 color_frame: random(),
2241 field_phase: random(),
2242 binary_group_flags: [random(),random(),random()],
2243 binary_groups: std::iter::repeat_with(|| rng.gen_range(0 .. 16)).take(8)
2244 .collect::<SmallVec<[u8;8]>>().into_inner().unwrap()
2245 });
2246
2247 for code in codes.take(500) {
2248 code.validate(true).expect("invalid timecode test input");
2249
2250 { let packed_tv60 = code.pack_time_as_tv60_u32().expect("invalid timecode test input");
2252 let packed_user = code.pack_user_data_as_u32();
2253 assert_eq!(TimeCode::from_tv60_time(packed_tv60, packed_user), code);
2254 }
2255
2256 { let mut bytes = Vec::<u8>::new();
2258 code.write(&mut bytes).unwrap();
2259 let decoded = TimeCode::read(&mut bytes.as_slice()).unwrap();
2260 assert_eq!(code, decoded);
2261 }
2262
2263 {
2264 let tv50_code = TimeCode {
2265 drop_frame: false, .. code
2267 };
2268
2269 let packed_tv50 = code.pack_time_as_tv50_u32().expect("invalid timecode test input");
2270 let packed_user = code.pack_user_data_as_u32();
2271 assert_eq!(TimeCode::from_tv50_time(packed_tv50, packed_user), tv50_code);
2272 }
2273
2274 {
2275 let film24_code = TimeCode {
2276 color_frame: false,
2278 drop_frame: false,
2279 .. code
2280 };
2281
2282 let packed_film24 = code.pack_time_as_film24_u32().expect("invalid timecode test input");
2283 let packed_user = code.pack_user_data_as_u32();
2284 assert_eq!(TimeCode::from_film24_time(packed_film24, packed_user), film24_code);
2285 }
2286 }
2287 }
2288
2289}