Git Product home page Git Product logo

openexr-rs's Introduction

OpenEXR-rs

CI Build Status Latest Release Documentation

Rust bindings for OpenEXR.

Overview

OpenEXR is a bitmap image file format that can store high dynamic range images along with other arbitrary per-pixel data. It is used heavily in the VFX and 3D animation industries.

The goal of this library is to wrap and support all features of OpenEXR 2.x. Convenient and safe API's will be provided for most functionality. However, to provide the full flexibility of the underlying C++ library, there may be a few unsafe API's as well that expose more nitty-gritty.

Building

You will need builds of OpenEXR and zlib available. You can specify the prefixes the libraries are installed to with the ILMBASE_DIR, OPENEXR_DIR, and ZLIB_DIR environment variables. Depending on how your OpenEXR was built, you may also need to set OPENEXR_LIB_SUFFIX to a value such as "2_2". If an _DIR variable is unset, pkgconfig will be used to try to find the corresponding library automatically.

Status

This library has been tested on Linux and Windows. Basic I/O is supported, including reading from memory.

TODO

  • Wrap scanline output.
  • Wrap generic input.
  • Support for Half floats.
  • Handle exceptions at the API boundary (safety!).
  • Wrap custom attributes.
  • Wrap tiled output.
  • Wrap tiled input.
  • Handle different tiled modes (e.g. MIP maps and RIP maps).
  • Wrap deep data input/output.
  • Wrap multi-part file input/output.
  • Make simple convenience functions for basic RGB/RGBA input and output.
  • Make build system more robust to various platforms and configurations.

License

OpenEXR-rs is distributed under the terms of the MIT license (see LICENSE for details). The code for OpenEXR itself is distributed under the terms of a modified BSD license (see http://www.openexr.com/license.html for details). zlib is distributed under the terms of the zlib license (see http://zlib.net/zlib_license.html for details).

openexr-rs's People

Contributors

calebsmith avatar cessen avatar norru avatar ralith avatar twinklebear avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

openexr-rs's Issues

Figure out a decent first draft API.

I'd like to take some time to play with API ideas, to see if we can come up with something better than we currently have, and also account for supporting the various features of OpenEXR.

I don't expect to figure out a final 1.0 API or anything, but rather a first draft that we can implement and use for a while to get more experience for the next iteration.

Some notes of my own below.

Using the builder pattern, pros and cons

For OutputFile I'm currently using a builder pattern, so creating a file and writing to it looks something like this:

let mut fb = {
    // Create the frame buffer ...
};

OutputFile::new()
    .resolution(256, 256)
    .channel("R", PixelType::FLOAT)
    .channel("G", PixelType::FLOAT)
    .channel("B", PixelType::FLOAT)
    .open(Path::new("/path/to/file.exr"))
    .unwrap();
    .write_pixels(&mut fb).unwrap();

This seems to make sense, because there are a lot of things that can potentially be specified about the file (but which mostly have obvious defaults), and due to OpenEXR's C++ API they all need to be specified before actually opening the file for writing. It's also convenient for creating an OutputFile inline somewhere.

However, a weakness of this is, for example, that if you have an array of channels already, the builder pattern actually makes it a bit more awkward. Instead of something like this:

let mut out = OutputFile::new().resolution(256, 256);
for (name, pixel_type) in channel_vec.iter() {
    out.add_channel(name, pixel_type);
}
// ...

You have to do this:

let mut out = OutputFile::new().resolution(256, 256);
for (name, pixel_type) in channel_vec.iter() {
    out = out.channel(name, pixel_type);
}
// ...

OutputFile::new()
.resolution(256, 256)

That isn't awful, but it does IMO read a bit strange with the out = out.whatever() in the loop.

Supporting different InputFile and OutputFile types

OpenEXR supports scanline files, tiled files, multi-part files, and deep files and all the permutations thereof. For simple input/output this isn't too much of a concern, and I would like to make sure there are simple API's for cases where people just don't care. But first I want to make sure we wrap all of the lower-level functionality well, and then we can build on top of that later for simpler use-cases.

For output, my current idea is to have multiple different *Writer types that you can get from *_open() calls. So, for example, if you want a create a tiled file you would do:

let mut out: TiledWriter = OutputFile::new()
    .resolution(256, 256)
    // ...
    .open_tiled(Path::new("/path/to/file.exr"));

And for a tiled and multi-part file:

let mut out: TiledMultiPartWriter = OutputFile::new()
    .resolution(256, 256)
    // ...
    .open_tiled_multipart(Path::new("/path/to/file.exr"));

Etc.

This would correspond closely to the various *OutputFile types in the C++ API, and would allow us to present a tailer-made API for each output type (e.g. writing tiles to a tiled file).

For InputFile I'm thinking we could do something similar by returning an enum of possible *Reader types.

Accessing InputFile's channels

To properly read an input file, it should either be verified that the expected channels exist in it and are of the right type, or the channels that do exist should be used to build the frame buffer. This requires accessing the channel descriptors.

So far all I've implemented for that is an iterator API:

let input = // Get input file
for (name, channel) in input.channels() {
    println!("{} {:#?}", name, channel);
}

But that is unlikely to cut it on its own. Some kind of direct access would probably be good:

let channel_descriptor = input.get_channel("R").unwrap();

Custom Attributes

OpenEXR files support custom attributes to be written to and read from exr files. I haven't investigated the API closely enough to know exactly how they work (e.g. what types are supported, if it's extensible, etc.). But at first blush, I think using an API similar to what we have for channels would be good:

OutputFile::new()
    .resolution(256, 256)
    .attribute("attribute_name_1", /* some way of specifying an attribute value */)
    .attribute("attribute_name_2", /* some way of specifying an attribute value */)
    // ...

let input = // Get input file
for (name, attribute) in input.attributes() {
    println!("{} {:#?}", name, attribute);
}

let attribute_value = input.get_attribute("attribute_name_1").unwrap();

Unresolved import

Hi there,

First of all, thank you for this wrapper. I am trying to use it following your examples but I am getting:

error[E0432]: unresolved import `openexr::Header`
  --> src/main.rs:15:28
   |
15 | use openexr::{FrameBuffer, Header, ScanlineOutputFile, PixelType};
   |                            ^^^^^^ no `Header` in the root

error[E0432]: unresolved import `openexr::ScanlineOutputFile`
  --> src/main.rs:15:36
   |
15 | use openexr::{FrameBuffer, Header, ScanlineOutputFile, PixelType};
   |                                    ^^^^^^^^^^^^^^^^^^ no `ScanlineOutputFile` in the root

For some reason it can find FrameBuffer and PixelType though. Any ideas why this is happening would be really appreciated. Thanks!

Suspicious lifetime of C++ exception messages

I've just spotted the following pattern in many functions:

int CEXR_InputFile_from_stream(CEXR_IStream *stream, int threads, CEXR_InputFile **out, const char **err_out) {
    try {
        *out = reinterpret_cast<CEXR_InputFile *>(new InputFile(*reinterpret_cast<IStream *>(stream), threads));
    } catch(const std::exception &e) {
        *err_out = e.what();
        return 1;
    }

    return 0;
}

At the call site:

        let mut error_out = ptr::null();
        let error = unsafe { CEXR_InputFile_from_stream(istream_ptr, 1, &mut out, &mut error_out) };
        if error != 0 {
            let msg = unsafe { CStr::from_ptr(error_out) };
            Err(Error::Generic(msg.to_string_lossy().into_owned()))
        } else {
...

It looks highly suspicious as the string pointed by error_out at the point of use is outside its "owner's" lifetime (the exception object).

The original exception object should be destroyed at the exit of the catch block, making the pointer coming out of it a dangling reference.

I wonder how this Could Have Possibly Ever Worked™. Am I missing something? I hope I am wrong here because, otherwise, the security implications would be huge.

Move from Travis CI to Github Actions

Travis CI will no longer be offering free CI to open source projects, so we need to move to something else.

I've made an initial attempt. It seems to work for running cargo build, but when running cargo test there is a linker error.

IStream / OStream API

Let's try to make OpenEXR play more nicely with the Rust I/O story.

The Rust standard library has the Read, Write, and Seek traits. I'm thinking that we can change our *InputFile and *OutputFile types to take anything that implement the Read+Seek and Write+Seek respectively.

We can also still provide convenience functions for just giving a file path.

Finally, we have a way to read OpenEXR data from memory, but not a way to write to memory. Reading from memory takes a slice, which makes sense. But writing will require the ability to grow the data. So maybe writing to memory takes a &mut Vec?

Error using compiling mac osx

Hey,

I tried to use your library in one of my projects. I used openexr installed via homebrew and got a compile error. Could you help me?

error: failed to run custom build command for `openexr-sys v0.5.0`
process didn't exit successfully: `/Users/stijndehaes/rust/ray-tracer/target/debug/build/openexr-sys-e8532d8c35689436/build-script-build` (exit code: 101)
--- stdout
cargo:rustc-link-search=native=/usr/local/Cellar/openexr/2.2.1_1/lib
cargo:rustc-link-search=native=/usr/local/Cellar/ilmbase/2.2.1/lib
cargo:rustc-link-lib=IlmImf
cargo:rustc-link-lib=Imath
cargo:rustc-link-lib=Half
cargo:rustc-link-lib=Iex
cargo:rustc-link-lib=IexMath
cargo:rustc-link-lib=IlmThread
cargo:rustc-link-search=native=/usr/lib
cargo:rustc-link-lib=z
TARGET = Some("x86_64-apple-darwin")
OPT_LEVEL = Some("3")
TARGET = Some("x86_64-apple-darwin")
HOST = Some("x86_64-apple-darwin")
TARGET = Some("x86_64-apple-darwin")
TARGET = Some("x86_64-apple-darwin")
HOST = Some("x86_64-apple-darwin")
CXX_x86_64-apple-darwin = None
CXX_x86_64_apple_darwin = None
HOST_CXX = None
CXX = None
HOST = Some("x86_64-apple-darwin")
TARGET = Some("x86_64-apple-darwin")
HOST = Some("x86_64-apple-darwin")
CXXFLAGS_x86_64-apple-darwin = None
CXXFLAGS_x86_64_apple_darwin = None
HOST_CXXFLAGS = None
CXXFLAGS = None
DEBUG = Some("true")
running: "c++" "-O3" "-ffunction-sections" "-fdata-sections" "-fPIC" "-g" "-m64" "-I" "c_wrapper" "-I" "/usr/local/Cellar/openexr/2.2.1_1/include/OpenEXR" "-I" "/usr/local/Cellar/ilmbase/2.2.1/include/OpenEXR" "-I" "/usr/local/Cellar/ilmbase/2.2.1/include/OpenEXR" "-std=c++0x" "-Wall" "-Wextra" "-o" "/Users/stijndehaes/rust/ray-tracer/target/debug/build/openexr-sys-830ad403a950ee27/out/c_wrapper/cexr.o" "-c" "c_wrapper/cexr.cpp"
cargo:warning=In file included from c_wrapper/cexr.cpp:11:
cargo:warning=In file included from /usr/local/Cellar/openexr/2.2.1_1/include/OpenEXR/ImfOutputFile.h:49:
cargo:warning=In file included from /usr/local/Cellar/openexr/2.2.1_1/include/OpenEXR/ImfGenericOutputFile.h:40:
cargo:warning=In file included from /usr/local/Cellar/openexr/2.2.1_1/include/OpenEXR/ImfXdr.h:108:
cargo:warning=/usr/local/Cellar/ilmbase/2.2.1/include/OpenEXR/half.h:462:2: warning: 'register' storage class specifier is deprecated and incompatible with C++17 [-Wdeprecated-register]
cargo:warning=        register int e = (x.i >> 23) & 0x000001ff;
cargo:warning=        ^~~~~~~~~
cargo:warning=/usr/local/Cellar/ilmbase/2.2.1/include/OpenEXR/half.h:473:6: warning: 'register' storage class specifier is deprecated and incompatible with C++17 [-Wdeprecated-register]
cargo:warning=            register int m = x.i & 0x007fffff;
cargo:warning=            ^~~~~~~~~
cargo:warning=In file included from c_wrapper/cexr.cpp:16:
cargo:warning=c_wrapper/rust_istream.hpp:26:19: error: virtual function 'tellg' has a different return type ('std::uint64_t' (aka 'unsigned long long')) than the function it overrides (which has return type 'Imath_2_2::Int64' (aka 'unsigned long'))
cargo:warning=    std::uint64_t tellg();
cargo:warning=    ~~~~~~~~~~~~~ ^
cargo:warning=/usr/local/Cellar/openexr/2.2.1_1/include/OpenEXR/ImfIO.h:114:19: note: overridden virtual function is here
cargo:warning=    virtual Int64       tellg () = 0;
cargo:warning=            ~~~~~       ^
cargo:warning=In file included from c_wrapper/cexr.cpp:16:
cargo:warning=c_wrapper/rust_istream.hpp:27:10: warning: 'RustIStream::seekg' hides overloaded virtual function [-Woverloaded-virtual]
cargo:warning=    void seekg(std::uint64_t pos);
cargo:warning=         ^
cargo:warning=/usr/local/Cellar/openexr/2.2.1_1/include/OpenEXR/ImfIO.h:122:18: note: hidden overloaded virtual function 'Imf_2_2::IStream::seekg' declared here: type mismatch at 1st parameter ('Imath_2_2::Int64' (aka 'unsigned long') vs 'std::uint64_t' (aka 'unsigned long long'))
cargo:warning=    virtual void        seekg (Int64 pos) = 0;
cargo:warning=                        ^
cargo:warning=In file included from c_wrapper/cexr.cpp:17:
cargo:warning=c_wrapper/rust_ostream.hpp:25:27: error: virtual function 'tellp' has a different return type ('std::uint64_t' (aka 'unsigned long long')) than the function it overrides (which has return type 'Imath_2_2::Int64' (aka 'unsigned long'))
cargo:warning=    virtual std::uint64_t tellp ();
cargo:warning=            ~~~~~~~~~~~~~ ^
cargo:warning=/usr/local/Cellar/openexr/2.2.1_1/include/OpenEXR/ImfIO.h:184:19: note: overridden virtual function is here
cargo:warning=    virtual Int64       tellp () = 0;
cargo:warning=            ~~~~~       ^
cargo:warning=In file included from c_wrapper/cexr.cpp:17:
cargo:warning=c_wrapper/rust_ostream.hpp:26:18: warning: 'RustOStream::seekp' hides overloaded virtual function [-Woverloaded-virtual]
cargo:warning=    virtual void seekp (std::uint64_t pos);
cargo:warning=                 ^
cargo:warning=/usr/local/Cellar/openexr/2.2.1_1/include/OpenEXR/ImfIO.h:192:18: note: hidden overloaded virtual function 'Imf_2_2::OStream::seekp' declared here: type mismatch at 1st parameter ('Imath_2_2::Int64' (aka 'unsigned long') vs 'std::uint64_t' (aka 'unsigned long long'))
cargo:warning=    virtual void        seekp (Int64 pos) = 0;
cargo:warning=                        ^
cargo:warning=c_wrapper/cexr.cpp:33:53: error: allocating an object of abstract class type 'RustIStream'
cargo:warning=        *out = reinterpret_cast<CEXR_IStream *>(new RustIStream(reader, read_ptr, seekp_ptr));
cargo:warning=                                                    ^
cargo:warning=/usr/local/Cellar/openexr/2.2.1_1/include/OpenEXR/ImfIO.h:122:18: note: unimplemented pure virtual method 'seekg' in 'RustIStream'
cargo:warning=    virtual void        seekg (Int64 pos) = 0;
cargo:warning=                        ^
cargo:warning=c_wrapper/cexr.cpp:58:53: error: allocating an object of abstract class type 'RustOStream'
cargo:warning=        *out = reinterpret_cast<CEXR_OStream *>(new RustOStream(writer, write_ptr, seekp_ptr));
cargo:warning=                                                    ^
cargo:warning=/usr/local/Cellar/openexr/2.2.1_1/include/OpenEXR/ImfIO.h:192:18: note: unimplemented pure virtual method 'seekp' in 'RustOStream'
cargo:warning=    virtual void        seekp (Int64 pos) = 0;
cargo:warning=                        ^
cargo:warning=4 warnings and 4 errors generated.
exit code: 1

--- stderr
thread 'main' panicked at '

Internal error occurred: Command "c++" "-O3" "-ffunction-sections" "-fdata-sections" "-fPIC" "-g" "-m64" "-I" "c_wrapper" "-I" "/usr/local/Cellar/openexr/2.2.1_1/include/OpenEXR" "-I" "/usr/local/Cellar/ilmbase/2.2.1/include/OpenEXR" "-I" "/usr/local/Cellar/ilmbase/2.2.1/include/OpenEXR" "-std=c++0x" "-Wall" "-Wextra" "-o" "/Users/stijndehaes/rust/ray-tracer/target/debug/build/openexr-sys-830ad403a950ee27/out/c_wrapper/cexr.o" "-c" "c_wrapper/cexr.cpp" with args "c++" did not execute successfully (status code exit code: 1).

', /Users/stijndehaes/.cargo/registry/src/github.com-1ecc6299db9ec823/gcc-0.3.54/src/lib.rs:1670:5
stack backtrace:
   0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
             at libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
   1: std::sys_common::backtrace::_print
             at libstd/sys_common/backtrace.rs:71
   2: std::panicking::default_hook::{{closure}}
             at libstd/sys_common/backtrace.rs:59
             at libstd/panicking.rs:380
   3: std::panicking::default_hook
             at libstd/panicking.rs:396
   4: std::panicking::begin_panic
             at libstd/panicking.rs:576
   5: std::panicking::begin_panic
             at libstd/panicking.rs:537
   6: std::panicking::try::do_call
             at libstd/panicking.rs:521
   7: gcc::fail
             at /Users/stijndehaes/.cargo/registry/src/github.com-1ecc6299db9ec823/gcc-0.3.54/src/lib.rs:1670
   8: <alloc::heap::Heap as alloc::allocator::Alloc>::oom
             at /Users/stijndehaes/.cargo/registry/src/github.com-1ecc6299db9ec823/gcc-0.3.54/src/lib.rs:783
   9: build_script_build::main
             at ./build.rs:88
  10: std::rt::lang_start::{{closure}}
             at /Users/travis/build/rust-lang/rust/src/libstd/rt.rs:74
  11: std::panicking::try::do_call
             at libstd/rt.rs:59
             at libstd/panicking.rs:479
  12: panic_unwind::dwarf::eh::read_encoded_pointer
             at libpanic_unwind/lib.rs:102
  13: rust_panic
             at libstd/panicking.rs:458
             at libstd/panic.rs:358
             at libstd/rt.rs:58
  14: build_script_build::main


Process finished with exit code 101

Crash on Windows 10 when calling fb.insert_channels

Compiles successfully, but can't get a minimal example going. Same result using 0.5.0 and master, stable-1.8 and nightly-1.9, msvc.

I don't know C++ / haven't used openexr before, so it's possible I installed the libraries wrong. I did have to rename all the dlls to append the -2_2 suffix. They are compiled using Windows C++ 2015 Build Tools.

Running the memory_io test through windbg

*** WARNING: Unable to verify checksum for C:\thirdparty\vs2015\x64\openexr-2.2.0\deploy\lib\IlmImf-2_2.dll
IlmImf_2_2!std::_Tree<std::_Tmap_traits<Imf_2_2::Name,Imf_2_2::Slice,std::less<Imf_2_2::Name>,std::allocator<std::pair<Imf_2_2::Name const ,Imf_2_2::Slice> >,0> >::_Lbound<Imf_2_2::Name>+0x2d:
00007ffe`7000086d 488b00          mov     rax,qwAord ptr [rax] ds:00000000`00000008=????????????????
0:004> k
 # Child-SP          RetAddr           Call Site
00 0000000d`ba3fe1d0 00007ffe`7000244e IlmImf_2_2!std::_Tree<std::_Tmap_traits<Imf_2_2::Name,Imf_2_2::Slice,std::less<Imf_2_2::Name>,std::allocator<std::pair<Imf_2_2::Name const ,Imf_2_2::Slice> >,0> >::_Lbound<Imf_2_2::Name>+0x2d [c:\program files (x86)\microsoft visual studio\shared\14.0\vc\include\xtree @ 2060]
01 0000000d`ba3fe210 00007ffe`7000098f IlmImf_2_2!std::_Tree<std::_Tmap_traits<Imf_2_2::Name,Imf_2_2::Slice,std::less<Imf_2_2::Name>,std::allocator<std::pair<Imf_2_2::Name const ,Imf_2_2::Slice> >,0> >::lower_bound+0x4e [c:\program files (x86)\microsoft visual studio\shared\14.0\vc\include\xtree @ 1538]
02 0000000d`ba3fe250 00007ffe`7000113c IlmImf_2_2!std::map<Imf_2_2::Name,Imf_2_2::Slice,std::less<Imf_2_2::Name>,std::allocator<std::pair<Imf_2_2::Name const ,Imf_2_2::Slice> > >::_Try_emplace<Imf_2_2::Name>+0x5f [c:\program files (x86)\microsoft visual studio\shared\14.0\vc\include\map @ 209]
03 0000000d`ba3fe370 00007ffe`700014d8 IlmImf_2_2!std::map<Imf_2_2::Name,Imf_2_2::Slice,std::less<Imf_2_2::Name>,std::allocator<std::pair<Imf_2_2::Name const ,Imf_2_2::Slice> > >::try_emplace<>+0x4c [c:\program files (x86)\microsoft visual studio\shared\14.0\vc\include\map @ 244]
04 0000000d`ba3fe3b0 00007ffe`6fffcb1c IlmImf_2_2!std::map<Imf_2_2::Name,Imf_2_2::Slice,std::less<Imf_2_2::Name>,std::allocator<std::pair<Imf_2_2::Name const ,Imf_2_2::Slice> > >::operator[]+0x48 [c:\program files (x86)\microsoft visual studio\shared\14.0\vc\include\map @ 178]
*** WARNING: Unable to verify checksum for memory_io-a1d6b46d4a337528.exe
05 0000000d`ba3fe420 00007ff6`2d80af04 IlmImf_2_2!Imf_2_2::FrameBuffer::insert+0x12c [c:\thirdparty\vs2015\x64\openexr-2.2.0\openexr\ilmimf\imfframebuffer.cpp @ 87]
06 0000000d`ba3fe710 00007ff6`2d79c83a memory_io_a1d6b46d4a337528!CEXR_FrameBuffer_insert+0xc4 [c:\users\dylan\code\openexr-rs\openexr-sys\c_wrapper\cexr.cpp @ 214]
07 0000000d`ba3fe7b0 00007ff6`2d796a6f memory_io_a1d6b46d4a337528!openexr::frame_buffer::FrameBuffer::insert_raw+0x20a [C:\Users\dylan\code\openexr-rs\src\frame_buffer.rs @ 145]
08 0000000d`ba3fe980 00007ff6`2d79890a memory_io_a1d6b46d4a337528!openexr::frame_buffer::FrameBuffer::insert_channels<(f32, f32, f32)>+0x4ff [C:\Users\dylan\code\openexr-rs\src\frame_buffer.rs @ 115]
09 0000000d`ba3fed30 00007ff6`2d7b2c1b memory_io_a1d6b46d4a337528!memory_io::memory_io+0x1da [C:\Users\dylan\code\openexr-rs\tests\memory_io.rs @ 25]
0a 0000000d`ba3ff220 00007ff6`2d7fdbc2 memory_io_a1d6b46d4a337528!test::{{impl}}::call_box<(),closure>+0x1b [C:\projects\rust\src\libtest\lib.rs @ 140]
0b 0000000d`ba3ff260 00007ff6`2d7a1dad memory_io_a1d6b46d4a337528!panic_unwind::__rust_maybe_catch_panic+0x22 [C:\projects\rust\src\libpanic_unwind\lib.rs @ 98]
0c 0000000d`ba3ff2c0 00007ff6`2d7fdbc2 memory_io_a1d6b46d4a337528!std::panicking::try::do_call<std::panic::AssertUnwindSafe<closure>,()>+0x1dd [C:\projects\rust\src\libstd\panicking.rs @ 450]
0d 0000000d`ba3ff950 00007ff6`2d7ac15f memory_io_a1d6b46d4a337528!panic_unwind::__rust_maybe_catch_panic+0x22 [C:\projects\rust\src\libpanic_unwind\lib.rs @ 98]
0e 0000000d`ba3ff9b0 00007ff6`2d7fafbf memory_io_a1d6b46d4a337528!alloc::boxed::{{impl}}::call_box<(),closure>+0x12f [C:\projects\rust\src\liballoc\boxed.rs @ 640]
0f 0000000d`ba3ffb60 00007ffe`c5628364 memory_io_a1d6b46d4a337528!std::sys::imp::thread::{{impl}}::new::thread_start+0x7f [C:\projects\rust\src\libstd\sys\windows\thread.rs @ 50]
10 0000000d`ba3ffbc0 00007ffe`c5fc70d1 KERNEL32!BaseThreadInitThunk+0x14
11 0000000d`ba3ffbf0 00000000`00000000 ntdll!RtlUserThreadStart+0x21

forget() self in OutputFile::open()

Making this issue as a note so I remember to do this later. I just realized that in OutputFile::open() the consumed self will get dropped, freeing the header. But the header is passed to the EXRWriter. Fix!

ILMBASE_DIR in Windows

What is Ilmbase and how can I get the binaries for it for windows? I can't compile it in windows.

Documentation fails to build on docs.rs

The docs.rs servers don't have any version of the C++ OpenEXR library installed, so building openexr-rs always fails, preventing our docs from being published there.

I recently looked into that, and according to the documentation on their site they provide an environment variable, DOCS_RS, that you can use in build scripts for situations just like this. In our case, we can use it to conditionally disable all of our C/C++ build steps in openexr-sys, which allows openexr-rs to "succeed" at building without the C++ OpenEXR library present, even though it would fail if you actually tried to link it into anything.

I've made precisely that change in commit dba20d8, which should allow documentation generation to succeed on docs.rs from now on. However, I don't want to cut a new release just for documentation generation, so I'm opening this issue so that there's visibility on this situation until the next release.

FrameBuffer can't read immutable pixel data

Because FrameBuffer is used by both input and output code, it takes mutable references to pixel storage, but this is excessively strict for many use-cases.

This could be addressed by making FrameBuffer a trait and providing both mutable and immutable versions, with output code taking a generic T: FrameBuffer and input code taking only a concrete FrameBufferMut. Both mutable and immutable versions would be very thin wrappers around an unsafe (and perhaps unexported) common object that contains the C API wrangling.

Alternatively, mutability could be stored per-channel and safety checked at runtime a la RefCell, but this strikes me as less desirable.

Support multi-threaded I/O

First of all, thank you for this crate! I've been using it in my project (https://github.com/abusch/rustracer) with great success. 👍

I'm not super familiar with OpenEXR but I've noticed it supports multi-threaded I/O by using its own worker thread pool. You configure it by calling setGlobalThreadCount(). Would it make sense to expose this function? I tried to give it a shot myself to see if it would work, but somehow I can't compile openexr-rs... I'm getting the following:

error[E0433]: failed to resolve. Could not find `Build` in `gcc`
  --> openexr-sys/build.rs:79:24
   |
79 |     let mut gcc = gcc::Build::new();
   |                        ^^^^^ Could not find `Build` in `gcc`
error: aborting due to previous error
error: Could not compile `openexr-sys`.

PKG_CONFIG_PATH issue on Debian

I was trying to build OpenEXR v2.3.0 on Debian 10,

If we build OpenEXR(Version <= 2.5.2) from source, then it will name the pkg config file as "Ilmbase.pc" instead of "OpenEXR.pc"
Thus when we build the project, it will run into the following issue:

--- stderr
  thread 'main' panicked at 'couldn't find OpenEXR: environment variable OPENEXR_DIR is unset and pkg-config failed: `"pkg-config" "--libs" "--cflags" "OpenEXR" "OpenEXR >= 2.0.0"` did not exit successfully: exit code: 1
  --- stderr
  Package OpenEXR was not found in the pkg-config search path.
  Perhaps you should add the directory containing `OpenEXR.pc'
  to the PKG_CONFIG_PATH environment variable
  No package 'OpenEXR' found
  Package OpenEXR was not found in the pkg-config search path.
  Perhaps you should add the directory containing `OpenEXR.pc'
  to the PKG_CONFIG_PATH environment variable

The changelog of OpenEXR is here: https://github.com/AcademySoftwareFoundation/openexr/releases/tag/v2.5.2

Can we make some changes to mitigate this issue?

Is it time to release 0.7.0 to crates.io?

I am currently linking openexr-rs from GitHub repositories as they contain latest updates.

Since 0.6.0 there have been significant changes:

  • data window fixes (crash bug)
  • exception message management fixes (crash/corruption bug)
  • set_global_thread_count() (enhancement)
  • set_multiview() (enhancement)

For consistency I would be happier to use crates.io repo instead.

Can't compile on macOS (zlib issue)

I am attempting to build on macOS 10.14.4. I get this:

error: could not find native static library zlibstatic, perhaps an -L flag is missing?

I seem to be unable to make it happy about zlib, trying both the system zlib and zlib installed through homebrew. It seems to be looking for zlibstatic, not sure if there is a naming issue here.

OpenEXR and ILMbase seem to be working fine.

Support tiled read

I am reading EXR files containing depth data from a third party software which uses tiled formats, whose output is not customizable in any way.

In fact, what I am currently trying to do is to read the files generated by this software and, among other things, convert them to scanline images.

I cannot think of alternative options except using direct native calls (or even a different programming languages).

file format version: 2, flags 0x200
channels (type chlist):
    Z, 32-bit floating-point, sampling 1 1
compression (type compression): pxr24
dataWindow (type box2i): (0 0) - (1919 1279)
displayWindow (type box2i): (0 0) - (1919 1279)
exif (type blob)
lineOrder (type lineOrder): increasing y
pixelAspectRatio (type float): 1
screenWindowCenter (type v2f): (0 0)
screenWindowWidth (type float): 1
tiles (type tiledesc):
    single level
    tile size 128 by 128 pixels
type (type string): "tiledimage"

I am not concerned about generating tiled images, just reading from them.

I am not concerned about MIPs and RIPs.

Include IlmImf and Zlib sources in openexr-sys if possible

Including library sources when licenses allow in -sys packages makes -sys packages a lot more convenient to use. As far as I can tell, the Zlib license and modified BSD license are both compatible with the MIT license.

IlmImf alone nearly breaks the normal 10MB limit for crates.io, but supposedly you can ask to have a higher limit for a specific crate if necessary, up to 50MB rust-lang/crates.io#40.

Undefined `uninitialized` behaviour panic on nightly since 1.49.0

I got 100% panic since upgrading nightly to 1.49.0. This causes 100% crash when writing images.

Update: reproduced in rust 1.51.0-nightly

This needs looking into as it kind of makes the library completely unusable on newer versions of rustc

rustc 1.49.0-nightly (31530e5d1 2020-10-20)

rust-lang/rust#73573

nico@devuan-3xS:~/Projects/3rdParty/openexr-rs$ RUST_BACKTRACE=1 cargo test
warning: use of deprecated function `std::mem::uninitialized`: use `mem::MaybeUninit` instead
   --> src/frame_buffer.rs:215:36
    |
215 |         let mut channel = unsafe { mem::uninitialized() };
    |                                    ^^^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(deprecated)]` on by default

warning: use of deprecated function `std::mem::uninitialized`: use `mem::MaybeUninit` instead
   --> src/header.rs:356:33
    |
356 |         let mut name = unsafe { std::mem::uninitialized() };
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^

warning: use of deprecated function `std::mem::uninitialized`: use `mem::MaybeUninit` instead
   --> src/header.rs:357:36
    |
357 |         let mut channel = unsafe { std::mem::uninitialized() };
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^

warning: the type `CEXR_Channel` does not permit being left uninitialized
   --> src/frame_buffer.rs:215:36
    |
215 |         let mut channel = unsafe { mem::uninitialized() };
    |                                    ^^^^^^^^^^^^^^^^^^^^
    |                                    |
    |                                    this code causes undefined behavior when executed
    |                                    help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
    = note: `#[warn(invalid_value)]` on by default
note: enums have to be initialized to a variant
   --> /home/nico/Projects/3rdParty/openexr-rs/openexr-sys/src/bindings.rs:105:1
    |
105 | pub enum CEXR_PixelType { UINT = 0, HALF = 1, FLOAT = 2, }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

warning: the type `CEXR_Channel` does not permit being left uninitialized
   --> src/header.rs:357:36
    |
357 |         let mut channel = unsafe { std::mem::uninitialized() };
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^
    |                                    |
    |                                    this code causes undefined behavior when executed
    |                                    help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
note: enums have to be initialized to a variant
   --> /home/nico/Projects/3rdParty/openexr-rs/openexr-sys/src/bindings.rs:105:1
    |
105 | pub enum CEXR_PixelType { UINT = 0, HALF = 1, FLOAT = 2, }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

warning: 5 warnings emitted

warning: use of deprecated function `std::mem::uninitialized`: use `mem::MaybeUninit` instead
   --> src/frame_buffer.rs:215:36
    |
215 |         let mut channel = unsafe { mem::uninitialized() };
    |                                    ^^^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(deprecated)]` on by default

warning: use of deprecated function `std::mem::uninitialized`: use `mem::MaybeUninit` instead
   --> src/header.rs:356:33
    |
356 |         let mut name = unsafe { std::mem::uninitialized() };
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^

warning: use of deprecated function `std::mem::uninitialized`: use `mem::MaybeUninit` instead
   --> src/header.rs:357:36
    |
357 |         let mut channel = unsafe { std::mem::uninitialized() };
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^

warning: the type `CEXR_Channel` does not permit being left uninitialized
   --> src/frame_buffer.rs:215:36
    |
215 |         let mut channel = unsafe { mem::uninitialized() };
    |                                    ^^^^^^^^^^^^^^^^^^^^
    |                                    |
    |                                    this code causes undefined behavior when executed
    |                                    help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
    = note: `#[warn(invalid_value)]` on by default
note: enums have to be initialized to a variant
   --> /home/nico/Projects/3rdParty/openexr-rs/openexr-sys/src/bindings.rs:105:1
    |
105 | pub enum CEXR_PixelType { UINT = 0, HALF = 1, FLOAT = 2, }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

warning: the type `CEXR_Channel` does not permit being left uninitialized
   --> src/header.rs:357:36
    |
357 |         let mut channel = unsafe { std::mem::uninitialized() };
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^
    |                                    |
    |                                    this code causes undefined behavior when executed
    |                                    help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
note: enums have to be initialized to a variant
   --> /home/nico/Projects/3rdParty/openexr-rs/openexr-sys/src/bindings.rs:105:1
    |
105 | pub enum CEXR_PixelType { UINT = 0, HALF = 1, FLOAT = 2, }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

warning: 5 warnings emitted

    Finished test [unoptimized + debuginfo] target(s) in 0.01s
     Running target/debug/deps/openexr-820bdf9eb2e33d8f

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

     Running target/debug/deps/incremental_io-df68b4539a48d82c

running 1 test
test incremental_io ... FAILED

failures:

---- incremental_io stdout ----
thread 'incremental_io' panicked at 'attempted to leave type `openexr_sys::CEXR_Channel` uninitialized, which is invalid', /home/nico/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/mem/mod.rs:659:9
stack backtrace:
   0: rust_begin_unwind
             at /rustc/158f8d034b15e65ba8dc0d066358dd0632bfcd6e/library/std/src/panicking.rs:493:5
   1: core::panicking::panic_fmt
             at /rustc/158f8d034b15e65ba8dc0d066358dd0632bfcd6e/library/core/src/panicking.rs:92:14
   2: core::panicking::panic
             at /rustc/158f8d034b15e65ba8dc0d066358dd0632bfcd6e/library/core/src/panicking.rs:50:5
   3: core::mem::uninitialized
             at /home/nico/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/mem/mod.rs:659:9
   4: <openexr::header::ChannelIter as core::iter::traits::iterator::Iterator>::next
             at ./src/header.rs:357:36
   5: openexr::header::Header::validate_framebuffer_for_output
             at ./src/header.rs:262:21
   6: openexr::output::scanline_output_file::ScanlineOutputFile::write_pixels_incremental
             at ./src/output/scanline_output_file.rs:244:9
   7: incremental_io::incremental_io
             at ./tests/incremental_io.rs:27:9
   8: incremental_io::incremental_io::{{closure}}
             at ./tests/incremental_io.rs:8:1
   9: core::ops::function::FnOnce::call_once
             at /home/nico/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:227:5
  10: core::ops::function::FnOnce::call_once
             at /rustc/158f8d034b15e65ba8dc0d066358dd0632bfcd6e/library/core/src/ops/function.rs:227:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.


failures:
    incremental_io

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s

error: test failed, to rerun pass '--test incremental_io'

stable rustc 1.47.0 does not trigger the panic.

SIGSEGV in CEXR_InputFile_read_pixels if data_window bounds < 0

I am attempting to load an image, saved by Nuke, whose data_window origin has negative x and y, but I get a 100% SIGSEGV crash (Ubuntu).

		// exr_file: &mut InputFile, loads from an .exr image whose x1,y1 < 0,0

		let (width, height) = exr_file.header().data_dimensions();
		let zero = f16::from_f32(0.0f32);
		println!("Reading pixels from {},{},{}", r_chan, g_chan, b_chan);
		let mut pixel_data = vec![(zero, zero, zero); (width * height) as usize];
		{
			let mut fb = FrameBufferMut::new(width, height);
			println!("Loading buffer as {}x{}", width, height);
			fb.insert_channels(
				&[(r_chan, 0.0), (g_chan, 0.0), (b_chan, 0.0)],
				&mut pixel_data,
			);
			exr_file
				.read_pixels(&mut fb) // crashes here 
				.map_err(|e| io::Error::new(io::ErrorKind::NotFound, e))?;
		}

call [stack:](url

)

0x7ffff798e84a
IlmThread_2_2::ThreadPool::addTask() at 0x7ffff03e927f
Imf_2_2::ScanLineInputFile::readPixels() at 0x7ffff799027a
Imf_2_2::InputFile::readPixels() at 0x7ffff795f8c1
CEXR_InputFile_read_pixels() at cexr.cpp:311 0x55555576eb81

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.