Coverage Report

Created: 2025-12-20 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/exr-1.74.0/src/image/mod.rs
Line
Count
Source
1
2
//! Data structures that represent a complete exr image.
3
//! Contains generic structs that must be nested to obtain a complete image type.
4
//!
5
//!
6
//! For example, an rgba image containing multiple layers
7
//! can be represented using `Image<Layers<SpecificChannels<MyPixelStorage>>>`.
8
//! An image containing a single layer with arbitrary channels and no deep data
9
//! can be represented using `Image<Layer<AnyChannels<FlatSamples>>>`.
10
//!
11
//!
12
//! These and other predefined types are included in this module as
13
//! 1. `PixelImage`: A single layer, fixed set of arbitrary channels.
14
//! 1. `PixelLayersImage`: Multiple layers, fixed set of arbitrary channels.
15
//! 1. `RgbaImage`: A single layer, fixed set of channels: rgb, optional a.
16
//! 1. `RgbaLayersImage`: Multiple layers, fixed set of channels: rgb, optional a.
17
//! 1. `FlatImage`: Multiple layers, any channels, no deep data.
18
//! 1. `AnyImage`: All supported data (multiple layers, arbitrary channels, no deep data yet)
19
//!
20
//! You can also use your own types inside an image,
21
//! for example if you want to use a custom sample storage.
22
//!
23
//! This is the high-level interface for the pixels of an image.
24
//! See `exr::blocks` module for a low-level interface.
25
26
pub mod read;
27
pub mod write;
28
pub mod crop;
29
pub mod pixel_vec;
30
pub mod recursive;
31
// pub mod channel_groups;
32
33
34
use crate::meta::header::{ImageAttributes, LayerAttributes};
35
use crate::meta::attribute::{Text, LineOrder};
36
use half::f16;
37
use crate::math::{Vec2, RoundingMode};
38
use crate::compression::Compression;
39
use smallvec::{SmallVec};
40
use crate::error::Error;
41
42
/// Don't do anything
43
718k
pub(crate) fn ignore_progress(_progress: f64){}
44
45
/// This image type contains all supported exr features and can represent almost any image.
46
/// It currently does not support deep data yet.
47
pub type AnyImage = Image<Layers<AnyChannels<Levels<FlatSamples>>>>;
48
49
/// This image type contains the most common exr features and can represent almost any plain image.
50
/// Does not contain resolution levels. Does not support deep data.
51
pub type FlatImage = Image<Layers<AnyChannels<FlatSamples>>>;
52
53
/// This image type contains multiple layers, with each layer containing a user-defined type of pixels.
54
pub type PixelLayersImage<Storage, Channels> = Image<Layers<SpecificChannels<Storage, Channels>>>;
55
56
/// This image type contains a single layer containing a user-defined type of pixels.
57
pub type PixelImage<Storage, Channels> = Image<Layer<SpecificChannels<Storage, Channels>>>;
58
59
/// This image type contains multiple layers, with each layer containing a user-defined type of rgba pixels.
60
pub type RgbaLayersImage<Storage> = PixelLayersImage<Storage, RgbaChannels>;
61
62
/// This image type contains a single layer containing a user-defined type of rgba pixels.
63
pub type RgbaImage<Storage> = PixelImage<Storage, RgbaChannels>;
64
65
/// Contains information about the channels in an rgba image, in the order `(red, green, blue, alpha)`.
66
/// The alpha channel is not required. May be `None` if the image did not contain an alpha channel.
67
pub type RgbaChannels = (ChannelDescription, ChannelDescription, ChannelDescription, Option<ChannelDescription>);
68
69
/// Contains information about the channels in an rgb image, in the order `(red, green, blue)`.
70
pub type RgbChannels = (ChannelDescription, ChannelDescription, ChannelDescription);
71
72
/// The complete exr image.
73
/// `Layers` can be either a single `Layer` or `Layers`.
74
#[derive(Debug, Clone, PartialEq)]
75
pub struct Image<Layers> {
76
77
    /// Attributes that apply to the whole image file.
78
    /// These attributes appear in each layer of the file.
79
    /// Excludes technical meta data.
80
    /// Each layer in this image also has its own attributes.
81
    pub attributes: ImageAttributes,
82
83
    /// The layers contained in the image file.
84
    /// Can be either a single `Layer` or a list of layers.
85
    pub layer_data: Layers,
86
}
87
88
/// A list of layers. `Channels` can be `SpecificChannels` or `AnyChannels`.
89
pub type Layers<Channels> = SmallVec<[Layer<Channels>; 2]>;
90
91
/// A single Layer, including fancy attributes and compression settings.
92
/// `Channels` can be either `SpecificChannels` or `AnyChannels`
93
#[derive(Debug, Clone, PartialEq)]
94
pub struct Layer<Channels> {
95
96
    /// The actual pixel data. Either `SpecificChannels` or `AnyChannels`
97
    pub channel_data: Channels,
98
99
    /// Attributes that apply to this layer.
100
    /// May still contain attributes that should be considered global for an image file.
101
    /// Excludes technical meta data: Does not contain data window size, line order, tiling, or compression attributes.
102
    /// The image also has attributes, which do not differ per layer.
103
    pub attributes: LayerAttributes,
104
105
    /// The pixel resolution of this layer.
106
    /// See `layer.attributes` for more attributes, like for example layer position.
107
    pub size: Vec2<usize>,
108
109
    /// How the pixels are split up and compressed.
110
    pub encoding: Encoding
111
}
112
113
/// How the pixels are split up and compressed.
114
#[derive(Copy, Clone, Debug, PartialEq)]
115
pub struct Encoding {
116
117
    /// How the pixel data of all channels in this layer is compressed. May be `Compression::Uncompressed`.
118
    /// See `layer.attributes` for more attributes.
119
    pub compression: Compression,
120
121
    /// Describes how the pixels of this layer are divided into smaller blocks.
122
    /// Either splits the image into its scan lines or splits the image into tiles of the specified size.
123
    /// A single block can be loaded without processing all bytes of a file.
124
    pub blocks: Blocks,
125
126
    /// In what order the tiles of this header occur in the file.
127
    /// Does not change any actual image orientation.
128
    /// See `layer.attributes` for more attributes.
129
    pub line_order: LineOrder,
130
}
131
132
/// How the image pixels are split up into separate blocks.
133
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
134
pub enum Blocks {
135
136
    /// The image is divided into scan line blocks.
137
    /// The number of scan lines in a block depends on the compression method.
138
    ScanLines,
139
140
    /// The image is divided into tile blocks.
141
    /// Also specifies the size of each tile in the image
142
    /// and whether this image contains multiple resolution levels.
143
    ///
144
    /// The inner `Vec2` describes the size of each tile.
145
    /// Stays the same number of pixels across all levels.
146
    Tiles (Vec2<usize>)
147
}
148
149
150
/// A grid of pixels. The pixels are written to your custom pixel storage.
151
/// `PixelStorage` can be anything, from a flat `Vec<f16>` to `Vec<Vec<AnySample>>`, as desired.
152
/// In order to write this image to a file, your `PixelStorage` must implement [`GetPixel`].
153
#[derive(Debug, Clone, PartialEq, Eq)]
154
pub struct SpecificChannels<Pixels, ChannelsDescription> {
155
156
    /// A description of the channels in the file, as opposed to the channels in memory.
157
    /// Should always be a tuple containing `ChannelDescription`s, one description for each channel.
158
    pub channels: ChannelsDescription, // TODO this is awkward. can this be not a type parameter please? maybe vec<option<chan_info>> ??
159
160
    /// Your custom pixel storage
161
    // TODO should also support `Levels<YourStorage>`, where levels are desired!
162
    pub pixels: Pixels, // TODO rename to "pixels"?
163
}
164
165
166
/// A dynamic list of arbitrary channels.
167
/// `Samples` can currently only be `FlatSamples` or `Levels<FlatSamples>`.
168
#[derive(Debug, Clone, PartialEq)]
169
pub struct AnyChannels<Samples> {
170
171
    /// This list must be sorted alphabetically, by channel name.
172
    /// Use `AnyChannels::sorted` for automatic sorting.
173
    pub list: SmallVec<[AnyChannel<Samples>; 4]>
174
}
175
176
/// A single arbitrary channel.
177
/// `Samples` can currently only be `FlatSamples` or `Levels<FlatSamples>`
178
#[derive(Debug, Clone, PartialEq)]
179
pub struct AnyChannel<Samples> {
180
181
    /// One of "R", "G", or "B" most of the time.
182
    pub name: Text,
183
184
    /// The actual pixel data.
185
    /// Can be `FlatSamples` or `Levels<FlatSamples>`.
186
    pub sample_data: Samples,
187
188
    /// This attribute only tells lossy compression methods
189
    /// whether this value should be quantized exponentially or linearly.
190
    ///
191
    /// Should be `false` for red, green, blue and luma channels, as they are not perceived linearly.
192
    /// Should be `true` for hue, chroma, saturation, and alpha channels.
193
    pub quantize_linearly: bool,
194
195
    /// How many of the samples are skipped compared to the other channels in this layer.
196
    ///
197
    /// Can be used for chroma subsampling for manual lossy data compression.
198
    /// Values other than 1 are allowed only in flat, scan-line based images.
199
    /// If an image is deep or tiled, the sampling rates for all of its channels must be 1.
200
    pub sampling: Vec2<usize>,
201
}
202
203
/// One or multiple resolution levels of the same image.
204
/// `Samples` can be `FlatSamples`.
205
#[derive(Debug, Clone, PartialEq, Eq)]
206
pub enum Levels<Samples> {
207
208
    /// A single image without smaller versions of itself.
209
    /// If you only want to handle exclusively this case, use `Samples` directly, and not `Levels<Samples>`.
210
    Singular(Samples),
211
212
    /// Contains uniformly scaled smaller versions of the original.
213
    Mip
214
    {
215
        /// Whether to round up or down when calculating Mip/Rip levels.
216
        rounding_mode: RoundingMode,
217
218
        /// The smaller versions of the original.
219
        level_data: LevelMaps<Samples>
220
    },
221
222
    /// Contains any possible combination of smaller versions of the original.
223
    Rip
224
    {
225
        /// Whether to round up or down when calculating Mip/Rip levels.
226
        rounding_mode: RoundingMode,
227
228
        /// The smaller versions of the original.
229
        level_data: RipMaps<Samples>
230
    },
231
}
232
233
/// A list of resolution levels. `Samples` can currently only be `FlatSamples`.
234
// or `DeepAndFlatSamples` (not yet implemented).
235
pub type LevelMaps<Samples> = Vec<Samples>;
236
237
/// In addition to the full resolution image,
238
/// this layer also contains smaller versions,
239
/// and each smaller version has further versions with varying aspect ratios.
240
/// `Samples` can currently only be `FlatSamples`.
241
#[derive(Debug, Clone, PartialEq, Eq)]
242
pub struct RipMaps<Samples> {
243
244
    /// A flattened list containing the individual levels
245
    pub map_data: LevelMaps<Samples>,
246
247
    /// The number of levels that were generated along the x-axis and y-axis.
248
    pub level_count: Vec2<usize>,
249
}
250
251
252
// TODO deep data
253
/*#[derive(Clone, PartialEq)]
254
pub enum DeepAndFlatSamples {
255
    Deep(DeepSamples),
256
    Flat(FlatSamples)
257
}*/
258
259
/// A vector of non-deep values (one value per pixel per channel).
260
/// Stores row after row in a single vector.
261
/// The precision of all values is either `f16`, `f32` or `u32`.
262
///
263
/// Since this is close to the pixel layout in the byte file,
264
/// this will most likely be the fastest storage.
265
/// Using a different storage, for example `SpecificChannels`,
266
/// will probably be slower.
267
#[derive(Clone, PartialEq)] // debug is implemented manually
268
pub enum FlatSamples {
269
270
    /// A vector of non-deep `f16` values.
271
    F16(Vec<f16>),
272
273
    /// A vector of non-deep `f32` values.
274
    F32(Vec<f32>),
275
276
    /// A vector of non-deep `u32` values.
277
    U32(Vec<u32>),
278
}
279
280
281
/*#[derive(Clone, PartialEq)]
282
pub enum DeepSamples {
283
    F16(Vec<Vec<f16>>),
284
    F32(Vec<Vec<f32>>),
285
    U32(Vec<Vec<u32>>),
286
}*/
287
288
use crate::block::samples::*;
289
use crate::meta::attribute::*;
290
use crate::error::Result;
291
use crate::block::samples::Sample;
292
use crate::image::write::channels::*;
293
use crate::image::write::layers::WritableLayers;
294
use crate::image::write::samples::{WritableSamples};
295
use crate::meta::{mip_map_levels, rip_map_levels};
296
use crate::io::Data;
297
use crate::image::recursive::{NoneMore, Recursive, IntoRecursive};
298
use std::marker::PhantomData;
299
use std::ops::Not;
300
use crate::image::validate_results::{ValidationOptions};
301
302
303
impl<Channels> Layer<Channels> {
304
    /// Sometimes called "data window"
305
0
    pub fn absolute_bounds(&self) -> IntegerBounds {
306
0
        IntegerBounds::new(self.attributes.layer_position, self.size)
307
0
    }
308
}
309
310
311
impl<SampleStorage, Channels> SpecificChannels<SampleStorage, Channels> {
312
    /// Create some pixels with channel information.
313
    /// The `Channels` must be a tuple containing either `ChannelDescription` or `Option<ChannelDescription>`.
314
    /// The length of the tuple dictates the number of channels in the sample storage.
315
0
    pub fn new(channels: Channels, source_samples: SampleStorage) -> Self
316
0
        where
317
0
            SampleStorage: GetPixel,
318
0
            SampleStorage::Pixel: IntoRecursive,
319
0
            Channels: Sync + Clone + IntoRecursive,
320
0
            <Channels as IntoRecursive>::Recursive: WritableChannelsDescription<<SampleStorage::Pixel as IntoRecursive>::Recursive>,
321
    {
322
0
        SpecificChannels { channels, pixels: source_samples }
323
0
    }
324
}
325
326
/// Convert this type into one of the known sample types.
327
/// Also specify the preferred native type, which dictates the default sample type in the image.
328
pub trait IntoSample: IntoNativeSample {
329
330
    /// The native sample types that this type should be converted to.
331
    const PREFERRED_SAMPLE_TYPE: SampleType;
332
}
333
334
impl IntoSample for f16 { const PREFERRED_SAMPLE_TYPE: SampleType = SampleType::F16; }
335
impl IntoSample for f32 { const PREFERRED_SAMPLE_TYPE: SampleType = SampleType::F32; }
336
impl IntoSample for u32 { const PREFERRED_SAMPLE_TYPE: SampleType = SampleType::U32; }
337
338
/// Used to construct a `SpecificChannels`.
339
/// Call `with_named_channel` as many times as desired,
340
/// and then call `with_pixels` to define the colors.
341
#[derive(Debug)]
342
pub struct SpecificChannelsBuilder<RecursiveChannels, RecursivePixel> {
343
    channels: RecursiveChannels,
344
    px: PhantomData<RecursivePixel>
345
}
346
347
/// This check can be executed at compile time
348
/// if the channel names are `&'static str` and the compiler is smart enough.
349
pub trait CheckDuplicates {
350
351
    /// Check for duplicate channel names.
352
    fn already_contains(&self, name: &Text) -> bool;
353
}
354
355
impl CheckDuplicates for NoneMore {
356
9.07k
    fn already_contains(&self, _: &Text) -> bool { false }
357
}
358
359
impl<Inner: CheckDuplicates> CheckDuplicates for Recursive<Inner, ChannelDescription> {
360
0
    fn already_contains(&self, name: &Text) -> bool {
361
0
        &self.value.name == name || self.inner.already_contains(name)
362
0
    }
363
}
364
365
impl SpecificChannels<(),()>
366
{
367
    /// Start building some specific channels. On the result of this function,
368
    /// call `with_named_channel` as many times as desired,
369
    /// and then call `with_pixels` to define the colors.
370
0
    pub fn build() -> SpecificChannelsBuilder<NoneMore, NoneMore> {
371
0
        SpecificChannelsBuilder { channels: NoneMore, px: Default::default() }
372
0
    }
373
}
374
375
impl<RecursiveChannels: CheckDuplicates, RecursivePixel> SpecificChannelsBuilder<RecursiveChannels, RecursivePixel>
376
{
377
    /// Add another channel to this image. Does not add the actual pixels,
378
    /// but instead only declares the presence of the channel.
379
    /// Panics if the name contains unsupported characters.
380
    /// Panics if a channel with the same name already exists.
381
    /// Use `Text::new_or_none()` to manually handle these cases.
382
    /// Use `with_channel_details` instead if you want to specify more options than just the name of the channel.
383
    /// The generic parameter can usually be inferred from the closure in `with_pixels`.
384
0
    pub fn with_channel<Sample: IntoSample>(self, name: impl Into<Text>)
385
0
                                            -> SpecificChannelsBuilder<Recursive<RecursiveChannels, ChannelDescription>, Recursive<RecursivePixel, Sample>>
386
    {
387
0
        self.with_channel_details::<Sample>(ChannelDescription::named(name, Sample::PREFERRED_SAMPLE_TYPE))
388
0
    }
389
390
    /// Add another channel to this image. Does not add the actual pixels,
391
    /// but instead only declares the presence of the channel.
392
    /// Use `with_channel` instead if you only want to specify the name of the channel.
393
    /// Panics if a channel with the same name already exists.
394
    /// The generic parameter can usually be inferred from the closure in `with_pixels`.
395
0
    pub fn with_channel_details<Sample: Into<Sample>>(self, channel: ChannelDescription)
396
0
        -> SpecificChannelsBuilder<Recursive<RecursiveChannels, ChannelDescription>, Recursive<RecursivePixel, Sample>>
397
    {
398
        // duplicate channel names are checked later, but also check now to make sure there are no problems with the `SpecificChannelsWriter`
399
0
        assert!(self.channels.already_contains(&channel.name).not(), "channel name `{}` is duplicate", channel.name);
400
401
0
        SpecificChannelsBuilder {
402
0
            channels: Recursive::new(self.channels, channel),
403
0
            px: PhantomData::default()
404
0
        }
405
0
    }
406
407
    /// Specify the actual pixel contents of the image.
408
    /// You can pass a closure that returns a color for each pixel (`Fn(Vec2<usize>) -> Pixel`),
409
    /// or you can pass your own image if it implements `GetPixel`.
410
    /// The pixel type must be a tuple with the correct number of entries, depending on the number of channels.
411
    /// The tuple entries can be either `f16`, `f32`, `u32` or `Sample`.
412
    /// Use `with_pixel_fn` instead of this function, to get extra type safety for your pixel closure.
413
0
    pub fn with_pixels<Pixels>(self, get_pixel: Pixels) -> SpecificChannels<Pixels, RecursiveChannels>
414
0
        where Pixels: GetPixel, <Pixels as GetPixel>::Pixel: IntoRecursive<Recursive=RecursivePixel>,
415
    {
416
0
        SpecificChannels {
417
0
            channels: self.channels,
418
0
            pixels: get_pixel
419
0
        }
420
0
    }
421
422
    /// Specify the contents of the image.
423
    /// The pixel type must be a tuple with the correct number of entries, depending on the number of channels.
424
    /// The tuple entries can be either `f16`, `f32`, `u32` or `Sample`.
425
    /// Use `with_pixels` instead of this function, if you want to pass an object that is not a closure.
426
    ///
427
    /// Usually, the compiler can infer the type of the pixel (for example, `f16,f32,f32`) from the closure.
428
    /// If that's not possible, you can specify the type of the channels
429
    /// when declaring the channel (for example, `with_named_channel::<f32>("R")`).
430
0
    pub fn with_pixel_fn<Pixel, Pixels>(self, get_pixel: Pixels) -> SpecificChannels<Pixels, RecursiveChannels>
431
0
        where Pixels: Sync + Fn(Vec2<usize>) -> Pixel, Pixel: IntoRecursive<Recursive=RecursivePixel>,
432
    {
433
0
        SpecificChannels {
434
0
            channels: self.channels,
435
0
            pixels: get_pixel
436
0
        }
437
0
    }
438
}
439
440
impl<SampleStorage> SpecificChannels<
441
    SampleStorage, (ChannelDescription, ChannelDescription, ChannelDescription, ChannelDescription)
442
>
443
{
444
445
    /// Create an image with red, green, blue, and alpha channels.
446
    /// You can pass a closure that returns a color for each pixel (`Fn(Vec2<usize>) -> (R,G,B,A)`),
447
    /// or you can pass your own image if it implements `GetPixel<Pixel=(R,G,B,A)>`.
448
    /// Each of `R`, `G`, `B` and `A` can be either `f16`, `f32`, `u32`, or `Sample`.
449
85
    pub fn rgba<R, G, B, A>(source_samples: SampleStorage) -> Self
450
85
        where R: IntoSample, G: IntoSample,
451
85
              B: IntoSample, A: IntoSample,
452
85
              SampleStorage: GetPixel<Pixel=(R, G, B, A)>
453
    {
454
85
        SpecificChannels {
455
85
            channels: (
456
85
                ChannelDescription::named("R", R::PREFERRED_SAMPLE_TYPE),
457
85
                ChannelDescription::named("G", G::PREFERRED_SAMPLE_TYPE),
458
85
                ChannelDescription::named("B", B::PREFERRED_SAMPLE_TYPE),
459
85
                ChannelDescription::named("A", A::PREFERRED_SAMPLE_TYPE),
460
85
            ),
461
85
            pixels: source_samples
462
85
        }
463
85
    }
Unexecuted instantiation: <exr::image::SpecificChannels<_, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>::rgba::<_, _, _, _>
Unexecuted instantiation: <exr::image::SpecificChannels<image::codecs::openexr::write_buffer<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>::{closure#1}, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>::rgba::<f32, f32, f32, f32>
<exr::image::SpecificChannels<image::codecs::openexr::write_buffer<std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>::{closure#1}, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>::rgba::<f32, f32, f32, f32>
Line
Count
Source
449
85
    pub fn rgba<R, G, B, A>(source_samples: SampleStorage) -> Self
450
85
        where R: IntoSample, G: IntoSample,
451
85
              B: IntoSample, A: IntoSample,
452
85
              SampleStorage: GetPixel<Pixel=(R, G, B, A)>
453
    {
454
85
        SpecificChannels {
455
85
            channels: (
456
85
                ChannelDescription::named("R", R::PREFERRED_SAMPLE_TYPE),
457
85
                ChannelDescription::named("G", G::PREFERRED_SAMPLE_TYPE),
458
85
                ChannelDescription::named("B", B::PREFERRED_SAMPLE_TYPE),
459
85
                ChannelDescription::named("A", A::PREFERRED_SAMPLE_TYPE),
460
85
            ),
461
85
            pixels: source_samples
462
85
        }
463
85
    }
464
}
465
466
impl<SampleStorage> SpecificChannels<
467
    SampleStorage, (ChannelDescription, ChannelDescription, ChannelDescription)
468
>
469
{
470
471
    /// Create an image with red, green, and blue channels.
472
    /// You can pass a closure that returns a color for each pixel (`Fn(Vec2<usize>) -> (R,G,B)`),
473
    /// or you can pass your own image if it implements `GetPixel<Pixel=(R,G,B)>`.
474
    /// Each of `R`, `G` and `B` can be either `f16`, `f32`, `u32`, or `Sample`.
475
0
    pub fn rgb<R, G, B>(source_samples: SampleStorage) -> Self
476
0
        where R: IntoSample, G: IntoSample, B: IntoSample,
477
0
              SampleStorage: GetPixel<Pixel=(R, G, B)>
478
    {
479
0
        SpecificChannels {
480
0
            channels: (
481
0
                ChannelDescription::named("R", R::PREFERRED_SAMPLE_TYPE),
482
0
                ChannelDescription::named("G", G::PREFERRED_SAMPLE_TYPE),
483
0
                ChannelDescription::named("B", B::PREFERRED_SAMPLE_TYPE),
484
0
            ),
485
0
            pixels: source_samples
486
0
        }
487
0
    }
Unexecuted instantiation: <exr::image::SpecificChannels<_, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>::rgb::<_, _, _>
Unexecuted instantiation: <exr::image::SpecificChannels<image::codecs::openexr::write_buffer<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>::{closure#0}, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>::rgb::<f32, f32, f32>
Unexecuted instantiation: <exr::image::SpecificChannels<image::codecs::openexr::write_buffer<std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>::{closure#0}, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>::rgb::<f32, f32, f32>
488
}
489
490
491
/// A list of samples representing a single pixel.
492
/// Does not heap allocate for images with 8 or fewer channels.
493
pub type FlatSamplesPixel = SmallVec<[Sample; 8]>;
494
495
// TODO also deep samples?
496
impl Layer<AnyChannels<FlatSamples>> {
497
498
    /// Use `samples_at` if you can borrow from this layer
499
0
    pub fn sample_vec_at(&self, position: Vec2<usize>) -> FlatSamplesPixel {
500
0
        self.samples_at(position).collect()
501
0
    }
502
503
    /// Lookup all channels of a single pixel in the image
504
0
    pub fn samples_at(&self, position: Vec2<usize>) -> FlatSampleIterator<'_> {
505
0
        FlatSampleIterator {
506
0
            layer: self,
507
0
            channel_index: 0,
508
0
            position
509
0
        }
510
0
    }
511
}
512
513
/// Iterate over all channels of a single pixel in the image
514
#[derive(Debug, Copy, Clone, PartialEq)]
515
pub struct FlatSampleIterator<'s> {
516
    layer: &'s Layer<AnyChannels<FlatSamples>>,
517
    channel_index: usize,
518
    position: Vec2<usize>,
519
}
520
521
impl Iterator for FlatSampleIterator<'_> {
522
    type Item = Sample;
523
524
0
    fn next(&mut self) -> Option<Self::Item> {
525
0
        if self.channel_index < self.layer.channel_data.list.len() {
526
0
            let channel = &self.layer.channel_data.list[self.channel_index];
527
0
            let sample = channel.sample_data.value_by_flat_index(self.position.flat_index_for_size(self.layer.size));
528
0
            self.channel_index += 1;
529
0
            Some(sample)
530
        }
531
0
        else { None }
532
0
    }
533
534
0
    fn nth(&mut self, pos: usize) -> Option<Self::Item> {
535
0
        self.channel_index += pos;
536
0
        self.next()
537
0
    }
538
539
0
    fn size_hint(&self) -> (usize, Option<usize>) {
540
0
        let remaining = self.layer.channel_data.list.len().saturating_sub(self.channel_index);
541
0
        (remaining, Some(remaining))
542
0
    }
543
}
544
545
impl ExactSizeIterator for FlatSampleIterator<'_> {}
546
547
impl<SampleData> AnyChannels<SampleData>{
548
549
    /// A new list of arbitrary channels. Sorts the list to make it alphabetically stable.
550
0
    pub fn sort(mut list: SmallVec<[AnyChannel<SampleData>; 4]>) -> Self {
551
0
        list.sort_unstable_by_key(|channel| channel.name.clone()); // TODO no clone?
552
0
        Self { list }
553
0
    }
554
}
555
556
// FIXME check content size of layer somewhere??? before writing?
557
impl<LevelSamples> Levels<LevelSamples> {
558
559
    /// Get a resolution level by index, sorted by size, decreasing.
560
0
    pub fn get_level(&self, level: Vec2<usize>) -> Result<&LevelSamples> {
561
0
        match self {
562
0
            Levels::Singular(block) => {
563
0
                debug_assert_eq!(level, Vec2(0,0), "singular image cannot write leveled blocks bug");
564
0
                Ok(block)
565
            },
566
567
0
            Levels::Mip { level_data, .. } => {
568
0
                debug_assert_eq!(level.x(), level.y(), "mip map levels must be equal on x and y bug");
569
0
                level_data.get(level.x()).ok_or(Error::invalid("block mip level index"))
570
            },
571
572
0
            Levels::Rip { level_data, .. } => {
573
0
                level_data.get_by_level(level).ok_or(Error::invalid("block rip level index"))
574
            }
575
        }
576
0
    }
577
578
    /// Get a resolution level by index, sorted by size, decreasing.
579
    // TODO storage order for RIP maps?
580
0
    pub fn get_level_mut(&mut self, level: Vec2<usize>) -> Result<&mut LevelSamples> {
581
0
        match self {
582
0
            Levels::Singular(ref mut block) => {
583
0
                debug_assert_eq!(level, Vec2(0,0), "singular image cannot write leveled blocks bug");
584
0
                Ok(block)
585
            },
586
587
0
            Levels::Mip { level_data, .. } => {
588
0
                debug_assert_eq!(level.x(), level.y(), "mip map levels must be equal on x and y bug");
589
0
                level_data.get_mut(level.x()).ok_or(Error::invalid("block mip level index"))
590
            },
591
592
0
            Levels::Rip { level_data, .. } => {
593
0
                level_data.get_by_level_mut(level).ok_or(Error::invalid("block rip level index"))
594
            }
595
        }
596
0
    }
597
598
    /// Get a slice of all resolution levels, sorted by size, decreasing.
599
0
    pub fn levels_as_slice(&self) -> &[LevelSamples] {
600
0
        match self {
601
0
            Levels::Singular(data) => std::slice::from_ref(data),
602
0
            Levels::Mip { level_data, .. } => level_data,
603
0
            Levels::Rip { level_data, .. } => &level_data.map_data,
604
        }
605
0
    }
606
607
    /// Get a mutable slice of all resolution levels, sorted by size, decreasing.
608
0
    pub fn levels_as_slice_mut(&mut self) -> &mut [LevelSamples] {
609
0
        match self {
610
0
            Levels::Singular(data) => std::slice::from_mut(data),
611
0
            Levels::Mip { level_data, .. } => level_data,
612
0
            Levels::Rip { level_data, .. } => &mut level_data.map_data,
613
        }
614
0
    }
615
616
    // TODO simplify working with levels in general! like level_size_by_index and such
617
618
    /*pub fn levels_with_size(&self, rounding: RoundingMode, max_resolution: Vec2<usize>) -> Vec<(Vec2<usize>, &S)> {
619
        match self {
620
            Levels::Singular(ref data) => vec![ (max_resolution, data) ],
621
            Levels::Mip(ref maps) => mip_map_levels(rounding, max_resolution).map(|(_index, size)| size).zip(maps).collect(),
622
            Levels::Rip(ref rip_maps) => rip_map_levels(rounding, max_resolution).map(|(_index, size)| size).zip(&rip_maps.map_data).collect(),
623
        }
624
    }*/
625
626
    /// Whether this stores multiple resolution levels.
627
0
    pub fn level_mode(&self) -> LevelMode {
628
0
        match self {
629
0
            Levels::Singular(_) => LevelMode::Singular,
630
0
            Levels::Mip { .. } => LevelMode::MipMap,
631
0
            Levels::Rip { .. } => LevelMode::RipMap,
632
        }
633
0
    }
634
}
635
636
impl<Samples> RipMaps<Samples> {
637
638
    /// Flatten the 2D level index to a one dimensional index.
639
0
    pub fn get_level_index(&self, level: Vec2<usize>) -> usize {
640
0
        level.flat_index_for_size(self.level_count)
641
0
    }
642
643
    /// Return a level by level index. Level `0` has the largest resolution.
644
0
    pub fn get_by_level(&self, level: Vec2<usize>) -> Option<&Samples> {
645
0
        self.map_data.get(self.get_level_index(level))
646
0
    }
647
648
    /// Return a mutable level reference by level index. Level `0` has the largest resolution.
649
0
    pub fn get_by_level_mut(&mut self, level: Vec2<usize>) -> Option<&mut Samples> {
650
0
        let index = self.get_level_index(level);
651
0
        self.map_data.get_mut(index)
652
0
    }
653
}
654
655
impl FlatSamples {
656
657
    /// The number of samples in the image. Should be the width times the height.
658
    /// Might vary when subsampling is used.
659
0
    pub fn len(&self) -> usize {
660
0
        match self {
661
0
            FlatSamples::F16(vec) => vec.len(),
662
0
            FlatSamples::F32(vec) => vec.len(),
663
0
            FlatSamples::U32(vec) => vec.len(),
664
        }
665
0
    }
666
667
    /// Views all samples in this storage as f32.
668
    /// Matches the underlying sample type again for every sample,
669
    /// match yourself if performance is critical! Does not allocate.
670
0
    pub fn values_as_f32<'s>(&'s self) -> impl 's + Iterator<Item = f32> {
671
0
        self.values().map(|sample| sample.to_f32())
672
0
    }
673
674
    /// All samples in this storage as iterator.
675
    /// Matches the underlying sample type again for every sample,
676
    /// match yourself if performance is critical! Does not allocate.
677
0
    pub fn values<'s>(&'s self) -> impl 's + Iterator<Item = Sample> {
678
0
        (0..self.len()).map(move |index| self.value_by_flat_index(index))
679
0
    }
680
681
    /// Lookup a single value, by flat index.
682
    /// The flat index can be obtained using `Vec2::flatten_for_width`
683
    /// which computes the index in a flattened array of pixel rows.
684
0
    pub fn value_by_flat_index(&self, index: usize) -> Sample {
685
0
        match self {
686
0
            FlatSamples::F16(vec) => Sample::F16(vec[index]),
687
0
            FlatSamples::F32(vec) => Sample::F32(vec[index]),
688
0
            FlatSamples::U32(vec) => Sample::U32(vec[index]),
689
        }
690
0
    }
691
}
692
693
694
impl<'s, ChannelData:'s> Layer<ChannelData> {
695
696
    /// Create a layer with the specified size, attributes, encoding and channels.
697
    /// The channels can be either `SpecificChannels` or `AnyChannels`.
698
85
    pub fn new(
699
85
        dimensions: impl Into<Vec2<usize>>,
700
85
        attributes: LayerAttributes,
701
85
        encoding: Encoding,
702
85
        channels: ChannelData
703
85
    ) -> Self
704
85
        where ChannelData: WritableChannels<'s>
705
    {
706
85
        Layer { channel_data: channels, attributes, size: dimensions.into(), encoding }
707
85
    }
Unexecuted instantiation: <exr::image::Layer<_>>::new::<_>
Unexecuted instantiation: <exr::image::Layer<exr::image::SpecificChannels<image::codecs::openexr::write_buffer<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>::{closure#0}, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>>::new::<(usize, usize)>
Unexecuted instantiation: <exr::image::Layer<exr::image::SpecificChannels<image::codecs::openexr::write_buffer<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>::{closure#1}, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>>::new::<(usize, usize)>
Unexecuted instantiation: <exr::image::Layer<exr::image::SpecificChannels<image::codecs::openexr::write_buffer<std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>::{closure#0}, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>>::new::<(usize, usize)>
<exr::image::Layer<exr::image::SpecificChannels<image::codecs::openexr::write_buffer<std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>::{closure#1}, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>>::new::<(usize, usize)>
Line
Count
Source
698
85
    pub fn new(
699
85
        dimensions: impl Into<Vec2<usize>>,
700
85
        attributes: LayerAttributes,
701
85
        encoding: Encoding,
702
85
        channels: ChannelData
703
85
    ) -> Self
704
85
        where ChannelData: WritableChannels<'s>
705
    {
706
85
        Layer { channel_data: channels, attributes, size: dimensions.into(), encoding }
707
85
    }
708
709
    // TODO test pls wtf
710
    /// Panics for images with Scanline encoding.
711
0
    pub fn levels_with_resolution<'l, L>(&self, levels: &'l Levels<L>) -> Box<dyn 'l + Iterator<Item=(&'l L, Vec2<usize>)>> {
712
0
        match levels {
713
0
            Levels::Singular(level) => Box::new(std::iter::once((level, self.size))),
714
715
0
            Levels::Mip { rounding_mode, level_data } => Box::new(level_data.iter().zip(
716
0
                mip_map_levels(*rounding_mode, self.size)
717
0
                    .map(|(_index, size)| size)
718
            )),
719
720
0
            Levels::Rip { rounding_mode, level_data } => Box::new(level_data.map_data.iter().zip(
721
0
                rip_map_levels(*rounding_mode, self.size)
722
0
                    .map(|(_index, size)| size)
723
            )),
724
        }
725
0
    }
726
}
727
728
impl Encoding {
729
730
    /// No compression. Massive space requirements.
731
    /// Fast, because it minimizes data shuffling and reallocation.
732
    pub const UNCOMPRESSED: Encoding = Encoding {
733
        compression: Compression::Uncompressed,
734
        blocks: Blocks::ScanLines, // longest lines, faster memcpy
735
        line_order: LineOrder::Increasing // presumably fastest?
736
    };
737
738
    /// Run-length encoding with tiles of 64x64 pixels. This is the recommended default encoding.
739
    /// Almost as fast as uncompressed data, but optimizes single-colored areas such as mattes and masks.
740
    pub const FAST_LOSSLESS: Encoding = Encoding {
741
        compression: Compression::RLE,
742
        blocks: Blocks::Tiles(Vec2(64, 64)), // optimize for RLE compression
743
        line_order: LineOrder::Unspecified
744
    };
745
746
    /// ZIP compression with blocks of 16 lines. Slow, but produces small files without visible artefacts.
747
    pub const SMALL_LOSSLESS: Encoding = Encoding {
748
        compression: Compression::ZIP16,
749
        blocks: Blocks::ScanLines, // largest possible, but also with high probability of parallel workers
750
        line_order: LineOrder::Increasing
751
    };
752
753
    /// PIZ compression with tiles of 256x256 pixels. Small images, not too slow.
754
    pub const SMALL_FAST_LOSSLESS: Encoding = Encoding {
755
        compression: Compression::PIZ,
756
        blocks: Blocks::Tiles(Vec2(256, 256)),
757
        line_order: LineOrder::Unspecified
758
    };
759
}
760
761
impl Default for Encoding {
762
85
    fn default() -> Self { Encoding::FAST_LOSSLESS }
763
}
764
765
impl<'s, LayerData: 's> Image<LayerData> where LayerData: WritableLayers<'s> {
766
    /// Create an image with one or multiple layers. The layer can be a `Layer`, or `Layers` small vector, or `Vec<Layer>` or `&[Layer]`.
767
85
    pub fn new(image_attributes: ImageAttributes, layer_data: LayerData) -> Self {
768
85
        Image { attributes: image_attributes, layer_data }
769
85
    }
Unexecuted instantiation: <exr::image::Image<_>>::new
Unexecuted instantiation: <exr::image::Image<exr::image::Layer<exr::image::SpecificChannels<image::codecs::openexr::write_buffer<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>::{closure#0}, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>>>::new
Unexecuted instantiation: <exr::image::Image<exr::image::Layer<exr::image::SpecificChannels<image::codecs::openexr::write_buffer<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>::{closure#1}, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>>>::new
Unexecuted instantiation: <exr::image::Image<exr::image::Layer<exr::image::SpecificChannels<image::codecs::openexr::write_buffer<std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>::{closure#0}, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>>>::new
<exr::image::Image<exr::image::Layer<exr::image::SpecificChannels<image::codecs::openexr::write_buffer<std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>::{closure#1}, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>>>::new
Line
Count
Source
767
85
    pub fn new(image_attributes: ImageAttributes, layer_data: LayerData) -> Self {
768
85
        Image { attributes: image_attributes, layer_data }
769
85
    }
770
}
771
772
// explorable constructor alias
773
impl<'s, Channels: 's> Image<Layers<Channels>> where Channels: WritableChannels<'s> {
774
    /// Create an image with multiple layers. The layer can be a `Vec<Layer>` or `Layers` (a small vector).
775
0
    pub fn from_layers(image_attributes: ImageAttributes, layer_data: impl Into<Layers<Channels>>) -> Self {
776
0
        Self::new(image_attributes, layer_data.into())
777
0
    }
778
}
779
780
781
impl<'s, ChannelData:'s> Image<Layer<ChannelData>> where ChannelData: WritableChannels<'s> {
782
783
    /// Uses the display position and size to the channel position and size of the layer.
784
85
    pub fn from_layer(layer: Layer<ChannelData>) -> Self {
785
85
        let bounds = IntegerBounds::new(layer.attributes.layer_position, layer.size);
786
85
        Self::new(ImageAttributes::new(bounds), layer)
787
85
    }
Unexecuted instantiation: <exr::image::Image<exr::image::Layer<_>>>::from_layer
Unexecuted instantiation: <exr::image::Image<exr::image::Layer<exr::image::SpecificChannels<image::codecs::openexr::write_buffer<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>::{closure#0}, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>>>::from_layer
Unexecuted instantiation: <exr::image::Image<exr::image::Layer<exr::image::SpecificChannels<image::codecs::openexr::write_buffer<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>::{closure#1}, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>>>::from_layer
Unexecuted instantiation: <exr::image::Image<exr::image::Layer<exr::image::SpecificChannels<image::codecs::openexr::write_buffer<std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>::{closure#0}, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>>>::from_layer
<exr::image::Image<exr::image::Layer<exr::image::SpecificChannels<image::codecs::openexr::write_buffer<std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>::{closure#1}, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>>>::from_layer
Line
Count
Source
784
85
    pub fn from_layer(layer: Layer<ChannelData>) -> Self {
785
85
        let bounds = IntegerBounds::new(layer.attributes.layer_position, layer.size);
786
85
        Self::new(ImageAttributes::new(bounds), layer)
787
85
    }
788
789
    /// Uses empty attributes.
790
85
    pub fn from_encoded_channels(size: impl Into<Vec2<usize>>, encoding: Encoding, channels: ChannelData) -> Self {
791
        // layer name is not required for single-layer images
792
85
        Self::from_layer(Layer::new(size, LayerAttributes::default(), encoding, channels))
793
85
    }
Unexecuted instantiation: <exr::image::Image<exr::image::Layer<_>>>::from_encoded_channels::<_>
Unexecuted instantiation: <exr::image::Image<exr::image::Layer<exr::image::SpecificChannels<image::codecs::openexr::write_buffer<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>::{closure#0}, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>>>::from_encoded_channels::<(usize, usize)>
Unexecuted instantiation: <exr::image::Image<exr::image::Layer<exr::image::SpecificChannels<image::codecs::openexr::write_buffer<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>::{closure#1}, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>>>::from_encoded_channels::<(usize, usize)>
Unexecuted instantiation: <exr::image::Image<exr::image::Layer<exr::image::SpecificChannels<image::codecs::openexr::write_buffer<std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>::{closure#0}, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>>>::from_encoded_channels::<(usize, usize)>
<exr::image::Image<exr::image::Layer<exr::image::SpecificChannels<image::codecs::openexr::write_buffer<std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>::{closure#1}, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>>>::from_encoded_channels::<(usize, usize)>
Line
Count
Source
790
85
    pub fn from_encoded_channels(size: impl Into<Vec2<usize>>, encoding: Encoding, channels: ChannelData) -> Self {
791
        // layer name is not required for single-layer images
792
85
        Self::from_layer(Layer::new(size, LayerAttributes::default(), encoding, channels))
793
85
    }
794
795
    /// Uses empty attributes and fast compression.
796
85
    pub fn from_channels(size: impl Into<Vec2<usize>>, channels: ChannelData) -> Self {
797
85
        Self::from_encoded_channels(size, Encoding::default(), channels)
798
85
    }
Unexecuted instantiation: <exr::image::Image<exr::image::Layer<_>>>::from_channels::<_>
Unexecuted instantiation: <exr::image::Image<exr::image::Layer<exr::image::SpecificChannels<image::codecs::openexr::write_buffer<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>::{closure#0}, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>>>::from_channels::<(usize, usize)>
Unexecuted instantiation: <exr::image::Image<exr::image::Layer<exr::image::SpecificChannels<image::codecs::openexr::write_buffer<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>::{closure#1}, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>>>::from_channels::<(usize, usize)>
Unexecuted instantiation: <exr::image::Image<exr::image::Layer<exr::image::SpecificChannels<image::codecs::openexr::write_buffer<std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>::{closure#0}, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>>>::from_channels::<(usize, usize)>
<exr::image::Image<exr::image::Layer<exr::image::SpecificChannels<image::codecs::openexr::write_buffer<std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>::{closure#1}, (exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription, exr::meta::attribute::ChannelDescription)>>>>::from_channels::<(usize, usize)>
Line
Count
Source
796
85
    pub fn from_channels(size: impl Into<Vec2<usize>>, channels: ChannelData) -> Self {
797
85
        Self::from_encoded_channels(size, Encoding::default(), channels)
798
85
    }
799
}
800
801
802
impl Image<NoneMore> {
803
804
    /// Create an empty image, to be filled with layers later on. Add at least one layer to obtain a valid image.
805
    /// Call `with_layer(another_layer)` for each layer you want to add to this image.
806
0
    pub fn empty(attributes: ImageAttributes) -> Self { Self { attributes, layer_data: NoneMore } }
807
}
808
809
impl<'s, InnerLayers: 's> Image<InnerLayers> where
810
    InnerLayers: WritableLayers<'s>,
811
{
812
    /// Add another layer to this image. The layer type does
813
    /// not have to equal the existing layers in this image.
814
0
    pub fn with_layer<NewChannels>(self, layer: Layer<NewChannels>)
815
0
        -> Image<Recursive<InnerLayers, Layer<NewChannels>>>
816
0
        where NewChannels: 's + WritableChannels<'s>
817
    {
818
0
        Image {
819
0
            attributes: self.attributes,
820
0
            layer_data: Recursive::new(self.layer_data, layer)
821
0
        }
822
0
    }
823
}
824
825
826
impl<'s, SampleData: 's> AnyChannel<SampleData> {
827
828
    /// Create a new channel without subsampling.
829
    ///
830
    /// Automatically flags this channel for specialized compression
831
    /// if the name is "R", "G", "B", "Y", or "L",
832
    /// as they typically encode values that are perceived non-linearly.
833
    /// Construct the value yourself using `AnyChannel { .. }`, if you want to control this flag.
834
0
    pub fn new(name: impl Into<Text>, sample_data: SampleData) -> Self where SampleData: WritableSamples<'s> {
835
0
        let name: Text = name.into();
836
837
0
        AnyChannel {
838
0
            quantize_linearly: ChannelDescription::guess_quantization_linearity(&name),
839
0
            name, sample_data,
840
0
            sampling: Vec2(1, 1),
841
0
        }
842
0
    }
843
844
    /*/// This is the same as `AnyChannel::new()`, but additionally ensures that the closure type is correct.
845
    pub fn from_closure<V>(name: Text, sample_data: S) -> Self
846
        where S: Sync + Fn(Vec2<usize>) -> V, V: InferSampleType + Data
847
    {
848
        Self::new(name, sample_data)
849
    }*/
850
}
851
852
impl std::fmt::Debug for FlatSamples {
853
0
    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
854
0
        if self.len() <= 6 {
855
0
            match self {
856
0
                FlatSamples::F16(vec) => vec.fmt(formatter),
857
0
                FlatSamples::F32(vec) => vec.fmt(formatter),
858
0
                FlatSamples::U32(vec) => vec.fmt(formatter),
859
            }
860
        }
861
        else {
862
0
            match self {
863
0
                FlatSamples::F16(vec) => write!(formatter, "[f16; {}]", vec.len()),
864
0
                FlatSamples::F32(vec) => write!(formatter, "[f32; {}]", vec.len()),
865
0
                FlatSamples::U32(vec) => write!(formatter, "[u32; {}]", vec.len()),
866
            }
867
        }
868
0
    }
869
}
870
871
872
873
/// Compare the result of a round trip test with the original method.
874
/// Supports lossy compression methods.
875
// #[cfg(test)] TODO do not ship this code
876
pub mod validate_results {
877
    use crate::prelude::*;
878
    use smallvec::Array;
879
    use crate::prelude::recursive::*;
880
    use crate::image::write::samples::WritableSamples;
881
    use std::ops::Not;
882
    use crate::block::samples::IntoNativeSample;
883
884
    /// Compare two objects, but with a few special quirks.
885
    /// Intended mainly for unit testing.
886
    pub trait ValidateResult {
887
888
        /// Compare self with the other. Panics if not equal.
889
        ///
890
        /// Exceptional behaviour:
891
        /// This does not work the other way around! This method is not symmetrical!
892
        /// Returns whether the result is correct for this image.
893
        /// For lossy compression methods, uses approximate equality.
894
        /// Intended for unit testing.
895
        ///
896
        /// Warning: If you use `SpecificChannels`, the comparison might be inaccurate
897
        /// for images with mixed compression methods. This is to be used with `AnyChannels` mainly.
898
0
        fn assert_equals_result(&self, result: &Self) {
899
0
            self.validate_result(result, ValidationOptions::default(), || String::new()).unwrap();
900
0
        }
901
902
        /// Compare self with the other.
903
        /// Exceptional behaviour:
904
        /// - Any two NaN values are considered equal, regardless of bit representation.
905
        /// - If a `lossy` is specified, any two values that differ only by a small amount will be considered equal.
906
        /// - If `nan_to_zero` is true, and __self is NaN/Infinite and the other value is zero, they are considered equal__
907
        ///   (because some compression methods replace nan with zero)
908
        ///
909
        /// This does not work the other way around! This method is not symmetrical!
910
        fn validate_result(
911
            &self, lossy_result: &Self,
912
            options: ValidationOptions,
913
            // this is a lazy string, because constructing a string is only necessary in the case of an error,
914
            // but eats up memory and allocation time every time. this was measured.
915
            context: impl Fn() -> String
916
        ) -> ValidationResult;
917
    }
918
919
    /// Whether to do accurate or approximate comparison.
920
    #[derive(Default, Debug, Eq, PartialEq, Hash, Copy, Clone)]
921
    pub struct ValidationOptions {
922
        allow_lossy: bool,
923
        nan_converted_to_zero: bool,
924
    }
925
926
    /// If invalid, contains the error message.
927
    pub type ValidationResult = std::result::Result<(), String>;
928
929
930
    impl<C> ValidateResult for Image<C> where C: ValidateResult {
931
0
        fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
932
0
            if self.attributes != other.attributes { Err(location() + "| image > attributes") }
933
0
            else { self.layer_data.validate_result(&other.layer_data, options, || location() + "| image > layer data") }
934
0
        }
935
    }
936
937
    impl<S> ValidateResult for Layer<AnyChannels<S>>
938
        where AnyChannel<S>: ValidateResult, S: for<'a> WritableSamples<'a>
939
    {
940
0
        fn validate_result(&self, other: &Self, _overridden: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
941
0
            let location = || format!("{} (layer `{:?}`)", location(), self.attributes.layer_name);
942
0
            if self.attributes != other.attributes { Err(location() + " > attributes") }
943
0
            else if self.encoding != other.encoding { Err(location() + " > encoding") }
944
0
            else if self.size != other.size { Err(location() + " > size") }
945
0
            else if self.channel_data.list.len() != other.channel_data.list.len() { Err(location() + " > channel count") }
946
            else {
947
0
                for (own_chan, other_chan) in self.channel_data.list.iter().zip(other.channel_data.list.iter()) {
948
0
                    own_chan.validate_result(
949
0
                        other_chan,
950
951
0
                        ValidationOptions {
952
0
                            // no tolerance for lossless channels
953
0
                            allow_lossy: other.encoding.compression
954
0
                                .is_lossless_for(other_chan.sample_data.sample_type()).not(),
955
0
956
0
                            // consider nan and zero equal if the compression method does not support nan
957
0
                            nan_converted_to_zero: other.encoding.compression.supports_nan().not()
958
0
                        },
959
960
0
                        || format!("{} > channel `{}`", location(), own_chan.name)
961
0
                    )?;
962
                }
963
0
                Ok(())
964
            }
965
0
        }
966
    }
967
968
    impl<Px, Desc> ValidateResult for Layer<SpecificChannels<Px, Desc>>
969
        where SpecificChannels<Px, Desc>: ValidateResult
970
    {
971
        /// This does an approximate comparison for all channels,
972
        /// even if some channels can be compressed without loss.
973
0
        fn validate_result(&self, other: &Self, _overridden: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
974
0
            let location = || format!("{} (layer `{:?}`)", location(), self.attributes.layer_name);
975
976
            // TODO dedup with above
977
0
            if self.attributes != other.attributes { Err(location() + " > attributes") }
978
0
            else if self.encoding != other.encoding { Err(location() + " > encoding") }
979
0
            else if self.size != other.size { Err(location() + " > size") }
980
            else {
981
0
                let options = ValidationOptions {
982
0
                    // no tolerance for lossless channels
983
0
                    // pxr only looses data for f32 values, B44 only for f16, not other any other types
984
0
                    allow_lossy: other.encoding.compression.may_loose_data(),// TODO check specific channels sample types
985
0
986
0
                    // consider nan and zero equal if the compression method does not support nan
987
0
                    nan_converted_to_zero: other.encoding.compression.supports_nan().not()
988
0
                };
989
990
0
                self.channel_data.validate_result(&other.channel_data, options, || location() + " > channel_data")?;
991
0
                Ok(())
992
            }
993
0
        }
994
    }
995
996
    impl<S> ValidateResult for AnyChannels<S> where S: ValidateResult {
997
0
        fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
998
0
            self.list.validate_result(&other.list, options, location)
999
0
        }
1000
    }
1001
1002
    impl<S> ValidateResult for AnyChannel<S> where S: ValidateResult {
1003
0
        fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1004
0
            if self.name != other.name { Err(location() + " > name") }
1005
0
            else if self.quantize_linearly != other.quantize_linearly { Err(location() + " > quantize_linearly") }
1006
0
            else if self.sampling != other.sampling { Err(location() + " > sampling") }
1007
            else {
1008
0
                self.sample_data.validate_result(&other.sample_data, options, || location() + " > sample_data")
1009
            }
1010
0
        }
1011
    }
1012
1013
    impl<Pxs, Chans> ValidateResult for SpecificChannels<Pxs, Chans> where Pxs: ValidateResult, Chans: Eq {
1014
0
        fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1015
0
            if self.channels != other.channels { Err(location() + " > specific channels") }
1016
0
            else { self.pixels.validate_result(&other.pixels, options, || location() + " > specific pixels") }
1017
0
        }
1018
    }
1019
1020
    impl<S> ValidateResult for Levels<S> where S: ValidateResult {
1021
0
        fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1022
0
            self.levels_as_slice().validate_result(&other.levels_as_slice(), options, || location() + " > levels")
1023
0
        }
1024
    }
1025
1026
    impl ValidateResult for FlatSamples {
1027
0
        fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1028
            use FlatSamples::*;
1029
0
            match (self, other) {
1030
0
                (F16(values), F16(other_values)) => values.as_slice().validate_result(&other_values.as_slice(), options, ||location() + " > f16 samples"),
1031
0
                (F32(values), F32(other_values)) => values.as_slice().validate_result(&other_values.as_slice(), options, ||location() + " > f32 samples"),
1032
0
                (U32(values), U32(other_values)) => values.as_slice().validate_result(&other_values.as_slice(), options, ||location() + " > u32 samples"),
1033
0
                (own, other) => Err(format!("{}: samples type mismatch. expected {:?}, found {:?}", location(), own.sample_type(), other.sample_type()))
1034
            }
1035
0
        }
1036
    }
1037
1038
    impl<T> ValidateResult for &[T] where T: ValidateResult {
1039
0
        fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1040
0
            if self.len() != other.len() { Err(location() + " count") }
1041
            else {
1042
0
                for (index, (slf, other)) in self.iter().zip(other.iter()).enumerate() {
1043
0
                    slf.validate_result(other, options, ||format!("{} element [{}] of {}", location(), index, self.len()))?;
1044
                }
1045
0
                Ok(())
1046
            }
1047
0
        }
1048
    }
1049
1050
    impl<A: Array> ValidateResult for SmallVec<A> where A::Item: ValidateResult {
1051
0
        fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1052
0
            self.as_slice().validate_result(&other.as_slice(), options, location)
1053
0
        }
1054
    }
1055
1056
    impl<A> ValidateResult for Vec<A> where A: ValidateResult {
1057
0
        fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1058
0
            self.as_slice().validate_result(&other.as_slice(), options, location)
1059
0
        }
1060
    }
1061
1062
    impl<A,B,C,D> ValidateResult for (A, B, C, D) where A: Clone+ ValidateResult, B: Clone+ ValidateResult, C: Clone+ ValidateResult, D: Clone+ ValidateResult {
1063
0
        fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1064
0
            self.clone().into_recursive().validate_result(&other.clone().into_recursive(), options, location)
1065
0
        }
1066
    }
1067
1068
    impl<A,B,C> ValidateResult for (A, B, C) where A: Clone+ ValidateResult, B: Clone+ ValidateResult, C: Clone+ ValidateResult {
1069
0
        fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1070
0
            self.clone().into_recursive().validate_result(&other.clone().into_recursive(), options, location)
1071
0
        }
1072
    }
1073
1074
    // // (low priority because it is only used in the tests)
1075
    /*TODO
1076
    impl<Tuple> SimilarToLossy for Tuple where
1077
        Tuple: Clone + IntoRecursive,
1078
        <Tuple as IntoRecursive>::Recursive: SimilarToLossy,
1079
    {
1080
        fn similar_to_lossy(&self, other: &Self, max_difference: f32) -> bool {
1081
            self.clone().into_recursive().similar_to_lossy(&other.clone().into_recursive(), max_difference)
1082
        } // TODO no clone?
1083
    }*/
1084
1085
1086
    // implement for recursive types
1087
    impl ValidateResult for NoneMore {
1088
0
        fn validate_result(&self, _: &Self, _: ValidationOptions, _: impl Fn()->String) -> ValidationResult { Ok(()) }
1089
    }
1090
1091
    impl<Inner, T> ValidateResult for Recursive<Inner, T> where Inner: ValidateResult, T: ValidateResult {
1092
0
        fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1093
0
            self.value.validate_result(&other.value, options, &location).and_then(|()|
1094
0
                self.inner.validate_result(&other.inner, options, &location)
1095
            )
1096
0
        }
1097
    }
1098
1099
    impl<S> ValidateResult for Option<S> where S: ValidateResult {
1100
0
        fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1101
0
            match (self, other) {
1102
0
                (None, None) => Ok(()),
1103
0
                (Some(value), Some(other)) => value.validate_result(other, options, location),
1104
0
                _ => Err(location() + ": option mismatch")
1105
            }
1106
0
        }
1107
    }
1108
1109
    impl ValidateResult for f32 {
1110
0
        fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1111
0
            if self == other || (self.is_nan() && other.is_nan()) || (options.nan_converted_to_zero && !self.is_normal() && *other == 0.0) {
1112
0
                return Ok(());
1113
0
            }
1114
1115
0
            if options.allow_lossy {
1116
0
                let epsilon = 0.06;
1117
0
                let max_difference = 0.1;
1118
1119
0
                let adaptive_threshold = epsilon * (self.abs() + other.abs());
1120
0
                let tolerance = adaptive_threshold.max(max_difference);
1121
0
                let difference = (self - other).abs();
1122
1123
0
                return if difference <= tolerance { Ok(()) }
1124
0
                else { Err(format!("{}: expected ~{}, found {} (adaptive tolerance {})", location(), self, other, tolerance)) };
1125
0
            }
1126
1127
0
            Err(format!("{}: expected exactly {}, found {}", location(), self, other))
1128
0
        }
1129
    }
1130
1131
    impl ValidateResult for f16 {
1132
0
        fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1133
0
            if self.to_bits() == other.to_bits() { Ok(()) } else {
1134
0
                self.to_f32().validate_result(&other.to_f32(), options, location)
1135
            }
1136
0
        }
1137
    }
1138
1139
    impl ValidateResult for u32 {
1140
0
        fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1141
0
            if self == other { Ok(()) } else { // todo to float conversion resulting in nan/infinity?
1142
0
                self.to_f32().validate_result(&other.to_f32(), options, location)
1143
            }
1144
0
        }
1145
    }
1146
1147
    impl ValidateResult for Sample {
1148
0
        fn validate_result(&self, other: &Self, options: ValidationOptions, location: impl Fn()->String) -> ValidationResult {
1149
            use Sample::*;
1150
0
            match (self, other) {
1151
0
                (F16(a), F16(b)) => a.validate_result(b, options, ||location() + " (f16)"),
1152
0
                (F32(a), F32(b)) => a.validate_result(b, options, ||location() + " (f32)"),
1153
0
                (U32(a), U32(b)) => a.validate_result(b, options, ||location() + " (u32)"),
1154
0
                (_,_) => Err(location() + ": sample type mismatch")
1155
            }
1156
0
        }
1157
    }
1158
1159
1160
    #[cfg(test)]
1161
    mod test_value_result {
1162
        use std::f32::consts::*;
1163
        use std::io::Cursor;
1164
        use crate::image::pixel_vec::PixelVec;
1165
        use crate::image::validate_results::{ValidateResult, ValidationOptions};
1166
        use crate::meta::attribute::LineOrder::Increasing;
1167
        use crate::image::{FlatSamples};
1168
1169
        fn expect_valid<T>(original: &T, result: &T, allow_lossy: bool, nan_converted_to_zero: bool) where T: ValidateResult {
1170
            original.validate_result(
1171
                result,
1172
                ValidationOptions { allow_lossy, nan_converted_to_zero },
1173
                || String::new()
1174
            ).unwrap();
1175
        }
1176
1177
        fn expect_invalid<T>(original: &T, result: &T, allow_lossy: bool, nan_converted_to_zero: bool) where T: ValidateResult {
1178
            assert!(original.validate_result(
1179
                result,
1180
                ValidationOptions { allow_lossy, nan_converted_to_zero },
1181
                || String::new()
1182
            ).is_err());
1183
        }
1184
1185
        #[test]
1186
        fn test_f32(){
1187
            let original:&[f32] = &[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, -20.4, f32::NAN];
1188
            let lossy:&[f32] = &[0.0, 0.2, 0.2, 0.3, 0.4, 0.5, -20.5, f32::NAN];
1189
1190
            expect_valid(&original, &original, true, true);
1191
            expect_valid(&original, &original, true, false);
1192
            expect_valid(&original, &original, false, true);
1193
            expect_valid(&original, &original, false, false);
1194
1195
            expect_invalid(&original, &lossy, false, false);
1196
            expect_valid(&original, &lossy, true, false);
1197
1198
            expect_invalid(&original, &&original[..original.len()-2], true, true);
1199
1200
            // test relative comparison with some large values
1201
            expect_valid(&1_000_f32, &1_001_f32, true, false);
1202
            expect_invalid(&1_000_f32, &1_200_f32, true, false);
1203
1204
            expect_valid(&10_000_f32, &10_100_f32, true, false);
1205
            expect_invalid(&10_000_f32, &12_000_f32, true, false);
1206
1207
            expect_valid(&33_120_f32, &30_120_f32, true, false);
1208
            expect_invalid(&33_120_f32, &20_120_f32, true, false);
1209
        }
1210
1211
        #[test]
1212
        fn test_nan(){
1213
            let original:&[f32] = &[ 0.0, f32::NAN, f32::NAN ];
1214
            let lossy:&[f32] = &[ 0.0, f32::NAN, 0.0 ];
1215
1216
            expect_valid(&original, &lossy, true, true);
1217
            expect_invalid(&lossy, &original, true, true);
1218
1219
            expect_valid(&lossy, &lossy, true, true);
1220
            expect_valid(&lossy, &lossy, false, true);
1221
        }
1222
1223
        #[test]
1224
        fn test_error(){
1225
1226
            fn print_error<T: ValidateResult>(original: &T, lossy: &T, allow_lossy: bool){
1227
                let message = original
1228
                    .validate_result(
1229
                        &lossy,
1230
                        ValidationOptions { allow_lossy, .. Default::default() },
1231
                        || String::new() // type_name::<T>().to_string()
1232
                    )
1233
                    .unwrap_err();
1234
1235
                println!("message: {}", message);
1236
            }
1237
1238
            let original:&[f32] = &[ 0.0, f32::NAN, f32::NAN ];
1239
            let lossy:&[f32] = &[ 0.0, f32::NAN, 0.0 ];
1240
            print_error(&original, &lossy, false);
1241
1242
            print_error(&2.0, &1.0, true);
1243
            print_error(&2.0, &1.0, false);
1244
1245
            print_error(&FlatSamples::F32(vec![0.1,0.1]), &FlatSamples::F32(vec![0.1,0.2]), false);
1246
            print_error(&FlatSamples::U32(vec![0,0]), &FlatSamples::F32(vec![0.1,0.2]), false);
1247
1248
            {
1249
                let image = crate::prelude::read_all_data_from_file("tests/images/valid/openexr/MultiResolution/Kapaa.exr").unwrap();
1250
1251
                let mut mutated = image.clone();
1252
                let samples = mutated.layer_data.first_mut().unwrap()
1253
                    .channel_data.list.first_mut().unwrap().sample_data.levels_as_slice_mut().first_mut().unwrap();
1254
1255
                match samples {
1256
                    FlatSamples::F16(vals) => vals[100] = vals[1],
1257
                    FlatSamples::F32(vals) => vals[100] = vals[1],
1258
                    FlatSamples::U32(vals) => vals[100] = vals[1],
1259
                }
1260
1261
                print_error(&image, &mutated, false);
1262
            }
1263
1264
            // TODO check out more nested behaviour!
1265
        }
1266
1267
        #[test]
1268
        fn test_uncompressed(){
1269
            use crate::prelude::*;
1270
1271
            let original_pixels: [(f32,f32,f32); 4] = [
1272
                (0.0, -1.1, PI),
1273
                (0.0, -1.1, TAU),
1274
                (0.0, -1.1, f32::EPSILON),
1275
                (f32::NAN, 10000.1, -1024.009),
1276
            ];
1277
1278
            let mut file_bytes = Vec::new();
1279
            let original_image = Image::from_encoded_channels(
1280
                (2,2),
1281
                Encoding {
1282
                    compression: Compression::Uncompressed,
1283
                    line_order: Increasing, // FIXME unspecified may be optimized to increasing, which destroys test eq
1284
                    .. Encoding::default()
1285
                },
1286
                SpecificChannels::rgb(PixelVec::new(Vec2(2,2), original_pixels.to_vec()))
1287
            );
1288
1289
            original_image.write().to_buffered(Cursor::new(&mut file_bytes)).unwrap();
1290
1291
            let lossy_image = read().no_deep_data().largest_resolution_level()
1292
                .rgb_channels(PixelVec::<(f32,f32,f32)>::constructor, PixelVec::set_pixel)
1293
                .first_valid_layer().all_attributes().from_buffered(Cursor::new(&file_bytes)).unwrap();
1294
1295
            original_image.assert_equals_result(&original_image);
1296
            lossy_image.assert_equals_result(&lossy_image);
1297
            original_image.assert_equals_result(&lossy_image);
1298
            lossy_image.assert_equals_result(&original_image);
1299
        }
1300
1301
        #[test]
1302
        fn test_compiles(){
1303
            use crate::prelude::*;
1304
1305
            fn accepts_validatable_value(_: &impl ValidateResult){}
1306
1307
            let object: Levels<FlatSamples> = Levels::Singular(FlatSamples::F32(Vec::default()));
1308
            accepts_validatable_value(&object);
1309
1310
            let object: AnyChannels<Levels<FlatSamples>> = AnyChannels::sort(SmallVec::default());
1311
            accepts_validatable_value(&object);
1312
1313
            let layer: Layer<AnyChannels<Levels<FlatSamples>>> = Layer::new((0,0), Default::default(), Default::default(), object);
1314
            accepts_validatable_value(&layer);
1315
1316
            let layers: Layers<AnyChannels<Levels<FlatSamples>>> = Default::default();
1317
            accepts_validatable_value(&layers);
1318
1319
            let object: Image<Layer<AnyChannels<Levels<FlatSamples>>>> = Image::from_layer(layer);
1320
            object.assert_equals_result(&object);
1321
        }
1322
    }
1323
1324
1325
    #[test]
1326
    fn test_nan_compression_attribute(){
1327
        use crate::prelude::*;
1328
        use crate::prelude::Compression::*;
1329
        use std::io::Cursor;
1330
        use crate::image::pixel_vec::PixelVec;
1331
        use crate::prelude::LineOrder::Increasing;
1332
1333
        let all_compression_methods = [
1334
            Uncompressed, RLE, ZIP1, ZIP16, PXR24, PIZ, B44, B44A,
1335
        ];
1336
1337
        let original_pixels: [(f32,f32,f16); 4] = [
1338
            (f32::NAN, f32::from_bits(0x7fc01234), f16::from_bits(0x7E01)),
1339
            (f32::NAN, f32::from_bits(0xffcabcde), f16::from_bits(0x7FFF)),
1340
            (f32::NAN, f32::from_bits(0x7f800001), f16::from_bits(0xFE01)),
1341
            (f32::NAN, f32::NAN, f16::NAN),
1342
        ];
1343
1344
        assert!(
1345
            original_pixels.iter()
1346
                .all(|&(a,b,c)| a.is_nan() && b.is_nan() && c.is_nan()),
1347
            "test case has a bug"
1348
        );
1349
1350
        for compression in all_compression_methods {
1351
            let mut file_bytes = Vec::new();
1352
1353
            let original_image = Image::from_encoded_channels(
1354
                (2, 2),
1355
                Encoding {
1356
                    compression,
1357
                    line_order: Increasing,
1358
                    ..Encoding::default()
1359
                },
1360
                SpecificChannels::rgb(PixelVec::new((2, 2), original_pixels.to_vec()))
1361
            );
1362
1363
            let result = original_image.write().to_buffered(Cursor::new(&mut file_bytes));
1364
            if let Err(Error::NotSupported(_)) = result { continue; }
1365
1366
            let reconstructed_image =
1367
                read().no_deep_data().largest_resolution_level()
1368
                    .rgb_channels(PixelVec::<(f32, f32, f16)>::constructor, PixelVec::set_pixel)
1369
                    .first_valid_layer().all_attributes().from_buffered(Cursor::new(&file_bytes)).unwrap();
1370
1371
            assert_eq!(
1372
                original_image.layer_data.channel_data.pixels.pixels.len(),
1373
                reconstructed_image.layer_data.channel_data.pixels.pixels.len()
1374
            );
1375
1376
            let was_nanness_preserved = reconstructed_image.layer_data.channel_data.pixels.pixels
1377
                .iter().all(|(r,g,b)| r.is_nan() && g.is_nan() && b.is_nan());
1378
1379
            assert_eq!(
1380
                was_nanness_preserved, compression.supports_nan(),
1381
                "{} nanness claims do not match real output", compression
1382
            );
1383
1384
            let was_nan_pattern_preserved = reconstructed_image.layer_data.channel_data.pixels.pixels
1385
                .iter().zip(original_pixels.iter())
1386
                .all(|((r2, g2, b2), (r1, g1, b1))|
1387
                    r2.to_bits() == r1.to_bits() &&
1388
                    g2.to_bits() == g1.to_bits() &&
1389
                    b2.to_bits() == b1.to_bits()
1390
                );
1391
1392
            assert_eq!(
1393
                was_nan_pattern_preserved, compression.preserves_nan_bits(),
1394
                "{} nan bit claims do not match real output", compression
1395
            );
1396
        }
1397
    }
1398
}
1399
1400