aboutsummaryrefslogtreecommitdiff
path: root/vendor/exr/examples/7_write_raw_blocks.rs
blob: 4cb2646c6a940be852aefc7a4b5d9c9a093697cb (plain) (blame)
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
#[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());
}