/rust/registry/src/index.crates.io-1949cf8c6b5b557f/exr-1.74.0/src/meta/attribute.rs
Line | Count | Source |
1 | | |
2 | | //! Contains all meta data attributes. |
3 | | //! Each layer can have any number of [`Attribute`]s, including custom attributes. |
4 | | |
5 | | use smallvec::SmallVec; |
6 | | |
7 | | |
8 | | /// Contains one of all possible attributes. |
9 | | /// Includes a variant for custom attributes. |
10 | | #[derive(Debug, Clone, PartialEq)] |
11 | | pub 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 |
116 | | pub 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)] |
127 | | pub 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)] |
161 | | pub 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. |
177 | | pub 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 | | |
193 | | pub use crate::compression::Compression; |
194 | | |
195 | | /// The integer rectangle describing where an layer is placed on the infinite 2D global space. |
196 | | pub type DataWindow = IntegerBounds; |
197 | | |
198 | | /// The integer rectangle limiting which part of the infinite 2D global space should be displayed. |
199 | | pub type DisplayWindow = IntegerBounds; |
200 | | |
201 | | /// An integer dividend and divisor, together forming a ratio. |
202 | | pub type Rational = (i32, u32); |
203 | | |
204 | | /// A float matrix with four rows and four columns. |
205 | | pub type Matrix4x4 = [f32; 4*4]; |
206 | | |
207 | | /// A float matrix with three rows and three columns. |
208 | | pub 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)] |
214 | | pub 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)] |
228 | | pub 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)] |
239 | | pub 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)] |
256 | | pub 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)] |
281 | | pub 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)] |
298 | | pub 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)] |
316 | | pub 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)] |
327 | | pub 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)] |
353 | | pub 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)] |
373 | | pub 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)] |
388 | | pub 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)] |
403 | | pub 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" |
419 | | pub type TextBytes = SmallVec<[u8; 24]>; |
420 | | |
421 | | /// A byte slice, interpreted as text |
422 | | pub type TextSlice = [u8]; |
423 | | |
424 | | |
425 | | use crate::io::*; |
426 | | use crate::meta::{sequence_end}; |
427 | | use crate::error::*; |
428 | | use crate::math::{RoundingMode, Vec2}; |
429 | | use half::f16; |
430 | | use std::convert::{TryFrom}; |
431 | | use std::borrow::Borrow; |
432 | | use std::hash::{Hash, Hasher}; |
433 | | use bit_field::BitField; |
434 | | |
435 | | |
436 | 0 | fn invalid_type() -> Error { |
437 | 0 | Error::invalid("attribute type mismatch") |
438 | 0 | } |
439 | | |
440 | | |
441 | | impl Text { |
442 | | |
443 | | /// Create a `Text` from an `str` reference. |
444 | | /// Returns `None` if this string contains unsupported chars. |
445 | 36.9k | pub fn new_or_none(string: impl AsRef<str>) -> Option<Self> { |
446 | 36.9k | let vec : Option<TextBytes> = string.as_ref().chars() |
447 | 36.9k | .map(|character| u8::try_from(character as u64).ok()) |
448 | 36.9k | .collect(); |
449 | | |
450 | 36.9k | vec.map(Self::from_bytes_unchecked) |
451 | 36.9k | } |
452 | | |
453 | | /// Create a `Text` from an `str` reference. |
454 | | /// Panics if this string contains unsupported chars. |
455 | 36.9k | pub fn new_or_panic(string: impl AsRef<str>) -> Self { |
456 | 36.9k | Self::new_or_none(string).expect("exr::Text contains unsupported characters") |
457 | 36.9k | } |
458 | | |
459 | | /// Create a `Text` from a slice of bytes, |
460 | | /// without checking any of the bytes. |
461 | 0 | pub fn from_slice_unchecked(text: &TextSlice) -> Self { |
462 | 0 | Self::from_bytes_unchecked(SmallVec::from_slice(text)) |
463 | 0 | } |
464 | | |
465 | | /// Create a `Text` from the specified bytes object, |
466 | | /// without checking any of the bytes. |
467 | 326k | pub fn from_bytes_unchecked(bytes: TextBytes) -> Self { |
468 | 326k | Text { bytes } |
469 | 326k | } |
470 | | |
471 | | /// The internal ASCII bytes this text is made of. |
472 | 2.14M | pub fn as_slice(&self) -> &TextSlice { |
473 | 2.14M | self.bytes.as_slice() |
474 | 2.14M | } |
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 | 354k | pub fn validate(&self, null_terminated: bool, long_names: Option<&mut bool>) -> UnitResult { |
479 | 354k | Self::validate_bytes(self.as_slice(), null_terminated, long_names) |
480 | 354k | } |
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 | 354k | pub fn validate_bytes(text: &TextSlice, null_terminated: bool, long_names: Option<&mut bool>) -> UnitResult { |
485 | 354k | if null_terminated && text.is_empty() { |
486 | 0 | return Err(Error::invalid("text must not be empty")); |
487 | 354k | } |
488 | | |
489 | 354k | if let Some(long) = long_names { |
490 | 290k | if text.len() >= 256 { return Err(Error::invalid("text must not be longer than 255")); } |
491 | 290k | if text.len() >= 32 { *long = true; } |
492 | 63.9k | } |
493 | | |
494 | 354k | Ok(()) |
495 | 354k | } |
496 | | |
497 | | /// The byte count this string would occupy if it were encoded as a null-terminated string. |
498 | 248 | pub fn null_terminated_byte_size(&self) -> usize { |
499 | 248 | self.bytes.len() + sequence_end::byte_size() |
500 | 248 | } |
501 | | |
502 | | /// The byte count this string would occupy if it were encoded as a size-prefixed string. |
503 | 0 | pub fn i32_sized_byte_size(&self) -> usize { |
504 | 0 | self.bytes.len() + i32::BYTE_SIZE |
505 | 0 | } |
506 | | |
507 | | /// The byte count this string would occupy if it were encoded as a size-prefixed string. |
508 | 0 | pub fn u32_sized_byte_size(&self) -> usize { |
509 | 0 | self.bytes.len() + u32::BYTE_SIZE |
510 | 0 | } |
511 | | |
512 | | /// Write the length of a string and then the contents with that length. |
513 | 0 | pub fn write_i32_sized_le<W: Write>(&self, write: &mut W) -> UnitResult { |
514 | 0 | debug_assert!(self.validate( false, None).is_ok(), "text size bug"); |
515 | 0 | i32::write_le(usize_to_i32(self.bytes.len(), "text length")?, write)?; |
516 | 0 | Self::write_unsized_bytes(self.bytes.as_slice(), write) |
517 | 0 | } Unexecuted instantiation: <exr::meta::attribute::Text>::write_i32_sized_le::<_> Unexecuted instantiation: <exr::meta::attribute::Text>::write_i32_sized_le::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> Unexecuted instantiation: <exr::meta::attribute::Text>::write_i32_sized_le::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> |
518 | | |
519 | | /// Write the length of a string and then the contents with that length. |
520 | 0 | pub fn write_u32_sized_le<W: Write>(&self, write: &mut W) -> UnitResult { |
521 | 0 | debug_assert!(self.validate( false, None).is_ok(), "text size bug"); |
522 | 0 | u32::write_le(usize_to_u32(self.bytes.len(), "text length")?, write)?; |
523 | 0 | Self::write_unsized_bytes(self.bytes.as_slice(), write) |
524 | 0 | } Unexecuted instantiation: <exr::meta::attribute::Text>::write_u32_sized_le::<_> Unexecuted instantiation: <exr::meta::attribute::Text>::write_u32_sized_le::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> Unexecuted instantiation: <exr::meta::attribute::Text>::write_u32_sized_le::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> |
525 | | |
526 | | /// Without validation, write this instance to the byte stream. |
527 | 1.61k | fn write_unsized_bytes<W: Write>(bytes: &[u8], write: &mut W) -> UnitResult { |
528 | 1.61k | u8::write_slice_le(write, bytes)?; |
529 | 1.61k | Ok(()) |
530 | 1.61k | } Unexecuted instantiation: <exr::meta::attribute::Text>::write_unsized_bytes::<_> Unexecuted instantiation: <exr::meta::attribute::Text>::write_unsized_bytes::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> <exr::meta::attribute::Text>::write_unsized_bytes::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> Line | Count | Source | 527 | 1.61k | fn write_unsized_bytes<W: Write>(bytes: &[u8], write: &mut W) -> UnitResult { | 528 | 1.61k | u8::write_slice_le(write, bytes)?; | 529 | 1.61k | Ok(()) | 530 | 1.61k | } |
|
531 | | |
532 | | /// Read the length of a string and then the contents with that length. |
533 | 28.9k | pub fn read_i32_sized_le<R: Read>(read: &mut R, max_size: usize) -> Result<Self> { |
534 | 28.9k | let size = i32_to_usize(i32::read_le(read)?, "vector size")?; |
535 | 28.9k | Ok(Text::from_bytes_unchecked(SmallVec::from_vec(u8::read_vec_le(read, size, 1024, Some(max_size), "text attribute length")?))) |
536 | 28.9k | } <exr::meta::attribute::Text>::read_i32_sized_le::<exr::io::PeekRead<&[u8]>> Line | Count | Source | 533 | 28.9k | pub fn read_i32_sized_le<R: Read>(read: &mut R, max_size: usize) -> Result<Self> { | 534 | 28.9k | let size = i32_to_usize(i32::read_le(read)?, "vector size")?; | 535 | 28.9k | Ok(Text::from_bytes_unchecked(SmallVec::from_vec(u8::read_vec_le(read, size, 1024, Some(max_size), "text attribute length")?))) | 536 | 28.9k | } |
Unexecuted instantiation: <exr::meta::attribute::Text>::read_i32_sized_le::<_> |
537 | | |
538 | | /// Read the length of a string and then the contents with that length. |
539 | 0 | pub fn read_u32_sized_le<R: Read>(read: &mut R, max_size: usize) -> Result<Self> { |
540 | 0 | let size = u32_to_usize(u32::read_le(read)?, "text length")?; |
541 | 0 | Ok(Text::from_bytes_unchecked(SmallVec::from_vec(u8::read_vec_le(read, size, 1024, Some(max_size), "text attribute length")?))) |
542 | 0 | } Unexecuted instantiation: <exr::meta::attribute::Text>::read_u32_sized_le::<&[u8]> Unexecuted instantiation: <exr::meta::attribute::Text>::read_u32_sized_le::<_> |
543 | | |
544 | | /// Read the contents with that length. |
545 | 257k | 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 | 257k | if size <= SMALL_SIZE { |
550 | 227k | let mut buffer = [0_u8; SMALL_SIZE]; |
551 | 227k | let data = &mut buffer[..size]; |
552 | | |
553 | 227k | read.read_exact(data)?; |
554 | 227k | 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 | 30.6k | Ok(Text::from_bytes_unchecked(SmallVec::from_vec(u8::read_vec_le(read, size, 1024, None, "text attribute length")?))) |
560 | | } |
561 | 257k | } <exr::meta::attribute::Text>::read_sized::<&[u8]> Line | Count | Source | 545 | 257k | 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 | 257k | if size <= SMALL_SIZE { | 550 | 227k | let mut buffer = [0_u8; SMALL_SIZE]; | 551 | 227k | let data = &mut buffer[..size]; | 552 | | | 553 | 227k | read.read_exact(data)?; | 554 | 227k | 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 | 30.6k | Ok(Text::from_bytes_unchecked(SmallVec::from_vec(u8::read_vec_le(read, size, 1024, None, "text attribute length")?))) | 560 | | } | 561 | 257k | } |
Unexecuted instantiation: <exr::meta::attribute::Text>::read_sized::<_> |
562 | | |
563 | | /// Write the string contents and a null-terminator. |
564 | 248 | pub fn write_null_terminated<W: Write>(&self, write: &mut W) -> UnitResult { |
565 | 248 | Self::write_null_terminated_bytes(self.as_slice(), write) |
566 | 248 | } Unexecuted instantiation: <exr::meta::attribute::Text>::write_null_terminated::<_> Unexecuted instantiation: <exr::meta::attribute::Text>::write_null_terminated::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> <exr::meta::attribute::Text>::write_null_terminated::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> Line | Count | Source | 564 | 248 | pub fn write_null_terminated<W: Write>(&self, write: &mut W) -> UnitResult { | 565 | 248 | Self::write_null_terminated_bytes(self.as_slice(), write) | 566 | 248 | } |
|
567 | | |
568 | | /// Write the string contents and a null-terminator. |
569 | 1.61k | fn write_null_terminated_bytes<W: Write>(bytes: &[u8], write: &mut W) -> UnitResult { |
570 | 1.61k | debug_assert!(!bytes.is_empty(), "text is empty bug"); // required to avoid mixup with "sequece_end" |
571 | | |
572 | 1.61k | Text::write_unsized_bytes(bytes, write)?; |
573 | 1.61k | sequence_end::write(write)?; |
574 | 1.61k | Ok(()) |
575 | 1.61k | } Unexecuted instantiation: <exr::meta::attribute::Text>::write_null_terminated_bytes::<_> Unexecuted instantiation: <exr::meta::attribute::Text>::write_null_terminated_bytes::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> <exr::meta::attribute::Text>::write_null_terminated_bytes::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> Line | Count | Source | 569 | 1.61k | fn write_null_terminated_bytes<W: Write>(bytes: &[u8], write: &mut W) -> UnitResult { | 570 | 1.61k | debug_assert!(!bytes.is_empty(), "text is empty bug"); // required to avoid mixup with "sequece_end" | 571 | | | 572 | 1.61k | Text::write_unsized_bytes(bytes, write)?; | 573 | 1.61k | sequence_end::write(write)?; | 574 | 1.61k | Ok(()) | 575 | 1.61k | } |
|
576 | | |
577 | | /// Read a string until the null-terminator is found. Then skips the null-terminator. |
578 | 3.72M | pub fn read_null_terminated<R: Read>(read: &mut R, max_len: usize) -> Result<Self> { |
579 | 3.72M | let mut bytes = smallvec![ u8::read_le(read)? ]; // null-terminated strings are always at least 1 byte |
580 | | |
581 | | loop { |
582 | 38.4M | match u8::read_le(read)? { |
583 | 3.71M | 0 => break, |
584 | 34.7M | non_terminator => bytes.push(non_terminator), |
585 | | } |
586 | | |
587 | 34.7M | if bytes.len() > max_len { |
588 | 56 | return Err(Error::invalid("text too long")) |
589 | 34.7M | } |
590 | | } |
591 | | |
592 | 3.71M | Ok(Text { bytes }) |
593 | 3.72M | } <exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>> Line | Count | Source | 578 | 3.56M | pub fn read_null_terminated<R: Read>(read: &mut R, max_len: usize) -> Result<Self> { | 579 | 3.56M | let mut bytes = smallvec![ u8::read_le(read)? ]; // null-terminated strings are always at least 1 byte | 580 | | | 581 | | loop { | 582 | 37.6M | match u8::read_le(read)? { | 583 | 3.56M | 0 => break, | 584 | 34.0M | non_terminator => bytes.push(non_terminator), | 585 | | } | 586 | | | 587 | 34.0M | if bytes.len() > max_len { | 588 | 52 | return Err(Error::invalid("text too long")) | 589 | 34.0M | } | 590 | | } | 591 | | | 592 | 3.56M | Ok(Text { bytes }) | 593 | 3.56M | } |
<exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<&[u8]>> Line | Count | Source | 578 | 149k | pub fn read_null_terminated<R: Read>(read: &mut R, max_len: usize) -> Result<Self> { | 579 | 149k | let mut bytes = smallvec![ u8::read_le(read)? ]; // null-terminated strings are always at least 1 byte | 580 | | | 581 | | loop { | 582 | 836k | match u8::read_le(read)? { | 583 | 149k | 0 => break, | 584 | 687k | non_terminator => bytes.push(non_terminator), | 585 | | } | 586 | | | 587 | 687k | if bytes.len() > max_len { | 588 | 4 | return Err(Error::invalid("text too long")) | 589 | 687k | } | 590 | | } | 591 | | | 592 | 149k | Ok(Text { bytes }) | 593 | 149k | } |
Unexecuted instantiation: <exr::meta::attribute::Text>::read_null_terminated::<_> <exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>> Line | Count | Source | 578 | 1.36k | pub fn read_null_terminated<R: Read>(read: &mut R, max_len: usize) -> Result<Self> { | 579 | 1.36k | let mut bytes = smallvec![ u8::read_le(read)? ]; // null-terminated strings are always at least 1 byte | 580 | | | 581 | | loop { | 582 | 11.5k | match u8::read_le(read)? { | 583 | 1.36k | 0 => break, | 584 | 10.2k | non_terminator => bytes.push(non_terminator), | 585 | | } | 586 | | | 587 | 10.2k | if bytes.len() > max_len { | 588 | 0 | return Err(Error::invalid("text too long")) | 589 | 10.2k | } | 590 | | } | 591 | | | 592 | 1.36k | Ok(Text { bytes }) | 593 | 1.36k | } |
|
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 | 33.8k | fn read_vec_of_i32_sized_texts_le( |
598 | 33.8k | read: &mut PeekRead<impl Read>, |
599 | 33.8k | total_byte_size: usize |
600 | 33.8k | ) -> Result<Vec<Text>> |
601 | | { |
602 | 33.8k | let mut result = Vec::with_capacity(2); |
603 | | |
604 | | // length of the text-vector can be inferred from attribute size |
605 | 33.8k | let mut processed_bytes = 0; |
606 | | |
607 | 62.7k | while processed_bytes < total_byte_size { |
608 | 28.9k | let text = Text::read_i32_sized_le(read, total_byte_size)?; |
609 | 28.9k | processed_bytes += ::std::mem::size_of::<i32>(); // size i32 of the text |
610 | 28.9k | processed_bytes += text.bytes.len(); |
611 | 28.9k | result.push(text); |
612 | | } |
613 | | |
614 | | // the expected byte size did not match the actual text byte size |
615 | 33.7k | if processed_bytes != total_byte_size { |
616 | 0 | return Err(Error::invalid("text array byte size")) |
617 | 33.7k | } |
618 | | |
619 | 33.7k | Ok(result) |
620 | 33.8k | } <exr::meta::attribute::Text>::read_vec_of_i32_sized_texts_le::<&[u8]> Line | Count | Source | 597 | 33.8k | fn read_vec_of_i32_sized_texts_le( | 598 | 33.8k | read: &mut PeekRead<impl Read>, | 599 | 33.8k | total_byte_size: usize | 600 | 33.8k | ) -> Result<Vec<Text>> | 601 | | { | 602 | 33.8k | let mut result = Vec::with_capacity(2); | 603 | | | 604 | | // length of the text-vector can be inferred from attribute size | 605 | 33.8k | let mut processed_bytes = 0; | 606 | | | 607 | 62.7k | while processed_bytes < total_byte_size { | 608 | 28.9k | let text = Text::read_i32_sized_le(read, total_byte_size)?; | 609 | 28.9k | processed_bytes += ::std::mem::size_of::<i32>(); // size i32 of the text | 610 | 28.9k | processed_bytes += text.bytes.len(); | 611 | 28.9k | result.push(text); | 612 | | } | 613 | | | 614 | | // the expected byte size did not match the actual text byte size | 615 | 33.7k | if processed_bytes != total_byte_size { | 616 | 0 | return Err(Error::invalid("text array byte size")) | 617 | 33.7k | } | 618 | | | 619 | 33.7k | Ok(result) | 620 | 33.8k | } |
Unexecuted instantiation: <exr::meta::attribute::Text>::read_vec_of_i32_sized_texts_le::<_> |
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 | 0 | 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 | 0 | for text in texts { |
627 | 0 | text.write_i32_sized_le(write)?; |
628 | | } |
629 | | |
630 | 0 | Ok(()) |
631 | 0 | } Unexecuted instantiation: <exr::meta::attribute::Text>::write_vec_of_i32_sized_texts_le::<_> Unexecuted instantiation: <exr::meta::attribute::Text>::write_vec_of_i32_sized_texts_le::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> Unexecuted instantiation: <exr::meta::attribute::Text>::write_vec_of_i32_sized_texts_le::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> |
632 | | |
633 | | /// The underlying bytes that represent this text. |
634 | 91.0k | pub fn bytes(&self) -> &[u8] { |
635 | 91.0k | self.bytes.as_slice() |
636 | 91.0k | } |
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 | 806 | pub fn chars(&self) -> impl '_ + Iterator<Item = char> { |
641 | 806 | self.bytes.iter().map(|&byte| byte as char) |
642 | 806 | } |
643 | | |
644 | | /// Compare this `exr::Text` with a plain `&str`. |
645 | 0 | pub fn eq(&self, string: &str) -> bool { |
646 | 0 | string.chars().eq(self.chars()) |
647 | 0 | } |
648 | | |
649 | | /// Compare this `exr::Text` with a plain `&str` ignoring capitalization. |
650 | 806 | 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 | 806 | let self_chars = self.chars().map(|char| char.to_ascii_lowercase()); |
653 | 806 | let string_chars = string.chars().flat_map(|ch| ch.to_lowercase()); |
654 | | |
655 | 806 | string_chars.eq(self_chars) |
656 | 806 | } |
657 | | } |
658 | | |
659 | | impl PartialEq<str> for Text { |
660 | 0 | fn eq(&self, other: &str) -> bool { |
661 | 0 | self.eq(other) |
662 | 0 | } |
663 | | } |
664 | | |
665 | | impl PartialEq<Text> for str { |
666 | 0 | fn eq(&self, other: &Text) -> bool { |
667 | 0 | other.eq(self) |
668 | 0 | } |
669 | | } |
670 | | |
671 | | impl Eq for Text {} |
672 | | |
673 | | impl Borrow<TextSlice> for Text { |
674 | 0 | fn borrow(&self) -> &TextSlice { |
675 | 0 | self.as_slice() |
676 | 0 | } |
677 | | } |
678 | | |
679 | | // forwarding implementation. guarantees `text.borrow().hash() == text.hash()` (required for Borrow) |
680 | | impl Hash for Text { |
681 | 2.11M | fn hash<H: Hasher>(&self, state: &mut H) { |
682 | 2.11M | self.bytes.hash(state) |
683 | 2.11M | } |
684 | | } |
685 | | |
686 | | impl Into<String> for Text { |
687 | 0 | fn into(self) -> String { |
688 | 0 | self.to_string() |
689 | 0 | } |
690 | | } |
691 | | |
692 | | impl<'s> From<&'s str> for Text { |
693 | | |
694 | | /// Panics if the string contains an unsupported character |
695 | 36.9k | fn from(str: &'s str) -> Self { |
696 | 36.9k | Self::new_or_panic(str) |
697 | 36.9k | } |
698 | | } |
699 | | |
700 | | |
701 | | /* TODO (currently conflicts with From<&str>) |
702 | | impl<'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 | | |
715 | | impl ::std::fmt::Debug for Text { |
716 | 0 | fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { |
717 | 0 | write!(f, "exr::Text(\"{}\")", self) |
718 | 0 | } |
719 | | } |
720 | | |
721 | | // automatically implements to_string for us |
722 | | impl ::std::fmt::Display for Text { |
723 | 6.47k | fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { |
724 | | use std::fmt::Write; |
725 | | |
726 | 6.47k | for &byte in self.bytes.iter() { |
727 | 6.47k | f.write_char(byte as char)?; |
728 | | } |
729 | | |
730 | 6.47k | Ok(()) |
731 | 6.47k | } |
732 | | } |
733 | | |
734 | | |
735 | | impl ChannelList { |
736 | | |
737 | | /// Does not validate channel order. |
738 | 61.6k | pub fn new(channels: SmallVec<[ChannelDescription; 5]>) -> Self { |
739 | 61.6k | let uniform_sample_type = { |
740 | 61.6k | if let Some(first) = channels.first() { |
741 | 57.0k | let has_uniform_types = channels.iter().skip(1) |
742 | 73.0k | .all(|chan| chan.sample_type == first.sample_type); |
743 | | |
744 | 57.0k | if has_uniform_types { Some(first.sample_type) } else { None } |
745 | | } |
746 | 4.56k | else { None } |
747 | | }; |
748 | | |
749 | | ChannelList { |
750 | 148k | bytes_per_pixel: channels.iter().map(|channel| channel.sample_type.bytes_per_sample()).sum(), |
751 | 61.6k | list: channels, uniform_sample_type, |
752 | | } |
753 | 61.6k | } |
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 | 22.9k | pub fn channels_with_byte_offset(&self) -> impl Iterator<Item=(usize, &ChannelDescription)> { |
758 | 47.8k | self.list.iter().scan(0, |byte_position, channel|{ |
759 | 47.8k | let previous_position = *byte_position; |
760 | 47.8k | *byte_position += channel.sample_type.bytes_per_sample(); |
761 | 47.8k | Some((previous_position, channel)) |
762 | 47.8k | }) <exr::meta::attribute::ChannelList>::channels_with_byte_offset::{closure#0}Line | Count | Source | 758 | 47.8k | self.list.iter().scan(0, |byte_position, channel|{ | 759 | 47.8k | let previous_position = *byte_position; | 760 | 47.8k | *byte_position += channel.sample_type.bytes_per_sample(); | 761 | 47.8k | Some((previous_position, channel)) | 762 | 47.8k | }) |
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::channels_with_byte_offset::{closure#0} |
763 | 22.9k | } |
764 | | |
765 | | /// Return the index of the channel with the exact name, case sensitive, or none. |
766 | | /// Potentially uses less than linear time. |
767 | 26.0k | pub fn find_index_of_channel(&self, exact_name: &Text) -> Option<usize> { |
768 | 64.9k | self.list.binary_search_by_key(&exact_name.bytes(), |chan| chan.name.bytes()).ok() |
769 | 26.0k | } |
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 | | |
785 | | impl 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 | 10.4k | pub fn parse(text: Text) -> Result<Self> { |
792 | 10.4k | match text.as_slice() { |
793 | 10.4k | block_type_strings::SCAN_LINE => Ok(BlockType::ScanLine), |
794 | 10.1k | block_type_strings::TILE => Ok(BlockType::Tile), |
795 | | |
796 | 2.75k | block_type_strings::DEEP_SCAN_LINE => Ok(BlockType::DeepScanLine), |
797 | 2.71k | block_type_strings::DEEP_TILE => Ok(BlockType::DeepTile), |
798 | | |
799 | 46 | _ => Err(Error::invalid("block type attribute value")), |
800 | | } |
801 | 10.4k | } |
802 | | |
803 | | /// Without validation, write this instance to the byte stream. |
804 | 62 | pub fn write(&self, write: &mut impl Write) -> UnitResult { |
805 | 62 | u8::write_slice_le(write, self.to_text_bytes())?; |
806 | 62 | Ok(()) |
807 | 62 | } Unexecuted instantiation: <exr::meta::attribute::BlockType>::write::<_> Unexecuted instantiation: <exr::meta::attribute::BlockType>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> <exr::meta::attribute::BlockType>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> Line | Count | Source | 804 | 62 | pub fn write(&self, write: &mut impl Write) -> UnitResult { | 805 | 62 | u8::write_slice_le(write, self.to_text_bytes())?; | 806 | 62 | Ok(()) | 807 | 62 | } |
|
808 | | |
809 | | /// Returns the raw attribute text value this type is represented by in a file. |
810 | 124 | pub fn to_text_bytes(&self) -> &[u8] { |
811 | 124 | match self { |
812 | 0 | BlockType::ScanLine => block_type_strings::SCAN_LINE, |
813 | 124 | BlockType::Tile => block_type_strings::TILE, |
814 | 0 | BlockType::DeepScanLine => block_type_strings::DEEP_SCAN_LINE, |
815 | 0 | BlockType::DeepTile => block_type_strings::DEEP_TILE, |
816 | | } |
817 | 124 | } |
818 | | |
819 | | /// Number of bytes this would consume in an exr file. |
820 | 62 | pub fn byte_size(&self) -> usize { |
821 | 62 | self.to_text_bytes().len() |
822 | 62 | } |
823 | | } |
824 | | |
825 | | |
826 | | impl IntegerBounds { |
827 | | |
828 | | /// Create a box with no size located at (0,0). |
829 | 34.9k | pub fn zero() -> Self { |
830 | 34.9k | Self::from_dimensions(Vec2(0, 0)) |
831 | 34.9k | } |
832 | | |
833 | | /// Create a box with a size starting at zero. |
834 | 34.9k | pub fn from_dimensions(size: impl Into<Vec2<usize>>) -> Self { |
835 | 34.9k | Self::new(Vec2(0,0), size) |
836 | 34.9k | } |
837 | | |
838 | | /// Create a box with a size and an origin point. |
839 | 367k | pub fn new(start: impl Into<Vec2<i32>>, size: impl Into<Vec2<usize>>) -> Self { |
840 | 367k | Self { position: start.into(), size: size.into() } |
841 | 367k | } |
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 | 175 | pub fn end(self) -> Vec2<i32> { |
847 | 175 | self.position + self.size.to_i32() // larger than max int32 is panic |
848 | 175 | } |
849 | | |
850 | | /// Returns the maximum coordinate that a value in this rectangle may have. |
851 | 124 | pub fn max(self) -> Vec2<i32> { |
852 | 124 | self.end() - Vec2(1,1) |
853 | 124 | } |
854 | | |
855 | | /// Validate this instance. |
856 | 1.17M | pub fn validate(&self, max_size: Option<Vec2<usize>>) -> UnitResult { |
857 | 1.17M | if let Some(max_size) = max_size { |
858 | 1.09M | if self.size.width() > max_size.width() || self.size.height() > max_size.height() { |
859 | 0 | return Err(Error::invalid("window attribute dimension value")); |
860 | 1.09M | } |
861 | 71.2k | } |
862 | | |
863 | 1.17M | let min_i64 = Vec2(self.position.x() as i64, self.position.y() as i64); |
864 | | |
865 | 1.17M | let max_i64 = Vec2( |
866 | 1.17M | self.position.x() as i64 + self.size.width() as i64, |
867 | 1.17M | self.position.y() as i64 + self.size.height() as i64, |
868 | 1.17M | ); |
869 | | |
870 | 1.17M | Self::validate_min_max_u64(min_i64, max_i64) |
871 | 1.17M | } |
872 | | |
873 | 1.30M | fn validate_min_max_u64(min: Vec2<i64>, max: Vec2<i64>) -> UnitResult { |
874 | 1.30M | let max_box_size_as_i64 = (i32::MAX / 2) as i64; // as defined in the original c++ library |
875 | | |
876 | 1.30M | if max.x() >= max_box_size_as_i64 |
877 | 1.30M | || max.y() >= max_box_size_as_i64 |
878 | 1.30M | || min.x() <= -max_box_size_as_i64 |
879 | 1.30M | || min.y() <= -max_box_size_as_i64 |
880 | | { |
881 | 73 | return Err(Error::invalid("window size exceeding integer maximum")); |
882 | 1.30M | } |
883 | | |
884 | 1.30M | Ok(()) |
885 | 1.30M | } |
886 | | |
887 | | /// Number of bytes this would consume in an exr file. |
888 | 124 | pub fn byte_size() -> usize { |
889 | 124 | 4 * i32::BYTE_SIZE |
890 | 124 | } |
891 | | |
892 | | /// Without validation, write this instance to the byte stream. |
893 | 124 | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { |
894 | 124 | let Vec2(x_min, y_min) = self.position; |
895 | 124 | let Vec2(x_max, y_max) = self.max(); |
896 | | |
897 | 124 | x_min.write_le(write)?; |
898 | 124 | y_min.write_le(write)?; |
899 | 124 | x_max.write_le(write)?; |
900 | 124 | y_max.write_le(write)?; |
901 | 124 | Ok(()) |
902 | 124 | } Unexecuted instantiation: <exr::meta::attribute::IntegerBounds>::write::<_> Unexecuted instantiation: <exr::meta::attribute::IntegerBounds>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> <exr::meta::attribute::IntegerBounds>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> Line | Count | Source | 893 | 124 | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { | 894 | 124 | let Vec2(x_min, y_min) = self.position; | 895 | 124 | let Vec2(x_max, y_max) = self.max(); | 896 | | | 897 | 124 | x_min.write_le(write)?; | 898 | 124 | y_min.write_le(write)?; | 899 | 124 | x_max.write_le(write)?; | 900 | 124 | y_max.write_le(write)?; | 901 | 124 | Ok(()) | 902 | 124 | } |
|
903 | | |
904 | | /// Read the value without validating. |
905 | 129k | pub fn read<R: Read>(read: &mut R) -> Result<Self> { |
906 | 129k | let x_min = i32::read_le(read)?; |
907 | 129k | let y_min = i32::read_le(read)?; |
908 | 129k | let x_max = i32::read_le(read)?; |
909 | 129k | let y_max = i32::read_le(read)?; |
910 | | |
911 | 129k | let min = Vec2(x_min.min(x_max), y_min.min(y_max)); |
912 | 129k | let max = Vec2(x_min.max(x_max), y_min.max(y_max)); |
913 | | |
914 | | // prevent addition overflow |
915 | 129k | Self::validate_min_max_u64( |
916 | 129k | Vec2(min.x() as i64, min.y() as i64), |
917 | 129k | Vec2(max.x() as i64, max.y() as i64), |
918 | 69 | )?; |
919 | | |
920 | | // add one to max because the max inclusive, but the size is not |
921 | 129k | let size = Vec2(max.x() + 1 - min.x(), max.y() + 1 - min.y()); |
922 | 129k | let size = size.to_usize("box coordinates")?; |
923 | | |
924 | 129k | Ok(IntegerBounds { position: min, size }) |
925 | 129k | } <exr::meta::attribute::IntegerBounds>::read::<&[u8]> Line | Count | Source | 905 | 129k | pub fn read<R: Read>(read: &mut R) -> Result<Self> { | 906 | 129k | let x_min = i32::read_le(read)?; | 907 | 129k | let y_min = i32::read_le(read)?; | 908 | 129k | let x_max = i32::read_le(read)?; | 909 | 129k | let y_max = i32::read_le(read)?; | 910 | | | 911 | 129k | let min = Vec2(x_min.min(x_max), y_min.min(y_max)); | 912 | 129k | let max = Vec2(x_min.max(x_max), y_min.max(y_max)); | 913 | | | 914 | | // prevent addition overflow | 915 | 129k | Self::validate_min_max_u64( | 916 | 129k | Vec2(min.x() as i64, min.y() as i64), | 917 | 129k | Vec2(max.x() as i64, max.y() as i64), | 918 | 69 | )?; | 919 | | | 920 | | // add one to max because the max inclusive, but the size is not | 921 | 129k | let size = Vec2(max.x() + 1 - min.x(), max.y() + 1 - min.y()); | 922 | 129k | let size = size.to_usize("box coordinates")?; | 923 | | | 924 | 129k | Ok(IntegerBounds { position: min, size }) | 925 | 129k | } |
Unexecuted instantiation: <exr::meta::attribute::IntegerBounds>::read::<_> |
926 | | |
927 | | /// Create a new rectangle which is offset by the specified origin. |
928 | 0 | pub fn with_origin(self, origin: Vec2<i32>) -> Self { // TODO rename to "move" or "translate"? |
929 | 0 | IntegerBounds { position: self.position + origin, .. self } |
930 | 0 | } |
931 | | |
932 | | /// Returns whether the specified rectangle is equal to or inside this rectangle. |
933 | 0 | pub fn contains(self, subset: Self) -> bool { |
934 | 0 | subset.position.x() >= self.position.x() |
935 | 0 | && subset.position.y() >= self.position.y() |
936 | 0 | && subset.end().x() <= self.end().x() |
937 | 0 | && subset.end().y() <= self.end().y() |
938 | 0 | } |
939 | | } |
940 | | |
941 | | |
942 | | impl FloatRect { |
943 | | |
944 | | /// Number of bytes this would consume in an exr file. |
945 | 0 | pub fn byte_size() -> usize { |
946 | 0 | 4 * f32::BYTE_SIZE |
947 | 0 | } |
948 | | |
949 | | /// Without validation, write this instance to the byte stream. |
950 | 0 | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { |
951 | 0 | self.min.x().write_le(write)?; |
952 | 0 | self.min.y().write_le(write)?; |
953 | 0 | self.max.x().write_le(write)?; |
954 | 0 | self.max.y().write_le(write)?; |
955 | 0 | Ok(()) |
956 | 0 | } Unexecuted instantiation: <exr::meta::attribute::FloatRect>::write::<_> Unexecuted instantiation: <exr::meta::attribute::FloatRect>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> Unexecuted instantiation: <exr::meta::attribute::FloatRect>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> |
957 | | |
958 | | /// Read the value without validating. |
959 | 885 | pub fn read<R: Read>(read: &mut R) -> Result<Self> { |
960 | 885 | let x_min = f32::read_le(read)?; |
961 | 883 | let y_min = f32::read_le(read)?; |
962 | 882 | let x_max = f32::read_le(read)?; |
963 | 881 | let y_max = f32::read_le(read)?; |
964 | | |
965 | 880 | Ok(FloatRect { |
966 | 880 | min: Vec2(x_min, y_min), |
967 | 880 | max: Vec2(x_max, y_max) |
968 | 880 | }) |
969 | 885 | } <exr::meta::attribute::FloatRect>::read::<&[u8]> Line | Count | Source | 959 | 885 | pub fn read<R: Read>(read: &mut R) -> Result<Self> { | 960 | 885 | let x_min = f32::read_le(read)?; | 961 | 883 | let y_min = f32::read_le(read)?; | 962 | 882 | let x_max = f32::read_le(read)?; | 963 | 881 | let y_max = f32::read_le(read)?; | 964 | | | 965 | 880 | Ok(FloatRect { | 966 | 880 | min: Vec2(x_min, y_min), | 967 | 880 | max: Vec2(x_max, y_max) | 968 | 880 | }) | 969 | 885 | } |
Unexecuted instantiation: <exr::meta::attribute::FloatRect>::read::<_> |
970 | | } |
971 | | |
972 | | impl SampleType { |
973 | | |
974 | | /// How many bytes a single sample takes up. |
975 | 103M | pub fn bytes_per_sample(&self) -> usize { |
976 | 103M | match self { |
977 | 115k | SampleType::F16 => f16::BYTE_SIZE, |
978 | 102M | SampleType::F32 => f32::BYTE_SIZE, |
979 | 81.2k | SampleType::U32 => u32::BYTE_SIZE, |
980 | | } |
981 | 103M | } |
982 | | |
983 | | /// Number of bytes this would consume in an exr file. |
984 | 248 | pub fn byte_size() -> usize { |
985 | 248 | i32::BYTE_SIZE |
986 | 248 | } |
987 | | |
988 | | /// Without validation, write this instance to the byte stream. |
989 | 248 | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { |
990 | 248 | match *self { |
991 | 0 | SampleType::U32 => 0_i32, |
992 | 0 | SampleType::F16 => 1_i32, |
993 | 248 | SampleType::F32 => 2_i32, |
994 | 248 | }.write_le(write)?; |
995 | | |
996 | 248 | Ok(()) |
997 | 248 | } Unexecuted instantiation: <exr::meta::attribute::SampleType>::write::<_> Unexecuted instantiation: <exr::meta::attribute::SampleType>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> <exr::meta::attribute::SampleType>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> Line | Count | Source | 989 | 248 | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { | 990 | 248 | match *self { | 991 | 0 | SampleType::U32 => 0_i32, | 992 | 0 | SampleType::F16 => 1_i32, | 993 | 248 | SampleType::F32 => 2_i32, | 994 | 248 | }.write_le(write)?; | 995 | | | 996 | 248 | Ok(()) | 997 | 248 | } |
|
998 | | |
999 | | /// Read the value without validating. |
1000 | 149k | 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 | 149k | Ok(match i32::read_le(read)? { |
1003 | 62.8k | 0 => SampleType::U32, |
1004 | 75.2k | 1 => SampleType::F16, |
1005 | 10.9k | 2 => SampleType::F32, |
1006 | 52 | _ => return Err(Error::invalid("pixel type attribute value")), |
1007 | | }) |
1008 | 149k | } <exr::meta::attribute::SampleType>::read::<exr::io::PeekRead<&[u8]>> Line | Count | Source | 1000 | 149k | 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 | 149k | Ok(match i32::read_le(read)? { | 1003 | 62.8k | 0 => SampleType::U32, | 1004 | 75.2k | 1 => SampleType::F16, | 1005 | 10.9k | 2 => SampleType::F32, | 1006 | 52 | _ => return Err(Error::invalid("pixel type attribute value")), | 1007 | | }) | 1008 | 149k | } |
Unexecuted instantiation: <exr::meta::attribute::SampleType>::read::<_> |
1009 | | } |
1010 | | |
1011 | | impl 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 | 248 | pub fn guess_quantization_linearity(name: &Text) -> bool { |
1015 | | !( |
1016 | 248 | name.eq_case_insensitive("R") || name.eq_case_insensitive("G") || |
1017 | 124 | name.eq_case_insensitive("B") || name.eq_case_insensitive("L") || |
1018 | 62 | name.eq_case_insensitive("Y") || name.eq_case_insensitive("X") || |
1019 | 62 | name.eq_case_insensitive("Z") |
1020 | | ) |
1021 | 248 | } |
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 | 248 | pub fn named(name: impl Into<Text>, sample_type: SampleType) -> Self { |
1026 | 248 | let name = name.into(); |
1027 | 248 | let linearity = Self::guess_quantization_linearity(&name); |
1028 | 248 | Self::new(name, sample_type, linearity) |
1029 | 248 | } Unexecuted instantiation: <exr::meta::attribute::ChannelDescription>::named::<_> Unexecuted instantiation: <exr::meta::attribute::ChannelDescription>::named::<&str> <exr::meta::attribute::ChannelDescription>::named::<&str> Line | Count | Source | 1025 | 248 | pub fn named(name: impl Into<Text>, sample_type: SampleType) -> Self { | 1026 | 248 | let name = name.into(); | 1027 | 248 | let linearity = Self::guess_quantization_linearity(&name); | 1028 | 248 | Self::new(name, sample_type, linearity) | 1029 | 248 | } |
|
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 | 248 | pub fn new(name: impl Into<Text>, sample_type: SampleType, quantize_linearly: bool) -> Self { |
1037 | 248 | Self { name: name.into(), sample_type, quantize_linearly, sampling: Vec2(1, 1) } |
1038 | 248 | } Unexecuted instantiation: <exr::meta::attribute::ChannelDescription>::new::<_> Unexecuted instantiation: <exr::meta::attribute::ChannelDescription>::new::<exr::meta::attribute::Text> <exr::meta::attribute::ChannelDescription>::new::<exr::meta::attribute::Text> Line | Count | Source | 1036 | 248 | pub fn new(name: impl Into<Text>, sample_type: SampleType, quantize_linearly: bool) -> Self { | 1037 | 248 | Self { name: name.into(), sample_type, quantize_linearly, sampling: Vec2(1, 1) } | 1038 | 248 | } |
|
1039 | | |
1040 | | /// The count of pixels this channel contains, respecting subsampling. |
1041 | | // FIXME this must be used everywhere |
1042 | 0 | pub fn subsampled_pixels(&self, dimensions: Vec2<usize>) -> usize { |
1043 | 0 | self.subsampled_resolution(dimensions).area() |
1044 | 0 | } |
1045 | | |
1046 | | /// The resolution pf this channel, respecting subsampling. |
1047 | 397 | pub fn subsampled_resolution(&self, dimensions: Vec2<usize>) -> Vec2<usize> { |
1048 | 397 | dimensions / self.sampling |
1049 | 397 | } |
1050 | | |
1051 | | /// Number of bytes this would consume in an exr file. |
1052 | 248 | pub fn byte_size(&self) -> usize { |
1053 | 248 | self.name.null_terminated_byte_size() |
1054 | 248 | + SampleType::byte_size() |
1055 | 248 | + 1 // is_linear |
1056 | 248 | + 3 // reserved bytes |
1057 | 248 | + 2 * u32::BYTE_SIZE // sampling x, y |
1058 | 248 | } |
1059 | | |
1060 | | /// Without validation, write this instance to the byte stream. |
1061 | 248 | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { |
1062 | 248 | Text::write_null_terminated(&self.name, write)?; |
1063 | 248 | self.sample_type.write(write)?; |
1064 | | |
1065 | 248 | match self.quantize_linearly { |
1066 | 186 | false => 0_u8, |
1067 | 62 | true => 1_u8, |
1068 | 248 | }.write_le(write)?; |
1069 | | |
1070 | 248 | i8::write_slice_le(write, &[0_i8, 0_i8, 0_i8])?; |
1071 | 248 | i32::write_le(usize_to_i32(self.sampling.x(), "text length")?, write)?; |
1072 | 248 | i32::write_le(usize_to_i32(self.sampling.y(), "text length")?, write)?; |
1073 | 248 | Ok(()) |
1074 | 248 | } Unexecuted instantiation: <exr::meta::attribute::ChannelDescription>::write::<_> Unexecuted instantiation: <exr::meta::attribute::ChannelDescription>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> <exr::meta::attribute::ChannelDescription>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> Line | Count | Source | 1061 | 248 | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { | 1062 | 248 | Text::write_null_terminated(&self.name, write)?; | 1063 | 248 | self.sample_type.write(write)?; | 1064 | | | 1065 | 248 | match self.quantize_linearly { | 1066 | 186 | false => 0_u8, | 1067 | 62 | true => 1_u8, | 1068 | 248 | }.write_le(write)?; | 1069 | | | 1070 | 248 | i8::write_slice_le(write, &[0_i8, 0_i8, 0_i8])?; | 1071 | 248 | i32::write_le(usize_to_i32(self.sampling.x(), "text length")?, write)?; | 1072 | 248 | i32::write_le(usize_to_i32(self.sampling.y(), "text length")?, write)?; | 1073 | 248 | Ok(()) | 1074 | 248 | } |
|
1075 | | |
1076 | | /// Read the value without validating. |
1077 | 149k | pub fn read<R: Read>(read: &mut R) -> Result<Self> { |
1078 | 149k | let name = Text::read_null_terminated(read, 256)?; |
1079 | 149k | let sample_type = SampleType::read(read)?; |
1080 | | |
1081 | 148k | let is_linear = match u8::read_le(read)? { |
1082 | 13.9k | 1 => true, |
1083 | 134k | 0 => false, |
1084 | 3 | _ => return Err(Error::invalid("channel linearity attribute value")), |
1085 | | }; |
1086 | | |
1087 | 148k | let mut reserved = [0_i8; 3]; |
1088 | 148k | i8::read_slice_le(read, &mut reserved)?; |
1089 | | |
1090 | 148k | let x_sampling = i32_to_usize(i32::read_le(read)?, "x channel sampling")?; |
1091 | 148k | let y_sampling = i32_to_usize(i32::read_le(read)?, "y channel sampling")?; |
1092 | | |
1093 | 148k | Ok(ChannelDescription { |
1094 | 148k | name, sample_type, |
1095 | 148k | quantize_linearly: is_linear, |
1096 | 148k | sampling: Vec2(x_sampling, y_sampling), |
1097 | 148k | }) |
1098 | 149k | } <exr::meta::attribute::ChannelDescription>::read::<exr::io::PeekRead<&[u8]>> Line | Count | Source | 1077 | 149k | pub fn read<R: Read>(read: &mut R) -> Result<Self> { | 1078 | 149k | let name = Text::read_null_terminated(read, 256)?; | 1079 | 149k | let sample_type = SampleType::read(read)?; | 1080 | | | 1081 | 148k | let is_linear = match u8::read_le(read)? { | 1082 | 13.9k | 1 => true, | 1083 | 134k | 0 => false, | 1084 | 3 | _ => return Err(Error::invalid("channel linearity attribute value")), | 1085 | | }; | 1086 | | | 1087 | 148k | let mut reserved = [0_i8; 3]; | 1088 | 148k | i8::read_slice_le(read, &mut reserved)?; | 1089 | | | 1090 | 148k | let x_sampling = i32_to_usize(i32::read_le(read)?, "x channel sampling")?; | 1091 | 148k | let y_sampling = i32_to_usize(i32::read_le(read)?, "y channel sampling")?; | 1092 | | | 1093 | 148k | Ok(ChannelDescription { | 1094 | 148k | name, sample_type, | 1095 | 148k | quantize_linearly: is_linear, | 1096 | 148k | sampling: Vec2(x_sampling, y_sampling), | 1097 | 148k | }) | 1098 | 149k | } |
Unexecuted instantiation: <exr::meta::attribute::ChannelDescription>::read::<_> |
1099 | | |
1100 | | /// Validate this instance. |
1101 | 63.9k | pub fn validate(&self, allow_sampling: bool, data_window: IntegerBounds, strict: bool) -> UnitResult { |
1102 | 63.9k | self.name.validate(true, None)?; // TODO spec says this does not affect `requirements.long_names` but is that true? |
1103 | | |
1104 | 63.9k | if self.sampling.x() == 0 || self.sampling.y() == 0 { |
1105 | 17 | return Err(Error::invalid("zero sampling factor")); |
1106 | 63.8k | } |
1107 | | |
1108 | 63.8k | if strict && !allow_sampling && self.sampling != Vec2(1,1) { |
1109 | 0 | return Err(Error::invalid("subsampling is only allowed in flat scan line images")); |
1110 | 63.8k | } |
1111 | | |
1112 | 63.8k | if data_window.position.x() % self.sampling.x() as i32 != 0 || data_window.position.y() % self.sampling.y() as i32 != 0 { |
1113 | 92 | return Err(Error::invalid("channel sampling factor not dividing data window position")); |
1114 | 63.8k | } |
1115 | | |
1116 | 63.8k | if data_window.size.x() % self.sampling.x() != 0 || data_window.size.y() % self.sampling.y() != 0 { |
1117 | 13 | return Err(Error::invalid("channel sampling factor not dividing data window size")); |
1118 | 63.7k | } |
1119 | | |
1120 | 63.7k | 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 | 2 | return Err(Error::unsupported("channel subsampling not supported yet")); |
1125 | 63.7k | } |
1126 | | |
1127 | 63.7k | Ok(()) |
1128 | 63.9k | } |
1129 | | } |
1130 | | |
1131 | | impl ChannelList { |
1132 | | |
1133 | | /// Number of bytes this would consume in an exr file. |
1134 | 62 | pub fn byte_size(&self) -> usize { |
1135 | 62 | self.list.iter().map(ChannelDescription::byte_size).sum::<usize>() + sequence_end::byte_size() |
1136 | 62 | } |
1137 | | |
1138 | | /// Without validation, write this instance to the byte stream. |
1139 | | /// Assumes channels are sorted alphabetically and all values are validated. |
1140 | 62 | pub fn write(&self, write: &mut impl Write) -> UnitResult { |
1141 | 310 | for channel in &self.list { |
1142 | 248 | channel.write(write)?; |
1143 | | } |
1144 | | |
1145 | 62 | sequence_end::write(write)?; |
1146 | 62 | Ok(()) |
1147 | 62 | } Unexecuted instantiation: <exr::meta::attribute::ChannelList>::write::<_> Unexecuted instantiation: <exr::meta::attribute::ChannelList>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> <exr::meta::attribute::ChannelList>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> Line | Count | Source | 1140 | 62 | pub fn write(&self, write: &mut impl Write) -> UnitResult { | 1141 | 310 | for channel in &self.list { | 1142 | 248 | channel.write(write)?; | 1143 | | } | 1144 | | | 1145 | 62 | sequence_end::write(write)?; | 1146 | 62 | Ok(()) | 1147 | 62 | } |
|
1148 | | |
1149 | | /// Read the value without validating. |
1150 | 61.7k | pub fn read(read: &mut PeekRead<impl Read>) -> Result<Self> { |
1151 | 61.7k | let mut channels = SmallVec::new(); |
1152 | 210k | while !sequence_end::has_come(read)? { |
1153 | 149k | channels.push(ChannelDescription::read(read)?); |
1154 | | } |
1155 | | |
1156 | 61.5k | Ok(ChannelList::new(channels)) |
1157 | 61.7k | } <exr::meta::attribute::ChannelList>::read::<&[u8]> Line | Count | Source | 1150 | 61.7k | pub fn read(read: &mut PeekRead<impl Read>) -> Result<Self> { | 1151 | 61.7k | let mut channels = SmallVec::new(); | 1152 | 210k | while !sequence_end::has_come(read)? { | 1153 | 149k | channels.push(ChannelDescription::read(read)?); | 1154 | | } | 1155 | | | 1156 | 61.5k | Ok(ChannelList::new(channels)) | 1157 | 61.7k | } |
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::read::<_> |
1158 | | |
1159 | | /// Check if channels are valid and sorted. |
1160 | 25.1k | pub fn validate(&self, allow_sampling: bool, data_window: IntegerBounds, strict: bool) -> UnitResult { |
1161 | 63.9k | let mut iter = self.list.iter().map(|chan| chan.validate(allow_sampling, data_window, strict).map(|_| &chan.name)); |
1162 | 25.1k | let mut previous = iter.next().ok_or(Error::invalid("at least one channel is required"))??; |
1163 | | |
1164 | 63.7k | for result in iter { |
1165 | 38.7k | let value = result?; |
1166 | 38.6k | if strict && previous == value { return Err(Error::invalid("channel names are not unique")); } |
1167 | 38.6k | else if previous > value { return Err(Error::invalid("channel names are not sorted alphabetically")); } |
1168 | 38.6k | else { previous = value; } |
1169 | | } |
1170 | | |
1171 | 25.0k | Ok(()) |
1172 | 25.1k | } |
1173 | | } |
1174 | | |
1175 | 0 | fn u8_to_decimal32(binary: u8) -> u32 { |
1176 | 0 | let units = binary as u32 % 10; |
1177 | 0 | let tens = (binary as u32 / 10) % 10; |
1178 | 0 | units | (tens << 4) |
1179 | 0 | } |
1180 | | |
1181 | | // assumes value fits into u8 |
1182 | 87.3k | fn u8_from_decimal32(coded: u32) -> u8 { |
1183 | 87.3k | ((coded & 0x0f) + 10 * ((coded >> 4) & 0x0f)) as u8 |
1184 | 87.3k | } |
1185 | | |
1186 | | // https://github.com/AcademySoftwareFoundation/openexr/blob/master/src/lib/OpenEXR/ImfTimeCode.cpp |
1187 | | impl 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 | 6.24k | pub fn validate(&self, strict: bool) -> UnitResult { |
1194 | 6.24k | if strict { |
1195 | 0 | if self.frame > 29 { Err(Error::invalid("time code frame larger than 29")) } |
1196 | 0 | else if self.seconds > 59 { Err(Error::invalid("time code seconds larger than 59")) } |
1197 | 0 | else if self.minutes > 59 { Err(Error::invalid("time code minutes larger than 59")) } |
1198 | 0 | else if self.hours > 23 { Err(Error::invalid("time code hours larger than 23")) } |
1199 | 0 | else if self.binary_groups.iter().any(|&group| group > 15) { |
1200 | 0 | Err(Error::invalid("time code binary group value too large for 3 bits")) |
1201 | | } |
1202 | 0 | else { Ok(()) } |
1203 | | } |
1204 | 6.24k | else { Ok(()) } |
1205 | 6.24k | } |
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 | 0 | pub fn pack_time_as_tv60_u32(&self) -> Result<u32> { |
1211 | | // validate strictly to prevent set_bit panic! below |
1212 | 0 | self.validate(true)?; |
1213 | | |
1214 | 0 | Ok(*0_u32 |
1215 | 0 | .set_bits(0..6, u8_to_decimal32(self.frame)) |
1216 | 0 | .set_bit(6, self.drop_frame) |
1217 | 0 | .set_bit(7, self.color_frame) |
1218 | 0 | .set_bits(8..15, u8_to_decimal32(self.seconds)) |
1219 | 0 | .set_bit(15, self.field_phase) |
1220 | 0 | .set_bits(16..23, u8_to_decimal32(self.minutes)) |
1221 | 0 | .set_bit(23, self.binary_group_flags[0]) |
1222 | 0 | .set_bits(24..30, u8_to_decimal32(self.hours)) |
1223 | 0 | .set_bit(30, self.binary_group_flags[1]) |
1224 | 0 | .set_bit(31, self.binary_group_flags[2]) |
1225 | 0 | ) |
1226 | 0 | } |
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 | 21.8k | pub fn from_tv60_time(tv60_time: u32, user_data: u32) -> Self { |
1231 | 21.8k | Self { |
1232 | 21.8k | frame: u8_from_decimal32(tv60_time.get_bits(0..6)), // cast cannot fail, as these are less than 8 bits |
1233 | 21.8k | drop_frame: tv60_time.get_bit(6), |
1234 | 21.8k | color_frame: tv60_time.get_bit(7), |
1235 | 21.8k | seconds: u8_from_decimal32(tv60_time.get_bits(8..15)), // cast cannot fail, as these are less than 8 bits |
1236 | 21.8k | field_phase: tv60_time.get_bit(15), |
1237 | 21.8k | minutes: u8_from_decimal32(tv60_time.get_bits(16..23)), // cast cannot fail, as these are less than 8 bits |
1238 | 21.8k | hours: u8_from_decimal32(tv60_time.get_bits(24..30)), // cast cannot fail, as these are less than 8 bits |
1239 | 21.8k | binary_group_flags: [ |
1240 | 21.8k | tv60_time.get_bit(23), |
1241 | 21.8k | tv60_time.get_bit(30), |
1242 | 21.8k | tv60_time.get_bit(31), |
1243 | 21.8k | ], |
1244 | 21.8k | |
1245 | 21.8k | binary_groups: Self::unpack_user_data_from_u32(user_data) |
1246 | 21.8k | } |
1247 | 21.8k | } |
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 | 0 | pub fn pack_time_as_tv50_u32(&self) -> Result<u32> { |
1252 | 0 | Ok(*self.pack_time_as_tv60_u32()? |
1253 | | |
1254 | | // swap some fields by replacing some bits in the packed u32 |
1255 | 0 | .set_bit(6, false) |
1256 | 0 | .set_bit(15, self.binary_group_flags[0]) |
1257 | 0 | .set_bit(30, self.binary_group_flags[1]) |
1258 | 0 | .set_bit(23, self.binary_group_flags[2]) |
1259 | 0 | .set_bit(31, self.field_phase) |
1260 | | ) |
1261 | 0 | } |
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 | 0 | pub fn from_tv50_time(tv50_time: u32, user_data: u32) -> Self { |
1266 | 0 | Self { |
1267 | 0 | drop_frame: false, // do not use bit [6] |
1268 | 0 |
|
1269 | 0 | // swap some fields: |
1270 | 0 | field_phase: tv50_time.get_bit(31), |
1271 | 0 | binary_group_flags: [ |
1272 | 0 | tv50_time.get_bit(15), |
1273 | 0 | tv50_time.get_bit(30), |
1274 | 0 | tv50_time.get_bit(23), |
1275 | 0 | ], |
1276 | 0 |
|
1277 | 0 | .. Self::from_tv60_time(tv50_time, user_data) |
1278 | 0 | } |
1279 | 0 | } |
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 | 0 | pub fn pack_time_as_film24_u32(&self) -> Result<u32> { |
1285 | 0 | Ok(*self.pack_time_as_tv60_u32()? |
1286 | 0 | .set_bit(6, false) |
1287 | 0 | .set_bit(7, false) |
1288 | | ) |
1289 | 0 | } |
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 | 0 | pub fn from_film24_time(film24_time: u32, user_data: u32) -> Self { |
1294 | 0 | Self { |
1295 | 0 | drop_frame: false, // bit [6] |
1296 | 0 | color_frame: false, // bit [7] |
1297 | 0 | .. Self::from_tv60_time(film24_time, user_data) |
1298 | 0 | } |
1299 | 0 | } |
1300 | | |
1301 | | |
1302 | | // in rust, group index starts at zero, not at one. |
1303 | 174k | fn user_data_bit_indices(group_index: usize) -> std::ops::Range<usize> { |
1304 | 174k | let min_bit = 4 * group_index; |
1305 | 174k | min_bit .. min_bit + 4 // +4, not +3, as `Range` is exclusive |
1306 | 174k | } |
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 | 0 | pub fn pack_user_data_as_u32(&self) -> u32 { |
1311 | 0 | let packed = self.binary_groups.iter().enumerate().fold(0_u32, |mut packed, (group_index, group_value)| |
1312 | 0 | *packed.set_bits(Self::user_data_bit_indices(group_index), *group_value.min(&15) as u32) |
1313 | | ); |
1314 | | |
1315 | 0 | debug_assert_eq!(Self::unpack_user_data_from_u32(packed), self.binary_groups, "round trip user data encoding"); |
1316 | 0 | packed |
1317 | 0 | } |
1318 | | |
1319 | | // Unpack the encoded u32 user data to an array of bytes, each byte having a value from 0 to 4. |
1320 | 21.8k | fn unpack_user_data_from_u32(user_data: u32) -> [u8; 8] { |
1321 | 174k | (0..8).map(|group_index| user_data.get_bits(Self::user_data_bit_indices(group_index)) as u8) |
1322 | 21.8k | .collect::<SmallVec<[u8;8]>>().into_inner().expect("array index bug") |
1323 | 21.8k | } |
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 | 0 | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { |
1329 | 0 | self.pack_time_as_tv60_u32()?.write_le(write)?; // will validate |
1330 | 0 | self.pack_user_data_as_u32().write_le(write)?; |
1331 | 0 | Ok(()) |
1332 | 0 | } Unexecuted instantiation: <exr::meta::attribute::TimeCode>::write::<_> Unexecuted instantiation: <exr::meta::attribute::TimeCode>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> Unexecuted instantiation: <exr::meta::attribute::TimeCode>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> |
1333 | | |
1334 | | /// Read the time code, without validating, extracting from TV60 integers. |
1335 | 21.8k | pub fn read<R: Read>(read: &mut R) -> Result<Self> { |
1336 | 21.8k | let time_and_flags = u32::read_le(read)?; |
1337 | 21.8k | let user_data = u32::read_le(read)?; |
1338 | 21.8k | Ok(Self::from_tv60_time(time_and_flags, user_data)) |
1339 | 21.8k | } <exr::meta::attribute::TimeCode>::read::<&[u8]> Line | Count | Source | 1335 | 21.8k | pub fn read<R: Read>(read: &mut R) -> Result<Self> { | 1336 | 21.8k | let time_and_flags = u32::read_le(read)?; | 1337 | 21.8k | let user_data = u32::read_le(read)?; | 1338 | 21.8k | Ok(Self::from_tv60_time(time_and_flags, user_data)) | 1339 | 21.8k | } |
Unexecuted instantiation: <exr::meta::attribute::TimeCode>::read::<_> |
1340 | | } |
1341 | | |
1342 | | impl Chromaticities { |
1343 | | |
1344 | | /// Number of bytes this would consume in an exr file. |
1345 | 0 | pub fn byte_size() -> usize { |
1346 | 0 | 8 * f32::BYTE_SIZE |
1347 | 0 | } |
1348 | | |
1349 | | /// Without validation, write this instance to the byte stream. |
1350 | 0 | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { |
1351 | 0 | self.red.x().write_le(write)?; |
1352 | 0 | self.red.y().write_le(write)?; |
1353 | | |
1354 | 0 | self.green.x().write_le(write)?; |
1355 | 0 | self.green.y().write_le(write)?; |
1356 | | |
1357 | 0 | self.blue.x().write_le(write)?; |
1358 | 0 | self.blue.y().write_le(write)?; |
1359 | | |
1360 | 0 | self.white.x().write_le(write)?; |
1361 | 0 | self.white.y().write_le(write)?; |
1362 | 0 | Ok(()) |
1363 | 0 | } Unexecuted instantiation: <exr::meta::attribute::Chromaticities>::write::<_> Unexecuted instantiation: <exr::meta::attribute::Chromaticities>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> Unexecuted instantiation: <exr::meta::attribute::Chromaticities>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> |
1364 | | |
1365 | | /// Read the value without validating. |
1366 | 5.41k | pub fn read<R: Read>(read: &mut R) -> Result<Self> { |
1367 | | Ok(Chromaticities { |
1368 | 5.41k | red: Vec2(f32::read_le(read)?, f32::read_le(read)?), |
1369 | 5.41k | green: Vec2(f32::read_le(read)?, f32::read_le(read)?), |
1370 | 5.41k | blue: Vec2(f32::read_le(read)?, f32::read_le(read)?), |
1371 | 5.41k | white: Vec2(f32::read_le(read)?, f32::read_le(read)?), |
1372 | | }) |
1373 | 5.41k | } <exr::meta::attribute::Chromaticities>::read::<&[u8]> Line | Count | Source | 1366 | 5.41k | pub fn read<R: Read>(read: &mut R) -> Result<Self> { | 1367 | | Ok(Chromaticities { | 1368 | 5.41k | red: Vec2(f32::read_le(read)?, f32::read_le(read)?), | 1369 | 5.41k | green: Vec2(f32::read_le(read)?, f32::read_le(read)?), | 1370 | 5.41k | blue: Vec2(f32::read_le(read)?, f32::read_le(read)?), | 1371 | 5.41k | white: Vec2(f32::read_le(read)?, f32::read_le(read)?), | 1372 | | }) | 1373 | 5.41k | } |
Unexecuted instantiation: <exr::meta::attribute::Chromaticities>::read::<_> |
1374 | | } |
1375 | | |
1376 | | impl Compression { |
1377 | | |
1378 | | /// Number of bytes this would consume in an exr file. |
1379 | 62 | pub fn byte_size() -> usize { u8::BYTE_SIZE } |
1380 | | |
1381 | | /// Without validation, write this instance to the byte stream. |
1382 | 62 | pub fn write<W: Write>(self, write: &mut W) -> UnitResult { |
1383 | | use self::Compression::*; |
1384 | 62 | match self { |
1385 | 0 | Uncompressed => 0_u8, |
1386 | 62 | RLE => 1_u8, |
1387 | 0 | ZIP1 => 2_u8, |
1388 | 0 | ZIP16 => 3_u8, |
1389 | 0 | PIZ => 4_u8, |
1390 | 0 | PXR24 => 5_u8, |
1391 | 0 | B44 => 6_u8, |
1392 | 0 | B44A => 7_u8, |
1393 | 0 | DWAA(_) => 8_u8, |
1394 | 0 | DWAB(_) => 9_u8, |
1395 | 0 | HTJ2K256 => 10_u8, |
1396 | 0 | HTJ2K32 => 11_u8, |
1397 | 62 | }.write_le(write)?; |
1398 | 62 | Ok(()) |
1399 | 62 | } Unexecuted instantiation: <exr::compression::Compression>::write::<_> Unexecuted instantiation: <exr::compression::Compression>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> <exr::compression::Compression>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> Line | Count | Source | 1382 | 62 | pub fn write<W: Write>(self, write: &mut W) -> UnitResult { | 1383 | | use self::Compression::*; | 1384 | 62 | match self { | 1385 | 0 | Uncompressed => 0_u8, | 1386 | 62 | RLE => 1_u8, | 1387 | 0 | ZIP1 => 2_u8, | 1388 | 0 | ZIP16 => 3_u8, | 1389 | 0 | PIZ => 4_u8, | 1390 | 0 | PXR24 => 5_u8, | 1391 | 0 | B44 => 6_u8, | 1392 | 0 | B44A => 7_u8, | 1393 | 0 | DWAA(_) => 8_u8, | 1394 | 0 | DWAB(_) => 9_u8, | 1395 | 0 | HTJ2K256 => 10_u8, | 1396 | 0 | HTJ2K32 => 11_u8, | 1397 | 62 | }.write_le(write)?; | 1398 | 62 | Ok(()) | 1399 | 62 | } |
|
1400 | | |
1401 | | /// Read the value without validating. |
1402 | 56.4k | pub fn read<R: Read>(read: &mut R) -> Result<Self> { |
1403 | | use self::Compression::*; |
1404 | 56.4k | Ok(match u8::read_le(read)? { |
1405 | 14.0k | 0 => Uncompressed, |
1406 | 1.65k | 1 => RLE, |
1407 | 5.96k | 2 => ZIP1, |
1408 | 8 | 3 => ZIP16, |
1409 | 12.9k | 4 => PIZ, |
1410 | 164 | 5 => PXR24, |
1411 | 12 | 6 => B44, |
1412 | 20.5k | 7 => B44A, |
1413 | 14 | 8 => DWAA(None), |
1414 | 1.12k | 9 => DWAB(None), |
1415 | 2 | 10 => HTJ2K256, |
1416 | 0 | 11 => HTJ2K32, |
1417 | 4 | _ => return Err(Error::unsupported("unknown compression method")), |
1418 | | }) |
1419 | 56.4k | } <exr::compression::Compression>::read::<&[u8]> Line | Count | Source | 1402 | 56.4k | pub fn read<R: Read>(read: &mut R) -> Result<Self> { | 1403 | | use self::Compression::*; | 1404 | 56.4k | Ok(match u8::read_le(read)? { | 1405 | 14.0k | 0 => Uncompressed, | 1406 | 1.65k | 1 => RLE, | 1407 | 5.96k | 2 => ZIP1, | 1408 | 8 | 3 => ZIP16, | 1409 | 12.9k | 4 => PIZ, | 1410 | 164 | 5 => PXR24, | 1411 | 12 | 6 => B44, | 1412 | 20.5k | 7 => B44A, | 1413 | 14 | 8 => DWAA(None), | 1414 | 1.12k | 9 => DWAB(None), | 1415 | 2 | 10 => HTJ2K256, | 1416 | 0 | 11 => HTJ2K32, | 1417 | 4 | _ => return Err(Error::unsupported("unknown compression method")), | 1418 | | }) | 1419 | 56.4k | } |
Unexecuted instantiation: <exr::compression::Compression>::read::<_> |
1420 | | } |
1421 | | |
1422 | | impl EnvironmentMap { |
1423 | | |
1424 | | /// Number of bytes this would consume in an exr file. |
1425 | 0 | pub fn byte_size() -> usize { |
1426 | 0 | u8::BYTE_SIZE |
1427 | 0 | } |
1428 | | |
1429 | | /// Without validation, write this instance to the byte stream. |
1430 | 0 | pub fn write<W: Write>(self, write: &mut W) -> UnitResult { |
1431 | | use self::EnvironmentMap::*; |
1432 | 0 | match self { |
1433 | 0 | LatitudeLongitude => 0_u8, |
1434 | 0 | Cube => 1_u8 |
1435 | 0 | }.write_le(write)?; |
1436 | | |
1437 | 0 | Ok(()) |
1438 | 0 | } Unexecuted instantiation: <exr::meta::attribute::EnvironmentMap>::write::<_> Unexecuted instantiation: <exr::meta::attribute::EnvironmentMap>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> Unexecuted instantiation: <exr::meta::attribute::EnvironmentMap>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> |
1439 | | |
1440 | | /// Read the value without validating. |
1441 | 1.02k | pub fn read<R: Read>(read: &mut R) -> Result<Self> { |
1442 | | use self::EnvironmentMap::*; |
1443 | 1.02k | Ok(match u8::read_le(read)? { |
1444 | 959 | 0 => LatitudeLongitude, |
1445 | 65 | 1 => Cube, |
1446 | 0 | _ => return Err(Error::invalid("environment map attribute value")), |
1447 | | }) |
1448 | 1.02k | } <exr::meta::attribute::EnvironmentMap>::read::<&[u8]> Line | Count | Source | 1441 | 1.02k | pub fn read<R: Read>(read: &mut R) -> Result<Self> { | 1442 | | use self::EnvironmentMap::*; | 1443 | 1.02k | Ok(match u8::read_le(read)? { | 1444 | 959 | 0 => LatitudeLongitude, | 1445 | 65 | 1 => Cube, | 1446 | 0 | _ => return Err(Error::invalid("environment map attribute value")), | 1447 | | }) | 1448 | 1.02k | } |
Unexecuted instantiation: <exr::meta::attribute::EnvironmentMap>::read::<_> |
1449 | | } |
1450 | | |
1451 | | impl KeyCode { |
1452 | | |
1453 | | /// Number of bytes this would consume in an exr file. |
1454 | 0 | pub fn byte_size() -> usize { |
1455 | 0 | 6 * i32::BYTE_SIZE |
1456 | 0 | } |
1457 | | |
1458 | | /// Without validation, write this instance to the byte stream. |
1459 | 0 | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { |
1460 | 0 | self.film_manufacturer_code.write_le(write)?; |
1461 | 0 | self.film_type.write_le(write)?; |
1462 | 0 | self.film_roll_prefix.write_le(write)?; |
1463 | 0 | self.count.write_le(write)?; |
1464 | 0 | self.perforation_offset.write_le(write)?; |
1465 | 0 | self.perforations_per_count.write_le(write)?; |
1466 | 0 | Ok(()) |
1467 | 0 | } Unexecuted instantiation: <exr::meta::attribute::KeyCode>::write::<_> Unexecuted instantiation: <exr::meta::attribute::KeyCode>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> Unexecuted instantiation: <exr::meta::attribute::KeyCode>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> |
1468 | | |
1469 | | /// Read the value without validating. |
1470 | 5.23k | pub fn read<R: Read>(read: &mut R) -> Result<Self> { |
1471 | | Ok(KeyCode { |
1472 | 5.23k | film_manufacturer_code: i32::read_le(read)?, |
1473 | 5.23k | film_type: i32::read_le(read)?, |
1474 | 5.23k | film_roll_prefix: i32::read_le(read)?, |
1475 | 5.23k | count: i32::read_le(read)?, |
1476 | 5.23k | perforation_offset: i32::read_le(read)?, |
1477 | 5.23k | perforations_per_frame: i32::read_le(read)?, |
1478 | 5.23k | perforations_per_count: i32::read_le(read)?, |
1479 | | }) |
1480 | 5.23k | } <exr::meta::attribute::KeyCode>::read::<&[u8]> Line | Count | Source | 1470 | 5.23k | pub fn read<R: Read>(read: &mut R) -> Result<Self> { | 1471 | | Ok(KeyCode { | 1472 | 5.23k | film_manufacturer_code: i32::read_le(read)?, | 1473 | 5.23k | film_type: i32::read_le(read)?, | 1474 | 5.23k | film_roll_prefix: i32::read_le(read)?, | 1475 | 5.23k | count: i32::read_le(read)?, | 1476 | 5.23k | perforation_offset: i32::read_le(read)?, | 1477 | 5.23k | perforations_per_frame: i32::read_le(read)?, | 1478 | 5.23k | perforations_per_count: i32::read_le(read)?, | 1479 | | }) | 1480 | 5.23k | } |
Unexecuted instantiation: <exr::meta::attribute::KeyCode>::read::<_> |
1481 | | } |
1482 | | |
1483 | | impl LineOrder { |
1484 | | |
1485 | | /// Number of bytes this would consume in an exr file. |
1486 | 62 | pub fn byte_size() -> usize { |
1487 | 62 | u8::BYTE_SIZE |
1488 | 62 | } |
1489 | | |
1490 | | /// Without validation, write this instance to the byte stream. |
1491 | 62 | pub fn write<W: Write>(self, write: &mut W) -> UnitResult { |
1492 | | use self::LineOrder::*; |
1493 | 62 | match self { |
1494 | 0 | Increasing => 0_u8, |
1495 | 0 | Decreasing => 1_u8, |
1496 | 62 | Unspecified => 2_u8, |
1497 | 62 | }.write_le(write)?; |
1498 | | |
1499 | 62 | Ok(()) |
1500 | 62 | } Unexecuted instantiation: <exr::meta::attribute::LineOrder>::write::<_> Unexecuted instantiation: <exr::meta::attribute::LineOrder>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> <exr::meta::attribute::LineOrder>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> Line | Count | Source | 1491 | 62 | pub fn write<W: Write>(self, write: &mut W) -> UnitResult { | 1492 | | use self::LineOrder::*; | 1493 | 62 | match self { | 1494 | 0 | Increasing => 0_u8, | 1495 | 0 | Decreasing => 1_u8, | 1496 | 62 | Unspecified => 2_u8, | 1497 | 62 | }.write_le(write)?; | 1498 | | | 1499 | 62 | Ok(()) | 1500 | 62 | } |
|
1501 | | |
1502 | | /// Read the value without validating. |
1503 | 8.52k | pub fn read<R: Read>(read: &mut R) -> Result<Self> { |
1504 | | use self::LineOrder::*; |
1505 | 8.52k | Ok(match u8::read_le(read)? { |
1506 | 7.85k | 0 => Increasing, |
1507 | 597 | 1 => Decreasing, |
1508 | 62 | 2 => Unspecified, |
1509 | 1 | _ => return Err(Error::invalid("line order attribute value")), |
1510 | | }) |
1511 | 8.52k | } <exr::meta::attribute::LineOrder>::read::<&[u8]> Line | Count | Source | 1503 | 8.52k | pub fn read<R: Read>(read: &mut R) -> Result<Self> { | 1504 | | use self::LineOrder::*; | 1505 | 8.52k | Ok(match u8::read_le(read)? { | 1506 | 7.85k | 0 => Increasing, | 1507 | 597 | 1 => Decreasing, | 1508 | 62 | 2 => Unspecified, | 1509 | 1 | _ => return Err(Error::invalid("line order attribute value")), | 1510 | | }) | 1511 | 8.52k | } |
Unexecuted instantiation: <exr::meta::attribute::LineOrder>::read::<_> |
1512 | | } |
1513 | | |
1514 | | |
1515 | | |
1516 | | |
1517 | | impl Preview { |
1518 | | |
1519 | | /// Number of bytes this would consume in an exr file. |
1520 | 0 | pub fn byte_size(&self) -> usize { |
1521 | 0 | 2 * u32::BYTE_SIZE + self.pixel_data.len() |
1522 | 0 | } |
1523 | | |
1524 | | /// Without validation, write this instance to the byte stream. |
1525 | 0 | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { |
1526 | 0 | u32::write_le(self.size.width() as u32, write)?; |
1527 | 0 | u32::write_le(self.size.height() as u32, write)?; |
1528 | | |
1529 | 0 | i8::write_slice_le(write, &self.pixel_data)?; |
1530 | 0 | Ok(()) |
1531 | 0 | } Unexecuted instantiation: <exr::meta::attribute::Preview>::write::<_> Unexecuted instantiation: <exr::meta::attribute::Preview>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> Unexecuted instantiation: <exr::meta::attribute::Preview>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> |
1532 | | |
1533 | | /// Read the value without validating. |
1534 | 4.66k | pub fn read<R: Read>(read: &mut R) -> Result<Self> { |
1535 | 4.66k | let width = u32::read_le(read)? as usize; |
1536 | 4.66k | let height = u32::read_le(read)? as usize; |
1537 | | |
1538 | 4.66k | if let Some(pixel_count) = width.checked_mul(height) { |
1539 | | // Multiply by the number of bytes per pixel. |
1540 | 4.66k | if let Some(byte_count) = pixel_count.checked_mul(4) { |
1541 | 4.66k | let pixel_data = i8::read_vec_le( |
1542 | 4.66k | read, |
1543 | 4.66k | byte_count, |
1544 | 4.66k | 1024 * 1024 * 4, |
1545 | 4.66k | None, |
1546 | | "preview attribute pixel count", |
1547 | 3 | )?; |
1548 | | |
1549 | 4.66k | let preview = Preview { |
1550 | 4.66k | size: Vec2(width, height), |
1551 | 4.66k | pixel_data, |
1552 | 4.66k | }; |
1553 | | |
1554 | 4.66k | return Ok(preview); |
1555 | 0 | } |
1556 | 0 | } |
1557 | | |
1558 | 0 | return Err(Error::invalid( |
1559 | 0 | format!("Overflow while calculating preview image Attribute size \ |
1560 | 0 | (width: {}, height: {}).", |
1561 | 0 | width, |
1562 | 0 | height))); |
1563 | 4.66k | } <exr::meta::attribute::Preview>::read::<&[u8]> Line | Count | Source | 1534 | 4.66k | pub fn read<R: Read>(read: &mut R) -> Result<Self> { | 1535 | 4.66k | let width = u32::read_le(read)? as usize; | 1536 | 4.66k | let height = u32::read_le(read)? as usize; | 1537 | | | 1538 | 4.66k | if let Some(pixel_count) = width.checked_mul(height) { | 1539 | | // Multiply by the number of bytes per pixel. | 1540 | 4.66k | if let Some(byte_count) = pixel_count.checked_mul(4) { | 1541 | 4.66k | let pixel_data = i8::read_vec_le( | 1542 | 4.66k | read, | 1543 | 4.66k | byte_count, | 1544 | 4.66k | 1024 * 1024 * 4, | 1545 | 4.66k | None, | 1546 | | "preview attribute pixel count", | 1547 | 3 | )?; | 1548 | | | 1549 | 4.66k | let preview = Preview { | 1550 | 4.66k | size: Vec2(width, height), | 1551 | 4.66k | pixel_data, | 1552 | 4.66k | }; | 1553 | | | 1554 | 4.66k | return Ok(preview); | 1555 | 0 | } | 1556 | 0 | } | 1557 | | | 1558 | 0 | return Err(Error::invalid( | 1559 | 0 | format!("Overflow while calculating preview image Attribute size \ | 1560 | 0 | (width: {}, height: {}).", | 1561 | 0 | width, | 1562 | 0 | height))); | 1563 | 4.66k | } |
Unexecuted instantiation: <exr::meta::attribute::Preview>::read::<_> |
1564 | | |
1565 | | /// Validate this instance. |
1566 | 1.39k | pub fn validate(&self, strict: bool) -> UnitResult { |
1567 | 1.39k | if strict && (self.size.area() * 4 != self.pixel_data.len()) { |
1568 | 0 | return Err(Error::invalid("preview dimensions do not match content length")) |
1569 | 1.39k | } |
1570 | | |
1571 | 1.39k | Ok(()) |
1572 | 1.39k | } |
1573 | | } |
1574 | | |
1575 | | impl ::std::fmt::Debug for Preview { |
1576 | 0 | fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { |
1577 | 0 | write!(f, "Preview ({}x{} px)", self.size.width(), self.size.height()) |
1578 | 0 | } |
1579 | | } |
1580 | | |
1581 | | impl TileDescription { |
1582 | | |
1583 | | /// Number of bytes this would consume in an exr file. |
1584 | 62 | pub fn byte_size() -> usize { |
1585 | 62 | 2 * u32::BYTE_SIZE + 1 // size x,y + (level mode + rounding mode) |
1586 | 62 | } |
1587 | | |
1588 | | /// Without validation, write this instance to the byte stream. |
1589 | 62 | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { |
1590 | 62 | u32::write_le(self.tile_size.width() as u32, write)?; |
1591 | 62 | u32::write_le(self.tile_size.height() as u32, write)?; |
1592 | | |
1593 | 62 | let level_mode = match self.level_mode { |
1594 | 62 | LevelMode::Singular => 0_u8, |
1595 | 0 | LevelMode::MipMap => 1_u8, |
1596 | 0 | LevelMode::RipMap => 2_u8, |
1597 | | }; |
1598 | | |
1599 | 62 | let rounding_mode = match self.rounding_mode { |
1600 | 62 | RoundingMode::Down => 0_u8, |
1601 | 0 | RoundingMode::Up => 1_u8, |
1602 | | }; |
1603 | | |
1604 | 62 | let mode: u8 = level_mode + (rounding_mode * 16); |
1605 | 62 | mode.write_le(write)?; |
1606 | 62 | Ok(()) |
1607 | 62 | } Unexecuted instantiation: <exr::meta::attribute::TileDescription>::write::<_> Unexecuted instantiation: <exr::meta::attribute::TileDescription>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> <exr::meta::attribute::TileDescription>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> Line | Count | Source | 1589 | 62 | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { | 1590 | 62 | u32::write_le(self.tile_size.width() as u32, write)?; | 1591 | 62 | u32::write_le(self.tile_size.height() as u32, write)?; | 1592 | | | 1593 | 62 | let level_mode = match self.level_mode { | 1594 | 62 | LevelMode::Singular => 0_u8, | 1595 | 0 | LevelMode::MipMap => 1_u8, | 1596 | 0 | LevelMode::RipMap => 2_u8, | 1597 | | }; | 1598 | | | 1599 | 62 | let rounding_mode = match self.rounding_mode { | 1600 | 62 | RoundingMode::Down => 0_u8, | 1601 | 0 | RoundingMode::Up => 1_u8, | 1602 | | }; | 1603 | | | 1604 | 62 | let mode: u8 = level_mode + (rounding_mode * 16); | 1605 | 62 | mode.write_le(write)?; | 1606 | 62 | Ok(()) | 1607 | 62 | } |
|
1608 | | |
1609 | | /// Read the value without validating. |
1610 | 18.6k | pub fn read<R: Read>(read: &mut R) -> Result<Self> { |
1611 | 18.6k | let x_size = u32::read_le(read)? as usize; |
1612 | 18.6k | let y_size = u32::read_le(read)? as usize; |
1613 | | |
1614 | 18.6k | let mode = u8::read_le(read)?; |
1615 | | |
1616 | | // wow you really saved that one byte here |
1617 | | // mode = level_mode + (rounding_mode * 16) |
1618 | 18.6k | let level_mode = mode & 0b00001111; // wow that works |
1619 | 18.6k | let rounding_mode = mode >> 4; // wow that works |
1620 | | |
1621 | 18.6k | let level_mode = match level_mode { |
1622 | 8.47k | 0 => LevelMode::Singular, |
1623 | 3.95k | 1 => LevelMode::MipMap, |
1624 | 6.24k | 2 => LevelMode::RipMap, |
1625 | 1 | _ => return Err(Error::invalid("tile description level mode")), |
1626 | | }; |
1627 | | |
1628 | 18.6k | let rounding_mode = match rounding_mode { |
1629 | 10.8k | 0 => RoundingMode::Down, |
1630 | 7.81k | 1 => RoundingMode::Up, |
1631 | 3 | _ => return Err(Error::invalid("tile description rounding mode")), |
1632 | | }; |
1633 | | |
1634 | 18.6k | Ok(TileDescription { tile_size: Vec2(x_size, y_size), level_mode, rounding_mode, }) |
1635 | 18.6k | } <exr::meta::attribute::TileDescription>::read::<&[u8]> Line | Count | Source | 1610 | 18.6k | pub fn read<R: Read>(read: &mut R) -> Result<Self> { | 1611 | 18.6k | let x_size = u32::read_le(read)? as usize; | 1612 | 18.6k | let y_size = u32::read_le(read)? as usize; | 1613 | | | 1614 | 18.6k | let mode = u8::read_le(read)?; | 1615 | | | 1616 | | // wow you really saved that one byte here | 1617 | | // mode = level_mode + (rounding_mode * 16) | 1618 | 18.6k | let level_mode = mode & 0b00001111; // wow that works | 1619 | 18.6k | let rounding_mode = mode >> 4; // wow that works | 1620 | | | 1621 | 18.6k | let level_mode = match level_mode { | 1622 | 8.47k | 0 => LevelMode::Singular, | 1623 | 3.95k | 1 => LevelMode::MipMap, | 1624 | 6.24k | 2 => LevelMode::RipMap, | 1625 | 1 | _ => return Err(Error::invalid("tile description level mode")), | 1626 | | }; | 1627 | | | 1628 | 18.6k | let rounding_mode = match rounding_mode { | 1629 | 10.8k | 0 => RoundingMode::Down, | 1630 | 7.81k | 1 => RoundingMode::Up, | 1631 | 3 | _ => return Err(Error::invalid("tile description rounding mode")), | 1632 | | }; | 1633 | | | 1634 | 18.6k | Ok(TileDescription { tile_size: Vec2(x_size, y_size), level_mode, rounding_mode, }) | 1635 | 18.6k | } |
Unexecuted instantiation: <exr::meta::attribute::TileDescription>::read::<_> |
1636 | | |
1637 | | /// Validate this instance. |
1638 | 13.6k | pub fn validate(&self) -> UnitResult { |
1639 | 13.6k | let max = i32::MAX as i64 / 2; |
1640 | | |
1641 | 13.6k | if self.tile_size.width() == 0 || self.tile_size.height() == 0 |
1642 | 13.6k | || self.tile_size.width() as i64 >= max || self.tile_size.height() as i64 >= max |
1643 | | { |
1644 | 12 | return Err(Error::invalid("tile size")) |
1645 | 13.6k | } |
1646 | | |
1647 | 13.6k | Ok(()) |
1648 | 13.6k | } |
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? |
1654 | 0 | pub fn byte_size(name: &Text, value: &AttributeValue) -> usize { |
1655 | 0 | name.null_terminated_byte_size() |
1656 | 0 | + value.kind_name().len() + sequence_end::byte_size() |
1657 | 0 | + i32::BYTE_SIZE // serialized byte size |
1658 | 0 | + value.byte_size() |
1659 | 0 | } |
1660 | | |
1661 | | /// Without validation, write this attribute to the byte stream. |
1662 | 682 | pub fn write<W: Write>(name: &TextSlice, value: &AttributeValue, write: &mut W) -> UnitResult { |
1663 | 682 | Text::write_null_terminated_bytes(name, write)?; |
1664 | 682 | Text::write_null_terminated_bytes(value.kind_name(), write)?; |
1665 | 682 | i32::write_le(value.byte_size() as i32, write)?; |
1666 | 682 | value.write(write) |
1667 | 682 | } Unexecuted instantiation: exr::meta::attribute::write::<_> Unexecuted instantiation: exr::meta::attribute::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> exr::meta::attribute::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> Line | Count | Source | 1662 | 682 | pub fn write<W: Write>(name: &TextSlice, value: &AttributeValue, write: &mut W) -> UnitResult { | 1663 | 682 | Text::write_null_terminated_bytes(name, write)?; | 1664 | 682 | Text::write_null_terminated_bytes(value.kind_name(), write)?; | 1665 | 682 | i32::write_le(value.byte_size() as i32, write)?; | 1666 | 682 | value.write(write) | 1667 | 682 | } |
|
1668 | | |
1669 | | /// Read the attribute without validating. The result may be `Ok` even if this single attribute is invalid. |
1670 | 1.78M | pub fn read(read: &mut PeekRead<impl Read>, max_size: usize) -> Result<(Text, Result<AttributeValue>)> { |
1671 | 1.78M | let name = Text::read_null_terminated(read, max_size)?; |
1672 | 1.78M | let kind = Text::read_null_terminated(read, max_size)?; |
1673 | 1.78M | let size = i32_to_usize(i32::read_le(read)?, "attribute size")?; |
1674 | 1.78M | let value = AttributeValue::read(read, kind, size)?; |
1675 | 1.78M | Ok((name, value)) |
1676 | 1.78M | } exr::meta::attribute::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>> Line | Count | Source | 1670 | 1.78M | pub fn read(read: &mut PeekRead<impl Read>, max_size: usize) -> Result<(Text, Result<AttributeValue>)> { | 1671 | 1.78M | let name = Text::read_null_terminated(read, max_size)?; | 1672 | 1.78M | let kind = Text::read_null_terminated(read, max_size)?; | 1673 | 1.78M | let size = i32_to_usize(i32::read_le(read)?, "attribute size")?; | 1674 | 1.78M | let value = AttributeValue::read(read, kind, size)?; | 1675 | 1.78M | Ok((name, value)) | 1676 | 1.78M | } |
Unexecuted instantiation: exr::meta::attribute::read::<_> exr::meta::attribute::read::<exr::io::Tracking<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> Line | Count | Source | 1670 | 682 | pub fn read(read: &mut PeekRead<impl Read>, max_size: usize) -> Result<(Text, Result<AttributeValue>)> { | 1671 | 682 | let name = Text::read_null_terminated(read, max_size)?; | 1672 | 682 | let kind = Text::read_null_terminated(read, max_size)?; | 1673 | 682 | let size = i32_to_usize(i32::read_le(read)?, "attribute size")?; | 1674 | 682 | let value = AttributeValue::read(read, kind, size)?; | 1675 | 682 | Ok((name, value)) | 1676 | 682 | } |
|
1677 | | |
1678 | | /// Validate this attribute. |
1679 | 290k | pub fn validate(name: &Text, value: &AttributeValue, long_names: &mut bool, allow_sampling: bool, data_window: IntegerBounds, strict: bool) -> UnitResult { |
1680 | 290k | name.validate(true, Some(long_names))?; // only name text has length restriction |
1681 | 290k | value.validate(allow_sampling, data_window, strict) // attribute value text length is never restricted |
1682 | 290k | } |
1683 | | |
1684 | | |
1685 | | impl AttributeValue { |
1686 | | |
1687 | | /// Number of bytes this would consume in an exr file. |
1688 | 682 | pub fn byte_size(&self) -> usize { |
1689 | | use self::AttributeValue::*; |
1690 | | |
1691 | 682 | match *self { |
1692 | 124 | IntegerBounds(_) => self::IntegerBounds::byte_size(), |
1693 | 0 | FloatRect(_) => self::FloatRect::byte_size(), |
1694 | | |
1695 | 62 | I32(_) => i32::BYTE_SIZE, |
1696 | 124 | F32(_) => f32::BYTE_SIZE, |
1697 | 0 | F64(_) => f64::BYTE_SIZE, |
1698 | | |
1699 | 0 | Rational(_) => { i32::BYTE_SIZE + u32::BYTE_SIZE }, |
1700 | 0 | TimeCode(_) => self::TimeCode::BYTE_SIZE, |
1701 | | |
1702 | 0 | IntVec2(_) => { 2 * i32::BYTE_SIZE }, |
1703 | 62 | FloatVec2(_) => { 2 * f32::BYTE_SIZE }, |
1704 | 0 | IntVec3(_) => { 3 * i32::BYTE_SIZE }, |
1705 | 0 | FloatVec3(_) => { 3 * f32::BYTE_SIZE }, |
1706 | | |
1707 | 62 | ChannelList(ref channels) => channels.byte_size(), |
1708 | 0 | Chromaticities(_) => self::Chromaticities::byte_size(), |
1709 | 62 | Compression(_) => self::Compression::byte_size(), |
1710 | 0 | EnvironmentMap(_) => self::EnvironmentMap::byte_size(), |
1711 | | |
1712 | 0 | KeyCode(_) => self::KeyCode::byte_size(), |
1713 | 62 | LineOrder(_) => self::LineOrder::byte_size(), |
1714 | | |
1715 | 0 | Matrix3x3(ref value) => value.len() * f32::BYTE_SIZE, |
1716 | 0 | Matrix4x4(ref value) => value.len() * f32::BYTE_SIZE, |
1717 | | |
1718 | 0 | 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 | 0 | Text(ref value) => value.bytes.len(), |
1723 | | |
1724 | 0 | TextVector(ref value) => value.iter().map(self::Text::i32_sized_byte_size).sum(), |
1725 | 62 | TileDescription(_) => self::TileDescription::byte_size(), |
1726 | 0 | Custom { ref bytes, .. } => bytes.len(), |
1727 | 62 | BlockType(ref kind) => kind.byte_size(), |
1728 | | |
1729 | 0 | Bytes { ref bytes, ref type_hint } => |
1730 | 0 | type_hint.u32_sized_byte_size() + bytes.len(), |
1731 | | } |
1732 | 682 | } |
1733 | | |
1734 | | /// The exr name string of the type that an attribute can have. |
1735 | 682 | pub fn kind_name(&self) -> &TextSlice { |
1736 | | use self::AttributeValue::*; |
1737 | | use self::type_names as ty; |
1738 | | |
1739 | 682 | match *self { |
1740 | 124 | IntegerBounds(_) => ty::I32BOX2, |
1741 | 0 | FloatRect(_) => ty::F32BOX2, |
1742 | 62 | I32(_) => ty::I32, |
1743 | 124 | F32(_) => ty::F32, |
1744 | 0 | F64(_) => ty::F64, |
1745 | 0 | Rational(_) => ty::RATIONAL, |
1746 | 0 | TimeCode(_) => ty::TIME_CODE, |
1747 | 0 | IntVec2(_) => ty::I32VEC2, |
1748 | 62 | FloatVec2(_) => ty::F32VEC2, |
1749 | 0 | IntVec3(_) => ty::I32VEC3, |
1750 | 0 | FloatVec3(_) => ty::F32VEC3, |
1751 | 62 | ChannelList(_) => ty::CHANNEL_LIST, |
1752 | 0 | Chromaticities(_) => ty::CHROMATICITIES, |
1753 | 62 | Compression(_) => ty::COMPRESSION, |
1754 | 0 | EnvironmentMap(_) => ty::ENVIRONMENT_MAP, |
1755 | 0 | KeyCode(_) => ty::KEY_CODE, |
1756 | 62 | LineOrder(_) => ty::LINE_ORDER, |
1757 | 0 | Matrix3x3(_) => ty::F32MATRIX3X3, |
1758 | 0 | Matrix4x4(_) => ty::F32MATRIX4X4, |
1759 | 0 | Preview(_) => ty::PREVIEW, |
1760 | 0 | Text(_) => ty::TEXT, |
1761 | 0 | TextVector(_) => ty::TEXT_VECTOR, |
1762 | 62 | TileDescription(_) => ty::TILES, |
1763 | 62 | BlockType(_) => super::BlockType::TYPE_NAME, |
1764 | 0 | Bytes{ .. } => ty::BYTES, |
1765 | 0 | Custom { ref kind, .. } => kind.as_slice(), |
1766 | | } |
1767 | 682 | } |
1768 | | |
1769 | | /// Without validation, write this instance to the byte stream. |
1770 | 682 | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { |
1771 | | use self::AttributeValue::*; |
1772 | 682 | match *self { |
1773 | 124 | IntegerBounds(value) => value.write(write)?, |
1774 | 0 | FloatRect(value) => value.write(write)?, |
1775 | | |
1776 | 62 | I32(value) => value.write_le(write)?, |
1777 | 124 | F32(value) => value.write_le(write)?, |
1778 | 0 | F64(value) => value.write_le(write)?, |
1779 | | |
1780 | 0 | Rational((a, b)) => { a.write_le(write)?; b.write_le(write)?; }, |
1781 | 0 | TimeCode(codes) => codes.write(write)?, |
1782 | | |
1783 | 0 | IntVec2(Vec2(x, y)) => { x.write_le(write)?; y.write_le(write)?; }, |
1784 | 62 | FloatVec2(Vec2(x, y)) => { x.write_le(write)?; y.write_le(write)?; }, |
1785 | 0 | IntVec3((x, y, z)) => { x.write_le(write)?; y.write_le(write)?; z.write_le(write)?; }, |
1786 | 0 | FloatVec3((x, y, z)) => { x.write_le(write)?; y.write_le(write)?; z.write_le(write)?; }, |
1787 | | |
1788 | 62 | ChannelList(ref channels) => channels.write(write)?, |
1789 | 0 | Chromaticities(ref value) => value.write(write)?, |
1790 | 62 | Compression(value) => value.write(write)?, |
1791 | 0 | EnvironmentMap(value) => value.write(write)?, |
1792 | | |
1793 | 0 | KeyCode(value) => value.write(write)?, |
1794 | 62 | LineOrder(value) => value.write(write)?, |
1795 | | |
1796 | 0 | Matrix3x3(mut value) => f32::write_slice_le(write, &mut value)?, |
1797 | 0 | Matrix4x4(mut value) => f32::write_slice_le(write, &mut value)?, |
1798 | | |
1799 | 0 | 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 | 0 | Text(ref value) => u8::write_slice_le(write, value.bytes.as_slice())?, |
1804 | | |
1805 | 0 | TextVector(ref value) => self::Text::write_vec_of_i32_sized_texts_le(write, value)?, |
1806 | 62 | TileDescription(ref value) => value.write(write)?, |
1807 | 62 | BlockType(kind) => kind.write(write)?, |
1808 | | |
1809 | 0 | Bytes { ref type_hint, ref bytes } => { |
1810 | 0 | type_hint.write_u32_sized_le(write)?; // no idea why this one is u32, everything else is usually i32... |
1811 | 0 | u8::write_slice_le(write, bytes.as_slice())? |
1812 | | } |
1813 | | |
1814 | 0 | Custom { ref bytes, .. } => u8::write_slice_le(write, &bytes)?, // write.write(&bytes).map(|_| ()), |
1815 | | }; |
1816 | | |
1817 | 682 | Ok(()) |
1818 | 682 | } Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::write::<_> Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> <exr::meta::attribute::AttributeValue>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>> Line | Count | Source | 1770 | 682 | pub fn write<W: Write>(&self, write: &mut W) -> UnitResult { | 1771 | | use self::AttributeValue::*; | 1772 | 682 | match *self { | 1773 | 124 | IntegerBounds(value) => value.write(write)?, | 1774 | 0 | FloatRect(value) => value.write(write)?, | 1775 | | | 1776 | 62 | I32(value) => value.write_le(write)?, | 1777 | 124 | F32(value) => value.write_le(write)?, | 1778 | 0 | F64(value) => value.write_le(write)?, | 1779 | | | 1780 | 0 | Rational((a, b)) => { a.write_le(write)?; b.write_le(write)?; }, | 1781 | 0 | TimeCode(codes) => codes.write(write)?, | 1782 | | | 1783 | 0 | IntVec2(Vec2(x, y)) => { x.write_le(write)?; y.write_le(write)?; }, | 1784 | 62 | FloatVec2(Vec2(x, y)) => { x.write_le(write)?; y.write_le(write)?; }, | 1785 | 0 | IntVec3((x, y, z)) => { x.write_le(write)?; y.write_le(write)?; z.write_le(write)?; }, | 1786 | 0 | FloatVec3((x, y, z)) => { x.write_le(write)?; y.write_le(write)?; z.write_le(write)?; }, | 1787 | | | 1788 | 62 | ChannelList(ref channels) => channels.write(write)?, | 1789 | 0 | Chromaticities(ref value) => value.write(write)?, | 1790 | 62 | Compression(value) => value.write(write)?, | 1791 | 0 | EnvironmentMap(value) => value.write(write)?, | 1792 | | | 1793 | 0 | KeyCode(value) => value.write(write)?, | 1794 | 62 | LineOrder(value) => value.write(write)?, | 1795 | | | 1796 | 0 | Matrix3x3(mut value) => f32::write_slice_le(write, &mut value)?, | 1797 | 0 | Matrix4x4(mut value) => f32::write_slice_le(write, &mut value)?, | 1798 | | | 1799 | 0 | 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 | 0 | Text(ref value) => u8::write_slice_le(write, value.bytes.as_slice())?, | 1804 | | | 1805 | 0 | TextVector(ref value) => self::Text::write_vec_of_i32_sized_texts_le(write, value)?, | 1806 | 62 | TileDescription(ref value) => value.write(write)?, | 1807 | 62 | BlockType(kind) => kind.write(write)?, | 1808 | | | 1809 | 0 | Bytes { ref type_hint, ref bytes } => { | 1810 | 0 | type_hint.write_u32_sized_le(write)?; // no idea why this one is u32, everything else is usually i32... | 1811 | 0 | u8::write_slice_le(write, bytes.as_slice())? | 1812 | | } | 1813 | | | 1814 | 0 | Custom { ref bytes, .. } => u8::write_slice_le(write, &bytes)?, // write.write(&bytes).map(|_| ()), | 1815 | | }; | 1816 | | | 1817 | 682 | Ok(()) | 1818 | 682 | } |
|
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 | 1.78M | 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 | 1.78M | let mut attribute_bytes = SmallVec::<[u8; 64]>::new(); |
1831 | 1.78M | 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 | 1.78M | let parse_attribute = move || { |
1835 | 1.78M | let reader = &mut attribute_bytes.as_slice(); |
1836 | | |
1837 | 1.78M | Ok(match kind.bytes.as_slice() { |
1838 | 1.78M | ty::I32BOX2 => IntegerBounds(self::IntegerBounds::read(reader)?), |
1839 | 885 | ty::F32BOX2 => FloatRect(self::FloatRect::read(reader)?), |
1840 | | |
1841 | 1.35M | ty::I32 => I32(i32::read_le(reader)?), |
1842 | 202k | ty::F32 => F32(f32::read_le(reader)?), |
1843 | 1.18M | ty::F64 => F64(f64::read_le(reader)?), |
1844 | | |
1845 | 758k | ty::RATIONAL => Rational({ |
1846 | 35.3k | let a = i32::read_le(reader)?; |
1847 | 35.3k | let b = u32::read_le(reader)?; |
1848 | 35.3k | (a, b) |
1849 | | }), |
1850 | | |
1851 | 21.8k | ty::TIME_CODE => TimeCode(self::TimeCode::read(reader)?), |
1852 | | |
1853 | | ty::I32VEC2 => IntVec2({ |
1854 | 931 | let a = i32::read_le(reader)?; |
1855 | 930 | let b = i32::read_le(reader)?; |
1856 | 929 | Vec2(a, b) |
1857 | | }), |
1858 | | |
1859 | | ty::F32VEC2 => FloatVec2({ |
1860 | 50.1k | let a = f32::read_le(reader)?; |
1861 | 50.1k | let b = f32::read_le(reader)?; |
1862 | 50.1k | Vec2(a, b) |
1863 | | }), |
1864 | | |
1865 | | ty::I32VEC3 => IntVec3({ |
1866 | 221 | let a = i32::read_le(reader)?; |
1867 | 220 | let b = i32::read_le(reader)?; |
1868 | 219 | let c = i32::read_le(reader)?; |
1869 | 218 | (a, b, c) |
1870 | | }), |
1871 | | |
1872 | | ty::F32VEC3 => FloatVec3({ |
1873 | 480 | let a = f32::read_le(reader)?; |
1874 | 479 | let b = f32::read_le(reader)?; |
1875 | 478 | let c = f32::read_le(reader)?; |
1876 | 474 | (a, b, c) |
1877 | | }), |
1878 | | |
1879 | 61.7k | ty::CHANNEL_LIST => ChannelList(self::ChannelList::read(&mut PeekRead::new(attribute_bytes.as_slice()))?), |
1880 | 628k | ty::CHROMATICITIES => Chromaticities(self::Chromaticities::read(reader)?), |
1881 | 605k | ty::COMPRESSION => Compression(self::Compression::read(reader)?), |
1882 | 1.02k | ty::ENVIRONMENT_MAP => EnvironmentMap(self::EnvironmentMap::read(reader)?), |
1883 | | |
1884 | 525k | ty::KEY_CODE => KeyCode(self::KeyCode::read(reader)?), |
1885 | 471k | ty::LINE_ORDER => LineOrder(self::LineOrder::read(reader)?), |
1886 | | |
1887 | 437k | ty::F32MATRIX3X3 => Matrix3x3({ |
1888 | 1.18k | let mut result = [0.0_f32; 9]; |
1889 | 1.18k | f32::read_slice_le(reader, &mut result)?; |
1890 | 1.18k | result |
1891 | | }), |
1892 | | |
1893 | | ty::F32MATRIX4X4 => Matrix4x4({ |
1894 | 25.3k | let mut result = [0.0_f32; 16]; |
1895 | 25.3k | f32::read_slice_le(reader, &mut result)?; |
1896 | 25.3k | result |
1897 | | }), |
1898 | | |
1899 | 4.66k | ty::PREVIEW => Preview(self::Preview::read(reader)?), |
1900 | 257k | 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 | 358k | ty::TEXT_VECTOR => TextVector(self::Text::read_vec_of_i32_sized_texts_le( |
1904 | 33.8k | &mut PeekRead::new(attribute_bytes.as_slice()), |
1905 | 33.8k | byte_size |
1906 | 14 | )?), |
1907 | | |
1908 | 18.6k | 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 | 0 | let type_hint = self::Text::read_u32_sized_le(reader, reader.len())?; |
1913 | 0 | let bytes = SmallVec::from(*reader); |
1914 | 0 | Bytes { type_hint, bytes } |
1915 | | } |
1916 | | |
1917 | 816k | _ => Custom { kind: kind.clone(), bytes: SmallVec::from(*reader) } |
1918 | | }) |
1919 | 1.78M | }; <exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>::{closure#0}Line | Count | Source | 1834 | 1.78M | let parse_attribute = move || { | 1835 | 1.78M | let reader = &mut attribute_bytes.as_slice(); | 1836 | | | 1837 | 1.78M | Ok(match kind.bytes.as_slice() { | 1838 | 1.78M | ty::I32BOX2 => IntegerBounds(self::IntegerBounds::read(reader)?), | 1839 | 885 | ty::F32BOX2 => FloatRect(self::FloatRect::read(reader)?), | 1840 | | | 1841 | 1.35M | ty::I32 => I32(i32::read_le(reader)?), | 1842 | 202k | ty::F32 => F32(f32::read_le(reader)?), | 1843 | 1.18M | ty::F64 => F64(f64::read_le(reader)?), | 1844 | | | 1845 | 758k | ty::RATIONAL => Rational({ | 1846 | 35.3k | let a = i32::read_le(reader)?; | 1847 | 35.3k | let b = u32::read_le(reader)?; | 1848 | 35.3k | (a, b) | 1849 | | }), | 1850 | | | 1851 | 21.8k | ty::TIME_CODE => TimeCode(self::TimeCode::read(reader)?), | 1852 | | | 1853 | | ty::I32VEC2 => IntVec2({ | 1854 | 931 | let a = i32::read_le(reader)?; | 1855 | 930 | let b = i32::read_le(reader)?; | 1856 | 929 | Vec2(a, b) | 1857 | | }), | 1858 | | | 1859 | | ty::F32VEC2 => FloatVec2({ | 1860 | 50.1k | let a = f32::read_le(reader)?; | 1861 | 50.1k | let b = f32::read_le(reader)?; | 1862 | 50.1k | Vec2(a, b) | 1863 | | }), | 1864 | | | 1865 | | ty::I32VEC3 => IntVec3({ | 1866 | 221 | let a = i32::read_le(reader)?; | 1867 | 220 | let b = i32::read_le(reader)?; | 1868 | 219 | let c = i32::read_le(reader)?; | 1869 | 218 | (a, b, c) | 1870 | | }), | 1871 | | | 1872 | | ty::F32VEC3 => FloatVec3({ | 1873 | 480 | let a = f32::read_le(reader)?; | 1874 | 479 | let b = f32::read_le(reader)?; | 1875 | 478 | let c = f32::read_le(reader)?; | 1876 | 474 | (a, b, c) | 1877 | | }), | 1878 | | | 1879 | 61.6k | ty::CHANNEL_LIST => ChannelList(self::ChannelList::read(&mut PeekRead::new(attribute_bytes.as_slice()))?), | 1880 | 628k | ty::CHROMATICITIES => Chromaticities(self::Chromaticities::read(reader)?), | 1881 | 605k | ty::COMPRESSION => Compression(self::Compression::read(reader)?), | 1882 | 1.02k | ty::ENVIRONMENT_MAP => EnvironmentMap(self::EnvironmentMap::read(reader)?), | 1883 | | | 1884 | 525k | ty::KEY_CODE => KeyCode(self::KeyCode::read(reader)?), | 1885 | 471k | ty::LINE_ORDER => LineOrder(self::LineOrder::read(reader)?), | 1886 | | | 1887 | 437k | ty::F32MATRIX3X3 => Matrix3x3({ | 1888 | 1.18k | let mut result = [0.0_f32; 9]; | 1889 | 1.18k | f32::read_slice_le(reader, &mut result)?; | 1890 | 1.18k | result | 1891 | | }), | 1892 | | | 1893 | | ty::F32MATRIX4X4 => Matrix4x4({ | 1894 | 25.3k | let mut result = [0.0_f32; 16]; | 1895 | 25.3k | f32::read_slice_le(reader, &mut result)?; | 1896 | 25.3k | result | 1897 | | }), | 1898 | | | 1899 | 4.66k | ty::PREVIEW => Preview(self::Preview::read(reader)?), | 1900 | 257k | 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 | 358k | ty::TEXT_VECTOR => TextVector(self::Text::read_vec_of_i32_sized_texts_le( | 1904 | 33.8k | &mut PeekRead::new(attribute_bytes.as_slice()), | 1905 | 33.8k | byte_size | 1906 | 14 | )?), | 1907 | | | 1908 | 18.6k | 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 | 0 | let type_hint = self::Text::read_u32_sized_le(reader, reader.len())?; | 1913 | 0 | let bytes = SmallVec::from(*reader); | 1914 | 0 | Bytes { type_hint, bytes } | 1915 | | } | 1916 | | | 1917 | 816k | _ => Custom { kind: kind.clone(), bytes: SmallVec::from(*reader) } | 1918 | | }) | 1919 | 1.78M | }; |
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::read::<_>::{closure#0}<exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::{closure#0}Line | Count | Source | 1834 | 682 | let parse_attribute = move || { | 1835 | 682 | let reader = &mut attribute_bytes.as_slice(); | 1836 | | | 1837 | 682 | Ok(match kind.bytes.as_slice() { | 1838 | 682 | ty::I32BOX2 => IntegerBounds(self::IntegerBounds::read(reader)?), | 1839 | 0 | ty::F32BOX2 => FloatRect(self::FloatRect::read(reader)?), | 1840 | | | 1841 | 434 | ty::I32 => I32(i32::read_le(reader)?), | 1842 | 124 | ty::F32 => F32(f32::read_le(reader)?), | 1843 | 310 | ty::F64 => F64(f64::read_le(reader)?), | 1844 | | | 1845 | 186 | ty::RATIONAL => Rational({ | 1846 | 0 | let a = i32::read_le(reader)?; | 1847 | 0 | let b = u32::read_le(reader)?; | 1848 | 0 | (a, b) | 1849 | | }), | 1850 | | | 1851 | 0 | ty::TIME_CODE => TimeCode(self::TimeCode::read(reader)?), | 1852 | | | 1853 | | ty::I32VEC2 => IntVec2({ | 1854 | 0 | let a = i32::read_le(reader)?; | 1855 | 0 | let b = i32::read_le(reader)?; | 1856 | 0 | Vec2(a, b) | 1857 | | }), | 1858 | | | 1859 | | ty::F32VEC2 => FloatVec2({ | 1860 | 62 | let a = f32::read_le(reader)?; | 1861 | 62 | let b = f32::read_le(reader)?; | 1862 | 62 | Vec2(a, b) | 1863 | | }), | 1864 | | | 1865 | | ty::I32VEC3 => IntVec3({ | 1866 | 0 | let a = i32::read_le(reader)?; | 1867 | 0 | let b = i32::read_le(reader)?; | 1868 | 0 | let c = i32::read_le(reader)?; | 1869 | 0 | (a, b, c) | 1870 | | }), | 1871 | | | 1872 | | ty::F32VEC3 => FloatVec3({ | 1873 | 0 | let a = f32::read_le(reader)?; | 1874 | 0 | let b = f32::read_le(reader)?; | 1875 | 0 | let c = f32::read_le(reader)?; | 1876 | 0 | (a, b, c) | 1877 | | }), | 1878 | | | 1879 | 62 | ty::CHANNEL_LIST => ChannelList(self::ChannelList::read(&mut PeekRead::new(attribute_bytes.as_slice()))?), | 1880 | 124 | ty::CHROMATICITIES => Chromaticities(self::Chromaticities::read(reader)?), | 1881 | 124 | ty::COMPRESSION => Compression(self::Compression::read(reader)?), | 1882 | 0 | ty::ENVIRONMENT_MAP => EnvironmentMap(self::EnvironmentMap::read(reader)?), | 1883 | | | 1884 | 62 | ty::KEY_CODE => KeyCode(self::KeyCode::read(reader)?), | 1885 | 62 | ty::LINE_ORDER => LineOrder(self::LineOrder::read(reader)?), | 1886 | | | 1887 | 0 | ty::F32MATRIX3X3 => Matrix3x3({ | 1888 | 0 | let mut result = [0.0_f32; 9]; | 1889 | 0 | f32::read_slice_le(reader, &mut result)?; | 1890 | 0 | result | 1891 | | }), | 1892 | | | 1893 | | ty::F32MATRIX4X4 => Matrix4x4({ | 1894 | 0 | let mut result = [0.0_f32; 16]; | 1895 | 0 | f32::read_slice_le(reader, &mut result)?; | 1896 | 0 | result | 1897 | | }), | 1898 | | | 1899 | 0 | ty::PREVIEW => Preview(self::Preview::read(reader)?), | 1900 | 62 | 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 | 0 | ty::TEXT_VECTOR => TextVector(self::Text::read_vec_of_i32_sized_texts_le( | 1904 | 0 | &mut PeekRead::new(attribute_bytes.as_slice()), | 1905 | 0 | byte_size | 1906 | 0 | )?), | 1907 | | | 1908 | 62 | 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 | 0 | let type_hint = self::Text::read_u32_sized_le(reader, reader.len())?; | 1913 | 0 | let bytes = SmallVec::from(*reader); | 1914 | 0 | Bytes { type_hint, bytes } | 1915 | | } | 1916 | | | 1917 | 0 | _ => Custom { kind: kind.clone(), bytes: SmallVec::from(*reader) } | 1918 | | }) | 1919 | 682 | }; |
|
1920 | | |
1921 | 1.78M | Ok(parse_attribute()) |
1922 | 1.78M | } <exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>> Line | Count | Source | 1824 | 1.78M | 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 | 1.78M | let mut attribute_bytes = SmallVec::<[u8; 64]>::new(); | 1831 | 1.78M | 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 | 1.78M | 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 | 1.78M | Ok(parse_attribute()) | 1922 | 1.78M | } |
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::read::<_> <exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>> Line | Count | Source | 1824 | 682 | 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 | 682 | let mut attribute_bytes = SmallVec::<[u8; 64]>::new(); | 1831 | 682 | 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 | 682 | 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 | 682 | Ok(parse_attribute()) | 1922 | 682 | } |
|
1923 | | |
1924 | | /// Validate this instance. |
1925 | 290k | pub fn validate(&self, allow_sampling: bool, data_window: IntegerBounds, strict: bool) -> UnitResult { |
1926 | | use self::AttributeValue::*; |
1927 | | |
1928 | 290k | match *self { |
1929 | 4.50k | ChannelList(ref channels) => channels.validate(allow_sampling, data_window, strict)?, |
1930 | 3.53k | TileDescription(ref value) => value.validate()?, |
1931 | 1.39k | Preview(ref value) => value.validate(strict)?, |
1932 | 6.24k | TimeCode(ref time_code) => time_code.validate(strict)?, |
1933 | | |
1934 | 13.7k | TextVector(ref vec) => if strict && vec.is_empty() { |
1935 | 0 | return Err(Error::invalid("text vector may not be empty")) |
1936 | 13.7k | }, |
1937 | | |
1938 | 261k | _ => {} |
1939 | | }; |
1940 | | |
1941 | 290k | Ok(()) |
1942 | 290k | } |
1943 | | |
1944 | | |
1945 | | /// Return `Ok(i32)` if this attribute is an i32. |
1946 | 0 | pub fn to_i32(&self) -> Result<i32> { |
1947 | 0 | match *self { |
1948 | 0 | AttributeValue::I32(value) => Ok(value), |
1949 | 0 | _ => Err(invalid_type()) |
1950 | | } |
1951 | 0 | } |
1952 | | |
1953 | | /// Return `Ok(f32)` if this attribute is an f32. |
1954 | 0 | pub fn to_f32(&self) -> Result<f32> { |
1955 | 0 | match *self { |
1956 | 0 | AttributeValue::F32(value) => Ok(value), |
1957 | 0 | _ => Err(invalid_type()) |
1958 | | } |
1959 | 0 | } |
1960 | | |
1961 | | /// Return `Ok(Text)` if this attribute is a text. |
1962 | 0 | pub fn into_text(self) -> Result<Text> { |
1963 | 0 | match self { |
1964 | 0 | AttributeValue::Text(value) => Ok(value), |
1965 | 0 | _ => Err(invalid_type()) |
1966 | | } |
1967 | 0 | } |
1968 | | |
1969 | | /// Return `Ok(Text)` if this attribute is a text. |
1970 | 0 | pub fn to_text(&self) -> Result<&Text> { |
1971 | 0 | match self { |
1972 | 0 | AttributeValue::Text(value) => Ok(value), |
1973 | 0 | _ => Err(invalid_type()) |
1974 | | } |
1975 | 0 | } |
1976 | | |
1977 | | /// Return `Ok(Chromaticities)` if this attribute is a chromaticities attribute. |
1978 | 0 | pub fn to_chromaticities(&self) -> Result<Chromaticities> { |
1979 | 0 | match *self { |
1980 | 0 | AttributeValue::Chromaticities(value) => Ok(value), |
1981 | 0 | _ => Err(invalid_type()) |
1982 | | } |
1983 | 0 | } |
1984 | | |
1985 | | /// Return `Ok(TimeCode)` if this attribute is a time code. |
1986 | 0 | pub fn to_time_code(&self) -> Result<TimeCode> { |
1987 | 0 | match *self { |
1988 | 0 | AttributeValue::TimeCode(value) => Ok(value), |
1989 | 0 | _ => Err(invalid_type()) |
1990 | | } |
1991 | 0 | } |
1992 | | } |
1993 | | |
1994 | | |
1995 | | |
1996 | | /// Contains string literals identifying the type of an attribute. |
1997 | | pub 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)] |
2037 | | mod 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 | | } |