Coverage Report

Created: 2026-04-12 07:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/exr-1.74.0/src/meta/header.rs
Line
Count
Source
1
2
//! Contains collections of common attributes.
3
//! Defines some data types that list all standard attributes.
4
5
use std::collections::HashMap;
6
use crate::meta::attribute::*; // FIXME shouldn't this need some more imports????
7
use crate::meta::*;
8
use crate::math::Vec2;
9
10
// TODO rename header to LayerDescription!
11
12
/// Describes a single layer in a file.
13
/// A file can have any number of layers.
14
/// The meta data contains one header per layer.
15
#[derive(Clone, Debug, PartialEq)]
16
pub struct Header {
17
18
    /// List of channels in this layer.
19
    pub channels: ChannelList,
20
21
    /// How the pixel data of all channels in this layer is compressed. May be `Compression::Uncompressed`.
22
    pub compression: Compression,
23
24
    /// Describes how the pixels of this layer are divided into smaller blocks.
25
    /// A single block can be loaded without processing all bytes of a file.
26
    ///
27
    /// Also describes whether a file contains multiple resolution levels: mip maps or rip maps.
28
    /// This allows loading not the full resolution, but the smallest sensible resolution.
29
    //
30
    // Required if file contains deep data or multiple layers.
31
    // Note: This value must agree with the version field's tile bit and deep data bit.
32
    // In this crate, this attribute will always have a value, for simplicity.
33
    pub blocks: BlockDescription,
34
35
    /// In what order the tiles of this header occur in the file.
36
    pub line_order: LineOrder,
37
38
    /// The resolution of this layer. Equivalent to the size of the `DataWindow`.
39
    pub layer_size: Vec2<usize>,
40
41
    /// Whether this layer contains deep data.
42
    pub deep: bool,
43
44
    /// This library supports only deep data version 1.
45
    pub deep_data_version: Option<i32>,
46
47
    /// Number of chunks, that is, scan line blocks or tiles, that this image has been divided into.
48
    /// This number is calculated once at the beginning
49
    /// of the read process or when creating a header object.
50
    ///
51
    /// This value includes all chunks of all resolution levels.
52
    ///
53
    ///
54
    /// __Warning__
55
    /// _This value is relied upon. You should probably use `Header::with_encoding`,
56
    /// which automatically updates the chunk count._
57
    pub chunk_count: usize,
58
59
    // Required for deep data (deepscanline and deeptile) layers.
60
    // Note: Since the value of "maxSamplesPerPixel"
61
    // maybe be unknown at the time of opening the
62
    // file, the value “ -1 ” is written to the file to
63
    // indicate an unknown value. When the file is
64
    // closed, this will be overwritten with the correct value.
65
    // If file writing does not complete
66
    // correctly due to an error, the value -1 will
67
    // remain. In this case, the value must be derived
68
    // by decoding each chunk in the layer
69
    /// Maximum number of samples in a single pixel in a deep image.
70
    pub max_samples_per_pixel: Option<usize>,
71
72
    /// Includes mandatory fields like pixel aspect or display window
73
    /// which must be the same for all layers.
74
    pub shared_attributes: ImageAttributes,
75
76
    /// Does not include the attributes required for reading the file contents.
77
    /// Excludes standard fields that must be the same for all headers.
78
    pub own_attributes: LayerAttributes,
79
}
80
81
/// Includes mandatory fields like pixel aspect or display window
82
/// which must be the same for all layers.
83
/// For more attributes, see struct `LayerAttributes`.
84
#[derive(Clone, PartialEq, Debug)]
85
pub struct ImageAttributes {
86
87
    /// The rectangle anywhere in the global infinite 2D space
88
    /// that clips all contents of the file.
89
    pub display_window: IntegerBounds,
90
91
    /// Aspect ratio of each pixel in this header.
92
    pub pixel_aspect: f32,
93
94
    /// The chromaticities attribute of the image. See the `Chromaticities` type.
95
    pub chromaticities: Option<Chromaticities>,
96
97
    /// The time code of the image.
98
    pub time_code: Option<TimeCode>,
99
100
    /// Contains custom attributes.
101
    /// Does not contain the attributes already present in the `ImageAttributes`.
102
    /// Contains only attributes that are standardized to be the same for all headers: chromaticities and time codes.
103
    pub other: HashMap<Text, AttributeValue>,
104
}
105
106
/// Does not include the attributes required for reading the file contents.
107
/// Excludes standard fields that must be the same for all headers.
108
/// For more attributes, see struct `ImageAttributes`.
109
#[derive(Clone, PartialEq)]
110
pub struct LayerAttributes {
111
112
    /// The name of this layer.
113
    /// Required if this file contains deep data or multiple layers.
114
    // As this is an attribute value, it is not restricted in length, may even be empty
115
    pub layer_name: Option<Text>,
116
117
    /// The top left corner of the rectangle that positions this layer
118
    /// within the global infinite 2D space of the whole file.
119
    /// This represents the position of the `DataWindow`.
120
    pub layer_position: Vec2<i32>,
121
122
    /// Part of the perspective projection. Default should be `(0, 0)`.
123
    // TODO same for all layers?
124
    pub screen_window_center: Vec2<f32>,
125
126
    // TODO same for all layers?
127
    /// Part of the perspective projection. Default should be `1`.
128
    pub screen_window_width: f32,
129
130
    /// The white luminance of the colors.
131
    /// Defines the luminance in candelas per square meter, Nits, of the rgb value `(1, 1, 1)`.
132
    // If the chromaticities and the whiteLuminance of an RGB image are
133
    // known, then it is possible to convert the image's pixels from RGB
134
    // to CIE XYZ tristimulus values (see function RGBtoXYZ() in header
135
    // file ImfChromaticities.h).
136
    pub white_luminance: Option<f32>,
137
138
    /// The adopted neutral of the colors. Specifies the CIE (x,y) frequency coordinates that should
139
    /// be considered neutral during color rendering. Pixels in the image
140
    /// whose CIE (x,y) frequency coordinates match the adopted neutral value should
141
    /// be mapped to neutral values on the given display.
142
    pub adopted_neutral: Option<Vec2<f32>>,
143
144
    /// Name of the color transform function that is applied for rendering the image.
145
    pub rendering_transform_name: Option<Text>,
146
147
    /// Name of the color transform function that computes the look modification of the image.
148
    pub look_modification_transform_name: Option<Text>,
149
150
    /// The horizontal density, in pixels per inch.
151
    /// The image's vertical output density can be computed using `horizontal_density * pixel_aspect_ratio`.
152
    pub horizontal_density: Option<f32>,
153
154
    /// Name of the owner.
155
    pub owner: Option<Text>,
156
157
    /// Additional textual information.
158
    pub comments: Option<Text>,
159
160
    /// The date of image creation, in `YYYY:MM:DD hh:mm:ss` format.
161
    // TODO parse!
162
    pub capture_date: Option<Text>,
163
164
    /// Time offset from UTC.
165
    pub utc_offset: Option<f32>,
166
167
    /// Geographical image location.
168
    pub longitude: Option<f32>,
169
170
    /// Geographical image location.
171
    pub latitude: Option<f32>,
172
173
    /// Geographical image location.
174
    pub altitude: Option<f32>,
175
176
    /// Camera focus in meters.
177
    pub focus: Option<f32>,
178
179
    /// Exposure time in seconds.
180
    pub exposure: Option<f32>,
181
182
    /// Camera aperture measured in f-stops. Equals the focal length
183
    /// of the lens divided by the diameter of the iris opening.
184
    pub aperture: Option<f32>,
185
186
    /// Iso-speed of the camera sensor.
187
    pub iso_speed: Option<f32>,
188
189
    /// If this is an environment map, specifies how to interpret it.
190
    pub environment_map: Option<EnvironmentMap>,
191
192
    /// Identifies film manufacturer, film type, film roll and frame position within the roll.
193
    pub film_key_code: Option<KeyCode>,
194
195
    /// Specifies how texture map images are extrapolated.
196
    /// Values can be `black`, `clamp`, `periodic`, or `mirror`.
197
    pub wrap_mode_name: Option<Text>,
198
199
    /// Frames per second if this is a frame in a sequence.
200
    pub frames_per_second: Option<Rational>,
201
202
    /// Specifies the view names for multi-view, for example stereo, image files.
203
    pub multi_view_names: Option<Vec<Text>>,
204
205
    /// The matrix that transforms 3D points from the world to the camera coordinate space.
206
    /// Left-handed coordinate system, y up, z forward.
207
    pub world_to_camera: Option<Matrix4x4>,
208
209
    /// The matrix that transforms 3D points from the world to the "Normalized Device Coordinate" space.
210
    /// Left-handed coordinate system, y up, z forward.
211
    pub world_to_normalized_device: Option<Matrix4x4>,
212
213
    /// Specifies whether the pixels in a deep image are sorted and non-overlapping.
214
    pub deep_image_state: Option<Rational>,
215
216
    /// If the image was cropped, contains the original data window.
217
    pub original_data_window: Option<IntegerBounds>,
218
219
    /// An 8-bit rgba image representing the rendered image.
220
    pub preview: Option<Preview>,
221
222
    /// Name of the view, which is typically either `"right"` or `"left"` for a stereoscopic image.
223
    pub view_name: Option<Text>,
224
225
    /// The name of the software that produced this image.
226
    pub software_name: Option<Text>,
227
228
    /// The near clip plane of the virtual camera projection.
229
    pub near_clip_plane: Option<f32>,
230
231
    /// The far clip plane of the virtual camera projection.
232
    pub far_clip_plane: Option<f32>,
233
234
    /// The field of view angle, along the horizontal axis, in degrees.
235
    pub horizontal_field_of_view: Option<f32>,
236
237
    /// The field of view angle, along the horizontal axis, in degrees.
238
    pub vertical_field_of_view: Option<f32>,
239
240
    /// Contains custom attributes.
241
    /// Does not contain the attributes already present in the `Header` or `LayerAttributes` struct.
242
    /// Does not contain attributes that are standardized to be the same for all layers: no chromaticities and no time codes.
243
    pub other: HashMap<Text, AttributeValue>,
244
}
245
246
247
impl LayerAttributes {
248
249
    /// Create default layer attributes with a data position of zero.
250
0
    pub fn named(layer_name: impl Into<Text>) -> Self {
251
0
        Self {
252
0
            layer_name: Some(layer_name.into()),
253
0
            .. Self::default()
254
0
        }
255
0
    }
256
257
    /// Set the data position of this layer.
258
0
    pub fn with_position(self, data_position: Vec2<i32>) -> Self {
259
0
        Self { layer_position: data_position, ..self }
260
0
    }
261
262
    /// Set all common camera projection attributes at once.
263
0
    pub fn with_camera_frustum(
264
0
        self,
265
0
        world_to_camera: Matrix4x4,
266
0
        world_to_normalized_device: Matrix4x4,
267
0
        field_of_view: impl Into<Vec2<f32>>,
268
0
        depth_clip_range: std::ops::Range<f32>,
269
0
    ) -> Self
270
    {
271
0
        let fov = field_of_view.into();
272
273
0
        Self {
274
0
            world_to_normalized_device: Some(world_to_normalized_device),
275
0
            world_to_camera: Some(world_to_camera),
276
0
            horizontal_field_of_view: Some(fov.x()),
277
0
            vertical_field_of_view: Some(fov.y()),
278
0
            near_clip_plane: Some(depth_clip_range.start),
279
0
            far_clip_plane: Some(depth_clip_range.end),
280
0
            ..self
281
0
        }
282
0
    }
283
}
284
285
impl ImageAttributes {
286
287
    /// Set the display position and size of this image.
288
43.4k
    pub fn new(display_window: IntegerBounds) -> Self {
289
43.4k
        Self {
290
43.4k
            pixel_aspect: 1.0,
291
43.4k
            chromaticities: None,
292
43.4k
            time_code: None,
293
43.4k
            other: Default::default(),
294
43.4k
            display_window,
295
43.4k
        }
296
43.4k
    }
297
298
    /// Set the display position to zero and use the specified size for this image.
299
0
    pub fn with_size(size: impl Into<Vec2<usize>>) -> Self {
300
0
        Self::new(IntegerBounds::from_dimensions(size))
301
0
    }
302
}
303
304
305
306
307
impl Header {
308
309
    /// Create a new Header with the specified name, display window and channels.
310
    /// Use `Header::with_encoding` and the similar methods to add further properties to the header.
311
    ///
312
    /// The other settings are left to their default values:
313
    /// - RLE compression
314
    /// - display window equal to data window
315
    /// - tiles (64 x 64 px)
316
    /// - unspecified line order
317
    /// - no custom attributes
318
0
    pub fn new(name: Text, data_size: impl Into<Vec2<usize>>, channels: SmallVec<[ChannelDescription; 5]>) -> Self {
319
0
        let data_size: Vec2<usize> = data_size.into();
320
321
0
        let compression = Compression::RLE;
322
0
        let blocks = BlockDescription::Tiles(TileDescription {
323
0
            tile_size: Vec2(64, 64),
324
0
            level_mode: LevelMode::Singular,
325
0
            rounding_mode: RoundingMode::Down
326
0
        });
327
328
0
        Self {
329
0
            layer_size: data_size,
330
0
            compression,
331
0
            blocks,
332
0
333
0
            channels: ChannelList::new(channels),
334
0
            line_order: LineOrder::Unspecified,
335
0
336
0
            shared_attributes: ImageAttributes::with_size(data_size),
337
0
            own_attributes: LayerAttributes::named(name),
338
0
339
0
            chunk_count: compute_chunk_count(compression, data_size, blocks),
340
0
341
0
            deep: false,
342
0
            deep_data_version: None,
343
0
            max_samples_per_pixel: None,
344
0
        }
345
0
    }
346
347
    /// Set the display window, that is, the global clipping rectangle.
348
    /// __Must be the same for all headers of a file.__
349
0
    pub fn with_display_window(mut self, display_window: IntegerBounds) -> Self {
350
0
        self.shared_attributes.display_window = display_window;
351
0
        self
352
0
    }
353
354
    /// Set the offset of this layer.
355
0
    pub fn with_position(mut self, position: Vec2<i32>) -> Self {
356
0
        self.own_attributes.layer_position = position;
357
0
        self
358
0
    }
359
360
    /// Set compression, tiling, and line order. Automatically computes chunk count.
361
0
    pub fn with_encoding(self, compression: Compression, blocks: BlockDescription, line_order: LineOrder) -> Self {
362
0
        Self {
363
0
            chunk_count: compute_chunk_count(compression, self.layer_size, blocks),
364
0
            compression, blocks, line_order,
365
0
            .. self
366
0
        }
367
0
    }
368
369
    /// Set **all** attributes of the header that are not shared with all other headers in the image.
370
0
    pub fn with_attributes(self, own_attributes: LayerAttributes) -> Self {
371
0
        Self { own_attributes, .. self }
372
0
    }
373
374
    /// Set **all** attributes of the header that are shared with all other headers in the image.
375
0
    pub fn with_shared_attributes(self, shared_attributes: ImageAttributes) -> Self {
376
0
        Self { shared_attributes, .. self }
377
0
    }
378
379
    /// Iterate over all blocks, in the order specified by the headers line order attribute.
380
    /// Unspecified line order is treated as increasing line order.
381
    /// Also enumerates the index of each block in the header, as if it were sorted in increasing line order.
382
81
    pub fn enumerate_ordered_blocks(&self) -> impl Iterator<Item=(usize, TileIndices)> + Send {
383
81
        let increasing_y = self.blocks_increasing_y_order().enumerate();
384
385
        // TODO without box?
386
81
        let ordered: Box<dyn Send + Iterator<Item=(usize, TileIndices)>> = {
387
81
            if self.line_order == LineOrder::Decreasing { Box::new(increasing_y.rev()) }
388
81
            else { Box::new(increasing_y) }
389
        };
390
391
81
        ordered
392
81
    }
393
394
    /*/// Iterate over all blocks, in the order specified by the headers line order attribute.
395
    /// Also includes an index of the block if it were `LineOrder::Increasing`, starting at zero for this header.
396
    pub fn enumerate_ordered_blocks(&self) -> impl Iterator<Item = (usize, TileIndices)> + Send {
397
        let increasing_y = self.blocks_increasing_y_order().enumerate();
398
399
        let ordered: Box<dyn Send + Iterator<Item = (usize, TileIndices)>> = {
400
            if self.line_order == LineOrder::Decreasing {
401
                Box::new(increasing_y.rev()) // TODO without box?
402
            }
403
            else {
404
                Box::new(increasing_y)
405
            }
406
        };
407
408
        ordered
409
    }*/
410
411
    /// Iterate over all tile indices in this header in `LineOrder::Increasing` order.
412
14.8k
    pub fn blocks_increasing_y_order(&self) -> impl Iterator<Item = TileIndices> + ExactSizeIterator + DoubleEndedIterator {
413
94.8k
        fn tiles_of(image_size: Vec2<usize>, tile_size: Vec2<usize>, level_index: Vec2<usize>) -> impl Iterator<Item=TileIndices> {
414
1.80M
            fn divide_and_rest(total_size: usize, block_size: usize) -> impl Iterator<Item=(usize, usize)> {
415
1.80M
                let block_count = compute_block_count(total_size, block_size);
416
1.80M
                (0..block_count).map(move |block_index| (
417
4.72M
                    block_index, calculate_block_size(total_size, block_size, block_index).expect("block size calculation bug")
418
                ))
419
1.80M
            }
420
421
1.71M
            divide_and_rest(image_size.height(), tile_size.height()).flat_map(move |(y_index, tile_height)|{
422
3.00M
                divide_and_rest(image_size.width(), tile_size.width()).map(move |(x_index, tile_width)|{
423
3.00M
                    TileIndices {
424
3.00M
                        size: Vec2(tile_width, tile_height),
425
3.00M
                        location: TileCoordinates { tile_index: Vec2(x_index, y_index), level_index, },
426
3.00M
                    }
427
3.00M
                })
428
1.71M
            })
429
94.8k
        }
430
431
14.8k
        let vec: Vec<TileIndices> = {
432
14.8k
            if let BlockDescription::Tiles(tiles) = self.blocks {
433
4.65k
                match tiles.level_mode {
434
                    LevelMode::Singular => {
435
1.96k
                        tiles_of(self.layer_size, tiles.tile_size, Vec2(0, 0)).collect()
436
                    },
437
                    LevelMode::MipMap => {
438
1.42k
                        mip_map_levels(tiles.rounding_mode, self.layer_size)
439
25.9k
                            .flat_map(move |(level_index, level_size)|{
440
25.9k
                                tiles_of(level_size, tiles.tile_size, Vec2(level_index, level_index))
441
25.9k
                            })
442
1.42k
                            .collect()
443
                    },
444
                    LevelMode::RipMap => {
445
1.26k
                        rip_map_levels(tiles.rounding_mode, self.layer_size)
446
56.7k
                            .flat_map(move |(level_index, level_size)| {
447
56.7k
                                tiles_of(level_size, tiles.tile_size, level_index)
448
56.7k
                            })
449
1.26k
                            .collect()
450
                    }
451
                }
452
            }
453
            else {
454
10.2k
                let tiles = Vec2(self.layer_size.0, self.compression.scan_lines_per_block());
455
10.2k
                tiles_of(self.layer_size, tiles, Vec2(0, 0)).collect()
456
            }
457
        };
458
459
14.8k
        vec.into_iter() // TODO without collect
460
14.8k
    }
461
462
    /* TODO
463
    /// The block indices of this header, ordered as they would appear in the file.
464
    pub fn ordered_block_indices<'s>(&'s self, layer_index: usize) -> impl 's + Iterator<Item=BlockIndex> {
465
        self.enumerate_ordered_blocks().map(|(chunk_index, tile)|{
466
            let data_indices = self.get_absolute_block_pixel_coordinates(tile.location).expect("tile coordinate bug");
467
468
            BlockIndex {
469
                layer: layer_index,
470
                level: tile.location.level_index,
471
                pixel_position: data_indices.position.to_usize("data indices start").expect("data index bug"),
472
                pixel_size: data_indices.size,
473
            }
474
        })
475
    }*/
476
477
    // TODO reuse this function everywhere
478
    /// The default pixel resolution of a single block (tile or scan line block).
479
    /// Not all blocks have this size, because they may be cutoff at the end of the image.
480
1.93M
    pub fn max_block_pixel_size(&self) -> Vec2<usize> {
481
1.93M
        match self.blocks {
482
7.31k
            BlockDescription::ScanLines => Vec2(self.layer_size.0, self.compression.scan_lines_per_block()),
483
1.93M
            BlockDescription::Tiles(tiles) => tiles.tile_size,
484
        }
485
1.93M
    }
486
487
    /// Calculate the position of a block in the global infinite 2D space of a file. May be negative.
488
0
    pub fn get_block_data_window_pixel_coordinates(&self, tile: TileCoordinates) -> Result<IntegerBounds> {
489
0
        let data = self.get_absolute_block_pixel_coordinates(tile)?;
490
0
        Ok(data.with_origin(self.own_attributes.layer_position))
491
0
    }
492
493
    /// Calculate the pixel index rectangle inside this header. Is not negative. Starts at `0`.
494
4.30M
    pub fn get_absolute_block_pixel_coordinates(&self, tile: TileCoordinates) -> Result<IntegerBounds> {
495
4.30M
        if let BlockDescription::Tiles(tiles) = self.blocks {
496
3.17M
            let Vec2(data_width, data_height) = self.layer_size;
497
498
3.17M
            let data_width = compute_level_size(tiles.rounding_mode, data_width, tile.level_index.x());
499
3.17M
            let data_height = compute_level_size(tiles.rounding_mode, data_height, tile.level_index.y());
500
3.17M
            let absolute_tile_coordinates = tile.to_data_indices(tiles.tile_size, Vec2(data_width, data_height))?;
501
502
3.17M
            if absolute_tile_coordinates.position.x() as i64 >= data_width as i64 || absolute_tile_coordinates.position.y() as i64 >= data_height as i64 {
503
0
                return Err(Error::invalid("data block tile index"))
504
3.17M
            }
505
506
3.17M
            Ok(absolute_tile_coordinates)
507
        }
508
        else { // this is a scanline image
509
1.13M
            debug_assert_eq!(tile.tile_index.0, 0, "block index calculation bug");
510
511
1.13M
            let (y, height) = calculate_block_position_and_size(
512
1.13M
                self.layer_size.height(),
513
1.13M
                self.compression.scan_lines_per_block(),
514
1.13M
                tile.tile_index.y()
515
1.87k
            )?;
516
517
            Ok(IntegerBounds {
518
1.13M
                position: Vec2(0, usize_to_i32(y, "tile y")?),
519
1.13M
                size: Vec2(self.layer_size.width(), height)
520
            })
521
        }
522
523
        // TODO deep data?
524
4.30M
    }
525
526
    /// Return the tile index, converting scan line block coordinates to tile indices.
527
    /// Starts at `0` and is not negative.
528
653k
    pub fn get_block_data_indices(&self, block: &CompressedBlock) -> Result<TileCoordinates> {
529
653k
        Ok(match block {
530
643k
            CompressedBlock::Tile(ref tile) => {
531
643k
                tile.coordinates
532
            },
533
534
9.35k
            CompressedBlock::ScanLine(ref block) => {
535
9.35k
                let size = self.compression.scan_lines_per_block() as i32;
536
537
9.35k
                let diff = block.y_coordinate.checked_sub(self.own_attributes.layer_position.y()).ok_or(Error::invalid("invalid header"))?;
538
9.33k
                let y = diff.checked_div(size).ok_or(Error::invalid("invalid header"))?;
539
540
9.33k
                if y < 0 {
541
146
                    return Err(Error::invalid("scan block y coordinate"));
542
9.19k
                }
543
544
9.19k
                TileCoordinates {
545
9.19k
                    tile_index: Vec2(0, y as usize),
546
9.19k
                    level_index: Vec2(0, 0)
547
9.19k
                }
548
            },
549
550
0
            _ => return Err(Error::unsupported("deep data not supported yet"))
551
        })
552
653k
    }
553
554
    /// Computes the absolute tile coordinate data indices, which start at `0`.
555
0
    pub fn get_scan_line_block_tile_coordinates(&self, block_y_coordinate: i32) -> Result<TileCoordinates> {
556
0
        let size = self.compression.scan_lines_per_block() as i32;
557
558
0
        let diff = block_y_coordinate.checked_sub(self.own_attributes.layer_position.1).ok_or(Error::invalid("invalid header"))?;
559
0
        let y = diff.checked_div(size).ok_or(Error::invalid("invalid header"))?;
560
561
0
        if y < 0 {
562
0
            return Err(Error::invalid("scan block y coordinate"));
563
0
        }
564
565
0
        Ok(TileCoordinates {
566
0
            tile_index: Vec2(0, y as usize),
567
0
            level_index: Vec2(0, 0)
568
0
        })
569
0
    }
570
571
    /// Maximum byte length of an uncompressed or compressed block, used for validation.
572
654k
    pub fn max_block_byte_size(&self) -> usize {
573
654k
        self.channels.bytes_per_pixel * match self.blocks {
574
645k
            BlockDescription::Tiles(tiles) => tiles.tile_size.area(),
575
9.87k
            BlockDescription::ScanLines => self.compression.scan_lines_per_block() * self.layer_size.width()
576
            // TODO What about deep data???
577
        }
578
654k
    }
579
580
    /// Returns the number of bytes that the pixels of this header will require
581
    /// when stored without compression. Respects multi-resolution levels and subsampling.
582
0
    pub fn total_pixel_bytes(&self) -> usize {
583
0
        assert!(!self.deep);
584
585
0
        let pixel_count_of_levels = |size: Vec2<usize>| -> usize {
586
0
            match self.blocks {
587
0
                BlockDescription::ScanLines => size.area(),
588
0
                BlockDescription::Tiles(tile_description) => match tile_description.level_mode {
589
0
                    LevelMode::Singular => size.area(),
590
591
0
                    LevelMode::MipMap => mip_map_levels(tile_description.rounding_mode, size)
592
0
                        .map(|(_, size)| size.area()).sum(),
593
594
0
                    LevelMode::RipMap => rip_map_levels(tile_description.rounding_mode, size)
595
0
                        .map(|(_, size)| size.area()).sum(),
596
                }
597
            }
598
0
        };
599
600
0
        self.channels.list.iter()
601
0
            .map(|channel: &ChannelDescription|
602
0
                pixel_count_of_levels(channel.subsampled_resolution(self.layer_size)) * channel.sample_type.bytes_per_sample()
603
            )
604
0
            .sum()
605
606
0
    }
607
608
    /// Approximates the maximum number of bytes that the pixels of this header will consume in a file.
609
    /// Due to compression, the actual byte size may be smaller.
610
0
    pub fn max_pixel_file_bytes(&self) -> usize {
611
0
        assert!(!self.deep);
612
613
0
        self.chunk_count * 64 // at most 64 bytes overhead for each chunk (header index, tile description, chunk size, and more)
614
0
            + self.total_pixel_bytes()
615
0
    }
616
617
    /// Validate this instance.
618
24.2k
    pub fn validate(&self, is_multilayer: bool, long_names: &mut bool, strict: bool) -> UnitResult {
619
620
24.2k
        self.data_window().validate(None)?;
621
24.2k
        self.shared_attributes.display_window.validate(None)?;
622
623
24.2k
        if strict {
624
81
            if is_multilayer {
625
0
                if self.own_attributes.layer_name.is_none() {
626
0
                    return Err(missing_attribute("layer name for multi layer file"));
627
0
                }
628
81
            }
629
630
81
            if self.blocks == BlockDescription::ScanLines && self.line_order == LineOrder::Unspecified {
631
0
                return Err(Error::invalid("unspecified line order in scan line images"));
632
81
            }
633
634
81
            if self.layer_size == Vec2(0, 0) {
635
0
                return Err(Error::invalid("empty data window"));
636
81
            }
637
638
81
            if self.shared_attributes.display_window.size == Vec2(0,0) {
639
0
                return Err(Error::invalid("empty display window"));
640
81
            }
641
642
81
            if !self.shared_attributes.pixel_aspect.is_normal() || self.shared_attributes.pixel_aspect < 1.0e-6 || self.shared_attributes.pixel_aspect > 1.0e6 {
643
0
                return Err(Error::invalid("pixel aspect ratio"));
644
81
            }
645
646
81
            if self.own_attributes.screen_window_width < 0.0 {
647
0
                return Err(Error::invalid("screen window width"));
648
81
            }
649
24.1k
        }
650
651
24.2k
        let allow_subsampling = !self.deep && self.blocks == BlockDescription::ScanLines;
652
24.2k
        self.channels.validate(allow_subsampling, self.data_window(), strict)?;
653
654
30.6k
        for (name, value) in &self.shared_attributes.other {
655
6.55k
            attribute::validate(name, value, long_names, allow_subsampling, self.data_window(), strict)?;
656
        }
657
658
349k
        for (name, value) in &self.own_attributes.other {
659
325k
            attribute::validate(name, value, long_names, allow_subsampling, self.data_window(), strict)?;
660
        }
661
662
        // this is only to check whether someone tampered with our precious values, to avoid writing an invalid file
663
24.0k
        if self.chunk_count != compute_chunk_count(self.compression, self.layer_size, self.blocks) {
664
0
            return Err(Error::invalid("chunk count attribute")); // TODO this may be an expensive check?
665
24.0k
        }
666
667
        // check if attribute names appear twice
668
24.0k
        if strict {
669
81
            for (name, _) in &self.shared_attributes.other {
670
0
                if self.own_attributes.other.contains_key(name) {
671
0
                    return Err(Error::invalid(format!("duplicate attribute name: `{}`", name)));
672
0
                }
673
            }
674
675
3.96k
            for &reserved in header::standard_names::ALL.iter() {
676
3.96k
                let name  = Text::from_bytes_unchecked(SmallVec::from_slice(reserved));
677
3.96k
                if self.own_attributes.other.contains_key(&name) || self.shared_attributes.other.contains_key(&name) {
678
0
                    return Err(Error::invalid(format!(
679
0
                        "attribute name `{}` is reserved and cannot be custom",
680
0
                        Text::from_bytes_unchecked(reserved.into())
681
0
                    )));
682
3.96k
                }
683
            }
684
24.0k
        }
685
686
24.0k
        if self.deep {
687
0
            if strict {
688
0
                if self.own_attributes.layer_name.is_none() {
689
0
                    return Err(missing_attribute("layer name for deep file"));
690
0
                }
691
692
0
                if self.max_samples_per_pixel.is_none() {
693
0
                    return Err(Error::invalid("missing max samples per pixel attribute for deepdata"));
694
0
                }
695
0
            }
696
697
0
            match self.deep_data_version {
698
0
                Some(1) => {},
699
0
                Some(_) => return Err(Error::unsupported("deep data version")),
700
0
                None => return Err(missing_attribute("deep data version")),
701
            }
702
703
0
            if !self.compression.supports_deep_data() {
704
0
                return Err(Error::invalid("compression method does not support deep data"));
705
0
            }
706
24.0k
        }
707
708
24.0k
        Ok(())
709
24.2k
    }
710
711
    /// Read the headers without validating them.
712
8.22k
    pub fn read_all(read: &mut PeekRead<impl Read>, version: &Requirements, pedantic: bool) -> Result<Headers> {
713
8.22k
        if !version.is_multilayer() {
714
7.05k
            Ok(smallvec![ Header::read(read, version, pedantic)? ])
715
        }
716
        else {
717
1.17k
            let mut headers = SmallVec::new();
718
719
36.9k
            while !sequence_end::has_come(read)? {
720
36.2k
                headers.push(Header::read(read, version, pedantic)?);
721
            }
722
723
677
            Ok(headers)
724
        }
725
8.22k
    }
<exr::meta::header::Header>::read_all::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
Line
Count
Source
712
8.14k
    pub fn read_all(read: &mut PeekRead<impl Read>, version: &Requirements, pedantic: bool) -> Result<Headers> {
713
8.14k
        if !version.is_multilayer() {
714
6.97k
            Ok(smallvec![ Header::read(read, version, pedantic)? ])
715
        }
716
        else {
717
1.17k
            let mut headers = SmallVec::new();
718
719
36.9k
            while !sequence_end::has_come(read)? {
720
36.2k
                headers.push(Header::read(read, version, pedantic)?);
721
            }
722
723
677
            Ok(headers)
724
        }
725
8.14k
    }
Unexecuted instantiation: <exr::meta::header::Header>::read_all::<_>
<exr::meta::header::Header>::read_all::<exr::io::Tracking<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
Line
Count
Source
712
81
    pub fn read_all(read: &mut PeekRead<impl Read>, version: &Requirements, pedantic: bool) -> Result<Headers> {
713
81
        if !version.is_multilayer() {
714
81
            Ok(smallvec![ Header::read(read, version, pedantic)? ])
715
        }
716
        else {
717
0
            let mut headers = SmallVec::new();
718
719
0
            while !sequence_end::has_come(read)? {
720
0
                headers.push(Header::read(read, version, pedantic)?);
721
            }
722
723
0
            Ok(headers)
724
        }
725
81
    }
726
727
    /// Without validation, write the headers to the byte stream.
728
81
    pub fn write_all(headers: &[Header], write: &mut impl Write, is_multilayer: bool) -> UnitResult {
729
162
        for header in headers {
730
81
            header.write(write)?;
731
        }
732
733
81
        if is_multilayer {
734
0
            sequence_end::write(write)?;
735
81
        }
736
737
81
        Ok(())
738
81
    }
Unexecuted instantiation: <exr::meta::header::Header>::write_all::<_>
Unexecuted instantiation: <exr::meta::header::Header>::write_all::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
<exr::meta::header::Header>::write_all::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>>
Line
Count
Source
728
81
    pub fn write_all(headers: &[Header], write: &mut impl Write, is_multilayer: bool) -> UnitResult {
729
162
        for header in headers {
730
81
            header.write(write)?;
731
        }
732
733
81
        if is_multilayer {
734
0
            sequence_end::write(write)?;
735
81
        }
736
737
81
        Ok(())
738
81
    }
739
740
    /// Iterate over all `(name, attribute_value)` pairs in this header that would be written to a file.
741
    /// The order of attributes is arbitrary and may change in future versions.
742
    /// Will always contain all strictly required attributes, such as channels, compression, data window, and similar.
743
    /// Hint: Use `attribute.kind_name()` to obtain the standardized name of the attribute type.
744
    /// Does not validate the header or attributes.
745
    // This function is used for writing the attributes to files.
746
    #[inline]
747
81
    pub fn all_named_attributes(&self) -> impl '_ + Iterator<Item=(&TextSlice, AttributeValue)> {
748
        use std::iter::{once, once_with, empty};
749
        use crate::meta::header::standard_names::*;
750
        use AttributeValue::*;
751
752
2.99k
        #[inline] fn optional<'t, T: Clone>(
753
2.99k
            name: &'t TextSlice,
754
2.99k
            to_attribute: impl Fn(T) -> AttributeValue,
755
2.99k
            value: &'t Option<T>
756
2.99k
        )
757
2.99k
           -> impl Iterator<Item=(&'t TextSlice, AttributeValue)>
758
        {
759
2.99k
            value.as_ref().map(move |value| (name, to_attribute(value.clone()))).into_iter()
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<_, _>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<[f32; 16], exr::meta::attribute::AttributeValue::Matrix4x4>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<exr::math::Vec2<f32>, exr::meta::attribute::AttributeValue::FloatVec2>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<alloc::vec::Vec<exr::meta::attribute::Text>, exr::meta::attribute::AttributeValue::TextVector>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::IntegerBounds, exr::meta::attribute::AttributeValue::IntegerBounds>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::Chromaticities, exr::meta::attribute::AttributeValue::Chromaticities>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::EnvironmentMap, exr::meta::attribute::AttributeValue::EnvironmentMap>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::Text, exr::meta::attribute::AttributeValue::Text>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::KeyCode, exr::meta::attribute::AttributeValue::KeyCode>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::Preview, exr::meta::attribute::AttributeValue::Preview>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::TimeCode, exr::meta::attribute::AttributeValue::TimeCode>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<(i32, u32), exr::meta::attribute::AttributeValue::Rational>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<f32, exr::meta::attribute::AttributeValue::F32>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<usize, <exr::meta::header::Header>::all_named_attributes::usize_as_i32>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<i32, exr::meta::attribute::AttributeValue::I32>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<[f32; 16], exr::meta::attribute::AttributeValue::Matrix4x4>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<exr::math::Vec2<f32>, exr::meta::attribute::AttributeValue::FloatVec2>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<alloc::vec::Vec<exr::meta::attribute::Text>, exr::meta::attribute::AttributeValue::TextVector>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::IntegerBounds, exr::meta::attribute::AttributeValue::IntegerBounds>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::Chromaticities, exr::meta::attribute::AttributeValue::Chromaticities>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::EnvironmentMap, exr::meta::attribute::AttributeValue::EnvironmentMap>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::Text, exr::meta::attribute::AttributeValue::Text>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::KeyCode, exr::meta::attribute::AttributeValue::KeyCode>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::Preview, exr::meta::attribute::AttributeValue::Preview>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::TimeCode, exr::meta::attribute::AttributeValue::TimeCode>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<(i32, u32), exr::meta::attribute::AttributeValue::Rational>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<f32, exr::meta::attribute::AttributeValue::F32>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<usize, <exr::meta::header::Header>::all_named_attributes::usize_as_i32>::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<i32, exr::meta::attribute::AttributeValue::I32>::{closure#0}
760
2.99k
        }
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<_, _>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<[f32; 16], exr::meta::attribute::AttributeValue::Matrix4x4>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<exr::math::Vec2<f32>, exr::meta::attribute::AttributeValue::FloatVec2>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<alloc::vec::Vec<exr::meta::attribute::Text>, exr::meta::attribute::AttributeValue::TextVector>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::IntegerBounds, exr::meta::attribute::AttributeValue::IntegerBounds>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::Chromaticities, exr::meta::attribute::AttributeValue::Chromaticities>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::EnvironmentMap, exr::meta::attribute::AttributeValue::EnvironmentMap>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::Text, exr::meta::attribute::AttributeValue::Text>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::KeyCode, exr::meta::attribute::AttributeValue::KeyCode>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::Preview, exr::meta::attribute::AttributeValue::Preview>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::TimeCode, exr::meta::attribute::AttributeValue::TimeCode>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<(i32, u32), exr::meta::attribute::AttributeValue::Rational>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<f32, exr::meta::attribute::AttributeValue::F32>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<usize, <exr::meta::header::Header>::all_named_attributes::usize_as_i32>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::optional::<i32, exr::meta::attribute::AttributeValue::I32>
<exr::meta::header::Header>::all_named_attributes::optional::<[f32; 16], exr::meta::attribute::AttributeValue::Matrix4x4>
Line
Count
Source
752
162
        #[inline] fn optional<'t, T: Clone>(
753
162
            name: &'t TextSlice,
754
162
            to_attribute: impl Fn(T) -> AttributeValue,
755
162
            value: &'t Option<T>
756
162
        )
757
162
           -> impl Iterator<Item=(&'t TextSlice, AttributeValue)>
758
        {
759
162
            value.as_ref().map(move |value| (name, to_attribute(value.clone()))).into_iter()
760
162
        }
<exr::meta::header::Header>::all_named_attributes::optional::<exr::math::Vec2<f32>, exr::meta::attribute::AttributeValue::FloatVec2>
Line
Count
Source
752
81
        #[inline] fn optional<'t, T: Clone>(
753
81
            name: &'t TextSlice,
754
81
            to_attribute: impl Fn(T) -> AttributeValue,
755
81
            value: &'t Option<T>
756
81
        )
757
81
           -> impl Iterator<Item=(&'t TextSlice, AttributeValue)>
758
        {
759
81
            value.as_ref().map(move |value| (name, to_attribute(value.clone()))).into_iter()
760
81
        }
<exr::meta::header::Header>::all_named_attributes::optional::<alloc::vec::Vec<exr::meta::attribute::Text>, exr::meta::attribute::AttributeValue::TextVector>
Line
Count
Source
752
81
        #[inline] fn optional<'t, T: Clone>(
753
81
            name: &'t TextSlice,
754
81
            to_attribute: impl Fn(T) -> AttributeValue,
755
81
            value: &'t Option<T>
756
81
        )
757
81
           -> impl Iterator<Item=(&'t TextSlice, AttributeValue)>
758
        {
759
81
            value.as_ref().map(move |value| (name, to_attribute(value.clone()))).into_iter()
760
81
        }
<exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::IntegerBounds, exr::meta::attribute::AttributeValue::IntegerBounds>
Line
Count
Source
752
81
        #[inline] fn optional<'t, T: Clone>(
753
81
            name: &'t TextSlice,
754
81
            to_attribute: impl Fn(T) -> AttributeValue,
755
81
            value: &'t Option<T>
756
81
        )
757
81
           -> impl Iterator<Item=(&'t TextSlice, AttributeValue)>
758
        {
759
81
            value.as_ref().map(move |value| (name, to_attribute(value.clone()))).into_iter()
760
81
        }
<exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::Chromaticities, exr::meta::attribute::AttributeValue::Chromaticities>
Line
Count
Source
752
81
        #[inline] fn optional<'t, T: Clone>(
753
81
            name: &'t TextSlice,
754
81
            to_attribute: impl Fn(T) -> AttributeValue,
755
81
            value: &'t Option<T>
756
81
        )
757
81
           -> impl Iterator<Item=(&'t TextSlice, AttributeValue)>
758
        {
759
81
            value.as_ref().map(move |value| (name, to_attribute(value.clone()))).into_iter()
760
81
        }
<exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::EnvironmentMap, exr::meta::attribute::AttributeValue::EnvironmentMap>
Line
Count
Source
752
81
        #[inline] fn optional<'t, T: Clone>(
753
81
            name: &'t TextSlice,
754
81
            to_attribute: impl Fn(T) -> AttributeValue,
755
81
            value: &'t Option<T>
756
81
        )
757
81
           -> impl Iterator<Item=(&'t TextSlice, AttributeValue)>
758
        {
759
81
            value.as_ref().map(move |value| (name, to_attribute(value.clone()))).into_iter()
760
81
        }
<exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::Text, exr::meta::attribute::AttributeValue::Text>
Line
Count
Source
752
729
        #[inline] fn optional<'t, T: Clone>(
753
729
            name: &'t TextSlice,
754
729
            to_attribute: impl Fn(T) -> AttributeValue,
755
729
            value: &'t Option<T>
756
729
        )
757
729
           -> impl Iterator<Item=(&'t TextSlice, AttributeValue)>
758
        {
759
729
            value.as_ref().map(move |value| (name, to_attribute(value.clone()))).into_iter()
760
729
        }
<exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::KeyCode, exr::meta::attribute::AttributeValue::KeyCode>
Line
Count
Source
752
81
        #[inline] fn optional<'t, T: Clone>(
753
81
            name: &'t TextSlice,
754
81
            to_attribute: impl Fn(T) -> AttributeValue,
755
81
            value: &'t Option<T>
756
81
        )
757
81
           -> impl Iterator<Item=(&'t TextSlice, AttributeValue)>
758
        {
759
81
            value.as_ref().map(move |value| (name, to_attribute(value.clone()))).into_iter()
760
81
        }
<exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::Preview, exr::meta::attribute::AttributeValue::Preview>
Line
Count
Source
752
81
        #[inline] fn optional<'t, T: Clone>(
753
81
            name: &'t TextSlice,
754
81
            to_attribute: impl Fn(T) -> AttributeValue,
755
81
            value: &'t Option<T>
756
81
        )
757
81
           -> impl Iterator<Item=(&'t TextSlice, AttributeValue)>
758
        {
759
81
            value.as_ref().map(move |value| (name, to_attribute(value.clone()))).into_iter()
760
81
        }
<exr::meta::header::Header>::all_named_attributes::optional::<exr::meta::attribute::TimeCode, exr::meta::attribute::AttributeValue::TimeCode>
Line
Count
Source
752
81
        #[inline] fn optional<'t, T: Clone>(
753
81
            name: &'t TextSlice,
754
81
            to_attribute: impl Fn(T) -> AttributeValue,
755
81
            value: &'t Option<T>
756
81
        )
757
81
           -> impl Iterator<Item=(&'t TextSlice, AttributeValue)>
758
        {
759
81
            value.as_ref().map(move |value| (name, to_attribute(value.clone()))).into_iter()
760
81
        }
<exr::meta::header::Header>::all_named_attributes::optional::<(i32, u32), exr::meta::attribute::AttributeValue::Rational>
Line
Count
Source
752
162
        #[inline] fn optional<'t, T: Clone>(
753
162
            name: &'t TextSlice,
754
162
            to_attribute: impl Fn(T) -> AttributeValue,
755
162
            value: &'t Option<T>
756
162
        )
757
162
           -> impl Iterator<Item=(&'t TextSlice, AttributeValue)>
758
        {
759
162
            value.as_ref().map(move |value| (name, to_attribute(value.clone()))).into_iter()
760
162
        }
<exr::meta::header::Header>::all_named_attributes::optional::<f32, exr::meta::attribute::AttributeValue::F32>
Line
Count
Source
752
1.13k
        #[inline] fn optional<'t, T: Clone>(
753
1.13k
            name: &'t TextSlice,
754
1.13k
            to_attribute: impl Fn(T) -> AttributeValue,
755
1.13k
            value: &'t Option<T>
756
1.13k
        )
757
1.13k
           -> impl Iterator<Item=(&'t TextSlice, AttributeValue)>
758
        {
759
1.13k
            value.as_ref().map(move |value| (name, to_attribute(value.clone()))).into_iter()
760
1.13k
        }
<exr::meta::header::Header>::all_named_attributes::optional::<usize, <exr::meta::header::Header>::all_named_attributes::usize_as_i32>
Line
Count
Source
752
81
        #[inline] fn optional<'t, T: Clone>(
753
81
            name: &'t TextSlice,
754
81
            to_attribute: impl Fn(T) -> AttributeValue,
755
81
            value: &'t Option<T>
756
81
        )
757
81
           -> impl Iterator<Item=(&'t TextSlice, AttributeValue)>
758
        {
759
81
            value.as_ref().map(move |value| (name, to_attribute(value.clone()))).into_iter()
760
81
        }
<exr::meta::header::Header>::all_named_attributes::optional::<i32, exr::meta::attribute::AttributeValue::I32>
Line
Count
Source
752
81
        #[inline] fn optional<'t, T: Clone>(
753
81
            name: &'t TextSlice,
754
81
            to_attribute: impl Fn(T) -> AttributeValue,
755
81
            value: &'t Option<T>
756
81
        )
757
81
           -> impl Iterator<Item=(&'t TextSlice, AttributeValue)>
758
        {
759
81
            value.as_ref().map(move |value| (name, to_attribute(value.clone()))).into_iter()
760
81
        }
761
762
648
        #[inline] fn required<'s, T: Clone>(name: &'s TextSlice, to_attribute: impl Fn(T) -> AttributeValue, value: &'s T)
763
648
            -> impl Iterator<Item=(&'s TextSlice, AttributeValue)>
764
        {
765
648
            once((name, to_attribute((*value).clone())))
766
648
        }
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::required::<_, _>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::required::<exr::math::Vec2<f32>, exr::meta::attribute::AttributeValue::FloatVec2>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::required::<exr::meta::attribute::ChannelList, exr::meta::attribute::AttributeValue::ChannelList>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::required::<exr::meta::attribute::IntegerBounds, exr::meta::attribute::AttributeValue::IntegerBounds>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::required::<exr::meta::attribute::LineOrder, exr::meta::attribute::AttributeValue::LineOrder>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::required::<exr::compression::Compression, exr::meta::attribute::AttributeValue::Compression>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::required::<f32, exr::meta::attribute::AttributeValue::F32>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::required::<usize, <exr::meta::header::Header>::all_named_attributes::usize_as_i32>
<exr::meta::header::Header>::all_named_attributes::required::<exr::math::Vec2<f32>, exr::meta::attribute::AttributeValue::FloatVec2>
Line
Count
Source
762
81
        #[inline] fn required<'s, T: Clone>(name: &'s TextSlice, to_attribute: impl Fn(T) -> AttributeValue, value: &'s T)
763
81
            -> impl Iterator<Item=(&'s TextSlice, AttributeValue)>
764
        {
765
81
            once((name, to_attribute((*value).clone())))
766
81
        }
<exr::meta::header::Header>::all_named_attributes::required::<exr::meta::attribute::ChannelList, exr::meta::attribute::AttributeValue::ChannelList>
Line
Count
Source
762
81
        #[inline] fn required<'s, T: Clone>(name: &'s TextSlice, to_attribute: impl Fn(T) -> AttributeValue, value: &'s T)
763
81
            -> impl Iterator<Item=(&'s TextSlice, AttributeValue)>
764
        {
765
81
            once((name, to_attribute((*value).clone())))
766
81
        }
<exr::meta::header::Header>::all_named_attributes::required::<exr::meta::attribute::IntegerBounds, exr::meta::attribute::AttributeValue::IntegerBounds>
Line
Count
Source
762
81
        #[inline] fn required<'s, T: Clone>(name: &'s TextSlice, to_attribute: impl Fn(T) -> AttributeValue, value: &'s T)
763
81
            -> impl Iterator<Item=(&'s TextSlice, AttributeValue)>
764
        {
765
81
            once((name, to_attribute((*value).clone())))
766
81
        }
<exr::meta::header::Header>::all_named_attributes::required::<exr::meta::attribute::LineOrder, exr::meta::attribute::AttributeValue::LineOrder>
Line
Count
Source
762
81
        #[inline] fn required<'s, T: Clone>(name: &'s TextSlice, to_attribute: impl Fn(T) -> AttributeValue, value: &'s T)
763
81
            -> impl Iterator<Item=(&'s TextSlice, AttributeValue)>
764
        {
765
81
            once((name, to_attribute((*value).clone())))
766
81
        }
<exr::meta::header::Header>::all_named_attributes::required::<exr::compression::Compression, exr::meta::attribute::AttributeValue::Compression>
Line
Count
Source
762
81
        #[inline] fn required<'s, T: Clone>(name: &'s TextSlice, to_attribute: impl Fn(T) -> AttributeValue, value: &'s T)
763
81
            -> impl Iterator<Item=(&'s TextSlice, AttributeValue)>
764
        {
765
81
            once((name, to_attribute((*value).clone())))
766
81
        }
<exr::meta::header::Header>::all_named_attributes::required::<f32, exr::meta::attribute::AttributeValue::F32>
Line
Count
Source
762
162
        #[inline] fn required<'s, T: Clone>(name: &'s TextSlice, to_attribute: impl Fn(T) -> AttributeValue, value: &'s T)
763
162
            -> impl Iterator<Item=(&'s TextSlice, AttributeValue)>
764
        {
765
162
            once((name, to_attribute((*value).clone())))
766
162
        }
<exr::meta::header::Header>::all_named_attributes::required::<usize, <exr::meta::header::Header>::all_named_attributes::usize_as_i32>
Line
Count
Source
762
81
        #[inline] fn required<'s, T: Clone>(name: &'s TextSlice, to_attribute: impl Fn(T) -> AttributeValue, value: &'s T)
763
81
            -> impl Iterator<Item=(&'s TextSlice, AttributeValue)>
764
        {
765
81
            once((name, to_attribute((*value).clone())))
766
81
        }
767
768
        // used to type-check local variables. only requried because you cannot do `let i: impl Iterator<> = ...`
769
486
        #[inline] fn expect_is_iter<'s, T: Iterator<Item=(&'s TextSlice, AttributeValue)>>(val: T) -> T { val }
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::expect_is_iter::<_>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::expect_is_iter::<core::iter::sources::once_with::OnceWith<<exr::meta::header::Header>::all_named_attributes::{closure#1}>>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::expect_is_iter::<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::sources::empty::Empty<(&[u8], exr::meta::attribute::AttributeValue)>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::expect_is_iter::<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::sources::empty::Empty<(&[u8], exr::meta::attribute::AttributeValue)>, core::iter::sources::once::Once<(&[u8], exr::meta::attribute::AttributeValue)>>, core::iter::sources::once::Once<(&[u8], exr::meta::attribute::AttributeValue)>>, core::iter::sources::once::Once<(&[u8], exr::meta::attribute::AttributeValue)>>, core::iter::sources::once::Once<(&[u8], exr::meta::attribute::AttributeValue)>>, core::iter::sources::once::Once<(&[u8], exr::meta::attribute::AttributeValue)>>, core::iter::sources::once::Once<(&[u8], exr::meta::attribute::AttributeValue)>>, core::iter::sources::once::Once<(&[u8], exr::meta::attribute::AttributeValue)>>, core::iter::sources::once::Once<(&[u8], exr::meta::attribute::AttributeValue)>>>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::expect_is_iter::<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::sources::empty::Empty<(&[u8], exr::meta::attribute::AttributeValue)>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::expect_is_iter::<core::iter::adapters::flatten::Flatten<core::iter::sources::once_with::OnceWith<<exr::meta::header::Header>::all_named_attributes::{closure#0}>>>
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::expect_is_iter::<core::iter::adapters::flatten::Flatten<core::iter::sources::once_with::OnceWith<<exr::meta::header::Header>::all_named_attributes::{closure#2}>>>
<exr::meta::header::Header>::all_named_attributes::expect_is_iter::<core::iter::sources::once_with::OnceWith<<exr::meta::header::Header>::all_named_attributes::{closure#1}>>
Line
Count
Source
769
81
        #[inline] fn expect_is_iter<'s, T: Iterator<Item=(&'s TextSlice, AttributeValue)>>(val: T) -> T { val }
<exr::meta::header::Header>::all_named_attributes::expect_is_iter::<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::sources::empty::Empty<(&[u8], exr::meta::attribute::AttributeValue)>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>>
Line
Count
Source
769
81
        #[inline] fn expect_is_iter<'s, T: Iterator<Item=(&'s TextSlice, AttributeValue)>>(val: T) -> T { val }
<exr::meta::header::Header>::all_named_attributes::expect_is_iter::<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::sources::empty::Empty<(&[u8], exr::meta::attribute::AttributeValue)>, core::iter::sources::once::Once<(&[u8], exr::meta::attribute::AttributeValue)>>, core::iter::sources::once::Once<(&[u8], exr::meta::attribute::AttributeValue)>>, core::iter::sources::once::Once<(&[u8], exr::meta::attribute::AttributeValue)>>, core::iter::sources::once::Once<(&[u8], exr::meta::attribute::AttributeValue)>>, core::iter::sources::once::Once<(&[u8], exr::meta::attribute::AttributeValue)>>, core::iter::sources::once::Once<(&[u8], exr::meta::attribute::AttributeValue)>>, core::iter::sources::once::Once<(&[u8], exr::meta::attribute::AttributeValue)>>, core::iter::sources::once::Once<(&[u8], exr::meta::attribute::AttributeValue)>>>
Line
Count
Source
769
81
        #[inline] fn expect_is_iter<'s, T: Iterator<Item=(&'s TextSlice, AttributeValue)>>(val: T) -> T { val }
<exr::meta::header::Header>::all_named_attributes::expect_is_iter::<core::iter::adapters::chain::Chain<core::iter::adapters::chain::Chain<core::iter::sources::empty::Empty<(&[u8], exr::meta::attribute::AttributeValue)>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>, core::option::IntoIter<(&[u8], exr::meta::attribute::AttributeValue)>>>
Line
Count
Source
769
81
        #[inline] fn expect_is_iter<'s, T: Iterator<Item=(&'s TextSlice, AttributeValue)>>(val: T) -> T { val }
<exr::meta::header::Header>::all_named_attributes::expect_is_iter::<core::iter::adapters::flatten::Flatten<core::iter::sources::once_with::OnceWith<<exr::meta::header::Header>::all_named_attributes::{closure#0}>>>
Line
Count
Source
769
81
        #[inline] fn expect_is_iter<'s, T: Iterator<Item=(&'s TextSlice, AttributeValue)>>(val: T) -> T { val }
<exr::meta::header::Header>::all_named_attributes::expect_is_iter::<core::iter::adapters::flatten::Flatten<core::iter::sources::once_with::OnceWith<<exr::meta::header::Header>::all_named_attributes::{closure#2}>>>
Line
Count
Source
769
81
        #[inline] fn expect_is_iter<'s, T: Iterator<Item=(&'s TextSlice, AttributeValue)>>(val: T) -> T { val }
770
771
        macro_rules! iter_all {
772
            ( $( $value:expr ),* ) => {
773
                empty() $( .chain( $value ) )*
774
            };
775
        }
776
777
        macro_rules! required_attributes {
778
            ( $($name: ident : $variant: ident = $value: expr),* ) => {
779
                expect_is_iter(iter_all!(
780
                    $( required($name, $variant, $value) ),*
781
                ))
782
            };
783
        }
784
785
        macro_rules! optional_attributes {
786
            ( $($name: ident : $variant: ident = $value: expr),* ) => {
787
                expect_is_iter(iter_all!(
788
                    $( optional($name, $variant, $value) ),*
789
                ))
790
            };
791
        }
792
793
81
        #[inline] fn usize_as_i32(value: usize) -> AttributeValue {
794
81
            I32(i32::try_from(value).expect("usize exceeds i32 range"))
795
81
        }
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::usize_as_i32
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::usize_as_i32
<exr::meta::header::Header>::all_named_attributes::usize_as_i32
Line
Count
Source
793
81
        #[inline] fn usize_as_i32(value: usize) -> AttributeValue {
794
81
            I32(i32::try_from(value).expect("usize exceeds i32 range"))
795
81
        }
796
797
798
81
        let block_type_and_tiles = expect_is_iter(once_with(move ||{
799
81
            let (block_type, tiles) = match self.blocks {
800
0
                BlockDescription::ScanLines => (attribute::BlockType::ScanLine, None),
801
81
                BlockDescription::Tiles(tiles) => (attribute::BlockType::Tile, Some(tiles))
802
            };
803
804
81
            once((BLOCK_TYPE, BlockType(block_type)))
805
81
                .chain(tiles.map(|tiles| (TILES, TileDescription(tiles))))
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::{closure#0}::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::{closure#0}::{closure#0}
<exr::meta::header::Header>::all_named_attributes::{closure#0}::{closure#0}
Line
Count
Source
805
81
                .chain(tiles.map(|tiles| (TILES, TileDescription(tiles))))
806
81
        }).flatten());
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::{closure#0}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::{closure#0}
<exr::meta::header::Header>::all_named_attributes::{closure#0}
Line
Count
Source
798
81
        let block_type_and_tiles = expect_is_iter(once_with(move ||{
799
81
            let (block_type, tiles) = match self.blocks {
800
0
                BlockDescription::ScanLines => (attribute::BlockType::ScanLine, None),
801
81
                BlockDescription::Tiles(tiles) => (attribute::BlockType::Tile, Some(tiles))
802
            };
803
804
81
            once((BLOCK_TYPE, BlockType(block_type)))
805
81
                .chain(tiles.map(|tiles| (TILES, TileDescription(tiles))))
806
81
        }).flatten());
807
808
81
        let data_window = expect_is_iter(once_with(move ||{
809
81
            (DATA_WINDOW, IntegerBounds(self.data_window()))
810
81
        }));
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::{closure#1}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::{closure#1}
<exr::meta::header::Header>::all_named_attributes::{closure#1}
Line
Count
Source
808
81
        let data_window = expect_is_iter(once_with(move ||{
809
81
            (DATA_WINDOW, IntegerBounds(self.data_window()))
810
81
        }));
811
812
        // dwa writes compression parameters as attribute.
813
81
        let dwa_compr_level = expect_is_iter(
814
81
            once_with(move ||{
815
0
                match self.compression {
816
0
                    attribute::Compression::DWAA(Some(level)) |
817
0
                    attribute::Compression::DWAB(Some(level)) =>
818
0
                        Some((DWA_COMPRESSION_LEVEL, F32(level))),
819
820
81
                    _ => None
821
                }
822
81
            }).flatten()
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::{closure#2}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::{closure#2}
<exr::meta::header::Header>::all_named_attributes::{closure#2}
Line
Count
Source
814
81
            once_with(move ||{
815
0
                match self.compression {
816
0
                    attribute::Compression::DWAA(Some(level)) |
817
0
                    attribute::Compression::DWAB(Some(level)) =>
818
0
                        Some((DWA_COMPRESSION_LEVEL, F32(level))),
819
820
81
                    _ => None
821
                }
822
81
            }).flatten()
823
        );
824
825
81
        let opt_core_attrs = optional_attributes!(
826
81
            DEEP_DATA_VERSION: I32 = &self.deep_data_version,
827
81
            MAX_SAMPLES: usize_as_i32 = &self.max_samples_per_pixel
828
81
        ).chain(block_type_and_tiles).chain(dwa_compr_level);
829
830
81
        let req_core_attrs = required_attributes!(
831
            // chunks is not actually required, but always computed in this library anyways
832
81
            CHUNKS: usize_as_i32 = &self.chunk_count,
833
834
81
            CHANNELS: ChannelList = &self.channels,
835
81
            COMPRESSION: Compression = &self.compression,
836
81
            LINE_ORDER: LineOrder = &self.line_order,
837
838
81
            DISPLAY_WINDOW: IntegerBounds = &self.shared_attributes.display_window,
839
81
            PIXEL_ASPECT: F32 = &self.shared_attributes.pixel_aspect,
840
841
81
            WINDOW_CENTER: FloatVec2 = &self.own_attributes.screen_window_center,
842
81
            WINDOW_WIDTH: F32 = &self.own_attributes.screen_window_width
843
81
        ).chain(data_window);
844
845
81
        let opt_attr = optional_attributes!(
846
81
            NAME: Text = &self.own_attributes.layer_name,
847
81
            WHITE_LUMINANCE: F32 = &self.own_attributes.white_luminance,
848
81
            ADOPTED_NEUTRAL: FloatVec2 = &self.own_attributes.adopted_neutral,
849
81
            RENDERING_TRANSFORM: Text = &self.own_attributes.rendering_transform_name,
850
81
            LOOK_MOD_TRANSFORM: Text = &self.own_attributes.look_modification_transform_name,
851
81
            X_DENSITY: F32 = &self.own_attributes.horizontal_density,
852
81
            OWNER: Text = &self.own_attributes.owner,
853
81
            COMMENTS: Text = &self.own_attributes.comments,
854
81
            CAPTURE_DATE: Text = &self.own_attributes.capture_date,
855
81
            UTC_OFFSET: F32 = &self.own_attributes.utc_offset,
856
81
            LONGITUDE: F32 = &self.own_attributes.longitude,
857
81
            LATITUDE: F32 = &self.own_attributes.latitude,
858
81
            ALTITUDE: F32 = &self.own_attributes.altitude,
859
81
            FOCUS: F32 = &self.own_attributes.focus,
860
81
            EXPOSURE_TIME: F32 = &self.own_attributes.exposure,
861
81
            APERTURE: F32 = &self.own_attributes.aperture,
862
81
            ISO_SPEED: F32 = &self.own_attributes.iso_speed,
863
81
            ENVIRONMENT_MAP: EnvironmentMap = &self.own_attributes.environment_map,
864
81
            KEY_CODE: KeyCode = &self.own_attributes.film_key_code,
865
81
            TIME_CODE: TimeCode = &self.shared_attributes.time_code,
866
81
            WRAP_MODES: Text = &self.own_attributes.wrap_mode_name,
867
81
            FRAMES_PER_SECOND: Rational = &self.own_attributes.frames_per_second,
868
81
            MULTI_VIEW: TextVector = &self.own_attributes.multi_view_names,
869
81
            WORLD_TO_CAMERA: Matrix4x4 = &self.own_attributes.world_to_camera,
870
81
            WORLD_TO_NDC: Matrix4x4 = &self.own_attributes.world_to_normalized_device,
871
81
            DEEP_IMAGE_STATE: Rational = &self.own_attributes.deep_image_state,
872
81
            ORIGINAL_DATA_WINDOW: IntegerBounds = &self.own_attributes.original_data_window,
873
81
            CHROMATICITIES: Chromaticities = &self.shared_attributes.chromaticities,
874
81
            PREVIEW: Preview = &self.own_attributes.preview,
875
81
            VIEW: Text = &self.own_attributes.view_name,
876
81
            NEAR: F32 = &self.own_attributes.near_clip_plane,
877
81
            FAR: F32 = &self.own_attributes.far_clip_plane,
878
81
            FOV_X: F32 = &self.own_attributes.horizontal_field_of_view,
879
81
            FOV_Y: F32 = &self.own_attributes.vertical_field_of_view,
880
81
            SOFTWARE: Text = &self.own_attributes.software_name
881
        );
882
883
81
        let other = self.own_attributes.other.iter()
884
81
            .chain(self.shared_attributes.other.iter())
885
81
            .map(|(name, val)| (name.as_slice(), val.clone())); // TODO no clone
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::{closure#3}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::{closure#3}
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes::{closure#3}
886
887
81
        req_core_attrs
888
81
            .chain(opt_core_attrs)
889
81
            .chain(opt_attr)
890
81
            .chain(other)
891
81
    }
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes
Unexecuted instantiation: <exr::meta::header::Header>::all_named_attributes
<exr::meta::header::Header>::all_named_attributes
Line
Count
Source
747
81
    pub fn all_named_attributes(&self) -> impl '_ + Iterator<Item=(&TextSlice, AttributeValue)> {
748
        use std::iter::{once, once_with, empty};
749
        use crate::meta::header::standard_names::*;
750
        use AttributeValue::*;
751
752
        #[inline] fn optional<'t, T: Clone>(
753
            name: &'t TextSlice,
754
            to_attribute: impl Fn(T) -> AttributeValue,
755
            value: &'t Option<T>
756
        )
757
           -> impl Iterator<Item=(&'t TextSlice, AttributeValue)>
758
        {
759
            value.as_ref().map(move |value| (name, to_attribute(value.clone()))).into_iter()
760
        }
761
762
        #[inline] fn required<'s, T: Clone>(name: &'s TextSlice, to_attribute: impl Fn(T) -> AttributeValue, value: &'s T)
763
            -> impl Iterator<Item=(&'s TextSlice, AttributeValue)>
764
        {
765
            once((name, to_attribute((*value).clone())))
766
        }
767
768
        // used to type-check local variables. only requried because you cannot do `let i: impl Iterator<> = ...`
769
        #[inline] fn expect_is_iter<'s, T: Iterator<Item=(&'s TextSlice, AttributeValue)>>(val: T) -> T { val }
770
771
        macro_rules! iter_all {
772
            ( $( $value:expr ),* ) => {
773
                empty() $( .chain( $value ) )*
774
            };
775
        }
776
777
        macro_rules! required_attributes {
778
            ( $($name: ident : $variant: ident = $value: expr),* ) => {
779
                expect_is_iter(iter_all!(
780
                    $( required($name, $variant, $value) ),*
781
                ))
782
            };
783
        }
784
785
        macro_rules! optional_attributes {
786
            ( $($name: ident : $variant: ident = $value: expr),* ) => {
787
                expect_is_iter(iter_all!(
788
                    $( optional($name, $variant, $value) ),*
789
                ))
790
            };
791
        }
792
793
        #[inline] fn usize_as_i32(value: usize) -> AttributeValue {
794
            I32(i32::try_from(value).expect("usize exceeds i32 range"))
795
        }
796
797
798
81
        let block_type_and_tiles = expect_is_iter(once_with(move ||{
799
            let (block_type, tiles) = match self.blocks {
800
                BlockDescription::ScanLines => (attribute::BlockType::ScanLine, None),
801
                BlockDescription::Tiles(tiles) => (attribute::BlockType::Tile, Some(tiles))
802
            };
803
804
            once((BLOCK_TYPE, BlockType(block_type)))
805
                .chain(tiles.map(|tiles| (TILES, TileDescription(tiles))))
806
81
        }).flatten());
807
808
81
        let data_window = expect_is_iter(once_with(move ||{
809
            (DATA_WINDOW, IntegerBounds(self.data_window()))
810
        }));
811
812
        // dwa writes compression parameters as attribute.
813
81
        let dwa_compr_level = expect_is_iter(
814
81
            once_with(move ||{
815
                match self.compression {
816
                    attribute::Compression::DWAA(Some(level)) |
817
                    attribute::Compression::DWAB(Some(level)) =>
818
                        Some((DWA_COMPRESSION_LEVEL, F32(level))),
819
820
                    _ => None
821
                }
822
81
            }).flatten()
823
        );
824
825
81
        let opt_core_attrs = optional_attributes!(
826
81
            DEEP_DATA_VERSION: I32 = &self.deep_data_version,
827
81
            MAX_SAMPLES: usize_as_i32 = &self.max_samples_per_pixel
828
81
        ).chain(block_type_and_tiles).chain(dwa_compr_level);
829
830
81
        let req_core_attrs = required_attributes!(
831
            // chunks is not actually required, but always computed in this library anyways
832
81
            CHUNKS: usize_as_i32 = &self.chunk_count,
833
834
81
            CHANNELS: ChannelList = &self.channels,
835
81
            COMPRESSION: Compression = &self.compression,
836
81
            LINE_ORDER: LineOrder = &self.line_order,
837
838
81
            DISPLAY_WINDOW: IntegerBounds = &self.shared_attributes.display_window,
839
81
            PIXEL_ASPECT: F32 = &self.shared_attributes.pixel_aspect,
840
841
81
            WINDOW_CENTER: FloatVec2 = &self.own_attributes.screen_window_center,
842
81
            WINDOW_WIDTH: F32 = &self.own_attributes.screen_window_width
843
81
        ).chain(data_window);
844
845
81
        let opt_attr = optional_attributes!(
846
81
            NAME: Text = &self.own_attributes.layer_name,
847
81
            WHITE_LUMINANCE: F32 = &self.own_attributes.white_luminance,
848
81
            ADOPTED_NEUTRAL: FloatVec2 = &self.own_attributes.adopted_neutral,
849
81
            RENDERING_TRANSFORM: Text = &self.own_attributes.rendering_transform_name,
850
81
            LOOK_MOD_TRANSFORM: Text = &self.own_attributes.look_modification_transform_name,
851
81
            X_DENSITY: F32 = &self.own_attributes.horizontal_density,
852
81
            OWNER: Text = &self.own_attributes.owner,
853
81
            COMMENTS: Text = &self.own_attributes.comments,
854
81
            CAPTURE_DATE: Text = &self.own_attributes.capture_date,
855
81
            UTC_OFFSET: F32 = &self.own_attributes.utc_offset,
856
81
            LONGITUDE: F32 = &self.own_attributes.longitude,
857
81
            LATITUDE: F32 = &self.own_attributes.latitude,
858
81
            ALTITUDE: F32 = &self.own_attributes.altitude,
859
81
            FOCUS: F32 = &self.own_attributes.focus,
860
81
            EXPOSURE_TIME: F32 = &self.own_attributes.exposure,
861
81
            APERTURE: F32 = &self.own_attributes.aperture,
862
81
            ISO_SPEED: F32 = &self.own_attributes.iso_speed,
863
81
            ENVIRONMENT_MAP: EnvironmentMap = &self.own_attributes.environment_map,
864
81
            KEY_CODE: KeyCode = &self.own_attributes.film_key_code,
865
81
            TIME_CODE: TimeCode = &self.shared_attributes.time_code,
866
81
            WRAP_MODES: Text = &self.own_attributes.wrap_mode_name,
867
81
            FRAMES_PER_SECOND: Rational = &self.own_attributes.frames_per_second,
868
81
            MULTI_VIEW: TextVector = &self.own_attributes.multi_view_names,
869
81
            WORLD_TO_CAMERA: Matrix4x4 = &self.own_attributes.world_to_camera,
870
81
            WORLD_TO_NDC: Matrix4x4 = &self.own_attributes.world_to_normalized_device,
871
81
            DEEP_IMAGE_STATE: Rational = &self.own_attributes.deep_image_state,
872
81
            ORIGINAL_DATA_WINDOW: IntegerBounds = &self.own_attributes.original_data_window,
873
81
            CHROMATICITIES: Chromaticities = &self.shared_attributes.chromaticities,
874
81
            PREVIEW: Preview = &self.own_attributes.preview,
875
81
            VIEW: Text = &self.own_attributes.view_name,
876
81
            NEAR: F32 = &self.own_attributes.near_clip_plane,
877
81
            FAR: F32 = &self.own_attributes.far_clip_plane,
878
81
            FOV_X: F32 = &self.own_attributes.horizontal_field_of_view,
879
81
            FOV_Y: F32 = &self.own_attributes.vertical_field_of_view,
880
81
            SOFTWARE: Text = &self.own_attributes.software_name
881
        );
882
883
81
        let other = self.own_attributes.other.iter()
884
81
            .chain(self.shared_attributes.other.iter())
885
81
            .map(|(name, val)| (name.as_slice(), val.clone())); // TODO no clone
886
887
81
        req_core_attrs
888
81
            .chain(opt_core_attrs)
889
81
            .chain(opt_attr)
890
81
            .chain(other)
891
81
    }
892
893
    /// Read the value without validating.
894
43.3k
    pub fn read(read: &mut PeekRead<impl Read>, requirements: &Requirements, pedantic: bool) -> Result<Self> {
895
43.3k
        let max_string_len = if requirements.has_long_names { 256 } else { 32 }; // TODO DRY this information
896
897
        // these required attributes will be filled when encountered while parsing
898
43.3k
        let mut tiles = None;
899
43.3k
        let mut block_type = None;
900
43.3k
        let mut version = None;
901
43.3k
        let mut chunk_count = None;
902
43.3k
        let mut max_samples_per_pixel = None;
903
43.3k
        let mut channels = None;
904
43.3k
        let mut compression = None;
905
43.3k
        let mut data_window = None;
906
43.3k
        let mut display_window = None;
907
43.3k
        let mut line_order = None;
908
43.3k
        let mut dwa_compression_level = None;
909
910
43.3k
        let mut layer_attributes = LayerAttributes::default();
911
43.3k
        let mut image_attributes = ImageAttributes::new(IntegerBounds::zero());
912
913
        // read each attribute in this header
914
2.01M
        while !sequence_end::has_come(read)? {
915
1.97M
            let (attribute_name, value) = attribute::read(read, max_string_len)?;
916
917
            // if the attribute value itself is ok, record it
918
1.96M
            match value {
919
1.96M
                Ok(value) => {
920
                    use crate::meta::header::standard_names as name;
921
                    use crate::meta::attribute::AttributeValue::*;
922
923
                    // if the attribute is a required attribute, set the corresponding variable directly.
924
                    // otherwise, add the attribute to the vector of custom attributes
925
926
                    // the following attributes will only be set if the type matches the commonly used type for that attribute
927
1.96M
                    match (attribute_name.as_slice(), value) {
928
1.96M
                        (name::BLOCK_TYPE, Text(value)) => block_type = Some(attribute::BlockType::parse(value)?),
929
1.88M
                        (name::TILES, TileDescription(value)) => tiles = Some(value),
930
1.80M
                        (name::CHANNELS, ChannelList(value)) => channels = Some(value),
931
1.62M
                        (name::COMPRESSION, Compression(value)) => compression = Some(value),
932
1.52M
                        (name::DATA_WINDOW, IntegerBounds(value)) => data_window = Some(value),
933
1.38M
                        (name::DISPLAY_WINDOW, IntegerBounds(value)) => display_window = Some(value),
934
1.26M
                        (name::LINE_ORDER, LineOrder(value)) => line_order = Some(value),
935
1.11M
                        (name::DEEP_DATA_VERSION, I32(value)) => version = Some(value),
936
937
1.03M
                        (name::MAX_SAMPLES, I32(value)) => max_samples_per_pixel = Some(
938
369
                            i32_to_usize(value, "max sample count")?
939
                        ),
940
941
250
                        (name::CHUNKS, I32(value)) => chunk_count = Some(
942
250
                            i32_to_usize(value, "chunk count")?
943
                        ),
944
945
11.8k
                        (name::NAME, Text(value)) => layer_attributes.layer_name = Some(value),
946
1.24k
                        (name::WINDOW_CENTER, FloatVec2(value)) => layer_attributes.screen_window_center = value,
947
919k
                        (name::WINDOW_WIDTH, F32(value)) => layer_attributes.screen_window_width = value,
948
949
881k
                        (name::WHITE_LUMINANCE, F32(value)) => layer_attributes.white_luminance = Some(value),
950
2.20k
                        (name::ADOPTED_NEUTRAL, FloatVec2(value)) => layer_attributes.adopted_neutral = Some(value),
951
3.37k
                        (name::RENDERING_TRANSFORM, Text(value)) => layer_attributes.rendering_transform_name = Some(value),
952
796k
                        (name::LOOK_MOD_TRANSFORM, Text(value)) => layer_attributes.look_modification_transform_name = Some(value),
953
443
                        (name::X_DENSITY, F32(value)) => layer_attributes.horizontal_density = Some(value),
954
955
2.95k
                        (name::OWNER, Text(value)) => layer_attributes.owner = Some(value),
956
886
                        (name::COMMENTS, Text(value)) => layer_attributes.comments = Some(value),
957
5.85k
                        (name::CAPTURE_DATE, Text(value)) => layer_attributes.capture_date = Some(value),
958
85
                        (name::UTC_OFFSET, F32(value)) => layer_attributes.utc_offset = Some(value),
959
0
                        (name::LONGITUDE, F32(value)) => layer_attributes.longitude = Some(value),
960
5.16k
                        (name::LATITUDE, F32(value)) => layer_attributes.latitude = Some(value),
961
132
                        (name::ALTITUDE, F32(value)) => layer_attributes.altitude = Some(value),
962
0
                        (name::FOCUS, F32(value)) => layer_attributes.focus = Some(value),
963
0
                        (name::EXPOSURE_TIME, F32(value)) => layer_attributes.exposure = Some(value),
964
504
                        (name::APERTURE, F32(value)) => layer_attributes.aperture = Some(value),
965
1.82k
                        (name::ISO_SPEED, F32(value)) => layer_attributes.iso_speed = Some(value),
966
746k
                        (name::ENVIRONMENT_MAP, EnvironmentMap(value)) => layer_attributes.environment_map = Some(value),
967
924
                        (name::KEY_CODE, KeyCode(value)) => layer_attributes.film_key_code = Some(value),
968
3.78k
                        (name::WRAP_MODES, Text(value)) => layer_attributes.wrap_mode_name = Some(value),
969
696k
                        (name::FRAMES_PER_SECOND, Rational(value)) => layer_attributes.frames_per_second = Some(value),
970
3.31k
                        (name::MULTI_VIEW, TextVector(value)) => layer_attributes.multi_view_names = Some(value),
971
599
                        (name::WORLD_TO_CAMERA, Matrix4x4(value)) => layer_attributes.world_to_camera = Some(value),
972
467
                        (name::WORLD_TO_NDC, Matrix4x4(value)) => layer_attributes.world_to_normalized_device = Some(value),
973
687
                        (name::DEEP_IMAGE_STATE, Rational(value)) => layer_attributes.deep_image_state = Some(value),
974
1.47k
                        (name::ORIGINAL_DATA_WINDOW, IntegerBounds(value)) => layer_attributes.original_data_window = Some(value),
975
633k
                        (name::DWA_COMPRESSION_LEVEL, F32(value)) => dwa_compression_level = Some(value),
976
594
                        (name::PREVIEW, Preview(value)) => layer_attributes.preview = Some(value),
977
624
                        (name::VIEW, Text(value)) => layer_attributes.view_name = Some(value),
978
979
0
                        (name::NEAR, F32(value)) => layer_attributes.near_clip_plane = Some(value),
980
579k
                        (name::FAR, F32(value)) => layer_attributes.far_clip_plane = Some(value),
981
497k
                        (name::FOV_X, F32(value)) => layer_attributes.horizontal_field_of_view = Some(value),
982
754
                        (name::FOV_Y, F32(value)) => layer_attributes.vertical_field_of_view = Some(value),
983
1.42k
                        (name::SOFTWARE, Text(value)) => layer_attributes.software_name = Some(value),
984
985
2.42k
                        (name::PIXEL_ASPECT, F32(value)) => image_attributes.pixel_aspect = value,
986
0
                        (name::TIME_CODE, TimeCode(value)) => image_attributes.time_code = Some(value),
987
568
                        (name::CHROMATICITIES, Chromaticities(value)) => image_attributes.chromaticities = Some(value),
988
989
                        // insert unknown attributes of these types into image attributes,
990
                        // as these must be the same for all headers
991
5.67k
                        (_, value @ Chromaticities(_)) |
992
29.4k
                        (_, value @ TimeCode(_)) => {
993
29.4k
                            image_attributes.other.insert(attribute_name, value);
994
29.4k
                        },
995
996
                        // insert unknown attributes into layer attributes
997
1.63M
                        (_, value) => {
998
1.63M
                            layer_attributes.other.insert(attribute_name, value);
999
1.63M
                        },
1000
1001
                    }
1002
                },
1003
1004
                // in case the attribute value itself is not ok, but the rest of the image is
1005
                // only abort reading the image if desired
1006
259
                Err(error) => {
1007
259
                    if pedantic { return Err(error); }
1008
                }
1009
            }
1010
        }
1011
1012
        // construct compression with parameters from properties
1013
39.0k
        let compression = match (dwa_compression_level, compression) {
1014
0
            (Some(level), Some(Compression::DWAA(_))) => Some(Compression::DWAA(Some(level))),
1015
0
            (Some(level), Some(Compression::DWAB(_))) => Some(Compression::DWAB(Some(level))),
1016
39.0k
            (_, other) => other,
1017
            // FIXME dwa compression level gets lost if any other compression is used later in the process
1018
        };
1019
1020
39.0k
        let compression = compression.ok_or(missing_attribute("compression"))?;
1021
38.3k
        image_attributes.display_window = display_window.ok_or(missing_attribute("display window"))?;
1022
1023
38.3k
        let data_window = data_window.ok_or(missing_attribute("data window"))?;
1024
38.2k
        data_window.validate(None)?; // validate now to avoid errors when computing the chunk_count
1025
38.2k
        layer_attributes.layer_position = data_window.position;
1026
1027
1028
        // validate now to avoid errors when computing the chunk_count
1029
38.2k
        if let Some(tiles) = tiles { tiles.validate()?; }
1030
38.2k
        let blocks = match block_type {
1031
1.61k
            None if requirements.is_single_layer_and_tiled => {
1032
1.61k
                BlockDescription::Tiles(tiles.ok_or(missing_attribute("tiles"))?)
1033
            },
1034
            Some(BlockType::Tile) | Some(BlockType::DeepTile) => {
1035
7.87k
                BlockDescription::Tiles(tiles.ok_or(missing_attribute("tiles"))?)
1036
            },
1037
1038
28.8k
            _ => BlockDescription::ScanLines,
1039
        };
1040
1041
38.2k
        let computed_chunk_count = compute_chunk_count(compression, data_window.size, blocks);
1042
38.2k
        if chunk_count.is_some() && pedantic && chunk_count != Some(computed_chunk_count) {
1043
3
            return Err(Error::invalid("chunk count not matching data size"));
1044
38.2k
        }
1045
1046
38.2k
        let header = Header {
1047
38.2k
            compression,
1048
1049
            // always compute ourselves, because we cannot trust anyone out there 😱
1050
38.2k
            chunk_count: computed_chunk_count,
1051
1052
38.2k
            layer_size: data_window.size,
1053
1054
38.2k
            shared_attributes: image_attributes,
1055
38.2k
            own_attributes: layer_attributes,
1056
1057
38.2k
            channels: channels.ok_or(missing_attribute("channels"))?,
1058
38.2k
            line_order: line_order.unwrap_or(LineOrder::Unspecified),
1059
1060
38.2k
            blocks,
1061
38.2k
            max_samples_per_pixel,
1062
38.2k
            deep_data_version: version,
1063
38.2k
            deep: block_type == Some(BlockType::DeepScanLine) || block_type == Some(BlockType::DeepTile),
1064
        };
1065
1066
38.2k
        Ok(header)
1067
43.3k
    }
<exr::meta::header::Header>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
Line
Count
Source
894
43.2k
    pub fn read(read: &mut PeekRead<impl Read>, requirements: &Requirements, pedantic: bool) -> Result<Self> {
895
43.2k
        let max_string_len = if requirements.has_long_names { 256 } else { 32 }; // TODO DRY this information
896
897
        // these required attributes will be filled when encountered while parsing
898
43.2k
        let mut tiles = None;
899
43.2k
        let mut block_type = None;
900
43.2k
        let mut version = None;
901
43.2k
        let mut chunk_count = None;
902
43.2k
        let mut max_samples_per_pixel = None;
903
43.2k
        let mut channels = None;
904
43.2k
        let mut compression = None;
905
43.2k
        let mut data_window = None;
906
43.2k
        let mut display_window = None;
907
43.2k
        let mut line_order = None;
908
43.2k
        let mut dwa_compression_level = None;
909
910
43.2k
        let mut layer_attributes = LayerAttributes::default();
911
43.2k
        let mut image_attributes = ImageAttributes::new(IntegerBounds::zero());
912
913
        // read each attribute in this header
914
2.01M
        while !sequence_end::has_come(read)? {
915
1.97M
            let (attribute_name, value) = attribute::read(read, max_string_len)?;
916
917
            // if the attribute value itself is ok, record it
918
1.96M
            match value {
919
1.96M
                Ok(value) => {
920
                    use crate::meta::header::standard_names as name;
921
                    use crate::meta::attribute::AttributeValue::*;
922
923
                    // if the attribute is a required attribute, set the corresponding variable directly.
924
                    // otherwise, add the attribute to the vector of custom attributes
925
926
                    // the following attributes will only be set if the type matches the commonly used type for that attribute
927
1.96M
                    match (attribute_name.as_slice(), value) {
928
1.96M
                        (name::BLOCK_TYPE, Text(value)) => block_type = Some(attribute::BlockType::parse(value)?),
929
1.88M
                        (name::TILES, TileDescription(value)) => tiles = Some(value),
930
1.80M
                        (name::CHANNELS, ChannelList(value)) => channels = Some(value),
931
1.62M
                        (name::COMPRESSION, Compression(value)) => compression = Some(value),
932
1.52M
                        (name::DATA_WINDOW, IntegerBounds(value)) => data_window = Some(value),
933
1.38M
                        (name::DISPLAY_WINDOW, IntegerBounds(value)) => display_window = Some(value),
934
1.26M
                        (name::LINE_ORDER, LineOrder(value)) => line_order = Some(value),
935
1.11M
                        (name::DEEP_DATA_VERSION, I32(value)) => version = Some(value),
936
937
1.03M
                        (name::MAX_SAMPLES, I32(value)) => max_samples_per_pixel = Some(
938
369
                            i32_to_usize(value, "max sample count")?
939
                        ),
940
941
169
                        (name::CHUNKS, I32(value)) => chunk_count = Some(
942
169
                            i32_to_usize(value, "chunk count")?
943
                        ),
944
945
11.8k
                        (name::NAME, Text(value)) => layer_attributes.layer_name = Some(value),
946
1.16k
                        (name::WINDOW_CENTER, FloatVec2(value)) => layer_attributes.screen_window_center = value,
947
919k
                        (name::WINDOW_WIDTH, F32(value)) => layer_attributes.screen_window_width = value,
948
949
880k
                        (name::WHITE_LUMINANCE, F32(value)) => layer_attributes.white_luminance = Some(value),
950
2.20k
                        (name::ADOPTED_NEUTRAL, FloatVec2(value)) => layer_attributes.adopted_neutral = Some(value),
951
3.37k
                        (name::RENDERING_TRANSFORM, Text(value)) => layer_attributes.rendering_transform_name = Some(value),
952
796k
                        (name::LOOK_MOD_TRANSFORM, Text(value)) => layer_attributes.look_modification_transform_name = Some(value),
953
443
                        (name::X_DENSITY, F32(value)) => layer_attributes.horizontal_density = Some(value),
954
955
2.95k
                        (name::OWNER, Text(value)) => layer_attributes.owner = Some(value),
956
886
                        (name::COMMENTS, Text(value)) => layer_attributes.comments = Some(value),
957
5.85k
                        (name::CAPTURE_DATE, Text(value)) => layer_attributes.capture_date = Some(value),
958
85
                        (name::UTC_OFFSET, F32(value)) => layer_attributes.utc_offset = Some(value),
959
0
                        (name::LONGITUDE, F32(value)) => layer_attributes.longitude = Some(value),
960
5.16k
                        (name::LATITUDE, F32(value)) => layer_attributes.latitude = Some(value),
961
132
                        (name::ALTITUDE, F32(value)) => layer_attributes.altitude = Some(value),
962
0
                        (name::FOCUS, F32(value)) => layer_attributes.focus = Some(value),
963
0
                        (name::EXPOSURE_TIME, F32(value)) => layer_attributes.exposure = Some(value),
964
504
                        (name::APERTURE, F32(value)) => layer_attributes.aperture = Some(value),
965
1.82k
                        (name::ISO_SPEED, F32(value)) => layer_attributes.iso_speed = Some(value),
966
746k
                        (name::ENVIRONMENT_MAP, EnvironmentMap(value)) => layer_attributes.environment_map = Some(value),
967
924
                        (name::KEY_CODE, KeyCode(value)) => layer_attributes.film_key_code = Some(value),
968
3.78k
                        (name::WRAP_MODES, Text(value)) => layer_attributes.wrap_mode_name = Some(value),
969
696k
                        (name::FRAMES_PER_SECOND, Rational(value)) => layer_attributes.frames_per_second = Some(value),
970
3.31k
                        (name::MULTI_VIEW, TextVector(value)) => layer_attributes.multi_view_names = Some(value),
971
599
                        (name::WORLD_TO_CAMERA, Matrix4x4(value)) => layer_attributes.world_to_camera = Some(value),
972
467
                        (name::WORLD_TO_NDC, Matrix4x4(value)) => layer_attributes.world_to_normalized_device = Some(value),
973
687
                        (name::DEEP_IMAGE_STATE, Rational(value)) => layer_attributes.deep_image_state = Some(value),
974
1.47k
                        (name::ORIGINAL_DATA_WINDOW, IntegerBounds(value)) => layer_attributes.original_data_window = Some(value),
975
633k
                        (name::DWA_COMPRESSION_LEVEL, F32(value)) => dwa_compression_level = Some(value),
976
594
                        (name::PREVIEW, Preview(value)) => layer_attributes.preview = Some(value),
977
624
                        (name::VIEW, Text(value)) => layer_attributes.view_name = Some(value),
978
979
0
                        (name::NEAR, F32(value)) => layer_attributes.near_clip_plane = Some(value),
980
579k
                        (name::FAR, F32(value)) => layer_attributes.far_clip_plane = Some(value),
981
497k
                        (name::FOV_X, F32(value)) => layer_attributes.horizontal_field_of_view = Some(value),
982
754
                        (name::FOV_Y, F32(value)) => layer_attributes.vertical_field_of_view = Some(value),
983
1.42k
                        (name::SOFTWARE, Text(value)) => layer_attributes.software_name = Some(value),
984
985
2.34k
                        (name::PIXEL_ASPECT, F32(value)) => image_attributes.pixel_aspect = value,
986
0
                        (name::TIME_CODE, TimeCode(value)) => image_attributes.time_code = Some(value),
987
568
                        (name::CHROMATICITIES, Chromaticities(value)) => image_attributes.chromaticities = Some(value),
988
989
                        // insert unknown attributes of these types into image attributes,
990
                        // as these must be the same for all headers
991
5.67k
                        (_, value @ Chromaticities(_)) |
992
29.4k
                        (_, value @ TimeCode(_)) => {
993
29.4k
                            image_attributes.other.insert(attribute_name, value);
994
29.4k
                        },
995
996
                        // insert unknown attributes into layer attributes
997
1.63M
                        (_, value) => {
998
1.63M
                            layer_attributes.other.insert(attribute_name, value);
999
1.63M
                        },
1000
1001
                    }
1002
                },
1003
1004
                // in case the attribute value itself is not ok, but the rest of the image is
1005
                // only abort reading the image if desired
1006
259
                Err(error) => {
1007
259
                    if pedantic { return Err(error); }
1008
                }
1009
            }
1010
        }
1011
1012
        // construct compression with parameters from properties
1013
38.9k
        let compression = match (dwa_compression_level, compression) {
1014
0
            (Some(level), Some(Compression::DWAA(_))) => Some(Compression::DWAA(Some(level))),
1015
0
            (Some(level), Some(Compression::DWAB(_))) => Some(Compression::DWAB(Some(level))),
1016
38.9k
            (_, other) => other,
1017
            // FIXME dwa compression level gets lost if any other compression is used later in the process
1018
        };
1019
1020
38.9k
        let compression = compression.ok_or(missing_attribute("compression"))?;
1021
38.2k
        image_attributes.display_window = display_window.ok_or(missing_attribute("display window"))?;
1022
1023
38.2k
        let data_window = data_window.ok_or(missing_attribute("data window"))?;
1024
38.2k
        data_window.validate(None)?; // validate now to avoid errors when computing the chunk_count
1025
38.2k
        layer_attributes.layer_position = data_window.position;
1026
1027
1028
        // validate now to avoid errors when computing the chunk_count
1029
38.2k
        if let Some(tiles) = tiles { tiles.validate()?; }
1030
38.2k
        let blocks = match block_type {
1031
1.61k
            None if requirements.is_single_layer_and_tiled => {
1032
1.61k
                BlockDescription::Tiles(tiles.ok_or(missing_attribute("tiles"))?)
1033
            },
1034
            Some(BlockType::Tile) | Some(BlockType::DeepTile) => {
1035
7.79k
                BlockDescription::Tiles(tiles.ok_or(missing_attribute("tiles"))?)
1036
            },
1037
1038
28.8k
            _ => BlockDescription::ScanLines,
1039
        };
1040
1041
38.2k
        let computed_chunk_count = compute_chunk_count(compression, data_window.size, blocks);
1042
38.2k
        if chunk_count.is_some() && pedantic && chunk_count != Some(computed_chunk_count) {
1043
3
            return Err(Error::invalid("chunk count not matching data size"));
1044
38.2k
        }
1045
1046
38.1k
        let header = Header {
1047
38.2k
            compression,
1048
1049
            // always compute ourselves, because we cannot trust anyone out there 😱
1050
38.2k
            chunk_count: computed_chunk_count,
1051
1052
38.2k
            layer_size: data_window.size,
1053
1054
38.2k
            shared_attributes: image_attributes,
1055
38.2k
            own_attributes: layer_attributes,
1056
1057
38.2k
            channels: channels.ok_or(missing_attribute("channels"))?,
1058
38.1k
            line_order: line_order.unwrap_or(LineOrder::Unspecified),
1059
1060
38.1k
            blocks,
1061
38.1k
            max_samples_per_pixel,
1062
38.1k
            deep_data_version: version,
1063
38.1k
            deep: block_type == Some(BlockType::DeepScanLine) || block_type == Some(BlockType::DeepTile),
1064
        };
1065
1066
38.1k
        Ok(header)
1067
43.2k
    }
Unexecuted instantiation: <exr::meta::header::Header>::read::<_>
<exr::meta::header::Header>::read::<exr::io::Tracking<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
Line
Count
Source
894
81
    pub fn read(read: &mut PeekRead<impl Read>, requirements: &Requirements, pedantic: bool) -> Result<Self> {
895
81
        let max_string_len = if requirements.has_long_names { 256 } else { 32 }; // TODO DRY this information
896
897
        // these required attributes will be filled when encountered while parsing
898
81
        let mut tiles = None;
899
81
        let mut block_type = None;
900
81
        let mut version = None;
901
81
        let mut chunk_count = None;
902
81
        let mut max_samples_per_pixel = None;
903
81
        let mut channels = None;
904
81
        let mut compression = None;
905
81
        let mut data_window = None;
906
81
        let mut display_window = None;
907
81
        let mut line_order = None;
908
81
        let mut dwa_compression_level = None;
909
910
81
        let mut layer_attributes = LayerAttributes::default();
911
81
        let mut image_attributes = ImageAttributes::new(IntegerBounds::zero());
912
913
        // read each attribute in this header
914
972
        while !sequence_end::has_come(read)? {
915
891
            let (attribute_name, value) = attribute::read(read, max_string_len)?;
916
917
            // if the attribute value itself is ok, record it
918
891
            match value {
919
891
                Ok(value) => {
920
                    use crate::meta::header::standard_names as name;
921
                    use crate::meta::attribute::AttributeValue::*;
922
923
                    // if the attribute is a required attribute, set the corresponding variable directly.
924
                    // otherwise, add the attribute to the vector of custom attributes
925
926
                    // the following attributes will only be set if the type matches the commonly used type for that attribute
927
891
                    match (attribute_name.as_slice(), value) {
928
891
                        (name::BLOCK_TYPE, Text(value)) => block_type = Some(attribute::BlockType::parse(value)?),
929
810
                        (name::TILES, TileDescription(value)) => tiles = Some(value),
930
729
                        (name::CHANNELS, ChannelList(value)) => channels = Some(value),
931
648
                        (name::COMPRESSION, Compression(value)) => compression = Some(value),
932
567
                        (name::DATA_WINDOW, IntegerBounds(value)) => data_window = Some(value),
933
405
                        (name::DISPLAY_WINDOW, IntegerBounds(value)) => display_window = Some(value),
934
324
                        (name::LINE_ORDER, LineOrder(value)) => line_order = Some(value),
935
243
                        (name::DEEP_DATA_VERSION, I32(value)) => version = Some(value),
936
937
243
                        (name::MAX_SAMPLES, I32(value)) => max_samples_per_pixel = Some(
938
0
                            i32_to_usize(value, "max sample count")?
939
                        ),
940
941
81
                        (name::CHUNKS, I32(value)) => chunk_count = Some(
942
81
                            i32_to_usize(value, "chunk count")?
943
                        ),
944
945
0
                        (name::NAME, Text(value)) => layer_attributes.layer_name = Some(value),
946
81
                        (name::WINDOW_CENTER, FloatVec2(value)) => layer_attributes.screen_window_center = value,
947
162
                        (name::WINDOW_WIDTH, F32(value)) => layer_attributes.screen_window_width = value,
948
949
81
                        (name::WHITE_LUMINANCE, F32(value)) => layer_attributes.white_luminance = Some(value),
950
0
                        (name::ADOPTED_NEUTRAL, FloatVec2(value)) => layer_attributes.adopted_neutral = Some(value),
951
0
                        (name::RENDERING_TRANSFORM, Text(value)) => layer_attributes.rendering_transform_name = Some(value),
952
81
                        (name::LOOK_MOD_TRANSFORM, Text(value)) => layer_attributes.look_modification_transform_name = Some(value),
953
0
                        (name::X_DENSITY, F32(value)) => layer_attributes.horizontal_density = Some(value),
954
955
0
                        (name::OWNER, Text(value)) => layer_attributes.owner = Some(value),
956
0
                        (name::COMMENTS, Text(value)) => layer_attributes.comments = Some(value),
957
0
                        (name::CAPTURE_DATE, Text(value)) => layer_attributes.capture_date = Some(value),
958
0
                        (name::UTC_OFFSET, F32(value)) => layer_attributes.utc_offset = Some(value),
959
0
                        (name::LONGITUDE, F32(value)) => layer_attributes.longitude = Some(value),
960
0
                        (name::LATITUDE, F32(value)) => layer_attributes.latitude = Some(value),
961
0
                        (name::ALTITUDE, F32(value)) => layer_attributes.altitude = Some(value),
962
0
                        (name::FOCUS, F32(value)) => layer_attributes.focus = Some(value),
963
0
                        (name::EXPOSURE_TIME, F32(value)) => layer_attributes.exposure = Some(value),
964
0
                        (name::APERTURE, F32(value)) => layer_attributes.aperture = Some(value),
965
0
                        (name::ISO_SPEED, F32(value)) => layer_attributes.iso_speed = Some(value),
966
0
                        (name::ENVIRONMENT_MAP, EnvironmentMap(value)) => layer_attributes.environment_map = Some(value),
967
0
                        (name::KEY_CODE, KeyCode(value)) => layer_attributes.film_key_code = Some(value),
968
0
                        (name::WRAP_MODES, Text(value)) => layer_attributes.wrap_mode_name = Some(value),
969
0
                        (name::FRAMES_PER_SECOND, Rational(value)) => layer_attributes.frames_per_second = Some(value),
970
0
                        (name::MULTI_VIEW, TextVector(value)) => layer_attributes.multi_view_names = Some(value),
971
0
                        (name::WORLD_TO_CAMERA, Matrix4x4(value)) => layer_attributes.world_to_camera = Some(value),
972
0
                        (name::WORLD_TO_NDC, Matrix4x4(value)) => layer_attributes.world_to_normalized_device = Some(value),
973
0
                        (name::DEEP_IMAGE_STATE, Rational(value)) => layer_attributes.deep_image_state = Some(value),
974
0
                        (name::ORIGINAL_DATA_WINDOW, IntegerBounds(value)) => layer_attributes.original_data_window = Some(value),
975
0
                        (name::DWA_COMPRESSION_LEVEL, F32(value)) => dwa_compression_level = Some(value),
976
0
                        (name::PREVIEW, Preview(value)) => layer_attributes.preview = Some(value),
977
0
                        (name::VIEW, Text(value)) => layer_attributes.view_name = Some(value),
978
979
0
                        (name::NEAR, F32(value)) => layer_attributes.near_clip_plane = Some(value),
980
0
                        (name::FAR, F32(value)) => layer_attributes.far_clip_plane = Some(value),
981
0
                        (name::FOV_X, F32(value)) => layer_attributes.horizontal_field_of_view = Some(value),
982
0
                        (name::FOV_Y, F32(value)) => layer_attributes.vertical_field_of_view = Some(value),
983
0
                        (name::SOFTWARE, Text(value)) => layer_attributes.software_name = Some(value),
984
985
81
                        (name::PIXEL_ASPECT, F32(value)) => image_attributes.pixel_aspect = value,
986
0
                        (name::TIME_CODE, TimeCode(value)) => image_attributes.time_code = Some(value),
987
0
                        (name::CHROMATICITIES, Chromaticities(value)) => image_attributes.chromaticities = Some(value),
988
989
                        // insert unknown attributes of these types into image attributes,
990
                        // as these must be the same for all headers
991
0
                        (_, value @ Chromaticities(_)) |
992
0
                        (_, value @ TimeCode(_)) => {
993
0
                            image_attributes.other.insert(attribute_name, value);
994
0
                        },
995
996
                        // insert unknown attributes into layer attributes
997
0
                        (_, value) => {
998
0
                            layer_attributes.other.insert(attribute_name, value);
999
0
                        },
1000
1001
                    }
1002
                },
1003
1004
                // in case the attribute value itself is not ok, but the rest of the image is
1005
                // only abort reading the image if desired
1006
0
                Err(error) => {
1007
0
                    if pedantic { return Err(error); }
1008
                }
1009
            }
1010
        }
1011
1012
        // construct compression with parameters from properties
1013
81
        let compression = match (dwa_compression_level, compression) {
1014
0
            (Some(level), Some(Compression::DWAA(_))) => Some(Compression::DWAA(Some(level))),
1015
0
            (Some(level), Some(Compression::DWAB(_))) => Some(Compression::DWAB(Some(level))),
1016
81
            (_, other) => other,
1017
            // FIXME dwa compression level gets lost if any other compression is used later in the process
1018
        };
1019
1020
81
        let compression = compression.ok_or(missing_attribute("compression"))?;
1021
81
        image_attributes.display_window = display_window.ok_or(missing_attribute("display window"))?;
1022
1023
81
        let data_window = data_window.ok_or(missing_attribute("data window"))?;
1024
81
        data_window.validate(None)?; // validate now to avoid errors when computing the chunk_count
1025
81
        layer_attributes.layer_position = data_window.position;
1026
1027
1028
        // validate now to avoid errors when computing the chunk_count
1029
81
        if let Some(tiles) = tiles { tiles.validate()?; }
1030
81
        let blocks = match block_type {
1031
0
            None if requirements.is_single_layer_and_tiled => {
1032
0
                BlockDescription::Tiles(tiles.ok_or(missing_attribute("tiles"))?)
1033
            },
1034
            Some(BlockType::Tile) | Some(BlockType::DeepTile) => {
1035
81
                BlockDescription::Tiles(tiles.ok_or(missing_attribute("tiles"))?)
1036
            },
1037
1038
0
            _ => BlockDescription::ScanLines,
1039
        };
1040
1041
81
        let computed_chunk_count = compute_chunk_count(compression, data_window.size, blocks);
1042
81
        if chunk_count.is_some() && pedantic && chunk_count != Some(computed_chunk_count) {
1043
0
            return Err(Error::invalid("chunk count not matching data size"));
1044
81
        }
1045
1046
81
        let header = Header {
1047
81
            compression,
1048
1049
            // always compute ourselves, because we cannot trust anyone out there 😱
1050
81
            chunk_count: computed_chunk_count,
1051
1052
81
            layer_size: data_window.size,
1053
1054
81
            shared_attributes: image_attributes,
1055
81
            own_attributes: layer_attributes,
1056
1057
81
            channels: channels.ok_or(missing_attribute("channels"))?,
1058
81
            line_order: line_order.unwrap_or(LineOrder::Unspecified),
1059
1060
81
            blocks,
1061
81
            max_samples_per_pixel,
1062
81
            deep_data_version: version,
1063
81
            deep: block_type == Some(BlockType::DeepScanLine) || block_type == Some(BlockType::DeepTile),
1064
        };
1065
1066
81
        Ok(header)
1067
81
    }
1068
1069
    /// Without validation, write this instance to the byte stream.
1070
81
    pub fn write(&self, write: &mut impl Write) -> UnitResult {
1071
891
        for (name, value) in self.all_named_attributes() {
1072
891
            attribute::write(name, &value, write)?;
1073
        }
1074
1075
81
        sequence_end::write(write)?;
1076
81
        Ok(())
1077
81
    }
Unexecuted instantiation: <exr::meta::header::Header>::write::<_>
Unexecuted instantiation: <exr::meta::header::Header>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
<exr::meta::header::Header>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>>
Line
Count
Source
1070
81
    pub fn write(&self, write: &mut impl Write) -> UnitResult {
1071
891
        for (name, value) in self.all_named_attributes() {
1072
891
            attribute::write(name, &value, write)?;
1073
        }
1074
1075
81
        sequence_end::write(write)?;
1076
81
        Ok(())
1077
81
    }
1078
1079
    /// The rectangle describing the bounding box of this layer
1080
    /// within the infinite global 2D space of the file.
1081
380k
    pub fn data_window(&self) -> IntegerBounds {
1082
380k
        IntegerBounds::new(self.own_attributes.layer_position, self.layer_size)
1083
380k
    }
1084
}
1085
1086
1087
1088
/// Collection of required attribute names.
1089
pub mod standard_names {
1090
    macro_rules! define_required_attribute_names {
1091
        ( $($name: ident  :  $value: expr),* ) => {
1092
1093
            /// A list containing all reserved names.
1094
            pub const ALL: &'static [&'static [u8]] = &[
1095
                $( $value ),*
1096
            ];
1097
1098
            $(
1099
                /// The byte-string name of this required attribute as it appears in an exr file.
1100
                pub const $name: &'static [u8] = $value;
1101
            )*
1102
        };
1103
    }
1104
1105
    define_required_attribute_names! {
1106
        TILES: b"tiles",
1107
        NAME: b"name",
1108
        BLOCK_TYPE: b"type",
1109
        DEEP_DATA_VERSION: b"version",
1110
        CHUNKS: b"chunkCount",
1111
        MAX_SAMPLES: b"maxSamplesPerPixel",
1112
        CHANNELS: b"channels",
1113
        COMPRESSION: b"compression",
1114
        DATA_WINDOW: b"dataWindow",
1115
        DISPLAY_WINDOW: b"displayWindow",
1116
        LINE_ORDER: b"lineOrder",
1117
        PIXEL_ASPECT: b"pixelAspectRatio",
1118
        WINDOW_CENTER: b"screenWindowCenter",
1119
        WINDOW_WIDTH: b"screenWindowWidth",
1120
        WHITE_LUMINANCE: b"whiteLuminance",
1121
        ADOPTED_NEUTRAL: b"adoptedNeutral",
1122
        RENDERING_TRANSFORM: b"renderingTransform",
1123
        LOOK_MOD_TRANSFORM: b"lookModTransform",
1124
        X_DENSITY: b"xDensity",
1125
        OWNER: b"owner",
1126
        COMMENTS: b"comments",
1127
        CAPTURE_DATE: b"capDate",
1128
        UTC_OFFSET: b"utcOffset",
1129
        LONGITUDE: b"longitude",
1130
        LATITUDE: b"latitude",
1131
        ALTITUDE: b"altitude",
1132
        FOCUS: b"focus",
1133
        EXPOSURE_TIME: b"expTime",
1134
        APERTURE: b"aperture",
1135
        ISO_SPEED: b"isoSpeed",
1136
        ENVIRONMENT_MAP: b"envmap",
1137
        KEY_CODE: b"keyCode",
1138
        TIME_CODE: b"timeCode",
1139
        WRAP_MODES: b"wrapmodes",
1140
        FRAMES_PER_SECOND: b"framesPerSecond",
1141
        MULTI_VIEW: b"multiView",
1142
        WORLD_TO_CAMERA: b"worldToCamera",
1143
        WORLD_TO_NDC: b"worldToNDC",
1144
        DEEP_IMAGE_STATE: b"deepImageState",
1145
        ORIGINAL_DATA_WINDOW: b"originalDataWindow",
1146
        DWA_COMPRESSION_LEVEL: b"dwaCompressionLevel",
1147
        PREVIEW: b"preview",
1148
        VIEW: b"view",
1149
        CHROMATICITIES: b"chromaticities",
1150
        NEAR: b"near",
1151
        FAR: b"far",
1152
        FOV_X: b"fieldOfViewHorizontal",
1153
        FOV_Y: b"fieldOfViewVertical",
1154
        SOFTWARE: b"software"
1155
    }
1156
}
1157
1158
1159
impl Default for LayerAttributes {
1160
43.4k
    fn default() -> Self {
1161
43.4k
        Self {
1162
43.4k
            layer_position: Vec2(0, 0),
1163
43.4k
            screen_window_center: Vec2(0.0, 0.0),
1164
43.4k
            screen_window_width: 1.0,
1165
43.4k
            layer_name: None,
1166
43.4k
            white_luminance: None,
1167
43.4k
            adopted_neutral: None,
1168
43.4k
            rendering_transform_name: None,
1169
43.4k
            look_modification_transform_name: None,
1170
43.4k
            horizontal_density: None,
1171
43.4k
            owner: None,
1172
43.4k
            comments: None,
1173
43.4k
            capture_date: None,
1174
43.4k
            utc_offset: None,
1175
43.4k
            longitude: None,
1176
43.4k
            latitude: None,
1177
43.4k
            altitude: None,
1178
43.4k
            focus: None,
1179
43.4k
            exposure: None,
1180
43.4k
            aperture: None,
1181
43.4k
            iso_speed: None,
1182
43.4k
            environment_map: None,
1183
43.4k
            film_key_code: None,
1184
43.4k
            wrap_mode_name: None,
1185
43.4k
            frames_per_second: None,
1186
43.4k
            multi_view_names: None,
1187
43.4k
            world_to_camera: None,
1188
43.4k
            world_to_normalized_device: None,
1189
43.4k
            deep_image_state: None,
1190
43.4k
            original_data_window: None,
1191
43.4k
            preview: None,
1192
43.4k
            view_name: None,
1193
43.4k
            software_name: None,
1194
43.4k
            near_clip_plane: None,
1195
43.4k
            far_clip_plane: None,
1196
43.4k
            horizontal_field_of_view: None,
1197
43.4k
            vertical_field_of_view: None,
1198
43.4k
            other: Default::default()
1199
43.4k
        }
1200
43.4k
    }
1201
}
1202
1203
impl std::fmt::Debug for LayerAttributes {
1204
0
    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1205
0
        let default_self = Self::default();
1206
1207
0
        let mut debug = formatter.debug_struct("LayerAttributes (default values omitted)");
1208
1209
        // always debug the following field
1210
0
        debug.field("name", &self.layer_name);
1211
1212
        macro_rules! debug_non_default_fields {
1213
            ( $( $name: ident ),* ) => { $(
1214
1215
                if self.$name != default_self.$name {
1216
                    debug.field(stringify!($name), &self.$name);
1217
                }
1218
1219
            )* };
1220
        }
1221
1222
        // only debug these fields if they are not the default value
1223
0
        debug_non_default_fields! {
1224
            screen_window_center, screen_window_width,
1225
            white_luminance, adopted_neutral, horizontal_density,
1226
            rendering_transform_name, look_modification_transform_name,
1227
            owner, comments,
1228
            capture_date, utc_offset,
1229
            longitude, latitude, altitude,
1230
            focus, exposure, aperture, iso_speed,
1231
            environment_map, film_key_code, wrap_mode_name,
1232
            frames_per_second, multi_view_names,
1233
            world_to_camera, world_to_normalized_device,
1234
            deep_image_state, original_data_window,
1235
            preview, view_name,
1236
            vertical_field_of_view, horizontal_field_of_view,
1237
            near_clip_plane, far_clip_plane, software_name
1238
        }
1239
1240
0
        for (name, value) in &self.other {
1241
0
            debug.field(&format!("\"{}\"", name), value);
1242
0
        }
1243
1244
        // debug.finish_non_exhaustive() TODO
1245
0
        debug.finish()
1246
0
    }
1247
}