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 Custom {
88
89 kind: Text,
91
92 bytes: Vec<u8>
95 },
96}
97
98#[derive(Clone, PartialEq, Ord, PartialOrd, Default)] pub struct Text {
103 bytes: TextBytes,
104}
105
106#[derive(Copy, Debug, Clone, Eq, PartialEq, Hash, Default)]
113pub struct TimeCode {
114
115 pub hours: u8,
117
118 pub minutes: u8,
120
121 pub seconds: u8,
123
124 pub frame: u8,
126
127 pub drop_frame: bool,
129
130 pub color_frame: bool,
132
133 pub field_phase: bool,
135
136 pub binary_group_flags: [bool; 3],
138
139 pub binary_groups: [u8; 8]
143}
144
145#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
147pub enum BlockType {
148
149 ScanLine,
151
152 Tile,
154
155 DeepScanLine,
157
158 DeepTile,
160}
161
162pub mod block_type_strings {
164
165 pub const SCAN_LINE: &'static [u8] = b"scanlineimage";
167
168 pub const TILE: &'static [u8] = b"tiledimage";
170
171 pub const DEEP_SCAN_LINE: &'static [u8] = b"deepscanline";
173
174 pub const DEEP_TILE: &'static [u8] = b"deeptile";
176}
177
178
179pub use crate::compression::Compression;
180
181pub type DataWindow = IntegerBounds;
183
184pub type DisplayWindow = IntegerBounds;
186
187pub type Rational = (i32, u32);
189
190pub type Matrix4x4 = [f32; 4*4];
192
193pub type Matrix3x3 = [f32; 3*3];
195
196#[derive(Clone, Copy, Debug, Eq, PartialEq, Default, Hash)]
200pub struct IntegerBounds {
201
202 pub position: Vec2<i32>,
205
206 pub size: Vec2<usize>,
210}
211
212#[derive(Clone, Copy, Debug, PartialEq)]
214pub struct FloatRect {
215
216 pub min: Vec2<f32>,
218
219 pub max: Vec2<f32>
221}
222
223#[derive(Clone, Debug, Eq, PartialEq, Hash)]
225pub struct ChannelList {
226
227 pub list: SmallVec<[ChannelDescription; 5]>,
229
230 pub bytes_per_pixel: usize, pub uniform_sample_type: Option<SampleType>,
236}
237
238#[derive(Clone, Debug, Eq, PartialEq, Hash)]
242pub struct ChannelDescription {
243
244 pub name: Text,
246
247 pub sample_type: SampleType,
249
250 pub quantize_linearly: bool,
256
257 pub sampling: Vec2<usize>,
263}
264
265#[derive(Clone, Debug, Eq, PartialEq, Copy, Hash)]
267pub enum SampleType {
268
269 U32,
271
272 F16,
274
275 F32,
277}
278
279#[derive(Debug, Clone, Copy, PartialEq)]
284pub struct Chromaticities {
285
286 pub red: Vec2<f32>,
288
289 pub green: Vec2<f32>,
291
292 pub blue: Vec2<f32>,
294
295 pub white: Vec2<f32>
297}
298
299#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
302pub enum EnvironmentMap {
303
304 LatitudeLongitude,
306
307 Cube,
309}
310
311#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
313pub struct KeyCode {
314
315 pub film_manufacturer_code: i32,
317
318 pub film_type: i32,
320
321 pub film_roll_prefix: i32,
323
324 pub count: i32,
326
327 pub perforation_offset: i32,
329
330 pub perforations_per_frame: i32,
332
333 pub perforations_per_count: i32,
335}
336
337#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
339pub enum LineOrder {
340
341 Increasing,
345
346 Decreasing,
350
351 Unspecified,
354}
355
356#[derive(Clone, Eq, PartialEq)]
359pub struct Preview {
360
361 pub size: Vec2<usize>,
363
364 pub pixel_data: Vec<i8>,
368}
369
370#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
374pub struct TileDescription {
375
376 pub tile_size: Vec2<usize>,
379
380 pub level_mode: LevelMode,
382
383 pub rounding_mode: RoundingMode,
385}
386
387#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
389pub enum LevelMode {
390
391 Singular,
393
394 MipMap,
396
397 RipMap,
399}
400
401
402pub type TextBytes = SmallVec<[u8; 24]>;
406
407pub type TextSlice = [u8];
409
410
411use crate::io::*;
412use crate::meta::{sequence_end};
413use crate::error::*;
414use crate::math::{RoundingMode, Vec2};
415use half::f16;
416use std::convert::{TryFrom};
417use std::borrow::Borrow;
418use std::hash::{Hash, Hasher};
419use bit_field::BitField;
420
421
422fn invalid_type() -> Error {
423 Error::invalid("attribute type mismatch")
424}
425
426
427impl Text {
428
429 pub fn new_or_none(string: impl AsRef<str>) -> Option<Self> {
432 let vec : Option<TextBytes> = string.as_ref().chars()
433 .map(|character| u8::try_from(character as u64).ok())
434 .collect();
435
436 vec.map(Self::from_bytes_unchecked)
437 }
438
439 pub fn new_or_panic(string: impl AsRef<str>) -> Self {
442 Self::new_or_none(string).expect("exr::Text contains unsupported characters")
443 }
444
445 pub fn from_slice_unchecked(text: &TextSlice) -> Self {
448 Self::from_bytes_unchecked(SmallVec::from_slice(text))
449 }
450
451 pub fn from_bytes_unchecked(bytes: TextBytes) -> Self {
454 Text { bytes }
455 }
456
457 pub fn as_slice(&self) -> &TextSlice {
459 self.bytes.as_slice()
460 }
461
462 pub fn validate(&self, null_terminated: bool, long_names: Option<&mut bool>) -> UnitResult {
465 Self::validate_bytes(self.as_slice(), null_terminated, long_names)
466 }
467
468 pub fn validate_bytes(text: &TextSlice, null_terminated: bool, long_names: Option<&mut bool>) -> UnitResult {
471 if null_terminated && text.is_empty() {
472 return Err(Error::invalid("text must not be empty"));
473 }
474
475 if let Some(long) = long_names {
476 if text.len() >= 256 { return Err(Error::invalid("text must not be longer than 255")); }
477 if text.len() >= 32 { *long = true; }
478 }
479
480 Ok(())
481 }
482
483 pub fn null_terminated_byte_size(&self) -> usize {
485 self.bytes.len() + sequence_end::byte_size()
486 }
487
488 pub fn i32_sized_byte_size(&self) -> usize {
490 self.bytes.len() + i32::BYTE_SIZE
491 }
492
493 pub fn write_i32_sized<W: Write>(&self, write: &mut W) -> UnitResult {
495 debug_assert!(self.validate( false, None).is_ok(), "text size bug");
496 i32::write(usize_to_i32(self.bytes.len()), write)?;
497 Self::write_unsized_bytes(self.bytes.as_slice(), write)
498 }
499
500 fn write_unsized_bytes<W: Write>(bytes: &[u8], write: &mut W) -> UnitResult {
502 u8::write_slice(write, bytes)?;
503 Ok(())
504 }
505
506 pub fn read_i32_sized<R: Read>(read: &mut R, max_size: usize) -> Result<Self> {
508 let size = i32_to_usize(i32::read(read)?, "vector size")?;
509 Ok(Text::from_bytes_unchecked(SmallVec::from_vec(u8::read_vec(read, size, 1024, Some(max_size), "text attribute length")?)))
510 }
511
512 pub fn read_sized<R: Read>(read: &mut R, size: usize) -> Result<Self> {
514 const SMALL_SIZE: usize = 24;
515
516 if size <= SMALL_SIZE {
518 let mut buffer = [0_u8; SMALL_SIZE];
519 let data = &mut buffer[..size];
520
521 read.read_exact(data)?;
522 Ok(Text::from_bytes_unchecked(SmallVec::from_slice(data)))
523 }
524
525 else {
527 Ok(Text::from_bytes_unchecked(SmallVec::from_vec(u8::read_vec(read, size, 1024, None, "text attribute length")?)))
528 }
529 }
530
531 pub fn write_null_terminated<W: Write>(&self, write: &mut W) -> UnitResult {
533 Self::write_null_terminated_bytes(self.as_slice(), write)
534 }
535
536 fn write_null_terminated_bytes<W: Write>(bytes: &[u8], write: &mut W) -> UnitResult {
538 debug_assert!(!bytes.is_empty(), "text is empty bug"); Text::write_unsized_bytes(bytes, write)?;
541 sequence_end::write(write)?;
542 Ok(())
543 }
544
545 pub fn read_null_terminated<R: Read>(read: &mut R, max_len: usize) -> Result<Self> {
547 let mut bytes = smallvec![ u8::read(read)? ]; loop {
550 match u8::read(read)? {
551 0 => break,
552 non_terminator => bytes.push(non_terminator),
553 }
554
555 if bytes.len() > max_len {
556 return Err(Error::invalid("text too long"))
557 }
558 }
559
560 Ok(Text { bytes })
561 }
562
563 fn read_vec_of_i32_sized(
566 read: &mut PeekRead<impl Read>,
567 total_byte_size: usize
568 ) -> Result<Vec<Text>>
569 {
570 let mut result = Vec::with_capacity(2);
571
572 let mut processed_bytes = 0;
574
575 while processed_bytes < total_byte_size {
576 let text = Text::read_i32_sized(read, total_byte_size)?;
577 processed_bytes += ::std::mem::size_of::<i32>(); processed_bytes += text.bytes.len();
579 result.push(text);
580 }
581
582 if processed_bytes != total_byte_size {
584 return Err(Error::invalid("text array byte size"))
585 }
586
587 Ok(result)
588 }
589
590 fn write_vec_of_i32_sized_texts<W: Write>(write: &mut W, texts: &[Text]) -> UnitResult {
593 for text in texts {
595 text.write_i32_sized(write)?;
596 }
597
598 Ok(())
599 }
600
601 pub fn bytes(&self) -> &[u8] {
603 self.bytes.as_slice()
604 }
605
606 pub fn chars(&self) -> impl '_ + Iterator<Item = char> {
609 self.bytes.iter().map(|&byte| byte as char)
610 }
611
612 pub fn eq(&self, string: &str) -> bool {
614 string.chars().eq(self.chars())
615 }
616
617 pub fn eq_case_insensitive(&self, string: &str) -> bool {
619 let self_chars = self.chars().map(|char| char.to_ascii_lowercase());
621 let string_chars = string.chars().flat_map(|ch| ch.to_lowercase());
622
623 string_chars.eq(self_chars)
624 }
625}
626
627impl PartialEq<str> for Text {
628 fn eq(&self, other: &str) -> bool {
629 self.eq(other)
630 }
631}
632
633impl PartialEq<Text> for str {
634 fn eq(&self, other: &Text) -> bool {
635 other.eq(self)
636 }
637}
638
639impl Eq for Text {}
640
641impl Borrow<TextSlice> for Text {
642 fn borrow(&self) -> &TextSlice {
643 self.as_slice()
644 }
645}
646
647impl Hash for Text {
649 fn hash<H: Hasher>(&self, state: &mut H) {
650 self.bytes.hash(state)
651 }
652}
653
654impl Into<String> for Text {
655 fn into(self) -> String {
656 self.to_string()
657 }
658}
659
660impl<'s> From<&'s str> for Text {
661
662 fn from(str: &'s str) -> Self {
664 Self::new_or_panic(str)
665 }
666}
667
668
669impl ::std::fmt::Debug for Text {
684 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
685 write!(f, "exr::Text(\"{}\")", self)
686 }
687}
688
689impl ::std::fmt::Display for Text {
691 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
692 use std::fmt::Write;
693
694 for &byte in self.bytes.iter() {
695 f.write_char(byte as char)?;
696 }
697
698 Ok(())
699 }
700}
701
702
703impl ChannelList {
704
705 pub fn new(channels: SmallVec<[ChannelDescription; 5]>) -> Self {
707 let uniform_sample_type = {
708 if let Some(first) = channels.first() {
709 let has_uniform_types = channels.iter().skip(1)
710 .all(|chan| chan.sample_type == first.sample_type);
711
712 if has_uniform_types { Some(first.sample_type) } else { None }
713 }
714 else { None }
715 };
716
717 ChannelList {
718 bytes_per_pixel: channels.iter().map(|channel| channel.sample_type.bytes_per_sample()).sum(),
719 list: channels, uniform_sample_type,
720 }
721 }
722
723 pub fn channels_with_byte_offset(&self) -> impl Iterator<Item=(usize, &ChannelDescription)> {
726 self.list.iter().scan(0, |byte_position, channel|{
727 let previous_position = *byte_position;
728 *byte_position += channel.sample_type.bytes_per_sample();
729 Some((previous_position, channel))
730 })
731 }
732
733 pub fn find_index_of_channel(&self, exact_name: &Text) -> Option<usize> {
736 self.list.binary_search_by_key(&exact_name.bytes(), |chan| chan.name.bytes()).ok()
737 }
738
739 }
752
753impl BlockType {
754
755 const TYPE_NAME: &'static [u8] = type_names::TEXT;
757
758 pub fn parse(text: Text) -> Result<Self> {
760 match text.as_slice() {
761 block_type_strings::SCAN_LINE => Ok(BlockType::ScanLine),
762 block_type_strings::TILE => Ok(BlockType::Tile),
763
764 block_type_strings::DEEP_SCAN_LINE => Ok(BlockType::DeepScanLine),
765 block_type_strings::DEEP_TILE => Ok(BlockType::DeepTile),
766
767 _ => Err(Error::invalid("block type attribute value")),
768 }
769 }
770
771 pub fn write(&self, write: &mut impl Write) -> UnitResult {
773 u8::write_slice(write, self.to_text_bytes())?;
774 Ok(())
775 }
776
777 pub fn to_text_bytes(&self) -> &[u8] {
779 match self {
780 BlockType::ScanLine => block_type_strings::SCAN_LINE,
781 BlockType::Tile => block_type_strings::TILE,
782 BlockType::DeepScanLine => block_type_strings::DEEP_SCAN_LINE,
783 BlockType::DeepTile => block_type_strings::DEEP_TILE,
784 }
785 }
786
787 pub fn byte_size(&self) -> usize {
789 self.to_text_bytes().len()
790 }
791}
792
793
794impl IntegerBounds {
795
796 pub fn zero() -> Self {
798 Self::from_dimensions(Vec2(0, 0))
799 }
800
801 pub fn from_dimensions(size: impl Into<Vec2<usize>>) -> Self {
803 Self::new(Vec2(0,0), size)
804 }
805
806 pub fn new(start: impl Into<Vec2<i32>>, size: impl Into<Vec2<usize>>) -> Self {
808 Self { position: start.into(), size: size.into() }
809 }
810
811 pub fn end(self) -> Vec2<i32> {
815 self.position + self.size.to_i32() }
817
818 pub fn max(self) -> Vec2<i32> {
820 self.end() - Vec2(1,1)
821 }
822
823 pub fn validate(&self, max_size: Option<Vec2<usize>>) -> UnitResult {
825 if let Some(max_size) = max_size {
826 if self.size.width() > max_size.width() || self.size.height() > max_size.height() {
827 return Err(Error::invalid("window attribute dimension value"));
828 }
829 }
830
831 let min_i64 = Vec2(self.position.x() as i64, self.position.y() as i64);
832
833 let max_i64 = Vec2(
834 self.position.x() as i64 + self.size.width() as i64,
835 self.position.y() as i64 + self.size.height() as i64,
836 );
837
838 Self::validate_min_max_u64(min_i64, max_i64)
839 }
840
841 fn validate_min_max_u64(min: Vec2<i64>, max: Vec2<i64>) -> UnitResult {
842 let max_box_size_as_i64 = (i32::MAX / 2) as i64; if max.x() >= max_box_size_as_i64
845 || max.y() >= max_box_size_as_i64
846 || min.x() <= -max_box_size_as_i64
847 || min.y() <= -max_box_size_as_i64
848 {
849 return Err(Error::invalid("window size exceeding integer maximum"));
850 }
851
852 Ok(())
853 }
854
855 pub fn byte_size() -> usize {
857 4 * i32::BYTE_SIZE
858 }
859
860 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
862 let Vec2(x_min, y_min) = self.position;
863 let Vec2(x_max, y_max) = self.max();
864
865 x_min.write(write)?;
866 y_min.write(write)?;
867 x_max.write(write)?;
868 y_max.write(write)?;
869 Ok(())
870 }
871
872 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
874 let x_min = i32::read(read)?;
875 let y_min = i32::read(read)?;
876 let x_max = i32::read(read)?;
877 let y_max = i32::read(read)?;
878
879 let min = Vec2(x_min.min(x_max), y_min.min(y_max));
880 let max = Vec2(x_min.max(x_max), y_min.max(y_max));
881
882 Self::validate_min_max_u64(
884 Vec2(min.x() as i64, min.y() as i64),
885 Vec2(max.x() as i64, max.y() as i64),
886 )?;
887
888 let size = Vec2(max.x() + 1 - min.x(), max.y() + 1 - min.y());
890 let size = size.to_usize("box coordinates")?;
891
892 Ok(IntegerBounds { position: min, size })
893 }
894
895 pub fn with_origin(self, origin: Vec2<i32>) -> Self { IntegerBounds { position: self.position + origin, .. self }
898 }
899
900 pub fn contains(self, subset: Self) -> bool {
902 subset.position.x() >= self.position.x()
903 && subset.position.y() >= self.position.y()
904 && subset.end().x() <= self.end().x()
905 && subset.end().y() <= self.end().y()
906 }
907}
908
909
910impl FloatRect {
911
912 pub fn byte_size() -> usize {
914 4 * f32::BYTE_SIZE
915 }
916
917 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
919 self.min.x().write(write)?;
920 self.min.y().write(write)?;
921 self.max.x().write(write)?;
922 self.max.y().write(write)?;
923 Ok(())
924 }
925
926 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
928 let x_min = f32::read(read)?;
929 let y_min = f32::read(read)?;
930 let x_max = f32::read(read)?;
931 let y_max = f32::read(read)?;
932
933 Ok(FloatRect {
934 min: Vec2(x_min, y_min),
935 max: Vec2(x_max, y_max)
936 })
937 }
938}
939
940impl SampleType {
941
942 pub fn bytes_per_sample(&self) -> usize {
944 match self {
945 SampleType::F16 => f16::BYTE_SIZE,
946 SampleType::F32 => f32::BYTE_SIZE,
947 SampleType::U32 => u32::BYTE_SIZE,
948 }
949 }
950
951 pub fn byte_size() -> usize {
953 i32::BYTE_SIZE
954 }
955
956 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
958 match *self {
959 SampleType::U32 => 0_i32,
960 SampleType::F16 => 1_i32,
961 SampleType::F32 => 2_i32,
962 }.write(write)?;
963
964 Ok(())
965 }
966
967 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
969 Ok(match i32::read(read)? {
971 0 => SampleType::U32,
972 1 => SampleType::F16,
973 2 => SampleType::F32,
974 _ => return Err(Error::invalid("pixel type attribute value")),
975 })
976 }
977}
978
979impl ChannelDescription {
980 pub fn guess_quantization_linearity(name: &Text) -> bool {
983 !(
984 name.eq_case_insensitive("R") || name.eq_case_insensitive("G") ||
985 name.eq_case_insensitive("B") || name.eq_case_insensitive("L") ||
986 name.eq_case_insensitive("Y") || name.eq_case_insensitive("X") ||
987 name.eq_case_insensitive("Z")
988 )
989 }
990
991 pub fn named(name: impl Into<Text>, sample_type: SampleType) -> Self {
994 let name = name.into();
995 let linearity = Self::guess_quantization_linearity(&name);
996 Self::new(name, sample_type, linearity)
997 }
998
999 pub fn new(name: impl Into<Text>, sample_type: SampleType, quantize_linearly: bool) -> Self {
1005 Self { name: name.into(), sample_type, quantize_linearly, sampling: Vec2(1, 1) }
1006 }
1007
1008 pub fn subsampled_pixels(&self, dimensions: Vec2<usize>) -> usize {
1011 self.subsampled_resolution(dimensions).area()
1012 }
1013
1014 pub fn subsampled_resolution(&self, dimensions: Vec2<usize>) -> Vec2<usize> {
1016 dimensions / self.sampling
1017 }
1018
1019 pub fn byte_size(&self) -> usize {
1021 self.name.null_terminated_byte_size()
1022 + SampleType::byte_size()
1023 + 1 + 3 + 2 * u32::BYTE_SIZE }
1027
1028 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1030 Text::write_null_terminated(&self.name, write)?;
1031 self.sample_type.write(write)?;
1032
1033 match self.quantize_linearly {
1034 false => 0_u8,
1035 true => 1_u8,
1036 }.write(write)?;
1037
1038 i8::write_slice(write, &[0_i8, 0_i8, 0_i8])?;
1039 i32::write(usize_to_i32(self.sampling.x()), write)?;
1040 i32::write(usize_to_i32(self.sampling.y()), write)?;
1041 Ok(())
1042 }
1043
1044 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1046 let name = Text::read_null_terminated(read, 256)?;
1047 let sample_type = SampleType::read(read)?;
1048
1049 let is_linear = match u8::read(read)? {
1050 1 => true,
1051 0 => false,
1052 _ => return Err(Error::invalid("channel linearity attribute value")),
1053 };
1054
1055 let mut reserved = [0_i8; 3];
1056 i8::read_slice(read, &mut reserved)?;
1057
1058 let x_sampling = i32_to_usize(i32::read(read)?, "x channel sampling")?;
1059 let y_sampling = i32_to_usize(i32::read(read)?, "y channel sampling")?;
1060
1061 Ok(ChannelDescription {
1062 name, sample_type,
1063 quantize_linearly: is_linear,
1064 sampling: Vec2(x_sampling, y_sampling),
1065 })
1066 }
1067
1068 pub fn validate(&self, allow_sampling: bool, data_window: IntegerBounds, strict: bool) -> UnitResult {
1070 self.name.validate(true, None)?; if self.sampling.x() == 0 || self.sampling.y() == 0 {
1073 return Err(Error::invalid("zero sampling factor"));
1074 }
1075
1076 if strict && !allow_sampling && self.sampling != Vec2(1,1) {
1077 return Err(Error::invalid("subsampling is only allowed in flat scan line images"));
1078 }
1079
1080 if data_window.position.x() % self.sampling.x() as i32 != 0 || data_window.position.y() % self.sampling.y() as i32 != 0 {
1081 return Err(Error::invalid("channel sampling factor not dividing data window position"));
1082 }
1083
1084 if data_window.size.x() % self.sampling.x() != 0 || data_window.size.y() % self.sampling.y() != 0 {
1085 return Err(Error::invalid("channel sampling factor not dividing data window size"));
1086 }
1087
1088 if self.sampling != Vec2(1,1) {
1089 return Err(Error::unsupported("channel subsampling not supported yet"));
1093 }
1094
1095 Ok(())
1096 }
1097}
1098
1099impl ChannelList {
1100
1101 pub fn byte_size(&self) -> usize {
1103 self.list.iter().map(ChannelDescription::byte_size).sum::<usize>() + sequence_end::byte_size()
1104 }
1105
1106 pub fn write(&self, write: &mut impl Write) -> UnitResult {
1109 for channel in &self.list {
1110 channel.write(write)?;
1111 }
1112
1113 sequence_end::write(write)?;
1114 Ok(())
1115 }
1116
1117 pub fn read(read: &mut PeekRead<impl Read>) -> Result<Self> {
1119 let mut channels = SmallVec::new();
1120 while !sequence_end::has_come(read)? {
1121 channels.push(ChannelDescription::read(read)?);
1122 }
1123
1124 Ok(ChannelList::new(channels))
1125 }
1126
1127 pub fn validate(&self, allow_sampling: bool, data_window: IntegerBounds, strict: bool) -> UnitResult {
1129 let mut iter = self.list.iter().map(|chan| chan.validate(allow_sampling, data_window, strict).map(|_| &chan.name));
1130 let mut previous = iter.next().ok_or(Error::invalid("at least one channel is required"))??;
1131
1132 for result in iter {
1133 let value = result?;
1134 if strict && previous == value { return Err(Error::invalid("channel names are not unique")); }
1135 else if previous > value { return Err(Error::invalid("channel names are not sorted alphabetically")); }
1136 else { previous = value; }
1137 }
1138
1139 Ok(())
1140 }
1141}
1142
1143fn u8_to_decimal32(binary: u8) -> u32 {
1144 let units = binary as u32 % 10;
1145 let tens = (binary as u32 / 10) % 10;
1146 units | (tens << 4)
1147}
1148
1149fn u8_from_decimal32(coded: u32) -> u8 {
1151 ((coded & 0x0f) + 10 * ((coded >> 4) & 0x0f)) as u8
1152}
1153
1154impl TimeCode {
1156
1157 pub const BYTE_SIZE: usize = 2 * u32::BYTE_SIZE;
1159
1160 pub fn validate(&self, strict: bool) -> UnitResult {
1162 if strict {
1163 if self.frame > 29 { Err(Error::invalid("time code frame larger than 29")) }
1164 else if self.seconds > 59 { Err(Error::invalid("time code seconds larger than 59")) }
1165 else if self.minutes > 59 { Err(Error::invalid("time code minutes larger than 59")) }
1166 else if self.hours > 23 { Err(Error::invalid("time code hours larger than 23")) }
1167 else if self.binary_groups.iter().any(|&group| group > 15) {
1168 Err(Error::invalid("time code binary group value too large for 3 bits"))
1169 }
1170 else { Ok(()) }
1171 }
1172 else { Ok(()) }
1173 }
1174
1175
1176 pub fn pack_time_as_tv60_u32(&self) -> Result<u32> {
1179 self.validate(true)?;
1181
1182 Ok(*0_u32
1183 .set_bits(0..6, u8_to_decimal32(self.frame))
1184 .set_bit(6, self.drop_frame)
1185 .set_bit(7, self.color_frame)
1186 .set_bits(8..15, u8_to_decimal32(self.seconds))
1187 .set_bit(15, self.field_phase)
1188 .set_bits(16..23, u8_to_decimal32(self.minutes))
1189 .set_bit(23, self.binary_group_flags[0])
1190 .set_bits(24..30, u8_to_decimal32(self.hours))
1191 .set_bit(30, self.binary_group_flags[1])
1192 .set_bit(31, self.binary_group_flags[2])
1193 )
1194 }
1195
1196 pub fn from_tv60_time(tv60_time: u32, user_data: u32) -> Self {
1199 Self {
1200 frame: u8_from_decimal32(tv60_time.get_bits(0..6)), drop_frame: tv60_time.get_bit(6),
1202 color_frame: tv60_time.get_bit(7),
1203 seconds: u8_from_decimal32(tv60_time.get_bits(8..15)), field_phase: tv60_time.get_bit(15),
1205 minutes: u8_from_decimal32(tv60_time.get_bits(16..23)), hours: u8_from_decimal32(tv60_time.get_bits(24..30)), binary_group_flags: [
1208 tv60_time.get_bit(23),
1209 tv60_time.get_bit(30),
1210 tv60_time.get_bit(31),
1211 ],
1212
1213 binary_groups: Self::unpack_user_data_from_u32(user_data)
1214 }
1215 }
1216
1217 pub fn pack_time_as_tv50_u32(&self) -> Result<u32> {
1220 Ok(*self.pack_time_as_tv60_u32()?
1221
1222 .set_bit(6, false)
1224 .set_bit(15, self.binary_group_flags[0])
1225 .set_bit(30, self.binary_group_flags[1])
1226 .set_bit(23, self.binary_group_flags[2])
1227 .set_bit(31, self.field_phase)
1228 )
1229 }
1230
1231 pub fn from_tv50_time(tv50_time: u32, user_data: u32) -> Self {
1234 Self {
1235 drop_frame: false, field_phase: tv50_time.get_bit(31),
1239 binary_group_flags: [
1240 tv50_time.get_bit(15),
1241 tv50_time.get_bit(30),
1242 tv50_time.get_bit(23),
1243 ],
1244
1245 .. Self::from_tv60_time(tv50_time, user_data)
1246 }
1247 }
1248
1249
1250 pub fn pack_time_as_film24_u32(&self) -> Result<u32> {
1253 Ok(*self.pack_time_as_tv60_u32()?
1254 .set_bit(6, false)
1255 .set_bit(7, false)
1256 )
1257 }
1258
1259 pub fn from_film24_time(film24_time: u32, user_data: u32) -> Self {
1262 Self {
1263 drop_frame: false, color_frame: false, .. Self::from_tv60_time(film24_time, user_data)
1266 }
1267 }
1268
1269
1270 fn user_data_bit_indices(group_index: usize) -> std::ops::Range<usize> {
1272 let min_bit = 4 * group_index;
1273 min_bit .. min_bit + 4 }
1275
1276 pub fn pack_user_data_as_u32(&self) -> u32 {
1279 let packed = self.binary_groups.iter().enumerate().fold(0_u32, |mut packed, (group_index, group_value)|
1280 *packed.set_bits(Self::user_data_bit_indices(group_index), *group_value.min(&15) as u32)
1281 );
1282
1283 debug_assert_eq!(Self::unpack_user_data_from_u32(packed), self.binary_groups, "round trip user data encoding");
1284 packed
1285 }
1286
1287 fn unpack_user_data_from_u32(user_data: u32) -> [u8; 8] {
1289 (0..8).map(|group_index| user_data.get_bits(Self::user_data_bit_indices(group_index)) as u8)
1290 .collect::<SmallVec<[u8;8]>>().into_inner().expect("array index bug")
1291 }
1292
1293
1294 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1297 self.pack_time_as_tv60_u32()?.write(write)?; self.pack_user_data_as_u32().write(write)?;
1299 Ok(())
1300 }
1301
1302 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1304 let time_and_flags = u32::read(read)?;
1305 let user_data = u32::read(read)?;
1306 Ok(Self::from_tv60_time(time_and_flags, user_data))
1307 }
1308}
1309
1310impl Chromaticities {
1311
1312 pub fn byte_size() -> usize {
1314 8 * f32::BYTE_SIZE
1315 }
1316
1317 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1319 self.red.x().write(write)?;
1320 self.red.y().write(write)?;
1321
1322 self.green.x().write(write)?;
1323 self.green.y().write(write)?;
1324
1325 self.blue.x().write(write)?;
1326 self.blue.y().write(write)?;
1327
1328 self.white.x().write(write)?;
1329 self.white.y().write(write)?;
1330 Ok(())
1331 }
1332
1333 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1335 Ok(Chromaticities {
1336 red: Vec2(f32::read(read)?, f32::read(read)?),
1337 green: Vec2(f32::read(read)?, f32::read(read)?),
1338 blue: Vec2(f32::read(read)?, f32::read(read)?),
1339 white: Vec2(f32::read(read)?, f32::read(read)?),
1340 })
1341 }
1342}
1343
1344impl Compression {
1345
1346 pub fn byte_size() -> usize { u8::BYTE_SIZE }
1348
1349 pub fn write<W: Write>(self, write: &mut W) -> UnitResult {
1351 use self::Compression::*;
1352 match self {
1353 Uncompressed => 0_u8,
1354 RLE => 1_u8,
1355 ZIP1 => 2_u8,
1356 ZIP16 => 3_u8,
1357 PIZ => 4_u8,
1358 PXR24 => 5_u8,
1359 B44 => 6_u8,
1360 B44A => 7_u8,
1361 DWAA(_) => 8_u8,
1362 DWAB(_) => 9_u8,
1363 }.write(write)?;
1364 Ok(())
1365 }
1366
1367 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1369 use self::Compression::*;
1370 Ok(match u8::read(read)? {
1371 0 => Uncompressed,
1372 1 => RLE,
1373 2 => ZIP1,
1374 3 => ZIP16,
1375 4 => PIZ,
1376 5 => PXR24,
1377 6 => B44,
1378 7 => B44A,
1379 8 => DWAA(None),
1380 9 => DWAB(None),
1381 _ => return Err(Error::unsupported("unknown compression method")),
1382 })
1383 }
1384}
1385
1386impl EnvironmentMap {
1387
1388 pub fn byte_size() -> usize {
1390 u8::BYTE_SIZE
1391 }
1392
1393 pub fn write<W: Write>(self, write: &mut W) -> UnitResult {
1395 use self::EnvironmentMap::*;
1396 match self {
1397 LatitudeLongitude => 0_u8,
1398 Cube => 1_u8
1399 }.write(write)?;
1400
1401 Ok(())
1402 }
1403
1404 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1406 use self::EnvironmentMap::*;
1407 Ok(match u8::read(read)? {
1408 0 => LatitudeLongitude,
1409 1 => Cube,
1410 _ => return Err(Error::invalid("environment map attribute value")),
1411 })
1412 }
1413}
1414
1415impl KeyCode {
1416
1417 pub fn byte_size() -> usize {
1419 6 * i32::BYTE_SIZE
1420 }
1421
1422 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1424 self.film_manufacturer_code.write(write)?;
1425 self.film_type.write(write)?;
1426 self.film_roll_prefix.write(write)?;
1427 self.count.write(write)?;
1428 self.perforation_offset.write(write)?;
1429 self.perforations_per_count.write(write)?;
1430 Ok(())
1431 }
1432
1433 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1435 Ok(KeyCode {
1436 film_manufacturer_code: i32::read(read)?,
1437 film_type: i32::read(read)?,
1438 film_roll_prefix: i32::read(read)?,
1439 count: i32::read(read)?,
1440 perforation_offset: i32::read(read)?,
1441 perforations_per_frame: i32::read(read)?,
1442 perforations_per_count: i32::read(read)?,
1443 })
1444 }
1445}
1446
1447impl LineOrder {
1448
1449 pub fn byte_size() -> usize {
1451 u8::BYTE_SIZE
1452 }
1453
1454 pub fn write<W: Write>(self, write: &mut W) -> UnitResult {
1456 use self::LineOrder::*;
1457 match self {
1458 Increasing => 0_u8,
1459 Decreasing => 1_u8,
1460 Unspecified => 2_u8,
1461 }.write(write)?;
1462
1463 Ok(())
1464 }
1465
1466 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1468 use self::LineOrder::*;
1469 Ok(match u8::read(read)? {
1470 0 => Increasing,
1471 1 => Decreasing,
1472 2 => Unspecified,
1473 _ => return Err(Error::invalid("line order attribute value")),
1474 })
1475 }
1476}
1477
1478
1479
1480
1481impl Preview {
1482
1483 pub fn byte_size(&self) -> usize {
1485 2 * u32::BYTE_SIZE + self.pixel_data.len()
1486 }
1487
1488 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1490 u32::write(self.size.width() as u32, write)?;
1491 u32::write(self.size.height() as u32, write)?;
1492
1493 i8::write_slice(write, &self.pixel_data)?;
1494 Ok(())
1495 }
1496
1497 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1499 let width = u32::read(read)? as usize;
1500 let height = u32::read(read)? as usize;
1501
1502 if let Some(pixel_count) = width.checked_mul(height) {
1503 if let Some(byte_count) = pixel_count.checked_mul(4) {
1505 let pixel_data = i8::read_vec(
1506 read,
1507 byte_count,
1508 1024 * 1024 * 4,
1509 None,
1510 "preview attribute pixel count",
1511 )?;
1512
1513 let preview = Preview {
1514 size: Vec2(width, height),
1515 pixel_data,
1516 };
1517
1518 return Ok(preview);
1519 }
1520 }
1521
1522 return Err(Error::invalid(
1523 format!("Overflow while calculating preview image Attribute size \
1524 (width: {}, height: {}).",
1525 width,
1526 height)));
1527 }
1528
1529 pub fn validate(&self, strict: bool) -> UnitResult {
1531 if strict && (self.size.area() * 4 != self.pixel_data.len()) {
1532 return Err(Error::invalid("preview dimensions do not match content length"))
1533 }
1534
1535 Ok(())
1536 }
1537}
1538
1539impl ::std::fmt::Debug for Preview {
1540 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
1541 write!(f, "Preview ({}x{} px)", self.size.width(), self.size.height())
1542 }
1543}
1544
1545impl TileDescription {
1546
1547 pub fn byte_size() -> usize {
1549 2 * u32::BYTE_SIZE + 1 }
1551
1552 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1554 u32::write(self.tile_size.width() as u32, write)?;
1555 u32::write(self.tile_size.height() as u32, write)?;
1556
1557 let level_mode = match self.level_mode {
1558 LevelMode::Singular => 0_u8,
1559 LevelMode::MipMap => 1_u8,
1560 LevelMode::RipMap => 2_u8,
1561 };
1562
1563 let rounding_mode = match self.rounding_mode {
1564 RoundingMode::Down => 0_u8,
1565 RoundingMode::Up => 1_u8,
1566 };
1567
1568 let mode: u8 = level_mode + (rounding_mode * 16);
1569 mode.write(write)?;
1570 Ok(())
1571 }
1572
1573 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1575 let x_size = u32::read(read)? as usize;
1576 let y_size = u32::read(read)? as usize;
1577
1578 let mode = u8::read(read)?;
1579
1580 let level_mode = mode & 0b00001111; let rounding_mode = mode >> 4; let level_mode = match level_mode {
1586 0 => LevelMode::Singular,
1587 1 => LevelMode::MipMap,
1588 2 => LevelMode::RipMap,
1589 _ => return Err(Error::invalid("tile description level mode")),
1590 };
1591
1592 let rounding_mode = match rounding_mode {
1593 0 => RoundingMode::Down,
1594 1 => RoundingMode::Up,
1595 _ => return Err(Error::invalid("tile description rounding mode")),
1596 };
1597
1598 Ok(TileDescription { tile_size: Vec2(x_size, y_size), level_mode, rounding_mode, })
1599 }
1600
1601 pub fn validate(&self) -> UnitResult {
1603 let max = i32::MAX as i64 / 2;
1604
1605 if self.tile_size.width() == 0 || self.tile_size.height() == 0
1606 || self.tile_size.width() as i64 >= max || self.tile_size.height() as i64 >= max
1607 {
1608 return Err(Error::invalid("tile size"))
1609 }
1610
1611 Ok(())
1612 }
1613}
1614
1615
1616pub fn byte_size(name: &Text, value: &AttributeValue) -> usize {
1619 name.null_terminated_byte_size()
1620 + value.kind_name().len() + sequence_end::byte_size()
1621 + i32::BYTE_SIZE + value.byte_size()
1623}
1624
1625pub fn write<W: Write>(name: &TextSlice, value: &AttributeValue, write: &mut W) -> UnitResult {
1627 Text::write_null_terminated_bytes(name, write)?;
1628 Text::write_null_terminated_bytes(value.kind_name(), write)?;
1629 i32::write(value.byte_size() as i32, write)?;
1630 value.write(write)
1631}
1632
1633pub fn read(read: &mut PeekRead<impl Read>, max_size: usize) -> Result<(Text, Result<AttributeValue>)> {
1635 let name = Text::read_null_terminated(read, max_size)?;
1636 let kind = Text::read_null_terminated(read, max_size)?;
1637 let size = i32_to_usize(i32::read(read)?, "attribute size")?;
1638 let value = AttributeValue::read(read, kind, size)?;
1639 Ok((name, value))
1640}
1641
1642pub fn validate(name: &Text, value: &AttributeValue, long_names: &mut bool, allow_sampling: bool, data_window: IntegerBounds, strict: bool) -> UnitResult {
1644 name.validate(true, Some(long_names))?; value.validate(allow_sampling, data_window, strict) }
1647
1648
1649impl AttributeValue {
1650
1651 pub fn byte_size(&self) -> usize {
1653 use self::AttributeValue::*;
1654
1655 match *self {
1656 IntegerBounds(_) => self::IntegerBounds::byte_size(),
1657 FloatRect(_) => self::FloatRect::byte_size(),
1658
1659 I32(_) => i32::BYTE_SIZE,
1660 F32(_) => f32::BYTE_SIZE,
1661 F64(_) => f64::BYTE_SIZE,
1662
1663 Rational(_) => { i32::BYTE_SIZE + u32::BYTE_SIZE },
1664 TimeCode(_) => self::TimeCode::BYTE_SIZE,
1665
1666 IntVec2(_) => { 2 * i32::BYTE_SIZE },
1667 FloatVec2(_) => { 2 * f32::BYTE_SIZE },
1668 IntVec3(_) => { 3 * i32::BYTE_SIZE },
1669 FloatVec3(_) => { 3 * f32::BYTE_SIZE },
1670
1671 ChannelList(ref channels) => channels.byte_size(),
1672 Chromaticities(_) => self::Chromaticities::byte_size(),
1673 Compression(_) => self::Compression::byte_size(),
1674 EnvironmentMap(_) => self::EnvironmentMap::byte_size(),
1675
1676 KeyCode(_) => self::KeyCode::byte_size(),
1677 LineOrder(_) => self::LineOrder::byte_size(),
1678
1679 Matrix3x3(ref value) => value.len() * f32::BYTE_SIZE,
1680 Matrix4x4(ref value) => value.len() * f32::BYTE_SIZE,
1681
1682 Preview(ref value) => value.byte_size(),
1683
1684 Text(ref value) => value.bytes.len(),
1687
1688 TextVector(ref value) => value.iter().map(self::Text::i32_sized_byte_size).sum(),
1689 TileDescription(_) => self::TileDescription::byte_size(),
1690 Custom { ref bytes, .. } => bytes.len(),
1691 BlockType(ref kind) => kind.byte_size()
1692 }
1693 }
1694
1695 pub fn kind_name(&self) -> &TextSlice {
1697 use self::AttributeValue::*;
1698 use self::type_names as ty;
1699
1700 match *self {
1701 IntegerBounds(_) => ty::I32BOX2,
1702 FloatRect(_) => ty::F32BOX2,
1703 I32(_) => ty::I32,
1704 F32(_) => ty::F32,
1705 F64(_) => ty::F64,
1706 Rational(_) => ty::RATIONAL,
1707 TimeCode(_) => ty::TIME_CODE,
1708 IntVec2(_) => ty::I32VEC2,
1709 FloatVec2(_) => ty::F32VEC2,
1710 IntVec3(_) => ty::I32VEC3,
1711 FloatVec3(_) => ty::F32VEC3,
1712 ChannelList(_) => ty::CHANNEL_LIST,
1713 Chromaticities(_) => ty::CHROMATICITIES,
1714 Compression(_) => ty::COMPRESSION,
1715 EnvironmentMap(_) => ty::ENVIRONMENT_MAP,
1716 KeyCode(_) => ty::KEY_CODE,
1717 LineOrder(_) => ty::LINE_ORDER,
1718 Matrix3x3(_) => ty::F32MATRIX3X3,
1719 Matrix4x4(_) => ty::F32MATRIX4X4,
1720 Preview(_) => ty::PREVIEW,
1721 Text(_) => ty::TEXT,
1722 TextVector(_) => ty::TEXT_VECTOR,
1723 TileDescription(_) => ty::TILES,
1724 BlockType(_) => super::BlockType::TYPE_NAME,
1725 Custom { ref kind, .. } => kind.as_slice(),
1726 }
1727 }
1728
1729 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1731 use self::AttributeValue::*;
1732 match *self {
1733 IntegerBounds(value) => value.write(write)?,
1734 FloatRect(value) => value.write(write)?,
1735
1736 I32(value) => value.write(write)?,
1737 F32(value) => value.write(write)?,
1738 F64(value) => value.write(write)?,
1739
1740 Rational((a, b)) => { a.write(write)?; b.write(write)?; },
1741 TimeCode(codes) => { codes.write(write)?; },
1742
1743 IntVec2(Vec2(x, y)) => { x.write(write)?; y.write(write)?; },
1744 FloatVec2(Vec2(x, y)) => { x.write(write)?; y.write(write)?; },
1745 IntVec3((x, y, z)) => { x.write(write)?; y.write(write)?; z.write(write)?; },
1746 FloatVec3((x, y, z)) => { x.write(write)?; y.write(write)?; z.write(write)?; },
1747
1748 ChannelList(ref channels) => channels.write(write)?,
1749 Chromaticities(ref value) => value.write(write)?,
1750 Compression(value) => value.write(write)?,
1751 EnvironmentMap(value) => value.write(write)?,
1752
1753 KeyCode(value) => value.write(write)?,
1754 LineOrder(value) => value.write(write)?,
1755
1756 Matrix3x3(mut value) => f32::write_slice(write, &mut value)?,
1757 Matrix4x4(mut value) => f32::write_slice(write, &mut value)?,
1758
1759 Preview(ref value) => { value.write(write)?; },
1760
1761 Text(ref value) => u8::write_slice(write, value.bytes.as_slice())?,
1764
1765 TextVector(ref value) => self::Text::write_vec_of_i32_sized_texts(write, value)?,
1766 TileDescription(ref value) => value.write(write)?,
1767 Custom { ref bytes, .. } => u8::write_slice(write, &bytes)?, BlockType(kind) => kind.write(write)?
1769 };
1770
1771 Ok(())
1772 }
1773
1774 pub fn read(read: &mut PeekRead<impl Read>, kind: Text, byte_size: usize) -> Result<Result<Self>> {
1779 use self::AttributeValue::*;
1780 use self::type_names as ty;
1781
1782 let attribute_bytes = u8::read_vec(read, byte_size, 128, None, "attribute value size")?;
1784 let parse_attribute = move || {
1787 let reader = &mut attribute_bytes.as_slice();
1788
1789 Ok(match kind.bytes.as_slice() {
1790 ty::I32BOX2 => IntegerBounds(self::IntegerBounds::read(reader)?),
1791 ty::F32BOX2 => FloatRect(self::FloatRect::read(reader)?),
1792
1793 ty::I32 => I32(i32::read(reader)?),
1794 ty::F32 => F32(f32::read(reader)?),
1795 ty::F64 => F64(f64::read(reader)?),
1796
1797 ty::RATIONAL => Rational({
1798 let a = i32::read(reader)?;
1799 let b = u32::read(reader)?;
1800 (a, b)
1801 }),
1802
1803 ty::TIME_CODE => TimeCode(self::TimeCode::read(reader)?),
1804
1805 ty::I32VEC2 => IntVec2({
1806 let a = i32::read(reader)?;
1807 let b = i32::read(reader)?;
1808 Vec2(a, b)
1809 }),
1810
1811 ty::F32VEC2 => FloatVec2({
1812 let a = f32::read(reader)?;
1813 let b = f32::read(reader)?;
1814 Vec2(a, b)
1815 }),
1816
1817 ty::I32VEC3 => IntVec3({
1818 let a = i32::read(reader)?;
1819 let b = i32::read(reader)?;
1820 let c = i32::read(reader)?;
1821 (a, b, c)
1822 }),
1823
1824 ty::F32VEC3 => FloatVec3({
1825 let a = f32::read(reader)?;
1826 let b = f32::read(reader)?;
1827 let c = f32::read(reader)?;
1828 (a, b, c)
1829 }),
1830
1831 ty::CHANNEL_LIST => ChannelList(self::ChannelList::read(&mut PeekRead::new(attribute_bytes.as_slice()))?),
1832 ty::CHROMATICITIES => Chromaticities(self::Chromaticities::read(reader)?),
1833 ty::COMPRESSION => Compression(self::Compression::read(reader)?),
1834 ty::ENVIRONMENT_MAP => EnvironmentMap(self::EnvironmentMap::read(reader)?),
1835
1836 ty::KEY_CODE => KeyCode(self::KeyCode::read(reader)?),
1837 ty::LINE_ORDER => LineOrder(self::LineOrder::read(reader)?),
1838
1839 ty::F32MATRIX3X3 => Matrix3x3({
1840 let mut result = [0.0_f32; 9];
1841 f32::read_slice(reader, &mut result)?;
1842 result
1843 }),
1844
1845 ty::F32MATRIX4X4 => Matrix4x4({
1846 let mut result = [0.0_f32; 16];
1847 f32::read_slice(reader, &mut result)?;
1848 result
1849 }),
1850
1851 ty::PREVIEW => Preview(self::Preview::read(reader)?),
1852 ty::TEXT => Text(self::Text::read_sized(reader, byte_size)?),
1853
1854 ty::TEXT_VECTOR => TextVector(self::Text::read_vec_of_i32_sized(
1856 &mut PeekRead::new(attribute_bytes.as_slice()),
1857 byte_size
1858 )?),
1859
1860 ty::TILES => TileDescription(self::TileDescription::read(reader)?),
1861
1862 _ => Custom { kind: kind.clone(), bytes: attribute_bytes.clone() } })
1864 };
1865
1866 Ok(parse_attribute())
1867 }
1868
1869 pub fn validate(&self, allow_sampling: bool, data_window: IntegerBounds, strict: bool) -> UnitResult {
1871 use self::AttributeValue::*;
1872
1873 match *self {
1874 ChannelList(ref channels) => channels.validate(allow_sampling, data_window, strict)?,
1875 TileDescription(ref value) => value.validate()?,
1876 Preview(ref value) => value.validate(strict)?,
1877 TimeCode(ref time_code) => time_code.validate(strict)?,
1878
1879 TextVector(ref vec) => if strict && vec.is_empty() {
1880 return Err(Error::invalid("text vector may not be empty"))
1881 },
1882
1883 _ => {}
1884 };
1885
1886 Ok(())
1887 }
1888
1889
1890 pub fn to_i32(&self) -> Result<i32> {
1892 match *self {
1893 AttributeValue::I32(value) => Ok(value),
1894 _ => Err(invalid_type())
1895 }
1896 }
1897
1898 pub fn to_f32(&self) -> Result<f32> {
1900 match *self {
1901 AttributeValue::F32(value) => Ok(value),
1902 _ => Err(invalid_type())
1903 }
1904 }
1905
1906 pub fn into_text(self) -> Result<Text> {
1908 match self {
1909 AttributeValue::Text(value) => Ok(value),
1910 _ => Err(invalid_type())
1911 }
1912 }
1913
1914 pub fn to_text(&self) -> Result<&Text> {
1916 match self {
1917 AttributeValue::Text(value) => Ok(value),
1918 _ => Err(invalid_type())
1919 }
1920 }
1921
1922 pub fn to_chromaticities(&self) -> Result<Chromaticities> {
1924 match *self {
1925 AttributeValue::Chromaticities(value) => Ok(value),
1926 _ => Err(invalid_type())
1927 }
1928 }
1929
1930 pub fn to_time_code(&self) -> Result<TimeCode> {
1932 match *self {
1933 AttributeValue::TimeCode(value) => Ok(value),
1934 _ => Err(invalid_type())
1935 }
1936 }
1937}
1938
1939
1940
1941pub mod type_names {
1943 macro_rules! define_attribute_type_names {
1944 ( $($name: ident : $value: expr),* ) => {
1945 $(
1946 pub const $name: &'static [u8] = $value;
1948 )*
1949 };
1950 }
1951
1952 define_attribute_type_names! {
1953 I32BOX2: b"box2i",
1954 F32BOX2: b"box2f",
1955 I32: b"int",
1956 F32: b"float",
1957 F64: b"double",
1958 RATIONAL: b"rational",
1959 TIME_CODE: b"timecode",
1960 I32VEC2: b"v2i",
1961 F32VEC2: b"v2f",
1962 I32VEC3: b"v3i",
1963 F32VEC3: b"v3f",
1964 CHANNEL_LIST: b"chlist",
1965 CHROMATICITIES: b"chromaticities",
1966 COMPRESSION: b"compression",
1967 ENVIRONMENT_MAP:b"envmap",
1968 KEY_CODE: b"keycode",
1969 LINE_ORDER: b"lineOrder",
1970 F32MATRIX3X3: b"m33f",
1971 F32MATRIX4X4: b"m44f",
1972 PREVIEW: b"preview",
1973 TEXT: b"string",
1974 TEXT_VECTOR: b"stringvector",
1975 TILES: b"tiledesc"
1976 }
1977}
1978
1979
1980#[cfg(test)]
1981mod test {
1982 use super::*;
1983 use ::std::io::Cursor;
1984 use rand::{random, thread_rng, Rng};
1985
1986 #[test]
1987 fn text_ord() {
1988 for _ in 0..1024 {
1989 let text1 = Text::from_bytes_unchecked((0..4).map(|_| rand::random::<u8>()).collect());
1990 let text2 = Text::from_bytes_unchecked((0..4).map(|_| rand::random::<u8>()).collect());
1991
1992 assert_eq!(text1.to_string().cmp(&text2.to_string()), text1.cmp(&text2), "in text {:?} vs {:?}", text1, text2);
1993 }
1994 }
1995
1996 #[test]
1997 fn rounding_up(){
1998 let round_up = RoundingMode::Up;
1999 assert_eq!(round_up.divide(10, 10), 1, "divide equal");
2000 assert_eq!(round_up.divide(10, 2), 5, "divide even");
2001 assert_eq!(round_up.divide(10, 5), 2, "divide even");
2002
2003 assert_eq!(round_up.divide(8, 5), 2, "round up");
2004 assert_eq!(round_up.divide(10, 3), 4, "round up");
2005 assert_eq!(round_up.divide(100, 50), 2, "divide even");
2006 assert_eq!(round_up.divide(100, 49), 3, "round up");
2007 }
2008
2009 #[test]
2010 fn rounding_down(){
2011 let round_down = RoundingMode::Down;
2012 assert_eq!(round_down.divide(8, 5), 1, "round down");
2013 assert_eq!(round_down.divide(10, 3), 3, "round down");
2014 assert_eq!(round_down.divide(100, 50), 2, "divide even");
2015 assert_eq!(round_down.divide(100, 49), 2, "round down");
2016 assert_eq!(round_down.divide(100, 51), 1, "round down");
2017 }
2018
2019 #[test]
2020 fn tile_description_write_read_roundtrip(){
2021 let tiles = [
2022 TileDescription {
2023 tile_size: Vec2(31, 7),
2024 level_mode: LevelMode::MipMap,
2025 rounding_mode: RoundingMode::Down,
2026 },
2027
2028 TileDescription {
2029 tile_size: Vec2(0, 0),
2030 level_mode: LevelMode::Singular,
2031 rounding_mode: RoundingMode::Up,
2032 },
2033
2034 TileDescription {
2035 tile_size: Vec2(4294967294, 4294967295),
2036 level_mode: LevelMode::RipMap,
2037 rounding_mode: RoundingMode::Down,
2038 },
2039 ];
2040
2041 for tile in &tiles {
2042 let mut bytes = Vec::new();
2043 tile.write(&mut bytes).unwrap();
2044
2045 let new_tile = TileDescription::read(&mut Cursor::new(bytes)).unwrap();
2046 assert_eq!(*tile, new_tile, "tile round trip");
2047 }
2048 }
2049
2050 #[test]
2051 fn attribute_write_read_roundtrip_and_byte_size(){
2052 let attributes = [
2053 (
2054 Text::from("greeting"),
2055 AttributeValue::Text(Text::from("hello")),
2056 ),
2057 (
2058 Text::from("age"),
2059 AttributeValue::I32(923),
2060 ),
2061 (
2062 Text::from("leg count"),
2063 AttributeValue::F64(9.114939599234),
2064 ),
2065 (
2066 Text::from("rabbit area"),
2067 AttributeValue::FloatRect(FloatRect {
2068 min: Vec2(23.4234, 345.23),
2069 max: Vec2(68623.0, 3.12425926538),
2070 }),
2071 ),
2072 (
2073 Text::from("rabbit area int"),
2074 AttributeValue::IntegerBounds(IntegerBounds {
2075 position: Vec2(23, 345),
2076 size: Vec2(68623, 3),
2077 }),
2078 ),
2079 (
2080 Text::from("rabbit area int"),
2081 AttributeValue::IntegerBounds(IntegerBounds {
2082 position: Vec2(-(i32::MAX / 2 - 1), -(i32::MAX / 2 - 1)),
2083 size: Vec2(i32::MAX as usize - 2, i32::MAX as usize - 2),
2084 }),
2085 ),
2086 (
2087 Text::from("rabbit area int 2"),
2088 AttributeValue::IntegerBounds(IntegerBounds {
2089 position: Vec2(0, 0),
2090 size: Vec2(i32::MAX as usize / 2 - 1, i32::MAX as usize / 2 - 1),
2091 }),
2092 ),
2093 (
2094 Text::from("tests are difficult"),
2095 AttributeValue::TextVector(vec![
2096 Text::from("sdoifjpsdv"),
2097 Text::from("sdoifjpsdvxxxx"),
2098 Text::from("sdoifjasd"),
2099 Text::from("sdoifj"),
2100 Text::from("sdoifjddddddddasdasd"),
2101 ]),
2102 ),
2103 (
2104 Text::from("what should we eat tonight"),
2105 AttributeValue::Preview(Preview {
2106 size: Vec2(10, 30),
2107 pixel_data: vec![31; 10 * 30 * 4],
2108 }),
2109 ),
2110 (
2111 Text::from("leg count, again"),
2112 AttributeValue::ChannelList(ChannelList::new(smallvec![
2113 ChannelDescription {
2114 name: Text::from("Green"),
2115 sample_type: SampleType::F16,
2116 quantize_linearly: false,
2117 sampling: Vec2(1,2)
2118 },
2119 ChannelDescription {
2120 name: Text::from("Red"),
2121 sample_type: SampleType::F32,
2122 quantize_linearly: true,
2123 sampling: Vec2(1,2)
2124 },
2125 ChannelDescription {
2126 name: Text::from("Purple"),
2127 sample_type: SampleType::U32,
2128 quantize_linearly: false,
2129 sampling: Vec2(0,0)
2130 }
2131 ],
2132 )),
2133 ),
2134 ];
2135
2136 for (name, value) in &attributes {
2137 let mut bytes = Vec::new();
2138 super::write(name.as_slice(), value, &mut bytes).unwrap();
2139 assert_eq!(super::byte_size(name, value), bytes.len(), "attribute.byte_size() for {:?}", (name, value));
2140
2141 let new_attribute = super::read(&mut PeekRead::new(Cursor::new(bytes)), 300).unwrap();
2142 assert_eq!((name.clone(), value.clone()), (new_attribute.0, new_attribute.1.unwrap()), "attribute round trip");
2143 }
2144
2145
2146 {
2147 let (name, value) = (
2148 Text::from("asdkaspfokpaosdkfpaokswdpoakpsfokaposdkf"),
2149 AttributeValue::I32(0),
2150 );
2151
2152 let mut long_names = false;
2153 super::validate(&name, &value, &mut long_names, false, IntegerBounds::zero(), false).unwrap();
2154 assert!(long_names);
2155 }
2156
2157 {
2158 let (name, value) = (
2159 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"),
2160 AttributeValue::I32(0),
2161 );
2162
2163 super::validate(&name, &value, &mut false, false, IntegerBounds::zero(), false).expect_err("name length check failed");
2164 }
2165 }
2166
2167 #[test]
2168 fn time_code_pack(){
2169 let mut rng = thread_rng();
2170
2171 let codes = std::iter::repeat_with(|| TimeCode {
2172 hours: rng.gen_range(0 .. 24),
2173 minutes: rng.gen_range(0 .. 60),
2174 seconds: rng.gen_range(0 .. 60),
2175 frame: rng.gen_range(0 .. 29),
2176 drop_frame: random(),
2177 color_frame: random(),
2178 field_phase: random(),
2179 binary_group_flags: [random(),random(),random()],
2180 binary_groups: std::iter::repeat_with(|| rng.gen_range(0 .. 16)).take(8)
2181 .collect::<SmallVec<[u8;8]>>().into_inner().unwrap()
2182 });
2183
2184 for code in codes.take(500) {
2185 code.validate(true).expect("invalid timecode test input");
2186
2187 { let packed_tv60 = code.pack_time_as_tv60_u32().expect("invalid timecode test input");
2189 let packed_user = code.pack_user_data_as_u32();
2190 assert_eq!(TimeCode::from_tv60_time(packed_tv60, packed_user), code);
2191 }
2192
2193 { let mut bytes = Vec::<u8>::new();
2195 code.write(&mut bytes).unwrap();
2196 let decoded = TimeCode::read(&mut bytes.as_slice()).unwrap();
2197 assert_eq!(code, decoded);
2198 }
2199
2200 {
2201 let tv50_code = TimeCode {
2202 drop_frame: false, .. code
2204 };
2205
2206 let packed_tv50 = code.pack_time_as_tv50_u32().expect("invalid timecode test input");
2207 let packed_user = code.pack_user_data_as_u32();
2208 assert_eq!(TimeCode::from_tv50_time(packed_tv50, packed_user), tv50_code);
2209 }
2210
2211 {
2212 let film24_code = TimeCode {
2213 color_frame: false,
2215 drop_frame: false,
2216 .. code
2217 };
2218
2219 let packed_film24 = code.pack_time_as_film24_u32().expect("invalid timecode test input");
2220 let packed_user = code.pack_user_data_as_u32();
2221 assert_eq!(TimeCode::from_film24_time(packed_film24, packed_user), film24_code);
2222 }
2223 }
2224 }
2225
2226}