Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
This commit is contained in:
36
vendor/exr/examples/0a_write_rgba.rs
vendored
Normal file
36
vendor/exr/examples/0a_write_rgba.rs
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
extern crate exr;
|
||||
|
||||
|
||||
/// `exr` offers a few simplified functions for the most basic use cases.
|
||||
/// `write_rgb_f32_file` is a such a function, which writes a plain rgba exr file.
|
||||
///
|
||||
/// To write your image data, you need to specify how to retrieve a single pixel from it.
|
||||
/// The closure may capture variables or generate data on the fly.
|
||||
fn main() {
|
||||
use exr::prelude::*;
|
||||
|
||||
// write a file, with 32-bit float precision per channel
|
||||
write_rgba_file(
|
||||
|
||||
// this accepts paths or &str
|
||||
"minimal_rgba.exr",
|
||||
|
||||
// image resolution is 2k
|
||||
2048, 2048,
|
||||
|
||||
// generate (or lookup in your own image)
|
||||
// an f32 rgb color for each of the 2048x2048 pixels
|
||||
// (you could also create f16 values here to save disk space)
|
||||
|x,y| {
|
||||
(
|
||||
x as f32 / 2048.0, // red
|
||||
y as f32 / 2048.0, // green
|
||||
1.0 - (y as f32 / 2048.0), // blue
|
||||
1.0 // alpha
|
||||
)
|
||||
}
|
||||
|
||||
).unwrap();
|
||||
|
||||
println!("created file minimal_rgb.exr");
|
||||
}
|
22
vendor/exr/examples/0b_read_meta.rs
vendored
Normal file
22
vendor/exr/examples/0b_read_meta.rs
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
|
||||
|
||||
// exr imports
|
||||
extern crate exr;
|
||||
|
||||
/// Print the custom meta data of a file, excluding technical encoding meta data.
|
||||
/// Prints compression method and tile size, but not purely technical data like chunk count.
|
||||
fn main() {
|
||||
use exr::prelude::*;
|
||||
|
||||
let meta_data = MetaData::read_from_file(
|
||||
"generated_rgba_with_meta.exr",
|
||||
false // do not throw an error for invalid or missing attributes, skipping them instead
|
||||
).expect("run example `1_write_rgba_with_metadata` to generate the required file");
|
||||
|
||||
for (layer_index, image_layer) in meta_data.headers.iter().enumerate() {
|
||||
println!(
|
||||
"custom meta data of layer #{}:\n{:#?}",
|
||||
layer_index, image_layer.own_attributes
|
||||
);
|
||||
}
|
||||
}
|
30
vendor/exr/examples/0c_read_rgba.rs
vendored
Normal file
30
vendor/exr/examples/0c_read_rgba.rs
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
extern crate exr;
|
||||
|
||||
/// `exr` offers a few simplified functions for the most basic use cases.
|
||||
/// `read_first_rgba_layer_from_file` is a such a function, which loads rgba exr files.
|
||||
/// To load the pixel data, you need to specify
|
||||
/// how to create and how to set the pixels of your image.
|
||||
fn main() {
|
||||
let image = exr::prelude::read_first_rgba_layer_from_file(
|
||||
"generated_rgba.exr",
|
||||
|
||||
// instantiate your image type with the size of the image in file
|
||||
|resolution, _| {
|
||||
let default_pixel = [0.0, 0.0, 0.0, 0.0];
|
||||
let empty_line = vec![ default_pixel; resolution.width() ];
|
||||
let empty_image = vec![ empty_line; resolution.height() ];
|
||||
empty_image
|
||||
},
|
||||
|
||||
// transfer the colors from the file to your image type,
|
||||
// requesting all values to be converted to f32 numbers (you can also directly use f16 instead)
|
||||
// and you could also use `Sample` instead of `f32` to keep the original data type from the file
|
||||
|pixel_vector, position, (r,g,b, a): (f32, f32, f32, f32)| {
|
||||
pixel_vector[position.y()][position.x()] = [r, g, b, a]
|
||||
},
|
||||
|
||||
).expect("run the `1_write_rgba` example to generate the required file");
|
||||
|
||||
// printing all pixels might kill the console, so only print some meta data about the image
|
||||
println!("opened file generated_rgba.exr: {:#?}", image.layer_data.attributes);
|
||||
}
|
64
vendor/exr/examples/1a_write_rgba_with_metadata.rs
vendored
Normal file
64
vendor/exr/examples/1a_write_rgba_with_metadata.rs
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
|
||||
// exr imports
|
||||
extern crate exr;
|
||||
|
||||
/// Write an rgba exr file, generating the pixel values on the fly.
|
||||
/// This streams the generated pixel directly to the file,
|
||||
/// never allocating the actual total pixel memory of the image.
|
||||
fn main() {
|
||||
use exr::prelude::*;
|
||||
use exr::meta::attribute::*;
|
||||
|
||||
// this function can generate a color for any pixel
|
||||
let generate_pixels = |position: Vec2<usize>| (
|
||||
position.x() as f32 / 2048.0, // red
|
||||
position.y() as f32 / 2048.0, // green
|
||||
1.0 - (position.y() as f32 / 2048.0), // blue
|
||||
1.0 // alpha
|
||||
);
|
||||
|
||||
let mut layer_attributes = LayerAttributes::named("generated rgba main layer");
|
||||
layer_attributes.comments = Some(Text::from("This image was generated as part of an example"));
|
||||
layer_attributes.owner = Some(Text::from("The holy lambda function"));
|
||||
layer_attributes.software_name = Some(Text::from("EXRS Project"));
|
||||
layer_attributes.exposure = Some(1.0);
|
||||
layer_attributes.focus = Some(12.4);
|
||||
layer_attributes.frames_per_second = Some((60, 1));
|
||||
layer_attributes.other.insert(
|
||||
Text::from("Layer Purpose (Custom Layer Attribute)"),
|
||||
AttributeValue::Text(Text::from("This layer contains the rgb pixel data"))
|
||||
);
|
||||
|
||||
let layer = Layer::new(
|
||||
(2*2048, 2*2048),
|
||||
layer_attributes,
|
||||
Encoding::SMALL_FAST_LOSSLESS, // use fast but lossy compression
|
||||
|
||||
SpecificChannels::rgba(generate_pixels)
|
||||
);
|
||||
|
||||
// crop away black and transparent pixels from the border, if any
|
||||
let layer = layer
|
||||
.crop_where_eq((0.0, 0.0, 0.0, 0.0))
|
||||
.or_crop_to_1x1_if_empty();
|
||||
|
||||
let mut image = Image::from_layer(layer);
|
||||
image.attributes.pixel_aspect = 1.0;
|
||||
|
||||
image.attributes.time_code = Some(TimeCode {
|
||||
hours: 0,
|
||||
minutes: 1,
|
||||
seconds: 59,
|
||||
frame: 29,
|
||||
..TimeCode::default()
|
||||
});
|
||||
|
||||
image.attributes.other.insert(
|
||||
Text::from("Mice Count (Custom Image Attribute)"),
|
||||
AttributeValue::I32(23333)
|
||||
);
|
||||
|
||||
// write it to a file with all cores in parallel
|
||||
image.write().to_file("generated_rgba_with_meta.exr").unwrap();
|
||||
println!("created file generated_rgba_with_meta.exr");
|
||||
}
|
53
vendor/exr/examples/1b_convert_exr_to_png.rs
vendored
Normal file
53
vendor/exr/examples/1b_convert_exr_to_png.rs
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
|
||||
extern crate image as png;
|
||||
|
||||
// exr imports
|
||||
extern crate exr;
|
||||
|
||||
/// Converts one rgba exr with one layer to one png, or fail.
|
||||
fn main() {
|
||||
use exr::prelude::*;
|
||||
use exr::prelude as exrs;
|
||||
|
||||
// read from the exr file directly into a new `png::RgbaImage` image without intermediate buffers
|
||||
let reader = exrs::read()
|
||||
.no_deep_data()
|
||||
.largest_resolution_level()
|
||||
.rgba_channels(
|
||||
|resolution, _channels: &RgbaChannels| -> png::RgbaImage {
|
||||
png::ImageBuffer::new(
|
||||
resolution.width() as u32,
|
||||
resolution.height() as u32
|
||||
)
|
||||
},
|
||||
|
||||
// set each pixel in the png buffer from the exr file
|
||||
|png_pixels, position, (r,g,b,a): (f32,f32,f32,f32)| { // TODO implicit argument types!
|
||||
png_pixels.put_pixel(
|
||||
position.x() as u32, position.y() as u32,
|
||||
png::Rgba([tone_map(r), tone_map(g), tone_map(b), (a * 255.0) as u8])
|
||||
);
|
||||
}
|
||||
)
|
||||
.first_valid_layer()
|
||||
.all_attributes();
|
||||
|
||||
// an image that contains a single layer containing an png rgba buffer
|
||||
let image: Image<Layer<SpecificChannels<png::RgbaImage, RgbaChannels>>> = reader
|
||||
.from_file("generated_rgba.exr")
|
||||
.expect("run the `1_write_rgba` example to generate the required file");
|
||||
|
||||
|
||||
/// compress any possible f32 into the range of [0,1].
|
||||
/// and then convert it to an unsigned byte.
|
||||
fn tone_map(linear: f32) -> u8 {
|
||||
// TODO does the `image` crate expect gamma corrected data?
|
||||
let clamped = (linear - 0.5).tanh() * 0.5 + 0.5;
|
||||
(clamped * 255.0) as u8
|
||||
}
|
||||
|
||||
// save the png buffer to a png file
|
||||
let png_buffer = &image.layer_data.channel_data.pixels;
|
||||
png_buffer.save("rgb.png").unwrap();
|
||||
println!("created image rgb.png")
|
||||
}
|
80
vendor/exr/examples/2_rgba_adjust_exposure.rs
vendored
Normal file
80
vendor/exr/examples/2_rgba_adjust_exposure.rs
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
|
||||
// exr imports
|
||||
extern crate exr;
|
||||
|
||||
/// Read an rgba image, increase the exposure, and then write it back.
|
||||
/// Uses multi-core compression where appropriate.
|
||||
///
|
||||
/// All non-rgba channels and all layers except the first rgba layers will not be present in the new file.
|
||||
fn main() {
|
||||
use exr::prelude::*;
|
||||
|
||||
/// This is an example of a custom image type.
|
||||
/// You use your own image struct here.
|
||||
// This struct trades sub-optimal memory-efficiency for clarity,
|
||||
// because this is an example, and does not have to be perfectly efficient.
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct CustomPixels { lines: Vec<Vec<RgbaF32Pixel>> }
|
||||
type RgbaF32Pixel = (f32, f32, f32, f32);
|
||||
|
||||
// read the image from a file
|
||||
let mut image = read().no_deep_data()
|
||||
.largest_resolution_level()
|
||||
.rgba_channels(
|
||||
// create our custom image based on the file info
|
||||
|resolution, _channels| -> CustomPixels {
|
||||
let default_rgba_pixel = (0.0, 0.0, 0.0, 0.0);
|
||||
let default_line = vec![default_rgba_pixel; resolution.width()];
|
||||
let lines = vec![default_line; resolution.height()];
|
||||
CustomPixels { lines }
|
||||
},
|
||||
|
||||
// request pixels with red, green, blue, and optionally and alpha values.
|
||||
// transfer each pixel from the file to our image
|
||||
|image, position, (r,g,b,a): RgbaF32Pixel| {
|
||||
|
||||
// insert the values into our custom image
|
||||
image.lines[position.y()][position.x()] = (r,g,b,a);
|
||||
}
|
||||
)
|
||||
.first_valid_layer()
|
||||
.all_attributes()
|
||||
.from_file("generated_rgba.exr")
|
||||
.expect("run the `1_write_rgba` example to generate the required file");
|
||||
|
||||
let exposure_multiplier = 2.0;
|
||||
|
||||
{ // increase exposure of all pixels
|
||||
for line in &mut image.layer_data.channel_data.pixels.lines {
|
||||
for (r,g,b,_) in line {
|
||||
// you should probably check the color space and white points
|
||||
// for high quality color adjustments
|
||||
*r *= exposure_multiplier;
|
||||
*g *= exposure_multiplier;
|
||||
*b *= exposure_multiplier;
|
||||
}
|
||||
}
|
||||
|
||||
// also update meta data after modifying the image
|
||||
if let Some(exposure) = &mut image.layer_data.attributes.exposure {
|
||||
println!("increased exposure from {}s to {}s", exposure, *exposure * exposure_multiplier);
|
||||
*exposure *= exposure_multiplier;
|
||||
}
|
||||
}
|
||||
|
||||
// enable writing our custom pixel storage to a file
|
||||
// FIXME this should be passed as a closure to the `write_with(|x| y)` call
|
||||
impl GetPixel for CustomPixels {
|
||||
type Pixel = RgbaF32Pixel;
|
||||
fn get_pixel(&self, position: Vec2<usize>) -> Self::Pixel {
|
||||
self.lines[position.y()][position.x()]
|
||||
}
|
||||
}
|
||||
|
||||
// write the image to a file
|
||||
image
|
||||
.write().to_file("rgba_exposure_adjusted.exr")
|
||||
.unwrap();
|
||||
|
||||
println!("created file rgba_exposure_adjusted.exr");
|
||||
}
|
78
vendor/exr/examples/3a_write_dynamic_channels_with_metadata.rs
vendored
Normal file
78
vendor/exr/examples/3a_write_dynamic_channels_with_metadata.rs
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
|
||||
#[macro_use]
|
||||
extern crate smallvec;
|
||||
extern crate rand;
|
||||
extern crate half;
|
||||
|
||||
use rand::Rng;
|
||||
|
||||
// exr imports
|
||||
extern crate exr;
|
||||
|
||||
|
||||
/// Generate a noisy image and write it to a file,
|
||||
/// also attaching some meta data.
|
||||
fn main() {
|
||||
use exr::prelude::*;
|
||||
|
||||
fn generate_f16_vector(size: Vec2<usize>) -> Vec<f16> {
|
||||
let mut values = vec![ f16::from_f32(0.5); size.area() ];
|
||||
|
||||
for _ in 0..(1024*1024/3)/4 {
|
||||
let index = rand::thread_rng().gen_range(0 .. values.len());
|
||||
let value = 1.0 / rand::random::<f32>() - 1.0;
|
||||
let value = if !value.is_normal() || value > 1000.0 { 1000.0 } else { value };
|
||||
values[index] = f16::from_f32(value);
|
||||
}
|
||||
|
||||
values
|
||||
}
|
||||
|
||||
let size = (1024, 512);
|
||||
|
||||
let r = AnyChannel::new(
|
||||
"R", FlatSamples::F16(generate_f16_vector(size.into()))
|
||||
);
|
||||
|
||||
let g = AnyChannel::new(
|
||||
"G", FlatSamples::F16(generate_f16_vector(size.into()))
|
||||
);
|
||||
|
||||
let b = AnyChannel::new(
|
||||
"B", FlatSamples::F32(generate_f16_vector(size.into()).into_iter().map(f16::to_f32).collect())
|
||||
);
|
||||
|
||||
let a = AnyChannel::new(
|
||||
"A", FlatSamples::F32(generate_f16_vector(size.into()).into_iter().map(f16::to_f32).collect())
|
||||
);
|
||||
|
||||
let mut layer_attributes = LayerAttributes::named("test-image");
|
||||
layer_attributes.owner = Some(Text::from("It's you!"));
|
||||
layer_attributes.comments = Some(Text::from("This image was procedurally generated"));
|
||||
|
||||
let layer = Layer::new(
|
||||
size,
|
||||
layer_attributes,
|
||||
Encoding::default(),
|
||||
AnyChannels::sort(smallvec![ r, g, b, a ]),
|
||||
);
|
||||
|
||||
// crop away transparent pixels from the border
|
||||
let layer = layer
|
||||
|
||||
// channel order is (a,b,g,r), as channels are already sorted
|
||||
.crop_where(|samples| samples[0].is_zero())
|
||||
|
||||
// throw error if the image is 100% transparent pixels and should be removed
|
||||
.or_none_if_empty().expect("image is empty and cannot be cropped");
|
||||
|
||||
let image = Image::from_layer(layer);
|
||||
|
||||
println!("writing image {:#?}", image);
|
||||
|
||||
image.write()
|
||||
.on_progress(|progress| println!("progress: {:.1}", progress*100.0))
|
||||
.to_file("noisy.exr").unwrap();
|
||||
|
||||
println!("created file noisy.exr");
|
||||
}
|
35
vendor/exr/examples/3b_read_all_channels_with_metadata.rs
vendored
Normal file
35
vendor/exr/examples/3b_read_all_channels_with_metadata.rs
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
|
||||
// exr imports
|
||||
extern crate exr;
|
||||
|
||||
/// Read an image and print information about the image into the console.
|
||||
/// This example shows how to read an image with multiple layers and arbitrary channels.
|
||||
/// For example, a layer with XYZ channels, and additionally a separate Depth layer.
|
||||
/// This example does not include resolution levels (mipmaps or ripmaps).
|
||||
fn main() {
|
||||
use exr::prelude::*;
|
||||
|
||||
let image = read().no_deep_data()
|
||||
.largest_resolution_level().all_channels().all_layers().all_attributes()
|
||||
.on_progress(|progress| println!("progress: {:.1}", progress*100.0))
|
||||
.from_file("generated_rgba_with_meta.exr")
|
||||
.expect("run example `1_write_rgba_with_metadata` to generate this image file");
|
||||
|
||||
println!("image was read: {:#?}", image);
|
||||
|
||||
// output the average value for each channel of each layer
|
||||
for layer in &image.layer_data {
|
||||
for channel in &layer.channel_data.list {
|
||||
|
||||
let sample_vec = &channel.sample_data;
|
||||
let average = sample_vec.values_as_f32().sum::<f32>() / sample_vec.len() as f32;
|
||||
|
||||
if let Some(layer_name) = &layer.attributes.layer_name {
|
||||
println!("Channel `{}` of Layer `{}` has an average value of {}", channel.name, layer_name, average);
|
||||
}
|
||||
else {
|
||||
println!("Channel `{}` has an average value of {}", channel.name, average);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
41
vendor/exr/examples/4a_write_custom_fixed_channels.rs
vendored
Normal file
41
vendor/exr/examples/4a_write_custom_fixed_channels.rs
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
// exr imports
|
||||
extern crate exr;
|
||||
|
||||
/// Create an image with strange channels and write it to a file.
|
||||
fn main() {
|
||||
use exr::prelude::*;
|
||||
|
||||
let pixels = SpecificChannels::build()
|
||||
.with_channel("Kharthanasus Korthus")
|
||||
.with_channel("Y")
|
||||
.with_channel("11023")
|
||||
.with_channel("*?!")
|
||||
.with_channel("`--\"")
|
||||
.with_channel("\r\r\r\n\n")
|
||||
.with_pixel_fn(|position|{
|
||||
if position.0 < 1000 {
|
||||
(f16::from_f32(0.2), 0.666_f32, 4_u32, 1532434.0213_f32, 0.99999_f32, 3.142594_f32/4.0)
|
||||
}
|
||||
else {
|
||||
(f16::from_f32(0.4), 0.777_f32, 8_u32, 102154.3_f32, 0.00001_f32, 3.142594_f32/4.0)
|
||||
}
|
||||
});
|
||||
|
||||
let image = Image::from_channels((2000, 1400), pixels);
|
||||
|
||||
// print progress only if it advances more than 1%
|
||||
let mut current_progress_percentage = 0;
|
||||
|
||||
image.write()
|
||||
.on_progress(|progress| {
|
||||
let new_progress = (progress * 100.0) as usize;
|
||||
if new_progress != current_progress_percentage {
|
||||
current_progress_percentage = new_progress;
|
||||
println!("progress: {}%", current_progress_percentage)
|
||||
}
|
||||
})
|
||||
.to_file("custom_channels.exr").unwrap();
|
||||
|
||||
println!("created file custom_channels.exr");
|
||||
}
|
49
vendor/exr/examples/4b_read_custom_fixed_channels.rs
vendored
Normal file
49
vendor/exr/examples/4b_read_custom_fixed_channels.rs
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
|
||||
// exr imports
|
||||
extern crate exr;
|
||||
|
||||
/// Read an image and print information about the image into the console.
|
||||
/// This example shows how to read an image with multiple layers and specific channels.
|
||||
/// This example does not include resolution levels (mipmaps or ripmaps).
|
||||
fn main() {
|
||||
use exr::prelude::*;
|
||||
|
||||
let image = read().no_deep_data()
|
||||
.largest_resolution_level()
|
||||
|
||||
.specific_channels()
|
||||
.optional("A", f16::ONE)
|
||||
.required("Y") // TODO also accept a closure with a detailed selection mechanism
|
||||
.optional("right.Y", 0.0)
|
||||
.collect_pixels(
|
||||
|resolution, (a_channel, y_channel, y_right_channel)| {
|
||||
println!("image contains alpha channel? {}", a_channel.is_some());
|
||||
println!("image contains stereoscopic luma channel? {}", y_right_channel.is_some());
|
||||
println!("the type of luma samples is {:?}", y_channel.sample_type);
|
||||
|
||||
vec![vec![(f16::ZERO, 0.0, 0.0); resolution.width()]; resolution.height()]
|
||||
},
|
||||
|
||||
// all samples will be converted to f32 (you can also use the enum `Sample` instead of `f32` here to retain the original data type from the file)
|
||||
|vec, position, (a,y,yr): (f16, f32, f32)| {
|
||||
vec[position.y()][position.x()] = (a, y, yr)
|
||||
}
|
||||
)
|
||||
|
||||
.all_layers()
|
||||
.all_attributes()
|
||||
.on_progress(|progress| println!("progress: {:.1}", progress*100.0))
|
||||
.from_file("custom_channels.exr")
|
||||
.expect("run example `4_write_custom_fixed_channels` to generate this image file");
|
||||
|
||||
// output a random color of each channel of each layer
|
||||
for layer in &image.layer_data {
|
||||
let (alpha, luma, luma_right) = layer.channel_data.pixels.first().unwrap().first().unwrap();
|
||||
|
||||
println!(
|
||||
"top left color of layer `{}`: (a, y, yr) = {:?}",
|
||||
layer.attributes.layer_name.clone().unwrap_or_default(),
|
||||
(alpha.to_f32(), luma, luma_right)
|
||||
)
|
||||
}
|
||||
}
|
45
vendor/exr/examples/5a_write_multiple_layers.rs
vendored
Normal file
45
vendor/exr/examples/5a_write_multiple_layers.rs
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
|
||||
extern crate smallvec;
|
||||
extern crate rand;
|
||||
extern crate half;
|
||||
|
||||
|
||||
// exr imports
|
||||
extern crate exr;
|
||||
|
||||
/// Writes multiple layers into one exr file
|
||||
/// Note: this may not be supported by legacy software
|
||||
fn main() {
|
||||
use exr::prelude::*;
|
||||
let size = Vec2(512, 512);
|
||||
|
||||
|
||||
let layer1 = Layer::new(
|
||||
size,
|
||||
LayerAttributes::named("teal rgb"),
|
||||
Encoding::FAST_LOSSLESS,
|
||||
SpecificChannels::rgb(|_pos| (0_f32, 0.4_f32, 0.4_f32)),
|
||||
);
|
||||
|
||||
let layer2 = Layer::new(
|
||||
size,
|
||||
LayerAttributes::named("orange rgba"),
|
||||
Encoding::FAST_LOSSLESS,
|
||||
SpecificChannels::rgba(|_pos| (0.8_f32, 0.5_f32, 0.1_f32, 1.0_f32)),
|
||||
);
|
||||
|
||||
// define the visible area of the canvas
|
||||
let attributes = ImageAttributes::new(
|
||||
// the pixel section that should be shown
|
||||
IntegerBounds::from_dimensions(size)
|
||||
);
|
||||
|
||||
let image = Image::empty(attributes)
|
||||
.with_layer(layer1) // add an rgb layer of type `SpecificChannels<ClosureA>`
|
||||
.with_layer(layer2); // add an rgba layer of different type, `SpecificChannels<ClosureB>`, not possible with a vector
|
||||
|
||||
println!("writing image...");
|
||||
image.write().to_file("layers.exr").unwrap();
|
||||
|
||||
println!("created file layers.exr");
|
||||
}
|
74
vendor/exr/examples/5b_extract_exr_layers_as_pngs.rs
vendored
Normal file
74
vendor/exr/examples/5b_extract_exr_layers_as_pngs.rs
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
extern crate image as png;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
extern crate exr;
|
||||
|
||||
/// For each layer in the exr file,
|
||||
/// extract each channel as grayscale png,
|
||||
/// including all multi-resolution levels.
|
||||
//
|
||||
// FIXME throws "access denied" sometimes, simply trying again usually works.
|
||||
//
|
||||
pub fn main() {
|
||||
use exr::prelude::*;
|
||||
|
||||
let path = "layers.exr";
|
||||
let now = ::std::time::Instant::now();
|
||||
|
||||
// load the exr file from disk with multi-core decompression
|
||||
let image = read()
|
||||
.no_deep_data().largest_resolution_level().all_channels().all_layers().all_attributes()
|
||||
.from_file(path).expect("run example `5a_write_multiple_layers` to generate this image file");
|
||||
|
||||
// warning: highly unscientific benchmarks ahead!
|
||||
println!("\nloaded file in {:?}s", now.elapsed().as_secs_f32());
|
||||
let _ = std::fs::create_dir_all("pngs/");
|
||||
println!("writing images...");
|
||||
|
||||
for (layer_index, layer) in image.layer_data.iter().enumerate() {
|
||||
let layer_name = layer.attributes.layer_name.as_ref()
|
||||
.map_or(String::from("main_layer"), Text::to_string);
|
||||
|
||||
for channel in &layer.channel_data.list {
|
||||
let data : Vec<f32> = channel.sample_data.values_as_f32().collect();
|
||||
save_f32_image_as_png(&data, layer.size, format!(
|
||||
"pngs/{} ({}) {}_{}x{}.png",
|
||||
layer_index, layer_name, channel.name,
|
||||
layer.size.width(), layer.size.height(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Save raw float data to a PNG file, doing automatic brightness adjustments per channel
|
||||
fn save_f32_image_as_png(data: &[f32], size: Vec2<usize>, name: String) {
|
||||
let mut png_buffer = png::GrayImage::new(size.width() as u32, size.height() as u32);
|
||||
let mut sorted = Vec::from(data);
|
||||
sorted.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Less));
|
||||
|
||||
// percentile normalization
|
||||
let max = sorted[7 * sorted.len() / 8];
|
||||
let min = sorted[1 * sorted.len() / 8];
|
||||
|
||||
// primitive tone mapping
|
||||
let tone = |v: f32| (v - 0.5).tanh() * 0.5 + 0.5;
|
||||
let max_toned = tone(*sorted.last().unwrap());
|
||||
let min_toned = tone(*sorted.first().unwrap());
|
||||
|
||||
// for each pixel, tone map the value
|
||||
for (x, y, pixel) in png_buffer.enumerate_pixels_mut() {
|
||||
let v = data[y as usize * size.0 + x as usize];
|
||||
let v = (v - min) / (max - min);
|
||||
let v = tone(v);
|
||||
|
||||
let v = (v - min_toned) / (max_toned - min_toned);
|
||||
|
||||
// TODO does the `image` crate expect gamma corrected data?
|
||||
*pixel = png::Luma([(v.max(0.0).min(1.0) * 255.0) as u8]);
|
||||
}
|
||||
|
||||
png_buffer.save(&name).unwrap();
|
||||
}
|
||||
|
||||
println!("extracted all layers to folder `./pngs/*.png`");
|
||||
}
|
||||
|
73
vendor/exr/examples/5c_write_mip_maps.rs
vendored
Normal file
73
vendor/exr/examples/5c_write_mip_maps.rs
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
|
||||
extern crate smallvec;
|
||||
extern crate rand;
|
||||
extern crate half;
|
||||
|
||||
|
||||
// exr imports
|
||||
extern crate exr;
|
||||
|
||||
|
||||
|
||||
/// Writes two layers, each with multiple mip maps.
|
||||
/// All mip maps have solid color for brevity.
|
||||
fn main() {
|
||||
use exr::prelude::*;
|
||||
use exr::math::RoundingMode;
|
||||
use smallvec::smallvec;
|
||||
|
||||
let full_size = Vec2(512, 512);
|
||||
let size_rounding = RoundingMode::Up;
|
||||
|
||||
let mip_levels_sizes = exr::meta::mip_map_levels(
|
||||
size_rounding, full_size
|
||||
).collect::<Vec<_>>();
|
||||
|
||||
let red_mip_levels = mip_levels_sizes.iter()
|
||||
.map(|(_index, level_size)|{
|
||||
FlatSamples::F32(vec![0.1_f32; level_size.area() ])
|
||||
})
|
||||
.collect();
|
||||
|
||||
let green_mip_levels = mip_levels_sizes.iter()
|
||||
.map(|(_index, level_size)|{
|
||||
FlatSamples::F32(vec![0.6_f32; level_size.area() ])
|
||||
})
|
||||
.collect();
|
||||
|
||||
let blue_mip_levels = mip_levels_sizes.iter()
|
||||
.map(|(_index, level_size)|{
|
||||
FlatSamples::F32(vec![1.0_f32; level_size.area() ])
|
||||
})
|
||||
.collect();
|
||||
|
||||
let rgb_mip_maps = AnyChannels::sort(smallvec![
|
||||
AnyChannel::new("R", Levels::Mip { level_data: red_mip_levels, rounding_mode: size_rounding }),
|
||||
AnyChannel::new("G", Levels::Mip { level_data: green_mip_levels, rounding_mode: size_rounding }),
|
||||
AnyChannel::new("B", Levels::Mip { level_data: blue_mip_levels, rounding_mode: size_rounding }),
|
||||
]);
|
||||
|
||||
let layer1 = Layer::new(
|
||||
full_size,
|
||||
LayerAttributes::named("teal rgb"),
|
||||
Encoding::FAST_LOSSLESS,
|
||||
rgb_mip_maps
|
||||
);
|
||||
|
||||
let mut layer2 = layer1.clone();
|
||||
layer2.attributes.layer_name = Some("Copied Layer".into());
|
||||
layer2.encoding = Encoding::SMALL_FAST_LOSSLESS;
|
||||
|
||||
// define the visible area of the canvas
|
||||
let image_attributes = ImageAttributes::new(
|
||||
IntegerBounds::from_dimensions(full_size)
|
||||
);
|
||||
|
||||
let image = Image::empty(image_attributes)
|
||||
.with_layer(layer1).with_layer(layer2);
|
||||
|
||||
println!("writing image...");
|
||||
image.write().to_file("mip_maps.exr").unwrap();
|
||||
|
||||
println!("created file mip_maps.exr");
|
||||
}
|
73
vendor/exr/examples/5d_write_legacy_layers.rs
vendored
Normal file
73
vendor/exr/examples/5d_write_legacy_layers.rs
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
|
||||
#[macro_use]
|
||||
extern crate smallvec;
|
||||
extern crate rand;
|
||||
extern crate half;
|
||||
|
||||
|
||||
// exr imports
|
||||
extern crate exr;
|
||||
|
||||
// TODO create a dedicated reader and writer for this scenario
|
||||
|
||||
/// Generate an image with channel groups and write it to a file.
|
||||
/// Some legacy software may group layers that contain a `.` in the layer name.
|
||||
///
|
||||
/// Note: This is an OpenEXR legacy strategy. OpenEXR supports layers natively since 2013.
|
||||
/// Use the natively supported exrs `Layer` types instead, if possible.
|
||||
///
|
||||
fn main() {
|
||||
use exr::prelude::*;
|
||||
// TODO simplify handling these types of layers using read() and write()
|
||||
|
||||
let size = Vec2(512, 512);
|
||||
|
||||
let create_channel = |name: &str| -> AnyChannel<FlatSamples> {
|
||||
let color: f16 = f16::from_bits(rand::random::<u16>());
|
||||
|
||||
AnyChannel::new(
|
||||
name,
|
||||
FlatSamples::F16(vec![color; size.area() ])
|
||||
)
|
||||
};
|
||||
|
||||
|
||||
// The channels have the following structure:
|
||||
//
|
||||
// - Object
|
||||
// - Red
|
||||
// - Green
|
||||
// - Blue
|
||||
// - Alpha
|
||||
|
||||
// - Background
|
||||
// - Red
|
||||
// - Green
|
||||
// - Blue
|
||||
|
||||
let foreground_r = create_channel("Object.R");
|
||||
let foreground_g = create_channel("Object.G");
|
||||
let foreground_b = create_channel("Object.B");
|
||||
let foreground_a = create_channel("Object.A");
|
||||
|
||||
let background_r = create_channel("Background.R");
|
||||
let background_g = create_channel("Background.G");
|
||||
let background_b = create_channel("Background.B");
|
||||
|
||||
let layer = Layer::new(
|
||||
size,
|
||||
LayerAttributes::named("test-image"),
|
||||
Encoding::FAST_LOSSLESS,
|
||||
AnyChannels::sort(smallvec![ // the order does not actually matter
|
||||
foreground_r, foreground_g, foreground_b, foreground_a,
|
||||
background_r, background_g, background_b
|
||||
]),
|
||||
);
|
||||
|
||||
let image = Image::from_layer(layer);
|
||||
|
||||
println!("writing image {:#?}", image);
|
||||
image.write().to_file("groups.exr").unwrap();
|
||||
|
||||
println!("created file groups.exr");
|
||||
}
|
74
vendor/exr/examples/6_extract_mip_map_pngs.rs
vendored
Normal file
74
vendor/exr/examples/6_extract_mip_map_pngs.rs
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
|
||||
extern crate image as png;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
extern crate exr;
|
||||
|
||||
/// Extract all exr pixel information into pngs.
|
||||
/// Writes each channel of each mip map of each layer as one grayscale png.
|
||||
/// May appear black for single-color images.
|
||||
pub fn main() {
|
||||
use exr::prelude::*;
|
||||
|
||||
let path = "mip_maps.exr";
|
||||
let start_time = ::std::time::Instant::now();
|
||||
|
||||
// load the exr file from disk with multi-core decompression
|
||||
let image = read_all_data_from_file(path)
|
||||
.expect("run example `5c_write_mip_maps` to generate this image file");
|
||||
|
||||
// warning: highly unscientific benchmarks ahead!
|
||||
println!("\nloaded file in {:?}s", start_time.elapsed().as_secs_f32());
|
||||
let _ = std::fs::create_dir_all("pngs/");
|
||||
println!("writing images...");
|
||||
|
||||
for (layer_index, layer) in image.layer_data.iter().enumerate() {
|
||||
let layer_name = layer.attributes.layer_name.as_ref()
|
||||
.map_or(String::from("1"), Text::to_string);
|
||||
|
||||
for channel in &layer.channel_data.list {
|
||||
for (level, level_size) in layer.levels_with_resolution(&channel.sample_data) {
|
||||
let data : Vec<f32> = level.values_as_f32().collect();
|
||||
|
||||
save_f32_image_as_png(&data, level_size, format!(
|
||||
"pngs/{} ({}) {}.{}x{}.png",
|
||||
layer_index, layer_name, channel.name,
|
||||
level_size.width(), level_size.height(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Save raw float data to a PNG file, doing automatic brightness adjustments per channel
|
||||
fn save_f32_image_as_png(data: &[f32], size: Vec2<usize>, name: String) {
|
||||
let mut png_buffer = png::GrayImage::new(size.width() as u32, size.height() as u32);
|
||||
let mut sorted = Vec::from(data);
|
||||
sorted.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Less));
|
||||
|
||||
// percentile normalization
|
||||
let max = sorted[7 * sorted.len() / 8];
|
||||
let min = sorted[1 * sorted.len() / 8];
|
||||
|
||||
// primitive tone mapping
|
||||
let tone = |v: f32| (v - 0.5).tanh() * 0.5 + 0.5;
|
||||
let max_toned = tone(*sorted.last().unwrap());
|
||||
let min_toned = tone(*sorted.first().unwrap());
|
||||
|
||||
// for each pixel, tone map the value
|
||||
for (x, y, pixel) in png_buffer.enumerate_pixels_mut() {
|
||||
let v = data[y as usize * size.0 + x as usize];
|
||||
let v = (v - min) / (max - min);
|
||||
let v = tone(v);
|
||||
|
||||
let v = (v - min_toned) / (max_toned - min_toned);
|
||||
|
||||
// TODO does the `image` crate expect gamma corrected data?
|
||||
*pixel = png::Luma([(v.max(0.0).min(1.0) * 255.0) as u8]);
|
||||
}
|
||||
|
||||
png_buffer.save(&name).unwrap();
|
||||
}
|
||||
|
||||
println!("extracted all layers to folder `./pngs/*.png`");
|
||||
}
|
||||
|
46
vendor/exr/examples/7_crop_alpha_any_image.rs
vendored
Normal file
46
vendor/exr/examples/7_crop_alpha_any_image.rs
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
|
||||
extern crate image as png;
|
||||
|
||||
extern crate exr;
|
||||
|
||||
/// Read an arbitrary image, crop away transparent pixels,
|
||||
/// then write the cropped result to another file.
|
||||
pub fn main() {
|
||||
use exr::prelude::*;
|
||||
|
||||
let path = "tests/images/valid/custom/oh crop.exr";
|
||||
|
||||
// loads any image (excluding deep data)
|
||||
let image: FlatImage = read_all_flat_layers_from_file(path)
|
||||
.expect("this file exists in the exrs repository. download that?");
|
||||
|
||||
// construct a cropped image
|
||||
let image = Image {
|
||||
attributes: image.attributes,
|
||||
|
||||
// crop each layer
|
||||
layer_data: image.layer_data.into_iter().map(|layer|{
|
||||
println!("cropping layer {:#?}", layer);
|
||||
|
||||
// find the alpha channel of the layer
|
||||
let alpha_channel_index = layer.channel_data.list.iter()
|
||||
.position(|channel| channel.name.eq_case_insensitive("A"));
|
||||
|
||||
// if has alpha, crop it where alpha is zero
|
||||
if let Some(alpha_channel_index) = alpha_channel_index {
|
||||
layer.crop_where(|pixel: FlatSamplesPixel| pixel[alpha_channel_index].is_zero())
|
||||
.or_crop_to_1x1_if_empty() // do not remove empty layers from image, because it could result in an image without content
|
||||
.reallocate_cropped() // actually perform the crop operation
|
||||
}
|
||||
else {
|
||||
// return the original layer, as no alpha channel can be used for cropping
|
||||
layer
|
||||
}
|
||||
|
||||
}).collect::<Layers<_>>(),
|
||||
};
|
||||
|
||||
image.write().to_file("cropped.exr").unwrap();
|
||||
println!("cropped file to cropped.exr");
|
||||
}
|
||||
|
48
vendor/exr/examples/7_crop_alpha_rgba.rs
vendored
Normal file
48
vendor/exr/examples/7_crop_alpha_rgba.rs
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
|
||||
extern crate image as png;
|
||||
|
||||
extern crate exr;
|
||||
|
||||
|
||||
/// Read an rgba image, or fail if none can be found.
|
||||
/// Then crop away transparent pixels,
|
||||
/// and write the cropped result to another file.
|
||||
/// This retains only the rgb pixels, and no other layers.
|
||||
pub fn main() {
|
||||
use exr::prelude::*;
|
||||
use exr::image::pixel_vec::*; // import predefined pixel storage
|
||||
|
||||
let path = "tests/images/valid/custom/oh crop.exr";
|
||||
|
||||
type DynamicRgbaPixel = (Sample, Sample, Sample, Sample); // `Sample` is an enum containing the original data type (f16,f32, or u32)
|
||||
|
||||
// load an rgba image
|
||||
// this specific example discards all but the first valid rgb layers and converts all pixels to f32 values
|
||||
// TODO optional alpha channel!
|
||||
let image: PixelImage<PixelVec<DynamicRgbaPixel>, RgbaChannels> = read_first_rgba_layer_from_file(
|
||||
path,
|
||||
PixelVec::<DynamicRgbaPixel>::constructor,
|
||||
|
||||
// use this predefined rgba pixel container from the exr crate, requesting any type of pixels with 3 or 4 values
|
||||
PixelVec::set_pixel
|
||||
).expect("this file exists in the exrs repository. download that?");
|
||||
|
||||
// construct a ~simple~ cropped image
|
||||
let image: Image<Layer<CroppedChannels<SpecificChannels<PixelVec<DynamicRgbaPixel>, RgbaChannels>>>> = Image {
|
||||
attributes: image.attributes,
|
||||
|
||||
// crop each layer
|
||||
layer_data: {
|
||||
println!("cropping layer {:#?}", image.layer_data);
|
||||
|
||||
// if has alpha, crop it where alpha is zero
|
||||
image.layer_data
|
||||
.crop_where(|(_r, _g, _b, alpha)| alpha.is_zero())
|
||||
.or_crop_to_1x1_if_empty() // do not remove empty layers from image, because it could result in an image without content
|
||||
},
|
||||
};
|
||||
|
||||
image.write().to_file("cropped_rgba.exr").unwrap();
|
||||
println!("cropped file to cropped_rgba.exr");
|
||||
}
|
||||
|
115
vendor/exr/examples/7_write_raw_blocks.rs
vendored
Normal file
115
vendor/exr/examples/7_write_raw_blocks.rs
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
|
||||
#[macro_use]
|
||||
extern crate smallvec;
|
||||
extern crate rand;
|
||||
extern crate half;
|
||||
|
||||
use std::convert::TryInto;
|
||||
use std::io::BufWriter;
|
||||
use std::fs::File;
|
||||
use exr::block::{UncompressedBlock};
|
||||
use exr::block::writer::ChunksWriter;
|
||||
|
||||
// exr imports
|
||||
extern crate exr;
|
||||
|
||||
/// Generate a striped image on the fly and directly write that to a file without allocating the whole image at once.
|
||||
/// On my machine, this program produces a 3GB file while only ever allocating 4MB memory (takes a while though).
|
||||
fn main() {
|
||||
use exr::prelude::*;
|
||||
use attribute::*;
|
||||
use exr::math::*;
|
||||
|
||||
// pre-compute a list of random values
|
||||
let random_values: Vec<f32> = (0..64)
|
||||
.map(|_| rand::random::<f32>())
|
||||
.collect();
|
||||
|
||||
// resulting resolution (268 megapixels for 3GB files)
|
||||
let size = (2048*8, 2048*8);
|
||||
|
||||
// define meta data header that will be written
|
||||
let header = exr::meta::header::Header::new(
|
||||
"test-image".try_into().unwrap(),
|
||||
size,
|
||||
smallvec![
|
||||
attribute::ChannelDescription::new("B", SampleType::F32, true),
|
||||
attribute::ChannelDescription::new("G", SampleType::F32, true),
|
||||
attribute::ChannelDescription::new("R", SampleType::F32, true),
|
||||
attribute::ChannelDescription::new("Z", SampleType::F32, true),
|
||||
],
|
||||
);
|
||||
|
||||
// define encoding that will be written
|
||||
let mut header = header.with_encoding(
|
||||
Compression::Uncompressed,
|
||||
|
||||
exr::meta::BlockDescription::Tiles(TileDescription {
|
||||
tile_size: Vec2(64, 64),
|
||||
level_mode: LevelMode::Singular,
|
||||
rounding_mode: RoundingMode::Down
|
||||
}),
|
||||
|
||||
LineOrder::Increasing
|
||||
);
|
||||
|
||||
// add some random meta data
|
||||
header.own_attributes.exposure = Some(1.0);
|
||||
|
||||
|
||||
let headers = smallvec![ header ];
|
||||
|
||||
// specify output path, and buffer it for better performance
|
||||
let file = BufWriter::new(File::create("3GB.exr").unwrap());
|
||||
|
||||
let start_time = ::std::time::Instant::now();
|
||||
|
||||
// finally write the image
|
||||
exr::block::write(
|
||||
file, headers, true,
|
||||
|meta_data, chunk_writer|{
|
||||
|
||||
|
||||
let blocks = meta_data.collect_ordered_blocks(|block_index|{
|
||||
let channel_description = &meta_data.headers[block_index.layer].channels;
|
||||
|
||||
// fill the image file contents with one of the precomputed random values,
|
||||
// picking a different one per channel
|
||||
UncompressedBlock::from_lines(channel_description, block_index, |line_mut|{
|
||||
// TODO iterate mut instead??
|
||||
|
||||
let chan = line_mut.location.channel;
|
||||
|
||||
if chan == 3 { // write time as depth (could also check for _meta.channels[chan].name == "Z")
|
||||
line_mut.write_samples(|_| start_time.elapsed().as_secs_f32())
|
||||
.expect("write to line bug");
|
||||
}
|
||||
|
||||
else { // write rgba color
|
||||
line_mut
|
||||
.write_samples(|sample_index| random_values[(sample_index + chan) % random_values.len()])
|
||||
.expect("write to line bug");
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// print progress only if it advances more than 1%
|
||||
let mut current_progress_percentage = 0;
|
||||
|
||||
chunk_writer
|
||||
.on_progress(|progress|{
|
||||
let new_progress = (progress * 100.0) as usize;
|
||||
if new_progress != current_progress_percentage {
|
||||
current_progress_percentage = new_progress;
|
||||
println!("progress: {}%", current_progress_percentage)
|
||||
}
|
||||
})
|
||||
.compress_all_blocks_parallel(&meta_data, blocks)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
).unwrap();
|
||||
|
||||
// warning: highly unscientific benchmarks ahead!
|
||||
println!("\ncreated file 3GB.exr in {:?}s", start_time.elapsed().as_secs_f32());
|
||||
}
|
129
vendor/exr/examples/8_read_raw_blocks.rs
vendored
Normal file
129
vendor/exr/examples/8_read_raw_blocks.rs
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
|
||||
extern crate rand;
|
||||
extern crate half;
|
||||
|
||||
use std::io::{BufReader};
|
||||
use std::fs::File;
|
||||
use exr::block::reader::ChunksReader;
|
||||
|
||||
// exr imports
|
||||
extern crate exr;
|
||||
|
||||
|
||||
/// Collects the average pixel value for each channel.
|
||||
/// Does not load the whole image into memory at once: only processes the image block by block.
|
||||
/// On my machine, this program analyzes a 3GB file while only allocating 1.1MB.
|
||||
fn main() {
|
||||
use exr::prelude::*;
|
||||
|
||||
let file = BufReader::new(
|
||||
File::open("3GB.exr")
|
||||
.expect("run example `7_write_raw_blocks` to generate this image file")
|
||||
);
|
||||
|
||||
|
||||
// -- the following structs will hold the collected data from the image --
|
||||
|
||||
/// Collect averages for each layer in the image
|
||||
#[derive(Debug)]
|
||||
struct Layer {
|
||||
#[allow(unused)] // note: is used in Debug impl
|
||||
layer_name: Option<Text>,
|
||||
|
||||
data_window: IntegerBounds,
|
||||
|
||||
/// Collect one average float per channel in the layer
|
||||
channels: Vec<Channel>,
|
||||
}
|
||||
|
||||
/// A single channel in the layer, holds a single average value
|
||||
#[derive(Debug)]
|
||||
struct Channel {
|
||||
#[allow(unused)] // note: is used in Debug impl
|
||||
channel_name: Text,
|
||||
|
||||
sample_type: SampleType, // f32, u32, or f16
|
||||
average: f32,
|
||||
}
|
||||
|
||||
let start_time = ::std::time::Instant::now();
|
||||
|
||||
|
||||
// -- read the file, summing up the average pixel values --
|
||||
|
||||
// start reading the file, extracting the meta data of the image
|
||||
let reader = exr::block::read(file, true).unwrap();
|
||||
|
||||
// print progress only if it advances more than 1%
|
||||
let mut current_progress_percentage = 0;
|
||||
|
||||
// create the empty data structure that will collect the analyzed results,
|
||||
// based on the extracted meta data of the file
|
||||
let mut averages = reader.headers().iter()
|
||||
// create a layer for each header in the file
|
||||
.map(|header| Layer {
|
||||
layer_name: header.own_attributes.layer_name.clone(),
|
||||
data_window: header.data_window(),
|
||||
|
||||
// create a averaging channel for each channel in the file
|
||||
channels: header.channels.list.iter()
|
||||
.map(|channel| Channel {
|
||||
channel_name: channel.name.clone(),
|
||||
sample_type: channel.sample_type,
|
||||
average: 0.0
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// create a reader that loads only relevant chunks from the file, and also prints something on progress
|
||||
let reader = reader
|
||||
|
||||
// do not worry about multi-resolution levels or deep data
|
||||
.filter_chunks(true, |meta_data, tile, block| {
|
||||
let header = &meta_data.headers[block.layer];
|
||||
!header.deep && tile.is_largest_resolution_level()
|
||||
}).unwrap()
|
||||
|
||||
.on_progress(|progress|{
|
||||
let new_progress = (progress * 100.0) as usize;
|
||||
if new_progress != current_progress_percentage {
|
||||
current_progress_percentage = new_progress;
|
||||
println!("progress: {}%", current_progress_percentage)
|
||||
}
|
||||
});
|
||||
|
||||
// read all pixel blocks from the image, decompressing in parallel
|
||||
reader.decompress_parallel(true, |meta_data, block|{
|
||||
let header = &meta_data.headers[block.index.layer];
|
||||
|
||||
// collect all pixel values from the pixel block
|
||||
for line in block.lines(&header.channels) {
|
||||
let layer = &mut averages[line.location.layer];
|
||||
let channel = &mut layer.channels[line.location.channel];
|
||||
let channel_sample_count = layer.data_window.size.area() as f32;
|
||||
|
||||
// now sum the average based on the values in this line section of pixels
|
||||
match channel.sample_type {
|
||||
SampleType::F16 => for value in line.read_samples::<f16>() {
|
||||
channel.average += value?.to_f32() / channel_sample_count;
|
||||
},
|
||||
|
||||
SampleType::F32 => for value in line.read_samples::<f32>() {
|
||||
channel.average += value? / channel_sample_count;
|
||||
},
|
||||
|
||||
SampleType::U32 => for value in line.read_samples::<u32>() {
|
||||
channel.average += (value? as f32) / channel_sample_count;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}).unwrap();
|
||||
|
||||
println!("average values: {:#?}", averages);
|
||||
|
||||
// warning: highly unscientific benchmarks ahead!
|
||||
println!("\nprocessed file in {:?}s", start_time.elapsed().as_secs_f32());
|
||||
}
|
24
vendor/exr/examples/README.md
vendored
Normal file
24
vendor/exr/examples/README.md
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
# Examples
|
||||
|
||||
These are examples that demonstrate how to use `exrs`.
|
||||
|
||||
Some of these examples read image files
|
||||
that can be generated by running a different example beforehand.
|
||||
The examples are named such that running all examples alphabetically
|
||||
will generate any image before it is used.
|
||||
|
||||
Only the cropping examples use images from the source repository's test folder.
|
||||
|
||||
## Things you can find in the examples:
|
||||
- Read image data into a custom data structure, without loosing any meta information:
|
||||
`2_rgba_adjust_exposure`
|
||||
- Access all pixel information in a file, fully dynamic:
|
||||
`6_extract_mip_map_pngs`
|
||||
|
||||
|
||||
## Older Versions
|
||||
The examples for any specific `exrs` version can be found on the `docs.rs` page:
|
||||
- [docs.rs/crate/exr/1.71.0/source/examples/](https://docs.rs/crate/exr/1.7.0/source/examples/)
|
||||
- [docs.rs/crate/exr/1.7.0/source/examples/](https://docs.rs/crate/exr/1.7.0/source/examples/)
|
||||
- [docs.rs/crate/exr/1.6.5/source/examples/](https://docs.rs/crate/exr/1.6.5/source/examples/)
|
||||
- ...
|
Reference in New Issue
Block a user