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 /// A custom attribute.
86 /// Contains the type name of this value.
87 Custom {
88
89 /// The name of the type this attribute is an instance of.
90 kind: Text,
91
92 /// The value, stored in little-endian byte order, of the value.
93 /// Use the `exr::io::Data` trait to extract binary values from this vector.
94 bytes: Vec<u8>
95 },
96}
97
98/// A byte array with each byte being a char.
99/// This is not UTF an must be constructed from a standard string.
100// TODO is this ascii? use a rust ascii crate?
101#[derive(Clone, PartialEq, Ord, PartialOrd, Default)] // hash implemented manually
102pub struct Text {
103 bytes: TextBytes,
104}
105
106/// Contains time information for this frame within a sequence.
107/// Also defined methods to compile this information into a
108/// `TV60`, `TV50` or `Film24` bit sequence, packed into `u32`.
109///
110/// Satisfies the [SMPTE standard 12M-1999](https://en.wikipedia.org/wiki/SMPTE_timecode).
111/// For more in-depth information, see [philrees.co.uk/timecode](http://www.philrees.co.uk/articles/timecode.htm).
112#[derive(Copy, Debug, Clone, Eq, PartialEq, Hash, Default)]
113pub struct TimeCode {
114
115 /// Hours 0 - 23 are valid.
116 pub hours: u8,
117
118 /// Minutes 0 - 59 are valid.
119 pub minutes: u8,
120
121 /// Seconds 0 - 59 are valid.
122 pub seconds: u8,
123
124 /// Frame Indices 0 - 29 are valid.
125 pub frame: u8,
126
127 /// Whether this is a drop frame.
128 pub drop_frame: bool,
129
130 /// Whether this is a color frame.
131 pub color_frame: bool,
132
133 /// Field Phase.
134 pub field_phase: bool,
135
136 /// Flags for `TimeCode.binary_groups`.
137 pub binary_group_flags: [bool; 3],
138
139 /// The user-defined control codes.
140 /// Every entry in this array can use at most 3 bits.
141 /// This results in a maximum value of 15, including 0, for each `u8`.
142 pub binary_groups: [u8; 8]
143}
144
145/// layer type, specifies block type and deepness.
146#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
147pub enum BlockType {
148
149 /// Corresponds to the string value `scanlineimage`.
150 ScanLine,
151
152 /// Corresponds to the string value `tiledimage`.
153 Tile,
154
155 /// Corresponds to the string value `deepscanline`.
156 DeepScanLine,
157
158 /// Corresponds to the string value `deeptile`.
159 DeepTile,
160}
161
162/// The string literals used to represent a `BlockType` in a file.
163pub mod block_type_strings {
164
165 /// Type attribute text value of flat scan lines
166 pub const SCAN_LINE: &'static [u8] = b"scanlineimage";
167
168 /// Type attribute text value of flat tiles
169 pub const TILE: &'static [u8] = b"tiledimage";
170
171 /// Type attribute text value of deep scan lines
172 pub const DEEP_SCAN_LINE: &'static [u8] = b"deepscanline";
173
174 /// Type attribute text value of deep tiles
175 pub const DEEP_TILE: &'static [u8] = b"deeptile";
176}
177
178
179pub use crate::compression::Compression;
180
181/// The integer rectangle describing where an layer is placed on the infinite 2D global space.
182pub type DataWindow = IntegerBounds;
183
184/// The integer rectangle limiting which part of the infinite 2D global space should be displayed.
185pub type DisplayWindow = IntegerBounds;
186
187/// An integer dividend and divisor, together forming a ratio.
188pub type Rational = (i32, u32);
189
190/// A float matrix with four rows and four columns.
191pub type Matrix4x4 = [f32; 4*4];
192
193/// A float matrix with three rows and three columns.
194pub type Matrix3x3 = [f32; 3*3];
195
196/// A rectangular section anywhere in 2D integer space.
197/// Valid from minimum coordinate (including) `-1,073,741,822`
198/// to maximum coordinate (including) `1,073,741,822`, the value of (`i32::MAX/2 -1`).
199#[derive(Clone, Copy, Debug, Eq, PartialEq, Default, Hash)]
200pub struct IntegerBounds {
201
202 /// The top left corner of this rectangle.
203 /// The `Box2I32` includes this pixel if the size is not zero.
204 pub position: Vec2<i32>,
205
206 /// How many pixels to include in this `Box2I32`.
207 /// Extends to the right and downwards.
208 /// Does not include the actual boundary, just like `Vec::len()`.
209 pub size: Vec2<usize>,
210}
211
212/// A rectangular section anywhere in 2D float space.
213#[derive(Clone, Copy, Debug, PartialEq)]
214pub struct FloatRect {
215
216 /// The top left corner location of the rectangle (inclusive)
217 pub min: Vec2<f32>,
218
219 /// The bottom right corner location of the rectangle (inclusive)
220 pub max: Vec2<f32>
221}
222
223/// A List of channels. Channels must be sorted alphabetically.
224#[derive(Clone, Debug, Eq, PartialEq, Hash)]
225pub struct ChannelList {
226
227 /// The channels in this list.
228 pub list: SmallVec<[ChannelDescription; 5]>,
229
230 /// The number of bytes that one pixel in this image needs.
231 // FIXME this needs to account for subsampling anywhere?
232 pub bytes_per_pixel: usize, // FIXME only makes sense for flat images!
233
234 /// The sample type of all channels, if all channels have the same type.
235 pub uniform_sample_type: Option<SampleType>,
236}
237
238/// A single channel in an layer.
239/// Does not contain the actual pixel data,
240/// but instead merely describes it.
241#[derive(Clone, Debug, Eq, PartialEq, Hash)]
242pub struct ChannelDescription {
243
244 /// One of "R", "G", or "B" most of the time.
245 pub name: Text,
246
247 /// U32, F16 or F32.
248 pub sample_type: SampleType,
249
250 /// This attribute only tells lossy compression methods
251 /// whether this value should be quantized exponentially or linearly.
252 ///
253 /// Should be `false` for red, green, or blue channels.
254 /// Should be `true` for hue, chroma, saturation, or alpha channels.
255 pub quantize_linearly: bool,
256
257 /// How many of the samples are skipped compared to the other channels in this layer.
258 ///
259 /// Can be used for chroma subsampling for manual lossy data compression.
260 /// Values other than 1 are allowed only in flat, scan-line based images.
261 /// If an image is deep or tiled, x and y sampling rates for all of its channels must be 1.
262 pub sampling: Vec2<usize>,
263}
264
265/// The type of samples in this channel.
266#[derive(Clone, Debug, Eq, PartialEq, Copy, Hash)]
267pub enum SampleType {
268
269 /// This channel contains 32-bit unsigned int values.
270 U32,
271
272 /// This channel contains 16-bit float values.
273 F16,
274
275 /// This channel contains 32-bit float values.
276 F32,
277}
278
279/// The color space of the pixels.
280///
281/// If a file doesn't have a chromaticities attribute, display software
282/// should assume that the file's primaries and the white point match `Rec. ITU-R BT.709-3`.
283#[derive(Debug, Clone, Copy, PartialEq)]
284pub struct Chromaticities {
285
286 /// "Red" location on the CIE XY chromaticity diagram.
287 pub red: Vec2<f32>,
288
289 /// "Green" location on the CIE XY chromaticity diagram.
290 pub green: Vec2<f32>,
291
292 /// "Blue" location on the CIE XY chromaticity diagram.
293 pub blue: Vec2<f32>,
294
295 /// "White" location on the CIE XY chromaticity diagram.
296 pub white: Vec2<f32>
297}
298
299/// If this attribute is present, it describes
300/// how this texture should be projected onto an environment.
301#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
302pub enum EnvironmentMap {
303
304 /// This image is an environment map projected like a world map.
305 LatitudeLongitude,
306
307 /// This image contains the six sides of a cube.
308 Cube,
309}
310
311/// Uniquely identifies a motion picture film frame.
312#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
313pub struct KeyCode {
314
315 /// Identifies a film manufacturer.
316 pub film_manufacturer_code: i32,
317
318 /// Identifies a film type.
319 pub film_type: i32,
320
321 /// Specifies the film roll prefix.
322 pub film_roll_prefix: i32,
323
324 /// Specifies the film count.
325 pub count: i32,
326
327 /// Specifies the perforation offset.
328 pub perforation_offset: i32,
329
330 /// Specifies the perforation count of each single frame.
331 pub perforations_per_frame: i32,
332
333 /// Specifies the perforation count of each single film.
334 pub perforations_per_count: i32,
335}
336
337/// In what order the `Block`s of pixel data appear in a file.
338#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
339pub enum LineOrder {
340
341 /// The blocks in the file are ordered in descending rows from left to right.
342 /// When compressing in parallel, this option requires potentially large amounts of memory.
343 /// In that case, use `LineOrder::Unspecified` for best performance.
344 Increasing,
345
346 /// The blocks in the file are ordered in ascending rows from right to left.
347 /// When compressing in parallel, this option requires potentially large amounts of memory.
348 /// In that case, use `LineOrder::Unspecified` for best performance.
349 Decreasing,
350
351 /// The blocks are not ordered in a specific way inside the file.
352 /// In multi-core file writing, this option offers the best performance.
353 Unspecified,
354}
355
356/// A small `rgba` image of `i8` values that approximates the real exr image.
357// TODO is this linear?
358#[derive(Clone, Eq, PartialEq)]
359pub struct Preview {
360
361 /// The dimensions of the preview image.
362 pub size: Vec2<usize>,
363
364 /// An array with a length of 4 × width × height.
365 /// The pixels are stored in `LineOrder::Increasing`.
366 /// Each pixel consists of the four `u8` values red, green, blue, alpha.
367 pub pixel_data: Vec<i8>,
368}
369
370/// Describes how the layer is divided into tiles.
371/// Specifies the size of each tile in the image
372/// and whether this image contains multiple resolution levels.
373#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
374pub struct TileDescription {
375
376 /// The size of each tile.
377 /// Stays the same number of pixels across all levels.
378 pub tile_size: Vec2<usize>,
379
380 /// Whether to also store smaller versions of the image.
381 pub level_mode: LevelMode,
382
383 /// Whether to round up or down when calculating Mip/Rip levels.
384 pub rounding_mode: RoundingMode,
385}
386
387/// Whether to also store increasingly smaller versions of the original image.
388#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
389pub enum LevelMode {
390
391 /// Only a single level.
392 Singular,
393
394 /// Levels with a similar aspect ratio.
395 MipMap,
396
397 /// Levels with all possible aspect ratios.
398 RipMap,
399}
400
401
402/// The raw bytes that make up a string in an exr file.
403/// Each `u8` is a single char.
404// will mostly be "R", "G", "B" or "deepscanlineimage"
405pub type TextBytes = SmallVec<[u8; 24]>;
406
407/// A byte slice, interpreted as text
408pub 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(message:"attribute type mismatch")
424}
425
426
427impl Text {
428
429 /// Create a `Text` from an `str` reference.
430 /// Returns `None` if this string contains unsupported chars.
431 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 /// Create a `Text` from an `str` reference.
440 /// Panics if this string contains unsupported chars.
441 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 /// Create a `Text` from a slice of bytes,
446 /// without checking any of the bytes.
447 pub fn from_slice_unchecked(text: &TextSlice) -> Self {
448 Self::from_bytes_unchecked(SmallVec::from_slice(text))
449 }
450
451 /// Create a `Text` from the specified bytes object,
452 /// without checking any of the bytes.
453 pub fn from_bytes_unchecked(bytes: TextBytes) -> Self {
454 Text { bytes }
455 }
456
457 /// The internal ASCII bytes this text is made of.
458 pub fn as_slice(&self) -> &TextSlice {
459 self.bytes.as_slice()
460 }
461
462 /// Check whether this string is valid, adjusting `long_names` if required.
463 /// If `long_names` is not provided, text length will be entirely unchecked.
464 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 /// Check whether some bytes are valid, adjusting `long_names` if required.
469 /// If `long_names` is not provided, text length will be entirely unchecked.
470 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 /// The byte count this string would occupy if it were encoded as a null-terminated string.
484 pub fn null_terminated_byte_size(&self) -> usize {
485 self.bytes.len() + sequence_end::byte_size()
486 }
487
488 /// The byte count this string would occupy if it were encoded as a size-prefixed string.
489 pub fn i32_sized_byte_size(&self) -> usize {
490 self.bytes.len() + i32::BYTE_SIZE
491 }
492
493 /// Write the length of a string and then the contents with that length.
494 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 /// Without validation, write this instance to the byte stream.
501 fn write_unsized_bytes<W: Write>(bytes: &[u8], write: &mut W) -> UnitResult {
502 u8::write_slice(write, bytes)?;
503 Ok(())
504 }
505
506 /// Read the length of a string and then the contents with that length.
507 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 /// Read the contents with that length.
513 pub fn read_sized<R: Read>(read: &mut R, size: usize) -> Result<Self> {
514 const SMALL_SIZE: usize = 24;
515
516 // for small strings, read into small vec without heap allocation
517 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 // for large strings, read a dynamic vec of arbitrary size
526 else {
527 Ok(Text::from_bytes_unchecked(SmallVec::from_vec(u8::read_vec(read, size, 1024, None, "text attribute length")?)))
528 }
529 }
530
531 /// Write the string contents and a null-terminator.
532 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 /// Write the string contents and a null-terminator.
537 fn write_null_terminated_bytes<W: Write>(bytes: &[u8], write: &mut W) -> UnitResult {
538 debug_assert!(!bytes.is_empty(), "text is empty bug"); // required to avoid mixup with "sequece_end"
539
540 Text::write_unsized_bytes(bytes, write)?;
541 sequence_end::write(write)?;
542 Ok(())
543 }
544
545 /// Read a string until the null-terminator is found. Then skips the null-terminator.
546 pub fn read_null_terminated<R: Read>(read: &mut R, max_len: usize) -> Result<Self> {
547 let mut bytes = smallvec![ u8::read(read)? ]; // null-terminated strings are always at least 1 byte
548
549 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 /// Allows any text length since it is only used for attribute values,
564 /// but not attribute names, attribute type names, or channel names.
565 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 // length of the text-vector can be inferred from attribute size
573 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>(); // size i32 of the text
578 processed_bytes += text.bytes.len();
579 result.push(text);
580 }
581
582 // the expected byte size did not match the actual text byte size
583 if processed_bytes != total_byte_size {
584 return Err(Error::invalid("text array byte size"))
585 }
586
587 Ok(result)
588 }
589
590 /// Allows any text length since it is only used for attribute values,
591 /// but not attribute names, attribute type names, or channel names.
592 fn write_vec_of_i32_sized_texts<W: Write>(write: &mut W, texts: &[Text]) -> UnitResult {
593 // length of the text-vector can be inferred from attribute size
594 for text in texts {
595 text.write_i32_sized(write)?;
596 }
597
598 Ok(())
599 }
600
601 /// The underlying bytes that represent this text.
602 pub fn bytes(&self) -> &[u8] {
603 self.bytes.as_slice()
604 }
605
606 /// Iterate over the individual chars in this text, similar to `String::chars()`.
607 /// Does not do any heap-allocation but borrows from this instance instead.
608 pub fn chars(&self) -> impl '_ + Iterator<Item = char> {
609 self.bytes.iter().map(|&byte| byte as char)
610 }
611
612 /// Compare this `exr::Text` with a plain `&str`.
613 pub fn eq(&self, string: &str) -> bool {
614 string.chars().eq(self.chars())
615 }
616
617 /// Compare this `exr::Text` with a plain `&str` ignoring capitalization.
618 pub fn eq_case_insensitive(&self, string: &str) -> bool {
619 // this is technically not working for a "turkish i", but those cannot be encoded in exr files anyways
620 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(string: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
647// forwarding implementation. guarantees `text.borrow().hash() == text.hash()` (required for Borrow)
648impl 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 /// Panics if the string contains an unsupported character
663 fn from(str: &'s str) -> Self {
664 Self::new_or_panic(string:str)
665 }
666}
667
668
669/* TODO (currently conflicts with From<&str>)
670impl<'s> TryFrom<&'s str> for Text {
671 type Error = String;
672
673 fn try_from(value: &'s str) -> std::result::Result<Self, Self::Error> {
674 Text::new_or_none(value)
675 .ok_or_else(|| format!(
676 "exr::Text does not support all characters in the string `{}`",
677 value
678 ))
679 }
680}*/
681
682
683impl ::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
689// automatically implements to_string for us
690impl ::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: u8 in self.bytes.iter() {
695 f.write_char(byte as char)?;
696 }
697
698 Ok(())
699 }
700}
701
702
703impl ChannelList {
704
705 /// Does not validate channel order.
706 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 /// Iterate over the channels, and adds to each channel the byte offset of the channels sample type.
724 /// Assumes the internal channel list is properly sorted.
725 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 /// Return the index of the channel with the exact name, case sensitive, or none.
734 /// Potentially uses less than linear time.
735 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 // TODO use this in compression methods
740 /*pub fn pixel_section_indices(&self, bounds: IntegerBounds) -> impl '_ + Iterator<Item=(&Channel, usize, usize)> {
741 (bounds.position.y() .. bounds.end().y()).flat_map(|y| {
742 self.list
743 .filter(|channel| mod_p(y, usize_to_i32(channel.sampling.1)) == 0)
744 .flat_map(|channel|{
745 (bounds.position.x() .. bounds.end().x())
746 .filter(|x| mod_p(*x, usize_to_i32(channel.sampling.0)) == 0)
747 .map(|x| (channel, x, y))
748 })
749 })
750 }*/
751}
752
753impl BlockType {
754
755 /// The corresponding attribute type name literal
756 const TYPE_NAME: &'static [u8] = type_names::TEXT;
757
758 /// Return a `BlockType` object from the specified attribute text value.
759 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 /// Without validation, write this instance to the byte stream.
772 pub fn write(&self, write: &mut impl Write) -> UnitResult {
773 u8::write_slice(write, self.to_text_bytes())?;
774 Ok(())
775 }
776
777 /// Returns the raw attribute text value this type is represented by in a file.
778 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 /// Number of bytes this would consume in an exr file.
788 pub fn byte_size(&self) -> usize {
789 self.to_text_bytes().len()
790 }
791}
792
793
794impl IntegerBounds {
795
796 /// Create a box with no size located at (0,0).
797 pub fn zero() -> Self {
798 Self::from_dimensions(Vec2(0, 0))
799 }
800
801 /// Create a box with a size starting at zero.
802 pub fn from_dimensions(size: impl Into<Vec2<usize>>) -> Self {
803 Self::new(Vec2(0,0), size)
804 }
805
806 /// Create a box with a size and an origin point.
807 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 /// Returns the top-right coordinate of the rectangle.
812 /// The row and column described by this vector are not included in the rectangle,
813 /// just like `Vec::len()`.
814 pub fn end(self) -> Vec2<i32> {
815 self.position + self.size.to_i32() // larger than max int32 is panic
816 }
817
818 /// Returns the maximum coordinate that a value in this rectangle may have.
819 pub fn max(self) -> Vec2<i32> {
820 self.end() - Vec2(1,1)
821 }
822
823 /// Validate this instance.
824 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; // as defined in the original c++ library
843
844 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 /// Number of bytes this would consume in an exr file.
856 pub fn byte_size() -> usize {
857 4 * i32::BYTE_SIZE
858 }
859
860 /// Without validation, write this instance to the byte stream.
861 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 /// Read the value without validating.
873 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 // prevent addition overflow
883 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 // add one to max because the max inclusive, but the size is not
889 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 /// Create a new rectangle which is offset by the specified origin.
896 pub fn with_origin(self, origin: Vec2<i32>) -> Self { // TODO rename to "move" or "translate"?
897 IntegerBounds { position: self.position + origin, .. self }
898 }
899
900 /// Returns whether the specified rectangle is equal to or inside this rectangle.
901 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 /// Number of bytes this would consume in an exr file.
913 pub fn byte_size() -> usize {
914 4 * f32::BYTE_SIZE
915 }
916
917 /// Without validation, write this instance to the byte stream.
918 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 /// Read the value without validating.
927 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 /// How many bytes a single sample takes up.
943 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 /// Number of bytes this would consume in an exr file.
952 pub fn byte_size() -> usize {
953 i32::BYTE_SIZE
954 }
955
956 /// Without validation, write this instance to the byte stream.
957 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 /// Read the value without validating.
968 pub fn read<R: Read>(read: &mut R) -> Result<Self> {
969 // there's definitely going to be more than 255 different pixel types in the future
970 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 /// Choose whether to compress samples linearly or not, based on the channel name.
981 /// Luminance-based channels will be compressed differently than linear data such as alpha.
982 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 /// Create a new channel with the specified properties and a sampling rate of (1,1).
992 /// Automatically chooses the linearity for compression based on the channel name.
993 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 from_name<T: Into<Sample> + Default>(name: impl Into<Text>) -> Self {
1000 Self::named(name, T::default().into().sample_type())
1001 }*/
1002
1003 /// Create a new channel with the specified properties and a sampling rate of (1,1).
1004 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 /// The count of pixels this channel contains, respecting subsampling.
1009 // FIXME this must be used everywhere
1010 pub fn subsampled_pixels(&self, dimensions: Vec2<usize>) -> usize {
1011 self.subsampled_resolution(dimensions).area()
1012 }
1013
1014 /// The resolution pf this channel, respecting subsampling.
1015 pub fn subsampled_resolution(&self, dimensions: Vec2<usize>) -> Vec2<usize> {
1016 dimensions / self.sampling
1017 }
1018
1019 /// Number of bytes this would consume in an exr file.
1020 pub fn byte_size(&self) -> usize {
1021 self.name.null_terminated_byte_size()
1022 + SampleType::byte_size()
1023 + 1 // is_linear
1024 + 3 // reserved bytes
1025 + 2 * u32::BYTE_SIZE // sampling x, y
1026 }
1027
1028 /// Without validation, write this instance to the byte stream.
1029 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 /// Read the value without validating.
1045 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 /// Validate this instance.
1069 pub fn validate(&self, allow_sampling: bool, data_window: IntegerBounds, strict: bool) -> UnitResult {
1070 self.name.validate(true, None)?; // TODO spec says this does not affect `requirements.long_names` but is that true?
1071
1072 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 // TODO this must only be implemented in the crate::image module and child modules,
1090 // should not be too difficult
1091
1092 return Err(Error::unsupported("channel subsampling not supported yet"));
1093 }
1094
1095 Ok(())
1096 }
1097}
1098
1099impl ChannelList {
1100
1101 /// Number of bytes this would consume in an exr file.
1102 pub fn byte_size(&self) -> usize {
1103 self.list.iter().map(ChannelDescription::byte_size).sum::<usize>() + sequence_end::byte_size()
1104 }
1105
1106 /// Without validation, write this instance to the byte stream.
1107 /// Assumes channels are sorted alphabetically and all values are validated.
1108 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 /// Read the value without validating.
1118 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 /// Check if channels are valid and sorted.
1128 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: u32 = binary as u32 % 10;
1145 let tens: u32 = (binary as u32 / 10) % 10;
1146 units | (tens << 4)
1147}
1148
1149// assumes value fits into u8
1150fn u8_from_decimal32(coded: u32) -> u8 {
1151 ((coded & 0x0f) + 10 * ((coded >> 4) & 0x0f)) as u8
1152}
1153
1154// https://github.com/AcademySoftwareFoundation/openexr/blob/master/src/lib/OpenEXR/ImfTimeCode.cpp
1155impl TimeCode {
1156
1157 /// Number of bytes this would consume in an exr file.
1158 pub const BYTE_SIZE: usize = 2 * u32::BYTE_SIZE;
1159
1160 /// Returns an error if this time code is considered invalid.
1161 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 /// Pack the SMPTE time code into a u32 value, according to TV60 packing.
1177 /// This is the encoding which is used within a binary exr file.
1178 pub fn pack_time_as_tv60_u32(&self) -> Result<u32> {
1179 // validate strictly to prevent set_bit panic! below
1180 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 /// Unpack a time code from one TV60 encoded u32 value and the encoded user data.
1197 /// This is the encoding which is used within a binary exr file.
1198 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)), // cast cannot fail, as these are less than 8 bits
1201 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)), // cast cannot fail, as these are less than 8 bits
1204 field_phase: tv60_time.get_bit(15),
1205 minutes: u8_from_decimal32(tv60_time.get_bits(16..23)), // cast cannot fail, as these are less than 8 bits
1206 hours: u8_from_decimal32(tv60_time.get_bits(24..30)), // cast cannot fail, as these are less than 8 bits
1207 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 /// Pack the SMPTE time code into a u32 value, according to TV50 packing.
1218 /// This encoding does not support the `drop_frame` flag, it will be lost.
1219 pub fn pack_time_as_tv50_u32(&self) -> Result<u32> {
1220 Ok(*self.pack_time_as_tv60_u32()?
1221
1222 // swap some fields by replacing some bits in the packed u32
1223 .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 /// Unpack a time code from one TV50 encoded u32 value and the encoded user data.
1232 /// This encoding does not support the `drop_frame` flag, it will always be false.
1233 pub fn from_tv50_time(tv50_time: u32, user_data: u32) -> Self {
1234 Self {
1235 drop_frame: false, // do not use bit [6]
1236
1237 // swap some fields:
1238 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 /// Pack the SMPTE time code into a u32 value, according to FILM24 packing.
1251 /// This encoding does not support the `drop_frame` and `color_frame` flags, they will be lost.
1252 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 /// Unpack a time code from one TV60 encoded u32 value and the encoded user data.
1260 /// This encoding does not support the `drop_frame` and `color_frame` flags, they will always be `false`.
1261 pub fn from_film24_time(film24_time: u32, user_data: u32) -> Self {
1262 Self {
1263 drop_frame: false, // bit [6]
1264 color_frame: false, // bit [7]
1265 .. Self::from_tv60_time(film24_time, user_data)
1266 }
1267 }
1268
1269
1270 // in rust, group index starts at zero, not at one.
1271 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 // +4, not +3, as `Range` is exclusive
1274 }
1275
1276 /// Pack the user data `u8` array into one u32.
1277 /// User data values are clamped to the valid range (maximum value is 4).
1278 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 // Unpack the encoded u32 user data to an array of bytes, each byte having a value from 0 to 4.
1288 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 /// Write this time code to the byte stream, encoded as TV60 integers.
1295 /// Returns an `Error::Invalid` if the fields are out of the allowed range.
1296 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1297 self.pack_time_as_tv60_u32()?.write(write)?; // will validate
1298 self.pack_user_data_as_u32().write(write)?;
1299 Ok(())
1300 }
1301
1302 /// Read the time code, without validating, extracting from TV60 integers.
1303 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 /// Number of bytes this would consume in an exr file.
1313 pub fn byte_size() -> usize {
1314 8 * f32::BYTE_SIZE
1315 }
1316
1317 /// Without validation, write this instance to the byte stream.
1318 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 /// Read the value without validating.
1334 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 /// Number of bytes this would consume in an exr file.
1347 pub fn byte_size() -> usize { u8::BYTE_SIZE }
1348
1349 /// Without validation, write this instance to the byte stream.
1350 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 /// Read the value without validating.
1368 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 /// Number of bytes this would consume in an exr file.
1389 pub fn byte_size() -> usize {
1390 u8::BYTE_SIZE
1391 }
1392
1393 /// Without validation, write this instance to the byte stream.
1394 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 /// Read the value without validating.
1405 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 /// Number of bytes this would consume in an exr file.
1418 pub fn byte_size() -> usize {
1419 6 * i32::BYTE_SIZE
1420 }
1421
1422 /// Without validation, write this instance to the byte stream.
1423 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 /// Read the value without validating.
1434 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 /// Number of bytes this would consume in an exr file.
1450 pub fn byte_size() -> usize {
1451 u8::BYTE_SIZE
1452 }
1453
1454 /// Without validation, write this instance to the byte stream.
1455 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 /// Read the value without validating.
1467 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 /// Number of bytes this would consume in an exr file.
1484 pub fn byte_size(&self) -> usize {
1485 2 * u32::BYTE_SIZE + self.pixel_data.len()
1486 }
1487
1488 /// Without validation, write this instance to the byte stream.
1489 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 /// Read the value without validating.
1498 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 // Multiply by the number of bytes per pixel.
1504 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 /// Validate this instance.
1530 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 /// Number of bytes this would consume in an exr file.
1548 pub fn byte_size() -> usize {
1549 2 * u32::BYTE_SIZE + 1 // size x,y + (level mode + rounding mode)
1550 }
1551
1552 /// Without validation, write this instance to the byte stream.
1553 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 /// Read the value without validating.
1574 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 // wow you really saved that one byte here
1581 // mode = level_mode + (rounding_mode * 16)
1582 let level_mode = mode & 0b00001111; // wow that works
1583 let rounding_mode = mode >> 4; // wow that works
1584
1585 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 /// Validate this instance.
1602 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
1616/// Number of bytes this attribute would consume in an exr file.
1617// TODO instead of pre calculating byte size, write to a tmp buffer whose length is inspected before actually writing?
1618pub 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 // serialized byte size
1622 + value.byte_size()
1623}
1624
1625/// Without validation, write this attribute to the byte stream.
1626pub fn write<W: Write>(name: &[u8], value: &AttributeValue, write: &mut W) -> UnitResult {
1627 Text::write_null_terminated_bytes(bytes:name, write)?;
1628 Text::write_null_terminated_bytes(bytes:value.kind_name(), write)?;
1629 i32::write(self:value.byte_size() as i32, write)?;
1630 value.write(write)
1631}
1632
1633/// Read the attribute without validating. The result may be `Ok` even if this single attribute is invalid.
1634pub fn read(read: &mut PeekRead<impl Read>, max_size: usize) -> Result<(Text, Result<AttributeValue>)> {
1635 let name: Text = Text::read_null_terminated(read, max_len:max_size)?;
1636 let kind: Text = Text::read_null_terminated(read, max_len:max_size)?;
1637 let size: usize = i32_to_usize(value:i32::read(read)?, error_message:"attribute size")?;
1638 let value: Result = AttributeValue::read(read, kind, byte_size:size)?;
1639 Ok((name, value))
1640}
1641
1642/// Validate this attribute.
1643pub fn validate(name: &Text, value: &AttributeValue, long_names: &mut bool, allow_sampling: bool, data_window: IntegerBounds, strict: bool) -> UnitResult {
1644 name.validate(null_terminated:true, long_names:Some(long_names))?; // only name text has length restriction
1645 value.validate(allow_sampling, data_window, strict) // attribute value text length is never restricted
1646}
1647
1648
1649impl AttributeValue {
1650
1651 /// Number of bytes this would consume in an exr file.
1652 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 // attribute value texts never have limited size.
1685 // also, don't serialize size, as it can be inferred from attribute size
1686 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 /// The exr name string of the type that an attribute can have.
1696 pub fn kind_name(&self) -> &[u8] {
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 Custom { ref kind, .. } => &kind.bytes,
1725 BlockType(_) => super::BlockType::TYPE_NAME,
1726 }
1727 }
1728
1729 /// Without validation, write this instance to the byte stream.
1730 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 // attribute value texts never have limited size.
1762 // also, don't serialize size, as it can be inferred from attribute size
1763 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)?, // write.write(&bytes).map(|_| ()),
1768 BlockType(kind) => kind.write(write)?
1769 };
1770
1771 Ok(())
1772 }
1773
1774 /// Read the value without validating.
1775 /// Returns `Ok(Ok(attribute))` for valid attributes.
1776 /// Returns `Ok(Err(Error))` for invalid attributes from a valid byte source.
1777 /// Returns `Err(Error)` for invalid byte sources, for example for invalid files.
1778 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 // always read bytes
1783 let attribute_bytes = u8::read_vec(read, byte_size, 128, None, "attribute value size")?;
1784 // TODO no allocation for small attributes // : SmallVec<[u8; 64]> = smallvec![0; byte_size];
1785
1786 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 // the number of strings can be inferred from the total attribute size
1855 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() } // TODO no clone
1863 })
1864 };
1865
1866 Ok(parse_attribute())
1867 }
1868
1869 /// Validate this instance.
1870 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 /// Return `Ok(i32)` if this attribute is an i32.
1891 pub fn to_i32(&self) -> Result<i32> {
1892 match *self {
1893 AttributeValue::I32(value) => Ok(value),
1894 _ => Err(invalid_type())
1895 }
1896 }
1897
1898 /// Return `Ok(f32)` if this attribute is an f32.
1899 pub fn to_f32(&self) -> Result<f32> {
1900 match *self {
1901 AttributeValue::F32(value) => Ok(value),
1902 _ => Err(invalid_type())
1903 }
1904 }
1905
1906 /// Return `Ok(Text)` if this attribute is a text.
1907 pub fn into_text(self) -> Result<Text> {
1908 match self {
1909 AttributeValue::Text(value) => Ok(value),
1910 _ => Err(invalid_type())
1911 }
1912 }
1913
1914 /// Return `Ok(Text)` if this attribute is a text.
1915 pub fn to_text(&self) -> Result<&Text> {
1916 match self {
1917 AttributeValue::Text(value) => Ok(value),
1918 _ => Err(invalid_type())
1919 }
1920 }
1921
1922 /// Return `Ok(Chromaticities)` if this attribute is a chromaticities attribute.
1923 pub fn to_chromaticities(&self) -> Result<Chromaticities> {
1924 match *self {
1925 AttributeValue::Chromaticities(value) => Ok(value),
1926 _ => Err(invalid_type())
1927 }
1928 }
1929
1930 /// Return `Ok(TimeCode)` if this attribute is a time code.
1931 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
1941/// Contains string literals identifying the type of an attribute.
1942pub mod type_names {
1943 macro_rules! define_attribute_type_names {
1944 ( $($name: ident : $value: expr),* ) => {
1945 $(
1946 /// The byte-string name of this attribute type as it appears in an exr file.
1947 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 { // through tv60 packing, roundtrip
2188 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 { // through bytes, roundtrip
2194 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, // apparently, tv50 does not support drop frame, so do not use this value
2203 .. 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 // apparently, film24 does not support some flags, so do not use those values
2214 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}
2227