exr/meta/
attribute.rs

1
2//! Contains all meta data attributes.
3//! Each layer can have any number of [`Attribute`]s, including custom attributes.
4
5use smallvec::SmallVec;
6
7
8/// Contains one of all possible attributes.
9/// Includes a variant for custom attributes.
10#[derive(Debug, Clone, PartialEq)]
11pub enum AttributeValue {
12
13    /// Channel meta data.
14    ChannelList(ChannelList),
15
16    /// Color space definition.
17    Chromaticities(Chromaticities),
18
19    /// Compression method of this layer.
20    Compression(Compression),
21
22    /// This image is an environment map.
23    EnvironmentMap(EnvironmentMap),
24
25    /// Film roll information.
26    KeyCode(KeyCode),
27
28    /// Order of the bocks in the file.
29    LineOrder(LineOrder),
30
31    /// A 3x3 matrix of floats.
32    Matrix3x3(Matrix3x3),
33
34    /// A 4x4 matrix of floats.
35    Matrix4x4(Matrix4x4),
36
37    /// 8-bit rgba Preview of the image.
38    Preview(Preview),
39
40    /// An integer dividend and divisor.
41    Rational(Rational),
42
43    /// Deep or flat and tiled or scan line.
44    BlockType(BlockType),
45
46    /// List of texts.
47    TextVector(Vec<Text>),
48
49    /// How to tile up the image.
50    TileDescription(TileDescription),
51
52    /// Timepoint and more.
53    TimeCode(TimeCode),
54
55    /// A string of byte-chars.
56    Text(Text),
57
58    /// 64-bit float
59    F64(f64),
60
61    /// 32-bit float
62    F32(f32),
63
64    /// 32-bit signed integer
65    I32(i32),
66
67    /// 2D integer rectangle.
68    IntegerBounds(IntegerBounds),
69
70    /// 2D float rectangle.
71    FloatRect(FloatRect),
72
73    /// 2D integer vector.
74    IntVec2(Vec2<i32>),
75
76    /// 2D float vector.
77    FloatVec2(Vec2<f32>),
78
79    /// 3D integer vector.
80    IntVec3((i32, i32, i32)),
81
82    /// 3D float vector.
83    FloatVec3((f32, f32, f32)),
84
85    /// An explicitly untyped attribute for binary application data.
86    /// Also contains the type name of this value.
87    /// The format of the byte contents is explicitly unspecified.
88    /// Used for custom application data.
89    Bytes {
90
91        /// An application-specific type hint of the byte contents.
92        type_hint: Text,
93
94        /// The contents of this byte array are completely unspecified
95        /// and should be treated as untrusted data.
96        bytes: SmallVec<[u8; 16]>
97    },
98
99    /// A custom attribute.
100    /// Contains the type name of this value.
101    Custom {
102
103        /// The name of the type this attribute is an instance of.
104        kind: Text,
105
106        /// The value, stored in little-endian byte order, of the value.
107        /// Use the `exr::io::Data` trait to extract binary values from this vector.
108        bytes: SmallVec<[u8; 16]>
109    },
110}
111
112/// A byte array with each byte being a char.
113/// This is not UTF and it must be constructed from a standard string.
114// TODO is this ascii? use a rust ascii crate?
115#[derive(Clone, PartialEq, Ord, PartialOrd, Default)] // hash implemented manually
116pub struct Text {
117    bytes: TextBytes,
118}
119
120/// Contains time information for this frame within a sequence.
121/// Also defined methods to compile this information into a
122/// `TV60`, `TV50` or `Film24` bit sequence, packed into `u32`.
123///
124/// Satisfies the [SMPTE standard 12M-1999](https://en.wikipedia.org/wiki/SMPTE_timecode).
125/// For more in-depth information, see [philrees.co.uk/timecode](http://www.philrees.co.uk/articles/timecode.htm).
126#[derive(Copy, Debug, Clone, Eq, PartialEq, Hash, Default)]
127pub struct TimeCode {
128
129    /// Hours 0 - 23 are valid.
130    pub hours: u8,
131
132    /// Minutes 0 - 59 are valid.
133    pub minutes: u8,
134
135    /// Seconds 0 - 59 are valid.
136    pub seconds: u8,
137
138    /// Frame Indices 0 - 29 are valid.
139    pub frame: u8,
140
141    /// Whether this is a drop frame.
142    pub drop_frame: bool,
143
144    /// Whether this is a color frame.
145    pub color_frame: bool,
146
147    /// Field Phase.
148    pub field_phase: bool,
149
150    /// Flags for `TimeCode.binary_groups`.
151    pub binary_group_flags: [bool; 3],
152
153    /// The user-defined control codes.
154    /// Every entry in this array can use at most 3 bits.
155    /// This results in a maximum value of 15, including 0, for each `u8`.
156    pub binary_groups: [u8; 8]
157}
158
159/// layer type, specifies block type and deepness.
160#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
161pub enum BlockType {
162
163    /// Corresponds to the string value `scanlineimage`.
164    ScanLine,
165
166    /// Corresponds to the string value `tiledimage`.
167    Tile,
168
169    /// Corresponds to the string value `deepscanline`.
170    DeepScanLine,
171
172    /// Corresponds to the string value `deeptile`.
173    DeepTile,
174}
175
176/// The string literals used to represent a `BlockType` in a file.
177pub mod block_type_strings {
178
179    /// Type attribute text value of flat scan lines
180    pub const SCAN_LINE: &'static [u8] = b"scanlineimage";
181
182    /// Type attribute text value of flat tiles
183    pub const TILE: &'static [u8] = b"tiledimage";
184
185    /// Type attribute text value of deep scan lines
186    pub const DEEP_SCAN_LINE: &'static [u8] = b"deepscanline";
187
188    /// Type attribute text value of deep tiles
189    pub const DEEP_TILE: &'static [u8] = b"deeptile";
190}
191
192
193pub use crate::compression::Compression;
194
195/// The integer rectangle describing where an layer is placed on the infinite 2D global space.
196pub type DataWindow = IntegerBounds;
197
198/// The integer rectangle limiting which part of the infinite 2D global space should be displayed.
199pub type DisplayWindow = IntegerBounds;
200
201/// An integer dividend and divisor, together forming a ratio.
202pub type Rational = (i32, u32);
203
204/// A float matrix with four rows and four columns.
205pub type Matrix4x4 = [f32; 4*4];
206
207/// A float matrix with three rows and three columns.
208pub type Matrix3x3 = [f32; 3*3];
209
210/// A rectangular section anywhere in 2D integer space.
211/// Valid from minimum coordinate (including) `-1,073,741,822`
212/// to maximum coordinate (including) `1,073,741,822`, the value of (`i32::MAX/2 -1`).
213#[derive(Clone, Copy, Debug, Eq, PartialEq, Default, Hash)]
214pub struct IntegerBounds {
215
216    /// The top left corner of this rectangle.
217    /// The `Box2I32` includes this pixel if the size is not zero.
218    pub position: Vec2<i32>,
219
220    /// How many pixels to include in this `Box2I32`.
221    /// Extends to the right and downwards.
222    /// Does not include the actual boundary, just like `Vec::len()`.
223    pub size: Vec2<usize>,
224}
225
226/// A rectangular section anywhere in 2D float space.
227#[derive(Clone, Copy, Debug, PartialEq)]
228pub struct FloatRect {
229
230    /// The top left corner location of the rectangle (inclusive)
231    pub min: Vec2<f32>,
232
233    /// The bottom right corner location of the rectangle (inclusive)
234    pub max: Vec2<f32>
235}
236
237/// A List of channels. Channels must be sorted alphabetically.
238#[derive(Clone, Debug, Eq, PartialEq, Hash)]
239pub struct ChannelList {
240
241    /// The channels in this list.
242    pub list: SmallVec<[ChannelDescription; 5]>,
243
244    /// The number of bytes that one pixel in this image needs.
245    // FIXME this needs to account for subsampling anywhere?
246    pub bytes_per_pixel: usize, // FIXME only makes sense for flat images!
247
248    /// The sample type of all channels, if all channels have the same type.
249    pub uniform_sample_type: Option<SampleType>,
250}
251
252/// A single channel in an layer.
253/// Does not contain the actual pixel data,
254/// but instead merely describes it.
255#[derive(Clone, Debug, Eq, PartialEq, Hash)]
256pub struct ChannelDescription {
257
258    /// One of "R", "G", or "B" most of the time.
259    pub name: Text,
260
261    /// U32, F16 or F32.
262    pub sample_type: SampleType,
263
264    /// This attribute only tells lossy compression methods
265    /// whether this value should be quantized exponentially or linearly.
266    ///
267    /// Should be `false` for red, green, or blue channels.
268    /// Should be `true` for hue, chroma, saturation, or alpha channels.
269    pub quantize_linearly: bool,
270
271    /// How many of the samples are skipped compared to the other channels in this layer.
272    ///
273    /// Can be used for chroma subsampling for manual lossy data compression.
274    /// Values other than 1 are allowed only in flat, scan-line based images.
275    /// If an image is deep or tiled, x and y sampling rates for all of its channels must be 1.
276    pub sampling: Vec2<usize>,
277}
278
279/// The type of samples in this channel.
280#[derive(Clone, Debug, Eq, PartialEq, Copy, Hash)]
281pub enum SampleType {
282
283    /// This channel contains 32-bit unsigned int values.
284    U32,
285
286    /// This channel contains 16-bit float values.
287    F16,
288
289    /// This channel contains 32-bit float values.
290    F32,
291}
292
293/// The color space of the pixels.
294///
295/// If a file doesn't have a chromaticities attribute, display software
296/// should assume that the file's primaries and the white point match `Rec. ITU-R BT.709-3`.
297#[derive(Debug, Clone, Copy, PartialEq)]
298pub struct Chromaticities {
299
300    /// "Red" location on the CIE XY chromaticity diagram.
301    pub red: Vec2<f32>,
302
303    /// "Green" location on the CIE XY chromaticity diagram.
304    pub green: Vec2<f32>,
305
306    /// "Blue" location on the CIE XY chromaticity diagram.
307    pub blue: Vec2<f32>,
308
309    /// "White" location on the CIE XY chromaticity diagram.
310    pub white: Vec2<f32>
311}
312
313/// If this attribute is present, it describes
314/// how this texture should be projected onto an environment.
315#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
316pub enum EnvironmentMap {
317
318    /// This image is an environment map projected like a world map.
319    LatitudeLongitude,
320
321    /// This image contains the six sides of a cube.
322    Cube,
323}
324
325/// Uniquely identifies a motion picture film frame.
326#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
327pub struct KeyCode {
328
329    /// Identifies a film manufacturer.
330    pub film_manufacturer_code: i32,
331
332    /// Identifies a film type.
333    pub film_type: i32,
334
335    /// Specifies the film roll prefix.
336    pub film_roll_prefix: i32,
337
338    /// Specifies the film count.
339    pub count: i32,
340
341    /// Specifies the perforation offset.
342    pub perforation_offset: i32,
343
344    /// Specifies the perforation count of each single frame.
345    pub perforations_per_frame: i32,
346
347    /// Specifies the perforation count of each single film.
348    pub perforations_per_count: i32,
349}
350
351/// In what order the `Block`s of pixel data appear in a file.
352#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
353pub enum LineOrder {
354
355    /// The blocks in the file are ordered in descending rows from left to right.
356    /// When compressing in parallel, this option requires potentially large amounts of memory.
357    /// In that case, use `LineOrder::Unspecified` for best performance.
358    Increasing,
359
360    /// The blocks in the file are ordered in ascending rows from right to left.
361    /// When compressing in parallel, this option requires potentially large amounts of memory.
362    /// In that case, use `LineOrder::Unspecified` for best performance.
363    Decreasing,
364
365    /// The blocks are not ordered in a specific way inside the file.
366    /// In multi-core file writing, this option offers the best performance.
367    Unspecified,
368}
369
370/// A small `rgba` image of `i8` values that approximates the real exr image.
371// TODO is this linear?
372#[derive(Clone, Eq, PartialEq)]
373pub struct Preview {
374
375    /// The dimensions of the preview image.
376    pub size: Vec2<usize>,
377
378    /// An array with a length of 4 × width × height.
379    /// The pixels are stored in `LineOrder::Increasing`.
380    /// Each pixel consists of the four `u8` values red, green, blue, alpha.
381    pub pixel_data: Vec<i8>,
382}
383
384/// Describes how the layer is divided into tiles.
385/// Specifies the size of each tile in the image
386/// and whether this image contains multiple resolution levels.
387#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
388pub struct TileDescription {
389
390    /// The size of each tile.
391    /// Stays the same number of pixels across all levels.
392    pub tile_size: Vec2<usize>,
393
394    /// Whether to also store smaller versions of the image.
395    pub level_mode: LevelMode,
396
397    /// Whether to round up or down when calculating Mip/Rip levels.
398    pub rounding_mode: RoundingMode,
399}
400
401/// Whether to also store increasingly smaller versions of the original image.
402#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
403pub enum LevelMode {
404
405    /// Only a single level.
406    Singular,
407
408    /// Levels with a similar aspect ratio.
409    MipMap,
410
411    /// Levels with all possible aspect ratios.
412    RipMap,
413}
414
415
416/// The raw bytes that make up a string in an exr file.
417/// Each `u8` is a single char.
418// will mostly be "R", "G", "B" or "deepscanlineimage"
419pub type TextBytes = SmallVec<[u8; 24]>;
420
421/// A byte slice, interpreted as text
422pub 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    /// Create a `Text` from an `str` reference.
444    /// Returns `None` if this string contains unsupported chars.
445    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    /// Create a `Text` from an `str` reference.
454    /// Panics if this string contains unsupported chars.
455    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    /// Create a `Text` from a slice of bytes,
460    /// without checking any of the bytes.
461    pub fn from_slice_unchecked(text: &TextSlice) -> Self {
462        Self::from_bytes_unchecked(SmallVec::from_slice(text))
463    }
464
465    /// Create a `Text` from the specified bytes object,
466    /// without checking any of the bytes.
467    pub fn from_bytes_unchecked(bytes: TextBytes) -> Self {
468        Text { bytes }
469    }
470
471    /// The internal ASCII bytes this text is made of.
472    pub fn as_slice(&self) -> &TextSlice {
473        self.bytes.as_slice()
474    }
475
476    /// Check whether this string is valid, adjusting `long_names` if required.
477    /// If `long_names` is not provided, text length will be entirely unchecked.
478    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    /// Check whether some bytes are valid, adjusting `long_names` if required.
483    /// If `long_names` is not provided, text length will be entirely unchecked.
484    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    /// The byte count this string would occupy if it were encoded as a null-terminated string.
498    pub fn null_terminated_byte_size(&self) -> usize {
499        self.bytes.len() + sequence_end::byte_size()
500    }
501
502    /// The byte count this string would occupy if it were encoded as a size-prefixed string.
503    pub fn i32_sized_byte_size(&self) -> usize {
504        self.bytes.len() + i32::BYTE_SIZE
505    }
506
507    /// The byte count this string would occupy if it were encoded as a size-prefixed string.
508    pub fn u32_sized_byte_size(&self) -> usize {
509        self.bytes.len() + u32::BYTE_SIZE
510    }
511
512    /// Write the length of a string and then the contents with that length.
513    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    /// Write the length of a string and then the contents with that length.
520    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    /// Without validation, write this instance to the byte stream.
527    fn write_unsized_bytes<W: Write>(bytes: &[u8], write: &mut W) -> UnitResult {
528        u8::write_slice_le(write, bytes)?;
529        Ok(())
530    }
531
532    /// Read the length of a string and then the contents with that length.
533    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    /// Read the length of a string and then the contents with that length.
539    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    /// Read the contents with that length.
545    pub fn read_sized<R: Read>(read: &mut R, size: usize) -> Result<Self> {
546        const SMALL_SIZE: usize  = 24;
547
548        // for small strings, read into small vec without heap allocation
549        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        // for large strings, read a dynamic vec of arbitrary size
558        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    /// Write the string contents and a null-terminator.
564    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    /// Write the string contents and a null-terminator.
569    fn write_null_terminated_bytes<W: Write>(bytes: &[u8], write: &mut W) -> UnitResult {
570        debug_assert!(!bytes.is_empty(), "text is empty bug"); // required to avoid mixup with "sequece_end"
571
572        Text::write_unsized_bytes(bytes, write)?;
573        sequence_end::write(write)?;
574        Ok(())
575    }
576
577    /// Read a string until the null-terminator is found. Then skips the null-terminator.
578    pub fn read_null_terminated<R: Read>(read: &mut R, max_len: usize) -> Result<Self> {
579        let mut bytes = smallvec![ u8::read_le(read)? ]; // null-terminated strings are always at least 1 byte
580
581        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    /// Allows any text length since it is only used for attribute values,
596    /// but not attribute names, attribute type names, or channel names.
597    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        // length of the text-vector can be inferred from attribute size
605        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>(); // size i32 of the text
610            processed_bytes += text.bytes.len();
611            result.push(text);
612        }
613
614        // the expected byte size did not match the actual text byte size
615        if processed_bytes != total_byte_size {
616            return Err(Error::invalid("text array byte size"))
617        }
618
619        Ok(result)
620    }
621
622    /// Allows any text length since it is only used for attribute values,
623    /// but not attribute names, attribute type names, or channel names.
624    fn write_vec_of_i32_sized_texts_le<W: Write>(write: &mut W, texts: &[Text]) -> UnitResult {
625        // length of the text-vector can be inferred from attribute size
626        for text in texts {
627            text.write_i32_sized_le(write)?;
628        }
629
630        Ok(())
631    }
632
633    /// The underlying bytes that represent this text.
634    pub fn bytes(&self) -> &[u8] {
635        self.bytes.as_slice()
636    }
637
638    /// Iterate over the individual chars in this text, similar to `String::chars()`.
639    /// Does not do any heap-allocation but borrows from this instance instead.
640    pub fn chars(&self) -> impl '_ + Iterator<Item = char> {
641        self.bytes.iter().map(|&byte| byte as char)
642    }
643
644    /// Compare this `exr::Text` with a plain `&str`.
645    pub fn eq(&self, string: &str) -> bool {
646        string.chars().eq(self.chars())
647    }
648
649    /// Compare this `exr::Text` with a plain `&str` ignoring capitalization.
650    pub fn eq_case_insensitive(&self, string: &str) -> bool {
651        // this is technically not working for a "turkish i", but those cannot be encoded in exr files anyways
652        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
679// forwarding implementation. guarantees `text.borrow().hash() == text.hash()` (required for Borrow)
680impl 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    /// Panics if the string contains an unsupported character
695    fn from(str: &'s str) -> Self {
696        Self::new_or_panic(str)
697    }
698}
699
700
701/* TODO (currently conflicts with From<&str>)
702impl<'s> TryFrom<&'s str> for Text {
703    type Error = String;
704
705    fn try_from(value: &'s str) -> std::result::Result<Self, Self::Error> {
706        Text::new_or_none(value)
707            .ok_or_else(|| format!(
708                "exr::Text does not support all characters in the string `{}`",
709                value
710            ))
711    }
712}*/
713
714
715impl ::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
721// automatically implements to_string for us
722impl ::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    /// Does not validate channel order.
738    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    /// Iterate over the channels, and adds to each channel the byte offset of the channels sample type.
756    /// Assumes the internal channel list is properly sorted.
757    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    /// Return the index of the channel with the exact name, case sensitive, or none.
766    /// Potentially uses less than linear time.
767    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    // TODO use this in compression methods
772    /*pub fn pixel_section_indices(&self, bounds: IntegerBounds) -> impl '_ + Iterator<Item=(&Channel, usize, usize)> {
773        (bounds.position.y() .. bounds.end().y()).flat_map(|y| {
774            self.list
775                .filter(|channel| mod_p(y, usize_to_i32(channel.sampling.1)) == 0)
776                .flat_map(|channel|{
777                    (bounds.position.x() .. bounds.end().x())
778                        .filter(|x| mod_p(*x, usize_to_i32(channel.sampling.0)) == 0)
779                        .map(|x| (channel, x, y))
780                })
781        })
782    }*/
783}
784
785impl BlockType {
786
787    /// The corresponding attribute type name literal
788    const TYPE_NAME: &'static [u8] = type_names::TEXT;
789
790    /// Return a `BlockType` object from the specified attribute text value.
791    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    /// Without validation, write this instance to the byte stream.
804    pub fn write(&self, write: &mut impl Write) -> UnitResult {
805        u8::write_slice_le(write, self.to_text_bytes())?;
806        Ok(())
807    }
808
809    /// Returns the raw attribute text value this type is represented by in a file.
810    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    /// Number of bytes this would consume in an exr file.
820    pub fn byte_size(&self) -> usize {
821        self.to_text_bytes().len()
822    }
823}
824
825
826impl IntegerBounds {
827
828    /// Create a box with no size located at (0,0).
829    pub fn zero() -> Self {
830        Self::from_dimensions(Vec2(0, 0))
831    }
832
833    /// Create a box with a size starting at zero.
834    pub fn from_dimensions(size: impl Into<Vec2<usize>>) -> Self {
835        Self::new(Vec2(0,0), size)
836    }
837
838    /// Create a box with a size and an origin point.
839    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    /// Returns the top-right coordinate of the rectangle.
844    /// The row and column described by this vector are not included in the rectangle,
845    /// just like `Vec::len()`.
846    pub fn end(self) -> Vec2<i32> {
847        self.position + self.size.to_i32() // larger than max int32 is panic
848    }
849
850    /// Returns the maximum coordinate that a value in this rectangle may have.
851    pub fn max(self) -> Vec2<i32> {
852        self.end() - Vec2(1,1)
853    }
854
855    /// Validate this instance.
856    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; // as defined in the original c++ library
875
876        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    /// Number of bytes this would consume in an exr file.
888    pub fn byte_size() -> usize {
889        4 * i32::BYTE_SIZE
890    }
891
892    /// Without validation, write this instance to the byte stream.
893    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    /// Read the value without validating.
905    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        // prevent addition overflow
915        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        // add one to max because the max inclusive, but the size is not
921        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    /// Create a new rectangle which is offset by the specified origin.
928    pub fn with_origin(self, origin: Vec2<i32>) -> Self { // TODO rename to "move" or "translate"?
929        IntegerBounds { position: self.position + origin, .. self }
930    }
931
932    /// Returns whether the specified rectangle is equal to or inside this rectangle.
933    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    /// Number of bytes this would consume in an exr file.
945    pub fn byte_size() -> usize {
946        4 * f32::BYTE_SIZE
947    }
948
949    /// Without validation, write this instance to the byte stream.
950    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    /// Read the value without validating.
959    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    /// How many bytes a single sample takes up.
975    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    /// Number of bytes this would consume in an exr file.
984    pub fn byte_size() -> usize {
985        i32::BYTE_SIZE
986    }
987
988    /// Without validation, write this instance to the byte stream.
989    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    /// Read the value without validating.
1000    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1001        // there's definitely going to be more than 255 different pixel types in the future
1002        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    /// Choose whether to compress samples linearly or not, based on the channel name.
1013    /// Luminance-based channels will be compressed differently than linear data such as alpha.
1014    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    /// Create a new channel with the specified properties and a sampling rate of (1,1).
1024    /// Automatically chooses the linearity for compression based on the channel name.
1025    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 from_name<T: Into<Sample> + Default>(name: impl Into<Text>) -> Self {
1032        Self::named(name, T::default().into().sample_type())
1033    }*/
1034
1035    /// Create a new channel with the specified properties and a sampling rate of (1,1).
1036    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    /// The count of pixels this channel contains, respecting subsampling.
1041    // FIXME this must be used everywhere
1042    pub fn subsampled_pixels(&self, dimensions: Vec2<usize>) -> usize {
1043        self.subsampled_resolution(dimensions).area()
1044    }
1045
1046    /// The resolution pf this channel, respecting subsampling.
1047    pub fn subsampled_resolution(&self, dimensions: Vec2<usize>) -> Vec2<usize> {
1048        dimensions / self.sampling
1049    }
1050
1051    /// Number of bytes this would consume in an exr file.
1052    pub fn byte_size(&self) -> usize {
1053        self.name.null_terminated_byte_size()
1054            + SampleType::byte_size()
1055            + 1 // is_linear
1056            + 3 // reserved bytes
1057            + 2 * u32::BYTE_SIZE // sampling x, y
1058    }
1059
1060    /// Without validation, write this instance to the byte stream.
1061    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    /// Read the value without validating.
1077    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    /// Validate this instance.
1101    pub fn validate(&self, allow_sampling: bool, data_window: IntegerBounds, strict: bool) -> UnitResult {
1102        self.name.validate(true, None)?; // TODO spec says this does not affect `requirements.long_names` but is that true?
1103
1104        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            // TODO this must only be implemented in the crate::image module and child modules,
1122            //      should not be too difficult
1123
1124            return Err(Error::unsupported("channel subsampling not supported yet"));
1125        }
1126
1127        Ok(())
1128    }
1129}
1130
1131impl ChannelList {
1132
1133    /// Number of bytes this would consume in an exr file.
1134    pub fn byte_size(&self) -> usize {
1135        self.list.iter().map(ChannelDescription::byte_size).sum::<usize>() + sequence_end::byte_size()
1136    }
1137
1138    /// Without validation, write this instance to the byte stream.
1139    /// Assumes channels are sorted alphabetically and all values are validated.
1140    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    /// Read the value without validating.
1150    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    /// Check if channels are valid and sorted.
1160    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
1181// assumes value fits into u8
1182fn u8_from_decimal32(coded: u32) -> u8 {
1183    ((coded & 0x0f) + 10 * ((coded >> 4) & 0x0f)) as u8
1184}
1185
1186// https://github.com/AcademySoftwareFoundation/openexr/blob/master/src/lib/OpenEXR/ImfTimeCode.cpp
1187impl TimeCode {
1188
1189    /// Number of bytes this would consume in an exr file.
1190    pub const BYTE_SIZE: usize = 2 * u32::BYTE_SIZE;
1191
1192    /// Returns an error if this time code is considered invalid.
1193    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    /// Pack the SMPTE time code into a u32 value, according to TV60 packing.
1209    /// This is the encoding which is used within a binary exr file.
1210    pub fn pack_time_as_tv60_u32(&self) -> Result<u32> {
1211        // validate strictly to prevent set_bit panic! below
1212        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    /// Unpack a time code from one TV60 encoded u32 value and the encoded user data.
1229    /// This is the encoding which is used within a binary exr file.
1230    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)), // cast cannot fail, as these are less than 8 bits
1233            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)), // cast cannot fail, as these are less than 8 bits
1236            field_phase: tv60_time.get_bit(15),
1237            minutes: u8_from_decimal32(tv60_time.get_bits(16..23)), // cast cannot fail, as these are less than 8 bits
1238            hours: u8_from_decimal32(tv60_time.get_bits(24..30)), // cast cannot fail, as these are less than 8 bits
1239            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    /// Pack the SMPTE time code into a u32 value, according to TV50 packing.
1250    /// This encoding does not support the `drop_frame` flag, it will be lost.
1251    pub fn pack_time_as_tv50_u32(&self) -> Result<u32> {
1252        Ok(*self.pack_time_as_tv60_u32()?
1253
1254            // swap some fields by replacing some bits in the packed u32
1255            .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    /// Unpack a time code from one TV50 encoded u32 value and the encoded user data.
1264    /// This encoding does not support the `drop_frame` flag, it will always be false.
1265    pub fn from_tv50_time(tv50_time: u32, user_data: u32) -> Self {
1266        Self {
1267            drop_frame: false, // do not use bit [6]
1268
1269            // swap some fields:
1270            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    /// Pack the SMPTE time code into a u32 value, according to FILM24 packing.
1283    /// This encoding does not support the `drop_frame` and `color_frame` flags, they will be lost.
1284    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    /// Unpack a time code from one TV60 encoded u32 value and the encoded user data.
1292    /// This encoding does not support the `drop_frame` and `color_frame` flags, they will always be `false`.
1293    pub fn from_film24_time(film24_time: u32, user_data: u32) -> Self {
1294        Self {
1295            drop_frame: false, // bit [6]
1296            color_frame: false, // bit [7]
1297            .. Self::from_tv60_time(film24_time, user_data)
1298        }
1299    }
1300
1301
1302    // in rust, group index starts at zero, not at one.
1303    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 // +4, not +3, as `Range` is exclusive
1306    }
1307
1308    /// Pack the user data `u8` array into one u32.
1309    /// User data values are clamped to the valid range (maximum value is 4).
1310    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    // Unpack the encoded u32 user data to an array of bytes, each byte having a value from 0 to 4.
1320    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    /// Write this time code to the byte stream, encoded as TV60 integers.
1327    /// Returns an `Error::Invalid` if the fields are out of the allowed range.
1328    pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1329        self.pack_time_as_tv60_u32()?.write_le(write)?; // will validate
1330        self.pack_user_data_as_u32().write_le(write)?;
1331        Ok(())
1332    }
1333
1334    /// Read the time code, without validating, extracting from TV60 integers.
1335    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    /// Number of bytes this would consume in an exr file.
1345    pub fn byte_size() -> usize {
1346        8 * f32::BYTE_SIZE
1347    }
1348
1349    /// Without validation, write this instance to the byte stream.
1350    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    /// Read the value without validating.
1366    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    /// Number of bytes this would consume in an exr file.
1379    pub fn byte_size() -> usize { u8::BYTE_SIZE }
1380
1381    /// Without validation, write this instance to the byte stream.
1382    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    /// Read the value without validating.
1402    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    /// Number of bytes this would consume in an exr file.
1425    pub fn byte_size() -> usize {
1426        u8::BYTE_SIZE
1427    }
1428
1429    /// Without validation, write this instance to the byte stream.
1430    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    /// Read the value without validating.
1441    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    /// Number of bytes this would consume in an exr file.
1454    pub fn byte_size() -> usize {
1455        6 * i32::BYTE_SIZE
1456    }
1457
1458    /// Without validation, write this instance to the byte stream.
1459    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    /// Read the value without validating.
1470    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    /// Number of bytes this would consume in an exr file.
1486    pub fn byte_size() -> usize {
1487        u8::BYTE_SIZE
1488    }
1489
1490    /// Without validation, write this instance to the byte stream.
1491    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    /// Read the value without validating.
1503    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    /// Number of bytes this would consume in an exr file.
1520    pub fn byte_size(&self) -> usize {
1521        2 * u32::BYTE_SIZE + self.pixel_data.len()
1522    }
1523
1524    /// Without validation, write this instance to the byte stream.
1525    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    /// Read the value without validating.
1534    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            // Multiply by the number of bytes per pixel.
1540            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    /// Validate this instance.
1566    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    /// Number of bytes this would consume in an exr file.
1584    pub fn byte_size() -> usize {
1585        2 * u32::BYTE_SIZE + 1 // size x,y + (level mode + rounding mode)
1586    }
1587
1588    /// Without validation, write this instance to the byte stream.
1589    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    /// Read the value without validating.
1610    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        // wow you really saved that one byte here
1617        // mode = level_mode + (rounding_mode * 16)
1618        let level_mode = mode & 0b00001111; // wow that works
1619        let rounding_mode = mode >> 4; // wow that works
1620
1621        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    /// Validate this instance.
1638    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
1652/// Number of bytes this attribute would consume in an exr file.
1653// TODO instead of pre calculating byte size, write to a tmp buffer whose length is inspected before actually writing?
1654pub 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 // serialized byte size
1658        + value.byte_size()
1659}
1660
1661/// Without validation, write this attribute to the byte stream.
1662pub 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
1669/// Read the attribute without validating. The result may be `Ok` even if this single attribute is invalid.
1670pub 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
1678/// Validate this attribute.
1679pub 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))?; // only name text has length restriction
1681    value.validate(allow_sampling, data_window, strict) // attribute value text length is never restricted
1682}
1683
1684
1685impl AttributeValue {
1686
1687    /// Number of bytes this would consume in an exr file.
1688    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            // attribute value texts never have limited size.
1721            // also, don't serialize size, as it can be inferred from attribute size
1722            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    /// The exr name string of the type that an attribute can have.
1735    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    /// Without validation, write this instance to the byte stream.
1770    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            // attribute value texts never have limited size.
1802            // also, don't serialize size, as it can be inferred from attribute size
1803            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)?; // no idea why this one is u32, everything else is usually i32...
1811                u8::write_slice_le(write, bytes.as_slice())?
1812            }
1813
1814            Custom { ref bytes, .. } => u8::write_slice_le(write, &bytes)?, // write.write(&bytes).map(|_| ()),
1815        };
1816
1817        Ok(())
1818    }
1819
1820    /// Read the value without validating.
1821    /// Returns `Ok(Ok(attribute))` for valid attributes.
1822    /// Returns `Ok(Err(Error))` for malformed attributes from a valid byte source.
1823    /// Returns `Err(Error)` for invalid byte sources, for example for invalid files.
1824    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        // always read bytes as to leave the read position at the end of the attribute
1829        // even if the attribute contents fails to decode
1830        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        // TODO: don't read into an array at all, just read directly from the reader and optionally seek afterwards?
1833
1834        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                // the number of strings can be inferred from the total attribute size
1903                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                    // for some reason, they went for unsigned sizes, in this place only
1912                    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    /// Validate this instance.
1925    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    /// Return `Ok(i32)` if this attribute is an i32.
1946    pub fn to_i32(&self) -> Result<i32> {
1947        match *self {
1948            AttributeValue::I32(value) => Ok(value),
1949            _ => Err(invalid_type())
1950        }
1951    }
1952
1953    /// Return `Ok(f32)` if this attribute is an f32.
1954    pub fn to_f32(&self) -> Result<f32> {
1955        match *self {
1956            AttributeValue::F32(value) => Ok(value),
1957            _ => Err(invalid_type())
1958        }
1959    }
1960
1961    /// Return `Ok(Text)` if this attribute is a text.
1962    pub fn into_text(self) -> Result<Text> {
1963        match self {
1964            AttributeValue::Text(value) => Ok(value),
1965            _ => Err(invalid_type())
1966        }
1967    }
1968
1969    /// Return `Ok(Text)` if this attribute is a text.
1970    pub fn to_text(&self) -> Result<&Text> {
1971        match self {
1972            AttributeValue::Text(value) => Ok(value),
1973            _ => Err(invalid_type())
1974        }
1975    }
1976
1977    /// Return `Ok(Chromaticities)` if this attribute is a chromaticities attribute.
1978    pub fn to_chromaticities(&self) -> Result<Chromaticities> {
1979        match *self {
1980            AttributeValue::Chromaticities(value) => Ok(value),
1981            _ => Err(invalid_type())
1982        }
1983    }
1984
1985    /// Return `Ok(TimeCode)` if this attribute is a time code.
1986    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
1996/// Contains string literals identifying the type of an attribute.
1997pub mod type_names {
1998    macro_rules! define_attribute_type_names {
1999        ( $($name: ident : $value: expr),* ) => {
2000            $(
2001                /// The byte-string name of this attribute type as it appears in an exr file.
2002                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            {   // through tv60 packing, roundtrip
2251                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            {   // through bytes, roundtrip
2257                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, // apparently, tv50 does not support drop frame, so do not use this value
2266                   .. 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                    // apparently, film24 does not support some flags, so do not use those values
2277                    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}