From 9ecc04f7b059ba176678d5cfd9d7794398d74a97 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Wed, 15 Feb 2023 16:12:08 -0800 Subject: [PATCH] Reorganize repo/readthedocs documentation (#1332) * Reorganize documentation, move content to readthedocs site * Move content from README.md/repo-top-level to docs/readthedocs * Move technical documentation/src/images to "technical" subdir * CONTRIBUTING, GOVERNANCE, INSTALL, ASWF now on readthedocs Signed-off-by: Cary Phillips * Remove GOVERNANCE.md, CONTRIBUTING.md, INSTALL.md Signed-off-by: Cary Phillips * Typos in README.md Signed-off-by: Cary Phillips * Doc re-org, pass 2 Signed-off-by: Cary Phillips * Use sphinx-press-theme, toc_redirect.rst Signed-off-by: Cary Phillips * windowExample1.small.png Signed-off-by: Cary Phillips * reader/writer Signed-off-by: Cary Phillips * copyright Signed-off-by: Cary Phillips * copyright, take 2 Signed-off-by: Cary Phillips * Copyright notice in *.md Signed-off-by: Cary Phillips * fix links; use $ instead of % Signed-off-by: Cary Phillips --------- Signed-off-by: Cary Phillips --- CHANGES.md | 3 + CODE_OF_CONDUCT.md | 3 + CONTRIBUTING.md | 5 +- CONTRIBUTORS.md | 3 + GOVERNANCE.md | 3 + LICENSE.md | 3 + README.md | 227 ++++----- SECURITY.md | 3 + cmake/FindPythonPackage.cmake | 79 +++ docs/API.rst | 21 + docs/CMakeLists.txt | 3 + docs/HelloWorld.rst | 43 ++ docs/InterpretingDeepPixels.rst | 24 +- docs/MultiViewOpenEXR.rst | 3 +- docs/OpenEXRCoreAPI.rst | 10 +- docs/OpenEXRFileLayout.rst | 17 +- docs/PortingGuide.rst | 605 +++++++++++++++++++++++ docs/ReadingAndWritingImageFiles.rst | 15 +- docs/StandardOptionalAttributes.rst | 5 +- docs/SymbolVisibility.md | 103 ---- docs/SymbolVisibility.rst | 126 +++++ docs/TechnicalIntroduction.rst | 265 ++++++++-- docs/TheoryDeepPixels.rst | 12 +- docs/about.rst | 124 +++++ docs/concepts.rst | 19 + docs/conf.py | 14 +- docs/images/openexr-horizontal-color.png | Bin 0 -> 17103 bytes docs/images/windowExample1.small.png | Bin 0 -> 89159 bytes docs/index.rst | 133 ++--- INSTALL.md => docs/install.rst | 294 ++++++----- docs/license.rst | 33 ++ docs/requirements.txt | 2 + docs/src/reader/CMakeLists.txt | 7 + docs/src/reader/build.sh | 3 + docs/src/reader/reader.cpp | 25 + docs/src/writer/CMakeLists.txt | 7 + docs/src/writer/build.sh | 3 + docs/src/writer/writer.cpp | 25 + docs/toc_redirect.rst | 33 ++ 39 files changed, 1785 insertions(+), 518 deletions(-) create mode 100644 cmake/FindPythonPackage.cmake create mode 100644 docs/API.rst create mode 100644 docs/HelloWorld.rst create mode 100644 docs/PortingGuide.rst delete mode 100644 docs/SymbolVisibility.md create mode 100644 docs/SymbolVisibility.rst create mode 100644 docs/about.rst create mode 100644 docs/concepts.rst create mode 100644 docs/images/openexr-horizontal-color.png create mode 100644 docs/images/windowExample1.small.png rename INSTALL.md => docs/install.rst (57%) create mode 100644 docs/license.rst create mode 100644 docs/src/reader/CMakeLists.txt create mode 100755 docs/src/reader/build.sh create mode 100644 docs/src/reader/reader.cpp create mode 100644 docs/src/writer/CMakeLists.txt create mode 100755 docs/src/writer/build.sh create mode 100644 docs/src/writer/writer.cpp create mode 100644 docs/toc_redirect.rst diff --git a/CHANGES.md b/CHANGES.md index 2d1ec9dc01..1fa7e5d4ec 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,6 @@ + + + # OpenEXR Release Notes * [Version 3.1.5](#version-315-april-11-2022) April 11, 2022 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 160ef4cbe6..33b4e37762 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,3 +1,6 @@ + + + # Code of Conduct The OpenEXR project abides by Linux Foundation's code of conduct, diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2c5248d13d..d9b8d27989 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,6 @@ + + + # Contributing to OpenEXR Thank you for your interest in contributing to OpenEXR. This document @@ -13,7 +16,7 @@ explains our contribution process and procedures: For a description of the roles and responsibilities of the various members of the OpenEXR community, see [GOVERNANCE](GOVERNANCE.md), and for further details, see the OpenEXR project's [Technical -Charter](https://github.com/AcademySoftwareFoundation/openexr/blob/main/ASWF/charter/OpenEXR-Technical-Charter.md). Briefly, +Charter](ASWF/charter/OpenEXR-Technical-Charter.md). Briefly, a "contributor" is anyone who submits content to the project, a "committer" reviews and approves such submissions, and the "Technical Steering Committee" provides general project oversight and governance. diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index abe3d33905..9fde40b23f 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,3 +1,6 @@ + + + This is a list of contributors to the OpenEXR project, sorted alphabetically by first name. diff --git a/GOVERNANCE.md b/GOVERNANCE.md index 61c6eaa1ec..d985eff038 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -1,3 +1,6 @@ + + + # OpenEXR Project Roles and Responsibilities OpenEXR is a project of the Academy Software Foundation and relies on diff --git a/LICENSE.md b/LICENSE.md index b2a016ed19..0443514b78 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,3 +1,6 @@ + + + Copyright (c) Contributors to the OpenEXR Project. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/README.md b/README.md index 4df5b50015..3937f3a54b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ + + + [![License](https://img.shields.io/github/license/AcademySoftwareFoundation/openexr)](LICENSE.md) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/2799/badge)](https://bestpractices.coreinfrastructure.org/projects/2799) [![Build Status](https://github.com/AcademySoftwareFoundation/openexr/workflows/CI/badge.svg)](https://github.com/AcademySoftwareFoundation/openexr/actions?query=workflow%3ACI) @@ -6,7 +9,7 @@ # OpenEXR - + OpenEXR provides the specification and reference implementation of the EXR file format, the professional-grade image storage format of the @@ -20,103 +23,7 @@ OpenEXR is widely used in host application software where accuracy is critical, such as photorealistic rendering, texture access, image compositing, deep compositing, and DI. -### About OpenEXR - -OpenEXR is a project of the [Academy Software -Foundation](https://www.aswf.io). The format and library were -originally developed by Industrial Light & Magic and first released -in 2003. Weta Digital, Walt Disney Animation Studios, Sony Pictures -Imageworks, Pixar Animation Studios, DreamWorks, and other studios, -companies, and individuals have made contributions to the code base. - -OpenEXR is included in the [VFX Reference -Platform](https://vfxplatform.com). - -### OpenEXR Features - -* High dynamic range and color precision. -* Support for 16-bit floating-point, 32-bit floating-point, and - 32-bit integer pixels. -* Multiple image compression algorithms, both lossless and lossy. Some of - the included codecs can achieve 2:1 lossless compression ratios on images - with film grain. The lossy codecs have been tuned for visual quality and - decoding performance. -* Extensibility. New compression codecs and image types can easily be added - by extending the C++ classes included in the OpenEXR software distribution. - New image attributes (strings, vectors, integers, etc.) can be added to - OpenEXR image headers without affecting backward compatibility with - existing OpenEXR applications. -* Support for stereoscopic image workflows and a generalization - to multi-views. -* Flexible support for deep data: pixels can store a variable-length list - of samples and, thus, it is possible to store multiple values at different - depths for each pixel. Hard surfaces and volumetric data representations - are accommodated. -* Multipart: ability to encode separate, but related, images in one file. - This allows for access to individual parts without the need to read other - parts in the file. -* Versioning: OpenEXR source allows for user configurable C++ - namespaces to provide protection when using multiple versions of the - library in the same process space. - -### OpenEXR and Imath Version 3 - -With the release of OpenEXR 3, the Imath library formerly distributed -via the IlmBase component of OpenEXR is now an independent library -dependency, available for download from https://github.com/AcademySoftwareFoundation/Imath. -You can choose to build OpenEXR against an external installation of -Imath, or the default CMake configuration will download and build it -automatically during the OpenEXR build process. Note that the half -16-bit floating point data type is included in Imath. - -See the [porting -guide](https://github.com/AcademySoftwareFoundation/Imath/blob/master/docs/PortingGuide2-3.md) -for details about differences from previous releases and how to -address them. Also refer to the porting guide for details about -changes to Imath. - -#### New Features in OpenEXR v3.1 - -The 3.1 release of OpenEXR introduces a new library, OpenEXRCore, -which is the result of a significant re-thinking of how OpenEXR -manages file I/O and provides access to image data. It begins to -address long-standing scalability issues with multithreaded image -reading and writing. - -The OpenEXRCore library provides thread-safe, non-blocking access to -files, which was not possible with the current API, where the -framebuffer management is separate from read requests. It is written -entirely in C and provides a new C-language API alongside the existing -C++ API. This new low-level API allows applications to do custom -unpacking of EXR data, such as on the GPU, while still benefiting from -efficient I/O, file validation, and other semantics. It provides -efficient direct access to EXR files in texturing applications. This C -library also introduces an easier path to implementing OpenEXR -bindings in other languages, such as Rust. - -The 3.1 release represents a technology preview for upcoming -releases. The initial release is incremental; the existing API and -underlying behavior has not changed. The new API is available now for -performance validation testing, and then in future OpenEXR releases, -the C++ API will migrate to use the new core in stages. It is not the -intention to entirely deprecate the C++ API, nor must all applications -re-implement EXR I/O in terms of the C library. The C API does not, -and will not, provide the rich set of utility classes that exist in -the C++ layer. The 3.1 release of the OpenEXRCore library simply -offers new functionality for specialty applications seeking the -highest possible performance. In the future, the ABI will evolve, but -the API will remain consistent, or only have additions. - -See [Reading and Writing OpenEXR Image Files with the C-language -API](https://openexr.readthedocs.io/en/latest/OpenEXRCoreAPI.html) -for more information. - -### Supported Platforms - -OpenEXR builds on Linux, macOS, Microsoft Windows, and is -cross-compilable on other systems. - -### OpenEXR Project Mission +## OpenEXR Project Mission The goal of the OpenEXR project is to keep the EXR format reliable and modern and to maintain its place as the preferred image format for @@ -141,72 +48,108 @@ correctness and verifiability, and breadth of adoption. Imath is not intended to be a comprehensive linear algebra or numerical analysis package. -### OpenEXR Project Governance +# Project Governance -OpenEXR is hosted by the Academy Software Foundation. See -[GOVERNANCE](GOVERNANCE.md) for more information about how the project -operates. +OpenEXR is a project of the [Academy Software +Foundation](https://www.aswf.io). See the project's [governance +policies](GOVERNANCE.md), [contribution guidelines](CONTRIBzuTING.md), and [code of conduct](CODE_OF_CONDUCT) +for more information. -The OpenEXR project is dedicated to promoting a harassment-free -community. Read our [code of conduct](CODE_OF_CONDUCT.md). +# Quick Start -## Developer Quick Start +See the [technical documentation](https://openexr.readthedocs.io) for +complete details, but to get started, the "hello, world" `.exr` writer program is: -See [INSTALL](INSTALL.md) for instructions on downloading and building OpenEXR -from source. + #include + #include + #include + + int + main() + { + try { + int width = 10; + int height = 10; + + Imf::Array2D pixels(width, height); + for (int y=0; y + + # Security Policy ## Reporting a Vulnerability diff --git a/cmake/FindPythonPackage.cmake b/cmake/FindPythonPackage.cmake new file mode 100644 index 0000000000..2e1a81169b --- /dev/null +++ b/cmake/FindPythonPackage.cmake @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright Contributors to the OpenColorIO Project. +# +# Locate a Python package +# +# Variables defined by this module: +# _FOUND +# +# Usage: +# find_python_package(Jinja2 2.10.1) +# +# If the package is not installed in a standard path, add it to the PYTHONPATH +# environment variable before running CMake. +# + +find_package(Python QUIET COMPONENTS Interpreter) + +macro(find_python_package package) + # Some Python packages have "-" in the PyPi name, but are replaced with "_" + # in the actual package name. + string(REPLACE "-" "_" _PKG_IMPORT ${package}) + + # Parse options + foreach(_ARG ${ARGN}) + if(_ARG STREQUAL "REQUIRED") + set(_PKG_REQUIRED TRUE) + endif() + if(_PREV_ARG STREQUAL "REQUIRES") + set(_PKG_REQUIRES ${_ARG}) + endif() + set(_PREV_ARG ${_ARG}) + endforeach() + + if(NOT TARGET ${package}) + add_custom_target(${package}) + if(_PKG_REQUIRES) + add_dependencies(${package} ${_PKG_REQUIRES}) + unset(_PKG_REQUIRES) + endif() + set(_${package}_TARGET_CREATE TRUE) + endif() + + set(_PKG_INSTALL TRUE) + + # Try importing Python package + execute_process( + COMMAND + "${Python_EXECUTABLE}" -c "import ${_PKG_IMPORT}" + RESULT_VARIABLE + _PKG_IMPORT_RESULT + OUTPUT_QUIET ERROR_QUIET + ) + + if(_PKG_IMPORT_RESULT EQUAL 0) + set(${package}_FOUND TRUE) + + # Get the package's location + execute_process( + COMMAND + "${Python_EXECUTABLE}" -c + "import ${_PKG_IMPORT}, os; print(os.path.dirname(${_PKG_IMPORT}.__file__))" + OUTPUT_VARIABLE + _PKG_DIR + ERROR_QUIET + ) + string(STRIP "${_PKG_DIR}" _PKG_DIR) + message(STATUS "Found ${package}: ${_PKG_DIR}") + + else() + set(${package}_FOUND FALSE) + set(_FIND_ERR "Could NOT find ${package} (import ${_PKG_IMPORT} failed)") + + if(_PKG_REQUIRED) + message(FATAL_ERROR "${_FIND_ERR}") + endif() + message(STATUS "${_FIND_ERR}") + endif() + +endmacro() diff --git a/docs/API.rst b/docs/API.rst new file mode 100644 index 0000000000..8c98d26803 --- /dev/null +++ b/docs/API.rst @@ -0,0 +1,21 @@ +.. + SPDX-License-Identifier: BSD-3-Clause + Copyright Contributors to the OpenEXR Project. + +.. _The OpenEXR API: + +The OpenEXR API +############### + +.. toctree:: + :caption: API + :maxdepth: 2 + + HelloWorld + ReadingAndWritingImageFiles + OpenEXRCoreAPI + PortingGuide + SymbolVisibility + +* :ref:`genindex` + diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index e3f363fda4..644f754885 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -6,6 +6,9 @@ set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) find_package(Doxygen REQUIRED) find_package(Sphinx REQUIRED) +include(FindPythonPackage) +find_python_package(sphinx-press-theme REQUIRED) + set(DOXYGEN_INPUT_DIR ${PROJECT_SOURCE_DIR}/src/lib/OpenEXRCore) set(DOXYGEN_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/doxygen) set(DOXYGEN_INDEX_FILE ${DOXYGEN_OUTPUT_DIR}/html/index.html) diff --git a/docs/HelloWorld.rst b/docs/HelloWorld.rst new file mode 100644 index 0000000000..bb5846bedb --- /dev/null +++ b/docs/HelloWorld.rst @@ -0,0 +1,43 @@ +.. + SPDX-License-Identifier: BSD-3-Clause + Copyright Contributors to the OpenEXR Project. + +.. _Hello: + +Hello, World +############ + +.. toctree:: + :caption: Hello, World + :maxdepth: 1 + +A simple program to write a simple ``.exr`` file of an image of 10x10 +pixels with values that are a ramp in green and blue: + +.. literalinclude:: src/writer/writer.cpp + +And the ``CMakeLists.txt`` file to build: + +.. literalinclude:: src/writer/CMakeLists.txt + +To build: + +.. literalinclude:: src/writer/build.sh + +For more details, see :ref:`The OpenEXR API`. + +And a simple program to read an ``.exr`` file: + +.. literalinclude:: src/reader/reader.cpp + + +And the ``CMakeLists.txt`` file to build: + +.. literalinclude:: src/reader/CMakeLists.txt + +To build: + +.. literalinclude:: src/reader/build.sh + + + diff --git a/docs/InterpretingDeepPixels.rst b/docs/InterpretingDeepPixels.rst index b5846f9c2d..ca0ace131e 100644 --- a/docs/InterpretingDeepPixels.rst +++ b/docs/InterpretingDeepPixels.rst @@ -1,6 +1,6 @@ .. SPDX-License-Identifier: BSD-3-Clause - Copyright (c) Contributors to the OpenEXR Project. + Copyright Contributors to the OpenEXR Project. Interpreting OpenEXR Deep Pixels ################################ @@ -189,6 +189,7 @@ the following table: .. list-table:: :header-rows: 1 + :align: left * - Color or auxiliary channel base name - Matching alpha channel base name @@ -209,6 +210,7 @@ channel. .. list-table:: :header-rows: 1 + :align: left * - Channel name - Associated alpha channel @@ -427,22 +429,18 @@ total opacity and color are the same as in the original sample. For the depth channels, the new samples are: -.. list-table:: - - * - .. math:: S_{i,new}\left( Z \right) = \ S_{i}\left( Z \right) - - .. math:: S_{i + 1,new}\left( Z \right) = \ z - * - .. math:: S_{i,new}\left( \text{ZBack} \right) = \ z - - .. math:: S_{i + 1,new}\left( \text{ZBack} \right) = \ S_{i}\left( \text{ZBack} \right) +.. math:: S_{i,new}\left( Z \right) = \ S_{i}\left( Z \right) +.. math:: S_{i + 1,new}\left( Z \right) = \ z +.. math:: S_{i,new}\left( \text{ZBack} \right) = \ z +.. math:: S_{i + 1,new}\left( \text{ZBack} \right) = \ S_{i}\left( \text{ZBack} \right) For a color channel, ``c``, and its associated alpha channel, :math:`\alpha`, the new samples are: -.. list-table:: - - * - .. math:: S_{i,new}\left( \alpha \right) = \alpha_{i}(z) - - .. math:: S_{i + 1,new}\left( \alpha \right) = \alpha_{i}({S_{i}\left( Z \right) + S}_{i}\left( \text{ZBack} \right) - z) - * - .. math:: S_{i,new}\left( c \right) = c_{i}(z) - - .. math:: S_{i + 1,new}\left( c \right) = c_{i}\left( {S_{i}\left( Z \right) + S}_{i}\left( \text{ZBack} \right) - z \right) +.. math:: S_{i,new}\left( \alpha \right) = \alpha_{i}(z) +.. math:: S_{i + 1,new}\left( \alpha \right) = \alpha_{i}({S_{i}\left( Z \right) + S}_{i}\left( \text{ZBack} \right) - z) +.. math:: S_{i,new}\left( c \right) = c_{i}(z) +.. math:: S_{i + 1,new}\left( c \right) = c_{i}\left( {S_{i}\left( Z \right) + S}_{i}\left( \text{ZBack} \right) - z \right) If it is not done exactly right, splitting a sample can lead to large rounding errors for the colors of the new samples when the opacity of diff --git a/docs/MultiViewOpenEXR.rst b/docs/MultiViewOpenEXR.rst index 71341ad693..58f827a3c6 100644 --- a/docs/MultiViewOpenEXR.rst +++ b/docs/MultiViewOpenEXR.rst @@ -1,6 +1,6 @@ .. SPDX-License-Identifier: BSD-3-Clause - Copyright (c) Contributors to the OpenEXR Project. + Copyright Contributors to the OpenEXR Project. Storing Multi-View Images in OpenEXR Files ########################################## @@ -259,6 +259,7 @@ For example, the following table shows several different combinations of .. list-table:: :header-rows: 1 + :align: left * - views listed in ``multiView`` attribute - channel names diff --git a/docs/OpenEXRCoreAPI.rst b/docs/OpenEXRCoreAPI.rst index c5869bd39d..90aaf856dd 100644 --- a/docs/OpenEXRCoreAPI.rst +++ b/docs/OpenEXRCoreAPI.rst @@ -1,9 +1,9 @@ .. SPDX-License-Identifier: BSD-3-Clause - Copyright (c) Contributors to the OpenEXR Project. + Copyright Contributors to the OpenEXR Project. -Reading and Writing OpenEXR Image Files with the C-language API -############################################################### +Reading and Writing Image Files with the C-language API +####################################################### The OpenEXRCore library has a few notable features to consider prior to beginning use: @@ -261,7 +261,7 @@ Context .. doxygentypedef:: exr_context_t .. doxygentypedef:: exr_const_context_t -.. doxygenstruct:: _exr_context_initializer +.. doxygenstruct:: _exr_context_initializer_v3 :members: .. doxygentypedef:: exr_context_initializer_t @@ -285,7 +285,7 @@ Decoding Encoding ^^^^^^^^ -.. doxygenenum:: transcoding_pipeline_buffer_id +.. doxygenenum:: exr_transcoding_pipeline_buffer_id .. doxygenstruct:: _exr_encode_pipeline :members: diff --git a/docs/OpenEXRFileLayout.rst b/docs/OpenEXRFileLayout.rst index b55dc7f3a3..d028b11151 100644 --- a/docs/OpenEXRFileLayout.rst +++ b/docs/OpenEXRFileLayout.rst @@ -1,6 +1,6 @@ .. SPDX-License-Identifier: BSD-3-Clause - Copyright (c) Contributors to the OpenEXR Project. + Copyright Contributors to the OpenEXR Project. OpenEXR File Layout ################### @@ -47,7 +47,8 @@ the file layout are required to support the new multi-part and deep data features: .. list-table:: - + :align: left + * - Feature - Description - See @@ -97,7 +98,8 @@ start of the file). OpenEXR uses the following six integer data types: .. list-table:: - + :align: left + * - name - signed - size in bytes @@ -137,6 +139,7 @@ The following table lists the names and sizes of OpenEXR's floating-point data types: .. list-table:: + :align: left * - name - size in bytes @@ -308,6 +311,7 @@ All valid combinations of the version field bits are as follows: .. list-table:: :header-rows: 1 + :align: left * - Description - Compatible with @@ -428,6 +432,7 @@ attributes: .. list-table:: :header-rows: 1 + :align: left * - attribute name - attribute type @@ -459,6 +464,7 @@ one or more tiles: .. list-table:: :header-rows: 1 + :align: left * - attribute name - attribute type @@ -480,6 +486,7 @@ This attribute can be used in the header for multi-part files: .. list-table:: :header-rows: 1 + :align: left * - attribute name - attribute type @@ -496,6 +503,7 @@ deep data OpenEXR files. .. list-table:: :header-rows: 1 + :align: left * - attribute name - attribute type @@ -534,6 +542,7 @@ deep data (deepscanline or deeptile): .. list-table:: :header-rows: 1 + :align: left * - attribute name - attribute type @@ -635,6 +644,7 @@ same format: .. list-table:: :header-rows: 1 + :align: left * - part type - type attribute @@ -662,6 +672,7 @@ may be stored together as a scan line block. The number of scan lines per block depends on how the pixel data are compressed: .. list-table:: + :align: left * - ``NO_COMPRESSION`` - 1 diff --git a/docs/PortingGuide.rst b/docs/PortingGuide.rst new file mode 100644 index 0000000000..6a9fc150eb --- /dev/null +++ b/docs/PortingGuide.rst @@ -0,0 +1,605 @@ +.. + SPDX-License-Identifier: BSD-3-Clause + Copyright Contributors to the OpenEXR Project. + +.. _porting: + +OpenEXR/Imath 2.x to 3.x Porting Guide +###################################### + +This porting guide outlines the several areas where switching from OpenEXR +2.x to OpenEXR 3.x + Imath 3.x will require source code or build changes of +downstream software. + +In each case, we will often explain both how to change if you are expecting +3.x only hereafter, or usually a more complex accommodation if you want to +keep compatibility with both 2.x and 3.x. + +OpenEXR and Imath Are Different Packages +======================================== + +If your use of OpenEXR was only for the sake of using the math classes and +utilities, maybe you were unhappy that you needed to download and build the +full OpenEXR dependency. You are in luck -- now Imath is a separate, very +lightweight open source package. You can use Imath functionality without +needing any of OpenEXR, which as of 3.x only includes the parts you need to +read and write OpenEXR image files. + +The parts of "IlmBase" that were ``Imath`` and ``half`` are now repackaged +as the ``Imath`` library. The ``IlmThread`` and ``Iex`` libraries have been +folded into the OpenEXR package, since they were were not necessary to +the rest of Imath. + +When building OpenEXR 3.x, note that if Imath 3.x library is not found +already installed at build time, it will be automatically downloaded and +built as part of the OpenEXR build. + +Background +========== + +Why is this happening? Here is the relevant history. + +The OpenEXR project has historically consisted of four separate subprojects: + +* ``OpenEXR`` - the Imf image format +* ``IlmBase`` - supporting utilities (Imath, Half, Iex, IlmThread) +* ``PyIlmBase`` - python bindings for the IlmBase libraries +* ``OpenEXR_Viewers`` - code for an example EXR image viewer + +Prior to the 2.4 release in 2019, OpenEXR relied primarily on the Gnu +autotools build system and was released as four separate tarballs +(ilmbase, pyilmbase, openexr, openexr_viewers) that were constructed +via the Gnu tools. This gave direct access to the "IlmBase" libraries +independent of the OpenEXR format library. The project also included +CMake files but CMake support was incomplete. + +With the adoption of OpenEXR by the Academy Software Foundation in +2019, the technical steering committee made several key changes: + +1. Drop support for autotools in favor of CMake. A significant portion + of the OpenEXR user base uses Windows, which the Gnu autotools does + not support. Supporting two build systems is a maintenance burden + that the TSC opted to avoid. We now assume that all modern users of + OpenEXR can reasonably be expected to rely on CMake. + +2. Rely on GitHub's automatic release packaging mechanism. This + packages the entire contents of package in a single + tarball. Separate tarballs are no longer generated by the Gnu + autotools setup. + +3. Deprecate the OpenEXR_Viewers code. It was impossibly out of date + and of little modern value. + +Thus, with the 2.4 release, the "IlmBase" libraries are no longer +distributed in a form that is readily separable from the rest of +OpenEXR. The build and installation process for the overall OpenEXR +project is complicated by the fact it consists of four separate +projects, which added signifcant complexity to the CMake setup. + +Because Imath is generally useful to the community, the TSC decided to +simplify the configuration by separating Imath into its own independent +project, maintained and released independently of OpenEXR, and +introducing it as a new external dependency of OpenEXR. + +To further simplify matters, the new Imath library includes the half +data type directly, rather than maintaining it in a separate +library. Also, the community at large has a strong desire for simple +vector/matrix utilities that are unencumbered by Iex, the IlmBase +library that provides higher-level exception classes, and even +further, a clear delineation between functionality that (1) relies on +exception handlings and (2) is free from exceptions. As a result, +support for Iex has been removed from Imath, and the Iex library is +now packaged as a component of OpenEXR. + +The Imath python bindings are a part of Imath as a configuration +option, although support is off by default to simplify the build process +for most users. + +New Library Names and Repository Structures +=========================================== + +The new repositories place all source code under the ``src`` top-level +subdirectory. + +Imath: +------ + +.. code-block:: + + src + ├── Imath + ├── ImathTest + └── python + ├── config + ├── PyImath + ├── PyImathNumpy + ├── PyImathTest + ├── PyImathNumpyTest + └── PyImathSpeedTest + + +OpenEXR: +-------- + +The ``IlmImf`` library has been renamed ``OpenEXR``. No header files have +changed names, only their locations in the repo have changes. + +.. code-block:: + + src + ├── bin + │ ├── exr2aces + │ ├── exrbuild + │ ├── exrcheck + │ ├── exrenvmap + │ ├── exrheader + │ ├── exrmakepreview + │ ├── exrmaketiled + │ ├── exrmultipart + │ ├── exrmultiview + │ └── exrstdattr + ├── lib + │ ├── Iex + │ ├── IexMath + │ ├── IlmThread + │ ├── OpenEXR + │ └── OpenEXRUtil + ├── examples + └── test + ├── IexTest + ├── OpenEXRTest + ├── OpenEXRUtilTest + └── OpenEXRFuzzTest + + +Finding and Using OpenEXR and Imath CMake Configs +================================================= + +OpenEXR/Imath 3.x Only +---------------------- + +If you are *only* concerned with OpenEXR/Imath 3.x going forward, this is +the recommended way to find the libraries in a downstream project that uses +the CMake build system: + +.. code-block:: + + find_package(Imath CONFIG) + find_package(OpenEXR CONFIG) + +Note that the second line may be omitted if you only need the Imath +portions. + +And then your project can reference the imported targets like this: + +.. code-block:: + + target_link_libraries (my_target + PRIVATE + OpenEXR::OpenEXR + Imath::Imath + Imath::Half + ) + +You only need the parts you use, so for example, if you only need Half and +Imath, you can omit the OpenEXR target. Also note that in our example above, +we have used the ``PRIVATE`` label, but you should specify them as ``PUBLIC`` if +you are exposing those classes in your own package's public interface. + + +Accommodating OpenEXR/Imath 3.x or OpenEXR 2.x +---------------------------------------------- + +On the other hand, to accommodate both 2.x and 3.x, it's admittedly +inconvenient because the packages and the import targets have changed their +names. We have found the following idioms to work: + +Finding either/both packages: + +.. code-block:: + + # First, try to find just the right config files + find_package(Imath CONFIG) + if (NOT TARGET Imath::Imath) + # Couldn't find Imath::Imath, maybe it's older and has IlmBase? + find_package(IlmBase CONFIG) + endif () + find_package(OpenEXR CONFIG) + +To link against them, we use CMake generator expressions so that we can +reference *both* sets of targets, but it will only use the ones +corresponding to the package version that was found. + +.. code-block:: + + target_link_libraries (my_target + PRIVATE + # For OpenEXR/Imath 3.x: + $<$:OpenEXR::OpenEXR> + $<$:Imath::Imath> + $<$:Imath::Half> + # For OpenEXR 2.4/2.5: + $<$:OpenEXR::IlmImf> + $<$:IlmBase::Imath> + $<$:IlmBase::Half> + $<$:IlmBase::IlmThread> + $<$:IlmBase::Iex> + ) + +Again, you can eliminate the references to any of the individual libaries +that you don't actually need for your application. + +Simultaneous Static/Shared Build +-------------------------------- + +The OpenEXR 2.x CMake configuration had options to simultaneously +build both shared and statically linked libraries. This has been +deprecated. A CMake configuration setting specifies whether to build +static or shared, but if you want both, you will need to run cmake and +build twice. + +Simultaneous Python 2/3 Build +----------------------------- + +The PyIlmBase 2.x CMake configuration had options to simultaneously +build both python2 and python3 bindings. This has been deprecated. +A CMake configuration setting specifies whether to build for +python 2 or python 3, but if you want both, you will need to run +cmake and build twice. + +Imath Include Files Are in a Different Subdirectory +=================================================== + +Imath 3.0 will copy its headers to some ``include/Imath`` subdirectory +instead of the old ``include/OpenEXR``. + +OpenEXR/Imath 3.x Only +---------------------- + +If you know that you are only using Imath 3.x, then just change any +include directions, like this: + +.. code-block:: + + #include + #include + +to the new locations: + +.. code-block:: + + #include + #include + +Accommodating OpenEXR/Imath 3.x or OpenEXR 2.x +---------------------------------------------- + +If you want your software to be able to build against either OpenEXR 2.x or +3.x (depending on which dependency is available at build time), we recommend +using a more complicated idiom: + +.. code-block:: + + // The version can reliably be found in this header file from OpenEXR, + // for both 2.x and 3.x: + #include + #define COMBINED_OPENEXR_VERSION ((10000*OPENEXR_VERSION_MAJOR) + \ + (100*OPENEXR_VERSION_MINOR) + \ + OPENEXR_VERSION_PATCH) + + // There's just no easy way to have an ``#include`` that works in both + // cases, so we use the version to switch which set of include files we + // use. + #if COMBINED_OPENEXR_VERSION >= 20599 /* 2.5.99: pre-3.0 */ + # include + # include + #else + // OpenEXR 2.x, use the old locations + # include + # include + #endif + +Include Files Include Fewer Other Headers +========================================= + +Extraneous ``#include`` statements have been removed from some header +files, which can lead to compile failures in application code that +previously included certain headers indirectly. + +For example, the Imath header files no longer include ``float.h``, so +application code that references symbols such as ``FLT_MAX`` may need +to add an explicit ``#include `` or equivalent. + +If your application code reports compile errors due to undefined or +incompletely-defined Imath or OpenEXR data types, locate the Imath or +OpenEXR header file that defines the type and include it explicitly. + +## Symbols Are Hidden by Default + +To reduce library size and make linkage behavior similar across +platforms, Imath and OpenEXR now build with directives that make +symbol visibility hidden by default, with specific externally-visible +symbols explicitly marked for export. See the [Symbol +Visibility](https://github.com/AcademySoftwareFoundation/openexr/blob/main/docs/SymbolVisibility.md) +doc and the appropriate ``*Export.h`` header file for more details. + +Imath Now Uses Standard C++ Exceptions and ``noexcept`` +======================================================= + +In OpenEXR 2.x, the Imath functions that threw exceptions used to throw +various Iex varieties. + +In Imath 3.x, these functions just throw ``std::exception`` varieties that +correspond to the failure (e.g., ``std::invalid_argument``, +``std::domain_error``, etc.). For that reason, all of the Iex exceptions are +now only part of the OpenEXR library (where they are still used in the same +manner they were for OpenEXR 2.x). + +Imath 3.x has very few functions that throw exceptions. Each is clearly +marked as such, and each has a version that does not throw exceptions (so +that it may be used from code where exceptions are avoided). The functions +that do not throw exceptions are now marked ``noexcept``. + +Some Headers and Classes Have Been Removed from Imath 3.x +========================================================= + +* The ``Math`` class (and ``ImathMath.h`` header file) are + deprecated. All of the ``Math`` functionality is subsumed by C++11 + ``std::`` math functions. For example, calls to + ``Imath::Math::abs(x)`` should be replaced with ``std::abs(x)``. + +* The ``Limits`` class (and the ``ImathLimits.h`` and + ``ImathHalfLimits.h`` headers) have been removed entirely. All uses of + ``Limits<>`` should be replaced with the appropriate + ``std::numeric_limits<>`` method call. The Imath-specific versions + predated C++11, and were not only redundant in a C++11 world, but + also potentially confusing because some of their functions behaved + quite differently than the ``std::numeric_limits`` method with the + same name. We are following the precept that if C++11 does something + in a standard way, we should not define our own equivalent function + (and especially not define it in a way that doesn't match the + standard behavior). + +* ``Vec::normalize()`` and ``length()`` methods, for integer ``T`` types, + have been removed. Also the standalone ``project()`` and + ``orthogonal()`` functions are no longer defined for vectors made of + integer elements. These all had behavior that was hard to understand + and probably useless. They still work as expected for vectors of + floating-point types. + +* The ``Int64`` and ``SInt64`` types are deprecated in favor of the + now-standard ``int64_t`` and ``uint64_t``. + +File/Class-specific Changes +=========================== + +``half`` in ``half.h`` +---------------------- + +* The half type is now in the ``Imath`` namespace, but a compile-time + option puts it in the global namespace, except when compiling for + CUDA, in which case the 'half' type refers to the CUDA type: + +.. code-block:: + + #ifndef __CUDACC__ + using half = IMATH_INTERNAL_NAMESPACE::half; + #else + #include + #endif + + If you desire to use Imath::half inside a CUDA kernal, you can refer + to it via the namespace, or define ``CUDA_NO_HALF`` to avoid the CUDA + type altogether. + +* ``HALF_MIN`` has changed value. It is now the smallest **normalized** + positive value, returned by ``std::numeric_limits::min()``. + +* New constructor from a bit pattern: + +.. code-block:: + + enum FromBitsTag + { + FromBits + }; + + constexpr half(FromBitsTag, unsigned short bits) noexcept; + +``Imath::Box`` in ``ImathBox.h`` +----------------------------------- + +* ``baseTypeMin()`` is replaced with ``baseTypeLowest()`` + +``Color3``, ``Color4`` in ``ImathColor.h`` +------------------------------------------------ + +* ``baseTypeMin()`` is replaced with ``baseTypeLowest()`` + +``Imath::Frustum`` in ``ImathFrustum.h`` +------------------------------------------- + +Akin to the ``Vec`` classes, there are now seperate API calls for +throwing and non-throwing functions: + +These functions previously threw exceptions but now do not throw and +are marked ``noexcept``: + +* ``Frustum::projectionMatrix() noexcept`` + +* ``Frustum::aspect() noexcept`` + +* ``Frustum::set() noexcept`` + +* ``Frustum::projectPointToScreen() noexcept`` + +* ``Frustum::ZToDepth() noexcept`` + +* ``Frustum::DepthToZ() noexcept`` + +* ``Frustum::screenRadius() noexcept`` + +* ``Frustum::localToScreen() noexcept`` + +These functions throw ``std::domain_error`` exceptions when the +associated frustum is degenerate: + +* ``Frustum::projectionMatrixExc()`` + +* ``Frustum::aspectExc()`` + +* ``Frustum::setExc()`` + +* ``Frustum::projectPointToScreenExc()`` + +* ``Frustum::ZToDepthExc()`` + +* ``Frustum::DepthToZExc()`` + +* ``Frustum::screenRadiusExc()`` + +* ``Frustum::localToScreenExc()`` + +``Imath::Interval`` in ``ImathInterval.h`` +--------------------------------------------- + +New methods/functions: + +* ``Interval::operator !=`` + +* ``Interval::makeInfinite()`` + +* ``IntervalisInfinite()`` + +* ``operator<< (std::ostream& s, const Interval&)`` + +``ImathMatrixAlgo.h`` +--------------------- + +* ``checkForZeroScaleInRow()`` and ``extractAndRemoveScalingAndShear()`` + throw ``std::domain_error`` exceptions instead of ``Iex::ZeroScale`` + +``Matrix22``, ``Matrix33``, ``Matrix44`` in ``ImathMatrix.h`` +---------------------------------------------------------------------- + +* ``baseTypeMin()`` is replaced with ``baseTypeLowest()`` + +* ``invert(bool singExc = false)`` is replace by: + + - ``invert() noexcept`` + + - ``invert(bool)`` which optionally throws an ``std::invalid_argument`` + exception. + +* ``inverse(bool singExc = false)`` is replace by: + + - ``inverse() noexcept`` + + - ``inverse(bool)`` which optionally throws an ``std::invalid_argument`` + exception. + +* ``gjInvert(bool singExc = false)`` is replace by: + + - ``gjInvert()`` noexcept + + - ``gjInvert(bool)`` which optionally throws an + ``std::invalid_argument`` exception. + +* ``gJinverse(bool singExc = false)`` is replace by: + + - ``gjInverse()`` noexcept + + - ``gjInverse(bool)`` which optionally throws an + ``std::invalid_argument`` exception. + +New functions: + +* ``operator<< (std::ostream& s, const Matrix22&)`` + +* ``operator<< (std::ostream& s, const Matrix33&)`` + +* ``operator<< (std::ostream& s, const Matrix44&)`` + +Other changes: + +* Initialization loops unrolled for efficiency + +* inline added where appropriate + +``ImathRoots.h`` +---------------- + +* When compiling for CUDA, the ``complex`` type comes from ``thrust`` + rather than ``std`` + +``Shear6`` in ``ImathShear.h`` +------------------------------ + +* ``baseTypeMin()`` is replaced with ``baseTypeLowest()`` + +``ImathVecAlgo.h`` +------------------ + +The following functions are no longer defined for integer-based +vectors, because such behavior is not clearly defined: + +* ``project (const Vec& s, const Vec& t)`` + +* ``orgthogonal (const Vec& s, const Vec& t)`` + +* ``reflect (const Vec& s, const Vec& t)`` + +``Vec2``, ``Vec3``, ``Vec4`` in ``ImathVec.h`` +------------------------------------------------------- + +* ``baseTypeMin()`` is replaced with ``baseTypeLowest()`` + +* The following methods are removed (via ``= delete``) for integer-based + vectors because the behavior is not clearly defined and thus prone + to confusion: + + - ``length()`` - although the length is indeed defined, its proper value + is floating point and can thus not be represented by the 'T' + return type. + + - ``normalize()`` + + - ``normalizeExc()`` + + - ``normalizeNonNull()`` + + - ``normalized()`` + + - ``normalizedExc()`` + + - ``normalizedNonNull()`` + +* Interoperability Constructors: The Vec and Matrix classes now have + constructors that take as an argument any data object of similar + size and layout. + +Imath Python Changes +==================== + +In general, the changes in Imath at the C++ level are reflected in the +python bindings. In particular: + +* The following methods are removed for integer-based + vector and matrix objects and arrays: + + - ``length()`` + - ``normalize()`` + - ``normalizeExc()`` + - ``normalizeNonNull()`` + - ``normalized()`` + - ``normalizedExc()`` + - ``normalizedNonNull()`` + +* ``baseTypeMin()`` is replaced with ``baseTypeLowest()`` for: + + - ``Vec2``, ``Vec3``, ``Vec4`` + - ``Color3``, ``Color4`` + - ``Matrix22``, ``Matrix33``, ``Matrix44`` + - ``Box`` + - ``Shear6`` + diff --git a/docs/ReadingAndWritingImageFiles.rst b/docs/ReadingAndWritingImageFiles.rst index 40ddbeb78c..94d921d0e3 100644 --- a/docs/ReadingAndWritingImageFiles.rst +++ b/docs/ReadingAndWritingImageFiles.rst @@ -1,9 +1,9 @@ .. SPDX-License-Identifier: BSD-3-Clause - Copyright (c) Contributors to the OpenEXR Project. + Copyright Contributors to the OpenEXR Project. -Reading and Writing OpenEXR Image Files with the OpenEXR Library -################################################################ +Reading and Writing Image Files with the OpenEXR Library +######################################################## Document Purpose and Audience ============================= @@ -41,7 +41,8 @@ the following eight C++ classes: .. list-table:: :header-rows: 1 - + :align: left + * - - tiles - scan lines @@ -801,6 +802,7 @@ each with a different resolution. Each version is called a stored in the file. There are three different level modes: .. list-table:: + :align: left * - ``ONE_LEVEL`` - The file contains only a single, full-resolution level. A ONE_LEVEL @@ -1914,6 +1916,7 @@ pixel locations and 3D directions. ``Envmap`` is an enumeration type. Two values are possible: .. list-table:: + :align: left * - ``ENVMAP_LATLONG`` - **Latitude-Longitude Map** The environment is projected onto @@ -1989,7 +1992,7 @@ To specify the compression algorithm, set the ``compression()`` value on the ``Header`` object: .. code-block:: - :linenos + :linenos: Header header (width, height); header.channels().insert ("G", Channel (HALF)); @@ -2042,7 +2045,7 @@ previous versions. The default DWA compression level is 45.0f. Alternatively, set the compression level on the ``Header`` object: .. code-block:: - :linenos + :linenos: Header header (width, height); header.channels().insert ("G", Channel (HALF)); diff --git a/docs/StandardOptionalAttributes.rst b/docs/StandardOptionalAttributes.rst index 2894093cc8..6b0eca5ecd 100644 --- a/docs/StandardOptionalAttributes.rst +++ b/docs/StandardOptionalAttributes.rst @@ -1,10 +1,13 @@ .. SPDX-License-Identifier: BSD-3-Clause - Copyright (c) Contributors to the OpenEXR Project. + Copyright Contributors to the OpenEXR Project. Standard Optional Attributes ############################ +.. toctree:: + :caption: Standard Optional Attributes + By default, OpenEXR files have the following attributes: **chromaticities** diff --git a/docs/SymbolVisibility.md b/docs/SymbolVisibility.md deleted file mode 100644 index 6133ead11c..0000000000 --- a/docs/SymbolVisibility.md +++ /dev/null @@ -1,103 +0,0 @@ -# Symbol Visibility in OpenEXR - -## Overview - -Managing symbol visibility in a C++ library can reduce library sizes, -and with the extra information, the optimizer may produce faster -code. To take advantage of this, OpenEXR 3.0 is switching to -explicitly manage symbols on all platforms, with a hidden-by-default -behavior on unix-based platforms. Managing symbols has always been -required for Windows DLLs, where one must explicitly tag functions for -import and export as appropriate. - -For C, this is trivial: just tag public functions or global variable -as default visibility and leave everything else defaulting to -hidden. However, in C++, this is not exactly the same story. Functions -and globals are of course the same. And class member functions are -largely the same, and other than the attribute specification -mechanics, follow the same rules between gcc, clang, and -msvc. However, types have richer information than they do in C. So, -unless extra work is done, concepts for RTTI like the typeinfo and the -vtable for virtual classes will be hidden, and not visible. These are -referred to as "vague" linkage objects in some discussions. - -It is with the "vague" linkage objects where different properties -arise. For example, if you have a template, it is happily instantiated -in multiple compile units. If the typeinfo is hidden for one library, -then this may cause things like dynamic_cast to fail because then the -same typeinfo is not used, and even though one might think that -ImfAttribute are the same in two places, because they -are instantiated in separate places, they may be considered different -types. To compound the issue, there are different rules for this in -different implementations. For example, a default gcc under linux -allows one to link against otherwise private "vague" linkage objects -such that the typeinfo ends up as the same entity. clang, for MacOS -anyway, follows a stricter approach and keeps those types separate, -perhaps due to the two level namespace they maintain for symbols. - -Unfortunately, this is not clearly discussed as an overview of the -differences between platforms, hence this document to add -clarity. Each compiler / platform describes their own behavior, but -not how that behaves relative to -others. [libc++](https://libcxx.llvm.org/docs/DesignDocs/VisibilityMacros.html) -from the llvm project is the closest to providing comparative -information, where by looking at how they define their macros and the -comments surrounding, one can infer the behavior among at least -windows DLL mode, then gcc vs. clang for unixen. Other compilers, for -example, Intel's icc, tend to adopt the behavior of the predominant -compiler for that platform (i.e. msvc under windows, gcc under linux), -and so can generally adopt that behavior and are ignored here. If this -is not true, the ifdef rules in the various library *Export.h headers -within OpenEXR may need to be adjusted, and this table updated. - -As a summary, below is a table of the attribute or declspec that needs -to be used for a particular C++ entity to be properly exported. This -does not address weak symbols, ABI versioning, and only focusing on -visibility. Under Windows DLL rules, if one exports the entire class, -it also exports the types for the member types as well, which is not -desired, so these are marked as N/A even though the compiler does -allow that to happen. - - -| C++ vs Compiler | MSVC | mingw | gcc | clang | -|-----------------|---------------------|---------------------|-----------------------|----------------------------| -| function | dllexport/dllimport | dllexport/dllimport | visibility("default") | visibility("default") | -| hide a function | N/A | N/A | visibility("hidden") | visibility("hidden") | -| class(typeinfo) | N/A | N/A | visibility("default") | visibility("default") | -| template class | N/A | N/A | visibility("default") | type_visibility("default") | -| template data | N/A | N/A | visibility("default") | visibility("default") | -| class template
instantiation | dllexport/dllimport | N/A | N/A | visibility("default") | -| enum | N/A | N/A | auto unhides (N/A) | type_visibility("default") | -| extern template | N/A | dllexport/dllimport | visibility("default") | visibility("default") | - -With this matrix in mind, we can see the maximal set of macros we need to -provide throughout the code. *NB*: This does not mean that we need to -declare all of these, just that they might be needed. `XXX` should be -substituted for the particular library name being compiled. - -| macro name | purpose | -|--------------------------------|------------------------------------------------------------------| -| `XXX_EXPORT` | one of export or import for windows, visibility for others | -| `XXX_EXPORT_TYPE` | for declaring a class / struct as public (for typeinfo / vtable) | -| `XXX_HIDDEN` | used to explicitly hide, especially members of types | -| `XXX_EXPORT_TEMPLATE_TYPE` | stating the template type should be visible | -| `XXX_EXPORT_EXTERN_TEMPLATE` | exporting template types (i.e. extern side of extern template) | -| `XXX_EXPORT_TEMPLATE_INSTANCE` | exporting specific template instantiations (in cpp code) | -| `XXX_EXPORT_TEMPLATE_DATA` | exporting templated data blocks | -| `XXX_EXPORT_ENUM` | exporting enum types | - -For a new library, the preference might be to call `XXX_EXPORT` -something like `XXX_FUNC`, and rename things such as `XXX_EXPORT_TYPE` -to `XXX_TYPE` for simplicity. However, historically, OpenEXR has used -the `_EXPORT` tag, and so that is preserved for consistency. - -## References - -LLVM libc++ visibility macros: -https://libcxx.llvm.org/docs/DesignDocs/VisibilityMacros.html - -GCC visibility wiki: -https://gcc.gnu.org/wiki/Visibility - -Apple library design docs: -https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/DynamicLibraryDesignGuidelines.html diff --git a/docs/SymbolVisibility.rst b/docs/SymbolVisibility.rst new file mode 100644 index 0000000000..83443054bf --- /dev/null +++ b/docs/SymbolVisibility.rst @@ -0,0 +1,126 @@ +.. + SPDX-License-Identifier: BSD-3-Clause + Copyright Contributors to the OpenEXR Project. + +.. _Symbol Visibility in OpenEXR: + +Symbol Visibility in OpenEXR +############################ + +Managing symbol visibility in a C++ library can reduce library sizes, +and with the extra information, the optimizer may produce faster +code. To take advantage of this, OpenEXR 3.0 is switching to +explicitly manage symbols on all platforms, with a hidden-by-default +behavior on unix-based platforms. Managing symbols has always been +required for Windows DLLs, where one must explicitly tag functions for +import and export as appropriate. + +For C, this is trivial: just tag public functions or global variable +as default visibility and leave everything else defaulting to +hidden. However, in C++, this is not exactly the same story. Functions +and globals are of course the same. And class member functions are +largely the same, and other than the attribute specification +mechanics, follow the same rules between gcc, clang, and +msvc. However, types have richer information than they do in C. So, +unless extra work is done, concepts for RTTI like the typeinfo and the +vtable for virtual classes will be hidden, and not visible. These are +referred to as "vague" linkage objects in some discussions. + +It is with the "vague" linkage objects where different properties +arise. For example, if you have a template, it is happily instantiated +in multiple compile units. If the typeinfo is hidden for one library, +then this may cause things like dynamic_cast to fail because then the +same typeinfo is not used, and even though one might think that +ImfAttribute are the same in two places, because they +are instantiated in separate places, they may be considered different +types. To compound the issue, there are different rules for this in +different implementations. For example, a default gcc under linux +allows one to link against otherwise private "vague" linkage objects +such that the typeinfo ends up as the same entity. clang, for MacOS +anyway, follows a stricter approach and keeps those types separate, +perhaps due to the two level namespace they maintain for symbols. + +Unfortunately, this is not clearly discussed as an overview of the +differences between platforms, hence this document to add +clarity. Each compiler / platform describes their own behavior, but +not how that behaves relative to others. `libc++ +`_ from +the llvm project is the closest to providing comparative information, +where by looking at how they define their macros and the comments +surrounding, one can infer the behavior among at least windows DLL +mode, then gcc vs. clang for unixen. Other compilers, for example, +Intel's icc, tend to adopt the behavior of the predominant compiler +for that platform (i.e. msvc under windows, gcc under linux), and so +can generally adopt that behavior and are ignored here. If this is not +true, the ifdef rules in the various library ``Export.h`` headers +within OpenEXR may need to be adjusted, and this table updated. + +As a summary, below is a table of the attribute or declspec that needs +to be used for a particular C++ entity to be properly exported. This +does not address weak symbols, ABI versioning, and only focusing on +visibility. Under Windows DLL rules, if one exports the entire class, +it also exports the types for the member types as well, which is not +desired, so these are marked as N/A even though the compiler does +allow that to happen. + + ++----------------------------------+-------------------------+-------------------------+---------------------------+--------------------------------+ +| C++ vs Compiler | MSVC | mingw | gcc | clang | ++----------------------------------+-------------------------+-------------------------+---------------------------+--------------------------------+ ++----------------------------------+-------------------------+-------------------------+---------------------------+--------------------------------+ +| function | ``dllexport/dllimport`` | ``dllexport/dllimport`` | ``visibility("default")`` | ``visibility("default")`` | ++----------------------------------+-------------------------+-------------------------+---------------------------+--------------------------------+ +| hide a function | N/A | N/A | ``visibility("hidden")`` | ``visibility("hidden")`` | ++----------------------------------+-------------------------+-------------------------+---------------------------+--------------------------------+ +| ``class(typeinfo)`` | N/A | N/A | ``visibility("default")`` | ``visibility("default")`` | ++----------------------------------+-------------------------+-------------------------+---------------------------+--------------------------------+ +| template class | N/A | N/A | ``visibility("default")`` | ``type_visibility("default")`` | ++----------------------------------+-------------------------+-------------------------+---------------------------+--------------------------------+ +| template data | N/A | N/A | ``visibility("default")`` | ``visibility("default")`` | ++----------------------------------+-------------------------+-------------------------+---------------------------+--------------------------------+ +| class template
instantiation | ``dllexport/dllimport`` | N/A | N/A | ``visibility("default")`` | ++----------------------------------+-------------------------+-------------------------+---------------------------+--------------------------------+ +| enum | N/A | N/A | auto unhides (N/A) | ``type_visibility("default")`` | ++----------------------------------+-------------------------+-------------------------+---------------------------+--------------------------------+ +| extern template | N/A | ``dllexport/dllimport`` | ``visibility("default")`` | ``visibility("default")`` | ++----------------------------------+-------------------------+-------------------------+---------------------------+--------------------------------+ + +With this matrix in mind, we can see the maximal set of macros we need to +provide throughout the code. *NB*: This does not mean that we need to +declare all of these, just that they might be needed. `XXX` should be +substituted for the particular library name being compiled. + ++----------------------------------+------------------------------------------------------------------+ +| macro name | purpose | ++----------------------------------+------------------------------------------------------------------+ ++----------------------------------+------------------------------------------------------------------+ +| ``XXX_EXPORT`` | one of export or import for windows, visibility for others | ++----------------------------------+------------------------------------------------------------------+ +| ``XXX_EXPORT_TYPE`` | for declaring a class / struct as public (for typeinfo / vtable) | ++----------------------------------+------------------------------------------------------------------+ +| ``XXX_HIDDEN`` | used to explicitly hide, especially members of types | ++----------------------------------+------------------------------------------------------------------+ +| ``XXX_EXPORT_TEMPLATE_TYPE`` | stating the template type should be visible | ++----------------------------------+------------------------------------------------------------------+ +| ``XXX_EXPORT_EXTERN_TEMPLATE`` | exporting template types (i.e. extern side of extern template) | ++----------------------------------+------------------------------------------------------------------+ +| ``XXX_EXPORT_TEMPLATE_INSTANCE`` | exporting specific template instantiations (in cpp code) | ++----------------------------------+------------------------------------------------------------------+ +| ``XXX_EXPORT_TEMPLATE_DATA`` | exporting templated data blocks | ++----------------------------------+------------------------------------------------------------------+ +| ``XXX_EXPORT_ENUM`` | exporting enum types | ++----------------------------------+------------------------------------------------------------------+ + +For a new library, the preference might be to call ``XXX_EXPORT`` +something like ``XXX_FUNC``, and rename things such as ``XXX_EXPORT_TYPE`` +to ``XXX_TYPE`` for simplicity. However, historically, OpenEXR has used +the ``_EXPORT`` tag, and so that is preserved for consistency. + +References +========== + +* LLVM libc++ visibility macros: https://libcxx.llvm.org/docs/DesignDocs/VisibilityMacros.html + +* GCC visibility wiki: https://gcc.gnu.org/wiki/Visibility + +* Apple library design docs: https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/DynamicLibraryDesignGuidelines.html diff --git a/docs/TechnicalIntroduction.rst b/docs/TechnicalIntroduction.rst index 47be9fc856..9a92eeb8d1 100644 --- a/docs/TechnicalIntroduction.rst +++ b/docs/TechnicalIntroduction.rst @@ -1,28 +1,18 @@ .. SPDX-License-Identifier: BSD-3-Clause - Copyright (c) Contributors to the OpenEXR Project. + Copyright Contributors to the OpenEXR Project. + +.. _Technical Introduction to OpenEXR: Technical Introduction to OpenEXR ################################# .. toctree:: - :maxdepth: 3 - -Document Purpose and Audience -============================= - -OpenEXR is an open-source high-dynamic-range image file format that -was developed by Industrial Light & Magic. This document presents a -brief overview of OpenEXR. + :caption: Technical Introduction Features of OpenEXR =================== -Starting in 1999, Industrial Light & Magic developed OpenEXR, a -high-dynamic-range image file format for use in digital visual effects -production. In early 2003, after using and refining the file format -for two years, ILM released OpenEXR as an open-source C++ library. - A unique combination of features makes OpenEXR a good fit for high-quality image processing and storage applications: @@ -35,7 +25,6 @@ high-quality image processing and storage applications: formats have around 7 to 10 stops. **good color resolution** - With 16-bit floating-point numbers, color resolution is 1024 steps per f-stop, as opposed to somewhere around 20 to 70 steps per f-stop for most 8-bit file formats. Even after significant processing (for @@ -43,7 +32,6 @@ high-quality image processing and storage applications: noticeable color banding. **compatible with graphics hardware** - The 16-bit floating-point data format is fully compatible with the 16-bit frame-buffer data format used in some new graphics hardware. Images can be transferred back and forth between an @@ -61,14 +49,12 @@ high-quality image processing and storage applications: compression schemes can be added in the future. **arbitrary image channels** - OpenEXR images can contain an arbitrary number and combination of image channels, for example red, green, blue, and alpha; luminance and sub-sampled chroma channels; depth, surface normal directions, or motion vectors. **scan line and tiled images, multi-resolution images** - Pixels in an OpenEXR file can be stored either as scan lines or as tiles. Tiled image files allow random-access to rectangular sub-regions of an image. Multiple versions of a tiled image, each @@ -83,7 +69,6 @@ high-quality image processing and storage applications: display very large images. **ability to store additional data** - Often it is necessary to annotate images with additional data; for example, color timing information, process tracking data, or camera position and view direction. OpenEXR allows storing of an arbitrary @@ -92,7 +77,6 @@ high-quality image processing and storage applications: not understand. **easy-to-use C++ and C programming interfaces** - In order to make writing and reading OpenEXR files easy, the file format was designed together with a C++ programming interface. Two levels of access to image files are provided: a fully general @@ -113,28 +97,24 @@ high-quality image processing and storage applications: library. **fast multi-threaded file reading and writing** - The OpenEXR library supports multi-threaded reading or writing of an OpenEXR image file: while one thread performs low-level file input or output, multiple other threads simultaneously encode or decode individual pieces of the file. **portability** - The OpenEXR file format is hardware and operating system independent. While implementing the C and C++ programming interfaces, an effort was made to use only language features and library functions that comply with the C and C++ ISO standards. **multi-view** - A “multi-view” image shows the same scene from multiple different points of view. A common application is 3D stereo imagery, where a left-eye and a right-eye view of a scene are stored in a single file. **deep data** - Support for a new data type has been added: deep data. Deep images store an arbitrarily long list of data at each pixel location. This is different from multichannel or 'deep channel images' which can @@ -148,7 +128,6 @@ high-quality image processing and storage applications: atmospheric effects such fog). **multi-part** - Multi-part files allow for storing multiple images in one OpenEXR file. One important application is to store layers of channels separately. This allows for faster access when only a subset of the @@ -234,6 +213,7 @@ For a few channel names, interpretation of the data is predefined: .. list-table:: :header-rows: 1 + :align: left * - name - interpretation @@ -254,6 +234,7 @@ Three channel data types are currently supported: .. list-table:: :header-rows: 1 + :align: left * - type name - description @@ -274,11 +255,11 @@ determine for which of the pixels in the image's data window data are stored in the file. Data for a pixel at pixel space coordinates (x, y) are stored only if - x mod s :sub:`x` = 0 +.. math:: x \mod{s_x} = 0 and - y mod s :sub:`y` = 0. +.. math:: y \mod{s_y} = 0 For RGBA (red, green, blue, alpha) images, s\ :sub:`x` and s\ :sub:`y` are 1 for all channels, and each channel contains data for every @@ -329,9 +310,9 @@ rectangles, called *tiles*. Each tile contains p\ :sub:`x` by p\ :sub:`x`) by ceil(h/p\ :sub:`y`) tiles, where w and h are the width and height of the data window: - w = x\ :sub:`max` - x\ :sub:`min` + 1 +.. math:: w = x_max - x_min + 1 - h = y\ :sub:`max` - y\ :sub:`min` + 1 +.. math:: h = y_max - y_min + 1 The upper left corner of the upper left tile is aligned with the upper left corner of the data window, at (x\ :sub:`min`, y\ :sub:`min`). The @@ -429,6 +410,7 @@ are present. .. list-table:: :header-rows: 1 + :align: left * - rounding mode - level resolution @@ -512,6 +494,7 @@ headers: .. list-table:: :header-rows: 1 + :align: left * - attribute name - description @@ -548,13 +531,14 @@ information, process tracking data, or camera position and view direction. Those data can be packaged as extra attributes in the image file's header. -Multi-view header attributes +Multi-View Header Attributes ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This attribute is required in the header for multi-view OpenEXR files. .. list-table:: :header-rows: 1 + :align: left * - attribute name - notes @@ -577,6 +561,7 @@ deep data OpenEXR files. .. list-table:: :header-rows: 1 + :align: left * - attribute name - notes @@ -608,6 +593,7 @@ deep data (deepscanline or deeptile): .. list-table:: :header-rows: 1 + :align: left * - name - notes @@ -760,6 +746,7 @@ Supported compression schemes: .. list-table:: :header-rows: 1 + :align: left * - name - description @@ -1014,7 +1001,8 @@ with more than three color channels. .. list-table:: :header-rows: 1 - + :align: left + * - name - interpretation * - Y @@ -1063,6 +1051,7 @@ data you are handling, always use the appropriate channel name. .. list-table:: :header-rows: 1 + :align: left * - name - definition @@ -1118,10 +1107,197 @@ the OpenEXR library defines a set of standard attributes for commonly used data, such as colorimetric data (see `RGB Color`_, time and place where an image was recorded, or the owner of an image file's content. Whenever possible, application programs should store data in -standard attributes, instead of defining their own. For a current list -of all standard attributes, see the OpenEXR library's source code. The -list grows over time as OpenEXR users identify new types of data they -would like to represent in a standard way. +standard attributes, instead of defining their own. + +By default, OpenEXR files have the following attributes: + +**chromaticities** + For RGB images, specifies the CIE (x,y) chromaticities of the + primaries and the white point. + +**whiteLuminance** + For RGB images, defines the luminance, in Nits (candelas per square + meter) of the RGB value (1.0, 1.0, 1.0). + + If the chromaticities and the whiteLuminance of an RGB image are + known, then it is possible to convert the image's pixels from RGB to + CIE XYZ tristimulus values. + +**adoptedNeutral** + Specifies the CIE (x,y) coordinates that should be considered + neutral during color rendering. Pixels in the image file whose + (x,y) coordinates match the adoptedNeutral value should be mapped to + neutral values on the display. + + +**renderingTransform**, lookModTransform + Specify the names of the CTL functions that implements the intended + color rendering and look modification transforms for this image. + +**xDensity** + Horizontal output density, in pixels per inch. The image's vertical + output density is xDensity * pixelAspectRatio. + +**owner** + Name of the owner of the image. + +**comments** + Additional image information in human-readable form, for example a + verbal description of the image. + +**capDate** + The date when the image was created or captured, in local time, and + formatted as ``YYYY:MM:DD hh:mm:ss``, where ``YYYY`` is the year (4 + digits, e.g. 2003), ``MM`` is the month (2 digits, 01, 02, ... 12), + ``DD`` is the day of the month (2 digits, 01, 02, ... 31), hh is the + hour (2 digits, 00, 01, ... 23), mm is the minute, and ss is the + second (2 digits, 00, 01, ... 59). + +**utcOffset** + Universal Coordinated Time (UTC), in seconds: UTC == local time + + utcOffset + +**longitude**, **latitude**, **altitude** + For images of real objects, the location where the image was + recorded. Longitude and latitude are in degrees east of Greenwich + and north of the equator. Altitude is in meters above sea level. + For example, Kathmandu, Nepal is at longitude 85.317, latitude + 27.717, altitude 1305. + +**focus** + The camera's focus distance, in meters. + +**exposure** + Exposure time, in seconds. + +**aperture** + The camera's lens aperture, in f-stops (focal length of the lens + divided by the diameter of the iris opening). + +**isoSpeed** + The ISO speed of the film or image sensor that was used to record + the image. + +**envmap** + If this attribute is present, the image represents an environment + map. The attribute's value defines how 3D directions are mapped to + 2D pixel locations. + +**keyCode** + For motion picture film frames. Identifies film manufacturer, film + type, film roll and frame position within the roll. + +**timeCode** + Time and control code + +**wrapmodes** + Determines how texture map images are extrapolated. If an OpenEXR + file is used as a texture map for 3D rendering, texture coordinates + (0.0, 0.0) and (1.0, 1.0) correspond to the upper left and lower + right corners of the data window. If the image is mapped onto a + surface with texture coordinates outside the zero-to-one range, then + the image must be extrapolated. This attribute tells the renderer + how to do this extrapolation. The attribute contains either a pair + of comma-separated keywords, to specify separate extrapolation modes + for the horizontal and vertical directions; or a single keyword, to + specify extrapolation in both directions (e.g. "clamp,periodic" or + "clamp"). Extra white space surrounding the keywords is allowed, + but should be ignored by the renderer ("clamp, black " is equivalent + to "clamp,black"). The keywords listed below are predefined; some + renderers may support additional extrapolation modes: + + **black** + pixels outside the zero-to-one range are black + + **clamp** + texture coordinates less than 0.0 and greater than 1.0 are clamped + to 0.0 and 1.0 respectively. + + **periodic** + the texture image repeats periodically + + **mirror** + the texture image repeats periodically, but every other instance + is mirrored + +**framesPerSecond** + Defines the nominal playback frame rate for image sequences, in + frames per second. Every image in a sequence should have a + framesPerSecond attribute, and the attribute value should be the + same for all images in the sequence. If an image sequence has no + framesPerSecond attribute, playback software should assume that the + frame rate for the sequence is 24 frames per second. + + In order to allow exact representation of NTSC frame and field + rates, framesPerSecond is stored as a rational number. A rational + number is a pair of integers, n and d, that represents the value + n/d. + +**multiView** + Defines the view names for multi-view image files. A multi-view + image contains two or more views of the same scene, as seen from + different viewpoints, for example a left-eye and a right-eye view + for stereo displays. The multiView attribute lists the names of the + views in an image, and a naming convention identifies the channels + that belong to each view. + +**worldToCamera** + For images generated by 3D computer graphics rendering, a matrix + that transforms 3D points from the world to the camera coordinate + space of the renderer. + + The camera coordinate space is left-handed. Its origin indicates + the location of the camera. The positive x and y axes correspond to + the "right" and "up" directions in the rendered image. The positive + z axis indicates the camera's viewing direction. (Objects in front + of the camera have positive z coordinates.) + + Camera coordinate space in OpenEXR is the same as in Pixar's + Renderman. + +**worldToNDC** + For images generated by 3D computer graphics rendering, a matrix + that transforms 3D points from the world to the Normalized Device + Coordinate (NDC) space of the renderer. + + NDC is a 2D coordinate space that corresponds to the image plane, + with positive x and pointing to the right and y positive pointing + down. The coordinates (0, 0) and (1, 1) correspond to the upper + left and lower right corners of the OpenEXR display window. + + To transform a 3D point in word space into a 2D point in NDC space, + multiply the 3D point by the worldToNDC matrix and discard the z + coordinate. + + NDC space in OpenEXR is the same as in Pixar's Renderman. + +**deepImageState** + Specifies whether the pixels in a deep image are sorted and + non-overlapping. + + Note: this attribute can be set by application code that writes a + file in order to tell applications that read the file whether the + pixel data must be cleaned up prior to image processing operations + such as flattening. The OpenEXR library does not verify that the + attribute is consistent with the actual state of the pixels. + Application software may assume that the attribute is valid, as long + as the software will not crash or lock up if any pixels are + inconsistent with the deepImageState attribute. + +**originalDataWindow** + If application software crops an image, then it should save the data + window of the original, un-cropped image in the originalDataWindow + attribute. + +**dwaCompressionLevel** + Sets the quality level for images compressed with the DWAA or DWAB + method. + +**ID Manifest** + ID manifest. See `A scheme for storing object ID manifests in + openEXR images + `_ for details. + Premultiplied vs. Un-Premultiplied Color Channels ------------------------------------------------- @@ -1131,7 +1307,7 @@ represent alpha or opacity: 0.0 means the pixel is transparent; 1.0 means the pixel is opaque. By convention, all color channels are premultiplied by alpha, so that - composite = foreground + (1-alpha) × background +.. math:: \text{composite} = \text{foreground} + (1-\text{alpha}) × \text{background} performs a correct "over" operation. @@ -1139,7 +1315,7 @@ Describing the color channels as "premultiplied" is a shorthand for describing a correct "over" operation. With un-premultiplied color channels "over" operations would require computing - composite = alpha × foreground + (1-alpha) × background. +.. math:: \text{composite} = \text{alpha} × \text{foreground} + (1-\text{alpha}) × \text{background}. "Premultiplied" does not mean that pixels with zero alpha and non-zero color channels are illegal. Such a pixel represents an object that @@ -1176,21 +1352,6 @@ when the image is saved in a new OpenEXR file. Depending on the application software there may be other ways to preserve color information in pixels with zero alpha. -Credits -======= - -The ILM OpenEXR file format was designed and implemented by Florian -Kainz, Wojciech Jarosz, and Rod Bogart. The PIZ compression scheme is -based on an algorithm by Christian Rouet. Josh Pines helped extend the -PIZ algorithm for 16-bit and found optimizations for the float-to-half -conversions. Drew Hess packaged and adapted ILM's internal source code -for public release and maintains the OpenEXR software -distribution. The PXR24 compression method is based on an algorithm -written by Loren Carpenter at Pixar Animation Studios. - -OpenEXR was developed at Industrial Light & Magic, a division of Lucas -Digital Ltd. LLC, Marin County, California. - .. [1] ``Z`` and ``ZBack`` distances are the z-coordinate of the point in camera space (that is, the distance to plane on which point lies), not the diff --git a/docs/TheoryDeepPixels.rst b/docs/TheoryDeepPixels.rst index f91d0912c6..86d657b232 100644 --- a/docs/TheoryDeepPixels.rst +++ b/docs/TheoryDeepPixels.rst @@ -1,15 +1,17 @@ .. SPDX-License-Identifier: BSD-3-Clause - Copyright (c) Contributors to the OpenEXR Project. + Copyright Contributors to the OpenEXR Project. Theory of Deep Samples ###################### -This document derives the techniques for splitting and combining two non-solid samples of -equal depth and thickness. These should should be used by deep image "flattening" algorithms to compute the combined colour of two samples. The formulas are defined in the document :doc:`InterpretingDeepPixels`. This document derives those formulas, and is for information only. - - +This document derives the techniques for splitting and combining two +non-solid samples of equal depth and thickness. These should should be +used by deep image "flattening" algorithms to compute the combined +colour of two samples. The formulas are defined in the document +:doc:`InterpretingDeepPixels`. This document derives those formulas, +and is for information only. Definitions =========== diff --git a/docs/about.rst b/docs/about.rst new file mode 100644 index 0000000000..f90ca7536d --- /dev/null +++ b/docs/about.rst @@ -0,0 +1,124 @@ +.. + SPDX-License-Identifier: BSD-3-Clause + Copyright Contributors to the OpenEXR Project. + +.. _About OpenEXR: + +About OpenEXR +============= + +.. toctree:: + :caption: About + +OpenEXR is a project of the `Academy Software Foundation +`_. The format and library were originally +developed at Industrial Light & Magic and first released as open +source in 2003. Weta Digital, Walt Disney Animation Studios, Sony +Pictures Imageworks, Pixar Animation Studios, DreamWorks, and other +studios, companies, and individuals have made contributions to the +code base. + +Read the origin story of OpenEXR on the `ASWF Blog +`_. + +OpenEXR is included in the `VFX Reference Platform `_. + +OpenEXR Features +---------------- + +* High dynamic range and color precision. +* Support for 16-bit floating-point, 32-bit floating-point, and + 32-bit integer pixels. +* Multiple image compression algorithms, both lossless and lossy. Some of + the included codecs can achieve 2:1 lossless compression ratios on images + with film grain. The lossy codecs have been tuned for visual quality and + decoding performance. +* Extensibility. New compression codecs and image types can easily be added + by extending the C++ classes included in the OpenEXR software distribution. + New image attributes (strings, vectors, integers, etc.) can be added to + OpenEXR image headers without affecting backward compatibility with + existing OpenEXR applications. +* Support for stereoscopic image workflows and a generalization + to multi-views. +* Flexible support for deep data: pixels can store a variable-length list + of samples and, thus, it is possible to store multiple values at different + depths for each pixel. Hard surfaces and volumetric data representations + are accommodated. +* Multipart: ability to encode separate, but related, images in one file. + This allows for access to individual parts without the need to read other + parts in the file. +* Versioning: OpenEXR source allows for user configurable C++ + namespaces to provide protection when using multiple versions of the + library in the same process space. + +OpenEXR and Imath Version 3 +---------------------------- + +With the release of OpenEXR 3, the Imath library formerly distributed +via the IlmBase component of OpenEXR is now an independent library +dependency, available for download from +https://github.com/AcademySoftwareFoundation/Imath. You can choose to +build OpenEXR against an external installation of Imath, or the +default CMake configuration will download and build it automatically +during the OpenEXR build process. Note that the half 16-bit floating +point data type is included in Imath. + +See :doc:`PortingGuide` for details about differences from previous +releases and how to address them. Also refer to the porting guide for +details about changes to Imath. + +New Features in OpenEXR v3.1 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The 3.1 release of OpenEXR introduces a new library, OpenEXRCore, +which is the result of a significant re-thinking of how OpenEXR +manages file I/O and provides access to image data. It begins to +address long-standing scalability issues with multithreaded image +reading and writing. + +The OpenEXRCore library provides thread-safe, non-blocking access to +files, which was not possible with the current API, where the +framebuffer management is separate from read requests. It is written +entirely in C and provides a new C-language API alongside the existing +C++ API. This new low-level API allows applications to do custom +unpacking of EXR data, such as on the GPU, while still benefiting from +efficient I/O, file validation, and other semantics. It provides +efficient direct access to EXR files in texturing applications. This C +library also introduces an easier path to implementing OpenEXR +bindings in other languages, such as Rust. + +The 3.1 release represents a technology preview for upcoming +releases. The initial release is incremental; the existing API and +underlying behavior has not changed. The new API is available now for +performance validation testing, and then in future OpenEXR releases, +the C++ API will migrate to use the new core in stages. It is not the +intention to entirely deprecate the C++ API, nor must all applications +re-implement EXR I/O in terms of the C library. The C API does not, +and will not, provide the rich set of utility classes that exist in +the C++ layer. The 3.1 release of the OpenEXRCore library simply +offers new functionality for specialty applications seeking the +highest possible performance. In the future, the ABI will evolve, but +the API will remain consistent, or only have additions. + +See :doc:`ReadingAndWritingImageFiles` for more information. + +Credits +======= + +The ILM OpenEXR file format was originally designed and implemented at +Industrial Light & Magic by Florian Kainz, Wojciech Jarosz, and Rod +Bogart. The PIZ compression scheme is based on an algorithm by +Christian Rouet. Josh Pines helped extend the PIZ algorithm for 16-bit +and found optimizations for the float-to-half conversions. Drew Hess +packaged and adapted ILM's internal source code for public release and +maintains the OpenEXR software distribution. The PXR24 compression +method is based on an algorithm written by Loren Carpenter at Pixar +Animation Studios. + +For a complete list of contributors see the `CONTRIBUTORS.md +`_ +file. + + + + diff --git a/docs/concepts.rst b/docs/concepts.rst new file mode 100644 index 0000000000..5a192d8996 --- /dev/null +++ b/docs/concepts.rst @@ -0,0 +1,19 @@ +.. + SPDX-License-Identifier: BSD-3-Clause + Copyright Contributors to the OpenEXR Project. + +.. _OpenEXR Concepts: + +OpenEXR Concepts +################ + +.. toctree:: + :caption: Concepts + :maxdepth: 2 + + TechnicalIntroduction + StandardOptionalAttributes + MultiViewOpenEXR + InterpretingDeepPixels + TheoryDeepPixels + OpenEXRFileLayout diff --git a/docs/conf.py b/docs/conf.py index eb07e1d149..679789babb 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -57,6 +57,7 @@ 'sphinx.ext.todo', 'sphinx.ext.viewcode', 'breathe', + 'sphinx_tabs.tabs', ] # Breathe extension variables @@ -143,9 +144,19 @@ #html_theme = 'agogo' #html_theme = 'default' # good #html_theme = 'nature' # too green -html_theme = 'bizstyle' # OK #html_theme = 'sphinxdoc' +html_theme = 'bizstyle' # OK + +html_theme = "press" +html_theme_options = { + "external_links": [ + ("Github", "https://github.com/AcademySoftwareFoundation/openexr"), + ] +} + + + # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. @@ -164,6 +175,7 @@ # The name of an image file (relative to this directory) to place at the top # of the sidebar. html_logo = "images/openexr-stacked-color.png" +html_logo = "images/openexr-horizontal-color.png" # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 diff --git a/docs/images/openexr-horizontal-color.png b/docs/images/openexr-horizontal-color.png new file mode 100644 index 0000000000000000000000000000000000000000..6974a631cde0ee4b9c5f67908b658a2f69f74d77 GIT binary patch literal 17103 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 X%YAu+=6wJQ2LeHrG@cYIzViP+ZpedC literal 0 HcmV?d00001 diff --git a/docs/images/windowExample1.small.png b/docs/images/windowExample1.small.png new file mode 100644 index 0000000000000000000000000000000000000000..ab366578e7dcd0d605cf162f3f2c1b099bdfbf8b GIT binary patch literal 89159 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 V;|bLrU;zLC002ovPDHLkV1idosw4ma literal 0 HcmV?d00001 diff --git a/docs/index.rst b/docs/index.rst index fd012ff4f3..8ce4acb633 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,13 +1,19 @@ .. SPDX-License-Identifier: BSD-3-Clause - Copyright (c) Contributors to the OpenEXR Project. + Copyright Contributors to the OpenEXR Project. -OpenEXR |version| Technical Documentation -========================================= +.. _Overview: -.. sidebar:: OpenEXR +Overview +######## - .. image:: images/windowExample1.png +.. toctree:: + :caption: Overview + :maxdepth: 1 + +.. sidebar:: + + .. image:: images/windowExample1.small.png OpenEXR provides the specification and reference implementation of the EXR file format, the professional-grade image storage format of the @@ -21,69 +27,70 @@ OpenEXR is widely used in host application software where accuracy is critical, such as photorealistic rendering, texture access, image compositing, deep compositing, and DI. -OpenEXR Features - -* High dynamic range and color precision. -* Support for 16-bit floating-point, 32-bit floating-point, and - 32-bit integer pixels. -* Multiple image compression algorithms, both lossless and lossy. Some of - the included codecs can achieve 2:1 lossless compression ratios on images - with film grain. The lossy codecs have been tuned for visual quality and - decoding performance. -* Extensibility. New compression codecs and image types can easily be added - by extending the C++ classes included in the OpenEXR software distribution. - New image attributes (strings, vectors, integers, etc.) can be added to - OpenEXR image headers without affecting backward compatibility with - existing OpenEXR applications. -* Support for stereoscopic image workflows and a generalization - to multi-views. -* Flexible support for deep data: pixels can store a variable-length list - of samples and, thus, it is possible to store multiple values at different - depths for each pixel. Hard surfaces and volumetric data representations - are accommodated. -* Multipart: ability to encode separate, but related, images in one file. - This allows for access to individual parts without the need to read other - parts in the file. -* Versioning: OpenEXR source allows for user configurable C++ - namespaces to provide protection when using multiple versions of the - library in the same process space. - -Technical Documents -################### +OpenEXR is a project of the `Academy Software Foundation +`_. -.. toctree:: - :maxdepth: 1 - TechnicalIntroduction - ReadingAndWritingImageFiles - OpenEXRCoreAPI - OpenEXRFileLayout - MultiViewOpenEXR - InterpretingDeepPixels - TheoryDeepPixels - StandardOptionalAttributes - -* :ref:`genindex` +Imath +===== -Resources -######### +The OpenEXR project includes `Imath `_, +a basic, light-weight, and efficient C++ representation of 2D and 3D +vectors and matrices and other simple but useful mathematical objects, +functions, and data types common in computer graphics applications, +including the “half” 16-bit floating-point type. -- Download: https://github.com/AcademySoftwareFoundation/openexr -- Install Help: `INSTALL.md `_ -- Porting Help: `Imath/OpenEXR Version 2->3 Porting Guide `_ -- License: `BSD License `_ -- Reference images: https://github.com/AcademySoftwareFoundation/openexr-images +Imath also includes optional python bindings for all types and +functions, including optimized implementations of vector and matrix +arrays. -About OpenEXR -############# +Quick Start +=========== -OpenEXR is a project of the `Academy Software Foundation -`_. The format and library were originally -developed by Industrial Light & Magic and first released in 2003. -Weta Digital, Walt Disney Animation Studios, Sony Pictures Imageworks, -Pixar Animation Studios, DreamWorks, and other studios, companies, and -individuals have made contributions to the code base. +For a simple program that uses the C++ API to read and write a ``.exr`` file, see the +:doc:`HelloWorld` examples. + +Community +========= + +* **Ask a question:** + + - Email: `openexr-dev@lists.aswf.io `_ + + - Slack: `academysoftwarefdn#openexr `_ + +* **Attend a meeting:** + + - Technical Steering Committee meetings are open to the + public, fortnightly on Thursdays, 1:30pm Pacific Time. + + - Calendar: https://lists.aswf.io/g/openexr-dev/calendar + +* **Report a bug:** + + - Submit an Issue: https://github.com/AcademySoftwareFoundation/openexr/issues + +* **Report a security vulnerability:** + + - Email security@openexr.com + +* **Make a contribution:** + + - Read the `Contribution guidelines `_ + + - Sign the `Contributor License Agreement + `_ + + - Submit a PR: https://github.com/AcademySoftwareFoundation/openexr/pulls + +Resources +========= + +- Reference images: https://github.com/AcademySoftwareFoundation/openexr-images +- Security policy: `SECURITY.md `_ +- Release notes: `CHANGES.md + `_ +- Contributors: `CONTRIBUTORS.md `_ -OpenEXR is included in the `VFX Reference Platform `_. +.. include:: toc_redirect.rst - diff --git a/INSTALL.md b/docs/install.rst similarity index 57% rename from INSTALL.md rename to docs/install.rst index 1281070d9d..ef22e07930 100644 --- a/INSTALL.md +++ b/docs/install.rst @@ -1,26 +1,54 @@ -# Building and Installation +.. + SPDX-License-Identifier: BSD-3-Clause + Copyright Contributors to the OpenEXR Project. -## Download +.. _Install: -To build the latest release of OpenEXR, begin by downloading the -source from the GitHub Releases page: -https://github.com/AcademySoftwareFoundation/openexr/releases. +Install +======== -To build from the latest development version, which may not be stable, -clone the GitHub repo and build from the master branch: +.. toctree:: + :caption: Install + +The OpenEXR library is available for download and installation in +binary form via package managers on many Linux distributions. See +`https://pkgs.org/download/openexr +`_ for a complete list. The common +ones that generally provide current releases include: - % git clone https://github.com/AcademySoftwareFoundation/openexr +* `Fedora `_ +* `Gentoo `_ +* `Ubuntu `_ -You can alternatively download the repository tarball file either via -a browser, or on the Linux/macOS via the command line using ``wget`` -or ``curl``: +Beware that some distributions are out of date and only provide +distributions of outdated releases OpenEXR. We recommend against using +OpenEXR v2, and we *strongly* recommend against using OpenEXR v1. - % curl -L https://github.com/AcademySoftwareFoundation/openexr/tarball/master | tar xv +On macOS, we do not recommend installation via HomeBrew because the +distribution is outdated. -In the instructions that follow, we will refer to the top-level -directory of the source code tree as ``$openexr_source_directory``. +Also note that the official OpenEXR project does not provide supported +python bindings. ``pip install openexr`` installs the `openexrpython +`_ module, which is not +affiliated with the OpenEXR project or the ASWF. Please direct +questions there. -## Prerequisites +Build from Source +----------------- + +OpenEXR builds on Linux, macOS, Microsoft Windows via CMake, and is +cross-compilable on other systems. + +Download the source from the `GitHub releases page +`_ +page, or clone the `repo `_. + +The ``release`` branch of the repo always points to the most advanced +release. + + +Prerequisites +~~~~~~~~~~~~~ Make sure these are installed on your system before building OpenEXR: @@ -34,21 +62,29 @@ The instructions that follow describe building OpenEXR with CMake. Note that as of OpenEXR 3, the Gnu autoconf bootstrap/configure build system is no longer supported. -## Linux/macOS Quick Start +Linux/macOS +~~~~~~~~~~~ -To build via CMake, first choose a location for the build directory, -which we will refer to as ``$build_directory``. +To build via CMake, you need to first identify three directories: - % mkdir $build_directory - % cd $build_directory - % cmake $openexr_source_directory - % make - % make install +1. The source directory, i.e. the top-level directory of the + downloaded source archive or cloned repo, referred to below as ``$srcdir`` +2. A temporary directory to hold the build artifacts, referred to below as + ``$builddir`` +3. A destination directory into which to install the + libraries and headers, referred to below as ``$installdir``. + +To build: +.. code-block:: + + $ cd $builddir + $ cmake $srcdir --install-prefix $installdir + $ cmake --build $builddir --target install --config Release Note that the CMake configuration prefers to apply an out-of-tree build process, since there may be multiple build configurations (i.e. debug and release), one per folder, all pointing at once source -tree, hence the ``$build_directory`` noted above, referred to in CMake +tree, hence the ``$builddir`` noted above, referred to in CMake parlance as the *build directory*. You can place this directory wherever you like. @@ -58,7 +94,8 @@ no arguments, as above, ``make install`` installs the header files in ``/usr/local/include``, the object libraries in ``/usr/local/lib``, and the executable programs in ``/usr/local/bin``. -## Windows Quick Start +Windows +~~~~~~~ Under Windows, if you are using a command line-based setup, such as cygwin, you can of course follow the above. For Visual Studio, cmake @@ -69,39 +106,12 @@ installs the headers, libraries, and programs into ``/usr/local``, but you can specify a local install directory to cmake via the ``CMAKE_INSTALL_PREFIX`` variable: - % cmake .. -DCMAKE_INSTALL_PREFIX=$openexr_install_directory - -## Porting Applications from OpenEXR v2 to v3 - -See the [porting -guide](https://github.com/AcademySoftwareFoundation/Imath/blob/master/docs/PortingGuide2-3.md) -for details about differences from previous releases and how to -address them. Also refer to the porting guide for details about -changes to Imath. +.. code-block:: -## Documentation + $ cmake .. -DCMAKE_INSTALL_PREFIX=$openexr_install_directory -The OpenEXR technical documentation at -[openexr.readthedocs.io](https://openexr.readthedocs.io) is generated -via [Sphinx](https://www.sphinx-doc.org) with the -[Breathe](https://breathe.readthedocs.io) extension using information -extracted from header comments by [Doxygen](https://www.doxygen.nl). - -To build the documentation locally from the source headers and -``.rst`` files, set the CMake option ``DOCS=ON``. This adds -``Doxygen`` and ``Sphinx`` CMake targets. Local documentation -generation is off by default. - -Building the documentation requires that sphinx, breathe, and doxygen -are installed. - -Note that the [openexr.readthedocs.io](https://openexr.readthedocs.io) -documentation takes the place of the formerly distributed .pdf -documents in the ``docs`` folder, although readthedocs supports -downloading of documentation in pdf format, for those who prefer it -that way. - -## Library Names +Library Names +------------- By default the installed libraries follow a pattern for how they are named. This is done to enable multiple versions of the library to be @@ -114,105 +124,113 @@ If you are building dynamic libraries, once you have configured, built, and installed the libraries, you should see the following pattern of symlinks and files in the install lib folder: +.. code-block:: + libOpenEXR.so -> libOpenEXR-3_1.so libOpenEXR-3_1.so -> libOpenEXR-3_1.so.30 libOpenEXR-3_1.so.30 -> libOpenEXR-3_1.so.30.3.0 libOpenEXR-3_1.so.30.3.0 (the shared object file) The ``-3_1`` suffix encodes the major and minor version, which can be -configured via the ``OPENEXR_LIB_SUFFIX`` CMake setting. The "30" +configured via the ``OPENEXR_LIB_SUFFIX`` CMake setting. The ``30`` corresponds to the so version, or in ``libtool`` terminology the -_current_ shared object version; the "3" denotes the ``libtool`` -_revision_, and the "0" denotes the ``libtool`` _age_. See the -[``libtool``](https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info) +``current`` shared object version; the `3` denotes the ``libtool`` +``revision``, and the ``0`` denotes the ``libtool`` ``age``. See the +`libtool +`_ documentation for more details. -## Imath Dependency +Imath Dependency +---------------- -OpenEXR depends on -[Imath](https://github.com/AcademySoftwareFoundation/Imath). If a -suitable installation of Imath cannot be found, CMake will -automatically download it at configuration time. To link against an -existing installation of Imath, add the Imath directory to the +OpenEXR depends on `Imath +`_. If a suitable +installation of Imath cannot be found, CMake will automatically +download it at configuration time. To link against an existing +installation of Imath, add the Imath directory to the ``CMAKE_PREFIX_PATH`` setting: - % mkdir $build_directory - % cd $build_directory - % cmake -DCMAKE_PREFIX_PATH=$imath_install_directory \ +.. code-block:: + + $ mkdir $build_directory + $ cd $build_directory + $ cmake -DCMAKE_PREFIX_PATH=$imath_install_directory \ -DCMAKE_INSTALL_PREFIX=$openexr_install_destination \ $openexr_source_directory - % cmake --build . --target install --config Release + $ cmake --build . --target install --config Release Alternatively, you can specify the ``Imath_DIR`` variable: - % mkdir $build_directory - % cd $build_directory - % cmake -DImath_DIR=$imath_config_directory \ +.. code-block:: + + $ mkdir $build_directory + $ cd $build_directory + $ cmake -DImath_DIR=$imath_config_directory \ -DCMAKE_INSTALL_PREFIX=$openexr_install_destination \ $openexr_source_directory - % cmake --build . --target install --config Release + $ cmake --build . --target install --config Release Note that ``Imath_DIR`` should point to the directory that includes the ``ImathConfig.cmake`` file, which is typically the ``lib/cmake/Imath`` folder of the root install directory where Imath is installed. -Please see ``cmake/OpenEXRSetup.cmake`` for other customization options. +See below for other customization options. -## Custom Namespaces +Porting Applications from OpenEXR v2 to v3 +------------------------------------------ -If you are interested in controlling custom namespace declarations or -similar options, you are encouraged to look at the ``CMakeLists.txt`` -infrastructure. The settings can be found in -``cmake/OpenEXRSetup.cmake``. As per usual, these settings can also be -seen and/or edited using any of the various gui editors for working -with cmake such as ``ccmake``, ``cmake-gui``, as well as some of the -IDEs in common use. +See the :doc:`PortingGuide` for details about differences from previous +releases and how to address them. Also refer to the porting guide for +details about changes to Imath. -## Cross Compiling / Specifying Specific Compilers +Building the Documentation +-------------------------- -When trying to either cross-compile for a different platform, or for -tasks such as specifying a compiler set to match the [VFX reference -platform](https://vfxplatform.com), cmake provides the idea of a -toolchain which may be useful instead of having to remember a chain of -configuration options. It also means that platform-specific compiler -names and options are out of the main cmake file, providing better -isolation. +The OpenEXR technical documentation at `https://openexr.readthedocs.io +`_ is generated via `Sphinx +`_ with the `Breathe +`_ extension using information +extracted from header comments by `Doxygen `_. -A toolchain file is simply just a cmake script that sets all the -compiler and related flags and is run very early in the configuration -step to be able to set all the compiler options and such for the -discovery that cmake performs automatically. These options can be set -on the command line still if that is clearer, but a theoretical -toolchain file for compiling for VFX Platform 2015 is provided in the -source tree at cmake/Toolchain-Linux-VFX_Platform15.cmake which will -hopefully provide a guide how this might work. +To build the documentation locally from the source headers and +``.rst`` files, set the CMake option ``DOCS=ON``. This adds +``Doxygen`` and ``Sphinx`` CMake targets and enables building the docs +by default. generation is off by default. -For cross-compiling for additional platforms, there is also an -included sample script in cmake/Toolchain-mingw.cmake which shows how -cross compiling from Linux for Windows may work. The compiler names -and paths may need to be changed for your environment. +Building the documentation requires that ``sphinx``, ``breathe``, and +``doxygen`` are installed. It further requires the `sphinx-press-theme +`_, as indicated in the +`requirements.txt +`_ +file. -More documentation: +Note that the `https://openexr.readthedocs.io `_ +documentation takes the place of the formerly distributed .pdf +documents in the ``docs`` folder, although readthedocs supports +downloading of documentation in pdf format, for those who prefer it +that way. -* Toolchains: https://cmake.org/cmake/help/v3.12/manual/cmake-toolchains.7.html -* Cross compiling: https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/ +CMake Build-time Configuration Options +-------------------------------------- -## CMake Configuration Options The default CMake configuration options are stored in ``cmake/OpenEXRSetup.cmake``. To see a complete set of option variables, run: - % cmake -LAH $openexr_source_directory +.. code-block:: + + $ cmake -LAH $openexr_source_directory You can customize these options three ways: 1. Modify the ``.cmake`` files in place. 2. Use the UI ``cmake-gui`` or ``ccmake``. -2. Specify them as command-line arguments when you invoke cmake. +3. Specify them as command-line arguments when you invoke cmake. -### Library Naming Options: +Library Naming Options +~~~~~~~~~~~~~~~~~~~~~~ * ``OPENEXR_LIB_SUFFIX`` @@ -220,7 +238,8 @@ You can customize these options three ways: libraries. Default is ``-_`` version string. Please see the section on library names -### Imath Dependency: +Imath Dependency +~~~~~~~~~~~~~~~~ * ``CMAKE_PREFIX_PATH`` @@ -236,7 +255,8 @@ You can customize these options three ways: file, which is typically the ``lib/cmake/Imath`` folder of the root install directory. -### Namespace Options: +Namespace Options +~~~~~~~~~~~~~~~~~ * ``OPENEXR_IMF_NAMESPACE`` @@ -277,7 +297,8 @@ You can customize these options three ways: Whether the namespace has been customized (so external users know) -### Component Options: +Component Options +~~~~~~~~~~~~~~~~~ * ``BUILD_TESTING`` @@ -298,10 +319,10 @@ You can customize these options three ways: Build and install the example code. Default is ``ON``. -### Additional CMake Options: +Additional CMake Options +~~~~~~~~~~~~~~~~~~~~~~~~ -See the cmake documentation for more information -(https://cmake.org/cmake/help/v3.12/) +See the CMake documentation for more information (https://cmake.org/cmake/help/v3.12/). * ``CMAKE_BUILD_TYPE`` @@ -343,15 +364,44 @@ See the cmake documentation for more information Echo all compile commands during make. Default is ``OFF``. -## Cmake Tips and Tricks: +Cross Compiling / Specifying Specific Compilers +----------------------------------------------- + +When trying to either cross-compile for a different platform, or for +tasks such as specifying a compiler set to match the `VFX reference +platform `_, cmake provides the idea of a +toolchain which may be useful instead of having to remember a chain of +configuration options. It also means that platform-specific compiler +names and options are out of the main cmake file, providing better +isolation. + +A toolchain file is simply just a cmake script that sets all the +compiler and related flags and is run very early in the configuration +step to be able to set all the compiler options and such for the +discovery that cmake performs automatically. These options can be set +on the command line still if that is clearer, but a theoretical +toolchain file for compiling for VFX Platform 2015 is provided in the +source tree at ``cmake/Toolchain-Linux-VFX_Platform15.cmake`` which +will hopefully provide a guide how this might work. + +For cross-compiling for additional platforms, there is also an +included sample script in ``cmake/Toolchain-mingw.cmake`` which shows +how cross compiling from Linux for Windows may work. The compiler +names and paths may need to be changed for your environment. + +More documentation: + +* Toolchains: https://cmake.org/cmake/help/v3.12/manual/cmake-toolchains.7.html +* Cross compiling: https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/ + +Ninja +----- -If you have ninja (https://ninja-build.org/) installed, it is faster +If you have `Ninja `_ installed, it is faster than make. You can generate ninja files using cmake when doing the initial generation: - % cmake -G “Ninja” .. +.. code-block:: -If you would like to confirm compile flags, you don’t have to specify -the verbose configuration up front, you can instead run + $ cmake -G “Ninja” .. - % make VERBOSE=1 diff --git a/docs/license.rst b/docs/license.rst new file mode 100644 index 0000000000..f6e0227d78 --- /dev/null +++ b/docs/license.rst @@ -0,0 +1,33 @@ +.. + SPDX-License-Identifier: BSD-3-Clause + Copyright Contributors to the OpenEXR Project. + +.. _License: + +License +======= + +.. toctree:: + :caption: License + +OpenEXR is licensed under the BSD-3-Clause license. Contributions to the +library should abide by that license unless otherwised approved by the OCIO +TSC and ASWF Governing Board. + +See `LICENSE.md +`__ +on GitHub. + +Copyright (c) Contributors to the OpenEXR Project. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + diff --git a/docs/requirements.txt b/docs/requirements.txt index cd6467ed82..804ea69d1d 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1 +1,3 @@ breathe +sphinx-press-theme +sphinx-tabs diff --git a/docs/src/reader/CMakeLists.txt b/docs/src/reader/CMakeLists.txt new file mode 100644 index 0000000000..cb974476f6 --- /dev/null +++ b/docs/src/reader/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.10) +project(exrreader) +find_package(OpenEXR REQUIRED) + +add_executable(${PROJECT_NAME} reader.cpp) +target_link_libraries(${PROJECT_NAME} OpenEXR::OpenEXR) + diff --git a/docs/src/reader/build.sh b/docs/src/reader/build.sh new file mode 100755 index 0000000000..7cd8c5801a --- /dev/null +++ b/docs/src/reader/build.sh @@ -0,0 +1,3 @@ +$ mkdir _build +$ cmake -S . -B _build +$ cmake --build _build diff --git a/docs/src/reader/reader.cpp b/docs/src/reader/reader.cpp new file mode 100644 index 0000000000..22e026dabd --- /dev/null +++ b/docs/src/reader/reader.cpp @@ -0,0 +1,25 @@ +#include +#include +#include + +int +main() +{ + try { + Imf::RgbaInputFile file("hello.exr"); + Imath::Box2i dw = file.dataWindow(); + int width = dw.max.x - dw.min.x + 1; + int height = dw.max.y - dw.min.y + 1; + + Imf::Array2D pixels(width, height); + + file.setFrameBuffer(&pixels[0][0], 1, width); + file.readPixels(dw.min.y, dw.max.y); + + } catch (const std::exception &e) { + std::cerr << "error reading image file hello.exr:" << e.what() << std::endl; + return 1; + } + + return 0; +} diff --git a/docs/src/writer/CMakeLists.txt b/docs/src/writer/CMakeLists.txt new file mode 100644 index 0000000000..f5fbe8666b --- /dev/null +++ b/docs/src/writer/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.10) +project(exrwriter) +find_package(OpenEXR REQUIRED) + +add_executable(${PROJECT_NAME} writer.cpp) +target_link_libraries(${PROJECT_NAME} OpenEXR::OpenEXR) + diff --git a/docs/src/writer/build.sh b/docs/src/writer/build.sh new file mode 100755 index 0000000000..7cd8c5801a --- /dev/null +++ b/docs/src/writer/build.sh @@ -0,0 +1,3 @@ +$ mkdir _build +$ cmake -S . -B _build +$ cmake --build _build diff --git a/docs/src/writer/writer.cpp b/docs/src/writer/writer.cpp new file mode 100644 index 0000000000..6367ee6d06 --- /dev/null +++ b/docs/src/writer/writer.cpp @@ -0,0 +1,25 @@ +#include +#include +#include + +int +main() +{ + int width = 10; + int height = 10; + + Imf::Array2D pixels(width, height); + for (int y=0; y