aboutsummaryrefslogtreecommitdiff
path: root/vendor/exr/examples/8_read_raw_blocks.rs
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2024-01-08 00:21:28 +0300
committerValentin Popov <valentin@popov.link>2024-01-08 00:21:28 +0300
commit1b6a04ca5504955c571d1c97504fb45ea0befee4 (patch)
tree7579f518b23313e8a9748a88ab6173d5e030b227 /vendor/exr/examples/8_read_raw_blocks.rs
parent5ecd8cf2cba827454317368b68571df0d13d7842 (diff)
downloadfparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.tar.xz
fparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.zip
Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
Diffstat (limited to 'vendor/exr/examples/8_read_raw_blocks.rs')
-rw-r--r--vendor/exr/examples/8_read_raw_blocks.rs129
1 files changed, 129 insertions, 0 deletions
diff --git a/vendor/exr/examples/8_read_raw_blocks.rs b/vendor/exr/examples/8_read_raw_blocks.rs
new file mode 100644
index 0000000..4864c98
--- /dev/null
+++ b/vendor/exr/examples/8_read_raw_blocks.rs
@@ -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());
+} \ No newline at end of file