From d8e09556096b8d2082efa5c4ad9c1e61881584ad Mon Sep 17 00:00:00 2001 From: Zach Lewis Date: Tue, 23 Jul 2024 13:34:18 -0400 Subject: [PATCH 001/147] build: Improve Python3 component detection The build system has been updated to specifically detect the Python3 Development.Module meta component, as opposed to the entire Development component. This allows for better compatibility with python distributions that do not provide the Development.Embed component, which is only required for projects that ship embedded Python interpreters. The changes have been made in CMakeLists.txt and pythonutils.cmake files. Signed-off-by: Zach Lewis --- CMakeLists.txt | 4 ++-- src/cmake/pythonutils.cmake | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index aebb4eafd5..e64f9d68ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -248,10 +248,10 @@ if (NOT EMBEDPLUGINS AND NOT BUILD_OIIOUTIL_ONLY) endforeach () endif () -if (USE_PYTHON AND Python3_Development_FOUND AND NOT BUILD_OIIOUTIL_ONLY) +if (USE_PYTHON AND Python3_Development.Module_FOUND AND NOT BUILD_OIIOUTIL_ONLY) add_subdirectory (src/python) else () - message (STATUS "Not building Python bindings: USE_PYTHON=${USE_PYTHON}, Python3_Development_FOUND=${Python3_Development_FOUND}") + message (STATUS "Not building Python bindings: USE_PYTHON=${USE_PYTHON}, Python3_Development.Module_FOUND=${Python3_Development.Module_FOUND}") endif () add_subdirectory (src/include) diff --git a/src/cmake/pythonutils.cmake b/src/cmake/pythonutils.cmake index ac7fb617a0..e13e012995 100644 --- a/src/cmake/pythonutils.cmake +++ b/src/cmake/pythonutils.cmake @@ -35,10 +35,11 @@ macro (find_python) checked_find_package (Python3 ${PYTHON_VERSION} ${_req} VERSION_MIN 3.7 - COMPONENTS Interpreter Development + COMPONENTS Interpreter Development.Module PRINT Python3_VERSION Python3_EXECUTABLE Python3_LIBRARIES Python3_Development_FOUND + Python3_Development.Module_FOUND Python3_Interpreter_FOUND ) # The version that was found may not be the default or user From df83fc880d9da3ee1344c5058266859d00e214e1 Mon Sep 17 00:00:00 2001 From: Zach Lewis Date: Tue, 23 Jul 2024 15:54:56 -0400 Subject: [PATCH 002/147] Add pyproject.toml for building wheels with scikit-build-core Scikit-build-core is used for collecting CMake and Ninja as needed, and for invoking the build. When invoked via cibuildwheels, `repairwheel` is used after each build to re-bundle and relink the shared library dependencies into properly redistributable whl archives. The command-line tools are exposed under the [project.scripts] section. This commit incorporates or is otherwise inspired by similar efforts by @aclark4life and @JeanChristopheMorinPerso, as well as @remia's work on the OpenColorIO wheels. Signed-off-by: Zach Lewis --- pyproject.toml | 110 +++++++++++++++++++++++++ src/python/OpenImageIO/__init__.py | 6 ++ src/python/OpenImageIO/command_line.py | 16 ++++ 3 files changed, 132 insertions(+) create mode 100644 pyproject.toml create mode 100644 src/python/OpenImageIO/__init__.py create mode 100644 src/python/OpenImageIO/command_line.py diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000000..e90c964644 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,110 @@ +[project] +name = "OpenImageIO" +dynamic = ["version"] +description = "Reading, writing, and processing images in a wide variety of file formats, using a format-agnostic API, aimed at VFX applications." +authors = [ + {name = "Larry Gritz", email = "lg@larrygritz.com"}, +] +maintainers = [ + {name = "Larry Gritz", email = "lg@larrygritz.com"}, +] +readme = "README.md" +license = {text = "Apache-2.0, BSD-3-Clause"} +keywords = [""] +classifiers = [ + "Development Status :: 4 - Beta", + "Natural Language :: English", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Multimedia :: Graphics", + "Topic :: Multimedia :: Video", + "Topic :: Multimedia :: Video :: Display", + "Topic :: Software Development :: Libraries :: Python Modules", +] +dependencies = [] +requires-python = ">= 3.9" + +[project.urls] +Homepage = "https://openimageio.org/" +Source = "https://github.com/AcademySoftwareFoundation/OpenImageIO" +Documentation = "https://openimageio.readthedocs.io" +Issues = "https://github.com/AcademySoftwareFoundation/OpenImageIO/issues" + +[project.scripts] +iconvert = "OpenImageIO.command_line:main" +idiff = "OpenImageIO.command_line:main" +igrep = "OpenImageIO.command_line:main" +iinfo = "OpenImageIO.command_line:main" +maketx = "OpenImageIO.command_line:main" +oiiotool = "OpenImageIO.command_line:main" +testtex = "OpenImageIO.command_line:main" + +[build-system] +build-backend = "scikit_build_core.build" +requires = [ + "scikit-build-core>=0.9.8", + "pybind11", + "oldest-supported-numpy", +] + +[tool.scikit-build.metadata.version] +provider = "scikit_build_core.metadata.regex" +input = "CMakeLists.txt" # path to the CMakeLists.txt setting OpenImageIO_VERSION +regex = 'set \(OpenImageIO_VERSION "(?P[0-9a-z.]+)"\)' + +[tool.scikit-build] +cmake.verbose = false +cmake.version = ">=3.29.1" +experimental = false +build-dir = "build_wheels" +wheel.install-dir = "OpenImageIO" +wheel.packages = [ + "src/python/OpenImageIO", # path to python cli shims +] + +cmake.args = [ + # OpenImageIO-2.6+ has a mechanism for building, linking, and + # distributing missing dependencies. See src/cmake for details. + "-DOpenImageIO_BUILD_MISSING_DEPS=all", + # Place the compiled python module under the OpenImageIO namespace. + # This is to avoid creating a separate package for the cli shims. + '-DPYTHON_SITE_DIR=${SKBUILD_PLATLIB_DIR}/OpenImageIO', + "-DCMAKE_INSTALL_LIBDIR=lib", +] + +[tool.cibuildwheel] +build-verbosity = 1 +build = "cp39-* cp310-* cp311-* cp312-* pp*" +skip = [ + #"pp*", + "*musllinux*", +] +before-build = "pipx install repairwheel" + +[tool.cibuildwheel.linux.environment] +# Suppress warnings that cause linux cibuildwheels build to fail +CXXFLAGS = "-Wno-error=stringop-overflow= -Wno-pragmas" + +[tool.cibuildwheel.linux] +# Repairwheel is a tool that gathers shared libraries and +# adjusts the rpath of the compiled wheels. The OIIO build +# process places any missing dependencies it compiles in +# the build_wheels/deps/dist/{lib,lib64} directories. +repair-wheel-command = """\ +repairwheel \ + -l build_wheels/deps/dist/lib \ + -l build_wheels/deps/dist/lib64 \ + -l build_wheels/lib \ + -o {dest_dir} \ + {wheel} +""" + +[tool.cibuildwheel.macos] +repair-wheel-command = "repairwheel -l build_wheels/lib -l build_wheels/deps/dist/lib -o {dest_dir} {wheel}" + +[tool.cibuildwheel.windows] +repair-wheel-command = "repairwheel -o {dest_dir} {wheel}" diff --git a/src/python/OpenImageIO/__init__.py b/src/python/OpenImageIO/__init__.py new file mode 100644 index 0000000000..e11f94e1b6 --- /dev/null +++ b/src/python/OpenImageIO/__init__.py @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright Contributors to the OpenImageIO Project. + +from .OpenImageIO import * + +__version__ = VERSION_STRING diff --git a/src/python/OpenImageIO/command_line.py b/src/python/OpenImageIO/command_line.py new file mode 100644 index 0000000000..8abe4f0865 --- /dev/null +++ b/src/python/OpenImageIO/command_line.py @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright Contributors to the OpenImageIO Project. + +import os +import subprocess +import sys + +BIN_DIR = os.path.join(os.path.dirname(__file__), 'bin') + +def call_program(name, args): + return subprocess.call([os.path.join(BIN_DIR, name)] + args) + + +def main(): + name = os.path.basename(sys.argv[0]) + raise SystemExit(call_program(name, sys.argv[1:])) From 5e86b2df2ba39ad93d40302e907c51af294cfc7e Mon Sep 17 00:00:00 2001 From: Zach Lewis Date: Fri, 26 Jul 2024 07:39:27 -0400 Subject: [PATCH 003/147] int(python): Adjust module metadata Use Apache-2.0 license identifier instead of BSD-3-Clause. Add "OpenImageIO Contributors" / "oiio-dev@lists.aswf.io" as author. I could not bring myself to remove Larry as an author and maintainer. Signed-off-by: Zach Lewis --- pyproject.toml | 4 ++++ src/python/OpenImageIO/__init__.py | 18 +++++++++++++++++- src/python/OpenImageIO/command_line.py | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e90c964644..ef17380404 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,9 +4,11 @@ dynamic = ["version"] description = "Reading, writing, and processing images in a wide variety of file formats, using a format-agnostic API, aimed at VFX applications." authors = [ {name = "Larry Gritz", email = "lg@larrygritz.com"}, + {name = "OpenImageIO Contributors", email = "oiio-dev@lists.aswf.io"} ] maintainers = [ {name = "Larry Gritz", email = "lg@larrygritz.com"}, + {name = "OpenImageIO Contributors", email="oiio-dev@lists.aswf.io"}, ] readme = "README.md" license = {text = "Apache-2.0, BSD-3-Clause"} @@ -52,9 +54,11 @@ requires = [ ] [tool.scikit-build.metadata.version] +# Match the project version to the OpenImageIO_VERSION value set in CMakeLists.txt. provider = "scikit_build_core.metadata.regex" input = "CMakeLists.txt" # path to the CMakeLists.txt setting OpenImageIO_VERSION regex = 'set \(OpenImageIO_VERSION "(?P[0-9a-z.]+)"\)' +# TODO: More robust method for detecting potential "dev" suffix. [tool.scikit-build] cmake.verbose = false diff --git a/src/python/OpenImageIO/__init__.py b/src/python/OpenImageIO/__init__.py index e11f94e1b6..accbebf0a8 100644 --- a/src/python/OpenImageIO/__init__.py +++ b/src/python/OpenImageIO/__init__.py @@ -1,6 +1,22 @@ -# SPDX-License-Identifier: BSD-3-Clause +# SPDX-License-Identifier: Apache-2.0 # Copyright Contributors to the OpenImageIO Project. from .OpenImageIO import * __version__ = VERSION_STRING + +__status__ = "dev" + +__author__ = "OpenImageIO Contributors" + +__email__ = "oiio-dev@lists.aswf.io" + +__license__ = "SPDX-License-Identifier: Apache-2.0" + +__copyright__ = "Copyright Contributors to the OpenImageIO Project" + +__doc__ = """ +OpenImageIO is a toolset for reading, writing, and manipulating image files of any +image file format relevant to VFX / animation via a format-agnostic API with a +feature set, scalability, and robustness needed for feature film production. +""" diff --git a/src/python/OpenImageIO/command_line.py b/src/python/OpenImageIO/command_line.py index 8abe4f0865..f72723bf2a 100644 --- a/src/python/OpenImageIO/command_line.py +++ b/src/python/OpenImageIO/command_line.py @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: BSD-3-Clause +# SPDX-License-Identifier: Apache-2.0 # Copyright Contributors to the OpenImageIO Project. import os From ea2432a55ef298c57b57e4ee62011e0f79a13292 Mon Sep 17 00:00:00 2001 From: Zach Lewis Date: Mon, 29 Jul 2024 16:15:46 -0400 Subject: [PATCH 004/147] build(deps): Improve ability to build, link, and alias shared and static libdeflate It's now possible to disable building of shared `libdeflate` libs. Also, we're checking for and aliasing `libdeflate` in `externalpackages.cmake`, just before checking for TIFF, as opposed to only doing so within `build_TIFF.cmake`. This change is necessary for certain build systems and pipelines that utilize cached dependency builds. Specifically, when building wheels for multiple versions of cpython, `cibuildwheel` would complete the first build, and then throw an exception on the *second* build re: not being able to find `Deflate::Deflate`. Moving the aliasing above the check for TIFF ensures that the expected aliasing always takes place, whether or not TIFF needs to be built; whereas before, we were only creating the alias when initially building TIFF. Signed-off-by: Zach Lewis --- src/cmake/build_libdeflate.cmake | 1 + src/cmake/externalpackages.cmake | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/src/cmake/build_libdeflate.cmake b/src/cmake/build_libdeflate.cmake index 50543699ce..eade63f6f7 100644 --- a/src/cmake/build_libdeflate.cmake +++ b/src/cmake/build_libdeflate.cmake @@ -20,6 +20,7 @@ build_dependency_with_cmake(libdeflate GIT_TAG ${libdeflate_GIT_TAG} CMAKE_ARGS -D BUILD_SHARED_LIBS=${libdeflate_BUILD_SHARED_LIBS} + -D LIBDEFLATE_BUILD_SHARED_LIB=${libdeflate_BUILD_SHARED_LIBS} -D CMAKE_POSITION_INDEPENDENT_CODE=ON -D CMAKE_INSTALL_LIBDIR=lib -D LIBDEFLATE_BUILD_GZIP=OFF diff --git a/src/cmake/externalpackages.cmake b/src/cmake/externalpackages.cmake index 71439639c1..687f48c3c2 100644 --- a/src/cmake/externalpackages.cmake +++ b/src/cmake/externalpackages.cmake @@ -85,6 +85,18 @@ else () endif () +# libdeflate +checked_find_package (libdeflate + VERSION_MIN 1.18) +# If found, doctor library so libdeflate is aliased as Deflate::Deflate +# (required for TIFF) +if (TARGET libdeflate::libdeflate_static) + alias_library_if_not_exists (Deflate::Deflate libdeflate::libdeflate_static) +elseif (TARGET libdeflate::libdeflate) + alias_library_if_not_exists (Deflate::Deflate libdeflate::libdeflate) +endif() + + checked_find_package (TIFF REQUIRED VERSION_MIN 4.0) alias_library_if_not_exists (TIFF::TIFF TIFF::tiff) From 5c1a1b88c6be8c7f7c6092dd7d791b79f7f89821 Mon Sep 17 00:00:00 2001 From: Zach Lewis Date: Mon, 29 Jul 2024 16:18:50 -0400 Subject: [PATCH 005/147] build(deps): Add libjpeg-turbo recipe Build and link missing libjpeg-turbo shared + static libs Signed-off-by: Zach Lewis --- src/cmake/build_libjpeg-turbo.cmake | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/cmake/build_libjpeg-turbo.cmake diff --git a/src/cmake/build_libjpeg-turbo.cmake b/src/cmake/build_libjpeg-turbo.cmake new file mode 100644 index 0000000000..1404c8935e --- /dev/null +++ b/src/cmake/build_libjpeg-turbo.cmake @@ -0,0 +1,34 @@ +# Copyright Contributors to the OpenImageIO project. +# SPDX-License-Identifier: Apache-2.0 +# https://github.com/Academ SoftwareFoundation/OpenImageIO + +set_cache (libjpeg-turbo_BUILD_VERSION 3.0.3 "libjpeg-turbo version for local builds") +set (libjpeg-turbo_GIT_REPOSITORY "https://github.com/libjpeg-turbo/libjpeg-turbo") +set (libjpeg-turbo_GIT_TAG "${libjpeg-turbo_BUILD_VERSION}") +set_cache (libjpeg-turbo_BUILD_SHARED_LIBS OFF #${LOCAL_BUILD_SHARED_LIBS_DEFAULT} + DOC "Should a local libjpeg-turbo build, if necessary, build shared libraries" ADVANCED) + +string (MAKE_C_IDENTIFIER ${libjpeg-turbo_BUILD_VERSION} libjpeg-turbo_VERSION_IDENT) + +build_dependency_with_cmake(libjpeg-turbo + VERSION ${libjpeg-turbo_BUILD_VERSION} + GIT_REPOSITORY ${libjpeg-turbo_GIT_REPOSITORY} + GIT_TAG ${libjpeg-turbo_GIT_TAG} + CMAKE_ARGS + -D ENABLE_SHARED=${libjpeg-turbo_BUILD_SHARED_LIBS} + -D WITH_JPEG8=1 + -D CMAKE_INSTALL_LIBDIR=lib + -D CMAKE_POSITION_INDEPENDENT_CODE=1 + + ) +# Set some things up that we'll need for a subsequent find_package to work +set (libjpeg-turbo_ROOT ${libjpeg-turbo_LOCAL_INSTALL_DIR}) + + +# Signal to caller that we need to find again at the installed location +set (libjpeg-turbo_REFIND TRUE) +set (libjpeg-turbo_REFIND_ARGS CONFIG) + +if (libjpeg-turbo_BUILD_SHARED_LIBS) + install_local_dependency_libs (libjpeg-turbo libjpeg-turbo) +endif () From 78fed979e29a28ad80f1fe443c43614cbb9c8c99 Mon Sep 17 00:00:00 2001 From: Zach Lewis Date: Mon, 29 Jul 2024 16:32:34 -0400 Subject: [PATCH 006/147] refactor: Simplify structure of Python module Instead of creating a separate OpenImageIO.OpenImageIO.command_line module for the CLI shims, move the CLI shim logic up to a "_command_line()" method in OpenImageIO.__init__.py. (Maybe this method should still be called "main()" though?) This also means the module is technically importable from OpenImageIO.OpenImageIO, but that's an improvement over OpenImageIO.OpenImageIO.OpenImageIO...! Signed-off-by: Zach Lewis --- pyproject.toml | 54 +++++++++++--------------- src/python/OpenImageIO/__init__.py | 22 ----------- src/python/OpenImageIO/command_line.py | 16 -------- src/python/__init__.py | 29 +++++++++++++- 4 files changed, 51 insertions(+), 70 deletions(-) delete mode 100644 src/python/OpenImageIO/__init__.py delete mode 100644 src/python/OpenImageIO/command_line.py diff --git a/pyproject.toml b/pyproject.toml index ef17380404..fc2eb43859 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,13 +37,13 @@ Documentation = "https://openimageio.readthedocs.io" Issues = "https://github.com/AcademySoftwareFoundation/OpenImageIO/issues" [project.scripts] -iconvert = "OpenImageIO.command_line:main" -idiff = "OpenImageIO.command_line:main" -igrep = "OpenImageIO.command_line:main" -iinfo = "OpenImageIO.command_line:main" -maketx = "OpenImageIO.command_line:main" -oiiotool = "OpenImageIO.command_line:main" -testtex = "OpenImageIO.command_line:main" +iconvert = "OpenImageIO:_command_line" +idiff = "OpenImageIO:_command_line" +igrep = "OpenImageIO:_command_line" +iinfo = "OpenImageIO:_command_line" +maketx = "OpenImageIO:_command_line" +oiiotool = "OpenImageIO:_command_line" +testtex = "OpenImageIO:_command_line" [build-system] build-backend = "scikit_build_core.build" @@ -51,64 +51,56 @@ requires = [ "scikit-build-core>=0.9.8", "pybind11", "oldest-supported-numpy", + "repairwheel>=0.3.1", ] [tool.scikit-build.metadata.version] -# Match the project version to the OpenImageIO_VERSION value set in CMakeLists.txt. provider = "scikit_build_core.metadata.regex" input = "CMakeLists.txt" # path to the CMakeLists.txt setting OpenImageIO_VERSION regex = 'set \(OpenImageIO_VERSION "(?P[0-9a-z.]+)"\)' -# TODO: More robust method for detecting potential "dev" suffix. [tool.scikit-build] cmake.verbose = false cmake.version = ">=3.29.1" -experimental = false build-dir = "build_wheels" wheel.install-dir = "OpenImageIO" -wheel.packages = [ - "src/python/OpenImageIO", # path to python cli shims -] +wheel.packages = [] cmake.args = [ # OpenImageIO-2.6+ has a mechanism for building, linking, and # distributing missing dependencies. See src/cmake for details. "-DOpenImageIO_BUILD_MISSING_DEPS=all", - # Place the compiled python module under the OpenImageIO namespace. - # This is to avoid creating a separate package for the cli shims. - '-DPYTHON_SITE_DIR=${SKBUILD_PLATLIB_DIR}/OpenImageIO', + # Make OIIO build the python module relative to scikit-build's + # expected install location. + '-DPYTHON_SITE_DIR=${SKBUILD_PLATLIB_DIR}', "-DCMAKE_INSTALL_LIBDIR=lib", ] [tool.cibuildwheel] build-verbosity = 1 -build = "cp39-* cp310-* cp311-* cp312-* pp*" +build = "cp39-* cp310-* cp311-* cp312-* cp313-* pp*" skip = [ - #"pp*", + "pp*", + #"cp39-*", + #"cp310-*", + #"cp311-*", + #"cp312-*", + "cp313-*", "*musllinux*", ] -before-build = "pipx install repairwheel" - -[tool.cibuildwheel.linux.environment] -# Suppress warnings that cause linux cibuildwheels build to fail -CXXFLAGS = "-Wno-error=stringop-overflow= -Wno-pragmas" - -[tool.cibuildwheel.linux] # Repairwheel is a tool that gathers shared libraries and # adjusts the rpath of the compiled wheels. The OIIO build # process places any missing dependencies it compiles in # the build_wheels/deps/dist/{lib,lib64} directories. +before-build = "pipx install repairwheel" repair-wheel-command = """\ repairwheel \ -l build_wheels/deps/dist/lib \ - -l build_wheels/deps/dist/lib64 \ -l build_wheels/lib \ -o {dest_dir} \ {wheel} """ -[tool.cibuildwheel.macos] -repair-wheel-command = "repairwheel -l build_wheels/lib -l build_wheels/deps/dist/lib -o {dest_dir} {wheel}" - -[tool.cibuildwheel.windows] -repair-wheel-command = "repairwheel -o {dest_dir} {wheel}" +[tool.cibuildwheel.linux.environment] +# Suppress warnings that cause linux cibuildwheels build to fail +CXXFLAGS = "-Wno-error=stringop-overflow= -Wno-pragmas" diff --git a/src/python/OpenImageIO/__init__.py b/src/python/OpenImageIO/__init__.py deleted file mode 100644 index accbebf0a8..0000000000 --- a/src/python/OpenImageIO/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 -# Copyright Contributors to the OpenImageIO Project. - -from .OpenImageIO import * - -__version__ = VERSION_STRING - -__status__ = "dev" - -__author__ = "OpenImageIO Contributors" - -__email__ = "oiio-dev@lists.aswf.io" - -__license__ = "SPDX-License-Identifier: Apache-2.0" - -__copyright__ = "Copyright Contributors to the OpenImageIO Project" - -__doc__ = """ -OpenImageIO is a toolset for reading, writing, and manipulating image files of any -image file format relevant to VFX / animation via a format-agnostic API with a -feature set, scalability, and robustness needed for feature film production. -""" diff --git a/src/python/OpenImageIO/command_line.py b/src/python/OpenImageIO/command_line.py deleted file mode 100644 index f72723bf2a..0000000000 --- a/src/python/OpenImageIO/command_line.py +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 -# Copyright Contributors to the OpenImageIO Project. - -import os -import subprocess -import sys - -BIN_DIR = os.path.join(os.path.dirname(__file__), 'bin') - -def call_program(name, args): - return subprocess.call([os.path.join(BIN_DIR, name)] + args) - - -def main(): - name = os.path.basename(sys.argv[0]) - raise SystemExit(call_program(name, sys.argv[1:])) diff --git a/src/python/__init__.py b/src/python/__init__.py index f3c345ec13..f898cdf2ee 100644 --- a/src/python/__init__.py +++ b/src/python/__init__.py @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 # https://github.com/AcademySoftwareFoundation/OpenImageIO -import os, sys, platform +import os, sys, platform, subprocess # This works around the python 3.8 change to stop loading DLLs from PATH on Windows. # We reproduce the old behaviour by manually tokenizing PATH, checking that the directories exist and are not ".", @@ -13,5 +13,32 @@ if os.path.exists(path) and path != ".": os.add_dll_directory(path) + from .OpenImageIO import * +__version__ = VERSION_STRING + +__status__ = "dev" + +__author__ = "OpenImageIO Contributors" + +__email__ = "oiio-dev@lists.aswf.io" + +__license__ = "SPDX-License-Identifier: Apache-2.0" + +__copyright__ = "Copyright Contributors to the OpenImageIO Project" + +__doc__ = """OpenImageIO is a toolset for reading, writing, and manipulating image files of +any image file format relevant to VFX / animation via a format-agnostic API +with a feature set, scalability, and robustness needed for feature film +production. +""" + + +def _call_program(name, args): + BIN_DIR = os.path.join(os.path.dirname(__file__), 'bin') + return subprocess.call([os.path.join(BIN_DIR, name)] + args) + +def _command_line(): + name = os.path.basename(sys.argv[0]) + raise SystemExit(_call_program(name, sys.argv[1:])) From bd271a3f057d3b39de5a87e5ba25cb5d297cb405 Mon Sep 17 00:00:00 2001 From: Larry Gritz Date: Fri, 26 Jul 2024 09:04:56 -0700 Subject: [PATCH 007/147] docs: clarify that IBA::rotate params are pixel coordinates (#4358) As suggested by Moritz Moeller Signed-off-by: Larry Gritz Signed-off-by: Zach Lewis --- src/include/OpenImageIO/imagebufalgo.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/OpenImageIO/imagebufalgo.h b/src/include/OpenImageIO/imagebufalgo.h index dd5403f348..fcc78e1aa9 100644 --- a/src/include/OpenImageIO/imagebufalgo.h +++ b/src/include/OpenImageIO/imagebufalgo.h @@ -580,8 +580,8 @@ bool OIIO_API circular_shift (ImageBuf &dst, const ImageBuf &src, /// /// Rotate the `src` image by the `angle` (in radians, with positive angles /// clockwise). When `center_x` and `center_y` are supplied, they denote the -/// center of rotation; in their absence, the rotation will be about the -/// center of the image's display window. +/// center of rotation, in pixel coordinates; in their absence, the rotation +/// will be about the center of the image's display window. /// /// Only the pixels (and channels) of `dst` that are specified by `roi` will /// be copied from the rotated `src`; the default `roi` is to alter all the From d298bad7355f4bf47c60ec8f0c7f5e812e0c67df Mon Sep 17 00:00:00 2001 From: Larry Gritz Date: Sun, 28 Jul 2024 22:22:01 -0700 Subject: [PATCH 008/147] build: A few cmake cleanups and minor code rearrangements (#4359) * Get rid of some obsolete cmake code. * Movement (but no change) to some parts of CMakeLists.txt, primarily to make it closer to the corresponding file in OSL to make it easy for me to diff them and port innovations back and forth between them. * Some typo/etc fixes * Remove unused OIIO_UNUSED_OK macro that's been deprecated since 2.0, and OIIO_CONSTEXPR and OIIO_CONSTEXPR14, neither of which have been needed for years. Signed-off-by: Larry Gritz Signed-off-by: Zach Lewis --- CMakeLists.txt | 5 -- docs/Deprecations-3.0.md | 10 +++ src/cmake/compiler.cmake | 6 +- src/cmake/dependency_utils.cmake | 96 ++++++++++++------------- src/include/OpenImageIO/platform.h | 110 +++++++++++++---------------- 5 files changed, 111 insertions(+), 116 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e64f9d68ca..f31d2b9515 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -265,11 +265,6 @@ if (NUKE_FOUND) add_subdirectory (src/nuke/txWriter) endif () -# Last minute site-specific instructions, if they exist -if (OIIO_SITE AND EXISTS "${PROJECT_SOURCE_DIR}/site/${OIIO_SITE}/cmake/sitecustom.cmake") - include ("${PROJECT_SOURCE_DIR}/site/${OIIO_SITE}/cmake/sitecustom.cmake") -endif () - # install pkgconfig file if (NOT MSVC) configure_file(src/build-scripts/OpenImageIO.pc.in "${CMAKE_BINARY_DIR}/OpenImageIO.pc" @ONLY) diff --git a/docs/Deprecations-3.0.md b/docs/Deprecations-3.0.md index bef5af6f8e..3200e3ea28 100644 --- a/docs/Deprecations-3.0.md +++ b/docs/Deprecations-3.0.md @@ -138,6 +138,16 @@ about being deprecated will be removed in the final 3.0 release. been considered deprecated since OIIO 2.3. Please use task functions that do not take a thread ID parameter. +## platform.h + +* Removed macros `OIIO_CONSTEXPR`, `OIIO_CONSTEXPR14`, and + `OIIO_CONSTEXPR_OR_CONST` and deprecated `OIIO_CONSTEXPR17` (use regular C++ + `constexpr` in place of all of these). Removed macro `OIIO_NOEXCEPT` (use + C++ `noexcept`). +* Removed macro `OIIO_UNUSED_OK`, which had been deprecated since 2.0. Marked + `OIIO_MAYBE_UNUSED` as deprecated as well, now that C++17 is the minimum, + there's no reason not to directly use the C++ attribute `[[maybe_unused]]`. + ## strutil.h * Added deprecation warnings to all the old (printf-convention) string diff --git a/src/cmake/compiler.cmake b/src/cmake/compiler.cmake index 844fce09c9..fb2b2c20ab 100644 --- a/src/cmake/compiler.cmake +++ b/src/cmake/compiler.cmake @@ -28,7 +28,7 @@ message (VERBOSE "CMAKE_CXX_COMPILE_FEATURES = ${CMAKE_CXX_COMPILE_FEATURES}") # set (CMAKE_CXX_MINIMUM 17) set (CMAKE_CXX_STANDARD 17 CACHE STRING - "C++ standard to build with (14, 17, 20, etc.) Minimum is ${CMAKE_CXX_MINIMUM}.") + "C++ standard to build with (17, 20, etc.) Minimum is ${CMAKE_CXX_MINIMUM}.") set (DOWNSTREAM_CXX_STANDARD 17 CACHE STRING "C++ minimum standard to impose on downstream clients") set (CMAKE_CXX_STANDARD_REQUIRED ON) @@ -69,13 +69,17 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER MATCHES "[Cc]lan set (CMAKE_CXX_COMPILER_ID "AppleClang") set (CMAKE_COMPILER_IS_APPLECLANG 1) string (REGEX REPLACE ".* version ([0-9]+\\.[0-9]+).*" "\\1" APPLECLANG_VERSION_STRING ${clang_full_version_string}) + set (ANY_CLANG_VERSION_STRING ${APPLECLANG_VERSION_STRING}) message (VERBOSE "The compiler is Clang: ${CMAKE_CXX_COMPILER_ID} version ${APPLECLANG_VERSION_STRING}") elseif (CMAKE_CXX_COMPILER_ID MATCHES "IntelLLVM") set (CMAKE_COMPILER_IS_INTELCLANG 1) string (REGEX MATCH "[0-9]+(\\.[0-9]+)+" INTELCLANG_VERSION_STRING ${clang_full_version_string}) + set (ANY_CLANG_VERSION_STRING ${INTELCLANG_VERSION_STRING}) message (VERBOSE "The compiler is Intel Clang: ${CMAKE_CXX_COMPILER_ID} version ${INTELCLANG_VERSION_STRING}") else () + set (CMAKE_COMPILER_IS_GENERICCLANG 1) string (REGEX REPLACE ".* version ([0-9]+\\.[0-9]+).*" "\\1" CLANG_VERSION_STRING ${clang_full_version_string}) + set (ANY_CLANG_VERSION_STRING ${CLANG_VERSION_STRING}) message (VERBOSE "The compiler is Clang: ${CMAKE_CXX_COMPILER_ID} version ${CLANG_VERSION_STRING}") endif () elseif (CMAKE_CXX_COMPILER_ID MATCHES "Intel") diff --git a/src/cmake/dependency_utils.cmake b/src/cmake/dependency_utils.cmake index a1470a1c70..99504819db 100644 --- a/src/cmake/dependency_utils.cmake +++ b/src/cmake/dependency_utils.cmake @@ -74,57 +74,55 @@ endfunction () # Helper: Print a report about missing dependencies and give insructions on # how to turn on automatic local dependency building. function (print_package_notfound_report) - if (CFP_ALL_BUILD_DEPS_NOTFOUND OR CFP_ALL_BUILD_DEPS_BADVERSION) - message (STATUS) - message (STATUS "${ColorBoldYellow}=========================================================================${ColorReset}") - message (STATUS "${ColorBoldYellow}= Dependency report =${ColorReset}") - message (STATUS "${ColorBoldYellow}=========================================================================${ColorReset}") - message (STATUS) - if (CFP_EXTERNAL_BUILD_DEPS_FOUND) - message (STATUS "${ColorBoldWhite}The following dependencies found externally:${ColorReset}") - list (SORT CFP_EXTERNAL_BUILD_DEPS_FOUND CASE INSENSITIVE) - list (REMOVE_DUPLICATES CFP_EXTERNAL_BUILD_DEPS_FOUND) - foreach (_pkg IN LISTS CFP_EXTERNAL_BUILD_DEPS_FOUND) - message (STATUS " ${_pkg} ${${_pkg}_VERSION}") - endforeach () - endif () - if (CFP_ALL_BUILD_DEPS_BADVERSION) - message (STATUS "${ColorBoldWhite}The following dependencies were found but were too old:${ColorReset}") - list (SORT CFP_ALL_BUILD_DEPS_BADVERSION CASE INSENSITIVE) - list (REMOVE_DUPLICATES CFP_ALL_BUILD_DEPS_BADVERSION) - foreach (_pkg IN LISTS CFP_ALL_BUILD_DEPS_BADVERSION) - if (_pkg IN_LIST CFP_LOCALLY_BUILT_DEPS) - message (STATUS " ${_pkg} ${${_pkg}_NOT_FOUND_EXPLANATION} ${ColorMagenta}(${${_pkg}_VERSION} BUILT LOCALLY)${ColorReset}") - else () - message (STATUS " ${_pkg} ${${_pkg}_NOT_FOUND_EXPLANATION}") - endif () - endforeach () - endif () - if (CFP_ALL_BUILD_DEPS_NOTFOUND) - message (STATUS "${ColorBoldWhite}The following dependencies were not found:${ColorReset}") - list (SORT CFP_ALL_BUILD_DEPS_NOTFOUND CASE INSENSITIVE) - list (REMOVE_DUPLICATES CFP_ALL_BUILD_DEPS_NOTFOUND) - foreach (_pkg IN LISTS CFP_ALL_BUILD_DEPS_NOTFOUND) - if (_pkg IN_LIST CFP_LOCALLY_BUILT_DEPS) - message (STATUS " ${_pkg} ${_${_pkg}_version_range} ${${_pkg}_NOT_FOUND_EXPLANATION} ${ColorMagenta}(${${_pkg}_VERSION} BUILT LOCALLY)${ColorReset}") - else () - message (STATUS " ${_pkg} ${_${_pkg}_version_range} ${${_pkg}_NOT_FOUND_EXPLANATION}") - endif () - endforeach () - endif () - if (CFP_LOCALLY_BUILDABLE_DEPS_NOTFOUND OR CFP_LOCALLY_BUILDABLE_DEPS_BADVERSION) - message (STATUS) - message (STATUS "${ColorBoldWhite}For some of these, we can build them locally:${ColorReset}") - foreach (_pkg IN LISTS CFP_LOCALLY_BUILDABLE_DEPS_NOTFOUND CFP_LOCALLY_BUILDABLE_DEPS_BADVERSION) - message (STATUS " ${_pkg}") - endforeach () - message (STATUS "${ColorBoldWhite}To build them automatically if not found, build again with option:${ColorReset}") - message (STATUS " ${ColorBoldGreen}-D${PROJECT_NAME}_BUILD_MISSING_DEPS=all${ColorReset}") - endif () - message (STATUS) - message (STATUS "${ColorBoldYellow}=========================================================================${ColorReset}") + message (STATUS) + message (STATUS "${ColorBoldYellow}=========================================================================${ColorReset}") + message (STATUS "${ColorBoldYellow}= Dependency report =${ColorReset}") + message (STATUS "${ColorBoldYellow}=========================================================================${ColorReset}") + message (STATUS) + if (CFP_EXTERNAL_BUILD_DEPS_FOUND) + message (STATUS "${ColorBoldWhite}The following dependencies found externally:${ColorReset}") + list (SORT CFP_EXTERNAL_BUILD_DEPS_FOUND CASE INSENSITIVE) + list (REMOVE_DUPLICATES CFP_EXTERNAL_BUILD_DEPS_FOUND) + foreach (_pkg IN LISTS CFP_EXTERNAL_BUILD_DEPS_FOUND) + message (STATUS " ${_pkg} ${${_pkg}_VERSION}") + endforeach () + endif () + if (CFP_ALL_BUILD_DEPS_BADVERSION) + message (STATUS "${ColorBoldWhite}The following dependencies were found but were too old:${ColorReset}") + list (SORT CFP_ALL_BUILD_DEPS_BADVERSION CASE INSENSITIVE) + list (REMOVE_DUPLICATES CFP_ALL_BUILD_DEPS_BADVERSION) + foreach (_pkg IN LISTS CFP_ALL_BUILD_DEPS_BADVERSION) + if (_pkg IN_LIST CFP_LOCALLY_BUILT_DEPS) + message (STATUS " ${_pkg} ${${_pkg}_NOT_FOUND_EXPLANATION} ${ColorMagenta}(${${_pkg}_VERSION} BUILT LOCALLY)${ColorReset}") + else () + message (STATUS " ${_pkg} ${${_pkg}_NOT_FOUND_EXPLANATION}") + endif () + endforeach () + endif () + if (CFP_ALL_BUILD_DEPS_NOTFOUND) + message (STATUS "${ColorBoldWhite}The following dependencies were not found:${ColorReset}") + list (SORT CFP_ALL_BUILD_DEPS_NOTFOUND CASE INSENSITIVE) + list (REMOVE_DUPLICATES CFP_ALL_BUILD_DEPS_NOTFOUND) + foreach (_pkg IN LISTS CFP_ALL_BUILD_DEPS_NOTFOUND) + if (_pkg IN_LIST CFP_LOCALLY_BUILT_DEPS) + message (STATUS " ${_pkg} ${_${_pkg}_version_range} ${${_pkg}_NOT_FOUND_EXPLANATION} ${ColorMagenta}(${${_pkg}_VERSION} BUILT LOCALLY)${ColorReset}") + else () + message (STATUS " ${_pkg} ${_${_pkg}_version_range} ${${_pkg}_NOT_FOUND_EXPLANATION}") + endif () + endforeach () + endif () + if (CFP_LOCALLY_BUILDABLE_DEPS_NOTFOUND OR CFP_LOCALLY_BUILDABLE_DEPS_BADVERSION) message (STATUS) + message (STATUS "${ColorBoldWhite}For some of these, we can build them locally:${ColorReset}") + foreach (_pkg IN LISTS CFP_LOCALLY_BUILDABLE_DEPS_NOTFOUND CFP_LOCALLY_BUILDABLE_DEPS_BADVERSION) + message (STATUS " ${_pkg}") + endforeach () + message (STATUS "${ColorBoldWhite}To build them automatically if not found, build again with option:${ColorReset}") + message (STATUS " ${ColorBoldGreen}-D${PROJECT_NAME}_BUILD_MISSING_DEPS=all${ColorReset}") endif () + message (STATUS) + message (STATUS "${ColorBoldYellow}=========================================================================${ColorReset}") + message (STATUS) endfunction () diff --git a/src/include/OpenImageIO/platform.h b/src/include/OpenImageIO/platform.h index 7fb09b43b5..1371096a64 100644 --- a/src/include/OpenImageIO/platform.h +++ b/src/include/OpenImageIO/platform.h @@ -52,64 +52,6 @@ #include #include -// Detect which C++ standard we're using, and handy macros. -// See https://en.cppreference.com/w/cpp/compiler_support -// -// OIIO_CPLUSPLUS_VERSION : which C++ standard is compiling (14, 17, ...) -// OIIO_CONSTEXPR14 : -// OIIO_CONSTEXPR17 : -// OIIO_CONSTEXPR20 : constexpr for C++ >= the designated version, otherwise -// nothing (this is useful for things that can only be -// constexpr for particular versions or greater). -// OIIO_INLINE_CONSTEXPR : inline constexpr variables, added in C++17. For -// older C++, static constexpr. -// -// Note: oiioversion.h defines OIIO_BUILD_CPP (set to 17, 20, etc.) -// reflecting what OIIO itself was *built* with. In contrast, -// OIIO_CPLUSPLUS_VERSION defined below will be set to the right number for -// the C++ standard being compiled RIGHT NOW. These two things may be the -// same when compiling OIIO, but they may not be the same if another -// package is compiling against OIIO and using these headers (OIIO may be -// C++14 but the client package may be newer, or vice versa -- use these two -// symbols to differentiate these cases, when important). -#if (__cplusplus >= 202001L) -# define OIIO_CPLUSPLUS_VERSION 20 -# define OIIO_CONSTEXPR17 constexpr -# define OIIO_CONSTEXPR20 constexpr -# define OIIO_INLINE_CONSTEXPR inline constexpr -#elif (__cplusplus >= 201703L) || (defined(_MSC_VER) && _MSC_VER >= 1914) -# define OIIO_CPLUSPLUS_VERSION 17 -# define OIIO_CONSTEXPR17 constexpr -# define OIIO_CONSTEXPR20 /* not constexpr before C++20 */ -# define OIIO_INLINE_CONSTEXPR inline constexpr -#else -# error "This version of OIIO is meant to work only with C++17 and above" -#endif - -// DEPRECATED(2.3): use C++14 constexpr -#define OIIO_CONSTEXPR14 constexpr - -// DEPRECATED(1.8): use C++11 constexpr -#define OIIO_CONSTEXPR constexpr -#define OIIO_CONSTEXPR_OR_CONST constexpr - -// DEPRECATED(1.8): use C++11 noexcept -#define OIIO_NOEXCEPT noexcept - - -// In C++20 (and some compilers before that), __has_cpp_attribute can -// test for understand of [[attr]] tests. -#ifndef __has_cpp_attribute -# define __has_cpp_attribute(x) 0 -#endif - -// On gcc & clang, __has_attribute can test for __attribute__((attr)) -#ifndef __has_attribute -# define __has_attribute(x) 0 -#endif - - - // Detect which compiler and version we're using // Notes: @@ -227,6 +169,55 @@ #endif +// Detect which C++ standard we're using, and handy macros. +// See https://en.cppreference.com/w/cpp/compiler_support +// +// OIIO_CPLUSPLUS_VERSION : which C++ standard is compiling (14, 17, ...) +// OIIO_CONSTEXPR14 : +// OIIO_CONSTEXPR17 : +// OIIO_CONSTEXPR20 : constexpr for C++ >= the designated version, otherwise +// nothing (this is useful for things that can only be +// constexpr for particular versions or greater). +// OIIO_INLINE_CONSTEXPR : inline constexpr variables, added in C++17. For +// older C++, static constexpr. +// +// Note: oiioversion.h defines OIIO_BUILD_CPP (set to 17, 20, etc.) +// reflecting what OIIO itself was *built* with. In contrast, +// OIIO_CPLUSPLUS_VERSION defined below will be set to the right number for +// the C++ standard being compiled RIGHT NOW. These two things may be the +// same when compiling OIIO, but they may not be the same if another +// package is compiling against OIIO and using these headers (OIIO may be +// C++17 but the client package may be newer, or vice versa -- use these two +// symbols to differentiate these cases, when important). +#if (__cplusplus >= 202001L) +# define OIIO_CPLUSPLUS_VERSION 20 +# define OIIO_CONSTEXPR20 constexpr +# define OIIO_INLINE_CONSTEXPR inline constexpr +#elif (__cplusplus >= 201703L) || (defined(_MSC_VER) && _MSC_VER >= 1914) +# define OIIO_CPLUSPLUS_VERSION 17 +# define OIIO_CONSTEXPR20 /* not constexpr before C++20 */ +# define OIIO_INLINE_CONSTEXPR inline constexpr +#else +# error "This version of OIIO is meant to work only with C++17 and above" +#endif + +// DEPRECATED(3.0): use C++17 constexpr +#define OIIO_CONSTEXPR17 constexpr + + +// In C++20 (and some compilers before that), __has_cpp_attribute can +// test for understand of [[attr]] tests. +#ifndef __has_cpp_attribute +# define __has_cpp_attribute(x) 0 +#endif + +// On gcc & clang, __has_attribute can test for __attribute__((attr)) +#ifndef __has_attribute +# define __has_attribute(x) 0 +#endif + + + // Pragma control // // OIIO_PRAGMA(x) make a pragma for *unquoted* x @@ -426,9 +417,6 @@ // [[maybe_unused]] attribute. #define OIIO_MAYBE_UNUSED [[maybe_unused]] -// DEPRECATED(1.9) name: -#define OIIO_UNUSED_OK OIIO_MAYBE_UNUSED - // OIIO_RESTRICT is a parameter attribute that indicates a promise that the // parameter definitely will not alias any other parameters in such a way // that creates a data dependency. Use with caution! From f9d7f210c80effcbc2fc303ea755b2d3f612edce Mon Sep 17 00:00:00 2001 From: Zach Lewis Date: Tue, 30 Jul 2024 15:23:11 -0400 Subject: [PATCH 009/147] Revert libdeflate-related changes to externalpackages.cmake This seems to break builds under certain circumstances. Better to handle the problem with cached rebuilds another way, either in a FindLibdeflate.cmake, or by always locally-building libdeflate and TIFF. Signed-off-by: Zach Lewis --- src/cmake/externalpackages.cmake | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/cmake/externalpackages.cmake b/src/cmake/externalpackages.cmake index 687f48c3c2..71439639c1 100644 --- a/src/cmake/externalpackages.cmake +++ b/src/cmake/externalpackages.cmake @@ -85,18 +85,6 @@ else () endif () -# libdeflate -checked_find_package (libdeflate - VERSION_MIN 1.18) -# If found, doctor library so libdeflate is aliased as Deflate::Deflate -# (required for TIFF) -if (TARGET libdeflate::libdeflate_static) - alias_library_if_not_exists (Deflate::Deflate libdeflate::libdeflate_static) -elseif (TARGET libdeflate::libdeflate) - alias_library_if_not_exists (Deflate::Deflate libdeflate::libdeflate) -endif() - - checked_find_package (TIFF REQUIRED VERSION_MIN 4.0) alias_library_if_not_exists (TIFF::TIFF TIFF::tiff) From f5551619a03a3a86e953e4e87226643473f454a5 Mon Sep 17 00:00:00 2001 From: Zach Lewis Date: Tue, 30 Jul 2024 16:00:47 -0400 Subject: [PATCH 010/147] build(python): set RPATHs to relative paths to distribution's 'libs' directory, under module root Added conditional logic to set relative RPATHs when building with scikit-build. This change ensures that the Python module and compiled cli tools correctly find all built dynamic libraries relative to a shared root, and keeps distributions self-contained and relocatable (i.e., without requiring a `repairwheel` step). Signed-off-by: Zach Lewis --- pyproject.toml | 6 +----- src/cmake/fancy_add_executable.cmake | 11 +++++++++++ src/cmake/pythonutils.cmake | 13 +++++++++++++ 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index fc2eb43859..3e4c9c6dad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,15 +65,11 @@ cmake.version = ">=3.29.1" build-dir = "build_wheels" wheel.install-dir = "OpenImageIO" wheel.packages = [] - cmake.args = [ # OpenImageIO-2.6+ has a mechanism for building, linking, and # distributing missing dependencies. See src/cmake for details. "-DOpenImageIO_BUILD_MISSING_DEPS=all", - # Make OIIO build the python module relative to scikit-build's - # expected install location. - '-DPYTHON_SITE_DIR=${SKBUILD_PLATLIB_DIR}', - "-DCMAKE_INSTALL_LIBDIR=lib", + "-DOpenImageIO_BUILD_LOCAL_DEPS=all", ] [tool.cibuildwheel] diff --git a/src/cmake/fancy_add_executable.cmake b/src/cmake/fancy_add_executable.cmake index e00e48bfac..fea5c91b80 100644 --- a/src/cmake/fancy_add_executable.cmake +++ b/src/cmake/fancy_add_executable.cmake @@ -57,6 +57,17 @@ macro (fancy_add_executable) target_link_libraries (${_target_NAME} PRIVATE ${_target_LINK_LIBRARIES}) endif () set_target_properties (${_target_NAME} PROPERTIES FOLDER ${_target_FOLDER}) + if (SKBUILD) + # to a relative path to the distributio + # When building cli tools with scikit-build, set RPATHn's lib directory. + if (APPLE) + set_target_properties (${_target_NAME} PROPERTIES + INSTALL_RPATH "@loader_path/../${CMAKE_INSTALL_LIBDIR}") + else () + set_target_properties (${_target_NAME} PROPERTIES + INSTALL_RPATH "$ORIGIN/../${CMAKE_INSTALL_LIBDIR}") + endif () + endif () check_is_enabled (INSTALL_${_target_NAME} _target_NAME_INSTALL_enabled) if (CMAKE_UNITY_BUILD AND UNITY_BUILD_MODE STREQUAL GROUP) set_source_files_properties(${_target_SRC} PROPERTIES diff --git a/src/cmake/pythonutils.cmake b/src/cmake/pythonutils.cmake index e13e012995..3c07c674ea 100644 --- a/src/cmake/pythonutils.cmake +++ b/src/cmake/pythonutils.cmake @@ -126,6 +126,19 @@ macro (setup_python_module) # SUFFIX ".pyd") # endif() + if (SKBUILD) + set (PYTHON_SITE_DIR .) + # When building python wheels, set RPATH to a relative path to + # the distribution's lib directory. + if (APPLE) + set_target_properties (${target_name} PROPERTIES + INSTALL_RPATH "@loader_path/${CMAKE_INSTALL_LIBDIR}") + else () + set_target_properties (${target_name} PROPERTIES + INSTALL_RPATH "$ORIGIN/${CMAKE_INSTALL_LIBDIR}") + endif () + endif () + # In the build area, put it in lib/python so it doesn't clash with the # non-python libraries of the same name (which aren't prefixed by "lib" # on Windows). From 5f70b0ae907b665743c8fff135cd3b7efc358a49 Mon Sep 17 00:00:00 2001 From: Zach Lewis Date: Wed, 31 Jul 2024 12:02:50 -0400 Subject: [PATCH 011/147] build(python): Improve pip-based build experience * The build-directory is no longer hard-coded to a local "build_wheels" path. The 'repairwheel' tool needs to know where it can find any dynamic libs compiled by the build system; and, frustratingly, doesn't seem to consider libraries already bundled in the whl. We can either point repairwheel to directory within an unzipped whl; or, we can point repairwheel back to where the compiled dependencies live inside the build-directory, under .../dist/deps/lib. There isn't a straightforward way of passing information from skbuild to repairwheel directly; but here, we're using cibw to set an environment variable dictating to where scikit-build-core builds, which we can also reference in the repair-wheel step. * Always (re)build the TIFF dependency when building local wheels. This is a workaround for an issue where "Deflate::Deflate" either can't be found, or can't be redeclared, under certain circumstances. A more robust solution might be to instead write a FindLibdeflate.cmake module that adds an alias for Deflate::Deflate as needed. * Add "wheelhouse" directory created by cibuildwheel to .gitignore. Signed-off-by: Zach Lewis --- .gitignore | 1 + pyproject.toml | 30 +++++++++++++++++------------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index c8c897e967..d9d9275b6d 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ ext/ .DS_Store *.pyc _coverage/ +wheelhouse/ # Exclude test files I tend to leave around at the top level. The leading # slash ensures that files with these extensions within subdirectories are not diff --git a/pyproject.toml b/pyproject.toml index 3e4c9c6dad..99253f1d54 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,6 +36,7 @@ Source = "https://github.com/AcademySoftwareFoundation/OpenImageIO" Documentation = "https://openimageio.readthedocs.io" Issues = "https://github.com/AcademySoftwareFoundation/OpenImageIO/issues" + [project.scripts] iconvert = "OpenImageIO:_command_line" idiff = "OpenImageIO:_command_line" @@ -48,28 +49,27 @@ testtex = "OpenImageIO:_command_line" [build-system] build-backend = "scikit_build_core.build" requires = [ - "scikit-build-core>=0.9.8", + "scikit-build-core>=0.9.8,<1", "pybind11", "oldest-supported-numpy", - "repairwheel>=0.3.1", ] [tool.scikit-build.metadata.version] +# Dynamically parse the version from the CMakeLists.txt file. provider = "scikit_build_core.metadata.regex" -input = "CMakeLists.txt" # path to the CMakeLists.txt setting OpenImageIO_VERSION +input = "CMakeLists.txt" regex = 'set \(OpenImageIO_VERSION "(?P[0-9a-z.]+)"\)' [tool.scikit-build] cmake.verbose = false cmake.version = ">=3.29.1" -build-dir = "build_wheels" wheel.install-dir = "OpenImageIO" -wheel.packages = [] cmake.args = [ # OpenImageIO-2.6+ has a mechanism for building, linking, and # distributing missing dependencies. See src/cmake for details. "-DOpenImageIO_BUILD_MISSING_DEPS=all", - "-DOpenImageIO_BUILD_LOCAL_DEPS=all", + # Always locally build TIFF to prevent problems with cached rebuilds. + "-DOpenImageIO_BUILD_LOCAL_DEPS=TIFF", ] [tool.cibuildwheel] @@ -78,9 +78,9 @@ build = "cp39-* cp310-* cp311-* cp312-* cp313-* pp*" skip = [ "pp*", #"cp39-*", - #"cp310-*", - #"cp311-*", - #"cp312-*", + "cp310-*", + "cp311-*", + "cp312-*", "cp313-*", "*musllinux*", ] @@ -91,12 +91,16 @@ skip = [ before-build = "pipx install repairwheel" repair-wheel-command = """\ repairwheel \ - -l build_wheels/deps/dist/lib \ - -l build_wheels/lib \ + -l ${SKBUILD_BUILD_DIR}/deps/dist/lib \ + -l ${SKBUILD_BUILD_DIR}/lib \ -o {dest_dir} \ {wheel} """ +[tool.cibuildwheel.macos.environment] +SKBUILD_BUILD_DIR = "/tmp/build_wheels" + [tool.cibuildwheel.linux.environment] -# Suppress warnings that cause linux cibuildwheels build to fail -CXXFLAGS = "-Wno-error=stringop-overflow= -Wno-pragmas" +# Suppress warnings that cause linux cibuildwheel build to fail +CXXFLAGS = "-Wno-error=stringop-overflow= -Wno-pragmas" +SKBUILD_BUILD_DIR = "/tmp/build_wheels" \ No newline at end of file From 3337f705f7e7b91c159db7c7e9bef30cf2b1a84c Mon Sep 17 00:00:00 2001 From: Zach Lewis Date: Wed, 31 Jul 2024 13:02:53 -0400 Subject: [PATCH 012/147] build(python): Force TIFF to always build locally only for CIBW We don't want to locally build TIFF when it already exists; but if we build static TIFF libs locally once, we have to rebuild every time (i.e., for subsequent builds), or else "Deflate::Deflate" is forgotten. This commit forces TIFF to be rebuilt every time, but only for cibuildwheel unix builds. Under normal circumstances, only missing dependencies will be locally built. Signed-off-by: Zach Lewis --- pyproject.toml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 99253f1d54..c98dc3c6f8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,8 +68,6 @@ cmake.args = [ # OpenImageIO-2.6+ has a mechanism for building, linking, and # distributing missing dependencies. See src/cmake for details. "-DOpenImageIO_BUILD_MISSING_DEPS=all", - # Always locally build TIFF to prevent problems with cached rebuilds. - "-DOpenImageIO_BUILD_LOCAL_DEPS=TIFF", ] [tool.cibuildwheel] @@ -77,9 +75,9 @@ build-verbosity = 1 build = "cp39-* cp310-* cp311-* cp312-* cp313-* pp*" skip = [ "pp*", - #"cp39-*", - "cp310-*", - "cp311-*", + "cp39-*", + #"cp310-*", + #"cp311-*", "cp312-*", "cp313-*", "*musllinux*", @@ -97,10 +95,14 @@ repairwheel \ {wheel} """ + [tool.cibuildwheel.macos.environment] SKBUILD_BUILD_DIR = "/tmp/build_wheels" +SKBUILD_CMAKE_ARGS = "-DOpenImageIO_BUILD_LOCAL_DEPS=TIFF; -DOpenImageIO_BUILD_MISSING_DEPS=all" + [tool.cibuildwheel.linux.environment] # Suppress warnings that cause linux cibuildwheel build to fail CXXFLAGS = "-Wno-error=stringop-overflow= -Wno-pragmas" -SKBUILD_BUILD_DIR = "/tmp/build_wheels" \ No newline at end of file +SKBUILD_BUILD_DIR = "/tmp/build_wheels" +SKBUILD_CMAKE_ARGS = "-DOpenImageIO_BUILD_LOCAL_DEPS=TIFF; -DOpenImageIO_BUILD_MISSING_DEPS=all" \ No newline at end of file From 50f0b4ebd5c6dfbbd067c2db15f511ef1305a494 Mon Sep 17 00:00:00 2001 From: Zach Lewis Date: Wed, 7 Aug 2024 18:17:15 -0400 Subject: [PATCH 013/147] cleanup: fix comment, whitespace Signed-off-by: Zach Lewis --- src/cmake/fancy_add_executable.cmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cmake/fancy_add_executable.cmake b/src/cmake/fancy_add_executable.cmake index fea5c91b80..94926c6b2f 100644 --- a/src/cmake/fancy_add_executable.cmake +++ b/src/cmake/fancy_add_executable.cmake @@ -58,15 +58,15 @@ macro (fancy_add_executable) endif () set_target_properties (${_target_NAME} PROPERTIES FOLDER ${_target_FOLDER}) if (SKBUILD) - # to a relative path to the distributio - # When building cli tools with scikit-build, set RPATHn's lib directory. + # When building cli tools with scikit-build, set RPATH + # to a relative path to the distribution's lib directory. if (APPLE) set_target_properties (${_target_NAME} PROPERTIES INSTALL_RPATH "@loader_path/../${CMAKE_INSTALL_LIBDIR}") else () set_target_properties (${_target_NAME} PROPERTIES INSTALL_RPATH "$ORIGIN/../${CMAKE_INSTALL_LIBDIR}") - endif () + endif () endif () check_is_enabled (INSTALL_${_target_NAME} _target_NAME_INSTALL_enabled) if (CMAKE_UNITY_BUILD AND UNITY_BUILD_MODE STREQUAL GROUP) From 2013d09d3898c3c88dcf21c7256ad240d3122513 Mon Sep 17 00:00:00 2001 From: Zach Lewis Date: Wed, 7 Aug 2024 18:27:06 -0400 Subject: [PATCH 014/147] build: pyproject housekeeping Update pyproject.toml configuration The project's TOML file has been updated to reflect changes in the build system, dependencies, and licensing. The scikit-build-core version requirement has been bumped up, and new tools have been added for wheel repair and invocation. The license text has also been simplified to only include Apache-2.0. Signed-off-by: Zach Lewis --- pyproject.toml | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c98dc3c6f8..8dd096a9c6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,11 +7,10 @@ authors = [ {name = "OpenImageIO Contributors", email = "oiio-dev@lists.aswf.io"} ] maintainers = [ - {name = "Larry Gritz", email = "lg@larrygritz.com"}, {name = "OpenImageIO Contributors", email="oiio-dev@lists.aswf.io"}, ] readme = "README.md" -license = {text = "Apache-2.0, BSD-3-Clause"} +license = {text = "Apache-2.0"} keywords = [""] classifiers = [ "Development Status :: 4 - Beta", @@ -22,6 +21,7 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "License :: OSI Approved :: Apache Software License", "Topic :: Multimedia :: Graphics", "Topic :: Multimedia :: Video", "Topic :: Multimedia :: Video :: Display", @@ -49,32 +49,43 @@ testtex = "OpenImageIO:_command_line" [build-system] build-backend = "scikit_build_core.build" requires = [ - "scikit-build-core>=0.9.8,<1", + "scikit-build-core>=0.10,<1", "pybind11", - "oldest-supported-numpy", + #"invoke", + #"repairwheel", +] + +[tool.scikit-build] +minimum-version = "build-system.requires" +cmake.version = "CMakeLists.txt" +wheel.expand-macos-universal-tags = false +wheel.install-dir = "OpenImageIO" +wheel.license-files = [ + "LICENSE.md", + "THIRD-PARTY.md" ] +[tool.scikit-build.cmake.define] +# OpenImageIO-2.6+ has a mechanism for building, linking, and +# distributing missing dependencies. See src/cmake for details. +OpenImageIO_BUILD_MISSING_DEPS = "all" +CMAKE_INSTALL_LIBDIR = "lib" +CMAKE_BUILD_TYPE = "MinSizeRel" # Optimize for size (not speed) + [tool.scikit-build.metadata.version] # Dynamically parse the version from the CMakeLists.txt file. provider = "scikit_build_core.metadata.regex" input = "CMakeLists.txt" regex = 'set \(OpenImageIO_VERSION "(?P[0-9a-z.]+)"\)' -[tool.scikit-build] -cmake.verbose = false -cmake.version = ">=3.29.1" -wheel.install-dir = "OpenImageIO" -cmake.args = [ - # OpenImageIO-2.6+ has a mechanism for building, linking, and - # distributing missing dependencies. See src/cmake for details. - "-DOpenImageIO_BUILD_MISSING_DEPS=all", -] - [tool.cibuildwheel] build-verbosity = 1 build = "cp39-* cp310-* cp311-* cp312-* cp313-* pp*" skip = [ - "pp*", + #"pp*", + "pp38-*", + "pp39-*", + "pp310-*", "cp39-*", #"cp310-*", #"cp311-*", From 71808726b2d35d26c35de3349e77c40e32bc3317 Mon Sep 17 00:00:00 2001 From: Zach Lewis Date: Wed, 7 Aug 2024 19:08:17 -0400 Subject: [PATCH 015/147] build: slim down wheels w/ refactored CIBW repair-wheel-command step The wheel repair command in the pyproject.toml file has been refactored to use an invoke task. he before-build step now also installs invoke. A new tasks.py file has been added with a 'wheel_repair' task that slims down and repairs the wheel file. Step 1: Remove `lib`, `include`, `share` directories from wheel Step 2: Let `repairwheel` fix the wheel with freshly-built libraries found in {build_dir}/lib and {build_dir}/deps/dist/lib. Signed-off-by: Zach Lewis --- pyproject.toml | 16 +------- tasks.py | 103 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 14 deletions(-) create mode 100644 tasks.py diff --git a/pyproject.toml b/pyproject.toml index 8dd096a9c6..77b76201c8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -93,25 +93,13 @@ skip = [ "cp313-*", "*musllinux*", ] -# Repairwheel is a tool that gathers shared libraries and -# adjusts the rpath of the compiled wheels. The OIIO build -# process places any missing dependencies it compiles in -# the build_wheels/deps/dist/{lib,lib64} directories. -before-build = "pipx install repairwheel" -repair-wheel-command = """\ -repairwheel \ - -l ${SKBUILD_BUILD_DIR}/deps/dist/lib \ - -l ${SKBUILD_BUILD_DIR}/lib \ - -o {dest_dir} \ - {wheel} -""" - +before-build = "pipx install repairwheel && pipx install invoke" +repair-wheel-command = "invoke wheel-repair --build-dir ${SKBUILD_BUILD_DIR} --wheel-path {wheel} --output-dir {dest_dir}" [tool.cibuildwheel.macos.environment] SKBUILD_BUILD_DIR = "/tmp/build_wheels" SKBUILD_CMAKE_ARGS = "-DOpenImageIO_BUILD_LOCAL_DEPS=TIFF; -DOpenImageIO_BUILD_MISSING_DEPS=all" - [tool.cibuildwheel.linux.environment] # Suppress warnings that cause linux cibuildwheel build to fail CXXFLAGS = "-Wno-error=stringop-overflow= -Wno-pragmas" diff --git a/tasks.py b/tasks.py new file mode 100644 index 0000000000..a837a52fa6 --- /dev/null +++ b/tasks.py @@ -0,0 +1,103 @@ +import invoke +import logging +from pathlib import Path +import os +import shutil +import tempfile +import zipfile +logger = logging.getLogger(__name__) + + +def _wheel_edit(wheel_path): + """ + Edit the contents of the wheel to remove the 'lib', 'share', and 'include' directories, + and ensure all files under 'OpenImageIO/bin' are executable. + """ + dirs_to_remove = ['lib', 'lib64', 'share', 'include'] + + with tempfile.TemporaryDirectory() as tempdir: + # Unzip the wheel into the temporary directory + with zipfile.ZipFile(wheel_path, 'r') as zip_ref: + zip_ref.extractall(tempdir) + + # Remove the specified directories + for root, dirs, files in os.walk(tempdir): + for dir_name in dirs_to_remove: + dir_path = Path(root) / 'OpenImageIO' / dir_name + if dir_path.is_dir(): + logger.debug(f"Removing {dir_path}") + shutil.rmtree(dir_path) + + # Remove the RECORD file entries for the specified directories + record_file_path = None + for root, dirs, files in os.walk(tempdir): + for dir in dirs: + if dir.endswith(".dist-info"): + possible_record_file = Path(root) / dir / 'RECORD' + if possible_record_file.is_file(): + record_file_path = possible_record_file + break + if record_file_path: + break + + if record_file_path: + with open(record_file_path, 'r') as record_file: + lines = record_file.readlines() + + new_lines = [] + remove_prefixes = [f"OpenImageIO/{lib}" for lib in dirs_to_remove] + + for line in lines: + if not any(line.startswith(prefix) for prefix in remove_prefixes): + new_lines.append(line) + + with open(record_file_path, 'w') as record_file: + record_file.writelines(new_lines) + + # Ensure all files under 'OpenImageIO/bin' are executable + bin_dir = Path(tempdir) / 'OpenImageIO' / 'bin' + if bin_dir.exists(): + for file_path in bin_dir.iterdir(): + if file_path.is_file(): + logger.debug(f"Making {file_path} executable") + file_path.chmod(file_path.stat().st_mode | 0o111) + + # Create a new wheel file with the modifications + with zipfile.ZipFile(wheel_path, 'w') as zip_ref: + for root, dirs, files in os.walk(tempdir): + for file in files: + file_path = Path(root) / file + arcname = file_path.relative_to(tempdir) + zip_ref.write(file_path, arcname) + + logger.debug(f"Modified wheel created at {wheel_path}") + + return Path(wheel_path) + + +def _wheel_edit_alt(wheel): + """ + Edit the contents of the repaired wheel to remove the 'lib', 'share', and 'include' directories. + """ + from repairwheel._vendor.auditwheel.wheeltools import InWheelCtx + + dirs_to_remove = ['share', 'lib', 'lib64', 'include'] + + with InWheelCtx(wheel, wheel) as ctx: + root = Path(ctx.path) + for dir_name in dirs_to_remove: + this_dir = root/"OpenImageIO"/dir_name + if this_dir.exists(): + shutil.rmtree(this_dir) + + return Path(wheel) + + +@invoke.task +def wheel_repair(c, build_dir, wheel_path, output_dir): + """ + Slim down and repair the wheel file at `wheel_path` with libraries from `build_dir` and save the result to `output_dir`. + """ + edited_wheel_path = _wheel_edit(wheel_path) + c.run(f"repairwheel -l {build_dir}/deps/dist/lib -l {build_dir}/lib -o {output_dir} {edited_wheel_path}") + print(f"Repaired + slimmed wheel created at {output_dir}") From 1997724474e9c4245216dccebfa5889c952c5c55 Mon Sep 17 00:00:00 2001 From: Zach Lewis Date: Wed, 7 Aug 2024 21:00:22 -0400 Subject: [PATCH 016/147] build: add `rye` artifacts to gitignore Signed-off-by: Zach Lewis --- .gitignore | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index d9d9275b6d..abac34a22e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,14 +4,17 @@ branches/ build/ dist/ ext/ +wheelhouse/ +_coverage/ +.python-version .idea .vscode .cproject .project .DS_Store *.pyc -_coverage/ -wheelhouse/ +*.lock +gastest.o # Exclude test files I tend to leave around at the top level. The leading # slash ensures that files with these extensions within subdirectories are not @@ -22,3 +25,12 @@ wheelhouse/ /*.jxl /*.tx /*.log + + + + + + +requirements-dev.lock +requirements.lock +#gastest.o From 80acc8cbbe481e9dbef36b17b7579fe19da4fadc Mon Sep 17 00:00:00 2001 From: Zach Lewis Date: Wed, 7 Aug 2024 22:38:25 -0400 Subject: [PATCH 017/147] build: simplify wheel_edit task Signed-off-by: Zach Lewis --- pyproject.toml | 14 ++------- tasks.py | 79 ++++---------------------------------------------- 2 files changed, 9 insertions(+), 84 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 77b76201c8..20c1875390 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,20 +80,12 @@ regex = 'set \(OpenImageIO_VERSION "(?P[0-9a-z.]+)"\)' [tool.cibuildwheel] build-verbosity = 1 -build = "cp39-* cp310-* cp311-* cp312-* cp313-* pp*" +build = "pp* cp*" skip = [ - #"pp*", - "pp38-*", - "pp39-*", - "pp310-*", - "cp39-*", - #"cp310-*", - #"cp311-*", - "cp312-*", - "cp313-*", "*musllinux*", ] -before-build = "pipx install repairwheel && pipx install invoke" +#before-build = "pipx install repairwheel && pipx install invoke" +before-build = "pip install repairwheel && pip install invoke" repair-wheel-command = "invoke wheel-repair --build-dir ${SKBUILD_BUILD_DIR} --wheel-path {wheel} --output-dir {dest_dir}" [tool.cibuildwheel.macos.environment] diff --git a/tasks.py b/tasks.py index a837a52fa6..4e03d962c3 100644 --- a/tasks.py +++ b/tasks.py @@ -5,92 +5,25 @@ import shutil import tempfile import zipfile -logger = logging.getLogger(__name__) - - -def _wheel_edit(wheel_path): - """ - Edit the contents of the wheel to remove the 'lib', 'share', and 'include' directories, - and ensure all files under 'OpenImageIO/bin' are executable. - """ - dirs_to_remove = ['lib', 'lib64', 'share', 'include'] - - with tempfile.TemporaryDirectory() as tempdir: - # Unzip the wheel into the temporary directory - with zipfile.ZipFile(wheel_path, 'r') as zip_ref: - zip_ref.extractall(tempdir) - - # Remove the specified directories - for root, dirs, files in os.walk(tempdir): - for dir_name in dirs_to_remove: - dir_path = Path(root) / 'OpenImageIO' / dir_name - if dir_path.is_dir(): - logger.debug(f"Removing {dir_path}") - shutil.rmtree(dir_path) - - # Remove the RECORD file entries for the specified directories - record_file_path = None - for root, dirs, files in os.walk(tempdir): - for dir in dirs: - if dir.endswith(".dist-info"): - possible_record_file = Path(root) / dir / 'RECORD' - if possible_record_file.is_file(): - record_file_path = possible_record_file - break - if record_file_path: - break - - if record_file_path: - with open(record_file_path, 'r') as record_file: - lines = record_file.readlines() - new_lines = [] - remove_prefixes = [f"OpenImageIO/{lib}" for lib in dirs_to_remove] - - for line in lines: - if not any(line.startswith(prefix) for prefix in remove_prefixes): - new_lines.append(line) - - with open(record_file_path, 'w') as record_file: - record_file.writelines(new_lines) - - # Ensure all files under 'OpenImageIO/bin' are executable - bin_dir = Path(tempdir) / 'OpenImageIO' / 'bin' - if bin_dir.exists(): - for file_path in bin_dir.iterdir(): - if file_path.is_file(): - logger.debug(f"Making {file_path} executable") - file_path.chmod(file_path.stat().st_mode | 0o111) - - # Create a new wheel file with the modifications - with zipfile.ZipFile(wheel_path, 'w') as zip_ref: - for root, dirs, files in os.walk(tempdir): - for file in files: - file_path = Path(root) / file - arcname = file_path.relative_to(tempdir) - zip_ref.write(file_path, arcname) - - logger.debug(f"Modified wheel created at {wheel_path}") +logger = logging.getLogger(__name__) - return Path(wheel_path) - +DIRS_TO_REMOVE = ['lib', 'lib64', 'share', 'include'] -def _wheel_edit_alt(wheel): +def _wheel_edit(wheel_path, dirs_to_remove=DIRS_TO_REMOVE): """ Edit the contents of the repaired wheel to remove the 'lib', 'share', and 'include' directories. """ from repairwheel._vendor.auditwheel.wheeltools import InWheelCtx - dirs_to_remove = ['share', 'lib', 'lib64', 'include'] - - with InWheelCtx(wheel, wheel) as ctx: + with InWheelCtx(wheel_path, wheel_path) as ctx: root = Path(ctx.path) for dir_name in dirs_to_remove: - this_dir = root/"OpenImageIO"/dir_name + this_dir = root / "OpenImageIO" / dir_name if this_dir.exists(): shutil.rmtree(this_dir) - return Path(wheel) + return Path(wheel_path) @invoke.task From 2ee72cdc3d4e000f1fd40f85a73af74f769a1351 Mon Sep 17 00:00:00 2001 From: Zach Lewis Date: Wed, 7 Aug 2024 22:46:33 -0400 Subject: [PATCH 018/147] cleanup: add copyright and license information to tasks.py Also, tiny bit of tidying. Signed-off-by: Zach Lewis --- .gitignore | 7 ------- pyproject.toml | 1 - tasks.py | 4 ++++ 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index abac34a22e..5938f8d559 100644 --- a/.gitignore +++ b/.gitignore @@ -27,10 +27,3 @@ gastest.o /*.log - - - - -requirements-dev.lock -requirements.lock -#gastest.o diff --git a/pyproject.toml b/pyproject.toml index 20c1875390..fc063574b2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -84,7 +84,6 @@ build = "pp* cp*" skip = [ "*musllinux*", ] -#before-build = "pipx install repairwheel && pipx install invoke" before-build = "pip install repairwheel && pip install invoke" repair-wheel-command = "invoke wheel-repair --build-dir ${SKBUILD_BUILD_DIR} --wheel-path {wheel} --output-dir {dest_dir}" diff --git a/tasks.py b/tasks.py index 4e03d962c3..86ac831e75 100644 --- a/tasks.py +++ b/tasks.py @@ -1,3 +1,7 @@ +# Copyright Contributors to the OpenImageIO project. +# SPDX-License-Identifier: Apache-2.0 +# https://github.com/AcademySoftwareFoundation/OpenImageIO + import invoke import logging from pathlib import Path From 0f5e1a38eabfc5a4555b663d34577142ee855ea0 Mon Sep 17 00:00:00 2001 From: Zach Lewis Date: Tue, 27 Aug 2024 16:07:45 -0400 Subject: [PATCH 019/147] build(deps): add zlib build recipe Signed-off-by: Zach Lewis --- src/cmake/build_ZLIB.cmake | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/cmake/build_ZLIB.cmake diff --git a/src/cmake/build_ZLIB.cmake b/src/cmake/build_ZLIB.cmake new file mode 100644 index 0000000000..861e657821 --- /dev/null +++ b/src/cmake/build_ZLIB.cmake @@ -0,0 +1,24 @@ +# Copyright Contributors to the OpenImageIO project. +# SPDX-License-Identifier: Apache-2.0 +# https://github.com/AcademySoftwareFoundation/OpenImageIO + +###################################################################### +# ZLIB by hand! +###################################################################### + +set_cache (ZLIB_BUILD_VERSION 1.3.1 "ZLIB version for local builds") +set (ZLIB_GIT_REPOSITORY "https://github.com/madler/zlib") +set (ZLIB_GIT_TAG "v${ZLIB_BUILD_VERSION}") + +build_dependency_with_cmake(ZLIB + VERSION ${ZLIB_BUILD_VERSION} + GIT_REPOSITORY ${ZLIB_GIT_REPOSITORY} + GIT_TAG ${ZLIB_GIT_TAG} + ) + +# Set some things up that we'll need for a subsequent find_package to work +set (ZLIB_ROOT ${ZLIB_INSTALL_DIR}) + +# Signal to caller that we need to find again at the installed location +set (ZLIB_REFIND TRUE) +set (ZLIB_VERSION ${ZLIB_BUILD_VERSION}) From 13f60cead769e2ae6bfa122687d575d7328fc20c Mon Sep 17 00:00:00 2001 From: Zach Lewis Date: Fri, 30 Aug 2024 10:02:39 -0400 Subject: [PATCH 020/147] build(deps): add yaml-cpp build recipe It's an OCIO dependency. Signed-off-by: Zach Lewis --- src/cmake/build_yaml-cpp.cmake | 41 ++++++++++++++++++++++++++++++++ src/cmake/externalpackages.cmake | 8 +++++-- 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 src/cmake/build_yaml-cpp.cmake diff --git a/src/cmake/build_yaml-cpp.cmake b/src/cmake/build_yaml-cpp.cmake new file mode 100644 index 0000000000..f4ace68103 --- /dev/null +++ b/src/cmake/build_yaml-cpp.cmake @@ -0,0 +1,41 @@ +# Copyright Contributors to the OpenImageIO project. +# SPDX-License-Identifier: Apache-2.0 +# https://github.com/AcademySoftwareFoundation/OpenImageIO + +###################################################################### +# yaml-cpp by hand! +###################################################################### + +set_cache (yaml-cpp_BUILD_VERSION 0.8.0 "yaml-cpp version for local builds") +set (yaml-cpp_GIT_REPOSITORY "https://github.com/jbeder/yaml-cpp") +set (yaml-cpp_GIT_TAG "${yaml-cpp_BUILD_VERSION}") # NB: versions earlier than 0.8.0 had a "yaml-cpp-" prefix + +set_cache (yaml-cpp_BUILD_SHARED_LIBS ${LOCAL_BUILD_SHARED_LIBS_DEFAULT} + DOC "Should a local yaml-cpp build, if necessary, build shared libraries" ADVANCED) + +string (MAKE_C_IDENTIFIER ${yaml-cpp_BUILD_VERSION} yaml-cpp_VERSION_IDENT) + +build_dependency_with_cmake(yaml-cpp + VERSION ${yaml-cpp_BUILD_VERSION} + GIT_REPOSITORY ${yaml-cpp_GIT_REPOSITORY} + GIT_TAG ${yaml-cpp_GIT_TAG} + CMAKE_ARGS + -D YAML_CPP_BUILD_TESTS=OFF + -D YAML_CPP_BUILD_TOOLS=OFF + -D YAML_CPP_BUILD_CONTRIB=OFF + -D YAML_BUILD_SHARED_LIBS=${yaml-cpp_BUILD_SHARED_LIBS} + -D CMAKE_INSTALL_LIBDIR=lib + ) + +set (yaml-cpp_ROOT ${yaml-cpp_LOCAL_INSTALL_DIR}) +set (yaml-cpp_DIR ${yaml-cpp_LOCAL_INSTALL_DIR}) +set (yaml-cpp_VERSION ${yaml-cpp_BUILD_VERSION}) + +set (yaml-cpp_REFIND TRUE) +set (yaml-cpp_REFIND_ARGS CONFIG) +set (yaml-cpp_REFIND_VERSION ${yaml-cpp_BUILD_VERSION}) + + +if (yaml-cpp_BUILD_SHARED_LIBS) + install_local_dependency_libs (yaml-cpp yaml-cpp) +endif () diff --git a/src/cmake/externalpackages.cmake b/src/cmake/externalpackages.cmake index 71439639c1..acecc0244b 100644 --- a/src/cmake/externalpackages.cmake +++ b/src/cmake/externalpackages.cmake @@ -129,8 +129,12 @@ checked_find_package (Freetype VERSION_MIN 2.10.0 DEFINITIONS USE_FREETYPE=1 ) -checked_find_package (OpenColorIO - VERSION_MIN 1.1 + +checked_find_package (yaml-cpp + VERSION_MIN 0.6.0 ) # Used by OpenColorIO + +checked_find_package (OpenColorIO REQUIRED + VERSION_MIN 2.2 VERSION_MAX 2.9 NO_FP_RANGE_CHECK DEFINITIONS USE_OCIO=1 USE_OPENCOLORIO=1 From b96525e8b63add02695f017db6f6105940a91cad Mon Sep 17 00:00:00 2001 From: Zach Lewis Date: Wed, 4 Sep 2024 13:36:33 -0400 Subject: [PATCH 021/147] build(python): On windows, include Development.Embed Python3 component Apparently MSVC is having trouble linking Python3::Python otherwise... Signed-off-by: Zach Lewis --- src/cmake/pythonutils.cmake | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/cmake/pythonutils.cmake b/src/cmake/pythonutils.cmake index 3c07c674ea..39e525b90e 100644 --- a/src/cmake/pythonutils.cmake +++ b/src/cmake/pythonutils.cmake @@ -32,10 +32,20 @@ macro (find_python) list (APPEND _req EXACT) endif () endif () + + # Support building on manylinux docker images, which do not contain + # the Development.Embedded component. + # https://pybind11.readthedocs.io/en/stable/compiling.html#findpython-mode + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.18.0" AND NOT WIN32) + set (_py_components Interpreter Development.Module) + else () + set (_py_components Interpreter Development) + endif () + checked_find_package (Python3 ${PYTHON_VERSION} ${_req} VERSION_MIN 3.7 - COMPONENTS Interpreter Development.Module + COMPONENTS ${_py_components} PRINT Python3_VERSION Python3_EXECUTABLE Python3_LIBRARIES Python3_Development_FOUND From 42caf759dd87a57db7b521f4f5655bfe3e55625c Mon Sep 17 00:00:00 2001 From: Zach Lewis Date: Fri, 6 Sep 2024 13:27:56 -0400 Subject: [PATCH 022/147] build(python): Increase verbosity of scikit-build-core build Signed-off-by: Zach Lewis --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index fc063574b2..719b06106e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,6 +57,7 @@ requires = [ [tool.scikit-build] minimum-version = "build-system.requires" +cmake.verbose = true cmake.version = "CMakeLists.txt" wheel.expand-macos-universal-tags = false wheel.install-dir = "OpenImageIO" From 5a70d3ed22489d142a608c79de319ddfc6fed2ef Mon Sep 17 00:00:00 2001 From: Zach Lewis Date: Mon, 9 Sep 2024 13:41:20 -0400 Subject: [PATCH 023/147] build(wheels): Refine build process and Windows compatibility - Lowered the required Python version from 3.9 to 3.7 - Added numpy as a new dependency - Refined DLL loading for Windows in Python 3.8+ - Adjusted build verbosity settings - Moved CMAKE_INSTALL_LIBDIR setting into platform-specific overrides for Linux and macOS only - On Windows, do not make adjustments to the INSTALL_RPATH. - Reorganized variables in cibuildwheel configuration for better readability - Refactored variable names in __init__._call_program function to follow PEP8 guidelines Signed-off-by: Zach Lewis --- pyproject.toml | 34 ++++++++++++++++------- src/cmake/fancy_add_executable.cmake | 2 +- src/cmake/pythonutils.cmake | 4 +-- src/python/__init__.py | 40 ++++++++++++++++++---------- 4 files changed, 53 insertions(+), 27 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 719b06106e..1cb1fe58d8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,8 +27,8 @@ classifiers = [ "Topic :: Multimedia :: Video :: Display", "Topic :: Software Development :: Libraries :: Python Modules", ] -dependencies = [] -requires-python = ">= 3.9" +dependencies = ["numpy"] +requires-python = ">= 3.7" [project.urls] Homepage = "https://openimageio.org/" @@ -51,13 +51,11 @@ build-backend = "scikit_build_core.build" requires = [ "scikit-build-core>=0.10,<1", "pybind11", - #"invoke", - #"repairwheel", ] [tool.scikit-build] minimum-version = "build-system.requires" -cmake.verbose = true +build.verbose = true cmake.version = "CMakeLists.txt" wheel.expand-macos-universal-tags = false wheel.install-dir = "OpenImageIO" @@ -70,7 +68,6 @@ wheel.license-files = [ # OpenImageIO-2.6+ has a mechanism for building, linking, and # distributing missing dependencies. See src/cmake for details. OpenImageIO_BUILD_MISSING_DEPS = "all" -CMAKE_INSTALL_LIBDIR = "lib" CMAKE_BUILD_TYPE = "MinSizeRel" # Optimize for size (not speed) [tool.scikit-build.metadata.version] @@ -79,21 +76,38 @@ provider = "scikit_build_core.metadata.regex" input = "CMakeLists.txt" regex = 'set \(OpenImageIO_VERSION "(?P[0-9a-z.]+)"\)' +# On Linux and macOS, we want to install libraries to lib to help +# with RPATH issues. This is not necessary on Windows. +[[tool.scikit-build.overrides]] +if.any.platform-system = "linux" +inherit.cmake.define = "append" +cmake.define.CMAKE_INSTALL_LIBDIR = "lib" + +[[tool.scikit-build.overrides]] +if.any.platform-system = "darwin" +inherit.cmake.define = "append" +cmake.define.CMAKE_INSTALL_LIBDIR = "lib" + [tool.cibuildwheel] build-verbosity = 1 build = "pp* cp*" skip = [ - "*musllinux*", + "*musllinux*", # building with musl seems to work, but the repairwheel step seems to fail... ] before-build = "pip install repairwheel && pip install invoke" repair-wheel-command = "invoke wheel-repair --build-dir ${SKBUILD_BUILD_DIR} --wheel-path {wheel} --output-dir {dest_dir}" [tool.cibuildwheel.macos.environment] +# Specify a build directory so the repairwheel command can (re)find +# dependency libraries built by OpenImageIO. SKBUILD_BUILD_DIR = "/tmp/build_wheels" +# Always (re)build the TIFF library; otherwise, OIIO has trouble +# with libdeflate when building successive permutations of python +# wheels against the build cache. SKBUILD_CMAKE_ARGS = "-DOpenImageIO_BUILD_LOCAL_DEPS=TIFF; -DOpenImageIO_BUILD_MISSING_DEPS=all" [tool.cibuildwheel.linux.environment] -# Suppress warnings that cause linux cibuildwheel build to fail -CXXFLAGS = "-Wno-error=stringop-overflow= -Wno-pragmas" SKBUILD_BUILD_DIR = "/tmp/build_wheels" -SKBUILD_CMAKE_ARGS = "-DOpenImageIO_BUILD_LOCAL_DEPS=TIFF; -DOpenImageIO_BUILD_MISSING_DEPS=all" \ No newline at end of file +SKBUILD_CMAKE_ARGS = "-DOpenImageIO_BUILD_LOCAL_DEPS=TIFF; -DOpenImageIO_BUILD_MISSING_DEPS=all" +# Suppress warnings that cause linux cibuildwheel build to fail +CXXFLAGS = "-Wno-error=stringop-overflow= -Wno-pragmas" \ No newline at end of file diff --git a/src/cmake/fancy_add_executable.cmake b/src/cmake/fancy_add_executable.cmake index 94926c6b2f..d216ee99fd 100644 --- a/src/cmake/fancy_add_executable.cmake +++ b/src/cmake/fancy_add_executable.cmake @@ -63,7 +63,7 @@ macro (fancy_add_executable) if (APPLE) set_target_properties (${_target_NAME} PROPERTIES INSTALL_RPATH "@loader_path/../${CMAKE_INSTALL_LIBDIR}") - else () + elseif (LINUX) set_target_properties (${_target_NAME} PROPERTIES INSTALL_RPATH "$ORIGIN/../${CMAKE_INSTALL_LIBDIR}") endif () diff --git a/src/cmake/pythonutils.cmake b/src/cmake/pythonutils.cmake index 39e525b90e..0addbaa73d 100644 --- a/src/cmake/pythonutils.cmake +++ b/src/cmake/pythonutils.cmake @@ -137,13 +137,13 @@ macro (setup_python_module) # endif() if (SKBUILD) - set (PYTHON_SITE_DIR .) + # set (PYTHON_SITE_DIR .) # When building python wheels, set RPATH to a relative path to # the distribution's lib directory. if (APPLE) set_target_properties (${target_name} PROPERTIES INSTALL_RPATH "@loader_path/${CMAKE_INSTALL_LIBDIR}") - else () + elseif (LINUX) set_target_properties (${target_name} PROPERTIES INSTALL_RPATH "$ORIGIN/${CMAKE_INSTALL_LIBDIR}") endif () diff --git a/src/python/__init__.py b/src/python/__init__.py index f898cdf2ee..df13290817 100644 --- a/src/python/__init__.py +++ b/src/python/__init__.py @@ -4,19 +4,31 @@ import os, sys, platform, subprocess -# This works around the python 3.8 change to stop loading DLLs from PATH on Windows. -# We reproduce the old behaviour by manually tokenizing PATH, checking that the directories exist and are not ".", -# then add them to the DLL load path. -# This behviour can be disabled by setting the environment variable "OIIO_LOAD_DLLS_FROM_PATH" to "0" -if sys.version_info >= (3, 8) and platform.system() == "Windows" and os.getenv("OIIO_LOAD_DLLS_FROM_PATH", "1") == "1": - for path in os.getenv("PATH", "").split(os.pathsep): - if os.path.exists(path) and path != ".": - os.add_dll_directory(path) - -from .OpenImageIO import * - -__version__ = VERSION_STRING +if platform.system() == "Windows": + # Python wheel module is dynamically linked to the OIIO DLL present in the bin folder. + here = os.path.abspath(os.path.dirname(__file__)) + bin_dir = os.path.join(here, "bin") + if os.path.exists(bin_dir): + if sys.version_info >= (3, 8): + os.add_dll_directory(bin_dir) + else: + os.environ['PATH'] = '{0};{1}'.format(bin_dir, os.getenv('PATH', '')) + + if sys.version_info >= (3, 8): + # This works around the python 3.8 change to stop loading DLLs from PATH on Windows. + # We reproduce the old behavior by manually tokenizing PATH, checking that the + # directories exist and are not ".", then add them to the DLL load path. + # Set the environment variable "OIIO_LOAD_DLLS_FROM_PATH" to "0" to disable this behavior. + if os.getenv("OIIO_LOAD_DLLS_FROM_PATH", "1") == "1": + for path in os.getenv("PATH", "").split(os.pathsep): + if os.path.exists(path) and path != ".": + os.add_dll_directory(path) + + +from .OpenImageIO import * # noqa: F401, F403 + +__version__ = VERSION_STRING # noqa: F405 __status__ = "dev" @@ -36,8 +48,8 @@ def _call_program(name, args): - BIN_DIR = os.path.join(os.path.dirname(__file__), 'bin') - return subprocess.call([os.path.join(BIN_DIR, name)] + args) + bin_dir = os.path.join(os.path.dirname(__file__), 'bin') + return subprocess.call([os.path.join(bin_dir, name)] + args) def _command_line(): name = os.path.basename(sys.argv[0]) From 151333fda67cac93faccf6b64f7f96f97415132d Mon Sep 17 00:00:00 2001 From: Zach Lewis Date: Tue, 10 Sep 2024 08:55:35 -0400 Subject: [PATCH 024/147] cleanup(python): formatting for PEP compliance Signed-off-by: Zach Lewis --- src/python/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/python/__init__.py b/src/python/__init__.py index df13290817..f02bba7535 100644 --- a/src/python/__init__.py +++ b/src/python/__init__.py @@ -2,7 +2,10 @@ # SPDX-License-Identifier: Apache-2.0 # https://github.com/AcademySoftwareFoundation/OpenImageIO -import os, sys, platform, subprocess +import os +import sys +import platform +import subprocess if platform.system() == "Windows": From 081054408fa6b7d406bd9d4b0949d0800aa9937b Mon Sep 17 00:00:00 2001 From: Zach Lewis Date: Tue, 10 Sep 2024 09:06:56 -0400 Subject: [PATCH 025/147] ci: add wheel workflow Stolen nearly line-for-line from OpenColorIO's wheel workflow. Signed-off-by: Zach Lewis --- .github/workflows/wheel.yml | 319 ++++++++++++++++++++++++++++++++++++ 1 file changed, 319 insertions(+) create mode 100644 .github/workflows/wheel.yml diff --git a/.github/workflows/wheel.yml b/.github/workflows/wheel.yml new file mode 100644 index 0000000000..368a40be57 --- /dev/null +++ b/.github/workflows/wheel.yml @@ -0,0 +1,319 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright Contributors to the OpenImageIO Project. +# + +name: Wheel + +on: + push: + # Workflow run on tags for v2.6 and v3 only. + tags: + - v2.6.* + - v3.* + pull_request: + # Workflow run on pull_request only when related files change. + branches-ignore: + - dev-* + - lg-* + - rtd + - sonar-1 + paths: + - .github/workflows/wheel.yml + - pyproject.toml + - tasks.py + - src/python/OpenImageIO/*.py + - src/cmake/pythonutils.cmake + schedule: + # Nightly build + - cron: "0 0 * * *" + +jobs: + # Linux jobs run in Docker containers (manylinux), so the latest OS version + # is OK. macOS and Windows jobs need to be locked to specific virtual + # environment versions to mitigate issues from OS updates, and will require + # maintenance as OS versions are retired. + # + # Due to documentation build failing on manylinux2010 (maybe too old doxygen + # version), we build on manylinux2014 image, this requires pip >= 19.3. + + # --------------------------------------------------------------------------- + # Source Distribution + # --------------------------------------------------------------------------- + + sdist: + name: Build SDist + runs-on: ubuntu-latest + # Don't run on OIIO forks + if: | + github.event_name != 'schedule' || + github.repository == 'AcademySoftwareFoundation/OpenImageIO' || + github.repository == 'zachlewis/OpenImageIO' + + steps: + + - uses: actions/checkout@v4 + + - name: Build SDist + run: pipx run build --sdist + + - name: Check metadata + run: pipx run twine check dist/* + + - uses: actions/upload-artifact@v4 + with: + name: cibw-sdist + path: dist/*.tar.gz + + # --------------------------------------------------------------------------- + # Linux Wheels + # --------------------------------------------------------------------------- + + linux: + name: Build wheels on Linux + runs-on: ubuntu-latest + # Don't run on OIIO forks + if: | + github.event_name != 'schedule' || + github.repository == 'AcademySoftwareFoundation/OpenImageIO' || + github.repository == 'zachlewis/OpenImageIO' + strategy: + matrix: + include: + # ------------------------------------------------------------------- + # CPython 64 bits manylinux_2_28 + # ------------------------------------------------------------------- + - build: CPython 3.8 64 bits manylinux_2_28 + manylinux: manylinux_2_28 + python: cp38-manylinux_x86_64 + arch: x86_64 + - build: CPython 3.9 64 bits manylinux_2_28 + manylinux: manylinux_2_28 + python: cp39-manylinux_x86_64 + arch: x86_64 + - build: CPython 3.10 64 bits manylinux_2_28 + manylinux: manylinux_2_28 + python: cp310-manylinux_x86_64 + arch: x86_64 + - build: CPython 3.11 64 bits manylinux_2_28 + manylinux: manylinux_2_28 + python: cp311-manylinux_x86_64 + arch: x86_64 + - build: CPython 3.12 64 bits manylinux_2_28 + manylinux: manylinux_2_28 + python: cp312-manylinux_x86_64 + arch: x86_64 + # ------------------------------------------------------------------- + # CPython 64 bits manylinux2014 + # ------------------------------------------------------------------- + - build: CPython 3.8 64 bits manylinux2014 + manylinux: manylinux2014 + python: cp38-manylinux_x86_64 + arch: x86_64 + - build: CPython 3.9 64 bits manylinux2014 + manylinux: manylinux2014 + python: cp39-manylinux_x86_64 + arch: x86_64 + - build: CPython 3.10 64 bits manylinux2014 + manylinux: manylinux2014 + python: cp310-manylinux_x86_64 + arch: x86_64 + - build: CPython 3.11 64 bits manylinux2014 + manylinux: manylinux2014 + python: cp311-manylinux_x86_64 + arch: x86_64 + - build: CPython 3.12 64 bits manylinux2014 + manylinux: manylinux2014 + python: cp312-manylinux_x86_64 + arch: x86_64 + # ------------------------------------------------------------------- + # CPython ARM 64 bits manylinux2014 + # ------------------------------------------------------------------- + - build: CPython 3.8 ARM 64 bits manylinux2014 + manylinux: manylinux2014 + python: cp38-manylinux_aarch64 + arch: aarch64 + - build: CPython 3.9 ARM 64 bits manylinux2014 + manylinux: manylinux2014 + python: cp39-manylinux_aarch64 + arch: aarch64 + - build: CPython 3.10 ARM 64 bits manylinux2014 + manylinux: manylinux2014 + python: cp310-manylinux_aarch64 + arch: aarch64 + - build: CPython 3.11 ARM 64 bits manylinux2014 + manylinux: manylinux2014 + python: cp311-manylinux_aarch64 + arch: aarch64 + - build: CPython 3.12 ARM 64 bits manylinux2014 + manylinux: manylinux2014 + python: cp312-manylinux_aarch64 + arch: aarch64 + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + name: Install Python + with: + python-version: '3.8' + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + with: + platforms: all + + - name: Build wheels + uses: pypa/cibuildwheel@v2.16.5 + env: + CIBW_BUILD: ${{ matrix.python }} + CIBW_ARCHS: ${{ matrix.arch }} + CIBW_MANYLINUX_X86_64_IMAGE: ${{ matrix.manylinux }} + CIBW_MANYLINUX_AARCH64_IMAGE: ${{ matrix.manylinux }} + + - uses: actions/upload-artifact@v4 + with: + name: cibw-wheels-${{ matrix.python }}-${{ matrix.manylinux }} + path: ./wheelhouse/*.whl + + # --------------------------------------------------------------------------- + # macOS Wheels + # --------------------------------------------------------------------------- + + macos: + name: Build wheels on macOS + runs-on: macos-12 + # Don't run on OIIO forks + if: | + github.event_name != 'schedule' || + github.repository == 'AcademySoftwareFoundation/OpenImageIO' || + github.repository == 'zachlewis/OpenImageIO' + strategy: + matrix: + include: + # ------------------------------------------------------------------- + # CPython 64 bits + # ------------------------------------------------------------------- + - build: CPython 3.8 64 bits + python: cp38-macosx_x86_64 + arch: x86_64 + - build: CPython 3.9 64 bits + python: cp39-macosx_x86_64 + arch: x86_64 + - build: CPython 3.10 64 bits + python: cp310-macosx_x86_64 + arch: x86_64 + - build: CPython 3.11 64 bits + python: cp311-macosx_x86_64 + arch: x86_64 + - build: CPython 3.12 64 bits + python: cp312-macosx_x86_64 + arch: x86_64 + # ------------------------------------------------------------------- + # CPython ARM 64 bits + # ------------------------------------------------------------------- + - build: CPython 3.8 ARM 64 bits + python: cp38-macosx_arm64 + arch: arm64 + - build: CPython 3.9 ARM 64 bits + python: cp39-macosx_arm64 + arch: arm64 + - build: CPython 3.10 ARM 64 bits + python: cp310-macosx_arm64 + arch: arm64 + - build: CPython 3.11 ARM 64 bits + python: cp311-macosx_arm64 + arch: arm64 + - build: CPython 3.12 ARM 64 bits + python: cp312-macosx_arm64 + arch: arm64 + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + name: Install Python + with: + python-version: '3.8' + + - name: Build wheels + uses: pypa/cibuildwheel@v2.16.5 + env: + CIBW_BUILD: ${{ matrix.python }} + CIBW_ARCHS: ${{ matrix.arch }} + + - uses: actions/upload-artifact@v4 + with: + name: cibw-wheels-${{ matrix.python }} + path: ./wheelhouse/*.whl + + # --------------------------------------------------------------------------- + # Windows Wheels + # --------------------------------------------------------------------------- + + windows: + name: Build wheels on Windows + runs-on: windows-2022 + # Don't run on OIIO forks + if: | + github.event_name != 'schedule' || + github.repository == 'AcademySoftwareFoundation/OpenImageIO' || + github.repository == 'zachlewis/OpenImageIO' + strategy: + matrix: + include: + # ------------------------------------------------------------------- + # CPython 64 bits + # ------------------------------------------------------------------- + - build: CPython 3.8 64 bits + python: cp38-win_amd64 + arch: AMD64 + - build: CPython 3.9 64 bits + python: cp39-win_amd64 + arch: AMD64 + - build: CPython 3.10 64 bits + python: cp310-win_amd64 + arch: AMD64 + - build: CPython 3.11 64 bits + python: cp311-win_amd64 + arch: AMD64 + - build: CPython 3.12 64 bits + python: cp312-win_amd64 + arch: AMD64 + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + name: Install Python + with: + python-version: '3.8' + + - name: Build wheels + uses: pypa/cibuildwheel@v2.16.5 + env: + CIBW_BUILD: ${{ matrix.python }} + CIBW_ARCHS: ${{ matrix.arch }} + + - uses: actions/upload-artifact@v4 + with: + name: cibw-wheels-${{ matrix.python }} + path: ./wheelhouse/*.whl + + + # upload_pypi: + # needs: [sdist, linux, macos, windows] + # runs-on: ubuntu-latest + # if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/v') + # steps: + # - uses: actions/setup-python@v5 + + # - uses: actions/download-artifact@v4 + # with: + # pattern: cibw-* + # path: dist + # merge-multiple: true + + # - uses: pypa/gh-action-pypi-publish@release/v1 + # with: + # user: __token__ + # password: ${{ secrets.PYPI_API_TOKEN }} \ No newline at end of file From bf4265e8c47b31d4e890d9c545c2a0791bab664b Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Fri, 2 Aug 2024 10:31:31 +1200 Subject: [PATCH 026/147] fix(IB): copy/paste error in the ImageBuf iterator copy constructor (#4365) Fixes a simple copy/paste error in a copy constructor where the y coordinate gets initialised twice instead of y and z. Signed-off-by: Anton Dukhovnikov Signed-off-by: Zach Lewis --- src/libOpenImageIO/imagebuf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libOpenImageIO/imagebuf.cpp b/src/libOpenImageIO/imagebuf.cpp index a31fd320c2..6781d7ef2a 100644 --- a/src/libOpenImageIO/imagebuf.cpp +++ b/src/libOpenImageIO/imagebuf.cpp @@ -3129,7 +3129,7 @@ ImageBuf::IteratorBase::operator=(const IteratorBase& i) m_rng_zend = i.m_rng_zend; m_x = i.m_x; m_y = i.m_y; - m_y = i.m_y; + m_z = i.m_z; return *this; } From 1c7cd37d7959c45c21267812b430b906ab1bb1a0 Mon Sep 17 00:00:00 2001 From: Larry Gritz Date: Wed, 7 Aug 2024 11:52:01 -0700 Subject: [PATCH 027/147] feat(oiiotool): additional stack commands and --for improvement (#4348) Additional stack manipulation commands: * `--popbottom` discards the bottom-of-stack image * `--stackreverse` reverses the order of the whole stack * `--stackclear` fully empties the stack * `--stackextract ` moves the indexed item from the stack (index 0 means the top) to the top. Make `--for` work correctly in both directions: * Correct behavior if `--for` has a negative step value. * If the end value is less than the begin value and no step is supplied, assume -1 (analogous to how we usually assueme step=1 under ordinary circumstances). * Error if step is 0 (presume it will make an infinite loop). Signed-off-by: Larry Gritz Signed-off-by: Zach Lewis --- src/doc/oiiotool.rst | 70 ++++++++++---- src/oiiotool/oiiotool.cpp | 122 ++++++++++++++++++++++--- src/oiiotool/oiiotool.h | 11 +++ testsuite/oiiotool-control/ref/out.txt | 49 ++++++++++ testsuite/oiiotool-control/run.py | 62 ++++++++++--- 5 files changed, 268 insertions(+), 46 deletions(-) diff --git a/src/doc/oiiotool.rst b/src/doc/oiiotool.rst index ed14ff5a82..47d39ae177 100644 --- a/src/doc/oiiotool.rst +++ b/src/doc/oiiotool.rst @@ -273,11 +273,12 @@ The usual programming constructs are supported: * Iteration : `--for` *variable* *range* *commands...* `--endfor` The range is a sequence of one to three comma-separated numbers: *begin*, - *end*, and *step*; *begin* and *end* (step is assumed to be 1); or just - *end* (begin assumed to be 0, step assumed to be 1). As in Python, the range - has an "exclusive end" -- when the *variable* is equal to *end*, the loop - will terminate, without actually running the commands for the *end* value - itself. + *end*, and *step*; *begin* and *end* (step is assumed to be 1 if *begin* + `<`` *end*, or -1 if *begin* `>` *end); or just *end* (begin assumed to be + 0, step assumed to be 1 or -1, depending on the relationship between *begin* + and *end*). As in Python, the range has an "exclusive end" -- when the + *variable* is equal to *end*, the loop will terminate, without actually + running the commands for the *end* value itself. Section :ref:`sec-oiiotool-control-flow-commands` contains more detailed descriptions of these commands and some examples to more clearly illustrate @@ -1023,11 +1024,12 @@ output each one to a different file, with names `sub0001.tif`, for each iteration. The range may be one, two, or three numbers separated by commas, indicating - - *end* : Iterate from 0 to *end*, incrementing by 1 each time. - - *begin* ``,`` *end* : Iterate from *begin* to *end*, incrementing - by 1 each time. + - *end* : Iterate from 0 to *end*, incrementing by 1 each iteration (or + decrementing, if *end* `<` 0). + - *begin* ``,`` *end* : Iterate from *begin* to *end*, incrementing by + 1 each iteration (or decrementing by 1, if *end* `<` *begin*). - *begin* ``,`` *end* ``,`` *step* : Iterate from *begin* to *end*, - incrementing by *step* each time. + adding *step* to the value after each iteration. Note that the *end* value is "exclusive," that is, the loop will terminate once the value is equal to end, and the loop body will @@ -1054,6 +1056,13 @@ output each one to a different file, with names `sub0001.tif`, 7 9 + $ oiiotool --for i 5,0,-1 --echo "i = {i}" --endfor + 5 + 4 + 3 + 2 + 1 + .. option:: --while commands... --endwhile If the *condition* is true, execute *commands*, and keep doing that @@ -2230,10 +2239,16 @@ current top image. :program:`oiiotool` commands that adjust the image stack ======================================================== -.. option:: --pop +.. option:: --label - Pop the image stack, discarding the current image and thereby making the - next image on the stack into the new current image. + Gives a name to (and saves) the current image at the top of the stack. + Thereafter, the label name may be used to refer to that saved image, in + the usual manner that an ordinary input image would be specified by + filename. + + The name of the label must be in the form of an "identifier" (a sequence + of alphanumeric characters and underscores, starting with a letter or + underscore). .. option:: --dup @@ -2245,16 +2260,31 @@ current top image. Swap the current image and the next one on the stack. -.. option:: --label +.. option:: --pop - Gives a name to (and saves) the current image at the top of the stack. - Thereafter, the label name may be used to refer to that saved image, in - the usual manner that an ordinary input image would be specified by - filename. + Pop the image stack, discarding the current image and thereby making the + next image on the stack into the new current image. - The name of the label must be in the form of an "identifier" (a sequence - of alphanumeric characters and underscores, starting with a letter or - underscore). +.. option:: --popbottom + + Remove and discard the bottom image from the image stack. + (Added in OIIO 3.0.) + +.. option:: --stackreverse + + Reverse the order of the entire stack, i.e. making the top be the new + bottom and the old bottom be the new top. (Added in OIIO 3.0.) + +.. option:: --stackextract + + Move the indexed item (0 for the top of the stack, 1 for the next item + down, etc.) to the top of the stack, preserving the relative order of all + other items. (Added in OIIO 3.0.) + +.. option:: --stackclear + + Remove all items from the stack, leaving it empty and with no "current" + image. (Added in OIIO 3.0.) :program:`oiiotool` commands that make entirely new images diff --git a/src/oiiotool/oiiotool.cpp b/src/oiiotool/oiiotool.cpp index a7e07b35cc..e517d6bd20 100644 --- a/src/oiiotool/oiiotool.cpp +++ b/src/oiiotool/oiiotool.cpp @@ -1234,12 +1234,30 @@ control_for(Oiiotool& ot, cspan argv) std::string variable = ot.express(argv[1]); string_view range = ot.express(argv[2]); + float val = 0, limit = 0, step = 1; + bool valid = true; auto rangevals = Strutil::extract_from_list_string(range); - if (rangevals.size() == 1) - rangevals.insert(rangevals.begin(), 0.0f); // supply missing start - if (rangevals.size() == 2) - rangevals.push_back(1.0f); // supply missing step - if (rangevals.size() != 3) { + if (rangevals.size() == 1) { + val = 0.0f; + limit = rangevals[0]; + step = limit >= 0.0f ? 1.0f : -1.0f; + } else if (rangevals.size() == 2) { + val = rangevals[0]; + limit = rangevals[1]; + step = limit >= val ? 1.0f : -1.0f; + } else if (rangevals.size() == 3) { + val = rangevals[0]; + limit = rangevals[1]; + step = rangevals[2]; + } else { + valid = false; + } + // step can't be zero or be opposite direction of val -> limit + valid &= (step != 0.0f); + if ((val < limit && step < 0.0f) || (val > limit && step > 0.0f)) + valid = false; + + if (!valid) { ot.errorfmt(argv[0], "Invalid range \"{}\"", range); return; } @@ -1249,24 +1267,22 @@ control_for(Oiiotool& ot, cspan argv) // There are two cases here: either we are hitting this --for // for the first time (need to initialize and set up the control // record), or we are re-iterating on a loop we already set up. - float val; if (ot.control_stack.empty() || ot.control_stack.top().start_arg != ot.ap.current_arg()) { // First time through the loop. Note that we recognize our first // time by the fact that the top of the control stack doesn't have // a start_arg that is this --for command. - val = rangevals[0]; ot.push_control("for", ot.ap.current_arg(), true); // Strutil::print("First for!\n"); } else { // We've started this loop already, this is at least our 2nd time // through. Just increment the variable and update the condition // for another pass through the loop. - val = ot.uservars.get_float(variable) + rangevals[2]; + val = ot.uservars.get_float(variable) + step; // Strutil::print("Repeat for!\n"); } ot.uservars.attribute(variable, val); - bool cond = val < rangevals[1]; + bool cond = step >= 0.0f ? val < limit : val > limit; ot.control_stack.top().condition = cond; ot.ap.running(ot.running()); // Strutil::print("for {} {} : {}={} cond={} (now running={})\n", variable, @@ -3439,6 +3455,16 @@ action_pop(Oiiotool& ot, cspan argv) +// --popbottom +static void +action_popbottom(Oiiotool& ot, cspan argv) +{ + OIIO_DASSERT(argv.size() == 1); + ot.popbottom(); +} + + + // --dup static void action_dup(Oiiotool& ot, cspan argv) @@ -3467,6 +3493,64 @@ action_swap(Oiiotool& ot, cspan argv) +// --stackreverse +static void +action_stackreverse(Oiiotool& ot, cspan argv) +{ + OIIO_DASSERT(argv.size() == 1); + string_view command = ot.express(argv[0]); + if (!ot.curimg) { + ot.error(command, "requires at least one loaded images"); + return; + } + if (ot.image_stack.empty()) + return; // only curimg -- reversing does nothing + ot.image_stack.push_back(ot.curimg); + std::reverse(ot.image_stack.begin(), ot.image_stack.end()); + ot.curimg = ot.image_stack.back(); + ot.image_stack.pop_back(); +} + + + +// --stackextract +static void +action_stackextract(Oiiotool& ot, cspan argv) +{ + OIIO_DASSERT(argv.size() == 2); + string_view command = ot.express(argv[0]); + int index = Strutil::stoi(ot.express(argv[1])); + if (index < 0 || index >= ot.image_stack_depth()) { + ot.errorfmt(command, "index {} out of range for stack depth {}", index, + ot.image_stack_depth()); + return; + } + if (ot.image_stack.empty()) + return; // only curimg -- extract does nothing + ot.image_stack.push_back(ot.curimg); + // Transform the index to the index of the stack data structure + index = int(ot.image_stack.size()) - 1 - index; + // Copy that item for safe keeping + ImageRecRef newtop = ot.image_stack[index]; + // Remove it from the stack + ot.image_stack.erase(ot.image_stack.begin() + size_t(index)); + // Now put it back on the top + ot.curimg = newtop; +} + + + +// --stackclear +static void +action_stackclear(Oiiotool& ot, cspan argv) +{ + OIIO_DASSERT(argv.size() == 1); + ot.image_stack.clear(); + ot.curimg = ImageRecRef(); +} + + + // --create static void action_create(Oiiotool& ot, cspan argv) @@ -6135,7 +6219,7 @@ Oiiotool::getargs(int argc, char* argv[]) ap.arg("-n", &ot.dryrun) .help("No saved output (dry run)"); ap.arg("--no-error-exit", ot.noerrexit) - .help("Do not exit upon error, try to process additional comands (danger!)"); + .help("Do not exit upon error, try to process additional commands (danger!)"); ap.arg("-a", &ot.allsubimages) .help("Do operations on all subimages/miplevels"); ap.arg("--debug", &ot.debug) @@ -6708,6 +6792,9 @@ Oiiotool::getargs(int argc, char* argv[]) .OTACTION(action_flatten); ap.separator("Image stack manipulation:"); + ap.arg("--label %s") + .help("Label the top image") + .OTACTION(action_label); ap.arg("--dup") .help("Duplicate the current image (push a copy onto the stack)") .OTACTION(action_dup); @@ -6717,9 +6804,18 @@ Oiiotool::getargs(int argc, char* argv[]) ap.arg("--pop") .help("Throw away the current image") .OTACTION(action_pop); - ap.arg("--label %s") - .help("Label the top image") - .OTACTION(action_label); + ap.arg("--popbottom") + .help("Throw away the image on the bottom of the stack") + .OTACTION(action_popbottom); + ap.arg("--stackreverse") + .help("Throw away the image on the bottom of the stack") + .OTACTION(action_stackreverse); + ap.arg("--stackextract %d:INDEX") + .help("Move an indexed stack item to the top of the stack") + .OTACTION(action_stackextract); + ap.arg("--stackclear") + .help("Remove all images from the stack, leaving it empty") + .OTACTION(action_stackclear); ap.separator("Color management:"); ap.arg("--colorconfiginfo") diff --git a/src/oiiotool/oiiotool.h b/src/oiiotool/oiiotool.h index a21a223d16..66e87255eb 100644 --- a/src/oiiotool/oiiotool.h +++ b/src/oiiotool/oiiotool.h @@ -259,6 +259,17 @@ class Oiiotool { return r; } + void popbottom() + { + if (image_stack.size()) { + // There are images on the full stack -- get rid of the bottom + image_stack.erase(image_stack.begin()); + } else { + // Nothing on the stack, so get rid of the current image + curimg = ImageRecRef(); + } + } + ImageRecRef top() { return curimg; } // How many images are on the stack? diff --git a/testsuite/oiiotool-control/ref/out.txt b/testsuite/oiiotool-control/ref/out.txt index 152a08b14f..ba8028348d 100644 --- a/testsuite/oiiotool-control/ref/out.txt +++ b/testsuite/oiiotool-control/ref/out.txt @@ -1,3 +1,38 @@ +Stack holds [0] = d.tif, [1] = c.tif, [2] = b.tif +TOP = d.tif, BOTTOM = a.tif +Stack bottom to top: + a.tif + b.tif + c.tif + d.tif +after --stackreverse: + d.tif + c.tif + b.tif + a.tif +after --stackreverse: + a.tif + b.tif + c.tif + d.tif +after --pop: + a.tif + b.tif + c.tif +after --popbottom: + b.tif + c.tif +after --stackclear: +Re-add a, b, c, d: + a.tif + b.tif + c.tif + d.tif +--stackextract 2: + a.tif + c.tif + d.tif + b.tif 42+2 = 44 42-2 = 40 42*2 = 84 @@ -114,6 +149,20 @@ Testing for i 5,10,2 (expect output 5,7,9): i = 7 i = 9 +Testing for i 10,5,-1 (expect output 10..6): + i = 10 + i = 9 + i = 8 + i = 7 + i = 6 + +Testing for i 10,5 (expect output 10..6): + i = 10 + i = 9 + i = 8 + i = 7 + i = 6 + Testing endfor without for: oiiotool ERROR: -endfor : endfor without matching for Full command line was: diff --git a/testsuite/oiiotool-control/run.py b/testsuite/oiiotool-control/run.py index 4ca8031b69..79eee9038d 100755 --- a/testsuite/oiiotool-control/run.py +++ b/testsuite/oiiotool-control/run.py @@ -14,13 +14,46 @@ redirect += " 2>&1" failureok = True +# Make some temp files +command += oiiotool ('-pattern:type=uint8 constant:color=1,0,0 2x2 3 -o a.tif ' + + '-pattern:type=uint8 constant:color=0,1,0 2x2 3 -o b.tif ' + + '-pattern:type=uint8 constant:color=0,0,1 2x2 3 -o c.tif ' + + '-pattern:type=uint8 constant:color=1,1,1 2x2 3 -o d.tif ') + +# Test TOP, BOTTOM, IMG[] +# TOP should be c.tif, BOTTOM should be a.tif +command += oiiotool ("a.tif b.tif c.tif d.tif " + + "--echo \"Stack holds [0] = {IMG[0].filename}, [1] = {IMG[1].filename}, [2] = {IMG[2].filename}\" " + + "--echo \"TOP = {TOP.filename}, BOTTOM = {BOTTOM.filename}\" " + ) +# Test --pop, --popbottom, --stackreverse, --stackclear, --stackextract +command += oiiotool ( + "a.tif b.tif c.tif d.tif " + + "--echo \"Stack bottom to top:\" " + + "--for i 0,{NIMAGES} --echo \" {IMG[NIMAGES-1-i].filename}\" --endfor " + + "--echo \"after --stackreverse:\" --stackreverse " + + "--for i 0,{NIMAGES} --echo \" {IMG[NIMAGES-1-i].filename}\" --endfor " + + "--echo \"after --stackreverse:\" --stackreverse " + + "--for i 0,{NIMAGES} --echo \" {IMG[NIMAGES-1-i].filename}\" --endfor " + + "--echo \"after --pop:\" --pop " + + "--for i 0,{NIMAGES} --echo \" {IMG[NIMAGES-1-i].filename}\" --endfor " + + "--echo \"after --popbottom:\" --popbottom " + + "--for i 0,{NIMAGES} --echo \" {IMG[NIMAGES-1-i].filename}\" --endfor " + + "--echo \"after --stackclear:\" --stackclear " + + "--for i 0,{NIMAGES} --echo \" {IMG[NIMAGES-1-i].filename}\" --endfor " + + "--echo \"Re-add a, b, c, d:\" " + + "a.tif b.tif c.tif d.tif " + + "--for i 0,{NIMAGES} --echo \" {IMG[NIMAGES-1-i].filename}\" --endfor " + + "--echo \"--stackextract 2:\" --stackextract 2 " + + "--for i 0,{NIMAGES} --echo \" {IMG[NIMAGES-1-i].filename}\" --endfor " + ) + # test expression substitution command += oiiotool ('-echo "42+2 = {42+2}" ' + '-echo "42-2 = {42-2}" ' + '-echo "42*2 = {42*2}" ' + - '-echo "42/2 = {42/2}"') - -command += oiiotool ('-echo "42<41 = {42<41}" ' + + '-echo "42/2 = {42/2}" ' + + '-echo "42<41 = {42<41}" ' + '-echo "42<42 = {42<42}" ' + '-echo "42<43 = {42<43}" ' + '-echo "42<=41 = {42<=41}" ' + @@ -40,9 +73,8 @@ '-echo "42!=43 = {42!=43}" ' + '-echo "42<=>41 = {42<=>41}" ' + '-echo "42<=>42 = {42<=>42}" ' + - '-echo "42<=>43 = {42<=>43}" ') - -command += oiiotool ('-echo "(1==2)&&(2==2) = {(1==2)&&(2==2)}" ' + + '-echo "42<=>43 = {42<=>43}" ' + + '-echo "(1==2)&&(2==2) = {(1==2)&&(2==2)}" ' + '-echo "(1==1)&&(2==2) = {(1==1)&&(2==2)}" ' + '-echo "(1==2)&&(1==2) = {(1==2)&&(1==2)}" ' + '-echo "(1==2)||(2==2) = {(1==2)||(2==2)}" ' + @@ -51,12 +83,11 @@ '-echo "not(1==1) = {not(1==1)}" ' + '-echo "not(1==2) = {not(1==2)}" ' + '-echo "!(1==1) = {!(1==1)}" ' + - '-echo "!(1==2) = {!(1==2)}"') - -command += oiiotool ('-echo "eq(foo,foo) = {eq(\'foo\',\'foo\')}" ' + + '-echo "!(1==2) = {!(1==2)}" ' + + '-echo "eq(foo,foo) = {eq(\'foo\',\'foo\')}" ' + '-echo "eq(foo,bar) = {eq(\'foo\',\'bar\')}" ' + '-echo "neq(foo,foo) = {neq(\'foo\',\'foo\')}" ' + - '-echo "neq(foo,bar) = {neq(\'foo\',\'bar\')}"') + '-echo "neq(foo,bar) = {neq(\'foo\',\'bar\')}" ') command += oiiotool ('-echo "16+5={16+5}" -echo "16-5={16-5}" -echo "16*5={16*5}"') command += oiiotool ('-echo "16/5={16/5}" -echo "16//5={16//5}" -echo "16%5={16%5}"') @@ -107,12 +138,17 @@ command += oiiotool ('-echo "Testing endwhile without while:" -endwhile -echo " "') # Test --for --endfor -command += oiiotool ('-echo "Testing for i 5 (expect output 0..4):" --for i 5 --echo " i = {i}" --endfor -echo " "') -command += oiiotool ('-echo "Testing for i 5,10 (expect output 5..9):" --for i 5,10 --echo " i = {i}" --endfor -echo " "') -command += oiiotool ('-echo "Testing for i 5,10,2 (expect output 5,7,9):" --for i 5,10,2 --echo " i = {i}" --endfor -echo " "') +command += oiiotool ( + '-echo "Testing for i 5 (expect output 0..4):" --for i 5 --echo " i = {i}" --endfor -echo " " ' + + '-echo "Testing for i 5,10 (expect output 5..9):" --for i 5,10 --echo " i = {i}" --endfor -echo " " ' + + '-echo "Testing for i 5,10,2 (expect output 5,7,9):" --for i 5,10,2 --echo " i = {i}" --endfor -echo " " ' + + '-echo "Testing for i 10,5,-1 (expect output 10..6):" --for i 10,5,-1 --echo " i = {i}" --endfor -echo " " ' + + '-echo "Testing for i 10,5 (expect output 10..6):" --for i 10,5 --echo " i = {i}" --endfor -echo " " ' + ) command += oiiotool ('-echo "Testing endfor without for:" -endfor -echo " "') command += oiiotool ('-echo "Testing for i 5,10,2,8 (bad range):" --for i 5,10,2,8 --echo " i = {i}" --endfor -echo " "') + # test sequences command += oiiotool ("../common/tahoe-tiny.tif -o copyA.1-10#.jpg") command += oiiotool ("--debug copyA.#.jpg -o copyB.#.jpg") From ea63dbbf65c998691947c247fa267f53d4d72581 Mon Sep 17 00:00:00 2001 From: Larry Gritz Date: Wed, 7 Aug 2024 11:52:46 -0700 Subject: [PATCH 028/147] int: Rename env OIIOTOOL_METADATA_HISTORY -> OPENIMAGEIO_METADATA_HISTORY (#4368) It's not just in oiiotool. This seems clearer and adheres to the env variable naming convention we chose. Reminder: This controls whether command line history gets written to output image metadata by default by oiiotool and maketx. We historically did it, but recently stopped because of security concerns. Signed-off-by: Larry Gritz Signed-off-by: Zach Lewis --- src/doc/imageioapi.rst | 6 +++--- src/doc/oiiotool.rst | 4 ++-- src/maketx/maketx.cpp | 10 +++++----- src/oiiotool/oiiotool.cpp | 10 +++++----- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/doc/imageioapi.rst b/src/doc/imageioapi.rst index 4f0623675d..0adcba25ca 100644 --- a/src/doc/imageioapi.rst +++ b/src/doc/imageioapi.rst @@ -370,10 +370,10 @@ inside the source code. take precedence. If neither is set, the default will be 0, which means to use as many threads as there are physical cores on the machine. -``OIIOTOOL_METADATA_HISTORY`` +``OPENIMAGEIO_METADATA_HISTORY`` - If set to a nonzero integer value, `oiiotool` will by default write the - command line into the ImageHistory and Software metadata fields of any + If set to a nonzero integer value, `oiiotool` and `maketx` will by default + write the command line into the ImageHistory and Software metadata fields of any images it outputs. The default if this is not set is to only write the name and version of the software and an indecipherable hash of the command line, but not the full human-readable command line. (This was added in diff --git a/src/doc/oiiotool.rst b/src/doc/oiiotool.rst index 47d39ae177..cfda570a1e 100644 --- a/src/doc/oiiotool.rst +++ b/src/doc/oiiotool.rst @@ -1991,7 +1991,7 @@ current top image. image to potentially reveal any proprietary information that might have been present in the command line arguments. - If the `OIIOTOOL_METADATA_HISTORY` environment variable is set to a + If the `OPENIMAGEIO_METADATA_HISTORY` environment variable is set to a nonzero integer value, the `--history` option will be enabled by default, but can be disabled on the command line with `--no-history`. @@ -2002,7 +2002,7 @@ current top image. Prior to OpenImageIO 2.5.11, the full information was always written, but could be overridden with `--nosoftwareattrib`. Beginning with 2.5.11, the default changed to only write the software name and version (unless the - `OIIOTOOL_METADATA_HISTORY` environment variable is set), and require the + `OPENIMAGEIO_METADATA_HISTORY` environment variable is set), and require the new `--history` option to cause the command line arguments to be written as metadata. diff --git a/src/maketx/maketx.cpp b/src/maketx/maketx.cpp index d85b49fc8c..3feeaf4d64 100644 --- a/src/maketx/maketx.cpp +++ b/src/maketx/maketx.cpp @@ -26,8 +26,8 @@ using namespace OIIO; -#ifndef OIIOTOOL_METADATA_HISTORY_DEFAULT -# define OIIOTOOL_METADATA_HISTORY_DEFAULT 0 +#ifndef OPENIMAGEIO_METADATA_HISTORY_DEFAULT +# define OPENIMAGEIO_METADATA_HISTORY_DEFAULT 0 #endif @@ -185,12 +185,12 @@ getargs(int argc, char* argv[], ImageSpec& configspec) bool cdf = false; float cdfsigma = 1.0f / 6; int cdfbits = 8; -#if OIIOTOOL_METADATA_HISTORY_DEFAULT +#if OPENIMAGEIO_METADATA_HISTORY_DEFAULT bool metadata_history = Strutil::from_string( - getenv("OIIOTOOL_METADATA_HISTORY", "1")); + getenv("OPENIMAGEIO_METADATA_HISTORY", "1")); #else bool metadata_history = Strutil::from_string( - getenv("OIIOTOOL_METADATA_HISTORY")); + getenv("OPENIMAGEIO_METADATA_HISTORY")); #endif std::string incolorspace; std::string outcolorspace; diff --git a/src/oiiotool/oiiotool.cpp b/src/oiiotool/oiiotool.cpp index e517d6bd20..b266ea641d 100644 --- a/src/oiiotool/oiiotool.cpp +++ b/src/oiiotool/oiiotool.cpp @@ -53,8 +53,8 @@ using pvt::print_info_options; # define OIIO_UNIT_TESTS 1 #endif -#ifndef OIIOTOOL_METADATA_HISTORY_DEFAULT -# define OIIOTOOL_METADATA_HISTORY_DEFAULT 0 +#ifndef OPENIMAGEIO_METADATA_HISTORY_DEFAULT +# define OPENIMAGEIO_METADATA_HISTORY_DEFAULT 0 #endif @@ -174,12 +174,12 @@ Oiiotool::clear_options() output_dither = false; output_force_tiles = false; metadata_nosoftwareattrib = false; -#if OIIOTOOL_METADATA_HISTORY_DEFAULT +#if OPENIMAGEIO_METADATA_HISTORY_DEFAULT metadata_history = Strutil::from_string( - getenv("OIIOTOOL_METADATA_HISTORY", "1")); + getenv("OPENIMAGEIO_METADATA_HISTORY", "1")); #else metadata_history = Strutil::from_string( - getenv("OIIOTOOL_METADATA_HISTORY")); + getenv("OPENIMAGEIO_METADATA_HISTORY")); #endif diff_warnthresh = 1.0e-6f; diff_warnpercent = 0; From 781ee80d61c2be7a9f61c4f017591f6e3a4d1804 Mon Sep 17 00:00:00 2001 From: Larry Gritz Date: Wed, 7 Aug 2024 11:53:32 -0700 Subject: [PATCH 029/147] feat(jpeg): output hint "jpeg:iptc" (#4346) JPEG output configuration hint "jpeg:iptc" (default: 1), if set to 0, will suppress IPTC block output to the file. In the process, we changed the return type of utility function encode_iptc_iim() to return true if anything was successfully encoded, false otherwise. Signed-off-by: Larry Gritz Signed-off-by: Zach Lewis --- src/doc/builtinplugins.rst | 4 ++++ src/include/OpenImageIO/tiffutils.h | 5 +++-- src/jpeg.imageio/jpegoutput.cpp | 4 ++-- src/libOpenImageIO/iptc.cpp | 3 ++- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/doc/builtinplugins.rst b/src/doc/builtinplugins.rst index 1c795a739c..7fa37e62a7 100644 --- a/src/doc/builtinplugins.rst +++ b/src/doc/builtinplugins.rst @@ -1077,6 +1077,10 @@ control aspects of the writing itself: - ptr - Pointer to a ``Filesystem::IOProxy`` that will handle the I/O, for example by writing to a memory buffer. + * - ``jpeg:iptc`` + - int (1) + - If zero, will suppress writing the IPTC metadata block to the + JPEG file. * - ``jpeg:progressive`` - int - If nonzero, will write a progressive JPEG file. diff --git a/src/include/OpenImageIO/tiffutils.h b/src/include/OpenImageIO/tiffutils.h index 9d69559a31..0803634271 100644 --- a/src/include/OpenImageIO/tiffutils.h +++ b/src/include/OpenImageIO/tiffutils.h @@ -189,8 +189,9 @@ OIIO_API bool decode_iptc_iim (const void *iptc, int length, ImageSpec &spec); /// for multiple format plugins to support embedding IPTC metadata /// without having to duplicate functionality within each plugin. Note /// that IIM is actually considered obsolete and is replaced by an XML -/// scheme called XMP. -OIIO_API void encode_iptc_iim (const ImageSpec &spec, std::vector &iptc); +/// scheme called XMP. Return true if it was successful and any items +/// were encoded. +OIIO_API bool encode_iptc_iim (const ImageSpec &spec, std::vector &iptc); /// Add metadata to spec based on XMP data in an XML block. Return true /// if all is ok, false if the xml was somehow malformed. This is a diff --git a/src/jpeg.imageio/jpegoutput.cpp b/src/jpeg.imageio/jpegoutput.cpp index da1c7506d1..b845a86bea 100644 --- a/src/jpeg.imageio/jpegoutput.cpp +++ b/src/jpeg.imageio/jpegoutput.cpp @@ -249,8 +249,8 @@ JpgOutput::open(const std::string& name, const ImageSpec& newspec, // Write IPTC IIM metadata tags, if we have anything std::vector iptc; - encode_iptc_iim(m_spec, iptc); - if (iptc.size()) { + if (m_spec.get_int_attribute("jpeg:iptc", 1) + && encode_iptc_iim(m_spec, iptc)) { static char photoshop[] = "Photoshop 3.0"; std::vector head(photoshop, photoshop + strlen(photoshop) + 1); static char _8BIM[] = "8BIM"; diff --git a/src/libOpenImageIO/iptc.cpp b/src/libOpenImageIO/iptc.cpp index b65c5c2949..0f79bbe0fe 100644 --- a/src/libOpenImageIO/iptc.cpp +++ b/src/libOpenImageIO/iptc.cpp @@ -179,7 +179,7 @@ encode_iptc_iim_one_tag(int tag, string_view data, std::vector& iptc) -void +bool encode_iptc_iim(const ImageSpec& spec, std::vector& iptc) { iptc.clear(); @@ -206,6 +206,7 @@ encode_iptc_iim(const ImageSpec& spec, std::vector& iptc) encode_iptc_iim_one_tag(iimtag[i].tag, p->get_string(0), iptc); } } + return iptc.size() != 0; } From 6eddaf5aba956943946badb5d631ee069d4dca1c Mon Sep 17 00:00:00 2001 From: Larry Gritz Date: Wed, 7 Aug 2024 11:53:52 -0700 Subject: [PATCH 030/147] fix(png): round dpi resolution to nearest 0.1 (#4347) Signed-off-by: Larry Gritz Signed-off-by: Zach Lewis --- src/png.imageio/png_pvt.h | 17 ++++++++++++----- testsuite/png/ref/out-libpng15.txt | 12 ++++++------ testsuite/png/ref/out.txt | 12 ++++++------ 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/png.imageio/png_pvt.h b/src/png.imageio/png_pvt.h index 55ce5d62cf..9119e19f65 100644 --- a/src/png.imageio/png_pvt.h +++ b/src/png.imageio/png_pvt.h @@ -303,15 +303,22 @@ read_info(png_structp& sp, png_infop& ip, int& bit_depth, int& color_type, int unit; png_uint_32 resx, resy; if (png_get_pHYs(sp, ip, &resx, &resy, &unit)) { - float scale = 1; if (unit == PNG_RESOLUTION_METER) { // Convert to inches, to match most other formats - scale = 2.54 / 100.0; + float scale = 2.54f / 100.0f; + float rx = resx * scale; + float ry = resy * scale; + // Round to nearest 0.1 + rx = std::round(10.0f * rx) / 10.0f; + ry = std::round(10.0f * ry) / 10.0f; spec.attribute("ResolutionUnit", "inch"); - } else + spec.attribute("XResolution", rx); + spec.attribute("YResolution", ry); + } else { spec.attribute("ResolutionUnit", "none"); - spec.attribute("XResolution", (float)resx * scale); - spec.attribute("YResolution", (float)resy * scale); + spec.attribute("XResolution", (float)resx); + spec.attribute("YResolution", (float)resy); + } } float aspect = (float)png_get_pixel_aspect_ratio(sp, ip); diff --git a/testsuite/png/ref/out-libpng15.txt b/testsuite/png/ref/out-libpng15.txt index e8855cd272..f19f586729 100644 --- a/testsuite/png/ref/out-libpng15.txt +++ b/testsuite/png/ref/out-libpng15.txt @@ -5,8 +5,8 @@ Reading ../oiio-images/oiio-logo-no-alpha.png Comment: "Created with GIMP" DateTime: "2009:03:26 17:19:47" ResolutionUnit: "inch" - XResolution: 72.009 - YResolution: 72.009 + XResolution: 72 + YResolution: 72 oiio:ColorSpace: "sRGB" Comparing "../oiio-images/oiio-logo-no-alpha.png" and "oiio-logo-no-alpha.png" PASS @@ -17,8 +17,8 @@ Reading ../oiio-images/oiio-logo-with-alpha.png Comment: "Created with GIMP" DateTime: "2009:03:26 18:44:26" ResolutionUnit: "inch" - XResolution: 72.009 - YResolution: 72.009 + XResolution: 72 + YResolution: 72 oiio:ColorSpace: "sRGB" Comparing "../oiio-images/oiio-logo-with-alpha.png" and "oiio-logo-with-alpha.png" PASS @@ -31,8 +31,8 @@ exif.png : 64 x 64, 3 channel, uint8 png channel list: R, G, B, A ResolutionUnit: "inch" Software: "OpenImageIO 2.4.1.1dev : oiiotool -no-autopremult SLEEP_MM.png -cut 1x1+227+1211 -o kaka.png" - XResolution: 299.999 - YResolution: 299.999 + XResolution: 300 + YResolution: 300 Exif:ImageHistory: "oiiotool -no-autopremult SLEEP_MM.png -cut 1x1+227+1211 -o kaka.png" oiio:ColorSpace: "Gamma2.2" oiio:Gamma: 2.2 diff --git a/testsuite/png/ref/out.txt b/testsuite/png/ref/out.txt index 3a8ed2f5ab..730a5cdd0a 100644 --- a/testsuite/png/ref/out.txt +++ b/testsuite/png/ref/out.txt @@ -5,8 +5,8 @@ Reading ../oiio-images/oiio-logo-no-alpha.png Comment: "Created with GIMP" DateTime: "2009:03:26 17:19:47" ResolutionUnit: "inch" - XResolution: 72.009 - YResolution: 72.009 + XResolution: 72 + YResolution: 72 oiio:ColorSpace: "sRGB" Comparing "../oiio-images/oiio-logo-no-alpha.png" and "oiio-logo-no-alpha.png" PASS @@ -17,8 +17,8 @@ Reading ../oiio-images/oiio-logo-with-alpha.png Comment: "Created with GIMP" DateTime: "2009:03:26 18:44:26" ResolutionUnit: "inch" - XResolution: 72.009 - YResolution: 72.009 + XResolution: 72 + YResolution: 72 oiio:ColorSpace: "sRGB" Comparing "../oiio-images/oiio-logo-with-alpha.png" and "oiio-logo-with-alpha.png" PASS @@ -35,8 +35,8 @@ exif.png : 64 x 64, 3 channel, uint8 png channel list: R, G, B, A ResolutionUnit: "inch" Software: "OpenImageIO 2.4.1.1dev : oiiotool -no-autopremult SLEEP_MM.png -cut 1x1+227+1211 -o kaka.png" - XResolution: 299.999 - YResolution: 299.999 + XResolution: 300 + YResolution: 300 Exif:ImageHistory: "oiiotool -no-autopremult SLEEP_MM.png -cut 1x1+227+1211 -o kaka.png" oiio:ColorSpace: "Gamma2.2" oiio:Gamma: 2.2 From 5ca303d898e0a491aa8421d4bc06d16139c25b87 Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Thu, 8 Aug 2024 06:58:28 +1200 Subject: [PATCH 031/147] raw: expose additional white balancing hints (#4360) The main purpose of this change is to make it possible to use OIIO for reading raw files in rawtoaces instead of calling LibRaw directly. There are the changes: - add the missing hints needed to implement all combinations of white-balancing methods and matrix methods provided by rawtoaces. - add the DNG-specific attributes The change adds this functionality: - new "raw:user_black" hint to override the default black point - new "raw:use_auto_wb" hint to force LibRaw to white balance by averaging over the whole image. - new "raw:grey_box" hint to make LibRaw to white balance by averaging over the given rectange. - new "raw:dng:XXX" attributes added to the output ImageBuf if the input image is a DNG file. The attributes consist of 2 sets of [calibration illuminant; calibration matrix, XYZ to camera RGB matrix]. Note, the current DNG standard supports up to 3 calibration illuminants, but both LibRaw and rawtoaces only use 2 currently. I have manually tested all permutations of white-balancing modes and matrix methods which are currently supported by raw to aces. The images match up to a rounding error. The current unit tests pass, but they only seem to use the default conversion settings. We may want to extend those. I'm not clear on how to do that, there are multiple reference images for different versions of LibRaw, not sure if I will have to re-generate all of them. I intend to make more changes to the raw plugin soon, may come back to updating tests during/after that. There are currently no tests using DNG files, so the new DNG-specific attributes are not covered. The code relying on those in rawtoaces works fine. I have also updated the documentation to add the new hints, however, I haven't been able to build the documentation. Signed-off-by: Anton Dukhovnikov Signed-off-by: Zach Lewis --- src/doc/builtinplugins.rst | 25 +++++++++++- src/raw.imageio/rawinput.cpp | 74 ++++++++++++++++++++++++++++-------- 2 files changed, 82 insertions(+), 17 deletions(-) diff --git a/src/doc/builtinplugins.rst b/src/doc/builtinplugins.rst index 7fa37e62a7..5743de5890 100644 --- a/src/doc/builtinplugins.rst +++ b/src/doc/builtinplugins.rst @@ -2066,7 +2066,23 @@ options are supported: - If nonzero, will use libraw's exposure correction. (Default: 0) * - ``raw:use_camera_wb`` - int - - If 1, use libraw's camera white balance adjustment. (Default: 1) + - If 1, use libraw's camera white balance adjustment. Takes precedence + over ``raw:use_auto_wb``, ``raw:greybox``, ``raw:user_mul``. + (Default: 1) + * - ``raw:use_auto_wb`` + - int + - If 1, white balance automatically by averaging over the entire image. + Only applies if ``raw:use_camera_wb`` is not equal to 0. Takes + precedence over ``raw:greybox``, ``raw:user_mul``. + (Default: 0) + * - ``raw:greybox`` + - int[4] + - White balance by averaging over the given box. The four values are the + X and Y coordinate of the top-left corner, the width and the height. + Only applies if the size is non-zero, and ``raw:use_camera_wb`` is not + equal to 0, ``raw:use_auto_wb`` is not equal to 0. Takes + precedence over ``raw:user_mul``. + (Default: 0, 0, 0, 0; meaning no correction.) * - ``raw:use_camera_matrix`` - int - Whether to use the embedded color profile, if it's present: 0 = @@ -2074,6 +2090,10 @@ options are supported: * - ``raw:adjust_maximum_thr`` - float - If nonzero, auto-adjusting maximum value. (Default:0.0) + * - ``raw:user_black`` + - int + - If not negative, sets the camera minimum value that will be normalized to + appear 0. (Default: -1) * - ``raw:user_sat`` - int - If nonzero, sets the camera maximum value that will be normalized to @@ -2090,7 +2110,8 @@ options are supported: * - ``raw:user_mul`` - float[4] - Sets user white balance coefficients. Only applies if ``raw:use_camera_wb`` - is not equal to 0. + is not equal to 0, ``raw:use_auto_wb`` is not equal to 0, and the + ``raw:greybox`` box is zero size. * - ``raw:ColorSpace`` - string - Which color primaries to use for the returned pixel values: ``raw``, diff --git a/src/raw.imageio/rawinput.cpp b/src/raw.imageio/rawinput.cpp index 2b4f715d7a..dd75df798f 100644 --- a/src/raw.imageio/rawinput.cpp +++ b/src/raw.imageio/rawinput.cpp @@ -459,6 +459,9 @@ RawInput::open_raw(bool unpack, const std::string& name, // Turn off maximum threshold value (unless set to non-zero) m_processor->imgdata.params.adjust_maximum_thr = config.get_float_attribute("raw:adjust_maximum_thr", 0.0f); + // Set camera minimum value if "raw:user_black" is not negative + m_processor->imgdata.params.user_black + = config.get_int_attribute("raw:user_black", -1); // Set camera maximum value if "raw:user_sat" is not 0 m_processor->imgdata.params.user_sat = config.get_int_attribute("raw:user_sat", 0); @@ -502,21 +505,34 @@ RawInput::open_raw(bool unpack, const std::string& name, params.user_mul[2] = norm[2]; params.user_mul[3] = norm[3]; } else { - // Set user white balance coefficients. - // Only has effect if "raw:use_camera_wb" is equal to 0, - // i.e. we are not using the camera white balance - auto p = config.find_attribute("raw:user_mul"); - if (p && p->type() == TypeDesc(TypeDesc::FLOAT, 4)) { - m_processor->imgdata.params.user_mul[0] = p->get(0); - m_processor->imgdata.params.user_mul[1] = p->get(1); - m_processor->imgdata.params.user_mul[2] = p->get(2); - m_processor->imgdata.params.user_mul[3] = p->get(3); - } - if (p && p->type() == TypeDesc(TypeDesc::DOUBLE, 4)) { - m_processor->imgdata.params.user_mul[0] = p->get(0); - m_processor->imgdata.params.user_mul[1] = p->get(1); - m_processor->imgdata.params.user_mul[2] = p->get(2); - m_processor->imgdata.params.user_mul[3] = p->get(3); + if (config.get_int_attribute("raw:use_auto_wb", 0) == 1) { + m_processor->imgdata.params.use_auto_wb = 1; + } else { + auto p = config.find_attribute("raw:greybox"); + if (p && p->type() == TypeDesc(TypeDesc::INT, 4)) { + // p->get() didn't work for me here + m_processor->imgdata.params.greybox[0] = p->get_int_indexed(0); + m_processor->imgdata.params.greybox[1] = p->get_int_indexed(1); + m_processor->imgdata.params.greybox[2] = p->get_int_indexed(2); + m_processor->imgdata.params.greybox[3] = p->get_int_indexed(3); + } else { + // Set user white balance coefficients. + // Only has effect if "raw:use_camera_wb" is equal to 0, + // i.e. we are not using the camera white balance + auto p = config.find_attribute("raw:user_mul"); + if (p && p->type() == TypeDesc(TypeDesc::FLOAT, 4)) { + m_processor->imgdata.params.user_mul[0] = p->get(0); + m_processor->imgdata.params.user_mul[1] = p->get(1); + m_processor->imgdata.params.user_mul[2] = p->get(2); + m_processor->imgdata.params.user_mul[3] = p->get(3); + } + if (p && p->type() == TypeDesc(TypeDesc::DOUBLE, 4)) { + m_processor->imgdata.params.user_mul[0] = p->get(0); + m_processor->imgdata.params.user_mul[1] = p->get(1); + m_processor->imgdata.params.user_mul[2] = p->get(2); + m_processor->imgdata.params.user_mul[3] = p->get(3); + } + } } } @@ -1319,6 +1335,34 @@ RawInput::get_colorinfo() cspan(&(m_processor->imgdata.color.cam_xyz[0][0]), &(m_processor->imgdata.color.cam_xyz[3][3])), false, 0.f); + + if (m_processor->imgdata.idata.dng_version) { + add("raw", "dng:version", m_processor->imgdata.idata.dng_version); + + auto const& c = m_processor->imgdata.rawdata.color; + +#if LIBRAW_VERSION >= LIBRAW_MAKE_VERSION(0, 20, 0) + add("raw", "dng:baseline_exposure", c.dng_levels.baseline_exposure); +#else + add("raw", "dng:baseline_exposure", c.baseline_exposure); +#endif + + for (int i = 0; i < 2; i++) { + std::string index = std::to_string(i + 1); + add("raw", "dng:calibration_illuminant" + index, + c.dng_color[i].illuminant); + + add("raw", "dng:color_matrix" + index, + cspan(&(c.dng_color[i].colormatrix[0][0]), + &(c.dng_color[i].colormatrix[3][3])), + false, 0.f); + + add("raw", "dng:camera_calibration" + index, + cspan(&(c.dng_color[i].calibration[0][0]), + &(c.dng_color[i].calibration[3][4])), + false, 0.f); + } + } } From 35990813cea683f5221c94d3cc3f16e840213ebe Mon Sep 17 00:00:00 2001 From: Larry Gritz Date: Wed, 7 Aug 2024 11:58:59 -0700 Subject: [PATCH 032/147] api: move OIIO::pvt::error and log_time into the exposed OIIO namespace (#4362) This is needed for the related OpenCV-related PR Signed-off-by: Larry Gritz Signed-off-by: Zach Lewis --- src/iff.imageio/noproxy-iff_pvt.h | 4 ++-- src/include/OpenImageIO/imageio.h | 16 ++++++++++++++++ src/include/OpenImageIO/strutil.h | 4 +++- src/include/imageio_pvt.h | 18 ------------------ src/libOpenImageIO/imagebufalgo_opencv.cpp | 14 ++++++-------- src/libOpenImageIO/imageinput.cpp | 2 +- src/libOpenImageIO/imageio.cpp | 2 +- src/libOpenImageIO/imageioplugin.cpp | 20 ++++++++++---------- src/libOpenImageIO/maketexture.cpp | 4 ++-- 9 files changed, 41 insertions(+), 43 deletions(-) diff --git a/src/iff.imageio/noproxy-iff_pvt.h b/src/iff.imageio/noproxy-iff_pvt.h index 7e6dc0a4fb..de78e39d47 100644 --- a/src/iff.imageio/noproxy-iff_pvt.h +++ b/src/iff.imageio/noproxy-iff_pvt.h @@ -145,7 +145,7 @@ class IffInput final : public ImageInput { try { close(); } catch (const std::exception& e) { - OIIO::pvt::errorfmt("{}", e.what()); + OIIO::errorfmt("{}", e.what()); } } const char* format_name(void) const override { return "iff"; } @@ -228,7 +228,7 @@ class IffOutput final : public ImageOutput { try { close(); } catch (const std::exception& e) { - OIIO::pvt::errorfmt("{}", e.what()); + OIIO::errorfmt("{}", e.what()); } } const char* format_name(void) const override { return "iff"; } diff --git a/src/include/OpenImageIO/imageio.h b/src/include/OpenImageIO/imageio.h index 071d9805c0..b675c4605e 100644 --- a/src/include/OpenImageIO/imageio.h +++ b/src/include/OpenImageIO/imageio.h @@ -41,6 +41,7 @@ OIIO_NAMESPACE_BEGIN class DeepData; class ImageBuf; +class Timer; /// Type we use for stride lengths between pixels, scanlines, or image @@ -3363,7 +3364,22 @@ void debugfmt (const char* fmt, Args&&... args) Strutil::debug(fmt, std::forward(args)...); } +namespace pvt { +// For internal use - use errorfmt() below for a nicer interface. +OIIO_API void append_error(string_view message); +} + +/// error logging (mostly for OIIO internals) with `std::format` conventions. +template +inline void errorfmt(const char* fmt, Args&&... args) +{ + pvt::append_error(string_view(Strutil::fmt::format(fmt, args...))); +} +/// Internal function to log time recorded by an OIIO::timer(). It will only +/// trigger a read of the time if the "log_times" attribute is set or the +/// OPENIMAGEIO_LOG_TIMES env variable is set. +OIIO_API void log_time(string_view key, const Timer& timer, int count = 1); // to force correct linkage on some systems OIIO_API void _ImageIO_force_link (); diff --git a/src/include/OpenImageIO/strutil.h b/src/include/OpenImageIO/strutil.h index d22a546481..e0c5ec302f 100644 --- a/src/include/OpenImageIO/strutil.h +++ b/src/include/OpenImageIO/strutil.h @@ -152,7 +152,9 @@ using old::format; #endif -// format_to comes from fmt library +// More things we wrap from fmt library +using ::fmt::format_args; +using ::fmt::make_format_args; using ::fmt::format_to; using ::fmt::format_to_n; diff --git a/src/include/imageio_pvt.h b/src/include/imageio_pvt.h index b6b606994c..c9befa7421 100644 --- a/src/include/imageio_pvt.h +++ b/src/include/imageio_pvt.h @@ -60,18 +60,6 @@ font_list(); -// For internal use - use error() below for a nicer interface. -void -append_error(string_view message); - -/// Use errorfmt() privately only. Formatting notation is like std::format. -template -inline void -errorfmt(const char* fmt, const Args&... args) -{ - append_error(Strutil::fmt::format(fmt, args...)); -} - // Make sure all plugins are inventoried. For internal use only. void catalog_all_plugins(std::string searchpath); @@ -123,12 +111,6 @@ parallel_convert_from_float(const float* src, void* dst, size_t nvals, OIIO_API bool check_texture_metadata_sanity(ImageSpec& spec); -/// Internal function to log time recorded by an OIIO::timer(). It will only -/// trigger a read of the time if the "log_times" attribute is set or the -/// OPENIMAGEIO_LOG_TIMES env variable is set. -OIIO_API void -log_time(string_view key, const Timer& timer, int count = 1); - /// Get the timing report from log_time entries. OIIO_API std::string timing_report(); diff --git a/src/libOpenImageIO/imagebufalgo_opencv.cpp b/src/libOpenImageIO/imagebufalgo_opencv.cpp index c95a8fd90f..1d5a37fda8 100644 --- a/src/libOpenImageIO/imagebufalgo_opencv.cpp +++ b/src/libOpenImageIO/imagebufalgo_opencv.cpp @@ -169,16 +169,14 @@ ImageBufAlgo::to_OpenCV(cv::Mat& dst, const ImageBuf& src, ROI roi, } else if (spec.format == TypeDesc(TypeDesc::DOUBLE)) { dstFormat = CV_MAKETYPE(CV_64F, chans); } else { - OIIO::pvt::errorfmt( - "to_OpenCV() doesn't know how to make a cv::Mat of {}", - spec.format); + OIIO::errorfmt("to_OpenCV() doesn't know how to make a cv::Mat of {}", + spec.format); return false; } dst.create(roi.height(), roi.width(), dstFormat); if (dst.empty()) { - OIIO::pvt::errorfmt( - "to_OpenCV() was unable to create cv::Mat of {}x{} {}", roi.width(), - roi.height(), dstSpecFormat); + OIIO::errorfmt("to_OpenCV() was unable to create cv::Mat of {}x{} {}", + roi.width(), roi.height(), dstSpecFormat); return false; } @@ -189,7 +187,7 @@ ImageBufAlgo::to_OpenCV(cv::Mat& dst, const ImageBuf& src, ROI roi, dst.ptr(), pixelsize, linestep, AutoStride); bool converted = ImageBufAlgo::copy(cvib, src); if (!converted) { - OIIO::pvt::errorfmt( + OIIO::errorfmt( "to_OpenCV() was unable to convert source {} to cv::Mat of {}", spec.format, dstSpecFormat); return false; @@ -204,7 +202,7 @@ ImageBufAlgo::to_OpenCV(cv::Mat& dst, const ImageBuf& src, ROI roi, return true; #else - OIIO::pvt::errorfmt( + OIIO::errorfmt( "to_OpenCV() not supported -- no OpenCV support at compile time"); return false; #endif diff --git a/src/libOpenImageIO/imageinput.cpp b/src/libOpenImageIO/imageinput.cpp index 0a03219c6a..a6814575bf 100644 --- a/src/libOpenImageIO/imageinput.cpp +++ b/src/libOpenImageIO/imageinput.cpp @@ -164,7 +164,7 @@ ImageInput::open(const std::string& filename, const ImageSpec* config, // error, delete the ImageInput we allocated, and return NULL. std::string err = in->geterror(); if (err.size()) - OIIO::pvt::errorfmt("{}", err); + OIIO::errorfmt("{}", err); in.reset(); } diff --git a/src/libOpenImageIO/imageio.cpp b/src/libOpenImageIO/imageio.cpp index a0a4e4e874..a78ff59947 100644 --- a/src/libOpenImageIO/imageio.cpp +++ b/src/libOpenImageIO/imageio.cpp @@ -364,7 +364,7 @@ debug(string_view message) void -pvt::log_time(string_view key, const Timer& timer, int count) +log_time(string_view key, const Timer& timer, int count) { timing_log(key, timer, count); } diff --git a/src/libOpenImageIO/imageioplugin.cpp b/src/libOpenImageIO/imageioplugin.cpp index c192035fbe..328a71664b 100644 --- a/src/libOpenImageIO/imageioplugin.cpp +++ b/src/libOpenImageIO/imageioplugin.cpp @@ -526,7 +526,7 @@ ImageOutput::create(string_view filename, Filesystem::IOProxy* ioproxy, { std::unique_ptr out; if (filename.empty()) { // Can't even guess if no filename given - OIIO::pvt::errorfmt("ImageOutput::create() called with no filename"); + OIIO::errorfmt("ImageOutput::create() called with no filename"); return out; } @@ -563,9 +563,9 @@ ImageOutput::create(string_view filename, Filesystem::IOProxy* ioproxy, const char* msg = "ImageOutput::create() could not find any ImageOutput plugins! Perhaps you need to set OIIO_LIBRARY_PATH.\n"; Strutil::print(stderr, "{}", msg); - OIIO::pvt::errorfmt("{}", msg); + OIIO::errorfmt("{}", msg); } else - OIIO::pvt::errorfmt( + OIIO::errorfmt( "OpenImageIO could not find a format writer for \"{}\". " "Is it a file format that OpenImageIO doesn't know about?\n", filename); @@ -582,7 +582,7 @@ ImageOutput::create(string_view filename, Filesystem::IOProxy* ioproxy, } if (out && ioproxy) { if (!out->supports("ioproxy")) { - OIIO::pvt::errorfmt( + OIIO::errorfmt( "ImageOutput::create called with IOProxy, but format {} does not support IOProxy", out->format_name()); out.reset(); @@ -609,7 +609,7 @@ ImageInput::create(string_view filename, bool do_open, const ImageSpec* config, // Only check REST arguments if the file does not exist if (!Filesystem::exists(filename)) { if (!Strutil::get_rest_arguments(filename, filename_stripped, args)) { - OIIO::pvt::errorfmt( + OIIO::errorfmt( "ImageInput::create() called with malformed filename"); return in; } @@ -619,7 +619,7 @@ ImageInput::create(string_view filename, bool do_open, const ImageSpec* config, filename_stripped = filename; if (filename_stripped.empty()) { // Can't even guess if no filename given - OIIO::pvt::errorfmt("ImageInput::create() called with no filename"); + OIIO::errorfmt("ImageInput::create() called with no filename"); return in; } @@ -770,18 +770,18 @@ ImageInput::create(string_view filename, bool do_open, const ImageSpec* config, = "ImageInput::create() could not find any ImageInput plugins!\n" " Perhaps you need to set OIIO_LIBRARY_PATH.\n"; Strutil::print(stderr, "{}", msg); - OIIO::pvt::errorfmt("{}", msg); + OIIO::errorfmt("{}", msg); } else if (!specific_error.empty()) { // Pass along any specific error message we got from our // best guess of the format. - OIIO::pvt::errorfmt("{}", specific_error); + OIIO::errorfmt("{}", specific_error); } else if (Filesystem::exists(filename)) - pvt::errorfmt( + OIIO::errorfmt( "OpenImageIO could not find a format reader for \"{}\". " "Is it a file format that OpenImageIO doesn't know about?\n", filename); else - OIIO::pvt::errorfmt( + OIIO::errorfmt( "Image \"{}\" does not exist. Also, it is not the name of an image format that OpenImageIO recognizes.\n", filename); OIIO_DASSERT(!in); diff --git a/src/libOpenImageIO/maketexture.cpp b/src/libOpenImageIO/maketexture.cpp index 6ea6ba3b4e..5bf2da43c6 100644 --- a/src/libOpenImageIO/maketexture.cpp +++ b/src/libOpenImageIO/maketexture.cpp @@ -615,7 +615,7 @@ write_mipmap(ImageBufAlgo::MakeTextureMode mode, std::shared_ptr& img, std::ostream& outstream, double& stat_writetime, double& stat_miptime, size_t& peak_mem) { - using OIIO::pvt::errorfmt; + using OIIO::errorfmt; using OIIO::Strutil::sync::print; // Be sure to use synchronized one bool envlatlmode = (mode == ImageBufAlgo::MakeTxEnvLatl); bool orig_was_overscan = (img->spec().x || img->spec().y || img->spec().z @@ -981,7 +981,7 @@ make_texture_impl(ImageBufAlgo::MakeTextureMode mode, const ImageBuf* input, std::string filename, std::string outputfilename, const ImageSpec& _configspec, std::ostream* outstream_ptr) { - using OIIO::pvt::errorfmt; + using OIIO::errorfmt; using OIIO::Strutil::sync::print; // Be sure to use synchronized one OIIO_ASSERT(mode >= 0 && mode < ImageBufAlgo::_MakeTxLast); double stat_readtime = 0; From 2db7b904e465ed4043736eaabff87cbb9def8d30 Mon Sep 17 00:00:00 2001 From: Larry Gritz Date: Sat, 10 Aug 2024 09:07:25 -0700 Subject: [PATCH 033/147] admin: Relicense code under Apache 2.0 (#3905) Some more updates to the relicensing. At this point, less than 0.15% of the codebase remains under the original BSD-3-clause license. Signed-off-by: Zach Lewis --- LICENSE-BSD.md | 27 --------------------------- README.md | 2 +- RELICENSING.md | 14 +++++++++++--- THIRD-PARTY.md | 8 ++++---- src/iconvert/iconvert.cpp | 2 +- src/include/OpenImageIO/platform.h | 2 +- src/libtexture/imagecache.cpp | 2 +- src/oiiotool/oiiotool.h | 2 +- src/python/py_imagebufalgo.cpp | 2 +- 9 files changed, 21 insertions(+), 40 deletions(-) delete mode 100644 LICENSE-BSD.md diff --git a/LICENSE-BSD.md b/LICENSE-BSD.md deleted file mode 100644 index de10a34492..0000000000 --- a/LICENSE-BSD.md +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2008-present by Contributors to the OpenImageIO 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/README.md b/README.md index fdcaa2d03b..220a228cb8 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ For original code, we use the [Apache-2.0 license](LICENSE.md), and for documentation, the [Creative Commons Attribution 4.0 Unported License](http://creativecommons.org/licenses/by/4.0/). In 2023 we asked historical users to [relicense](RELICENSING.md) from the original BSD-3-clause -license to Apache-2.0, and over 99.75% of lines of code have been relicensed +license to Apache-2.0, and over 99.86% of lines of code have been relicensed to Apache-2.0. A small amount of code incorporated into this repository from other projects are covered by compatible [third-party open source licenses](THIRD-PARTY.md). diff --git a/RELICENSING.md b/RELICENSING.md index a8658d729a..c6390ca009 100644 --- a/RELICENSING.md +++ b/RELICENSING.md @@ -2,7 +2,11 @@ New code entering the OpenImageIO repository from July 1 2023 onward is subject to the [Apache 2.0 license](LICENSE.md). Code dating from earlier than July 1 2023 was contributed under the [BSD -3-clause license](LICENSE-BSD-3-Clause.md), unless relicensed below. +3-clause license](https://opensource.org/license/bsd-3-clause), unless +relicensed below. + +Stragglers who haven't relicensed yet, it's never too late, just sign onto the +PR: https://github.com/AcademySoftwareFoundation/OpenImageIO/pull/3905 The following copyright holders agree that all of their contributions originally submitted to this project under the 3-Clause BSD License are hereby @@ -137,9 +141,13 @@ the Developer Certificate of Origin, version 1.1: - Damien Courtois (ix-dcourtois) - Carl Rand (crand) - Gregor Mückl (gmueckl) +- Jep Hill (jephill) +- John Haddon (johnhaddon) +... -**Prior authors, please submit a PR against this file that adds your name -above. If, at the time of your prior contributions, you were employed by a +**Prior authors, please follow the directions for adding your name to +[this PR](https://github.com/AcademySoftwareFoundation/OpenImageIO/pull/3905). +If, at the time of your prior contributions, you were employed by a company who would have owned your IP output, then please have someone from that company who is authorized to do so submit a PR to add their company’s name to the list under the statement in this file.** diff --git a/THIRD-PARTY.md b/THIRD-PARTY.md index 17f4a882bd..96e2a1523a 100644 --- a/THIRD-PARTY.md +++ b/THIRD-PARTY.md @@ -9,15 +9,15 @@ In no particular order: ------------------------------------------------------------------------- -BSD 3-Clause License +BSD 3-Clause License (https://opensource.org/license/bsd-3-clause) SPDX-License-Identifier: BSD-3-Clause * OpenImageIO prior to July 1, 2023 Code that was contributed to OpenImageIO prior to July 1 2023, and has not - yet been [relicensed](RELICENSING.md), was contributed under the [BSD - 3-clause license](LICENSE-BSD.md). Currently, this is less than 2% of the - codebase (by lines of code). + yet been [relicensed](RELICENSING.md), was contributed under the BSD + 3-clause license. Currently, less than 0.15% of the codebase (by lines of + code) remains under this license. * Gelato, Copyright (c) 2004 by NVIDIA Corp. diff --git a/src/iconvert/iconvert.cpp b/src/iconvert/iconvert.cpp index d98a2dfd49..66b513c381 100644 --- a/src/iconvert/iconvert.cpp +++ b/src/iconvert/iconvert.cpp @@ -1,5 +1,5 @@ // Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: BSD-3-Clause and Apache-2.0 +// SPDX-License-Identifier: Apache-2.0 // https://github.com/AcademySoftwareFoundation/OpenImageIO diff --git a/src/include/OpenImageIO/platform.h b/src/include/OpenImageIO/platform.h index 1371096a64..f5f1101786 100644 --- a/src/include/OpenImageIO/platform.h +++ b/src/include/OpenImageIO/platform.h @@ -1,5 +1,5 @@ // Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: BSD-3-Clause and Apache-2.0 +// SPDX-License-Identifier: Apache-2.0 // https://github.com/AcademySoftwareFoundation/OpenImageIO diff --git a/src/libtexture/imagecache.cpp b/src/libtexture/imagecache.cpp index e21ffbed24..de1afac15d 100644 --- a/src/libtexture/imagecache.cpp +++ b/src/libtexture/imagecache.cpp @@ -1,5 +1,5 @@ // Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: BSD-3-Clause and Apache-2.0 +// SPDX-License-Identifier: Apache-2.0 // https://github.com/AcademySoftwareFoundation/OpenImageIO diff --git a/src/oiiotool/oiiotool.h b/src/oiiotool/oiiotool.h index 66e87255eb..48706faedb 100644 --- a/src/oiiotool/oiiotool.h +++ b/src/oiiotool/oiiotool.h @@ -1,5 +1,5 @@ // Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: BSD-3-Clause and Apache-2.0 +// SPDX-License-Identifier: Apache-2.0 // https://github.com/AcademySoftwareFoundation/OpenImageIO diff --git a/src/python/py_imagebufalgo.cpp b/src/python/py_imagebufalgo.cpp index b5f9eb015b..22db42d338 100644 --- a/src/python/py_imagebufalgo.cpp +++ b/src/python/py_imagebufalgo.cpp @@ -1,5 +1,5 @@ // Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: BSD-3-Clause and Apache-2.0 +// SPDX-License-Identifier: Apache-2.0 // https://github.com/AcademySoftwareFoundation/OpenImageIO #include "py_oiio.h" From 2c10095e33236c8a9ea038eab36a84381787a514 Mon Sep 17 00:00:00 2001 From: Basile Fraboni Date: Sun, 11 Aug 2024 16:27:27 -0700 Subject: [PATCH 034/147] api: add pvt::heapsize() and pvt::footprint() methods and image cache memory tracking (#4322) First PR of two, following @lgritz and I discussions on memory tracking in the OIIO::ImageCache. - Add two template methods and their specializations for types various to help memory tracking: ```c++ // return the total heap allocated memory held by the object and its members template inline size_t heapsize(const T& t); // return the total memory footprint including the size of the structure itself template inline size_t footprint(const T& t); ``` - Specialized for: ParamValue, ParamValueList, ImageSpec, ImageInput, ImageOutput, std::vector, std::shared_ptr, std::unique_ptr, oiio::intrusive_ptr, ImageCacheImpl related objects. - New files: - `include/memory.h` : adds base and few types specialization of heapsize and footprint. - `libtexture/imagecache_memory_pvt.h` : adds specilializations for ImageCacheImpl and related objects. - `libtexture/imagecache_memory_print.h` : adds a helper function that print a breakdown of the ImageCacheImpl total memory usage as well, as well as per image format. Note: this is slow, but gives accurate memory estimation. Related PR from Larry : https://github.com/AcademySoftwareFoundation/OpenImageIO/pull/4317 Signed-off-by: Basile Fraboni Signed-off-by: Zach Lewis --- src/include/OpenImageIO/imagecache.h | 2 + src/include/OpenImageIO/imageio.h | 20 ++ src/include/OpenImageIO/memory.h | 117 ++++++++++++ src/include/OpenImageIO/paramlist.h | 9 +- src/include/OpenImageIO/refcnt.h | 22 +++ src/libOpenImageIO/formatspec.cpp | 13 ++ src/libOpenImageIO/imageinput.cpp | 13 ++ src/libOpenImageIO/imageoutput.cpp | 11 ++ src/libOpenImageIO/imagespec_test.cpp | 4 + src/libtexture/imagecache.cpp | 5 + src/libtexture/imagecache_memory_print.h | 234 +++++++++++++++++++++++ src/libtexture/imagecache_memory_pvt.h | 109 +++++++++++ src/libtexture/imagecache_pvt.h | 17 +- src/libutil/paramlist.cpp | 11 ++ src/libutil/paramlist_test.cpp | 46 ++--- 15 files changed, 609 insertions(+), 24 deletions(-) create mode 100644 src/include/OpenImageIO/memory.h create mode 100644 src/libtexture/imagecache_memory_print.h create mode 100644 src/libtexture/imagecache_memory_pvt.h diff --git a/src/include/OpenImageIO/imagecache.h b/src/include/OpenImageIO/imagecache.h index fedc3f3041..2cb7bb89ad 100644 --- a/src/include/OpenImageIO/imagecache.h +++ b/src/include/OpenImageIO/imagecache.h @@ -257,6 +257,8 @@ class OIIO_API ImageCache { /// all files referenced by calls to the ImageCache. (The /// array is of `ustring` or `char*`.) /// + /// - `int64 stat:cache_footprint` : + /// Total bytes used by image cache. /// - `int64 stat:cache_memory_used` : /// Total bytes used by tile cache. /// diff --git a/src/include/OpenImageIO/imageio.h b/src/include/OpenImageIO/imageio.h index b675c4605e..af233d0d0f 100644 --- a/src/include/OpenImageIO/imageio.h +++ b/src/include/OpenImageIO/imageio.h @@ -36,6 +36,7 @@ #include #include #include +#include OIIO_NAMESPACE_BEGIN @@ -1884,6 +1885,9 @@ class OIIO_API ImageInput { std::unique_ptr m_impl; void append_error(string_view message) const; // add to error message + + /// declare a friend heapsize definition + template friend size_t pvt::heapsize(const T&); }; @@ -2788,10 +2792,26 @@ class OIIO_API ImageOutput { std::unique_ptr m_impl; void append_error(string_view message) const; // add to m_errmessage + + /// declare a friend heapsize definition + template friend size_t pvt::heapsize(const T&); }; +/// Memory tracking. Specializes the base memory tracking functions from memory.h. + +// heapsize specialization for `ImageSpec` +template <> OIIO_API size_t pvt::heapsize(const ImageSpec&); + +// heapsize specialization for `ImageInput` +template <> OIIO_API size_t pvt::heapsize(const ImageInput&); + +// heapsize specialization for `ImageOutput` +template <> OIIO_API size_t pvt::heapsize(const ImageOutput&); + + + // Utility functions /// `OIIO::shutdown` prepares OpenImageIO for shutdown. Before exiting an diff --git a/src/include/OpenImageIO/memory.h b/src/include/OpenImageIO/memory.h new file mode 100644 index 0000000000..cae5f34b5e --- /dev/null +++ b/src/include/OpenImageIO/memory.h @@ -0,0 +1,117 @@ +// Copyright Contributors to the OpenImageIO project. +// SPDX-License-Identifier: Apache-2.0 +// https://github.com/AcademySoftwareFoundation/OpenImageIO + + +///////////////////////////////////////////////////////////////////////// +/// @file memory.h +/// +/// @brief Utilities for memory tracking. +///////////////////////////////////////////////////////////////////////// + + +#pragma once + +#define OPENIMAGEIO_MEMORY_H + +#include +#include +#include + +OIIO_NAMESPACE_BEGIN + +namespace pvt { + +/// Return the total heap memory allocated by `object`. +/// The template specialization can be used to give improved results for non trivial types +/// that perform heap allocation, and to include members allocations recursively. +template +inline size_t +heapsize(const T& t) +{ + return 0; +} + +/// Return the total memory footprint of `object`. If possible, including any heap +/// allocations done by any constituent parts. The default implementation just reduces +/// to sizeof(object), given that heapsize(object) would return 0. +/// The template specialization can be used to give improved results for non trivial types +/// that perform heap allocation. +template +inline size_t +footprint(const T& t) +{ + return sizeof(T) + heapsize(t); +} + +template +inline size_t +footprint(const T* t) +{ + return sizeof(T) + (t ? footprint(*t) : 0); +} + +/// Specializations for common STL types + + +// heapsize specialization for std::string +template<> +inline size_t +heapsize(const std::string& s) +{ + // accounts for small string optimization that does not + // use any heap allocations + const char* const sbegin = (const char*)&s; + const char* const send = sbegin + sizeof(std::string); + const char* const sdata = s.data(); + const bool is_small = sdata >= sbegin && sdata < send; + return is_small ? 0 : s.capacity(); +} + +// heapsize specialization for std::vector +template +inline size_t +heapsize(const std::vector& vec) +{ + size_t size = 0; + for (const T& elem : vec) + size += footprint(elem); + return size; +} + +// heapsize specialization for std::shared_ptr +template +inline size_t +heapsize(const std::shared_ptr& ref) +{ + return ref ? footprint(*ref.get()) : 0; +} + +// footprint specialization for std::shared_ptr +template +inline size_t +footprint(const std::shared_ptr& ref) +{ + return sizeof(std::shared_ptr) + heapsize(ref); +} + +// heapsize specialization for std::unique_ptr +template +inline size_t +heapsize(const std::unique_ptr& ref) +{ + return ref ? footprint(*ref.get()) : 0; +} + +// footprint specialization for std::unique_ptr +template +inline size_t +footprint(const std::unique_ptr& ref) +{ + return sizeof(std::unique_ptr) + heapsize(ref); +} + +} // namespace pvt + + +OIIO_NAMESPACE_END \ No newline at end of file diff --git a/src/include/OpenImageIO/paramlist.h b/src/include/OpenImageIO/paramlist.h index f4840fc8b2..6d278a38df 100644 --- a/src/include/OpenImageIO/paramlist.h +++ b/src/include/OpenImageIO/paramlist.h @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -276,9 +277,15 @@ class OIIO_UTIL_API ParamValue { Copy _copy = Copy(true), FromUstring _from_ustring = FromUstring(false)) noexcept; void clear_value() noexcept; -}; + /// declare a friend heapsize definition + template friend size_t pvt::heapsize(const T&); +}; +/// heapsize specialization for `ParamValue` +template<> +OIIO_API size_t +pvt::heapsize(const ParamValue&); /// Factory for a ParamValue that holds a single value of any type supported /// by a corresponding ParamValue constructor (such as int, float, string). diff --git a/src/include/OpenImageIO/refcnt.h b/src/include/OpenImageIO/refcnt.h index 06dc97213c..68cacd319c 100644 --- a/src/include/OpenImageIO/refcnt.h +++ b/src/include/OpenImageIO/refcnt.h @@ -16,6 +16,7 @@ #include #include +#include OIIO_NAMESPACE_BEGIN @@ -232,4 +233,25 @@ intrusive_ptr_release(T* x) #define OIIO_REFCNT_HAS_RELEASE 1 /* intrusive_ptr::release() */ +/// Memory tracking. Specializes the base memory tracking functions from memory.h. + +// heapsize specialization for `intrusive_ptr` +namespace pvt { +template +inline size_t +heapsize(const intrusive_ptr& ref) +{ + return ref ? footprint(*ref.get()) : 0; +} + +// footprint specialization for `intrusive_ptr` +template +inline size_t +footprint(const intrusive_ptr& ref) +{ + return sizeof(intrusive_ptr) + heapsize(ref); +} +} // namespace pvt + + OIIO_NAMESPACE_END diff --git a/src/libOpenImageIO/formatspec.cpp b/src/libOpenImageIO/formatspec.cpp index 461ab88ee1..11515f6b4e 100644 --- a/src/libOpenImageIO/formatspec.cpp +++ b/src/libOpenImageIO/formatspec.cpp @@ -1251,4 +1251,17 @@ ImageSpec::set_colorspace(string_view colorspace) } + +template<> +size_t +pvt::heapsize(const ImageSpec& is) +{ + size_t size = pvt::heapsize(is.channelformats); + size += pvt::heapsize(is.channelnames); + size += pvt::heapsize(is.extra_attribs); + return size; +} + + + OIIO_NAMESPACE_END diff --git a/src/libOpenImageIO/imageinput.cpp b/src/libOpenImageIO/imageinput.cpp index a6814575bf..9d2d658ce7 100644 --- a/src/libOpenImageIO/imageinput.cpp +++ b/src/libOpenImageIO/imageinput.cpp @@ -1337,4 +1337,17 @@ ImageInput::check_open(const ImageSpec& spec, ROI range, uint64_t /*flags*/) return true; // all is ok } + + +template<> +size_t +pvt::heapsize(const ImageInput& input) +{ + //! TODO: change ImageInput API to add a virtual heapsize() function + //! to allow per image input override, and call that function here. + return pvt::heapsize(input.m_spec); +} + + + OIIO_NAMESPACE_END diff --git a/src/libOpenImageIO/imageoutput.cpp b/src/libOpenImageIO/imageoutput.cpp index 2d74ac205b..002429fc93 100644 --- a/src/libOpenImageIO/imageoutput.cpp +++ b/src/libOpenImageIO/imageoutput.cpp @@ -1021,4 +1021,15 @@ ImageOutput::check_open(OpenMode mode, const ImageSpec& userspec, ROI range, +template<> +size_t +pvt::heapsize(const ImageOutput& output) +{ + //! TODO: change ImageOutput API to add a virtual heapsize() function + //! to allow per image output override, and call that function here. + return pvt::heapsize(output.m_spec); +} + + + OIIO_NAMESPACE_END diff --git a/src/libOpenImageIO/imagespec_test.cpp b/src/libOpenImageIO/imagespec_test.cpp index 9450174018..3846faa92f 100644 --- a/src/libOpenImageIO/imagespec_test.cpp +++ b/src/libOpenImageIO/imagespec_test.cpp @@ -313,6 +313,8 @@ test_imagespec_from_xml() std::cout << "test_imagespec_from_xml\n"; ImageSpec spec; spec.from_xml(imagespec_xml_string); + print(" spec heapsize = {}\n", pvt::heapsize(spec)); + print(" spec footprint = {}\n", pvt::footprint(spec)); OIIO_CHECK_EQUAL(spec.nchannels, 4); OIIO_CHECK_EQUAL(spec.width, 1920); @@ -331,6 +333,8 @@ test_imagespec_from_xml() int main(int /*argc*/, char* /*argv*/[]) { + print("sizeof(ImageSpec) = {}\n", sizeof(ImageSpec)); + test_imagespec_pixels(); test_imagespec_metadata_val(); test_imagespec_attribute_from_string(); diff --git a/src/libtexture/imagecache.cpp b/src/libtexture/imagecache.cpp index de1afac15d..c048b04fd1 100644 --- a/src/libtexture/imagecache.cpp +++ b/src/libtexture/imagecache.cpp @@ -30,6 +30,8 @@ #include #include +#include "imagecache_memory_print.h" +#include "imagecache_memory_pvt.h" #include "imagecache_pvt.h" #include "imageio_pvt.h" @@ -2004,6 +2006,8 @@ ImageCacheImpl::getstats(int level) const " Failure reads followed by unexplained success:" " {} files, {} tiles\n", stats.file_retry_success, stats.tile_retry_success); + + printImageCacheMemory(out, *this); } if (level >= 2 && files.size()) { @@ -2464,6 +2468,7 @@ ImageCacheImpl::getattribute(string_view name, TypeDesc type, void* val) const if (Strutil::starts_with(name, "stat:")) { // Stats we can just grab + ATTR_DECODE("stat:cache_footprint", long long, footprint(*this)); ATTR_DECODE("stat:cache_memory_used", long long, m_mem_used); ATTR_DECODE("stat:tiles_created", int, m_stat_tiles_created); ATTR_DECODE("stat:tiles_current", int, m_stat_tiles_current); diff --git a/src/libtexture/imagecache_memory_print.h b/src/libtexture/imagecache_memory_print.h new file mode 100644 index 0000000000..1c8cdeff17 --- /dev/null +++ b/src/libtexture/imagecache_memory_print.h @@ -0,0 +1,234 @@ +// Copyright Contributors to the OpenImageIO project. +// SPDX-License-Identifier: Apache-2.0 +// https://github.com/AcademySoftwareFoundation/OpenImageIO + + +/// \file +//// Memory printing utilities specific to the ImageCacheImpl. + + +#pragma once +#define OPENIMAGEIO_IMAGECACHE_MEMORY_PRINT_H + +#include "imagecache_memory_pvt.h" + +#include + +OIIO_NAMESPACE_BEGIN + +namespace pvt { + +//// Memory tracking helper to get ImageCacheImpl statistics + +//! recorded entries per file format +enum FileFootprintEnty : uint8_t { + kMem = 0, + kCount, + kSpecMem, + kSpecCount, + kInputMem, + kInputCount, + kSubImageMem, + kSubImageCount, + kLevelInfoMem, + kLevelInfoCount, + kLevelInfoSpecMem, + kLevelInfoSpecMembMem, + kLevelInfoSpecParmsMem, + kLevelInfoSpecChanMem, + kFootprintEntrySize +}; + +typedef std::array FileFootprint; +typedef tsl::robin_map FileFootprintMap; + +struct ImageCacheFootprint { + static const ustring utotal; + static const ustring uconstant; + + // basic infos + size_t ic_mem = 0; // image cache + size_t ic_str_mem = 0, ic_str_count = 0; // std::string + size_t ic_tile_mem = 0, ic_tile_count = 0; // tile + size_t ic_thdi_mem = 0, ic_thdi_count = 0; // thread info + size_t ic_fgpt_mem = 0, ic_fgpt_count = 0; // fingerprint + + FileFootprintMap fmap; + template + void add(const size_t size, const ustring& format) + { + addInternal(size, utotal); + addInternal(size, format); + } + + template + void addInternal(const size_t size, const ustring& key) + { + std::pair insert = fmap.insert( + { key, FileFootprint() }); + FileFootprint& array = insert.first.value(); + if (insert.second) + std::fill(array.begin(), array.end(), + 0ul); // std::array has no default init to zero + + // update memory entry + array[entry] += size; + + // update memory entry counter if exists + if constexpr (entry % 2 == 0 && entry <= kLevelInfoMem) + array[entry + 1] += 1; + } +}; + +const ustring ImageCacheFootprint::utotal = ustring("total"); +const ustring ImageCacheFootprint::uconstant = ustring("constant"); + +/// Fills the parameter with a memory breakdown of the ImageCache. +inline size_t +footprint(const ImageCacheImpl& ic, ImageCacheFootprint& output) +{ + // strings + output.ic_str_count = ic.m_searchdirs.size() + 2; + output.ic_str_mem = heapsize(ic.m_searchdirs) + heapsize(ic.m_searchpath) + + heapsize(ic.m_plugin_searchpath); + + // thread info + output.ic_thdi_count = ic.m_all_perthread_info.size(); + output.ic_thdi_mem = heapsize(ic.m_all_perthread_info); + + // tile cache + output.ic_tile_count = ic.m_tilecache.size(); + for (TileCache::iterator t = ic.m_tilecache.begin(), + e = ic.m_tilecache.end(); + t != e; ++t) + output.ic_tile_mem += footprint(t->first) + footprint(t->second); + + // finger prints; we only account for references, this map does not own the files. + constexpr size_t sizeofFingerprintPair = sizeof(ustring) + + sizeof(ImageCacheFileRef); + output.ic_fgpt_count = ic.m_fingerprints.size(); + output.ic_fgpt_mem = output.ic_fgpt_count * sizeofFingerprintPair; + + // files; count the footprint of files, subimages, level infos, image inputs, image specs + for (FilenameMap::iterator t = ic.m_files.begin(), e = ic.m_files.end(); + t != e; ++t) { + // get file format ustring; files with empty file format are simply constant valued. + const ImageCacheFile& file(*t->second); + const ustring& format = !file.fileformat().empty() + ? file.fileformat() + : ImageCacheFootprint::uconstant; + + const size_t fileftp = footprint(t->first) + footprint(t->second); + output.add(fileftp, format); + + const size_t specftp = footprint(file.m_configspec); + output.add(specftp, format); + + const size_t inputftp = footprint(file.m_input); + output.add(inputftp, format); + + // subimages + for (int s = 0, send = file.subimages(); s < send; ++s) { + const ImageCacheFile::SubimageInfo& sub(file.subimageinfo(s)); + const size_t subftp = footprint(sub); + output.add(subftp, format); + + // level infos + for (const auto& level : sub.levels) { + const size_t lvlftp = footprint(level); + output.add(lvlftp, format); + + // extra infos; there are two ImageSpec structures stored in each LevelInfos, + // and they turn out to be memory heavy, so we further break that down next. + const size_t lvlspecftp = footprint(level.m_spec) + + footprint(level.nativespec); + const size_t lvlattrftp + = (level.m_spec ? footprint(level.m_spec->extra_attribs) + : 0) + + footprint(level.nativespec.extra_attribs); + const size_t lvlchanftp + = (level.m_spec ? footprint(level.m_spec->channelnames) : 0) + + footprint(level.nativespec.channelnames); + output.add(lvlspecftp, format); + output.add(2 * sizeof(ImageSpec), + format); + output.add(lvlattrftp, format); + output.add(lvlchanftp, format); + } + } + } + + // update total memory + output.ic_mem += output.ic_str_mem; + output.ic_mem += output.ic_tile_mem; + output.ic_mem += output.ic_thdi_mem; + output.ic_mem += output.fmap.find(ImageCacheFootprint::utotal)->second[kMem]; + output.ic_mem += output.ic_fgpt_mem; + + return output.ic_mem; +} + +inline void +printImageCacheMemory(std::ostream& out, const ImageCacheImpl& ic) +{ + // get memory data + pvt::ImageCacheFootprint data; + pvt::footprint(ic, data); + + // print image cache memory usage + print(out, " Cache : {}\n", Strutil::memformat(data.ic_mem)); + print(out, " Strings : {}, count : {}\n", + Strutil::memformat(data.ic_str_mem), data.ic_str_count); + print(out, " Thread info : {}, count : {}\n", + Strutil::memformat(data.ic_thdi_mem), data.ic_thdi_count); + print(out, " Fingerprints : {}, count : {}\n", + Strutil::memformat(data.ic_fgpt_mem), data.ic_fgpt_count); + print(out, " Tiles : {}, count : {}\n", + Strutil::memformat(data.ic_tile_mem), data.ic_tile_count); + print(out, " Files : {}, count : {}\n", + Strutil::memformat(data.fmap[ImageCacheFootprint::utotal][kMem]), + data.fmap[ImageCacheFootprint::utotal][kCount]); + + // print file formats memory usage + for (pvt::FileFootprintMap::const_iterator t = data.fmap.begin(), + e = data.fmap.end(); + t != e; ++t) { + if (t.key() == ImageCacheFootprint::utotal) + continue; + print(out, " Format '{}' : {}, count : {}\n", t->first, + Strutil::memformat(t.value()[kMem]), t.value()[kCount]); + if (t.value()[kInputMem] > 0ul) + print(out, " Image inputs : {}, count : {}\n", + Strutil::memformat(t.value()[kInputMem]), + t.value()[kInputCount]); + if (t.value()[kSpecMem] > 0ul) + print(out, " Image specs : {}, count : {}\n", + Strutil::memformat(t.value()[kSpecMem]), + t.value()[kSpecCount]); + if (t.value()[kSubImageMem] > 0ul) + print(out, " Subimages : {}, count : {}\n", + Strutil::memformat(t.value()[kSubImageMem]), + t.value()[kSubImageCount]); + if (t.value()[kLevelInfoMem] > 0ul) + print(out, " Level infos : {}, count : {}\n", + Strutil::memformat(t.value()[kLevelInfoMem]), + t.value()[kLevelInfoCount]); + if (t.value()[kLevelInfoSpecMem] > 0ul) + print(out, " Image specs : {}, count : {}\n", + Strutil::memformat(t.value()[kLevelInfoSpecMem]), + t.value()[kLevelInfoCount] * 2); + if (t.value()[kLevelInfoSpecMembMem] > 0ul) + print(out, " Members : {}\n", + Strutil::memformat(t.value()[kLevelInfoSpecMembMem])); + if (t.value()[kLevelInfoSpecParmsMem] > 0ul) + print(out, " Extra attributes : {}\n", + Strutil::memformat(t.value()[kLevelInfoSpecParmsMem])); + if (t.value()[kLevelInfoSpecChanMem] > 0ul) + print(out, " Channel names : {}\n", + Strutil::memformat(t.value()[kLevelInfoSpecChanMem])); + } +} + +} // namespace pvt + +OIIO_NAMESPACE_END \ No newline at end of file diff --git a/src/libtexture/imagecache_memory_pvt.h b/src/libtexture/imagecache_memory_pvt.h new file mode 100644 index 0000000000..10ee4ee8b9 --- /dev/null +++ b/src/libtexture/imagecache_memory_pvt.h @@ -0,0 +1,109 @@ +// Copyright Contributors to the OpenImageIO project. +// SPDX-License-Identifier: Apache-2.0 +// https://github.com/AcademySoftwareFoundation/OpenImageIO + + +/// \file +//// Memory tracking utilities specific to the ImageCacheImpl. + + +#pragma once +#define OPENIMAGEIO_IMAGECACHE_MEMORY_PVT_H + +#include + +#include "imagecache_pvt.h" + +OIIO_NAMESPACE_BEGIN + +namespace pvt { + +// heapsize specialization for ImageCacheFile::LevelInfo +template<> +inline size_t +heapsize(const ImageCacheFile::LevelInfo& lvl) +{ + size_t size = heapsize(lvl.polecolor); + size += heapsize(lvl.m_spec); + size += heapsize(lvl.nativespec); + if (lvl.tiles_read) { + const size_t total_tiles = lvl.nxtiles * lvl.nytiles * lvl.nztiles; + const size_t bitfield_size = round_to_multiple(total_tiles, 64) / 64; + size += sizeof(atomic_ll) * bitfield_size; + } + return size; +} + +// heapsize specialization for ImageCacheFile::SubimageInfo +template<> +inline size_t +heapsize(const ImageCacheFile::SubimageInfo& sub) +{ + size_t size = heapsize(sub.levels); + size += heapsize(sub.average_color); + size += (sub.minwh ? sub.n_mip_levels * sizeof(int) : 0); + size += (sub.Mlocal ? sizeof(Imath::M44f) : 0); + return size; +} + +// heapsize specialization for ImageCacheFile +template<> +inline size_t +heapsize(const ImageCacheFile& file) +{ + size_t size = heapsize(file.m_subimages); + size += heapsize(file.m_configspec); + size += heapsize(file.m_input); + size += heapsize(file.m_mipreadcount); + size += heapsize(file.m_udim_lookup); + return size; +} + +// heapsize specialization for ImageCacheTile +template<> +inline size_t +heapsize(const ImageCacheTile& tile) +{ + return tile.memsize(); +} + +// heapsize specialization for ImageCachePerThreadInfo +template<> +inline size_t +heapsize(const ImageCachePerThreadInfo& info) +{ + /// TODO: this should take into account the two last tiles, if their refcount is zero. + constexpr size_t sizeofPair = sizeof(ustring) + sizeof(ImageCacheFile*); + return info.m_thread_files.size() * sizeofPair; +} + +// heapsize specialization for ImageCacheImpl +template<> +inline size_t +heapsize(const ImageCacheImpl& ic) +{ + size_t size = 0; + // strings + size += heapsize(ic.m_searchpath) + heapsize(ic.m_plugin_searchpath) + + heapsize(ic.m_searchdirs); + // thread info + size += heapsize(ic.m_all_perthread_info); + // tile cache + for (TileCache::iterator t = ic.m_tilecache.begin(), + e = ic.m_tilecache.end(); + t != e; ++t) + size += footprint(t->first) + footprint(t->second); + // files + for (FilenameMap::iterator t = ic.m_files.begin(), e = ic.m_files.end(); + t != e; ++t) + size += footprint(t->first) + footprint(t->second); + // finger prints; we only account for references, this map does not own the files. + constexpr size_t sizeofFingerprintPair = sizeof(ustring) + + sizeof(ImageCacheFileRef); + size += ic.m_fingerprints.size() * sizeofFingerprintPair; + return size; +} + +} // namespace pvt + +OIIO_NAMESPACE_END \ No newline at end of file diff --git a/src/libtexture/imagecache_pvt.h b/src/libtexture/imagecache_pvt.h index d0d353fce1..262ee99ca1 100644 --- a/src/libtexture/imagecache_pvt.h +++ b/src/libtexture/imagecache_pvt.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,7 @@ namespace pvt { struct TileID; class ImageCacheImpl; class ImageCachePerThreadInfo; +struct ImageCacheFootprint; const char* texture_format_name(TexFormat f); @@ -466,6 +468,12 @@ class OIIO_API ImageCacheFile final : public RefCnt { friend class ImageCacheImpl; friend class TextureSystemImpl; friend struct SubimageInfo; + + /// Memory tracking. Specializes the base memory tracking functions from memory.h. + /// declare a friend heapsize definition + template friend inline size_t heapsize(const T&); + /// declare a friend image cache footprint definition + friend inline size_t footprint(const ImageCacheImpl&, ImageCacheFootprint&); }; @@ -1197,7 +1205,9 @@ class ImageCacheImpl final : public ImageCache { spin_mutex m_fingerprints_mutex; ///< Protect m_fingerprints FingerprintMap m_fingerprints; ///< Map fingerprints to files - TileCache m_tilecache; ///< Our in-memory tile cache + /// FIXME: if unordered_map_concurrent had const iterators, + /// m_tilecache wouldn't need to be mutable + mutable TileCache m_tilecache; ///< Our in-memory tile cache TileID m_tile_sweep_id; ///< Sweeper for "clock" paging algorithm spin_mutex m_tile_sweep_mutex; ///< Ensure only one in check_max_mem @@ -1236,6 +1246,11 @@ class ImageCacheImpl final : public ImageCache { // done it with nobody else interfering. } while (llstat->compare_exchange_strong(*llnewval, *lloldval)); } + + /// declare a friend heapsize definition + template friend inline size_t heapsize(const T&); + /// declare a friend image cache footprint definition + friend inline size_t footprint(const ImageCacheImpl&, ImageCacheFootprint&); }; diff --git a/src/libutil/paramlist.cpp b/src/libutil/paramlist.cpp index c3edb9cedb..8439a56ba2 100644 --- a/src/libutil/paramlist.cpp +++ b/src/libutil/paramlist.cpp @@ -383,6 +383,17 @@ ParamValue::clear_value() noexcept +template<> +size_t +pvt::heapsize(const ParamValue& pv) +{ + return (pv.m_nonlocal && pv.m_copy) + ? pv.m_nvalues * static_cast(pv.m_type.size()) + : 0; +} + + + ParamValueList::const_iterator ParamValueList::find(ustring name, TypeDesc type, bool casesensitive) const { diff --git a/src/libutil/paramlist_test.cpp b/src/libutil/paramlist_test.cpp index fbd4e9555d..6531de20a6 100644 --- a/src/libutil/paramlist_test.cpp +++ b/src/libutil/paramlist_test.cpp @@ -274,14 +274,30 @@ test_from_string() +void +populate_pvl(ParamValueList& pl) +{ + pl["foo"] = 42; + pl["pi"] = float(M_PI); + pl["bar"] = "barbarbar?"; + pl["bar2"] = std::string("barbarbar?"); + pl["bar3"] = ustring("barbarbar?"); + pl["bar4"] = string_view("barbarbar?"); + pl["red"] = Imath::Color3f(1.0f, 0.0f, 0.0f); + pl["xy"] = Imath::V3f(0.5f, 0.5f, 0.0f); + pl["Tx"] = Imath::M44f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 42, 0, 0, 1); +} + + + static void test_paramlist() { std::cout << "test_paramlist\n"; ParamValueList pl; - pl.emplace_back("foo", int(42)); - pl.emplace_back("pi", float(M_PI)); - pl.emplace_back("bar", "barbarbar?"); + populate_pvl(pl); + print("ParamValueList pl heapsize is: {}\n", pvt::heapsize(pl)); + print("ParamValueList pl footprint is: {}\n", pvt::footprint(pl)); OIIO_CHECK_EQUAL(pl.get_int("foo"), 42); OIIO_CHECK_EQUAL(pl.get_int("pi", 4), 4); // should fail int @@ -344,15 +360,7 @@ test_delegates() { std::cout << "test_delegates\n"; ParamValueList pl; - pl["foo"] = 42; - pl["pi"] = float(M_PI); - pl["bar"] = "barbarbar?"; - pl["bar2"] = std::string("barbarbar?"); - pl["bar3"] = ustring("barbarbar?"); - pl["bar4"] = string_view("barbarbar?"); - pl["red"] = Imath::Color3f(1.0f, 0.0f, 0.0f); - pl["xy"] = Imath::V3f(0.5f, 0.5f, 0.0f); - pl["Tx"] = Imath::M44f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 42, 0, 0, 1); + populate_pvl(pl); OIIO_CHECK_EQUAL(pl["absent"].get(), 0); OIIO_CHECK_EQUAL(pl["absent"].type(), TypeUnknown); @@ -402,15 +410,7 @@ test_paramlistspan() { std::cout << "test_paramlistspan\n"; ParamValueList pvlist; - pvlist.emplace_back("foo", int(42)); - pvlist.emplace_back("pi", float(M_PI)); - pvlist.emplace_back("bar", "barbarbar?"); - pvlist["bar2"] = std::string("barbarbar?"); - pvlist["bar3"] = ustring("barbarbar?"); - pvlist["bar4"] = string_view("barbarbar?"); - pvlist["red"] = Imath::Color3f(1.0f, 0.0f, 0.0f); - pvlist["xy"] = Imath::V3f(0.5f, 0.5f, 0.0f); - pvlist["Tx"] = Imath::M44f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 42, 0, 0, 1); + populate_pvl(pvlist); ParamValueSpan pl(pvlist); OIIO_CHECK_EQUAL(pl.get_int("foo"), 42); @@ -526,7 +526,9 @@ test_implied_construction() int main(int /*argc*/, char* /*argv*/[]) { - std::cout << "ParamValue size = " << sizeof(ParamValue) << "\n"; + print("sizeof(ParamValue) is: {}\n", sizeof(ParamValue)); + print("sizeof(ParamValueList) is: {}\n", sizeof(ParamValueList)); + test_value_types(); test_from_string(); test_paramlist(); From a7c8fd81cd5712f878697bce09bd1ba0d2226f55 Mon Sep 17 00:00:00 2001 From: Larry Gritz Date: Mon, 12 Aug 2024 10:53:32 -0700 Subject: [PATCH 035/147] deps: Make OCIO 2.2+ a required dependency (#4367) Make OCIO a hard dependency, at least version 2.2. Revise and improve the OCIO "auto-build" scripts. Remove OCIO 1.x testsuite reference output. No longer need FindOpenColorIO.cmake module As part of this, I split the CI "oldest/hobbled" test into two different tests: * oldest -- test against the oldest supported versions of all dependencies. * hobbled -- test against most optional dependencies missing and optional features disabled. --------- Signed-off-by: Larry Gritz --- .github/workflows/ci.yml | 37 +- INSTALL.md | 3 +- src/build-scripts/build_opencolorio.bash | 4 +- src/build-scripts/ci-build.bash | 2 +- src/build-scripts/ci-startup.bash | 1 - src/cmake/Config.cmake.in | 1 + src/cmake/build_OpenColorIO.cmake | 17 +- src/cmake/externalpackages.cmake | 18 +- src/cmake/modules/FindOpenColorIO.cmake | 138 - src/cmake/testing.cmake | 14 +- src/iv/imageviewer.cpp | 17 +- src/iv/imageviewer.h | 6 - src/iv/ivgl_ocio.cpp | 8 +- src/iv/ivgl_ocio.h | 26 +- src/iv/ivmain.cpp | 14 +- src/libOpenImageIO/CMakeLists.txt | 3 +- src/libOpenImageIO/color_ocio.cpp | 184 +- .../OpenColorIO/nuke-default/config.ocio | 191 - .../nuke-default/luts/alexalogc.spi1d | 4107 - .../nuke-default/luts/cineon.spi1d | 4107 - .../nuke-default/luts/panalog.spi1d | 4107 - .../nuke-default/luts/ploglin.spi1d | 4107 - .../nuke-default/luts/rec709.spi1d | 4107 - .../nuke-default/luts/redlog.spi1d | 4107 - .../OpenColorIO/nuke-default/luts/slog.spi1d | 4107 - .../OpenColorIO/nuke-default/luts/srgb.spi1d | 4107 - .../OpenColorIO/nuke-default/luts/srgbf.spi1d | 65567 ---------------- .../nuke-default/luts/viperlog.spi1d | 4107 - .../common/OpenColorIO/nuke-default/make.py | 489 - .../common/OpenColorIO/ocio-v2_demo.ocio | 534 - .../oiiotool-color/ref/out-ocio1.1.0.txt | 62 - .../oiiotool-color/ref/out-ocio1.1.0b.txt | 62 - testsuite/oiiotool-color/ref/out-ocio22.txt | 58 - testsuite/oiiotool-color/ref/out.txt | 7 +- testsuite/oiiotool-color/run.py | 21 +- .../ref/out-noocio-python3.txt | 30 - .../ref/out-ocio11-python3.txt | 30 - .../ref/out-ocio21-python3.txt | 30 - .../python-colorconfig/ref/out-ocio22.txt | 30 - testsuite/python-colorconfig/ref/out.txt | 37 +- testsuite/runtest.py | 16 +- 41 files changed, 102 insertions(+), 104518 deletions(-) delete mode 100644 src/cmake/modules/FindOpenColorIO.cmake delete mode 100644 testsuite/common/OpenColorIO/nuke-default/config.ocio delete mode 100644 testsuite/common/OpenColorIO/nuke-default/luts/alexalogc.spi1d delete mode 100644 testsuite/common/OpenColorIO/nuke-default/luts/cineon.spi1d delete mode 100644 testsuite/common/OpenColorIO/nuke-default/luts/panalog.spi1d delete mode 100644 testsuite/common/OpenColorIO/nuke-default/luts/ploglin.spi1d delete mode 100644 testsuite/common/OpenColorIO/nuke-default/luts/rec709.spi1d delete mode 100644 testsuite/common/OpenColorIO/nuke-default/luts/redlog.spi1d delete mode 100644 testsuite/common/OpenColorIO/nuke-default/luts/slog.spi1d delete mode 100644 testsuite/common/OpenColorIO/nuke-default/luts/srgb.spi1d delete mode 100644 testsuite/common/OpenColorIO/nuke-default/luts/srgbf.spi1d delete mode 100644 testsuite/common/OpenColorIO/nuke-default/luts/viperlog.spi1d delete mode 100755 testsuite/common/OpenColorIO/nuke-default/make.py delete mode 100644 testsuite/common/OpenColorIO/ocio-v2_demo.ocio delete mode 100644 testsuite/oiiotool-color/ref/out-ocio1.1.0.txt delete mode 100644 testsuite/oiiotool-color/ref/out-ocio1.1.0b.txt delete mode 100644 testsuite/oiiotool-color/ref/out-ocio22.txt delete mode 100644 testsuite/python-colorconfig/ref/out-noocio-python3.txt delete mode 100644 testsuite/python-colorconfig/ref/out-ocio11-python3.txt delete mode 100644 testsuite/python-colorconfig/ref/out-ocio21-python3.txt delete mode 100644 testsuite/python-colorconfig/ref/out-ocio22.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3ea0ac8a8c..40a2cfff30 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -94,6 +94,7 @@ jobs: container: aswf/ci-osl:2022 vfxyear: 2022 cxx_std: 17 + opencolorio_ver: v2.2.1 python_ver: 3.9 # simd: "avx2,f16c" fmt_ver: 7.1.3 @@ -104,7 +105,7 @@ jobs: FREETYPE_VERSION=VER-2-13-0 # For icc, use fp-model precise to eliminate needless LSB errors # that make test results differ from other platforms. - - desc: icx/C++17 py3.9 exr3.1 ocio2.1 qt5.15 + - desc: icx/C++17 py3.9 exr3.1 ocio2.2 qt5.15 nametag: linux-vfx2022-icx runner: ubuntu-latest container: aswf/ci-osl:2022 @@ -112,10 +113,14 @@ jobs: cc_compiler: icx cxx_compiler: icpx cxx_std: 17 + opencolorio_ver: v2.3.2 python_ver: 3.9 - simd: "avx2,f16c" pybind11_ver: v2.9.0 + simd: "avx2,f16c" setenvs: export USE_OPENVDB=0 + OPENCOLORIO_CXX=g++ + # OCIO doesn't build with icx, so we have to force the ocio build + # to use g++. - desc: sanitizers nametag: sanitizer runner: ubuntu-latest @@ -124,6 +129,7 @@ jobs: cc_compiler: clang cxx_compiler: clang++ cxx_std: 17 + opencolorio_ver: v2.3.2 python_ver: 3.9 setenvs: export SANITIZE=address,undefined OIIO_CMAKE_FLAGS="-DSANITIZE=address,undefined -DUSE_PYTHON=0" @@ -150,15 +156,15 @@ jobs: simd: "avx2,f16c" fmt_ver: 10.1.1 pybind11_ver: v2.12.0 - - desc: oldest gcc9.3/C++17 py3.7 exr-3.1 no-sse no-ocio - # Oldest versions of the dependencies that we can muster, and various - # things disabled (no SSE, OCIO, or OpenCV, don't embed plugins). + - desc: oldest gcc9.3/C++17 py3.7 exr-3.1 + # Oldest versions of the dependencies that we support. nametag: linux-oldest runner: ubuntu-latest container: aswf/ci-osl:2021 vfxyear: 2021 cxx_std: 17 fmt_ver: 7.0.1 + opencolorio_ver: v2.2.1 openexr_ver: v3.1.0 pybind11_ver: v2.7.0 python_ver: 3.7 @@ -166,18 +172,19 @@ jobs: PTEX_VERSION=v2.3.2 WEBP_VERSION=v1.1.0 depcmds: sudo rm -rf /usr/local/include/OpenEXR - - desc: hobbled gcc9.3/C++17 py3.7 exr-3.1 no-sse no-ocio + - desc: hobbled gcc9.3/C++17 py3.7 exr-3.1 no-sse # Use the oldest supported versions of required dependencies, and - # disable most optional dependencies and features (no SSE, OCIO, - # or OpenCV, don't embed plugins). + # disable most optional dependencies and features (no SSE or + # OpenCV, don't embed plugins). nametag: linux-disabled runner: ubuntu-latest container: aswf/ci-osl:2021 vfxyear: 2021 cxx_std: 17 fmt_ver: 7.0.1 + opencolorio_ver: v2.2.1 openexr_ver: v3.1.0 - pybind11_ver: v2.7.0 + pybind11_ver: v2.4.2 python_ver: 3.7 simd: 0 setenvs: export EMBEDPLUGINS=0 @@ -185,7 +192,6 @@ jobs: PTEX_VERSION=v2.3.2 WEBP_VERSION=v1.1.0 USE_JPEGTURBO=0 - USE_OPENCOLORIO=0 USE_OPENCV=0 FREETYPE_VERSION=VER-2-10-0 depcmds: sudo rm -rf /usr/local/include/OpenEXR @@ -220,6 +226,7 @@ jobs: CMAKE_CXX_STANDARD: ${{matrix.cxx_std}} USE_SIMD: ${{matrix.simd}} FMT_VERSION: ${{matrix.fmt_ver}} + OPENCOLORIO_VERSION: ${{matrix.opencolorio_ver}} OPENEXR_VERSION: ${{matrix.openexr_ver}} PYBIND11_VERSION: ${{matrix.pybind11_ver}} PYTHON_VERSION: ${{matrix.python_ver}} @@ -308,6 +315,7 @@ jobs: cxx_compiler: g++-12 cxx_std: 17 fmt_ver: 10.1.1 + opencolorio_ver: v2.3.2 openexr_ver: v3.2.4 pybind11_ver: v2.12.0 python_ver: "3.10" @@ -315,7 +323,6 @@ jobs: setenvs: export LIBJPEGTURBO_VERSION=3.0.1 LIBRAW_VERSION=0.21.2 LIBTIFF_VERSION=v4.6.0 - OPENCOLORIO_VERSION=v2.3.2 OPENJPEG_VERSION=v2.4.0 PTEX_VERSION=v2.4.2 PUGIXML_VERSION=v1.14 @@ -329,6 +336,7 @@ jobs: cxx_compiler: g++-14 cxx_std: 20 fmt_ver: master + opencolorio_ver: main openexr_ver: main pybind11_ver: master python_ver: "3.12" @@ -336,7 +344,6 @@ jobs: setenvs: export LIBJPEGTURBO_VERSION=main LIBRAW_VERSION=master LIBTIFF_VERSION=master - OPENCOLORIO_VERSION=main OPENJPEG_VERSION=master PTEX_VERSION=main PUGIXML_VERSION=master @@ -376,12 +383,12 @@ jobs: cc_compiler: clang cxx_std: 20 fmt_ver: 10.1.1 + opencolorio_ver: v2.2.1 openexr_ver: v3.1.13 pybind11_ver: v2.12.0 python_ver: 3.8 simd: avx2,f16c setenvs: export LLVM_VERSION=14.0.0 - OPENCOLORIO_VERSION=v2.1.2 USE_OPENVDB=0 # The installed OpenVDB has a TLS conflict with Python 3.8 - desc: debug gcc9/C++17, sse4.2, exr3.1 @@ -425,7 +432,8 @@ jobs: OIIO_CMAKE_FLAGS=-DUSE_PYTHON=0 LLVM_VERSION=17.0.6 LLVM_DISTRO_NAME=ubuntu-22.04 SKIP_SYSTEM_DEPS_INSTALL=1 QT_VERSION=0 - OpenImageIO_BUILD_MISSING_DEPS=none + xOpenImageIO_BUILD_MISSING_DEPS=missing + OpenImageIO_OPTIONAL_DEPS=ALL runs-on: ${{ matrix.runner }} env: @@ -434,6 +442,7 @@ jobs: CMAKE_CXX_STANDARD: ${{matrix.cxx_std}} USE_SIMD: ${{matrix.simd}} FMT_VERSION: ${{matrix.fmt_ver}} + OPENCOLORIO_VERSION: ${{matrix.opencolorio_ver}} OPENEXR_VERSION: ${{matrix.openexr_ver}} PYBIND11_VERSION: ${{matrix.pybind11_ver}} PYTHON_VERSION: ${{matrix.python_ver}} diff --git a/INSTALL.md b/INSTALL.md index 40270955af..91bf97d707 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -23,6 +23,7 @@ NEW or CHANGED MINIMUM dependencies since the last major release are **bold**. * **Imath >= 3.1** (tested through 3.1.x and main) * **OpenEXR >= 3.1** (tested through 3.2 and main) * **libTIFF >= 4.0** (tested through 4.6) + * **OpenColorIO >= 2.2** (tested through 2.3) * libjpeg >= 8 (tested through jpeg9e), or **libjpeg-turbo >= 2.1** (tested through 3.0) * **[fmtlib](https://github.com/fmtlib/fmt) >= 7.0** (tested through 10.2). @@ -66,8 +67,6 @@ NEW or CHANGED MINIMUM dependencies since the last major release are **bold**. * DCMTK >= 3.6.1 (tested through 3.6.8) * If you want support for WebP images: * **WebP >= 1.1** (tested through 1.4) - * If you want support for OpenColorIO color transformations: - * OpenColorIO >= 1.1 (tested through 2.3; 2.0+ is recommended) * If you want support for Ptex: * Ptex >= 2.3.1 (probably works for older; tested through 2.4.2) * If you want to be able to do font rendering into images: diff --git a/src/build-scripts/build_opencolorio.bash b/src/build-scripts/build_opencolorio.bash index ef37c121ad..b5018bc13c 100755 --- a/src/build-scripts/build_opencolorio.bash +++ b/src/build-scripts/build_opencolorio.bash @@ -11,7 +11,7 @@ set -ex # Which OCIO to retrieve, how to build it OPENCOLORIO_REPO=${OPENCOLORIO_REPO:=https://github.com/AcademySoftwareFoundation/OpenColorIO.git} -OPENCOLORIO_VERSION=${OPENCOLORIO_VERSION:=v2.2.1} +OPENCOLORIO_VERSION=${OPENCOLORIO_VERSION:=v2.3.2} # Where to install the final results LOCAL_DEPS_DIR=${LOCAL_DEPS_DIR:=${PWD}/ext} @@ -19,6 +19,7 @@ OPENCOLORIO_SOURCE_DIR=${OPENCOLORIO_SOURCE_DIR:=${LOCAL_DEPS_DIR}/OpenColorIO} OPENCOLORIO_BUILD_DIR=${OPENCOLORIO_BUILD_DIR:=${LOCAL_DEPS_DIR}/OpenColorIO-build} OPENCOLORIO_INSTALL_DIR=${OPENCOLORIO_INSTALL_DIR:=${LOCAL_DEPS_DIR}/dist} OPENCOLORIO_BUILD_TYPE=${OPENCOLORIO_BUILD_TYPE:=Release} +OPENCOLORIO_CXX=${OPENCOLORIO_CXX:=g++} OPENCOLORIO_CXX_FLAGS=${OPENCOLORIO_CXX_FLAGS:="-Wno-unused-function -Wno-deprecated-declarations -Wno-cast-qual -Wno-write-strings"} # Just need libs: OPENCOLORIO_BUILDOPTS="-DOCIO_BUILD_APPS=OFF -DOCIO_BUILD_NUKE=OFF \ @@ -46,6 +47,7 @@ git checkout ${OPENCOLORIO_VERSION} --force time cmake -S . -B ${OPENCOLORIO_BUILD_DIR} \ -DCMAKE_BUILD_TYPE=${OPENCOLORIO_BUILD_TYPE} \ -DCMAKE_INSTALL_PREFIX=${OPENCOLORIO_INSTALL_DIR} \ + -DCMAKE_CXX_COMPILER=${OPENCOLORIO_CXX} \ -DCMAKE_CXX_FLAGS="${OPENCOLORIO_CXX_FLAGS}" \ ${OPENCOLORIO_BUILDOPTS} time cmake --build ${OPENCOLORIO_BUILD_DIR} --config Release --target install diff --git a/src/build-scripts/ci-build.bash b/src/build-scripts/ci-build.bash index e5dfaf6c3f..fa5857abaf 100755 --- a/src/build-scripts/ci-build.bash +++ b/src/build-scripts/ci-build.bash @@ -43,7 +43,7 @@ cmake -S $OIIO_SRC_DIR -B $OIIO_BUILD_DIR -G "$CMAKE_GENERATOR" \ $OIIO_CMAKE_FLAGS -DVERBOSE=1 # Save a copy of the generated files for debugging broken CI builds. -mkdir ${OIIO_BUILD_DIR}/cmake-save || /bin/true +mkdir ${OIIO_BUILD_DIR}/cmake-save || true cp -r ${OIIO_BUILD_DIR}/CMake* ${OIIO_BUILD_DIR}/*.cmake ${OIIO_BUILD_DIR}/cmake-save : ${BUILDTARGET:=install} diff --git a/src/build-scripts/ci-startup.bash b/src/build-scripts/ci-startup.bash index bb49fd3311..527f29d594 100755 --- a/src/build-scripts/ci-startup.bash +++ b/src/build-scripts/ci-startup.bash @@ -44,7 +44,6 @@ export LD_LIBRARY_PATH=${LOCAL_DEPS_DIR}/dist/lib:$LD_LIBRARY_PATH export LD_LIBRARY_PATH=${LOCAL_DEPS_DIR}/dist/lib64:$LD_LIBRARY_PATH export DYLD_LIBRARY_PATH=${LOCAL_DEPS_DIR}/dist/lib:$DYLD_LIBRARY_PATH -# export OCIO="$PWD/testsuite/common/OpenColorIO/nuke-default/config.ocio" export TESTSUITE_CLEANUP_ON_SUCCESS=${TESTSUITE_CLEANUP_ON_SUCCESS:=1} # For CI, default to building missing dependencies automatically diff --git a/src/cmake/Config.cmake.in b/src/cmake/Config.cmake.in index 30d4e3a5d2..2620994b38 100644 --- a/src/cmake/Config.cmake.in +++ b/src/cmake/Config.cmake.in @@ -21,6 +21,7 @@ if (NOT @BUILD_SHARED_LIBS@) # INTERFACE_LINK_LIBRARIES. If the project does not know about PNG target, it will cause # configuration error about unknown targets being linked in. find_dependency(TIFF) + find_dependency(OpenColorIO) if (@JPEG_FOUND@) find_dependency(JPEG) endif() diff --git a/src/cmake/build_OpenColorIO.cmake b/src/cmake/build_OpenColorIO.cmake index 5905eb597a..6e772245f0 100644 --- a/src/cmake/build_OpenColorIO.cmake +++ b/src/cmake/build_OpenColorIO.cmake @@ -15,6 +15,14 @@ set_cache (OpenColorIO_BUILD_SHARED_LIBS ON # it all work with the static dependencies, it just makes things complicated # downstream. +# Clear variables from the failed find_package +unset (OPENCOLORIO_LIBRARY) +unset (OPENCOLORIO_INCLUDE_DIR) +unset (FIND_PACKAGE_MESSAGE_DETAILS_OpenColorIO) +unset (OPENCOLORIO_VERSION_MAJOR) +unset (OPENCOLORIO_VERSION_MINOR) +unset (OpenColorIO_DIR) + string (MAKE_C_IDENTIFIER ${OpenColorIO_BUILD_VERSION} OpenColorIO_VERSION_IDENT) build_dependency_with_cmake(OpenColorIO @@ -35,8 +43,8 @@ build_dependency_with_cmake(OpenColorIO -D OCIO_INSTALL_EXT_PACKAGES=MISSING # Give the library a custom name and symbol namespace so it can't # conflict with any others in the system or linked into the same app. - -D OCIO_NAMESPACE=${PROJ_NAMESPACE_V}_OpenColorIO - -D OCIO_LIBNAME_SUFFIX=_v${OpenColorIO_VERSION_IDENT}_${PROJ_NAMESPACE_V} + # -D OCIO_NAMESPACE=${OpenColorIO_VERSION_IDENT}_${PROJ_NAME} + -D OCIO_LIBNAME_SUFFIX=_v${OpenColorIO_VERSION_IDENT}_${PROJ_NAME} ) # Set some things up that we'll need for a subsequent find_package to work @@ -46,8 +54,9 @@ set (OpenColorIO_ROOT ${OpenColorIO_LOCAL_INSTALL_DIR}) set (OpenColorIO_DIR ${OpenColorIO_LOCAL_INSTALL_DIR}) # Signal to caller that we need to find again at the installed location -set (OpenColorIO_REFIND TRUE) -set (OpenColorIO_REFIND_ARGS CONFIG) +# set (OpenColorIO_REFIND TRUE) +# set (OpenColorIO_REFIND_ARGS CONFIG) +find_package (OpenColorIO ${OpenColorIO_BUILD_VERSION} EXACT CONFIG REQUIRED) if (OpenColorIO_BUILD_SHARED_LIBS) install_local_dependency_libs (OpenColorIO OpenColorIO) diff --git a/src/cmake/externalpackages.cmake b/src/cmake/externalpackages.cmake index acecc0244b..3364954715 100644 --- a/src/cmake/externalpackages.cmake +++ b/src/cmake/externalpackages.cmake @@ -136,20 +136,10 @@ checked_find_package (yaml-cpp checked_find_package (OpenColorIO REQUIRED VERSION_MIN 2.2 VERSION_MAX 2.9 - NO_FP_RANGE_CHECK - DEFINITIONS USE_OCIO=1 USE_OPENCOLORIO=1 - ) -if (OpenColorIO_FOUND) - option (OIIO_DISABLE_BUILTIN_OCIO_CONFIGS - "For deveoper debugging/testing ONLY! Disable OCIO 2.2 builtin configs." OFF) - if (OIIO_DISABLE_BUILTIN_OCIO_CONFIGS OR "$ENV{OIIO_DISABLE_BUILTIN_OCIO_CONFIGS}") - add_compile_definitions(OIIO_DISABLE_BUILTIN_OCIO_CONFIGS) - endif () - if (NOT OPENCOLORIO_INCLUDES) - get_target_property(OPENCOLORIO_INCLUDES OpenColorIO::OpenColorIO INTERFACE_INCLUDE_DIRECTORIES) - endif () -else () - set (OpenColorIO_FOUND 0) + PREFER_CONFIG + ) +if (NOT OPENCOLORIO_INCLUDES) + get_target_property(OPENCOLORIO_INCLUDES OpenColorIO::OpenColorIO INTERFACE_INCLUDE_DIRECTORIES) endif () include_directories(BEFORE ${OPENCOLORIO_INCLUDES}) diff --git a/src/cmake/modules/FindOpenColorIO.cmake b/src/cmake/modules/FindOpenColorIO.cmake deleted file mode 100644 index 474813917b..0000000000 --- a/src/cmake/modules/FindOpenColorIO.cmake +++ /dev/null @@ -1,138 +0,0 @@ -# Copyright Contributors to the OpenImageIO project. -# SPDX-License-Identifier: Apache-2.0 -# https://github.com/AcademySoftwareFoundation/OpenImageIO - -# Module to find OpenColorIO -# -# This module will first look into the directories hinted by the variables: -# - OpenColorIO_ROOT -# -# This module defines the following targets: -# -# - OpenColorIO::OpenColorIO -# -# Old style CMake, this module also defines the following variables: -# -# OpenColorIO_FOUND - True if OpenColorIO was found. -# OPENCOLORIO_INCLUDES - where to find OpenColorIO.h -# OPENCOLORIO_LIBRARIES - list of libraries to link against when using OpenColorIO -# OPENCOLORIO_DEFINITIONS - Definitions needed when using OpenColorIO -# -# Hints and overrides: -# -# - OPENCOLORIO_INTERFACE_LINK_LIBRARIES - override for interface link -# libraries on the OpenColorIO::OpenColorIO target. -# - OPENCOLORIO_NO_CONFIG - if ON, this module will be used even if an -# OCIO >= 2.1 cmake config is found. If OFF (the default), a config file -# will be preferred if found. -# -# OpenColorIO 2.1 exports proper cmake config files on its own. -# Once OCIO 2.1 is our new minimum, this FindOpenColorIO.cmake will -# eventually be deprecated and disappear. -# - -if (NOT OPENCOLORIO_NO_CONFIG) - find_package(OpenColorIO CONFIG) -endif () - -if (TARGET OpenColorIO::OpenColorIO) - if (OPENCOLORIO_INTERFACE_LINK_LIBRARIES) - set_target_properties(OpenColorIO::OpenColorIO PROPERTIES - INTERFACE_LINK_LIBRARIES "${OPENCOLORIO_INTERFACE_LINK_LIBRARIES}") - endif () - -else () -# vvvv the rest is if no OCIO exported config file is found - -include (FindPackageHandleStandardArgs) -include (FindPackageMessage) - -find_path (OPENCOLORIO_INCLUDE_DIR - OpenColorIO/OpenColorIO.h - HINTS - ${OPENCOLORIO_INCLUDE_PATH} - ENV OPENCOLORIO_INCLUDE_PATH - PATHS - /sw/include - /opt/local/include - DOC "The directory where OpenColorIO/OpenColorIO.h resides") - -if (EXISTS "${OPENCOLORIO_INCLUDE_DIR}/OpenColorIO/OpenColorABI.h") - # Search twice, because this symbol changed between OCIO 1.x and 2.x - file(STRINGS "${OPENCOLORIO_INCLUDE_DIR}/OpenColorIO/OpenColorABI.h" TMP - REGEX "^#define OCIO_VERSION_STR[ \t].*$") - if (NOT TMP) - file(STRINGS "${OPENCOLORIO_INCLUDE_DIR}/OpenColorIO/OpenColorABI.h" TMP - REGEX "^#define OCIO_VERSION[ \t].*$") - endif () - string (REGEX MATCHALL "([0-9]+)\\.([0-9]+)\\.[0-9]+" OPENCOLORIO_VERSION ${TMP}) - set (OPENCOLORIO_VERSION_MAJOR ${CMAKE_MATCH_1}) - set (OPENCOLORIO_VERSION_MINOR ${CMAKE_MATCH_2}) -endif () - -find_library (OPENCOLORIO_LIBRARY - NAMES - OpenColorIO - OpenColorIO_${OPENCOLORIO_VERSION_MAJOR}_${OPENCOLORIO_VERSION_MINOR} - HINTS - ${OPENCOLORIO_LIBRARY_PATH} - ENV OPENCOLORIO_LIBRARY_PATH - PATHS - /usr/lib64 - /usr/local/lib64 - /sw/lib - /opt/local/lib - DOC "The OCIO library") - -find_package_handle_standard_args (OpenColorIO - REQUIRED_VARS OPENCOLORIO_INCLUDE_DIR OPENCOLORIO_LIBRARY - FOUND_VAR OpenColorIO_FOUND - VERSION_VAR OPENCOLORIO_VERSION - ) - -if (OpenColorIO_FOUND) - set (OpenColorIO_VERSION ${OPENCOLORIO_VERSION}) - set (OPENCOLORIO_INCLUDES ${OPENCOLORIO_INCLUDE_DIR}) - set (OPENCOLORIO_LIBRARIES ${OPENCOLORIO_LIBRARY}) - set (OPENCOLORIO_DEFINITIONS "") - if (NOT TARGET OpenColorIO::OpenColorIO) - add_library(OpenColorIO::OpenColorIO UNKNOWN IMPORTED) - set_target_properties(OpenColorIO::OpenColorIO PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${OPENCOLORIO_INCLUDES}") - - set_property(TARGET OpenColorIO::OpenColorIO APPEND PROPERTY - IMPORTED_LOCATION "${OPENCOLORIO_LIBRARIES}") - if (OPENCOLORIO_INTERFACE_LINK_LIBRARIES) - set_target_properties(OpenColorIO::OpenColorIO PROPERTIES - INTERFACE_LINK_LIBRARIES "${OPENCOLORIO_INTERFACE_LINK_LIBRARIES}") - endif () - if (LINKSTATIC) - target_compile_definitions(OpenColorIO::OpenColorIO - INTERFACE "-DOpenColorIO_STATIC") - endif() - endif () - if (NOT TARGET OpenColorIO::OpenColorIOHeaders) - add_library(OpenColorIO::OpenColorIOHeaders INTERFACE IMPORTED) - set_target_properties(OpenColorIO::OpenColorIOHeaders PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${OPENCOLORIO_INCLUDES}") - endif () -endif () - -if (OpenColorIO_FOUND AND LINKSTATIC) - # Is this necessary? - set (OPENCOLORIO_DEFINITIONS "OpenColorIO_STATIC") - find_library (TINYXML_LIBRARY NAMES tinyxml) - if (TINYXML_LIBRARY) - set (OPENCOLORIO_LIBRARIES "${OPENCOLORIO_LIBRARIES};${TINYXML_LIBRARY}" CACHE STRING "" FORCE) - endif () - find_library (YAML_LIBRARY NAMES yaml-cpp) - if (YAML_LIBRARY) - set (OPENCOLORIO_LIBRARIES "${OPENCOLORIO_LIBRARIES};${YAML_LIBRARY}" CACHE STRING "" FORCE) - endif () - find_library (LCMS2_LIBRARY NAMES lcms2) - if (LCMS2_LIBRARY) - set (OPENCOLORIO_LIBRARIES "${OPENCOLORIO_LIBRARIES};${LCMS2_LIBRARY}" CACHE STRING "" FORCE) - endif () -endif () - -endif() diff --git a/src/cmake/testing.cmake b/src/cmake/testing.cmake index 49ffa8af09..cf348a3cee 100644 --- a/src/cmake/testing.cmake +++ b/src/cmake/testing.cmake @@ -69,17 +69,9 @@ macro (oiio_add_tests) set (_test_disabled 1) endif () endforeach () - if (OpenColorIO_VERSION VERSION_GREATER_EQUAL 2.2 - AND NOT (OIIO_DISABLE_BUILTIN_OCIO_CONFIGS OR "$ENV{OIIO_DISABLE_BUILTIN_OCIO_CONFIGS}")) - # For OCIO 2.2+, have the testsuite use the default built-in config - list (APPEND _ats_ENVIRONMENT "OCIO=ocio://default" - "OIIO_TESTSUITE_OCIOCONFIG=ocio://default") - else () - # For OCIO 2.1 and earlier, have the testsuite use one we have in - # the testsuite directory. - list (APPEND _ats_ENVIRONMENT "OCIO=../common/OpenColorIO/nuke-default/config.ocio" - "OIIO_TESTSUITE_OCIOCONFIG=../common/OpenColorIO/nuke-default/config.ocio") - endif () + # For OCIO 2.2+, have the testsuite use the default built-in config + list (APPEND _ats_ENVIRONMENT "OCIO=ocio://default" + "OIIO_TESTSUITE_OCIOCONFIG=ocio://default") if (_test_disabled) message (STATUS "Skipping test(s) ${_ats_UNPARSED_ARGUMENTS} because of disabled ${_ats_ENABLEVAR}") elseif (_ats_IMAGEDIR AND NOT EXISTS ${_ats_testdir}) diff --git a/src/iv/imageviewer.cpp b/src/iv/imageviewer.cpp index 8aa7aac13e..a22c5eae81 100644 --- a/src/iv/imageviewer.cpp +++ b/src/iv/imageviewer.cpp @@ -111,12 +111,10 @@ ImageViewer::ImageViewer(bool use_ocio, const std::string& image_color_space, , m_fullscreen(false) , m_default_gamma(1) , m_darkPalette(false) -#ifdef HAS_OCIO_2 , m_useOCIO(use_ocio) , m_ocioColourSpace(image_color_space) , m_ocioDisplay(display) , m_ocioView(view) -#endif // HAS_OCIO_2 { readSettings(false); @@ -139,11 +137,7 @@ ImageViewer::ImageViewer(bool use_ocio, const std::string& image_color_space, slideDuration_ms = 5000; slide_loop = true; -#ifdef HAS_OCIO_2 glwin = new IvGL_OCIO(this, *this); -#else - glwin = new IvGL(this, *this); -#endif glwin->setPalette(m_palette); glwin->resize(m_default_width, m_default_height); @@ -462,7 +456,7 @@ ImageViewer::createActions() SLOT(setSlideShowDuration(int))); } -#ifdef HAS_OCIO_2 + void ImageViewer::createOCIOMenus(QMenu* parent) @@ -606,7 +600,6 @@ ImageViewer::ocioDisplayViewAction() } } -#endif // HAS_OCIO_2 void ImageViewer::createMenus() @@ -694,9 +687,7 @@ ImageViewer::createMenus() viewMenu->addMenu(channelMenu); viewMenu->addMenu(colormodeMenu); -#ifdef HAS_OCIO_2 createOCIOMenus(viewMenu); -#endif viewMenu->addMenu(expgamMenu); menuBar()->addMenu(viewMenu); @@ -1046,14 +1037,8 @@ void ImageViewer::moveToNewWindow() { if (m_images.size()) { -#ifdef HAS_OCIO_2 ImageViewer* imageViewer = new ImageViewer(m_useOCIO, m_ocioColourSpace, m_ocioDisplay, m_ocioView); -#else - std::string dummy; - ImageViewer* imageViewer = new ImageViewer(false, dummy, dummy, dummy); -#endif - imageViewer->show(); imageViewer->rawcolor(rawcolor()); imageViewer->add_image(m_images[m_current_image]->name()); diff --git a/src/iv/imageviewer.h b/src/iv/imageviewer.h index d7dc8ef1d1..f1c0622547 100644 --- a/src/iv/imageviewer.h +++ b/src/iv/imageviewer.h @@ -244,12 +244,10 @@ class ImageViewer final : public QMainWindow { void rawcolor(bool val) { m_rawcolor = val; } bool rawcolor() const { return m_rawcolor; } -#ifdef HAS_OCIO_2 bool useOCIO() { return m_useOCIO; } const std::string& ocioColorSpace() { return m_ocioColourSpace; } const std::string& ocioDisplay() { return m_ocioDisplay; } const std::string& ocioView() { return m_ocioView; } -#endif // HAS_OCIO_2 private slots: void open(); ///< Dialog to open new image from file @@ -310,11 +308,9 @@ private slots: void showPixelviewWindow(); ///< View closeup pixel view void editPreferences(); ///< Edit viewer preferences -#ifdef HAS_OCIO_2 void useOCIOAction(bool checked); void ocioColorSpaceAction(); void ocioDisplayViewAction(); -#endif // HAS_OCIO_2 private: void createActions(); @@ -427,7 +423,6 @@ private slots: friend class IvPreferenceWindow; friend bool image_progress_callback(void* opaque, float done); -#ifdef HAS_OCIO_2 friend class IvGL_OCIO; void createOCIOMenus(QMenu* parent); @@ -444,7 +439,6 @@ private slots: std::string m_ocioColourSpace; std::string m_ocioDisplay; std::string m_ocioView; -#endif // HAS_OCIO_2 }; diff --git a/src/iv/ivgl_ocio.cpp b/src/iv/ivgl_ocio.cpp index d85439573c..0997fb6e4c 100644 --- a/src/iv/ivgl_ocio.cpp +++ b/src/iv/ivgl_ocio.cpp @@ -7,7 +7,6 @@ #include -#ifdef HAS_OCIO_2 IvGL_OCIO::IvGL_OCIO(QWidget* parent, ImageViewer& viewer) : IvGL(parent, viewer) @@ -360,15 +359,15 @@ IvGL_OCIO::allocate_all_textures(unsigned start_index) unsigned height = 0; GpuShaderDesc::TextureType channel = GpuShaderDesc::TEXTURE_RGB_CHANNEL; Interpolation interpolation = INTERP_LINEAR; -# ifdef HAS_OCIO_2_3 +#if OCIO_VERSION_HEX >= MAKE_OCIO_VERSION_HEX(2, 3, 0) GpuShaderCreator::TextureDimensions dimensions = GpuShaderCreator::TextureDimensions::TEXTURE_2D; m_shader_desc->getTexture(idx, textureName, samplerName, width, height, channel, dimensions, interpolation); -# else +#else m_shader_desc->getTexture(idx, textureName, samplerName, width, height, channel, interpolation); -# endif +#endif if (!textureName || !*textureName || !samplerName || !*samplerName || width == 0) { @@ -407,6 +406,5 @@ IvGL_OCIO::use_all_textures() } } -#endif // HAS_OCIO_2 //OIIO_PRAGMA_WARNING_POP diff --git a/src/iv/ivgl_ocio.h b/src/iv/ivgl_ocio.h index 38468b9b6a..ca4639c2b7 100644 --- a/src/iv/ivgl_ocio.h +++ b/src/iv/ivgl_ocio.h @@ -6,23 +6,14 @@ #ifndef OPENIMAGEIO_IVGL_OCIO_H #define OPENIMAGEIO_IVGL_OCIO_H -#ifdef USE_OCIO -# include -# if OCIO_VERSION_MAJOR >= 2 -# define HAS_OCIO_2 -# if OCIO_VERSION_MAJOR == 2 -# if OCIO_VERSION_MINOR >= 3 -# define HAS_OCIO_2_3 -# endif -# endif -# endif -#endif - -#ifdef HAS_OCIO_2 -# include "ivgl.h" - -# include -# include +#include + +#define MAKE_OCIO_VERSION_HEX(maj, min, patch) \ + (((maj) << 24) | ((min) << 16) | (patch)) + +#include "ivgl.h" + +#include using namespace OIIO; @@ -104,5 +95,4 @@ class IvGL_OCIO : public IvGL { Interpolation interpolation); }; -#endif // HAS_OCIO_2 #endif // OPENIMAGEIO_IVGL_OCIO_H diff --git a/src/iv/ivmain.cpp b/src/iv/ivmain.cpp index 0b17831aa3..a9c1181f55 100644 --- a/src/iv/ivmain.cpp +++ b/src/iv/ivmain.cpp @@ -58,7 +58,6 @@ getargs(int argc, char* argv[]) ap.arg("--rawcolor") .help("Do not automatically transform to RGB"); -#ifdef HAS_OCIO_2 ap.arg("--display") .help("OCIO display") .metavar("STRING") @@ -74,7 +73,6 @@ getargs(int argc, char* argv[]) .metavar("STRING") .defaultval("") .action(ArgParse::store()); -#endif ap.parse(argc, (const char**)argv); return ap; @@ -110,28 +108,18 @@ main(int argc, char* argv[]) // Q_INIT_RESOURCE(iv); QApplication app(argc, argv); -#ifdef HAS_OCIO_2 std::string color_space = ap["image-color-space"].as_string(""); std::string display = ap["display"].as_string(""); std::string view = ap["view"].as_string(""); // std::string look = ap["look"].as_string(""); bool use_ocio = color_space != "" && display != "" && view != ""; - -#ifdef OCIO_HAS_BUILTIN_CONFIGS std::string ocioenv = Sysutil::getenv("OCIO"); - if (ocioenv.empty() || !Filesystem::exists(ocioenv)) { + if (ocioenv.empty() || !Filesystem::exists(ocioenv)) setenv("OCIO", "ocio://default", 1); - } -#endif ImageViewer* mainWin = new ImageViewer(use_ocio, color_space, display, view); -#else - std::string dummy; - ImageViewer* mainWin = new ImageViewer(false, dummy, dummy, dummy); -#endif - mainWin->show(); diff --git a/src/libOpenImageIO/CMakeLists.txt b/src/libOpenImageIO/CMakeLists.txt index 7a76509f5b..fc3ab80512 100644 --- a/src/libOpenImageIO/CMakeLists.txt +++ b/src/libOpenImageIO/CMakeLists.txt @@ -137,7 +137,6 @@ target_include_directories (OpenImageIO ${OPENEXR_INCLUDES} PRIVATE ${ROBINMAP_INCLUDES} - ${OPENIMAGEIO_OPENCOLORIO_INCLUDES} ) target_include_directories (OpenImageIO SYSTEM PUBLIC ${OpenCV_INCLUDES}) @@ -158,7 +157,7 @@ target_link_libraries (OpenImageIO ${OPENIMAGEIO_OPENEXR_TARGETS} ${OpenCV_LIBRARIES} ${format_plugin_libs} # Add all the target link libraries from the plugins - $ + OpenColorIO::OpenColorIO $ $ $ diff --git a/src/libOpenImageIO/color_ocio.cpp b/src/libOpenImageIO/color_ocio.cpp index 38e8d39525..dd48db4985 100644 --- a/src/libOpenImageIO/color_ocio.cpp +++ b/src/libOpenImageIO/color_ocio.cpp @@ -24,19 +24,13 @@ #define MAKE_OCIO_VERSION_HEX(maj, min, patch) \ (((maj) << 24) | ((min) << 16) | (patch)) -#ifdef USE_OCIO -# include -# if OCIO_VERSION_HEX >= MAKE_OCIO_VERSION_HEX(2, 0, 0) -# define OCIO_v2 1 -# endif -# if OCIO_VERSION_HEX >= MAKE_OCIO_VERSION_HEX(2, 2, 0) \ - && !defined(OIIO_DISABLE_BUILTIN_OCIO_CONFIGS) -# define OCIO_HAS_BUILTIN_CONFIGS 1 -# endif -namespace OCIO = OCIO_NAMESPACE; -#else -# define OCIO_VERSION_HEX 0 +#include + +#define OCIO_v2 1 +#ifndef OIIO_DISABLE_BUILTIN_OCIO_CONFIGS +# define OCIO_HAS_BUILTIN_CONFIGS 1 #endif +namespace OCIO = OCIO_NAMESPACE; OIIO_NAMESPACE_BEGIN @@ -63,9 +57,7 @@ static bool colordebug = Strutil::stoi(Sysutil::getenv("OIIO_DEBUG_COLOR")) static int disable_ocio = Strutil::stoi(Sysutil::getenv("OIIO_DISABLE_OCIO")); static int disable_builtin_configs = Strutil::stoi( Sysutil::getenv("OIIO_DISABLE_BUILTIN_OCIO_CONFIGS")); -#ifdef USE_OCIO static OCIO::ConstConfigRcPtr ocio_current_config; -#endif @@ -151,11 +143,7 @@ typedef tsl::robin_map