1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207

//! Read an exr image.
//!
//! For great flexibility and customization, use the `read()` function.
//! The return value of the `read()` function must be further customized before reading a file.

//!
//! For very simple applications, you can alternatively use one of these functions:
//!
//! 1. `read_first_rgba_layer_from_file(path, your_constructor, your_pixel_setter)`:
//!     You specify how to store the pixels.
//!     The first layer containing rgba channels is then loaded from the file.
//!     Fails if no rgba layer can be found.
//!
//! 1. `read_all_rgba_layers_from_file(path, your_constructor, your_pixel_setter)`:
//!     You specify how to store the pixels.
//!     All layers containing rgba channels are then loaded from the file.
//!     Fails if any layer in the image does not contain rgba channels.
//!
//! 1. `read_first_flat_layer_from_file(path)`:
//!     The first layer containing non-deep data with arbitrary channels is loaded from the file.
//!     Fails if no non-deep layer can be found.
//!
//! 1. `read_all_flat_layers_from_file(path)`:
//!     All layers containing non-deep data with arbitrary channels are loaded from the file.
//!     Fails if any layer in the image contains deep data.
//!
//! 1. `read_all_data_from_file(path)`:
//!     All layers with arbitrary channels and all resolution levels are extracted from the file.
//!
//!     Note: Currently does not support deep data, and currently fails
//!     if any layer in the image contains deep data.
//!

// The following three stages are internally used to read an image.
// 1. `ReadImage` - The specification. Contains everything the user wants to tell us about loading an image.
//    The data in this structure will be instantiated and might be borrowed.
// 2. `ImageReader` - The temporary reader. Based on the specification of the blueprint,
//    a reader is instantiated, once for each layer.
//    This data structure accumulates the image data from the file.
//    It also owns temporary data and references the blueprint.
// 3. `Image` - The clean image. The accumulated data from the Reader
//    is converted to the clean image structure, without temporary data.

pub mod image;
pub mod layers;
pub mod any_channels;
pub mod levels;
pub mod samples;
pub mod specific_channels;

use crate::error::{Result};
use crate::image::read::samples::{ReadFlatSamples};
use std::path::Path;
use crate::image::{AnyImage, AnyChannels, FlatSamples, Image, Layer, FlatImage, PixelLayersImage, RgbaChannels};
use crate::image::read::image::ReadLayers;
use crate::image::read::layers::ReadChannels;
use crate::math::Vec2;
use crate::prelude::{PixelImage};
use crate::block::samples::FromNativeSample;


/// All resolution levels, all channels, all layers.
/// Does not support deep data yet. Uses parallel decompression and relaxed error handling.
/// Inspect the source code of this function if you need customization.
pub fn read_all_data_from_file(path: impl AsRef<Path>) -> Result<AnyImage> {
    read()
        .no_deep_data() // TODO deep data
        .all_resolution_levels()
        .all_channels()
        .all_layers()
        .all_attributes()
        .from_file(path)
}

// FIXME do not throw error on deep data but just skip it!
/// No deep data, no resolution levels, all channels, all layers.
/// Uses parallel decompression and relaxed error handling.
/// Inspect the source code of this function if you need customization.
pub fn read_all_flat_layers_from_file(path: impl AsRef<Path>) -> Result<FlatImage> {
    read()
        .no_deep_data()
        .largest_resolution_level()
        .all_channels()
        .all_layers()
        .all_attributes()
        .from_file(path)
}

/// No deep data, no resolution levels, all channels, first layer.
/// Uses parallel decompression and relaxed error handling.
/// Inspect the source code of this function if you need customization.
pub fn read_first_flat_layer_from_file(path: impl AsRef<Path>) -> Result<Image<Layer<AnyChannels<FlatSamples>>>> {
    read()
        .no_deep_data()
        .largest_resolution_level()
        .all_channels()
        .first_valid_layer()
        .all_attributes()
        .from_file(path)
}

/// No deep data, no resolution levels, rgba channels, all layers.
/// If a single layer does not contain rgba data, this method returns an error.
/// Uses parallel decompression and relaxed error handling.
/// `Create` and `Set` can be closures, see the examples for more information.
/// Inspect the source code of this function if you need customization.
/// The alpha channel will contain the value `1.0` if no alpha channel can be found in the image.
///
/// Using two closures, define how to store the pixels.
/// The first closure creates an image, and the second closure inserts a single pixel.
/// The type of the pixel can be defined by the second closure;
/// it must be a tuple containing four values, each being either `f16`, `f32`, `u32` or `Sample`.
// FIXME Set and Create should not need to be static
pub fn read_all_rgba_layers_from_file<R,G,B,A, Set:'static, Create:'static, Pixels: 'static>(
    path: impl AsRef<Path>, create: Create, set_pixel: Set
)
    -> Result<PixelLayersImage<Pixels, RgbaChannels>>
    where
        R: FromNativeSample, G: FromNativeSample, B: FromNativeSample, A: FromNativeSample,
        Create: Fn(Vec2<usize>, &RgbaChannels) -> Pixels, // TODO type alias? CreateRgbaPixels<Pixels=Pixels>,
        Set: Fn(&mut Pixels, Vec2<usize>, (R,G,B,A)),
{
    read()
        .no_deep_data()
        .largest_resolution_level()
        .rgba_channels(create, set_pixel)
        .all_layers()
        .all_attributes()
        .from_file(path)
}

/// No deep data, no resolution levels, rgba channels, choosing the first layer with rgba channels.
/// Uses parallel decompression and relaxed error handling.
/// `Create` and `Set` can be closures, see the examples for more information.
/// Inspect the source code of this function if you need customization.
/// The alpha channel will contain the value `1.0` if no alpha channel can be found in the image.
///
/// Using two closures, define how to store the pixels.
/// The first closure creates an image, and the second closure inserts a single pixel.
/// The type of the pixel can be defined by the second closure;
/// it must be a tuple containing four values, each being either `f16`, `f32`, `u32` or `Sample`.
// FIXME Set and Create should not need to be static
pub fn read_first_rgba_layer_from_file<R,G,B,A, Set:'static, Create:'static, Pixels: 'static>(
    path: impl AsRef<Path>, create: Create, set_pixel: Set
)
    -> Result<PixelImage<Pixels, RgbaChannels>>
    where
        R: FromNativeSample, G: FromNativeSample, B: FromNativeSample, A: FromNativeSample,
        Create: Fn(Vec2<usize>, &RgbaChannels) -> Pixels, // TODO type alias? CreateRgbaPixels<Pixels=Pixels>,
        Set: Fn(&mut Pixels, Vec2<usize>, (R,G,B,A)),
{
    read()
        .no_deep_data()
        .largest_resolution_level()
        .rgba_channels(create, set_pixel)
        .first_valid_layer()
        .all_attributes()
        .from_file(path)
}


/// Utilizes the builder pattern to configure an image reader. This is the initial struct.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct ReadBuilder;

/// Create a reader which can be used to load an exr image.
/// Allows you to exactly specify how to load the image, for example:
///
/// ```no_run
///     use exr::prelude::*;
///
///     // the type of the this image depends on the chosen options
///     let image = read()
///         .no_deep_data() // (currently required)
///         .largest_resolution_level() // or `all_resolution_levels()`
///         .all_channels() // or `rgba_channels(constructor, setter)`
///         .all_layers() // or `first_valid_layer()`
///         .all_attributes() // (currently required)
///         .on_progress(|progress| println!("progress: {:.1}", progress*100.0)) // optional
///         .from_file("image.exr").unwrap(); // or `from_buffered(my_byte_slice)`
/// ```
///
/// You can alternatively use one of the following simpler functions:
/// 1. `read_first_flat_layer_from_file`
/// 1. `read_all_rgba_layers_from_file`
/// 1. `read_all_flat_layers_from_file`
/// 1. `read_all_data_from_file`
///
// TODO not panic but skip deep layers!
pub fn read() -> ReadBuilder { ReadBuilder }

impl ReadBuilder {

    /// Specify to handle only one sample per channel, disabling "deep data".
    // TODO not panic but skip deep layers!
    pub fn no_deep_data(self) -> ReadFlatSamples { ReadFlatSamples }

    // pub fn any_resolution_levels() -> ReadBuilder<> {}

    // TODO
    // e. g. `let sum = reader.any_channels_with(|sample, sum| sum += sample)`
    // e. g. `let floats = reader.any_channels_with(|sample, f32_samples| f32_samples[index] = sample as f32)`
    // pub fn no_deep_data_with <S> (self, storage: S) -> FlatSamplesWith<S> {  }

    // pub fn flat_and_deep_data(self) -> ReadAnySamples { ReadAnySamples }
}