Reading, writing, and processing images in a wide variety of file formats, using a format-agnostic API, aimed at VFX applications.

README for OpenImageIO

License Build Status Windows Build Status CII Best Practices

Introduction

The primary target audience for OIIO is VFX studios and developers of tools such as renderers, compositors, viewers, and other image-related software you'd find in a production pipeline.

OpenImageIO consists of:

  • Simple but powerful ImageInput and ImageOutput APIs that provide an abstraction for reading and writing image files of nearly any format, without the calling application needing to know any of the details of these file formats, and indeed without the calling application needing to be aware of which formats are available.

  • A library that manages subclasses of ImageInput and ImageOutput that implement I/O from specific file formats, with each file format's implementation stored as a plug-in. Therefore, an application using OpenImageIO's APIs can read and write any image file for which a plugin can be found at runtime.

  • Plugins implementing I/O for several popular image file formats, including TIFF, JPEG/JFIF, OpenEXR, PNG, HDR/RGBE, ICO, BMP, Targa, JPEG-2000, RMan Zfile, FITS, DDS, Softimage PIC, PNM, DPX, Cineon, IFF, Field3D, OpenVDB, Ptex, Photoshop PSD, Wavefront RLA, SGI, WebP, GIF, DICOM, HEIF/HEIC/AVIF, many "RAW" digital camera formats, and a variety of movie formats (readable as individual frames). More are being developed all the time.

  • Several command line image tools based on these classes, including oiiotool (command-line format conversion and image processing), iinfo (print detailed info about images), iconvert (convert among formats, data types, or modify metadata), idiff (compare images), igrep (search images for matching metadata), and iv (an image viewer). Because these tools are based on ImageInput/ImageOutput, they work with any image formats for which ImageIO plugins are available.

  • An ImageCache class that transparently manages a cache so that it can access truly vast amounts of image data (tens of thousands of image files totaling multiple TB) very efficiently using only a tiny amount (tens of megabytes at most) of runtime memory.

  • A TextureSystem class that provides filtered MIP-map texture lookups, atop the nice caching behavior of ImageCache. This is used in commercial renderers and has been used on many large VFX and animated films.

  • ImageBuf and ImageBufAlgo functions -- a simple class for storing and manipulating whole images in memory, and a collection of the most useful computations you might want to do involving those images, including many image processing operations.

  • Python bindings for all of the major APIs.

Licensing

OpenImageIO is (c) Copyright Contributors to the OpenImageIO project.

OpenImageIO is distributed using the modified BSD license (also known as the "new BSD" or "3-clause BSD" license). The documentation is licensed under the Creative Commons Attribution 3.0 Unported License.

The plain English bottom line is that OpenImageIO is free, as well as freely modifiable and redistributable (in both source and binary form). You may use part or all of it in your own applications, whether proprietary or open, free or commercial. Using it in a commercial or proprietary application DOES NOT obligate you to pay us, or to use any particular licensing terms in your own application.

Some code and resources are distributed along with OIIO that have highly compatible, though slightly different, licenses (generally MIT or Apache). See the PDF documentation Acknowledgements section, and the THIRD-PARTY file for details.

Building and Installation

Please read the INSTALL.md file for detailed instructions on how to build and install OpenImageIO.

If you build with EMBEDPLUGINS=0, remember that you need to set the environment variable OIIO_LIBRARY_PATH to point to the 'lib' directory where OpenImageIO is installed, or else it will not be able to find the plugins.

Documentation

The primary user and programmer documentation can be found on openimageio.readthedocs.io as html or as PDF.

Contact & reporting problems

Simple "how do I...", "I'm having trouble", or "is this a bug" questions are best asked on the oiio-dev developer mail list. That's where the most people will see it and potentially be able to answer your question quickly (more so than a GH "issue").

Bugs, build problems, and discovered vulnerabilities that you are relatively certain is a legit problem in the code, and for which you can give clear instructions for how to reproduce, should be reported as issues.

If confidentiality precludes a public question or issue, you may contact us privately at [email protected], or for security-related issues [email protected].

Contributing

OpenImageIO welcomes code contributions, and nearly 150 people have done so over the years. We take code contributions via the usual GitHub pull request (PR) mechanism. Please see CONTRIBUTING for detailed instructions.

Web Resources

Main web page: http://www.openimageio.org

GitHub page: http://github.com/OpenImageIO/oiio

Mail list subscriptions and archives:

Comments
  • ImageCache: On-demand layer reading for multi-layered files

    ImageCache: On-demand layer reading for multi-layered files

    Hi,

    First off thanks for this amazing library. We use it extensively in Natron (open-source compositing software) (https://github.com/MrKepzie/Natron/tree/workshop via OpenFX: https://github.com/MrKepzie/openfx-io ) for most of the image reading/writing.

    We have received some complaints by our users that the reading of multi-layered EXR files was freakishly slow compared to other similar applications. I have narrowed it down to the ImageCache of OIIO. We make use of the ImageCache::get_pixels function. The problem is that if the image is not present into the cache, the OIIO cache internaly will create a new Tile and calls ImageInput::read_image which in turns calls
    ImageInput::read_scanlines(ybegin,yend,z,0,m_spec.nchannels,format,data,xstride,ystride)

    So basically regardless of what we requested via the get_pixels function with chbegin and chend, the Tile will always decode all available layers in the image. Needless to say that for EXR files rendered out with many passes it takes a while.

    Could this be improved to only read the channels that were requested by ImageCache::get_pixels in the first place ?

    Our temporary workaround is to use the ImageInput::read_scanlines API directly, but we suffer from the lack of caching because if the user of Natron requests more than 1 layer to display, it will open as many ImageInput on our side that the the user requested, which is not efficient at all.

  • ThreadSanitizer says ustring.cpp:179 has a data race

    ThreadSanitizer says ustring.cpp:179 has a data race

    While using ThreadSanitizer to check Duke's implementation I stumbled upon this data race.

    WARNING: ThreadSanitizer: data race (pid=17556)
      Atomic write of size 4 at 0x7ff153d4cdc0 by thread T2:
        #0 __tsan_atomic32_exchange ??:0 (exe+0x0000001376a7)
        #1 OpenImageIO::v1_3::spin_mutex::try_lock() /home/clitte/git/oiio/src/include/thread.h:570 (libOpenImageIO.so.1.3+0x0000003d482a)
        #2 OpenImageIO::v1_3::spin_mutex::lock() /home/clitte/git/oiio/src/include/thread.h:534 (libOpenImageIO.so.1.3+0x0000003d4731)
        #3 OpenImageIO::v1_3::spin_rw_mutex::read_lock() /home/clitte/git/oiio/src/include/thread.h:633 (libOpenImageIO.so.1.3+0x000000b62ff7)
        #4 read_lock_guard /home/clitte/git/oiio/src/include/thread.h:669 (libOpenImageIO.so.1.3+0x000000b62f96)
        #5 read_lock_guard /home/clitte/git/oiio/src/include/thread.h:669 (libOpenImageIO.so.1.3+0x000000b58430)
        #6 OpenImageIO::v1_3::ustring::make_unique(char const*) /home/clitte/git/oiio/src/libutil/ustring.cpp:179 (libOpenImageIO.so.1.3+0x000000b56457)
        #7 ustring /home/clitte/git/oiio/src/include/ustring.h:166 (libOpenImageIO.so.1.3+0x000000306ea6)
        #8 ustring /home/clitte/git/oiio/src/include/ustring.h:167 (libOpenImageIO.so.1.3+0x000000306e10)
        #9 ustring /home/clitte/git/oiio/src/include/ustring.h:186 (libOpenImageIO.so.1.3+0x000000306c67)
        #10 ustring /home/clitte/git/oiio/src/include/ustring.h:186 (libOpenImageIO.so.1.3+0x000000306bd0)
        #11 OpenImageIO::v1_3::ParamValue::init(std::string, OpenImageIO::v1_3::TypeDesc, int, void const*, bool) /home/clitte/git/oiio/src/include/paramlist.h:104 (libOpenImageIO.so.1.3+0x0000002e8399)
        #12 OpenImageIO::v1_3::ImageSpec::attribute(std::string const&, OpenImageIO::v1_3::TypeDesc, void const*) /home/clitte/git/oiio/src/libOpenImageIO/formatspec.cpp:355 (libOpenImageIO.so.1.3+0x0000002d962f)
        #13 OpenImageIO::v1_3::ImageSpec::attribute(std::string const&, char const*) /home/clitte/git/oiio/src/include/imageio.h:306 (libOpenImageIO.so.1.3+0x0000002c2643)
        #14 OpenImageIO::v1_3::JpgInput::open(std::string const&, OpenImageIO::v1_3::ImageSpec&) /home/clitte/git/oiio/src/jpeg.imageio/jpeginput.cpp:212 (libOpenImageIO.so.1.3+0x000000d76af6)
        #15 OpenImageIOReader /home/clitte/git/duke/src/duke/imageio_plugins/openimageio/OpenImageIO.cpp:135 (exe+0x0000001603b6)
        #16 OpenImageIOReader /home/clitte/git/duke/src/duke/imageio_plugins/openimageio/OpenImageIO.cpp:175 (exe+0x00000015fee0)
        #17 duke::OpenImageIODescriptor::getReaderFromFile(char const*) const /home/clitte/git/duke/src/duke/imageio_plugins/openimageio/OpenImageIO.cpp:223 (exe+0x00000015fdba)
        #18 duke::(anonymous namespace)::tryReader(char const*, duke::IIODescriptor const*, std::function<void (duke::RawPackedFrame&&, void const*)> const&) /home/clitte/git/duke/src/duke/engine/ImageLoadUtils.cpp:45 (exe+0x0000002e7f80)
        #19 duke::(anonymous namespace)::load(char const*, char const*, std::function<void (duke::RawPackedFrame&&, void const*)> const&) /home/clitte/git/duke/src/duke/engine/ImageLoadUtils.cpp:55 (exe+0x0000002e6d71)
        #20 duke::load(char const*, char const*, std::function<void (duke::RawPackedFrame&&, void const*)> const&, std::string&) /home/clitte/git/duke/src/duke/engine/ImageLoadUtils.cpp:66 (exe+0x0000002e69a3)
        #21 duke::LoadedImageCache::workerStep(std::pair<duke::IMediaStream const*, unsigned long>&, std::string&, std::string&) /home/clitte/git/duke/src/duke/engine/cache/LoadedImageCache.cpp:142 (exe+0x00000024d04c)
        #22 duke::LoadedImageCache::workerFunction() /home/clitte/git/duke/src/duke/engine/cache/LoadedImageCache.cpp:109 (exe+0x00000024c82f)
        #23 void std::_Mem_fn<void (duke::LoadedImageCache::*)()>::operator()<, void>(duke::LoadedImageCache*) const /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/functional:601 (exe+0x00000026ca43)
        #24 void std::_Bind_simple<std::_Mem_fn<void (duke::LoadedImageCache::*)()> (duke::LoadedImageCache*)>::_M_invoke<0ul>(std::_Index_tuple<0ul>) /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/functional:1732 (exe+0x00000026c8d0)
        #25 std::_Bind_simple<std::_Mem_fn<void (duke::LoadedImageCache::*)()> (duke::LoadedImageCache*)>::operator()() /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/functional:1720 (exe+0x00000026c840)
        #26 std::thread::_Impl<std::_Bind_simple<std::_Mem_fn<void (duke::LoadedImageCache::*)()> (duke::LoadedImageCache*)> >::_M_run() /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/thread:115 (exe+0x00000026c7e9)
        #27 <null> <null>:0 (libstdc++.so.6+0x0000000b1d2f)
    
      Previous write of size 4 at 0x7ff153d4cdc0 by thread T1:
        #0 OpenImageIO::v1_3::spin_mutex::unlock() /home/clitte/git/oiio/src/include/thread.h:553 (libOpenImageIO.so.1.3+0x0000003d4618)
        #1 OpenImageIO::v1_3::spin_rw_mutex::read_lock() /home/clitte/git/oiio/src/include/thread.h:637 (libOpenImageIO.so.1.3+0x000000b63015)
        #2 read_lock_guard /home/clitte/git/oiio/src/include/thread.h:669 (libOpenImageIO.so.1.3+0x000000b62f96)
        #3 read_lock_guard /home/clitte/git/oiio/src/include/thread.h:669 (libOpenImageIO.so.1.3+0x000000b58430)
        #4 OpenImageIO::v1_3::ustring::make_unique(char const*) /home/clitte/git/oiio/src/libutil/ustring.cpp:179 (libOpenImageIO.so.1.3+0x000000b56457)
        #5 ustring /home/clitte/git/oiio/src/include/ustring.h:166 (libOpenImageIO.so.1.3+0x000000306ea6)
        #6 ustring /home/clitte/git/oiio/src/include/ustring.h:167 (libOpenImageIO.so.1.3+0x000000306e10)
        #7 ustring /home/clitte/git/oiio/src/include/ustring.h:186 (libOpenImageIO.so.1.3+0x000000306c67)
        #8 ustring /home/clitte/git/oiio/src/include/ustring.h:186 (libOpenImageIO.so.1.3+0x000000306bd0)
        #9 OpenImageIO::v1_3::ParamValue::init(std::string, OpenImageIO::v1_3::TypeDesc, int, void const*, bool) /home/clitte/git/oiio/src/include/paramlist.h:104 (libOpenImageIO.so.1.3+0x0000002e8399)
        #10 OpenImageIO::v1_3::ImageSpec::attribute(std::string const&, OpenImageIO::v1_3::TypeDesc, void const*) /home/clitte/git/oiio/src/libOpenImageIO/formatspec.cpp:355 (libOpenImageIO.so.1.3+0x0000002d962f)
        #11 OpenImageIO::v1_3::ImageSpec::attribute(std::string const&, char const*) /home/clitte/git/oiio/src/include/imageio.h:306 (libOpenImageIO.so.1.3+0x0000002c2643)
        #12 OpenImageIO::v1_3::JpgInput::open(std::string const&, OpenImageIO::v1_3::ImageSpec&) /home/clitte/git/oiio/src/jpeg.imageio/jpeginput.cpp:212 (libOpenImageIO.so.1.3+0x000000d76af6)
        #13 OpenImageIOReader /home/clitte/git/duke/src/duke/imageio_plugins/openimageio/OpenImageIO.cpp:135 (exe+0x0000001603b6)
        #14 OpenImageIOReader /home/clitte/git/duke/src/duke/imageio_plugins/openimageio/OpenImageIO.cpp:175 (exe+0x00000015fee0)
        #15 duke::OpenImageIODescriptor::getReaderFromFile(char const*) const /home/clitte/git/duke/src/duke/imageio_plugins/openimageio/OpenImageIO.cpp:223 (exe+0x00000015fdba)
        #16 duke::(anonymous namespace)::tryReader(char const*, duke::IIODescriptor const*, std::function<void (duke::RawPackedFrame&&, void const*)> const&) /home/clitte/git/duke/src/duke/engine/ImageLoadUtils.cpp:45 (exe+0x0000002e7f80)
        #17 duke::(anonymous namespace)::load(char const*, char const*, std::function<void (duke::RawPackedFrame&&, void const*)> const&) /home/clitte/git/duke/src/duke/engine/ImageLoadUtils.cpp:55 (exe+0x0000002e6d71)
        #18 duke::load(char const*, char const*, std::function<void (duke::RawPackedFrame&&, void const*)> const&, std::string&) /home/clitte/git/duke/src/duke/engine/ImageLoadUtils.cpp:66 (exe+0x0000002e69a3)
        #19 duke::LoadedImageCache::workerStep(std::pair<duke::IMediaStream const*, unsigned long>&, std::string&, std::string&) /home/clitte/git/duke/src/duke/engine/cache/LoadedImageCache.cpp:142 (exe+0x00000024d04c)
        #20 duke::LoadedImageCache::workerFunction() /home/clitte/git/duke/src/duke/engine/cache/LoadedImageCache.cpp:109 (exe+0x00000024c82f)
        #21 void std::_Mem_fn<void (duke::LoadedImageCache::*)()>::operator()<, void>(duke::LoadedImageCache*) const /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/functional:601 (exe+0x00000026ca43)
        #22 void std::_Bind_simple<std::_Mem_fn<void (duke::LoadedImageCache::*)()> (duke::LoadedImageCache*)>::_M_invoke<0ul>(std::_Index_tuple<0ul>) /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/functional:1732 (exe+0x00000026c8d0)
        #23 std::_Bind_simple<std::_Mem_fn<void (duke::LoadedImageCache::*)()> (duke::LoadedImageCache*)>::operator()() /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/functional:1720 (exe+0x00000026c840)
        #24 std::thread::_Impl<std::_Bind_simple<std::_Mem_fn<void (duke::LoadedImageCache::*)()> (duke::LoadedImageCache*)> >::_M_run() /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/thread:115 (exe+0x00000026c7e9)
        #25 <null> <null>:0 (libstdc++.so.6+0x0000000b1d2f)
    
      Thread T2 (tid=17560, running) created by main thread at:
        #0 pthread_create ??:0 (exe+0x000000123772)
        #1 <null> <null>:0 (libstdc++.so.6+0x0000000b1f7e)
        #2 std::thread::thread<void (duke::LoadedImageCache::*)(), duke::LoadedImageCache*>(void (duke::LoadedImageCache::*&&)(), duke::LoadedImageCache*&&) /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/thread:138 (exe+0x000000268ab0)
        #3 void __gnu_cxx::new_allocator<std::thread>::construct<std::thread, void (duke::LoadedImageCache::*)(), duke::LoadedImageCache*>(std::thread*, void (duke::LoadedImageCache::*&&)(), duke::LoadedImageCache*&&) /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/ext/new_allocator.h:120 (exe+0x0000002689f5)
        #4 _ZNSt16allocator_traitsISaISt6threadEE12_S_constructIS0_JMN4duke16LoadedImageCacheEFvvEPS5_EEENSt9enable_ifIXsr18__construct_helperIT_DpT0_EE5valueEvE4typeERS1_PSA_DpOSB_ /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/bits/alloc_traits.h:254 (exe+0x0000002688fd)
        #5 _ZNSt16allocator_traitsISaISt6threadEE9constructIS0_JMN4duke16LoadedImageCacheEFvvEPS5_EEEDTcl12_S_constructfp_fp0_spclsr3stdE7forwardIT0_Efp1_EEERS1_PT_DpOS9_ /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/bits/alloc_traits.h:393 (exe+0x000000266acd)
        #6 void std::vector<std::thread, std::allocator<std::thread> >::_M_emplace_back_aux<void (duke::LoadedImageCache::*)(), duke::LoadedImageCache*>(void (duke::LoadedImageCache::*&&)(), duke::LoadedImageCache*&&) /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/bits/vector.tcc:409 (exe+0x000000266d0e)
        #7 void std::vector<std::thread, std::allocator<std::thread> >::emplace_back<void (duke::LoadedImageCache::*)(), duke::LoadedImageCache*>(void (duke::LoadedImageCache::*&&)(), duke::LoadedImageCache*&&) /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/bits/vector.tcc:101 (exe+0x00000024f497)
        #8 duke::LoadedImageCache::startWorkers() /home/clitte/git/duke/src/duke/engine/cache/LoadedImageCache.cpp:93 (exe+0x00000024ba46)
        #9 duke::LoadedImageCache::load(duke::Timeline const&) /home/clitte/git/duke/src/duke/engine/cache/LoadedImageCache.cpp:32 (exe+0x00000024bbbb)
        #10 duke::LoadedTextureCache::load(duke::Timeline const&) /home/clitte/git/duke/src/duke/engine/cache/LoadedTextureCache.cpp:20 (exe+0x00000020d995)
        #11 duke::Player::load(duke::Timeline const&, FrameDuration const&) /home/clitte/git/duke/src/duke/engine/Player.cpp:11 (exe+0x000000277019)
        #12 duke::DukeMainWindow::load(duke::Timeline const&, FrameDuration const&, duke::FitMode, int) /home/clitte/git/duke/src/duke/engine/DukeMainWindow.cpp:64 (exe+0x0000001e9269)
        #13 DukeApplication /home/clitte/git/duke/src/duke/engine/DukeApplication.cpp:136 (exe+0x0000001be2ef)
        #14 main /home/clitte/git/duke/src/duke/main.cpp:37 (exe+0x000000168d34)
    
      Thread T1 (tid=17559, running) created by main thread at:
        #0 pthread_create ??:0 (exe+0x000000123772)
        #1 <null> <null>:0 (libstdc++.so.6+0x0000000b1f7e)
        #2 std::thread::thread<void (duke::LoadedImageCache::*)(), duke::LoadedImageCache*>(void (duke::LoadedImageCache::*&&)(), duke::LoadedImageCache*&&) /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/thread:138 (exe+0x000000268ab0)
        #3 void __gnu_cxx::new_allocator<std::thread>::construct<std::thread, void (duke::LoadedImageCache::*)(), duke::LoadedImageCache*>(std::thread*, void (duke::LoadedImageCache::*&&)(), duke::LoadedImageCache*&&) /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/ext/new_allocator.h:120 (exe+0x0000002689f5)
        #4 _ZNSt16allocator_traitsISaISt6threadEE12_S_constructIS0_JMN4duke16LoadedImageCacheEFvvEPS5_EEENSt9enable_ifIXsr18__construct_helperIT_DpT0_EE5valueEvE4typeERS1_PSA_DpOSB_ /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/bits/alloc_traits.h:254 (exe+0x0000002688fd)
        #5 _ZNSt16allocator_traitsISaISt6threadEE9constructIS0_JMN4duke16LoadedImageCacheEFvvEPS5_EEEDTcl12_S_constructfp_fp0_spclsr3stdE7forwardIT0_Efp1_EEERS1_PT_DpOS9_ /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/bits/alloc_traits.h:393 (exe+0x000000266acd)
        #6 void std::vector<std::thread, std::allocator<std::thread> >::_M_emplace_back_aux<void (duke::LoadedImageCache::*)(), duke::LoadedImageCache*>(void (duke::LoadedImageCache::*&&)(), duke::LoadedImageCache*&&) /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/bits/vector.tcc:409 (exe+0x000000266d0e)
        #7 void std::vector<std::thread, std::allocator<std::thread> >::emplace_back<void (duke::LoadedImageCache::*)(), duke::LoadedImageCache*>(void (duke::LoadedImageCache::*&&)(), duke::LoadedImageCache*&&) /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/bits/vector.tcc:101 (exe+0x00000024f497)
        #8 duke::LoadedImageCache::startWorkers() /home/clitte/git/duke/src/duke/engine/cache/LoadedImageCache.cpp:93 (exe+0x00000024ba46)
        #9 duke::LoadedImageCache::load(duke::Timeline const&) /home/clitte/git/duke/src/duke/engine/cache/LoadedImageCache.cpp:32 (exe+0x00000024bbbb)
        #10 duke::LoadedTextureCache::load(duke::Timeline const&) /home/clitte/git/duke/src/duke/engine/cache/LoadedTextureCache.cpp:20 (exe+0x00000020d995)
        #11 duke::Player::load(duke::Timeline const&, FrameDuration const&) /home/clitte/git/duke/src/duke/engine/Player.cpp:11 (exe+0x000000277019)
        #12 duke::DukeMainWindow::load(duke::Timeline const&, FrameDuration const&, duke::FitMode, int) /home/clitte/git/duke/src/duke/engine/DukeMainWindow.cpp:64 (exe+0x0000001e9269)
        #13 DukeApplication /home/clitte/git/duke/src/duke/engine/DukeApplication.cpp:136 (exe+0x0000001be2ef)
        #14 main /home/clitte/git/duke/src/duke/main.cpp:37 (exe+0x000000168d34)
    
    SUMMARY: ThreadSanitizer: data race ??:0 __tsan_atomic32_exchange
    
    
  • Sketch of a C API for comment

    Sketch of a C API for comment

    Description

    This adds a minimal C API called "coiio" currently that is built as an additional shared library, the implementation of which is under src/coiio and gated behind option BUILD_COIIO (defaults to ON in this PR). I've also added a test under testsuite/coiio that exercises it by loading a tiff, adding a couple of attributes to the header, writing it out as an exr, then reading the exr back and getting the attribute values.

    Notable things are right now I've only wrapped TypeDesc::TypeDesc(string_view) as TypeDesc_from_string in order to generate TypeDescs because it was quick. I imagine we'll ultimately want to declare prebuilt extern TypeDesc objects as a replacement for the static constexpr ones for commonly used types in C++.

    One slight wrinkle is in all the *_geterror() functions. In C++ they return a copy of an internally owned std::string. I've worked around this for now by caching the string in a thread_local and returning a pointer from that to C. I'm not completely up to date on the semantics of thread_local (does it even work in Apple's libc++ yet?) so not sure if this is that great.

    An alternative would be to add a new function, e.g. const char* ImageInput::geterrorc() that would just call m_errmsg.c_str(), then ImageInput::geterror() could call that and make a copy of the string to return, while the C API would just call geterrorc, with an explicit warning that the pointer is only valid until the ImageInput is mutated again. Obviously if ImageInput were to be mutated from another thread then all bets are off and thus I don't think this idea works.

    Yet another way, and an idiom you see often in C APIs would be to provide a couple more functions:

    int ImageInput::geterrorlength() { return m_errmsg.size(); }
    void ImageInput::geterrormsg(char* msg) { strcpy(msg, m_errmsg.c_str(), m_errmsg.size()); }
    

    and have the caller manage the memory. In the multithreaded case this also doesn't work, but another way of doing this is:

    void ImageInput::geterrormsg(char* msg, int buffer_len) { 
        lock_guard lock(m_mutex);
        strcpy(msg, m_errmsg.c_str(), min(buffer_len, m_errmsg.size()));
    }
    

    Plenty of opportunity for bikeshedding here too. The name is just what I called the library in my rust crate, so can be whatever you prefer. I would suggest making it different enough from OpenImageIO so that you don't mistake the headers in include statements though, e.g.:

    #include <OpenImageIO/imagebuf.h>
    #include <COpenImageIO/imageio.h> //< oops, but probably won't lead to subtle bugs so may be ok?
    

    Tests

    New test is testsuite/coiio. I also copied over run_app() from OSL to the testsuite to allow building the test binary as part of the test.

    Checklist:

    • [x] I have read the contribution guidelines.
    • [ ] If this is more extensive than a small change to existing code, I have previously submitted a Contributor License Agreement (individual, and if there is any way my employers might think my programming belongs to them, then also corporate).
    • [x] I have updated the documentation, if applicable.
    • [x] I have ensured that the change is tested somewhere in the testsuite (adding new test cases if necessary).
    • [x] My code follows the prevailing code style of this project.

    TODO checklist:

    • [x] Add licence blurb to each file
    • [x] 3 lines between functions
    • [x] extra newline before closing namespace
    • [x] rename files to c-imageio.h (or imageio-c.h?)
    • [x] fix doc comments to refer to underlying C++ instead of copying full doc comments
    • [x] Resolve geterror() situation
  • Does OpenImageIO support nChannel images

    Does OpenImageIO support nChannel images

    Hi, just a question can images (tiff, PSD and others) with more than 4 Channels be read into a memory buffer and written back using OpenImageIO? In the printing industry images with CMYK plus a number of spot color channels are quite common. Photoshop files must only be read, but TIFF must be written.

    Is also BigTIFF supported?

    Regards

    Stefan

  • Added support for converting ImageBuf to OpenCV IplImage

    Added support for converting ImageBuf to OpenCV IplImage

    Hey,

    This PR is to add support for converting from ImageBuf to IplImage. I noticed there was the code to go one way, but not the other. If there's any bad code smell, let me know. I'm primarily a Python programmer, so there's a few things that I'm use to being able to do in Python that I can't seem to do in C++. It could be a limitation of the programmer (most likely), or the language.

    If this successfully goes through, then I'll work on implementing OpenCV's Mat next.

    I have tested this on a simple image that I grabbed from the net, so it works, but may break under more testing. I want to clean up the code more before I try throwing more image types at this.

    One thing that isn't supported right now is the Half type because I'm not sure how is the best way to handle that. Suggestions welcome!

  • Make atomic_test and spinlock_test run for many more iterations, and time their results.

    Make atomic_test and spinlock_test run for many more iterations, and time their results.

    Make atomic_test and spinlock_test run for many more iterations, and time their results.

    This allows us to rigorously compare the speed of our atomics and spin locks. Also make their output a little neater by locking around the status printouts, and eliminate the #if's that provide safety for Boost < 1.35, which is no longer supported.

  • Allow ImageCache/TextureSystem to store partial channel sets in cache.

    Allow ImageCache/TextureSystem to store partial channel sets in cache.

    Allow ImageCache/TextureSystem to store partial channel sets in cache.

    ImageCache's original design would read all channels into a tile, because (1) most files have only a few channels, (2) most uses (for example, texture) tend to use most or all of the channels in the file, in close temporal proximity if not in the same lookup, (3) most file formats don't have a way to read a channel subset that's any more efficient than reading all of them.

    However, for the rare case that there are MANY channels, only a few of which are needed (for example, looking up 3 channels of textures from a 40 channel file), this is very wasteful of texture space, and MAY (depending on the format) also be wasteful of I/O.

    So this patch:

    • Modifies ImageCache so that a tile can store any contiguous subset of channels. This means the TileID stores a chbegin/chend range, the hashes consider this, and certain ImageCache public API calls now have varieties that take chbegin/chend parameters.
    • ImageCache will create cache tiles that store exactly the channel range requested. The default is all channels in the tile. Use subsets wisely -- if you have a 4-channel file and you separately look up channel ranges [0,1) and [0,3), it will redundantly read and store the overlapping channels!
    • TextureSystem is modified to ask for all channels when there are only a few channels in the file, but when there are more than max_tile_channels (a new settable attribute of the TS) channels in the file, it will ask the IC for only the channels it needs for the texture lookup. The max_tile_channels is set by default to 5, which means for the vast majority of files (R, RGB, RGBA, RGBAZ) it will read all channels and behave as before. But if you have a mega-channel file, it will try to read and cache only the subset of channels you requested with the texture call. If you don't want the new behavior, just set max_tile_channels to something bigger.

    The bottom line is that if your app uses IC with the old API calls, or if you use TS with texture files having 5 or fewer channels (which is almost always the case), you should see no change in behavior or performance. But for those of you who for some reason deal with files of many many channels, accessing a small subset of them via texture or IC should result much more efficient cache behavior because the IC won't be caching channels you aren't accessing.

  • Raw input: Added new input format for camera raw formats. Uses LibRaw.

    Raw input: Added new input format for camera raw formats. Uses LibRaw.

    Hi,

    I've been working on this for a few days, and just wanted to get some feedback. Raw format reader powered by LibRaw. Handles most RAW formats. I've given some attributes to control the most common settings (Exposure, ColorSpace primaries, Demosaic algorithm). Only thing missing at the moment is the EXIF metadata, but It shouldn't be too difficult to add that in.

    Thanks, Mark

  • [Feature Request] Ability to read an image from memory

    [Feature Request] Ability to read an image from memory

    Following up on a conversation with @lgritz , I'd like to request the other direction of what #1895 is requesting.

    The Need

    In USD and Hydra, we’ve been relying on OIIO for marquee image services, and it’s far and away the most compelling choice. However, recently we’ve grown a need to be able to decode formats (USD, images, volumes) from in-memory buffers, which may have been mmapped from files or created or transmitted. There are two different scenarios:

    1. We’re providing an archive format that, in a single (uncompressed zip) file, contains USD files, textures, and anything else a scene requires. To be able to consume the scene without unpacking it, we want to access data out of it by mmapping with offsets into the zip file.
    2. People can create “asset resolvers” that deliver data to USD directly over the network, from dbs, etc, and would like to void the step of writing that data out to disk.

    So...

    We'd like to be able to hand OIIO a buffer-pointer, plus length, plus "identifier" that corresponds to a filename and has an extension that indicate format; that buffer represents an actual serialized image. When we're using OIIO as primarily an image reader, the problem is reasonably straightforward - as Larry suggested, we should be able to initialize an ImageInput from these inputs. This is sufficient for our more immediate needs.

    The more involved case is when a client wants to use OIIO as a texture manager, using ImageCache/TextureSystem . In that case, we need to acknowledge that our buffer is a resource that needs to be managed, so we will need a way to allow OIIO to do that. On the USD-side, we'll have a resource object whose lifetime manages the buffer's lifetime, but we'd need a way to adapt that for OIIO's consumption.

    Thanks!

  • [jpeg2000] libjasper does not create profile 3 and profile 4 images required for Digital Cinema applications

    [jpeg2000] libjasper does not create profile 3 and profile 4 images required for Digital Cinema applications

    Based on private mail with Terrance Mali..., the author of OpenDCP, he brought up the fact that Jasper does not support profile 3 or 4 of the jpeg2000 spec as well as supporting codestream lengths or single tiles, making it unsuitable for DCDM creation.

    The solution I put forward is to rewrite the jpeg2000 plugin to use libopenjpeg instead.

  • new ArgParse code does not build with VS2015

    new ArgParse code does not build with VS2015

    After commit e81036b6559 (#2531), I can no longer build on Windows using VS2015 because I get build errors of the form:

    oiio\src\oiiotool\oiiotool.cpp(5244): error C2664: 'OpenImageIO_v2_2::ArgParse::Arg &OpenImageIO_v2_2::ArgParse::Arg::action(int (__cdecl *)(int,const char **))': cannot convert argument 1 from 'void (__cdecl *)(OpenImageIO_v2_2::span<const char *const ,-1>)' to 'OpenImageIO_v2_2::ArgParse::ArgAction &&'
    oiio\src\oiiotool\oiiotool.cpp(5244): note: Reason: cannot convert from 'overloaded-function' to 'OpenImageIO_v2_2::ArgParse::ArgAction'
    oiio\src\oiiotool\oiiotool.cpp(5244): note: No constructor could take the source type, or constructor overload resolution was ambiguous
    

    Looking at the code, I can't see how this could be considered ambiguous and this should work, so I suspect a compiler bug. And in fact, if I build with VS2019 I get no error.

    I'm hoping very soon we'll be building OIIO with a newer compiler than VS2015, so in my particular case I don't think I need this fixed in OIIO. However, currently the minimum visual studio required, according to the following is 2015:

    src/include/OpenImageIO/platform.h
    # if _MSC_VER < 1900
     # error "This version of OIIO is meant to work only with Visual Studio 2015 or later"
    # endif
    

    So I think either we'd want to raise the minimum VS (I haven't tested 2017, but I do know 2019 works) or implement a temporary work-around? There's also the possibility I'm messing something up, so of course would be good if someone else could do a sanity check?

  • include error with fmt lib

    include error with fmt lib

    Describe the bug I include the fmt library header before the OpenImageIO and get the compiler error.

    #include <fmt/format.h> 
    #include <OpenImageIO/imagebuf.h>
    

    Detailed compilation errors

    /usr/include/OpenImageIO/fmt/ostream.h:22:3: error: ‘buffer’ does not name a type
       22 |   buffer<Char>& buffer_;
          |   ^~~~~~
    /usr/include/OpenImageIO/fmt/ostream.h:25:19: error: expected ‘)’ before ‘<’ token
       25 |   formatbuf(buffer<Char>& buf) : buffer_(buf) {}
          |            ~      ^
          |                   )
    /usr/include/OpenImageIO/fmt/ostream.h:35:53: error: expected ‘;’ at end of member declaration
       35 |   int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE {
          |                                                     ^
          |                                                      ;
    /usr/include/OpenImageIO/fmt/ostream.h:35:55: error: ‘FMT_OVERRIDE’ does not name a type; did you mean ‘FMT_VERSION’?
       35 |   int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE {
          |                                                       ^~~~~~~~~~~~
          |                                                       FMT_VERSION
    /usr/include/OpenImageIO/fmt/ostream.h:41:62: error: expected ‘;’ at end of member declaration
       41 |   std::streamsize xsputn(const Char* s, std::streamsize count) FMT_OVERRIDE {
          |                                                              ^
          |                                                               ;
    /usr/include/OpenImageIO/fmt/ostream.h:41:64: error: ‘FMT_OVERRIDE’ does not name a type; did you mean ‘FMT_VERSION’?
       41 |   std::streamsize xsputn(const Char* s, std::streamsize count) FMT_OVERRIDE {
          |                                                                ^~~~~~~~~~~~
          |                                                                FMT_VERSION
    
    
  • Centralize ImageOutput validity checks

    Centralize ImageOutput validity checks

    Many ImageOutput::open implementations start out with various validity checks -- such as whether the ImageSpec requests a resolution, number of channels, or other features simply not allowed by that file format. This is not only repetitive, but which checks are done by each file type is somewhat haphazard, error-prone, hard to get full test coverage (must we separately test each possible failure case for every file format?), and the error messages are not always consistent across formats. Frankly, most of the format writers assume that the caller has a full understanding of supports() and will never send requests for features that are unsupported, which is obviously not a careful approach.

    This PR proposes adding a utility method ImageOutput::check_open(), which performs all validity checks on the ImageSpec that can be deduced from supports(). The various ImageOutput::open() implementations may call this function and avoid having to replicate (or forget) all the checks done in other output formats. This is a protected method that is used by ImageOutput implementations internally, but has no use for client-side code.

    I've implemented check_open, and also used it here for all the output formats. If this seems ok to everyone, I also plan to do an analogous helper for ImageInput common validity checks (which will be an even bigger reduction of redundant code and greatly increase the safety against corrupted or nonsensical input files).

    Along the way I also instituted a new supports() query: "noimage". That is to indicate a file for which it is permitted to have a pixel data window consisting of 0 pixels (i.e. an "image" that is only a container for metadata). Currently, FITS is the only format we support that allows this, though it's something we occasionally talk about for OpenEXR. Allowing an explicit way for formats to say they allow no pixels is what allows check_open to issue error messages for all the other formats if it is passed zero-sized width, height, depth, or nchannels.

  • [Config.cmake.in] An OpenImageIO_INCLUDE_DIR path error

    [Config.cmake.in] An OpenImageIO_INCLUDE_DIR path error

    I am the official maintainer of vcpkg, and I have encountered problems when upgrading to a new version.

    Describe the bug The calculation of the OpenImageIO_INCLUDE_DIR path is inaccurate, so the include directory cannot be found.

    To Reproduce

    1. git clone https://github.com/microsoft/vcpkg.git
    2. cd vcpkg
    3. .\bootstrap-vcpkg.bat
    4. Modify the version information in the portfile.cmake and vcpkg.jaon files in order to upgrade to 2.4.5.0.
    5. .\vcpkg install openimageio
    6. Create a cmake project to test usage, where the code information is as follows: CMakeSetting CMakeList
    7. Output details:
    1> CMake generation started for configuration: 'x86-Debug'.
    1> Command line: "C:\Windows\system32\cmd.exe" /c "%SYSTEMROOT%\System32\chcp.com 65001 >NUL && "C:\PROGRAM FILES (X86)\MICROSOFT VISUAL STUDIO\2019\ENTERPRISE\COMMON7\IDE\COMMONEXTENSIONS\MICROSOFT\CMAKE\CMake\bin\cmake.exe"  -G "Visual Studio 16 2019" -A Win32  -DCMAKE_CONFIGURATION_TYPES:STRING="Debug" -DCMAKE_INSTALL_PREFIX:PATH="C:\Users\monica\source\repos\CMakeFindUsage\out\install\x86-Debug" -DCMAKE_TOOLCHAIN_FILE=E:/src/Monica/vcpkg03/scripts/buildsystems/vcpkg.cmake "C:\Users\monica\source\repos\CMakeFindUsage" 2>&1"
    1> Working directory: C:\Users\monica\source\repos\CMakeFindUsage\out\build\x86-Debug
    1> [CMake] -- Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.19045.
    1> [CMake] -- The C compiler identification is MSVC 19.29.30147.0
    1> [CMake] -- The CXX compiler identification is MSVC 19.29.30147.0
    1> [CMake] -- Detecting C compiler ABI info
    1> [CMake] -- Detecting C compiler ABI info - done
    1> [CMake] -- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/MSVC/14.29.30133/bin/Hostx64/x86/cl.exe - skipped
    1> [CMake] -- Detecting C compile features
    1> [CMake] -- Detecting C compile features - done
    1> [CMake] -- Detecting CXX compiler ABI info
    1> [CMake] -- Detecting CXX compiler ABI info - done
    1> [CMake] -- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/MSVC/14.29.30133/bin/Hostx64/x86/cl.exe - skipped
    1> [CMake] -- Detecting CXX compile features
    1> [CMake] -- Detecting CXX compile features - done
    1> [CMake] -- Found ZLIB: optimized;E:/src/Monica/vcpkg03/installed/x86-windows/lib/zlib.lib;debug;E:/src/Monica/vcpkg03/installed/x86-windows/debug/lib/zlibd.lib (found version "1.2.13") 
    1> [CMake] -- Found PNG: optimized;E:/src/Monica/vcpkg03/installed/x86-windows/lib/libpng16.lib;debug;E:/src/Monica/vcpkg03/installed/x86-windows/debug/lib/libpng16d.lib (found version "1.6.37") 
    **1> [CMake] ***************************************************output info * start**************************************************
    1> [CMake] *******_CURR_INSTALL_LIBDIR=E:/src/Monica/vcpkg03/installed/x86-windows***************
    1> [CMake] *******_ABS_CMAKE_INSTALL_LIBDIR=E:/src/Monica/vcpkg03/installed/x86-windows/lib***************
    1> [CMake] *******_ABS_CMAKE_INSTALL_INCLUDEDIR=E:/src/Monica/vcpkg03/installed/x86-windows/include***************
    1> [CMake] *******_INCLUDEDIR_RELATIVE_TO_LIBDIR=../include***************
    1> [CMake] *******_CURR_INSTALL_INCLUDE_DIR=E:/src/Monica/vcpkg03/installed/include***************
    1> [CMake] ***************************************************output info * end****************************************************
    1> [CMake] *****_var=OpenImageIO_INCLUDE_DIR
    1> [CMake] *****_file=E:/src/Monica/vcpkg03/installed/include**
    1> [CMake] CMake Error at E:/src/Monica/vcpkg03/installed/x86-windows/share/imath/ImathConfig.cmake:13 (message):
    1> [CMake]   File or directory E:/src/Monica/vcpkg03/installed/include referenced by
    1> [CMake]   variable OpenImageIO_INCLUDE_DIR does not exist !
    1> [CMake] Call Stack (most recent call first):
    1> [CMake]   E:/src/Monica/vcpkg03/installed/x86-windows/share/openimageio/OpenImageIOConfig.cmake:98 (set_and_check)
    1> [CMake]   E:/src/Monica/vcpkg03/scripts/buildsystems/vcpkg.cmake:834 (_find_package)
    1> [CMake]   CMakeFindUsage/CMakeLists.txt:10 (find_package)
    1> [CMake] -- Configuring incomplete, errors occurred!
    1> [CMake] See also "C:/Users/monica/source/repos/CMakeFindUsage/out/build/x86-Debug/CMakeFiles/CMakeOutput.log".
    1> 'C:\Windows\system32\cmd.exe' '/c "%SYSTEMROOT%\System32\chcp.com 65001 >NUL && "C:\PROGRAM FILES (X86)\MICROSOFT VISUAL STUDIO\2019\ENTERPRISE\COMMON7\IDE\COMMONEXTENSIONS\MICROSOFT\CMAKE\CMake\bin\cmake.exe"  -G "Visual Studio 16 2019" -A Win32  -DCMAKE_CONFIGURATION_TYPES:STRING="Debug" -DCMAKE_INSTALL_PREFIX:PATH="C:\Users\monica\source\repos\CMakeFindUsage\out\install\x86-Debug" -DCMAKE_TOOLCHAIN_FILE=E:/src/Monica/vcpkg03/scripts/buildsystems/vcpkg.cmake "C:\Users\monica\source\repos\CMakeFindUsage" 2>&1"' execution failed with error: ''C:\Windows\system32\cmd.exe' '/c "%SYSTEMROOT%\System32\chcp.com 65001 >NUL && "C:\PROGRAM FILES (X86)\MICROSOFT VISUAL STUDIO\2019\ENTERPRISE\COMMON7\IDE\COMMONEXTENSIONS\MICROSOFT\CMAKE\CMake\bin\cmake.exe"  -G "Visual Studio 16 2019" -A Win32  -DCMAKE_CONFIGURATION_TYPES:STRING="Debug" -DCMAKE_INSTALL_PREFIX:PATH="C:\Users\monica\source\repos\CMakeFindUsage\out\install\x86-Debug" -DCMAKE_TOOLCHAIN_FILE=E:/src/Monica/vcpkg03/scripts/buildsystems/vcpkg.cmake "C:\Users\monica\source\repos\CMakeFindUsage" 2>&1"' returned with exit code: 1'.
    

    Platform information:

    • OIIO branch/version: 2.4.5.0,master
    • OS: Windows(x86 and x64)
    • C++ compiler: VS2019

    **IF YOU ALREADY HAVE A CODE FIX: Problematic code location: Config.cmake.in#L40-L46 I think that since _CURR_INSTALL_LIBDIR is used to splice addresses, _CURR_INSTALL_LIBDIR should be used for calculation. Suggested changes:

    get_filename_component(_CURR_INSTALL_LIBDIR "${CMAKE_CURRENT_LIST_DIR}/../../" ABSOLUTE)
    get_filename_component(_ABS_CMAKE_INSTALL_LIBDIR "${VCPKG_IMPORT_PREFIX}/lib" ABSOLUTE)
    get_filename_component(_ABS_CMAKE_INSTALL_INCLUDEDIR "${VCPKG_IMPORT_PREFIX}/include" ABSOLUTE)
    
    file(RELATIVE_PATH _INCLUDEDIR_RELATIVE_TO_LIBDIR
         "${_CURR_INSTALL_LIBDIR}" "${_ABS_CMAKE_INSTALL_INCLUDEDIR}")
    
    get_filename_component(_CURR_INSTALL_INCLUDE_DIR
                           "${_CURR_INSTALL_LIBDIR}/${_INCLUDEDIR_RELATIVE_TO_LIBDIR}" ABSOLUTE)
    

    (I used the above code to configure successfully, but I am not sure if it will have any impact on users who build with other compilers, so I did not raise PR to modify.)

  • [BUG] Cannot force single threaded behaviour via OPENIMAGEIO_THREADS

    [BUG] Cannot force single threaded behaviour via OPENIMAGEIO_THREADS

    I'm trying to force openexr output to be single threaded via OPENIMAGEIO_THREADS, but that seems to be impossible. Should it be possible?

    In exroutput.cpp's set_exr_threads(), we have:

        int oiio_threads = 1;
        OIIO::getattribute("exr_threads", oiio_threads);
    
        // 0 means all threads in OIIO, but single-threaded in OpenEXR
        // -1 means single-threaded in OIIO
        if (oiio_threads == 0) {
            oiio_threads = Sysutil::hardware_concurrency();
        } else if (oiio_threads == -1) {
            oiio_threads = 0;
    

    So this code would imply that setting OPENIMAGEIO_THREADS to -1 should do it.

    However, in imageio.cpp's threads_default(), we have:

        int n = Strutil::from_string<int>(
            Sysutil::getenv("OPENIMAGEIO_THREADS", Sysutil::getenv("CUE_THREADS")));
        if (n < 1)
            n = Sysutil::hardware_concurrency();
    

    So what happens is that we end up with "exr_threads" set to Sysutil::hardware_concurrency() before we even get to the check in set_exr_threads(), making it impossible to be single threaded.

  • MOV file causes exception when opening

    MOV file causes exception when opening

            oiio::ImageSpec configSpec;
            
            configSpec.attribute("raw:auto_bright", 0);   
            configSpec.attribute("raw:use_camera_wb", 1); 
            configSpec.attribute("raw:ColorSpace", "Linear"); /
            configSpec.attribute("raw:use_camera_matrix", 3); 
    
            configSpec["oiio:UnassociatedAlpha"] = 1;
    
            auto imageInput = oiio::ImageInput::open(path, &configSpec);
    
    

    Stack trace

            avcodec-58.dll!00007ffc18ab3370()	Unknown
    
     	TintaMediaReader.dll!OpenImageIO_v2_4_0::FFmpegInput::close(void)	C++
    
    	TintaMediaReader.dll!QtOIIOHandler::read(QImage * image) Line 284	C++
    
    

    IMG_1683.zip

  • CMake: also find jconfig.h from libturbojpeg from arch-specific include directory

    CMake: also find jconfig.h from libturbojpeg from arch-specific include directory

    Description

    This header file is architecture-dependent and can be stored as:

    • /usr/include/i386-linux-gnu/jconfig.h
    • /usr/include/x86_64-linux-gnu/jconfig.h

    Instead of:

    • /usr/include/jconfig.h

    That fixes build errors like this:

    CMake Error at src/cmake/modules/FindJPEGTurbo.cmake:32 (file):
      file STRINGS file "/usr/include/jconfig.h" cannot be read.
    Call Stack (most recent call first):
      src/cmake/checked_find_package.cmake:127 (find_package)
      src/cmake/externalpackages.cmake:139 (checked_find_package)
      CMakeLists.txt:155 (include)
    

    Checklist:

    • [x] I have read the contribution guidelines.
    • [x] ~~If this is more extensive than a small change to existing code, I have previously submitted a Contributor License Agreement (individual, and if there is any way my employers might think my programming belongs to them, then also corporate).~~
      This change is too small and not original enough to be subject to copyright.
    • [x] ~~I have updated the documentation, if applicable.~~
      Not applicable.
    • [x] ~~I have ensured that the change is tested somewhere in the testsuite (adding new test cases if necessary).~~
      Not applicable.
    • [x] My code follows the prevailing code style of this project.
A simple API wrapper that generates images & facts of any animal

animality.h A simple API wrapper that generates images & facts of any animal Required dependencies: libcurl for sending HTTPS requests. pthreads for t

Nov 10, 2022
Like feh, but better, faster, more image formats, simpler, more lightweight, animation support, and better UI
Like feh, but better, faster, more image formats, simpler, more lightweight, animation support, and better UI

Like feh, but better, faster, more image formats, simpler, more lightweight, animation support, and better UI

Oct 23, 2022
An AV1 Image (AVIF) file format plug-in for Adobe® Photoshop®

avif-format An AV1 Image (AVIF) file format plug-in for Adobe® Photoshop®. Single images can be loaded and saved using 8, 10 or 12 bits-per-channel, i

Nov 29, 2022
C++ image processing and machine learning library with using of SIMD: SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX, AVX2, AVX-512, VMX(Altivec) and VSX(Power7), NEON for ARM.

Introduction The Simd Library is a free open source image processing and machine learning library, designed for C and C++ programmers. It provides man

Nov 23, 2022
CGIF, A fast and lightweight GIF encoder that can create GIF animations and images

CGIF, a GIF encoder written in C A fast and lightweight GIF encoder that can create GIF animations and images. Summary of the main features: user-defi

Nov 25, 2022
A crude untested example showing how to retrieve and display images from multiple cameras with OpenCV and wxWidgets.

About wxOpenCVCameras is a crude untested example of how to retrieve and display images from multiple cameras, using OpenCV to grab images from a came

Nov 18, 2022
HDRView is a simple research-oriented image viewer with an emphasis on examining and comparing high-dynamic range (HDR) images
HDRView is a simple research-oriented image viewer with an emphasis on examining and comparing high-dynamic range (HDR) images

HDRView is a simple research-oriented high-dynamic range image viewer with an emphasis on examining and comparing images, and including minimalistic tonemapping capabilities. HDRView currently supports reading EXR, PNG, TGA, BMP, HDR, JPG, GIF, PNM, PFM, and PSD images and writing EXR, HDR, PNG, TGA, PPM, PFM, and BMP images.

Nov 23, 2022
You can use this to compile the code and output images into a word doc for assignment purposes
You can use this to compile the code and output images into a word doc for assignment purposes

Code_n_Ouput_to_docx You can use this to compile the code and output images into a word doc for assignment purposes Basic requirements: Python 3.7 or

Aug 21, 2022
An open source library for face detection in images. The face detection speed can reach 1000FPS.
An open source library for face detection in images. The face detection speed can reach 1000FPS.

libfacedetection This is an open source library for CNN-based face detection in images. The CNN model has been converted to static variables in C sour

Nov 28, 2022
Convert images to ASCII art.
Convert images to ASCII art.

Image-to-ascii Convert images to ASCII art. This program using stb library to load images. Usage Usage: compile the program to get *.out file

Aug 20, 2022
Very fast C++ .PNG writer for 24/32bpp images.

fpng Very fast C++ .PNG writer for 24/32bpp images. fpng.cpp was written to see just how fast you can write .PNG's without sacrificing too much compre

Nov 23, 2022
Make It Pixel is a programming language to process images to look like pixel art.
Make It Pixel is a programming language to process images to look like pixel art.

Make images look like pixel art Make It Pixel is a programming language to process images to look like pixel art. Its interpreter is written in C++ an

Oct 14, 2022
Given a set of images, LeastAverageImage generates the least average -- the opposite of the average.
Given a set of images, LeastAverageImage generates the least average -- the opposite of the average.

LeastAverageImage Given a set of images, LeastAverageImage generates the least average -- the opposite of the average. More information about the prog

Nov 27, 2022
Video++, a C++14 high performance video and image processing library.

Video++ Video++ is a video and image processing library taking advantage of the C++14 standard to ease the writing of fast video and image processing

Oct 14, 2022
ppl.cv is a high-performance image processing library of openPPL supporting x86 and cuda platforms.

ppl.cv is a high-performance image processing library of openPPL supporting x86 and cuda platforms.

Nov 23, 2022
The CImg Library is a small and open-source C++ toolkit for image processing
The CImg Library is a small and open-source C++ toolkit for image processing

http://cimg.eu The CImg Library is a small and open-source C++ toolkit for image processing, designed with these properties in mind: CImg defines clas

Nov 23, 2022
The “Quite OK Image” format for fast, lossless image compression

The “Quite OK Image” format for fast, lossless image compression

Nov 30, 2022
QOY - The "Quite OK YCbCr420A" format for fast, lossless image compression

QOY - The "Quite OK YCbCr420A" format for fast, lossless* image compression ( * colorspace conversion to/from RGBA is lossy, if used ) Single-file MIT

Oct 1, 2022