[Pkg-phototools-commits] [SCM] openimageio branch, upstream, updated. upstream/1.1.3+dfsg0-2-g46e86ea
Matteo F. Vescovi
mfv.debian at gmail.com
Thu Jan 31 16:40:06 UTC 2013
The following commit has been merged in the upstream branch:
commit 3e146639f85b6bb0dec60a93e16c9d9e2a2147db
Author: Matteo F. Vescovi <mfv.debian at gmail.com>
Date: Thu Jan 31 17:22:21 2013 +0100
Imported Upstream version 1.1.4+dfsg0
diff --git a/CHANGES b/CHANGES
index b93fae4..0a0ee2b 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,30 @@
Changes:
+Release 1.1.4 (27 Jan 2013)
+---------------------------
+* ImageBufAlgo::make_texture() allows you to do the same thing that
+ maketx does, but from inside an application and without launching a
+ shell invocation of maketx.
+* oiiotool now recognizes --metamatch and --nometamatch arguments which
+ cause metadata names matching (or only info NOT matching) the given
+ regular expression to be printed with --info.
+* oiiotool --zover does z (depth) composites (it's like a regular "over",
+ but uses the z depth at each pixel to determine which of the two images
+ is the foreground and which is the background).
+* ImageBufAlgo::fixNonFinite didn't work properly with 'half' image buffers.
+* Performance improvements when reading and writing images.
+* Fix error when writing tiled 'float' TIFF images, corrupted output.
+ (Could easily happen when using 'maketx' to convert float images into
+ TIFF textures.)
+* Eliminate warnings when compiling with Clang 3.2.
+* New CMake variable "USE_EXTERNAL_TBB" can optionally be set to force use
+ of an external TBB library rather than the embedded one.
+* Additional testsuite tests (doesn't affect users, but makes bugs easier
+ to catch).
+* Fix build problem with SHA1.cpp on some platforms.
+
+
Release 1.1.3 (9 Jan 2013)
---------------------------
* Build fix: incorrectly named OpenEXR 2.x files.
diff --git a/site/spi/Makefile-bits-arnold b/site/spi/Makefile-bits-arnold
index 6423ec9..57bd057 100644
--- a/site/spi/Makefile-bits-arnold
+++ b/site/spi/Makefile-bits-arnold
@@ -19,7 +19,7 @@ endif
## Spinux (current)
ifeq ($(SP_ARCH), spinux1_x86_64)
platform=spinux1
- COMPILER=gcc44m64
+ SPCOMP2_COMPILER=gcc44m64
INSTALL_SPCOMP2_LOCATION = /shots/spi/home/lib/SpComp2
# At SPI, we have two "flavors" of spinux. One is based on Foresight, which
# uses a special libGL (below). The other is based on Fedora which uses
@@ -27,11 +27,34 @@ ifeq ($(SP_ARCH), spinux1_x86_64)
SPINUX_GL_LIB = /usr/lib64/xorg.nvidia.3d/libGL.so
MY_CMAKE_FLAGS += $(if $(wildcard ${SPINUX_GL_LIB}), -DOPENGL_gl_LIBRARY=${SPINUX_GL_LIB})
ifeq (${OCIO_PATH},)
- OCIO_PATH="${INSTALL_SPCOMP2_LOCATION}/OpenColorIO/${platform}-${COMPILER}/v2"
+ OCIO_PATH="${INSTALL_SPCOMP2_LOCATION}/OpenColorIO/${platform}-${SPCOMP2_COMPILER}/v2"
endif
ifeq (${FIELD3D_HOME},)
- FIELD3D_HOME="${INSTALL_SPCOMP2_LOCATION}/Field3D/${platform}-${COMPILER}/v227"
+ FIELD3D_HOME="${INSTALL_SPCOMP2_LOCATION}/Field3D/${platform}-${SPCOMP2_COMPILER}/v227"
endif
+
+ ## custom compiler: clang
+ ifeq (${LLVM_DIRECTORY},)
+ LLVM_DIRECTORY := /shots/spi/home/lib/arnold/spinux1/llvm_3.2
+ endif
+ ifeq (${COMPILER}, clang)
+ MY_CMAKE_FLAGS += \
+ -DCMAKE_C_COMPILER=${LLVM_DIRECTORY}/bin/clang \
+ -DCMAKE_CXX_COMPILER=${LLVM_DIRECTORY}/bin/clang++
+ endif
+
+ ifeq (${COMPILER}, gcc463)
+ MY_CMAKE_FLAGS += \
+ -DCMAKE_C_COMPILER=/net/soft_scratch/apps/arnold/tools/gcc-4.6.3-test/bin/gcc \
+ -DCMAKE_CXX_COMPILER=/net/soft_scratch/apps/arnold/tools/gcc-4.6.3-test/bin/g++
+ endif
+ ifeq (${COMPILER}, gcc470)
+ MY_CMAKE_FLAGS += \
+ -DCMAKE_C_COMPILER=/net/soft_scratch/apps/arnold/tools/gcc-4.7.0-test/bin/gcc \
+ -DCMAKE_CXX_COMPILER=/net/soft_scratch/apps/arnold/tools/gcc-4.7.0-test/bin/g++
+ endif
+
+
MY_CMAKE_FLAGS += \
-DILMBASE_CUSTOM=1 \
-DILMBASE_CUSTOM_LIBRARIES="SpiImath SpiHalf SpiIlmThread SpiIex" \
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 46a85cd..d0b2849 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -3,7 +3,7 @@ project (OpenImageIO)
# Release version of the library
set (OIIO_VERSION_MAJOR 1)
set (OIIO_VERSION_MINOR 1)
-set (OIIO_VERSION_PATCH 3)
+set (OIIO_VERSION_PATCH 4)
cmake_minimum_required (VERSION 2.6)
if (NOT CMAKE_VERSION VERSION_LESS 2.8.4)
@@ -83,6 +83,8 @@ set (NOTHREADS OFF CACHE BOOL "Compile with no threads or locking")
set (PYTHON_VERSION 2.6)
set (USE_EXTERNAL_PUGIXML OFF CACHE BOOL
"Use an externally built shared library version of the pugixml library")
+set (USE_EXTERNAL_TBB OFF CACHE BOOL
+ "Use system TBB library instead of bundled.")
set (SOVERSION ${OIIO_VERSION_MAJOR}.${OIIO_VERSION_MINOR}
CACHE STRING "Set the SO version in the SO name of the output library")
@@ -311,10 +313,11 @@ if (DEFINED CMAKE_VERSION AND NOT CMAKE_VERSION VERSION_LESS 2.8)
endif()
# List all the individual testsuite tests here:
-oiio_add_tests (ico gpsread misnamed-file nonwhole-tiles
+oiio_add_tests (gpsread misnamed-file nonwhole-tiles
oiiotool oiiotool-composite oiiotool-fixnan
perchannel
- sgi rla psd dpx png
+ dpx ico png psd rla sgi
+ maketx
texture-blurtube texture-fill texture-filtersize
texture-gray texture-grid
texture-missing texture-overscan
@@ -333,6 +336,8 @@ oiio_add_tests (tiff-suite tiff-depths
IMAGEDIR libtiffpic
URL http://www.remotesensing.org/libtiff/images.html)
+oiio_add_tests (tiff-misc)
+
oiio_add_tests (openexr-suite openexr-multires openexr-chroma openexr-v2
IMAGEDIR openexr-images
URL http://www.openexr.com/downloads.html)
diff --git a/src/cmake/modules/FindTBB.cmake b/src/cmake/modules/FindTBB.cmake
new file mode 100644
index 0000000..f9e3e0f
--- /dev/null
+++ b/src/cmake/modules/FindTBB.cmake
@@ -0,0 +1,283 @@
+# Locate Intel Threading Building Blocks include paths and libraries
+# FindTBB.cmake can be found at https://code.google.com/p/findtbb/
+# Written by Hannes Hofmann <hannes.hofmann _at_ informatik.uni-erlangen.de>
+# Improvements by Gino van den Bergen <gino _at_ dtecta.com>,
+# Florian Uhlig <F.Uhlig _at_ gsi.de>,
+# Jiri Marsik <jiri.marsik89 _at_ gmail.com>
+
+# The MIT License
+#
+# Copyright (c) 2011 Hannes Hofmann
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+# GvdB: This module uses the environment variable TBB_ARCH_PLATFORM which defines architecture and compiler.
+# e.g. "ia32/vc8" or "em64t/cc4.1.0_libc2.4_kernel2.6.16.21"
+# TBB_ARCH_PLATFORM is set by the build script tbbvars[.bat|.sh|.csh], which can be found
+# in the TBB installation directory (TBB_INSTALL_DIR).
+#
+# GvdB: Mac OS X distribution places libraries directly in lib directory.
+#
+# For backwards compatibility, you may explicitely set the CMake variables TBB_ARCHITECTURE and TBB_COMPILER.
+# TBB_ARCHITECTURE [ ia32 | em64t | itanium ]
+# which architecture to use
+# TBB_COMPILER e.g. vc9 or cc3.2.3_libc2.3.2_kernel2.4.21 or cc4.0.1_os10.4.9
+# which compiler to use (detected automatically on Windows)
+
+# This module respects
+# TBB_INSTALL_DIR or $ENV{TBB21_INSTALL_DIR} or $ENV{TBB_INSTALL_DIR}
+
+# This module defines
+# TBB_INCLUDE_DIRS, where to find task_scheduler_init.h, etc.
+# TBB_LIBRARY_DIRS, where to find libtbb, libtbbmalloc
+# TBB_DEBUG_LIBRARY_DIRS, where to find libtbb_debug, libtbbmalloc_debug
+# TBB_INSTALL_DIR, the base TBB install directory
+# TBB_LIBRARIES, the libraries to link against to use TBB.
+# TBB_DEBUG_LIBRARIES, the libraries to link against to use TBB with debug symbols.
+# TBB_FOUND, If false, don't try to use TBB.
+# TBB_INTERFACE_VERSION, as defined in tbb/tbb_stddef.h
+
+
+if (WIN32)
+ # has em64t/vc8 em64t/vc9
+ # has ia32/vc7.1 ia32/vc8 ia32/vc9
+ set(_TBB_DEFAULT_INSTALL_DIR "C:/Program Files/Intel/TBB" "C:/Program Files (x86)/Intel/TBB")
+ set(_TBB_LIB_NAME "tbb")
+ set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc")
+ set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug")
+ set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug")
+ if (MSVC71)
+ set (_TBB_COMPILER "vc7.1")
+ endif(MSVC71)
+ if (MSVC80)
+ set(_TBB_COMPILER "vc8")
+ endif(MSVC80)
+ if (MSVC90)
+ set(_TBB_COMPILER "vc9")
+ endif(MSVC90)
+ if(MSVC10)
+ set(_TBB_COMPILER "vc10")
+ endif(MSVC10)
+ # Todo: add other Windows compilers such as ICL.
+ set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE})
+endif (WIN32)
+
+if (UNIX)
+ if (APPLE)
+ # MAC
+ set(_TBB_DEFAULT_INSTALL_DIR "/Library/Frameworks/Intel_TBB.framework/Versions")
+ # libs: libtbb.dylib, libtbbmalloc.dylib, *_debug
+ set(_TBB_LIB_NAME "tbb")
+ set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc")
+ set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug")
+ set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug")
+ # default flavor on apple: ia32/cc4.0.1_os10.4.9
+ # Jiri: There is no reason to presume there is only one flavor and
+ # that user's setting of variables should be ignored.
+ if(NOT TBB_COMPILER)
+ set(_TBB_COMPILER "cc4.0.1_os10.4.9")
+ elseif (NOT TBB_COMPILER)
+ set(_TBB_COMPILER ${TBB_COMPILER})
+ endif(NOT TBB_COMPILER)
+ if(NOT TBB_ARCHITECTURE)
+ set(_TBB_ARCHITECTURE "ia32")
+ elseif(NOT TBB_ARCHITECTURE)
+ set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE})
+ endif(NOT TBB_ARCHITECTURE)
+ else (APPLE)
+ # LINUX
+ set(_TBB_DEFAULT_INSTALL_DIR "/opt/intel/tbb" "/usr/local/include" "/usr/include")
+ set(_TBB_LIB_NAME "tbb")
+ set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc")
+ set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug")
+ set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug")
+ # has em64t/cc3.2.3_libc2.3.2_kernel2.4.21 em64t/cc3.3.3_libc2.3.3_kernel2.6.5 em64t/cc3.4.3_libc2.3.4_kernel2.6.9 em64t/cc4.1.0_libc2.4_kernel2.6.16.21
+ # has ia32/*
+ # has itanium/*
+ set(_TBB_COMPILER ${TBB_COMPILER})
+ set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE})
+ endif (APPLE)
+endif (UNIX)
+
+if (CMAKE_SYSTEM MATCHES "SunOS.*")
+# SUN
+# not yet supported
+# has em64t/cc3.4.3_kernel5.10
+# has ia32/*
+endif (CMAKE_SYSTEM MATCHES "SunOS.*")
+
+
+#-- Clear the public variables
+set (TBB_FOUND "NO")
+
+
+#-- Find TBB install dir and set ${_TBB_INSTALL_DIR} and cached ${TBB_INSTALL_DIR}
+# first: use CMake variable TBB_INSTALL_DIR
+if (TBB_INSTALL_DIR)
+ set (_TBB_INSTALL_DIR ${TBB_INSTALL_DIR})
+endif (TBB_INSTALL_DIR)
+# second: use environment variable
+if (NOT _TBB_INSTALL_DIR)
+ if (NOT "$ENV{TBB_INSTALL_DIR}" STREQUAL "")
+ set (_TBB_INSTALL_DIR $ENV{TBB_INSTALL_DIR})
+ endif (NOT "$ENV{TBB_INSTALL_DIR}" STREQUAL "")
+ # Intel recommends setting TBB21_INSTALL_DIR
+ if (NOT "$ENV{TBB21_INSTALL_DIR}" STREQUAL "")
+ set (_TBB_INSTALL_DIR $ENV{TBB21_INSTALL_DIR})
+ endif (NOT "$ENV{TBB21_INSTALL_DIR}" STREQUAL "")
+ if (NOT "$ENV{TBB22_INSTALL_DIR}" STREQUAL "")
+ set (_TBB_INSTALL_DIR $ENV{TBB22_INSTALL_DIR})
+ endif (NOT "$ENV{TBB22_INSTALL_DIR}" STREQUAL "")
+ if (NOT "$ENV{TBB30_INSTALL_DIR}" STREQUAL "")
+ set (_TBB_INSTALL_DIR $ENV{TBB30_INSTALL_DIR})
+ endif (NOT "$ENV{TBB30_INSTALL_DIR}" STREQUAL "")
+endif (NOT _TBB_INSTALL_DIR)
+# third: try to find path automatically
+if (NOT _TBB_INSTALL_DIR)
+ if (_TBB_DEFAULT_INSTALL_DIR)
+ set (_TBB_INSTALL_DIR ${_TBB_DEFAULT_INSTALL_DIR})
+ endif (_TBB_DEFAULT_INSTALL_DIR)
+endif (NOT _TBB_INSTALL_DIR)
+# sanity check
+if (NOT _TBB_INSTALL_DIR)
+ message ("ERROR: Unable to find Intel TBB install directory. ${_TBB_INSTALL_DIR}")
+else (NOT _TBB_INSTALL_DIR)
+# finally: set the cached CMake variable TBB_INSTALL_DIR
+if (NOT TBB_INSTALL_DIR)
+ set (TBB_INSTALL_DIR ${_TBB_INSTALL_DIR} CACHE PATH "Intel TBB install directory")
+ mark_as_advanced(TBB_INSTALL_DIR)
+endif (NOT TBB_INSTALL_DIR)
+
+
+#-- A macro to rewrite the paths of the library. This is necessary, because
+# find_library() always found the em64t/vc9 version of the TBB libs
+macro(TBB_CORRECT_LIB_DIR var_name)
+# if (NOT "${_TBB_ARCHITECTURE}" STREQUAL "em64t")
+ string(REPLACE em64t "${_TBB_ARCHITECTURE}" ${var_name} ${${var_name}})
+# endif (NOT "${_TBB_ARCHITECTURE}" STREQUAL "em64t")
+ string(REPLACE ia32 "${_TBB_ARCHITECTURE}" ${var_name} ${${var_name}})
+ string(REPLACE vc7.1 "${_TBB_COMPILER}" ${var_name} ${${var_name}})
+ string(REPLACE vc8 "${_TBB_COMPILER}" ${var_name} ${${var_name}})
+ string(REPLACE vc9 "${_TBB_COMPILER}" ${var_name} ${${var_name}})
+ string(REPLACE vc10 "${_TBB_COMPILER}" ${var_name} ${${var_name}})
+endmacro(TBB_CORRECT_LIB_DIR var_content)
+
+
+#-- Look for include directory and set ${TBB_INCLUDE_DIR}
+set (TBB_INC_SEARCH_DIR ${_TBB_INSTALL_DIR}/include)
+# Jiri: tbbvars now sets the CPATH environment variable to the directory
+# containing the headers.
+find_path(TBB_INCLUDE_DIR
+ tbb/task_scheduler_init.h
+ PATHS ${TBB_INC_SEARCH_DIR} ENV CPATH
+)
+mark_as_advanced(TBB_INCLUDE_DIR)
+
+
+#-- Look for libraries
+# GvdB: $ENV{TBB_ARCH_PLATFORM} is set by the build script tbbvars[.bat|.sh|.csh]
+if (NOT $ENV{TBB_ARCH_PLATFORM} STREQUAL "")
+ set (_TBB_LIBRARY_DIR
+ ${_TBB_INSTALL_DIR}/lib/$ENV{TBB_ARCH_PLATFORM}
+ ${_TBB_INSTALL_DIR}/$ENV{TBB_ARCH_PLATFORM}/lib
+ )
+endif (NOT $ENV{TBB_ARCH_PLATFORM} STREQUAL "")
+# Jiri: This block isn't mutually exclusive with the previous one
+# (hence no else), instead I test if the user really specified
+# the variables in question.
+if ((NOT ${TBB_ARCHITECTURE} STREQUAL "") AND (NOT ${TBB_COMPILER} STREQUAL ""))
+ # HH: deprecated
+ message(STATUS "[Warning] FindTBB.cmake: The use of TBB_ARCHITECTURE and TBB_COMPILER is deprecated and may not be supported in future versions. Please set \$ENV{TBB_ARCH_PLATFORM} (using tbbvars.[bat|csh|sh]).")
+ # Jiri: It doesn't hurt to look in more places, so I store the hints from
+ # ENV{TBB_ARCH_PLATFORM} and the TBB_ARCHITECTURE and TBB_COMPILER
+ # variables and search them both.
+ set (_TBB_LIBRARY_DIR "${_TBB_INSTALL_DIR}/${_TBB_ARCHITECTURE}/${_TBB_COMPILER}/lib" ${_TBB_LIBRARY_DIR})
+endif ((NOT ${TBB_ARCHITECTURE} STREQUAL "") AND (NOT ${TBB_COMPILER} STREQUAL ""))
+
+# GvdB: Mac OS X distribution places libraries directly in lib directory.
+list(APPEND _TBB_LIBRARY_DIR ${_TBB_INSTALL_DIR}/lib)
+
+# Jiri: No reason not to check the default paths. From recent versions,
+# tbbvars has started exporting the LIBRARY_PATH and LD_LIBRARY_PATH
+# variables, which now point to the directories of the lib files.
+# It all makes more sense to use the ${_TBB_LIBRARY_DIR} as a HINTS
+# argument instead of the implicit PATHS as it isn't hard-coded
+# but computed by system introspection. Searching the LIBRARY_PATH
+# and LD_LIBRARY_PATH environment variables is now even more important
+# that tbbvars doesn't export TBB_ARCH_PLATFORM and it facilitates
+# the use of TBB built from sources.
+find_library(TBB_LIBRARY ${_TBB_LIB_NAME} HINTS ${_TBB_LIBRARY_DIR}
+ PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH)
+find_library(TBB_MALLOC_LIBRARY ${_TBB_LIB_MALLOC_NAME} HINTS ${_TBB_LIBRARY_DIR}
+ PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH)
+
+#Extract path from TBB_LIBRARY name
+get_filename_component(TBB_LIBRARY_DIR ${TBB_LIBRARY} PATH)
+
+#TBB_CORRECT_LIB_DIR(TBB_LIBRARY)
+#TBB_CORRECT_LIB_DIR(TBB_MALLOC_LIBRARY)
+mark_as_advanced(TBB_LIBRARY TBB_MALLOC_LIBRARY)
+
+#-- Look for debug libraries
+# Jiri: Changed the same way as for the release libraries.
+find_library(TBB_LIBRARY_DEBUG ${_TBB_LIB_DEBUG_NAME} HINTS ${_TBB_LIBRARY_DIR}
+ PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH)
+find_library(TBB_MALLOC_LIBRARY_DEBUG ${_TBB_LIB_MALLOC_DEBUG_NAME} HINTS ${_TBB_LIBRARY_DIR}
+ PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH)
+
+# Jiri: Self-built TBB stores the debug libraries in a separate directory.
+# Extract path from TBB_LIBRARY_DEBUG name
+get_filename_component(TBB_LIBRARY_DEBUG_DIR ${TBB_LIBRARY_DEBUG} PATH)
+
+#TBB_CORRECT_LIB_DIR(TBB_LIBRARY_DEBUG)
+#TBB_CORRECT_LIB_DIR(TBB_MALLOC_LIBRARY_DEBUG)
+mark_as_advanced(TBB_LIBRARY_DEBUG TBB_MALLOC_LIBRARY_DEBUG)
+
+
+if (TBB_INCLUDE_DIR)
+ if (TBB_LIBRARY)
+ set (TBB_FOUND "YES")
+ set (TBB_LIBRARIES ${TBB_LIBRARY} ${TBB_MALLOC_LIBRARY} ${TBB_LIBRARIES})
+ set (TBB_DEBUG_LIBRARIES ${TBB_LIBRARY_DEBUG} ${TBB_MALLOC_LIBRARY_DEBUG} ${TBB_DEBUG_LIBRARIES})
+ set (TBB_INCLUDE_DIRS ${TBB_INCLUDE_DIR} CACHE PATH "TBB include directory" FORCE)
+ set (TBB_LIBRARY_DIRS ${TBB_LIBRARY_DIR} CACHE PATH "TBB library directory" FORCE)
+ # Jiri: Self-built TBB stores the debug libraries in a separate directory.
+ set (TBB_DEBUG_LIBRARY_DIRS ${TBB_LIBRARY_DEBUG_DIR} CACHE PATH "TBB debug library directory" FORCE)
+ mark_as_advanced(TBB_INCLUDE_DIRS TBB_LIBRARY_DIRS TBB_DEBUG_LIBRARY_DIRS TBB_LIBRARIES TBB_DEBUG_LIBRARIES)
+ message(STATUS "Found Intel TBB")
+ endif (TBB_LIBRARY)
+endif (TBB_INCLUDE_DIR)
+
+if (NOT TBB_FOUND)
+ message("ERROR: Intel TBB NOT found!")
+ message(STATUS "Looked for Threading Building Blocks in ${_TBB_INSTALL_DIR}")
+ # do only throw fatal, if this pkg is REQUIRED
+ if (TBB_FIND_REQUIRED)
+ message(FATAL_ERROR "Could NOT find TBB library.")
+ endif (TBB_FIND_REQUIRED)
+endif (NOT TBB_FOUND)
+
+endif (NOT _TBB_INSTALL_DIR)
+
+if (TBB_FOUND)
+ set(TBB_INTERFACE_VERSION 0)
+ FILE(READ "${TBB_INCLUDE_DIRS}/tbb/tbb_stddef.h" _TBB_VERSION_CONTENTS)
+ STRING(REGEX REPLACE ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" TBB_INTERFACE_VERSION "${_TBB_VERSION_CONTENTS}")
+ set(TBB_INTERFACE_VERSION "${TBB_INTERFACE_VERSION}")
+endif (TBB_FOUND)
diff --git a/src/doc/oiiotool.tex b/src/doc/oiiotool.tex
index a229a25..47c0826 100644
--- a/src/doc/oiiotool.tex
+++ b/src/doc/oiiotool.tex
@@ -285,6 +285,18 @@ If verbose mode is not turned on, only the resolution and data format
are printed.
\apiend
+\apiitem{--metamatch \emph{regex} \\
+--no-metamatch \emph{regex}}
+\NEW
+Regular expressions to restrict which metadata are output when using
+{\cf oiiotool --info -v}. The {\cf --metamatch} expression causes only
+metadata whose name matches to print; non-matches are not output. The
+{\cf --no-metamatch} expression causes metadata whose name matches to be
+suppressed; others (non-matches) are printed. It is not advised to use
+both of these options at the same time (probably nothing bad will
+happen, but it's hard to reason about the behavior in that case).
+\apiend
+
\apiitem{--stats}
Prints detailed statistical information about each input image as it is
read.
@@ -709,9 +721,24 @@ consisting of the \emph{absolute value} of he old pixel value.
\apiend
\apiitem{--over}
+\index{composite}
Replace the \emph{two} top images with a new image that is the
-Porter/Duff ``over'' composite of the first image over the second
-image.
+Porter/Duff ``over'' composite with the first image as the foreground
+and the second image as the background.
+Both input images must have the same number and order of channels
+and must contain an alpha channel.
+\apiend
+
+\apiitem{--zover}
+\index{depth composite}
+\NEW
+Replace the \emph{two} top images with a new image that is a \emph{depth
+composite} of the two images -- the operation is the
+Porter/Duff ``over'' composite, but each pixel individually will choose
+which of the two images is the foreground and which background, depending on
+the ``Z'' channel values for that pixel (larger Z means farther away).
+Both input images must have the same number and order of channels
+and must contain both depth/Z and alpha channels.
\apiend
\apiitem{--flip}
diff --git a/src/doc/openimageio.tex b/src/doc/openimageio.tex
index de854bf..dd0fae4 100644
--- a/src/doc/openimageio.tex
+++ b/src/doc/openimageio.tex
@@ -85,7 +85,7 @@
\date{{\large
%Editor: Larry Gritz \\[2ex]
Date: 18 Nov, 2012
-\\ (with corrections, 5 Jan 2013)
+\\ (with corrections, 25 Jan 2013)
}}
diff --git a/src/include/CMakeLists.txt b/src/include/CMakeLists.txt
index 4705673..6c6da5d 100644
--- a/src/include/CMakeLists.txt
+++ b/src/include/CMakeLists.txt
@@ -22,7 +22,7 @@ list(APPEND public_headers ${CMAKE_BINARY_DIR}/include/version.h)
install (FILES ${public_headers} DESTINATION ${INCLUDE_INSTALL_DIR}
COMPONENT developer)
-if (USE_TBB)
+if (USE_TBB AND NOT USE_EXTERNAL_TBB)
install (DIRECTORY tbb DESTINATION ${INCLUDE_INSTALL_DIR}
COMPONENT developer)
endif ()
diff --git a/src/include/imagebufalgo.h b/src/include/imagebufalgo.h
index 298d4a8..829c0aa 100644
--- a/src/include/imagebufalgo.h
+++ b/src/include/imagebufalgo.h
@@ -365,6 +365,14 @@ bool OIIO_API over (ImageBuf &R, const ImageBuf &A, const ImageBuf &B,
ROI roi = ROI(), int threads = 0);
+/// Just like ImageBufAlgo::over(), but inputs A and B must have
+/// designated 'z' channels, and on a pixel-by-pixel basis, the z values
+/// will determine which of A or B will be considered the foreground or
+/// background (lower z is foreground).
+bool OIIO_API zover (ImageBuf &R, const ImageBuf &A, const ImageBuf &B,
+ ROI roi = ROI(), int threads = 0);
+
+
/// Render a text string into image R, essentially doing an "over" of
/// the character into the existing pixel data. The baseline of the
/// first character will start at position (x,y). The font is given by
@@ -416,6 +424,123 @@ bool OIIO_API histogram_draw (ImageBuf &R,
+enum OIIO_API MakeTextureMode {
+ MakeTxTexture, MakeTxShadow, MakeTxEnvLatl, _MakeTxLast
+};
+
+/// Turn an image file (filename) into a tiled, MIP-mapped, texture file
+/// (outputfilename). The 'mode' describes what type of texture file we
+/// are creating. If the outstream pointer is not NULL, it should point
+/// to a stream (for example, &std::out, or a pointer to a local
+/// std::stringstream to capture output), which is where console output
+/// and error messages will be deposited.
+///
+/// The 'config' is an ImageSpec that contains all the information and
+/// special instructions for making the texture. Anything set in config
+/// (format, tile size, or named metadata) will take precedence over
+/// whatever is specified by the input file itself. Additionally, named
+/// metadata that starts with "maketx:" will not be output to the file
+/// itself, but may contain instructions controlling how the texture is
+/// created. The full list of supported configuration options is:
+///
+/// Named fields:
+/// format Data format of the texture file (default: UNKNOWN =
+/// same format as the input)
+/// tile_width Preferred tile size (default: 64x64x1)
+/// tile_height
+/// tile_depth
+/// Metadata in config.extra_attribs:
+/// compression (string) Default: "zip"
+/// fovcot (float) Default: aspect ratio of the image resolution
+/// planarconfig (string) Default: "separate"
+/// worldtocamera (matrix) World-to-camera matrix of the view.
+/// worldtoscreen (matrix) World-to-screen space matrix of the view.
+/// wrapmodes (string) Default: "black,black"
+/// maketx:verbose (int) How much detail should go to outstream (0).
+/// maketx:stats (int) If nonzero, print stats to outstream (0).
+/// maketx:resize (int) If nonzero, resize to power of 2. (0)
+/// maketx:nomipmap (int) If nonzero, only output the top MIP level (0).
+/// maketx:updatemode (int) If nonzero, write new output only if the
+/// output file doesn't already exist, or is
+/// older than the input file. (0)
+/// maketx:constant_color_detect (int)
+/// If nonzero, detect images that are entirely
+/// one color, and change them to be low
+/// resolution (default: 0).
+/// maketx:monochrome_detect (int)
+/// If nonzero, change RGB images which have
+/// R==G==B everywhere to single-channel
+/// grayscale (default: 0).
+/// maketx:opaquedetect (int)
+/// If nonzero, drop the alpha channel if alpha
+/// is 1.0 in all pixels (default: 0).
+/// maketx:unpremult (int) If nonzero, unpremultiply color by alpha before
+/// color conversion, then multiply by alpha
+/// after color conversion (default: 0).
+/// maketx:incolorspace (string)
+/// maketx:outcolorspace (string)
+/// These two together will apply a color conversion
+/// (with OpenColorIO, if compiled). Default: ""
+/// maketx:checknan (int) If nonzero, will consider it an error if the
+/// input image has any NaN pixels. (0)
+/// maketx:fixnan (string) If set to "black" or "box3", will attempt
+/// to repair any NaN pixels found in the
+/// input image (default: "none").
+/// maketx:set_full_to_pixels (int)
+/// If nonzero, doctors the full/display window
+/// of the texture to be identical to the
+/// pixel/data window and reset the origin
+/// to 0,0 (default: 0).
+/// maketx:filtername (string)
+/// If set, will specify the name of a high-quality
+/// filter to use when resampling for MIPmap levels.
+/// Default: "", use simple bilinear resampling.
+/// maketx:nchannels (int) If nonzero, will specify how many channels
+/// the output texture should have, padding with
+/// 0 values or dropping channels, if it doesn't
+/// the number of channels in the input.
+/// (default: 0, meaning keep all input channels)
+/// maketx:fileformatname (string)
+/// If set, will specify the output file format.
+/// (default: "", meaning infer the format from
+/// the output filename)
+/// maketx:prman_metadata (int)
+/// If set, output some metadata that PRMan will
+/// need for its textures. (0)
+/// maketx:oiio_options (int)
+/// (Deprecated; all are handled by default)
+/// maketx:prman_options (int)
+/// If nonzero, override a whole bunch of settings
+/// as needed to make textures that are
+/// compatible with PRMan. (0)
+/// maketx:mipimages (string)
+/// Semicolon-separated list of alternate images
+/// to be used for individual MIPmap levels,
+/// rather than simply downsizing. (default: "")
+/// maketx:full_command_line (string)
+/// The command or program used to generate this
+/// call, will be embedded in the metadata.
+/// (default: "")
+/// maketx:ignore_unassoc (int)
+/// If nonzero, will disbelieve any evidence that
+/// the input image is unassociated alpha. (0)
+///
+bool OIIO_API make_texture (MakeTextureMode mode,
+ const std::string &filename,
+ const std::string &outputfilename,
+ const ImageSpec &config,
+ std::ostream *outstream = NULL);
+
+/// Version of make_texture that takes multiple filenames (reserved for
+/// future expansion, such as assembling several faces into a cube map).
+bool OIIO_API make_texture (MakeTextureMode mode,
+ const std::vector<std::string> &filenames,
+ const std::string &outputfilename,
+ const ImageSpec &config,
+ std::ostream *outstream = NULL);
+
+
+
/// Helper template for generalized multithreading for image processing
/// functions. Some function/functor f is applied to every pixel the
/// region of interest roi, dividing the region into multiple threads if
@@ -431,7 +556,7 @@ bool OIIO_API histogram_draw (ImageBuf &R,
/// float scale, ROI roi);
/// Then you can parallelize it as follows:
/// ImageBuf R /*result*/, A /*input*/;
-/// ROI roi = get_roi (R);
+/// ROI roi = get_roi (R.spec());
/// parallel_image (boost::bind(my_image_op,boost::ref(R),
/// boost::cref(A),3.14,_1), roi);
///
diff --git a/src/include/imageio.h b/src/include/imageio.h
index 85858b8..58c6890 100644
--- a/src/include/imageio.h
+++ b/src/include/imageio.h
@@ -1191,8 +1191,14 @@ OIIO_API int quantize (float value, int quant_black, int quant_white,
/// conversion. If dst_type is UNKNWON, it will be assumed to be the
/// same as src_type.
OIIO_API bool convert_types (TypeDesc src_type, const void *src,
- TypeDesc dst_type, void *to, int n,
- int alpha_channel = -1, int z_channel = -1);
+ TypeDesc dst_type, void *dst, int n);
+
+/// DEPRECATED -- for some reason we had a convert_types that took
+/// alpha_channel and z_channel parameters, but never did anything
+/// with them.
+OIIO_API bool convert_types (TypeDesc src_type, const void *src,
+ TypeDesc dst_type, void *dst, int n,
+ int alpha_channel, int z_channel = -1);
/// Helper routine for data conversion: Convert an image of nchannels x
/// width x height x depth from src to dst. The src and dst may have
diff --git a/src/libOpenImageIO/CMakeLists.txt b/src/libOpenImageIO/CMakeLists.txt
index bd5dbe3..f18ee66 100644
--- a/src/libOpenImageIO/CMakeLists.txt
+++ b/src/libOpenImageIO/CMakeLists.txt
@@ -36,6 +36,7 @@ set (libOpenImageIO_srcs exif.cpp formatspec.cpp imagebuf.cpp
color_ocio.cpp
imagebufalgo.cpp imagebufalgo_orient.cpp
imagebufalgo_yee.cpp imagebufalgo_opencv.cpp
+ maketexture.cpp
../libutil/argparse.cpp
../libutil/errorhandler.cpp
../libutil/filesystem.cpp
@@ -62,7 +63,13 @@ if (NOT USE_EXTERNAL_PUGIXML)
endif ()
# Include our own TBB if using it
-if (USE_TBB)
+if (USE_TBB AND USE_EXTERNAL_TBB)
+ message (STATUS "System TBB library will be used.")
+ find_package (TBB REQUIRED)
+ include_directories (${TBB_INCLUDE_DIRS})
+ set (libOpenImageIO_srcs ${libOpenImageIO_srcs})
+elseif (USE_TBB AND NOT USE_EXTERNAL_TBB)
+ message (STATUS "Built-in TBB library will be used.")
set (libOpenImageIO_srcs ${libOpenImageIO_srcs} ../libutil/tbb_misc.cpp)
endif ()
@@ -202,7 +209,11 @@ target_link_libraries (OpenImageIO
${VISIBILITY_COMMAND} ${VISIBILITY_MAP_COMMAND}
${Boost_LIBRARIES})
-
+# Link against system TBB library if specified
+if (USE_TBB AND USE_EXTERNAL_TBB)
+ message (STATUS "Linking TBB: ${TBB_LIBRARIES}")
+ target_link_libraries (OpenImageIO ${TBB_LIBRARIES})
+endif ()
# Include OpenColorIO if using it
if (USE_OCIO AND OCIO_FOUND)
diff --git a/src/libOpenImageIO/imagebufalgo.cpp b/src/libOpenImageIO/imagebufalgo.cpp
index bd4af14..f4d598a 100644
--- a/src/libOpenImageIO/imagebufalgo.cpp
+++ b/src/libOpenImageIO/imagebufalgo.cpp
@@ -1103,6 +1103,10 @@ ImageBufAlgo::resize (ImageBuf &dst, const ImageBuf &src,
namespace
{
+// Make sure isfinite is defined for 'half'
+inline bool isfinite (half h) { return h.isFinite(); }
+
+
template<typename SRCTYPE>
bool fixNonFinite_ (ImageBuf &dst, const ImageBuf &src,
ImageBufAlgo::NonFiniteFixMode mode,
@@ -1123,7 +1127,7 @@ bool fixNonFinite_ (ImageBuf &dst, const ImageBuf &src,
if (! dst.copy (src))
return false;
- ImageBuf::Iterator<SRCTYPE> pixel (dst);
+ ImageBuf::Iterator<SRCTYPE,SRCTYPE> pixel (dst);
while (pixel.valid()) {
bool fixed = false;
for (int c = 0; c < nchannels; ++c) {
@@ -1159,7 +1163,7 @@ bool fixNonFinite_ (ImageBuf &dst, const ImageBuf &src,
if (! dst.copy (src))
return false;
- ImageBuf::Iterator<SRCTYPE> pixel (dst);
+ ImageBuf::Iterator<SRCTYPE,SRCTYPE> pixel (dst);
while (pixel.valid()) {
bool fixed = false;
@@ -1175,7 +1179,7 @@ bool fixNonFinite_ (ImageBuf &dst, const ImageBuf &src,
int left = pixel.y() - boxwidth;
int right = pixel.y() + boxwidth;
- ImageBuf::Iterator<SRCTYPE> it (dst, top, bottom, left, right);
+ ImageBuf::Iterator<SRCTYPE,SRCTYPE> it (dst, top, bottom, left, right);
while (it.valid()) {
SRCTYPE v = it[c];
if (isfinite (v)) {
@@ -1220,9 +1224,7 @@ ImageBufAlgo::fixNonFinite (ImageBuf &dst, const ImageBuf &src,
case TypeDesc::FLOAT :
return fixNonFinite_<float> (dst, src, mode, pixelsFixed);
case TypeDesc::HALF :
- // This use of float here is on purpose to allow for simpler
- // implementations that work on all data types
- return fixNonFinite_<float> (dst, src, mode, pixelsFixed);
+ return fixNonFinite_<half> (dst, src, mode, pixelsFixed);
case TypeDesc::DOUBLE:
return fixNonFinite_<double> (dst, src, mode, pixelsFixed);
default:
@@ -1241,10 +1243,43 @@ ImageBufAlgo::fixNonFinite (ImageBuf &dst, const ImageBuf &src,
namespace { // anonymous namespace
+static bool
+decode_over_channels (const ImageBuf &R, int &nchannels,
+ int &alpha, int &z, int &colors)
+{
+ if (! R.initialized()) {
+ alpha = -1;
+ z = -1;
+ colors = 0;
+ return false;
+ }
+ const ImageSpec &spec (R.spec());
+ alpha = spec.alpha_channel;
+ bool has_alpha = (alpha >= 0);
+ z = spec.z_channel;
+ bool has_z = (z >= 0);
+ nchannels = spec.nchannels;
+ colors = nchannels - has_alpha - has_z;
+ if (! has_alpha && colors == 4) {
+ // No marked alpha channel, but suspiciously 4 channel -- assume
+ // it's RGBA.
+ has_alpha = true;
+ colors -= 1;
+ // Assume alpha is the highest channel that's not z
+ alpha = nchannels - 1;
+ if (alpha == z)
+ --alpha;
+ }
+ return true;
+}
+
+
+
// Fully type-specialized version of over.
template<class Rtype, class Atype, class Btype>
-bool
-over_impl (ImageBuf &R, const ImageBuf &A, const ImageBuf &B, ROI roi)
+static bool
+over_impl (ImageBuf &R, const ImageBuf &A, const ImageBuf &B, ROI roi,
+ bool zcomp=false)
{
if (R.spec().format != BaseTypeFromC<Rtype>::value ||
A.spec().format != BaseTypeFromC<Atype>::value ||
@@ -1254,23 +1289,12 @@ over_impl (ImageBuf &R, const ImageBuf &A, const ImageBuf &B, ROI roi)
return false; // double check that types match
}
- // Output image R.
- const ImageSpec &specR = R.spec();
- int channels_R = specR.nchannels;
-
- // Input image A.
- const ImageSpec &specA = A.spec();
- int alpha_index_A = specA.alpha_channel;
- int has_alpha_A = (alpha_index_A >= 0);
- int channels_A = specA.nchannels;
-
- // Input image B.
- const ImageSpec &specB = B.spec();
- int alpha_index_B = specB.alpha_channel;
- int has_alpha_B = (alpha_index_B >= 0);
- int channels_B = specB.nchannels;
-
- int channels_AB = std::min (channels_A, channels_B);
+ // It's already guaranteed that R, A, and B have matching channel
+ // ordering, and have an alpha channel. So just decode one.
+ int nchannels = 0, alpha_channel = 0, z_channel = 0, ncolor_channels = 0;
+ decode_over_channels (R, nchannels, alpha_channel,
+ z_channel, ncolor_channels);
+ bool has_z = (z_channel >= 0);
ImageBuf::ConstIterator<Atype, float> a (A);
ImageBuf::ConstIterator<Btype, float> b (B);
@@ -1281,32 +1305,41 @@ over_impl (ImageBuf &R, const ImageBuf &A, const ImageBuf &B, ROI roi)
if (! a.valid()) {
if (! b.valid()) {
- // a and b invalid.
- for (int c = 0; c < channels_R; c++) { r[c] = 0.0f; }
+ // a and b are both invalid -- make it an "empty" pixel
+ for (int c = 0; c < nchannels; c++)
+ r[c] = 0.0f;
} else {
- // a invalid, b valid.
- for (int c = 0; c < channels_B; c++) { r[c] = b[c]; }
- if (! has_alpha_B) { r[3] = 1.0f; }
+ // a invalid, b valid -- copy B
+ for (int c = 0; c < nchannels; ++c)
+ r[c] = b[c];
}
continue;
}
if (! b.valid()) {
- // a valid, b invalid.
- for (int c = 0; c < channels_A; c++) { r[c] = a[c]; }
- if (! has_alpha_A) { r[3] = 1.0f; }
+ // a valid, b invalid -- copy A
+ for (int c = 0; c < nchannels; ++c)
+ r[c] = a[c];
continue;
}
// At this point, a and b are valid.
- float alpha_A = has_alpha_A
- ? clamp (a[alpha_index_A], 0.0f, 1.0f) : 1.0f;
- float one_minus_alpha_A = 1.0f - alpha_A;
- for (int c = 0; c < channels_AB; c++)
- r[c] = a[c] + one_minus_alpha_A * b[c];
- if (channels_R != channels_AB) {
- // R has 4 channels, A or B has 3 channels -> alpha channel is 3.
- r[3] = alpha_A + one_minus_alpha_A * (has_alpha_B ? b[3] : 1.0f);
+
+ if (!zcomp || a[z_channel] <= b[z_channel]) {
+ // A over B
+ float alpha = clamp (a[alpha_channel], 0.0f, 1.0f);
+ float one_minus_alpha = 1.0f - alpha;
+ for (int c = 0; c < nchannels; c++)
+ r[c] = a[c] + one_minus_alpha * b[c];
+ if (has_z)
+ r[z_channel] = (alpha != 0.0) ? a[z_channel] : b[z_channel];
+ } else {
+ // B over A -- because we're doing a Z composite
+ float alpha = clamp (b[alpha_channel], 0.0f, 1.0f);
+ float one_minus_alpha = 1.0f - alpha;
+ for (int c = 0; c < nchannels; c++)
+ r[c] = b[c] + one_minus_alpha * a[c];
+ r[z_channel] = (alpha != 0.0) ? b[z_channel] : a[z_channel];
}
}
return true;
@@ -1319,98 +1352,138 @@ bool
ImageBufAlgo::over (ImageBuf &R, const ImageBuf &A, const ImageBuf &B, ROI roi,
int nthreads)
{
- // Output image R.
const ImageSpec &specR = R.spec();
- int alpha_R = specR.alpha_channel;
- int has_alpha_R = (alpha_R >= 0);
- int channels_R = specR.nchannels;
- int non_alpha_R = channels_R - has_alpha_R;
- bool initialized_R = R.initialized();
-
- // Input image A.
const ImageSpec &specA = A.spec();
- int alpha_A = specA.alpha_channel;
- int has_alpha_A = (alpha_A >= 0);
- int channels_A = specA.nchannels;
- int non_alpha_A = has_alpha_A ? (channels_A - 1) : 3;
- bool A_not_34 = channels_A != 3 && channels_A != 4;
-
- // Input image B.
const ImageSpec &specB = B.spec();
- int alpha_B = specB.alpha_channel;
- int has_alpha_B = (alpha_B >= 0);
- int channels_B = specB.nchannels;
- int non_alpha_B = has_alpha_B ? (channels_B - 1) : 3;
- bool B_not_34 = channels_B != 3 && channels_B != 4;
+ int nchannels_R, nchannels_A, nchannels_B;
+ int alpha_R, alpha_A, alpha_B;
+ int z_R, z_A, z_B;
+ int colors_R, colors_A, colors_B;
+ bool initialized_R = decode_over_channels (R, nchannels_R, alpha_R,
+ z_R, colors_R);
+ bool initialized_A = decode_over_channels (A, nchannels_A, alpha_A,
+ z_A, colors_A);
+ bool initialized_B = decode_over_channels (B, nchannels_B, alpha_B,
+ z_B, colors_B);
+
+ if (! initialized_A || ! initialized_B) {
+ R.error ("Can't 'over' uninitialized images");
+ return false;
+ }
+
+ // Fail if the input images don't have an alpha channel.
+ if (alpha_A < 0 || alpha_B < 0 || (initialized_R && alpha_R < 0)) {
+ R.error ("'over' requires alpha channels");
+ return false;
+ }
+ // Fail for mismatched channel counts
+ if (colors_A != colors_B || colors_A < 1) {
+ R.error ("Can't 'over' images with mismatched color channel counts (%d vs %d)",
+ colors_A, colors_B);
+ return false;
+ }
+ // Fail for unaligned alpha or z channels
+ if (alpha_A != alpha_B || z_A != z_B ||
+ (initialized_R && alpha_R != alpha_A) ||
+ (initialized_R && z_R != z_A)) {
+ R.error ("Can't 'over' images with mismatched channel order",
+ colors_A, colors_B);
+ return false;
+ }
+
// At present, this operation only supports ImageBuf's containing
// float pixel data.
- if (R.spec().format != TypeDesc::TypeFloat ||
- A.spec().format != TypeDesc::TypeFloat ||
- B.spec().format != TypeDesc::TypeFloat) {
- R.error ("Unsupported pixel data format combination '%s / %s / %s'",
- R.spec().format, A.spec().format, B.spec().format);
+ if ((initialized_R && specR.format != TypeDesc::TypeFloat) ||
+ specA.format != TypeDesc::TypeFloat ||
+ specB.format != TypeDesc::TypeFloat) {
+ R.error ("Unsupported pixel data format combination '%s = %s over %s'",
+ specR.format, specA.format, specB.format);
return false;
}
- // Fail if the input images have a Z channel.
- if (specA.z_channel >= 0 || specB.z_channel >= 0) {
- R.error ("'over' does not support Z channels");
- return false;
+ // Uninitialized R -> size it to the union of A and B.
+ if (! initialized_R) {
+ ImageSpec newspec = specA;
+ set_roi (newspec, roi_union (get_roi(specA), get_roi(specB)));
+ R.reset ("over", newspec);
}
- // If input images A and B have different number of non-alpha channels
- // then return false.
- if (non_alpha_A != non_alpha_B) {
- R.error ("inputs had different numbers of color channels");
+ // Specified ROI -> use it. Unspecified ROI -> initialize from R.
+ if (! roi.defined())
+ roi = get_roi (R.spec());
+
+ parallel_image (boost::bind (over_impl<float,float,float>, boost::ref(R),
+ boost::cref(A), boost::cref(B), _1, false),
+ roi, nthreads);
+ return ! R.has_error();
+}
+
+
+
+bool
+ImageBufAlgo::zover (ImageBuf &R, const ImageBuf &A, const ImageBuf &B,
+ ROI roi, int nthreads)
+{
+ const ImageSpec &specR = R.spec();
+ const ImageSpec &specA = A.spec();
+ const ImageSpec &specB = B.spec();
+
+ int nchannels_R, nchannels_A, nchannels_B;
+ int alpha_R, alpha_A, alpha_B;
+ int z_R, z_A, z_B;
+ int colors_R, colors_A, colors_B;
+ bool initialized_R = decode_over_channels (R, nchannels_R, alpha_R,
+ z_R, colors_R);
+ bool initialized_A = decode_over_channels (A, nchannels_A, alpha_A,
+ z_A, colors_A);
+ bool initialized_B = decode_over_channels (B, nchannels_B, alpha_B,
+ z_B, colors_B);
+
+ if (! initialized_A || ! initialized_B) {
+ R.error ("Can't 'zover' uninitialized images");
return false;
}
-
- // A or B has number of channels different than 3 and 4, and it does
- // not have an alpha channel.
- if ((A_not_34 && !has_alpha_A) || (B_not_34 && !has_alpha_B)) {
- R.error ("inputs must have alpha channels (or be implicitly RGB or RGBA)");
+ // Fail if the input images don't have a Z channel.
+ if (z_A < 0 || z_B < 0 || (initialized_R && z_R < 0)) {
+ R.error ("'zover' requires Z channels");
return false;
}
-
- // A or B has zero or one channel -> return false.
- if (channels_A <= 1 || channels_B <= 1) {
- R.error ("unsupported number of channels");
+ // Fail if the input images don't have an alpha channel.
+ if (alpha_A < 0 || alpha_B < 0 || (initialized_R && alpha_R < 0)) {
+ R.error ("'zover' requires alpha channels");
+ return false;
+ }
+ // Fail for mismatched channel counts
+ if (colors_A != colors_B || colors_A < 1) {
+ R.error ("Can't 'zover' images with mismatched color channel counts (%d vs %d)",
+ colors_A, colors_B);
+ return false;
+ }
+ // Fail for unaligned alpha or z channels
+ if (alpha_A != alpha_B || z_A != z_B ||
+ (initialized_R && alpha_R != alpha_A) ||
+ (initialized_R && z_R != z_A)) {
+ R.error ("Can't 'zover' images with mismatched channel order",
+ colors_A, colors_B);
+ return false;
+ }
+
+ // At present, this operation only supports ImageBuf's containing
+ // float pixel data.
+ if ((initialized_R && specR.format != TypeDesc::TypeFloat) ||
+ specA.format != TypeDesc::TypeFloat ||
+ specB.format != TypeDesc::TypeFloat) {
+ R.error ("Unsupported pixel data format combination '%s = %s zover %s'",
+ specR.format, specA.format, specB.format);
return false;
}
- // Initialized R -> use as allocated.
// Uninitialized R -> size it to the union of A and B.
- ImageSpec newspec = ImageSpec ();
- ROI union_AB = roi_union (get_roi(specA), get_roi(specB));
- set_roi (newspec, union_AB);
- if ((! has_alpha_A && ! has_alpha_B)
- || (has_alpha_A && ! has_alpha_B && alpha_A == channels_A - 1)
- || (! has_alpha_A && has_alpha_B && alpha_B == channels_B - 1)) {
- if (! initialized_R) {
- newspec.nchannels = 4;
- newspec.alpha_channel = 3;
- R.reset ("over", newspec);
- } else {
- if (non_alpha_R != 3 || alpha_R != 3) {
- R.error ("unsupported channel layout");
- return false;
- }
- }
- } else if (has_alpha_A && has_alpha_B && alpha_A == alpha_B) {
- if (! initialized_R) {
- newspec.nchannels = channels_A;
- newspec.alpha_channel = alpha_A;
- R.reset ("over", newspec);
- } else {
- if (non_alpha_R != non_alpha_A || alpha_R != alpha_A) {
- R.error ("unsupported channel layout");
- return false;
- }
- }
- } else {
- R.error ("unsupported channel layout");
- return false;
+ if (! initialized_R) {
+ ImageSpec newspec = specA;
+ set_roi (newspec, roi_union (get_roi(specA), get_roi(specB)));
+ R.reset ("zover", newspec);
}
// Specified ROI -> use it. Unspecified ROI -> initialize from R.
@@ -1418,8 +1491,8 @@ ImageBufAlgo::over (ImageBuf &R, const ImageBuf &A, const ImageBuf &B, ROI roi,
roi = get_roi (R.spec());
parallel_image (boost::bind (over_impl<float,float,float>, boost::ref(R),
- boost::cref(A), boost::cref(B), _1),
- roi, nthreads);
+ boost::cref(A), boost::cref(B), _1, true),
+ roi, nthreads);
return ! R.has_error();
}
diff --git a/src/libOpenImageIO/imageinput.cpp b/src/libOpenImageIO/imageinput.cpp
index d7ea193..b3dd7f6 100644
--- a/src/libOpenImageIO/imageinput.cpp
+++ b/src/libOpenImageIO/imageinput.cpp
@@ -41,6 +41,9 @@
#include "imageio.h"
#include "imageio_pvt.h"
+#include <boost/scoped_array.hpp>
+
+
OIIO_NAMESPACE_ENTER
{
using namespace pvt;
@@ -200,7 +203,7 @@ ImageInput::read_scanlines (int ybegin, int yend, int z,
const imagesize_t limit = 16*1024*1024; // Allocate 16 MB, or 1 scanline
int chunk = std::max (1, int(limit / native_scanline_bytes));
- std::vector<unsigned char> buf (chunk * native_scanline_bytes);
+ boost::scoped_array<char> buf (new char [chunk * native_scanline_bytes]);
bool ok = true;
int scanline_values = m_spec.width * nchans;
@@ -281,7 +284,7 @@ ImageInput::read_native_scanlines (int ybegin, int yend, int z,
size_t native_pixel_bytes = m_spec.pixel_bytes (true);
size_t native_ystride = m_spec.width * native_pixel_bytes;
- std::vector<char> buf (native_ystride);
+ boost::scoped_array<char> buf (new char [native_ystride]);
yend = std::min (yend, spec().y+spec().height);
for (int y = ybegin; y < yend; ++y) {
bool ok = read_native_scanline (y, z, &buf[0]);
@@ -333,7 +336,7 @@ ImageInput::read_tile (int x, int y, int z, TypeDesc format, void *data,
// Complex case -- either changing data type or stride
size_t tile_values = (size_t)m_spec.tile_pixels() * m_spec.nchannels;
- std::vector<char> buf (m_spec.tile_bytes(true));
+ boost::scoped_array<char> buf (new char [m_spec.tile_bytes(true)]);
bool ok = read_native_tile (x, y, z, &buf[0]);
if (! ok)
return false;
@@ -510,7 +513,7 @@ ImageInput::read_native_tiles (int xbegin, int xend, int ybegin, int yend,
stride_t tilezstride = tileystride * m_spec.tile_height;
stride_t ystride = (xend-xbegin) * pixel_bytes;
stride_t zstride = (yend-ybegin) * ystride;
- std::vector<char> pels (m_spec.tile_bytes(true));
+ boost::scoped_array<char> pels (new char [m_spec.tile_bytes(true)]);
for (int z = zbegin; z < zend; z += m_spec.tile_depth) {
for (int y = ybegin; y < yend; y += m_spec.tile_height) {
for (int x = xbegin; x < xend; x += m_spec.tile_width) {
@@ -562,7 +565,7 @@ ImageInput::read_native_tiles (int xbegin, int xend, int ybegin, int yend,
stride_t subset_ystride = (xend-xbegin) * subset_bytes;
stride_t subset_zstride = (yend-ybegin) * subset_ystride;
- std::vector<char> pels (m_spec.tile_bytes(true));
+ boost::scoped_array<char> pels (new char [m_spec.tile_bytes(true)]);
for (int z = zbegin; z < zend; z += m_spec.tile_depth) {
for (int y = ybegin; y < yend; y += m_spec.tile_height) {
for (int x = xbegin; x < xend; x += m_spec.tile_width) {
diff --git a/src/libOpenImageIO/imageio.cpp b/src/libOpenImageIO/imageio.cpp
index 6112cf9..434eb4e 100644
--- a/src/libOpenImageIO/imageio.cpp
+++ b/src/libOpenImageIO/imageio.cpp
@@ -228,10 +228,6 @@ pvt::contiguize (const void *src, int nchannels,
return _contiguize ((const float *)src, nchannels,
xstride, ystride, zstride,
(float *)dst, width, height, depth);
- case TypeDesc::DOUBLE :
- return _contiguize ((const double *)src, nchannels,
- xstride, ystride, zstride,
- (double *)dst, width, height, depth);
case TypeDesc::INT8:
case TypeDesc::UINT8 :
return _contiguize ((const char *)src, nchannels,
@@ -254,6 +250,10 @@ pvt::contiguize (const void *src, int nchannels,
return _contiguize ((const long long *)src, nchannels,
xstride, ystride, zstride,
(long long *)dst, width, height, depth);
+ case TypeDesc::DOUBLE :
+ return _contiguize ((const double *)src, nchannels,
+ xstride, ystride, zstride,
+ (double *)dst, width, height, depth);
default:
ASSERT (0 && "OpenImageIO::contiguize : bad format");
return NULL;
@@ -269,24 +269,21 @@ pvt::convert_to_float (const void *src, float *dst, int nvals,
switch (format.basetype) {
case TypeDesc::FLOAT :
return (float *)src;
+ case TypeDesc::UINT8 :
+ convert_type ((const unsigned char *)src, dst, nvals);
+ break;
case TypeDesc::HALF :
convert_type ((const half *)src, dst, nvals);
break;
- case TypeDesc::DOUBLE :
- convert_type ((const double *)src, dst, nvals);
+ case TypeDesc::UINT16 :
+ convert_type ((const unsigned short *)src, dst, nvals);
break;
case TypeDesc::INT8:
convert_type ((const char *)src, dst, nvals);
break;
- case TypeDesc::UINT8 :
- convert_type ((const unsigned char *)src, dst, nvals);
- break;
case TypeDesc::INT16 :
convert_type ((const short *)src, dst, nvals);
break;
- case TypeDesc::UINT16 :
- convert_type ((const unsigned short *)src, dst, nvals);
- break;
case TypeDesc::INT :
convert_type ((const int *)src, dst, nvals);
break;
@@ -299,6 +296,9 @@ pvt::convert_to_float (const void *src, float *dst, int nvals,
case TypeDesc::UINT64 :
convert_type ((const unsigned long long *)src, dst, nvals);
break;
+ case TypeDesc::DOUBLE :
+ convert_type ((const double *)src, dst, nvals);
+ break;
default:
ASSERT (0 && "ERROR to_float: bad format");
return NULL;
@@ -400,8 +400,7 @@ pvt::convert_from_float (const float *src, void *dst, size_t nvals,
bool
convert_types (TypeDesc src_type, const void *src,
- TypeDesc dst_type, void *dst, int n,
- int alpha_channel, int z_channel)
+ TypeDesc dst_type, void *dst, int n)
{
// If no conversion is necessary, just memcpy
if ((src_type == dst_type || dst_type.basetype == TypeDesc::UNKNOWN)) {
@@ -409,39 +408,29 @@ convert_types (TypeDesc src_type, const void *src,
return true;
}
- // Conversions are via a temporary float array
- bool use_tmp = false;
- boost::scoped_array<float> tmp;
- float *buf;
- if (src_type == TypeDesc::FLOAT) {
- buf = (float *) src;
- } else {
- tmp.reset (new float[n]); // Will be freed when tmp exists its scope
- buf = tmp.get();
- use_tmp = true;
+ if (dst_type == TypeDesc::TypeFloat) {
+ // Special case -- converting non-float to float
+ pvt::convert_to_float (src, (float *)dst, n, src_type);
+ return true;
}
- if (use_tmp) {
- // Convert from 'src_type' to float (or nothing, if already float)
- switch (src_type.basetype) {
- case TypeDesc::UINT8 : convert_type ((const unsigned char *)src, buf, n); break;
- case TypeDesc::UINT16 : convert_type ((const unsigned short *)src, buf, n); break;
- case TypeDesc::FLOAT : convert_type ((const float *)src, buf, n); break;
- case TypeDesc::HALF : convert_type ((const half *)src, buf, n); break;
- case TypeDesc::DOUBLE : convert_type ((const double *)src, buf, n); break;
- case TypeDesc::INT8 : convert_type ((const char *)src, buf, n); break;
- case TypeDesc::INT16 : convert_type ((const short *)src, buf, n); break;
- case TypeDesc::INT : convert_type ((const int *)src, buf, n); break;
- case TypeDesc::UINT : convert_type ((const unsigned int *)src, buf, n); break;
- case TypeDesc::INT64 : convert_type ((const long long *)src, buf, n); break;
- case TypeDesc::UINT64 : convert_type ((const unsigned long long *)src, buf, n); break;
- default: return false; // unknown format
+ // Conversion is to a non-float type
+
+ boost::scoped_array<float> tmp; // In case we need a lot of temp space
+ float *buf = (float *)src;
+ if (src_type != TypeDesc::TypeFloat) {
+ // If src is also not float, convert through an intermediate buffer
+ if (n <= 4096) // If < 16k, use the stack
+ buf = ALLOCA (float, n);
+ else {
+ tmp.reset (new float[n]); // Freed when tmp exists its scope
+ buf = tmp.get();
}
+ pvt::convert_to_float (src, buf, n, src_type);
}
- // Convert float to 'dst_type' (just a copy if dst is float)
+ // Convert float to 'dst_type'
switch (dst_type.basetype) {
- case TypeDesc::FLOAT : memcpy (dst, buf, n * sizeof(float)); break;
case TypeDesc::UINT8 : convert_type (buf, (unsigned char *)dst, n); break;
case TypeDesc::UINT16 : convert_type (buf, (unsigned short *)dst, n); break;
case TypeDesc::HALF : convert_type (buf, (half *)dst, n); break;
@@ -460,6 +449,17 @@ convert_types (TypeDesc src_type, const void *src,
+// Deprecated version -- keep for link compatibiity
+bool
+convert_types (TypeDesc src_type, const void *src,
+ TypeDesc dst_type, void *dst, int n,
+ int alpha_channel, int z_channel)
+{
+ return convert_types (src_type, src, dst_type, dst, n);
+}
+
+
+
bool
convert_image (int nchannels, int width, int height, int depth,
const void *src, TypeDesc src_type,
diff --git a/src/libOpenImageIO/imageoutput.cpp b/src/libOpenImageIO/imageoutput.cpp
index 6ba0775..eaeac6e 100644
--- a/src/libOpenImageIO/imageoutput.cpp
+++ b/src/libOpenImageIO/imageoutput.cpp
@@ -45,6 +45,8 @@
#include "imageio.h"
#include "imageio_pvt.h"
+#include <boost/scoped_array.hpp>
+
OIIO_NAMESPACE_ENTER
{
@@ -485,7 +487,7 @@ ImageOutput::copy_image (ImageInput *in)
// a time, to minimize mem footprint.
bool native = supports("channelformats") && inspec.channelformats.size();
TypeDesc format = native ? TypeDesc::UNKNOWN : inspec.format;
- std::vector<char> pixels (inspec.image_bytes(native));
+ boost::scoped_array<char> pixels (new char [inspec.image_bytes(native)]);
bool ok = in->read_image (format, &pixels[0]);
if (ok)
ok = write_image (format, &pixels[0]);
diff --git a/src/libOpenImageIO/imagespeed_test.cpp b/src/libOpenImageIO/imagespeed_test.cpp
index 4d926d3..de175dd 100644
--- a/src/libOpenImageIO/imagespeed_test.cpp
+++ b/src/libOpenImageIO/imagespeed_test.cpp
@@ -40,23 +40,30 @@
#include "unittest.h"
#include <iostream>
+#include <vector>
+
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
OIIO_NAMESPACE_USING;
static bool verbose = false;
static int iterations = 1;
static int ntrials = 1;
-static ustring input_filename;
+static int numthreads = 0;
+static int autotile_size = 64;
+static bool iter_only = false;
+static std::vector<ustring> input_filename;
static std::vector<char> buffer;
static ImageCache *imagecache = NULL;
-static ImageSpec spec;
+static imagesize_t total_image_pixels = 0;
static int
parse_files (int argc, const char *argv[])
{
- input_filename = ustring(argv[0]);
+ input_filename.push_back (ustring(argv[0]));
return 0;
}
@@ -69,16 +76,18 @@ getargs (int argc, char *argv[])
ArgParse ap;
ap.options ("imagespeed_test\n"
OIIO_INTRO_STRING "\n"
- "Usage: imagespeed_test [options]",
+ "Usage: imagespeed_test [options] filename...",
"%*", parse_files, "",
"--help", &help, "Print help message",
"-v", &verbose, "Verbose mode",
-// "--threads %d", &numthreads,
-// ustring::format("Number of threads (default: %d)", numthreads).c_str(),
+ "--threads %d", &numthreads,
+ ustring::format("Number of threads (default: %d)", numthreads).c_str(),
"--iters %d", &iterations,
ustring::format("Number of iterations (default: %d)", iterations).c_str(),
"--trials %d", &ntrials, "Number of trials",
-// "--wedge", &wedge, "Do a wedge test",
+ "--autotile %d", &autotile_size,
+ ustring::format("Autotile size (when used; default: %d)", autotile_size).c_str(),
+ "--iteronly", &iter_only, "Run iteration tests only (not read tests)",
NULL);
if (ap.parse (argc, (const char**)argv) < 0) {
std::cerr << ap.geterror() << std::endl;
@@ -96,11 +105,53 @@ getargs (int argc, char *argv[])
static void
time_read_image ()
{
- ImageInput *in = ImageInput::open (input_filename.c_str());
- ASSERT (in);
- in->read_image (TypeDesc::TypeFloat, &buffer[0]);
- in->close ();
- delete in;
+ BOOST_FOREACH (ustring filename, input_filename) {
+ ImageInput *in = ImageInput::open (filename.c_str());
+ ASSERT (in);
+ in->read_image (TypeDesc::TypeFloat, &buffer[0]);
+ in->close ();
+ delete in;
+ }
+}
+
+
+
+static void
+time_read_scanline_at_a_time ()
+{
+ BOOST_FOREACH (ustring filename, input_filename) {
+ ImageInput *in = ImageInput::open (filename.c_str());
+ ASSERT (in);
+ const ImageSpec &spec (in->spec());
+ size_t pixelsize = spec.nchannels * sizeof(float);
+ imagesize_t scanlinesize = spec.width * pixelsize;
+ for (int y = 0; y < spec.height; ++y) {
+ in->read_scanline (y+spec.y, 0, TypeDesc::TypeFloat,
+ &buffer[scanlinesize*y]);
+ }
+ in->close ();
+ delete in;
+ }
+}
+
+
+
+static void
+time_read_64_scanlines_at_a_time ()
+{
+ BOOST_FOREACH (ustring filename, input_filename) {
+ ImageInput *in = ImageInput::open (filename.c_str());
+ ASSERT (in);
+ const ImageSpec &spec (in->spec());
+ size_t pixelsize = spec.nchannels * sizeof(float);
+ imagesize_t scanlinesize = spec.width * pixelsize;
+ for (int y = 0; y < spec.height; y += 64) {
+ in->read_scanlines (y+spec.y, std::min(y+spec.y+64, spec.y+spec.height),
+ 0, TypeDesc::TypeFloat, &buffer[scanlinesize*y]);
+ }
+ in->close ();
+ delete in;
+ }
}
@@ -108,9 +159,11 @@ time_read_image ()
static void
time_read_imagebuf ()
{
- ImageBuf ib (input_filename.string(), imagecache);
- ib.read (0, 0, true, TypeDesc::TypeFloat);
imagecache->invalidate_all (true);
+ BOOST_FOREACH (ustring filename, input_filename) {
+ ImageBuf ib (filename.string(), imagecache);
+ ib.read (0, 0, true, TypeDesc::TypeFloat);
+ }
}
@@ -118,11 +171,178 @@ time_read_imagebuf ()
static void
time_ic_get_pixels ()
{
- imagecache->get_pixels (input_filename, 0, 0, spec.x, spec.x+spec.width,
- spec.y, spec.y+spec.height,
- spec.z, spec.z+spec.depth,
- TypeDesc::TypeFloat, &buffer[0]);
imagecache->invalidate_all (true);
+ BOOST_FOREACH (ustring filename, input_filename) {
+ const ImageSpec spec = (*imagecache->imagespec (filename));
+ imagecache->get_pixels (filename, 0, 0, spec.x, spec.x+spec.width,
+ spec.y, spec.y+spec.height,
+ spec.z, spec.z+spec.depth,
+ TypeDesc::TypeFloat, &buffer[0]);
+ }
+}
+
+
+
+static void
+test_read (const std::string &explanation,
+ void (*func)(), int autotile=64, int autoscanline=1)
+{
+ imagecache->invalidate_all (true); // Don't hold anything
+ imagecache->attribute ("autotile", autotile);
+ imagecache->attribute ("autoscanline", autoscanline);
+ double t = time_trial (func, ntrials);
+ double rate = double(total_image_pixels) / t;
+ std::cout << " " << explanation << ": "
+ << Strutil::timeintervalformat(t,2)
+ << " = " << Strutil::format("%5.1f",rate/1.0e6) << " Mpel/s\n";
+}
+
+
+
+static float
+time_loop_pixels_1D (ImageBuf &ib, int iters)
+{
+ ASSERT (ib.localpixels() && ib.pixeltype() == TypeDesc::TypeFloat);
+ const ImageSpec &spec (ib.spec());
+ imagesize_t npixels = spec.image_pixels();
+ int nchannels = spec.nchannels;
+ double sum = 0.0f;
+ for (int i = 0; i < iters; ++i) {
+ const float *f = (const float *) ib.pixeladdr (spec.x, spec.y, spec.z);
+ ASSERT (f);
+ for (imagesize_t p = 0; p < npixels; ++p) {
+ sum += f[0];
+ f += nchannels;
+ }
+ }
+ // std::cout << float(sum/npixels/iters) << "\n";
+ return float(sum/npixels/iters);
+}
+
+
+
+static float
+time_loop_pixels_3D (ImageBuf &ib, int iters)
+{
+ ASSERT (ib.localpixels() && ib.pixeltype() == TypeDesc::TypeFloat);
+ const ImageSpec &spec (ib.spec());
+ imagesize_t npixels = spec.image_pixels();
+ int nchannels = spec.nchannels;
+ double sum = 0.0f;
+ for (int i = 0; i < iters; ++i) {
+ const float *f = (const float *) ib.pixeladdr (spec.x, spec.y, spec.z);
+ ASSERT (f);
+ for (int z = spec.z, ze = spec.z+spec.depth; z < ze; ++z) {
+ for (int y = spec.y, ye = spec.y+spec.height; y < ye; ++y) {
+ for (int x = spec.x, xe = spec.x+spec.width; x < xe; ++x) {
+ sum += f[0];
+ f += nchannels;
+ }
+ }
+ }
+ }
+ // std::cout << float(sum/npixels/iters) << "\n";
+ return float(sum/npixels/iters);
+}
+
+
+
+static float
+time_loop_pixels_3D_getchannel (ImageBuf &ib, int iters)
+{
+ ASSERT (ib.pixeltype() == TypeDesc::TypeFloat);
+ const ImageSpec &spec (ib.spec());
+ imagesize_t npixels = spec.image_pixels();
+ double sum = 0.0f;
+ for (int i = 0; i < iters; ++i) {
+ for (int z = spec.z, ze = spec.z+spec.depth; z < ze; ++z) {
+ for (int y = spec.y, ye = spec.y+spec.height; y < ye; ++y) {
+ for (int x = spec.x, xe = spec.x+spec.width; x < xe; ++x) {
+ sum += ib.getchannel (x, y, 0);
+ }
+ }
+ }
+ }
+ // std::cout << float(sum/npixels/iters) << "\n";
+ return float(sum/npixels/iters);
+}
+
+
+
+static float
+time_iterate_pixels (ImageBuf &ib, int iters)
+{
+ ASSERT (ib.pixeltype() == TypeDesc::TypeFloat);
+ const ImageSpec &spec (ib.spec());
+ imagesize_t npixels = spec.image_pixels();
+ double sum = 0.0f;
+ for (int i = 0; i < iters; ++i) {
+ for (ImageBuf::ConstIterator<float,float> p (ib); !p.done(); ++p) {
+ sum += p[0];
+ }
+ }
+ // std::cout << float(sum/npixels/iters) << "\n";
+ return float(sum/npixels/iters);
+}
+
+
+
+static float
+time_iterate_pixels_slave_pos (ImageBuf &ib, int iters)
+{
+ ASSERT (ib.pixeltype() == TypeDesc::TypeFloat);
+ const ImageSpec &spec (ib.spec());
+ imagesize_t npixels = spec.image_pixels();
+ double sum = 0.0f;
+ for (int i = 0; i < iters; ++i) {
+ ImageBuf::ConstIterator<float,float> slave (ib);
+ for (ImageBuf::ConstIterator<float,float> p (ib); !p.done(); ++p) {
+ slave.pos (p.x(), p.y());
+ sum += p[0];
+ }
+ }
+ // std::cout << float(sum/npixels/iters) << "\n";
+ return float(sum/npixels/iters);
+}
+
+
+
+static float
+time_iterate_pixels_slave_incr (ImageBuf &ib, int iters)
+{
+ ASSERT (ib.pixeltype() == TypeDesc::TypeFloat);
+ const ImageSpec &spec (ib.spec());
+ imagesize_t npixels = spec.image_pixels();
+ double sum = 0.0f;
+ for (int i = 0; i < iters; ++i) {
+ ImageBuf::ConstIterator<float,float> slave (ib);
+ for (ImageBuf::ConstIterator<float,float> p (ib); !p.done(); ++p) {
+ sum += p[0];
+ ++slave;
+ }
+ }
+ // std::cout << float(sum/npixels/iters) << "\n";
+ return float(sum/npixels/iters);
+}
+
+
+
+static void
+test_pixel_iteration (const std::string &explanation,
+ float (*func)(ImageBuf&,int),
+ bool preload, int iters=100, int autotile=64)
+{
+ imagecache->invalidate_all (true); // Don't hold anything
+ // Force the whole image to be read at once
+ imagecache->attribute ("autotile", autotile);
+ imagecache->attribute ("autoscanline", 1);
+ ImageBuf ib (input_filename[0].string(), imagecache);
+ ib.read (0, 0, preload, TypeDesc::TypeFloat);
+ double t = time_trial (boost::bind(func,boost::ref(ib),iters), ntrials);
+ double rate = double(ib.spec().image_pixels()) / (t/iters);
+ std::cout << " " << explanation << ": "
+ << Strutil::timeintervalformat(t/iters,3)
+ << " = " << Strutil::format("%5.1f",rate/1.0e6) << " Mpel/s\n";
}
@@ -131,37 +351,88 @@ int
main (int argc, char **argv)
{
getargs (argc, argv);
-
- if (input_filename.empty()) {
+ if (input_filename.size() == 0) {
std::cout << "Error: Must supply a filename.\n";
return -1;
}
+ OIIO::attribute ("threads", numthreads);
+
imagecache = ImageCache::create ();
imagecache->attribute ("forcefloat", 1);
// Allocate a buffer big enough (for floats)
- bool ok = imagecache->get_imagespec (input_filename, spec);
- ASSERT (ok);
- imagecache->invalidate_all (true); // Don't hold anything
- buffer.resize (spec.image_pixels()*spec.nchannels*sizeof(float), 0);
-
- {
- double t = time_trial (time_read_image, ntrials);
- std::cout << "image_read speed: " << Strutil::timeintervalformat(t,2) << "\n";
- }
-
- {
- double t = time_trial (time_read_imagebuf, ntrials);
- std::cout << "ImageBuf read speed: " << Strutil::timeintervalformat(t,2) << "\n";
+ bool all_scanline = true;
+ total_image_pixels = 0;
+ imagesize_t maxpelchans = 0;
+ for (size_t i = 0; i < input_filename.size(); ++i) {
+ ImageSpec spec;
+ if (! imagecache->get_imagespec (input_filename[i], spec, 0, 0, true)) {
+ std::cout << "File \"" << input_filename[i] << "\" could not be opened.\n";
+ return -1;
+ }
+ total_image_pixels += spec.image_pixels();
+ maxpelchans = std::max (maxpelchans, spec.image_pixels()*spec.nchannels);
+ all_scanline &= (spec.tile_width == 0);
}
+ imagecache->invalidate_all (true); // Don't hold anything
- {
- double t = time_trial (time_ic_get_pixels, ntrials);
- std::cout << "ImageCache get_pixels speed: " << Strutil::timeintervalformat(t,2) << "\n";
+ if (! iter_only) {
+ std::cout << "Timing various ways of reading images:\n";
+ buffer.resize (maxpelchans*sizeof(float), 0);
+ test_read ("read_image ",
+ time_read_image, 0, 0);
+ if (all_scanline) {
+ test_read ("read_scanline (1 at a time) ",
+ time_read_scanline_at_a_time, 0, 0);
+ test_read ("read_scanlines (64 at a time) ",
+ time_read_64_scanlines_at_a_time, 0, 0);
+ }
+ test_read ("ImageBuf read ",
+ time_read_imagebuf, 0, 0);
+ test_read ("ImageCache get_pixels ",
+ time_ic_get_pixels, 0, 0);
+ test_read ("ImageBuf read (autotile) ",
+ time_read_imagebuf, autotile_size, 0);
+ test_read ("ImageCache get_pixels (autotile) ",
+ time_ic_get_pixels, autotile_size, 0);
+ if (all_scanline) { // don't bother for tiled images
+ test_read ("ImageBuf read (autotile+autoscanline) ",
+ time_read_imagebuf, autotile_size, 1);
+ test_read ("ImageCache get_pixels (autotile+autoscanline)",
+ time_ic_get_pixels, autotile_size, 1);
+ }
+ if (verbose)
+ std::cout << "\n" << imagecache->getstats(2) << "\n";
+ std::cout << "\n";
}
- imagecache->invalidate_all (true); // Don't hold anything
+ const int iters = 64;
+ std::cout << "Timing ways of iterating over an image:\n";
+
+ test_pixel_iteration ("Loop pointers on loaded image (\"1D\") ",
+ time_loop_pixels_1D, true, iters);
+ test_pixel_iteration ("Loop pointers on loaded image (\"3D\") ",
+ time_loop_pixels_3D, true, iters);
+ test_pixel_iteration ("Loop + getchannel on loaded image (\"3D\")",
+ time_loop_pixels_3D_getchannel, true, iters/32);
+ test_pixel_iteration ("Loop + getchannel on cached image (\"3D\")",
+ time_loop_pixels_3D_getchannel, false, iters/32);
+ test_pixel_iteration ("Iterate over a loaded image ",
+ time_iterate_pixels, true, iters);
+ test_pixel_iteration ("Iterate over a cache image ",
+ time_iterate_pixels, false, iters);
+ test_pixel_iteration ("Iterate over a loaded image (pos slave)",
+ time_iterate_pixels_slave_pos, true, iters);
+ test_pixel_iteration ("Iterate over a cache image (pos slave) ",
+ time_iterate_pixels_slave_pos, false, iters);
+ test_pixel_iteration ("Iterate over a loaded image (incr slave)",
+ time_iterate_pixels_slave_incr, true, iters);
+ test_pixel_iteration ("Iterate over a cache image (incr slave) ",
+ time_iterate_pixels_slave_incr, false, iters);
+
+ if (verbose)
+ std::cout << "\n" << imagecache->getstats(2) << "\n";
ImageCache::destroy (imagecache);
return unit_test_failures;
diff --git a/src/maketx/maketx.cpp b/src/libOpenImageIO/maketexture.cpp
similarity index 54%
copy from src/maketx/maketx.cpp
copy to src/libOpenImageIO/maketexture.cpp
index ca17b9d..503bada 100644
--- a/src/maketx/maketx.cpp
+++ b/src/libOpenImageIO/maketexture.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2008 Larry Gritz and the other authors and contributors.
+ Copyright 2013 Larry Gritz and the other authors and contributors.
All Rights Reserved.
Redistribution and use in source and binary forms, with or without
@@ -57,133 +57,7 @@
OIIO_NAMESPACE_USING
-// # FIXME: Refactor all statics into a struct
-
-// Basic runtime options
-static std::string full_command_line;
-static std::vector<std::string> filenames;
-static std::string outputfilename;
-static std::string dataformatname = "";
-static std::string fileformatname = "";
-static std::vector<std::string> mipimages;
-//static float ingamma = 1.0f, outgamma = 1.0f;
-static bool verbose = false;
-static bool stats = false;
-static int nthreads = 0; // default: use #cores threads if available
-static int tile[3] = { 64, 64, 1 };
-static std::string channellist;
-static std::string compression = "zip";
-static bool updatemode = false;
-static double stat_readtime = 0;
-static double stat_writetime = 0;
-static double stat_resizetime = 0;
-static double stat_miptime = 0;
-static double stat_colorconverttime = 0;
-static bool checknan = false;
-static std::string fixnan = "none"; // none, black, box3
-static bool set_full_to_pixels = false;
-static int found_nonfinite = 0;
static spin_mutex maketx_mutex; // for anything that needs locking
-static std::string filtername = "box";
-static Filter2D *filter = NULL;
-
-// Conversion modes. If none are true, we just make an ordinary texture.
-static bool mipmapmode = false;
-static bool shadowmode = false;
-static bool shadowcubemode = false;
-static bool volshadowmode = false;
-static bool envlatlmode = false;
-static bool envcubemode = false;
-static bool lightprobemode = false;
-static bool vertcrossmode = false;
-static bool latl2envcubemode = false;
-
-// Options controlling file metadata or mipmap creation
-static float fov = 90;
-static float fovcot = 0.0f;
-static std::string wrap = "black";
-static std::string swrap;
-static std::string twrap;
-static bool doresize = false;
-//static float opaquewidth = 0; // should be volume shadow epsilon
-static Imath::M44f Mcam(0.0f), Mscr(0.0f); // Initialize to 0
-static bool separate = false;
-static bool nomipmap = false;
-static bool embed_hash = false; // Ignored.
-static bool prman_metadata = false;
-static bool constant_color_detect = false;
-static bool monochrome_detect = false;
-static bool opaque_detect = false;
-static int nchannels = -1;
-static bool prman = false;
-static bool oiio = false;
-static bool src_samples_border = false; // are src edge samples on the border?
-static bool ignore_unassoc = false; // ignore unassociated alpha tags
-
-static bool unpremult = false;
-static std::string incolorspace;
-static std::string outcolorspace;
-static ColorConfig colorconfig;
-
-
-// forward decl
-static void write_mipmap (ImageBuf &img, const ImageSpec &outspec_template,
- std::string outputfilename, ImageOutput *out,
- TypeDesc outputdatatype, bool mipmap);
-
-
-
-static std::string
-filter_help_string ()
-{
- std::string s ("Select filter for resizing (choices:");
- for (int i = 0, e = Filter2D::num_filters(); i < e; ++i) {
- FilterDesc d;
- Filter2D::get_filterdesc (i, &d);
- s.append (" ");
- s.append (d.name);
- }
- s.append (", default=box)");
- return s;
-}
-
-
-
-static std::string
-colortitle_help_string ()
-{
- std::string s ("Color Management Options ");
- if(ColorConfig::supportsOpenColorIO()) {
- s += "(OpenColorIO enabled)";
- }
- else {
- s += "(OpenColorIO DISABLED)";
- }
- return s;
-}
-
-
-
-static std::string
-colorconvert_help_string ()
-{
- std::string s = "Apply a color space conversion to the image. "
- "If the output color space is not the same bit depth "
- "as input color space, it is your responsibility to set the data format "
- "to the proper bit depth using the -d option. ";
-
- s += " (choices: ";
- if (colorconfig.error() || colorconfig.getNumColorSpaces()==0) {
- s += "NONE";
- } else {
- for (int i=0; i < colorconfig.getNumColorSpaces(); ++i) {
- if (i!=0) s += ", ";
- s += colorconfig.getColorSpaceNameByIndex(i);
- }
- }
- s += ")";
- return s;
-}
@@ -208,199 +82,55 @@ setup_filter (const std::string &filtername)
-static int
-parse_files (int argc, const char *argv[])
-{
- for (int i = 0; i < argc; i++)
- filenames.push_back (argv[i]);
- return 0;
-}
-
-
-
-static void
-getargs (int argc, char *argv[])
-{
- bool help = false;
-
- ArgParse ap;
- ap.options ("maketx -- convert images to tiled, MIP-mapped textures\n"
- OIIO_INTRO_STRING "\n"
- "Usage: maketx [options] file...",
- "%*", parse_files, "",
- "--help", &help, "Print help message",
- "-v", &verbose, "Verbose status messages",
- "-o %s", &outputfilename, "Output filename",
- "--threads %d", &nthreads, "Number of threads (default: #cores)",
- "-u", &updatemode, "Update mode",
- "--format %s", &fileformatname, "Specify output file format (default: guess from extension)",
- "--nchannels %d", &nchannels, "Specify the number of output image channels.",
- "-d %s", &dataformatname, "Set the output data format to one of: "
- "uint8, sint8, uint16, sint16, half, float",
- "--tile %d %d", &tile[0], &tile[1], "Specify tile size",
- "--separate", &separate, "Use planarconfig separate (default: contiguous)",
- "--compression %s", &compression, "Set the compression method (default = zip, if possible)",
- "--fov %f", &fov, "Field of view for envcube/shadcube/twofish",
- "--fovcot %f", &fovcot, "Override the frame aspect ratio. Default is width/height.",
- "--wrap %s", &wrap, "Specify wrap mode (black, clamp, periodic, mirror)",
- "--swrap %s", &swrap, "Specific s wrap mode separately",
- "--twrap %s", &twrap, "Specific t wrap mode separately",
- "--resize", &doresize, "Resize textures to power of 2 (default: no)",
- "--noresize %!", &doresize, "Do not resize textures to power of 2 (deprecated)",
- "--filter %s", &filtername, filter_help_string().c_str(),
- "--nomipmap", &nomipmap, "Do not make multiple MIP-map levels",
- "--checknan", &checknan, "Check for NaN/Inf values (abort if found)",
- "--fixnan %s", &fixnan, "Attempt to fix NaN/Inf values in the image (options: none, black, box3)",
- "--fullpixels", &set_full_to_pixels, "Set the 'full' image range to be the pixel data window",
- "--Mcamera %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f",
- &Mcam[0][0], &Mcam[0][1], &Mcam[0][2], &Mcam[0][3],
- &Mcam[1][0], &Mcam[1][1], &Mcam[1][2], &Mcam[1][3],
- &Mcam[2][0], &Mcam[2][1], &Mcam[2][2], &Mcam[2][3],
- &Mcam[3][0], &Mcam[3][1], &Mcam[3][2], &Mcam[3][3],
- "Set the camera matrix",
- "--Mscreen %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f",
- &Mscr[0][0], &Mscr[0][1], &Mscr[0][2], &Mscr[0][3],
- &Mscr[1][0], &Mscr[1][1], &Mscr[1][2], &Mscr[1][3],
- &Mscr[2][0], &Mscr[2][1], &Mscr[2][2], &Mscr[2][3],
- &Mscr[3][0], &Mscr[3][1], &Mscr[3][2], &Mscr[3][3],
- "Set the camera matrix",
- "--hash", &embed_hash, "Embed SHA-1 hash of pixels in the header",
- "--prman-metadata", &prman_metadata, "Add prman specific metadata",
- "--constant-color-detect", &constant_color_detect, "Create 1-tile textures from constant color inputs",
- "--monochrome-detect", &monochrome_detect, "Create 1-channel textures from monochrome inputs",
- "--opaque-detect", &opaque_detect, "Drop alpha channel that is always 1.0",
- "--ignore-unassoc", &ignore_unassoc, "Ignore unassociated alpha tags in input (don't autoconvert)",
- "--stats", &stats, "Print runtime statistics",
- "--mipimage %L", &mipimages, "Specify an individual MIP level",
-//FIXME "-c %s", &channellist, "Restrict/shuffle channels",
-//FIXME "-debugdso"
-//FIXME "-note %s", ¬e, "Append a note to the image comments",
- "<SEPARATOR>", "Basic modes (default is plain texture):",
- "--shadow", &shadowmode, "Create shadow map",
-// "--shadcube", &shadowcubemode, "Create shadow cube (file order: px,nx,py,ny,pz,nz) (UNIMPLEMENTED)",
-// "--volshad", &volshadowmode, "Create volume shadow map (UNIMP)",
- "--envlatl", &envlatlmode, "Create lat/long environment map",
- "--envcube", &envcubemode, "Create cubic env map (file order: px, nx, py, ny, pz, nz) (UNIMP)",
-// "--lightprobe", &lightprobemode, "Convert a lightprobe to cubic env map (UNIMP)",
-// "--latl2envcube", &latl2envcubemode, "Convert a lat-long env map to a cubic env map (UNIMP)",
-// "--vertcross", &vertcrossmode, "Convert a vertical cross layout to a cubic env map (UNIMP)",
- "<SEPARATOR>", colortitle_help_string().c_str(),
- "--colorconvert %s %s", &incolorspace, &outcolorspace,
- colorconvert_help_string().c_str(),
- "--unpremult", &unpremult, "Unpremultiply before color conversion, then premultiply "
- "after the color conversion. You'll probably want to use this flag "
- "if your image contains an alpha channel.",
- "<SEPARATOR>", "Configuration Presets",
- "--prman", &prman, "Use PRMan-safe settings for tile size, planarconfig, and metadata.",
- "--oiio", &oiio, "Use OIIO-optimized settings for tile size, planarconfig, metadata.",
- NULL);
- if (ap.parse (argc, (const char**)argv) < 0) {
- std::cerr << ap.geterror() << std::endl;
- ap.usage ();
- exit (EXIT_FAILURE);
- }
- if (help) {
- ap.usage ();
- exit (EXIT_FAILURE);
- }
- full_command_line = ap.command_line ();
-
- int optionsum = ((int)shadowmode + (int)shadowcubemode + (int)volshadowmode +
- (int)envlatlmode + (int)envcubemode +
- (int)lightprobemode + (int)vertcrossmode +
- (int)latl2envcubemode);
- if (optionsum > 1) {
- std::cerr << "maketx ERROR: At most one of the following options may be set:\n"
- << "\t--shadow --shadcube --volshad --envlatl --envcube\n"
- << "\t--lightprobe --vertcross --latl2envcube\n";
- ap.usage ();
- exit (EXIT_FAILURE);
- }
- if (optionsum == 0)
- mipmapmode = true;
-
- if (prman && oiio) {
- std::cerr << "maketx ERROR: '--prman' compatibility, and '--oiio' optimizations are mutually exclusive.\n";
- std::cerr << "\tIf you'd like both prman and oiio compatibility, you should choose --prman\n";
- std::cerr << "\t(at the expense of oiio-specific optimizations)\n";
- ap.usage ();
- exit (EXIT_FAILURE);
- }
-
- if (filenames.size() < 1) {
- std::cerr << "maketx ERROR: Must have at least one input filename specified.\n";
- ap.usage();
- exit (EXIT_FAILURE);
- }
-
- filter = setup_filter (filtername);
- if (! filter) {
- std::cerr << "maketx ERROR: could not make filter '" << filtername << "\n";
- exit (EXIT_FAILURE);
- }
-
- if (embed_hash && verbose) {
- std::cerr << "maketx WARNING: The --embed_hash option is deprecated, and no longer necessary.\n";
- std::cerr << " (Hashes are always computed.)\n";
- }
-
-// std::cout << "Converting " << filenames[0] << " to " << outputfilename << "\n";
-}
-
-
-
static TypeDesc
-set_prman_options(TypeDesc out_dataformat)
+set_prman_options(TypeDesc out_dataformat, ImageSpec &configspec)
{
- // Force planar image handling, and also emit prman metadata
- separate = true;
- prman_metadata = true;
-
+ // Force separate planar image handling, and also emit prman metadata
+ configspec.attribute ("planarconfig", "separate");
+ configspec.attribute ("maketx:prman_metadata", 1);
+
// 8-bit : 64x64
- if (out_dataformat == TypeDesc::UINT8 ||
- out_dataformat == TypeDesc::INT8) {
- tile[0] = 64;
- tile[1] = 64;
+ if (out_dataformat == TypeDesc::UINT8 || out_dataformat == TypeDesc::INT8) {
+ configspec.tile_width = 64;
+ configspec.tile_height = 64;
}
-
+
// 16-bit : 64x32
// Force u16 -> s16
// In prman's txmake (last tested in 15.0)
// specifying -short creates a signed int representation
- if (out_dataformat == TypeDesc::UINT16) {
+ if (out_dataformat == TypeDesc::UINT16)
out_dataformat = TypeDesc::INT16;
+
+ if (out_dataformat == TypeDesc::INT16) {
+ configspec.tile_width = 64;
+ configspec.tile_height = 32;
}
-
- if (out_dataformat == TypeDesc::UINT16 ||
- out_dataformat == TypeDesc::INT16) {
- tile[0] = 64;
- tile[1] = 32;
- }
-
+
// Float: 32x32
// In prman's txmake (last tested in 15.0)
// specifying -half or -float make 32x32 tile size
- if (out_dataformat == TypeDesc::HALF ||
- out_dataformat == TypeDesc::FLOAT ||
- out_dataformat == TypeDesc::DOUBLE) {
- tile[0] = 32;
- tile[1] = 32;
+ if (out_dataformat == TypeDesc::DOUBLE)
+ out_dataformat = TypeDesc::FLOAT;
+ if (out_dataformat == TypeDesc::HALF || out_dataformat == TypeDesc::FLOAT) {
+ configspec.tile_width = 32;
+ configspec.tile_height = 32;
}
-
+
return out_dataformat;
}
static TypeDesc
-set_oiio_options(TypeDesc out_dataformat)
+set_oiio_options(TypeDesc out_dataformat, ImageSpec &configspec)
{
// Interleaved channels are faster to read
- separate = false;
+ configspec.attribute ("planarconfig", "contig");
// Force fixed tile-size across the board
- tile[0] = 64;
- tile[1] = 64;
+ configspec.tile_width = 64;
+ configspec.tile_height = 64;
return out_dataformat;
}
@@ -419,52 +149,11 @@ datestring (time_t t)
-// Run func over all pixels of dst, but split into separate threads for
-// bands of the image. Assumes that the calling profile of func is:
-// func (dst, src, xbegin, xend, ybegin, yend);
-// Also assumes that every pixel processed is approximately the same
-// cost, so it just divides the image space into equal-sized bands without
-// worrying about any sophisticated load balancing.
-template <class Func>
-void
-parallel_image (Func func, ImageBuf *dst, const ImageBuf *src,
- int xbegin, int xend, int ybegin, int yend, int nthreads)
-{
- const ImageSpec &dstspec (dst->spec());
-
- // Don't parallelize with too few pixels
- if (dstspec.image_pixels() < 1000)
- nthreads = 1;
- // nthreads < 1 means try to make enough threads to fill all cores
- if (nthreads < 1) {
- nthreads = boost::thread::hardware_concurrency();
- }
-
- if (nthreads > 1) {
- boost::thread_group threads;
- int blocksize = std::max (1, ((xend-xbegin) + nthreads-1) / nthreads);
- for (int i = 0; i < nthreads; ++i) {
- int x0 = xbegin + i*blocksize;
- int x1 = std::min (xbegin + (i+1)*blocksize, xend);
-// std::cerr << " launching " << x0 << ' ' << x1 << ' '
-// << ybegin << ' ' << yend << "\n";
- threads.add_thread (new boost::thread (func, dst, src,
- x0, x1,
- ybegin, yend));
- }
- threads.join_all ();
- } else {
- func (dst, src, xbegin, xend, ybegin, yend);
- }
-}
-
-
-
// Copy src into dst, but only for the range [x0,x1) x [y0,y1).
static void
-copy_block (ImageBuf *dst, const ImageBuf *src,
- int x0, int x1, int y0, int y1)
+copy_block (ImageBuf *dst, const ImageBuf *src, ROI roi)
{
+ int x0 = roi.xbegin, x1 = roi.xend, y0 = roi.ybegin, y1 = roi.yend;
const ImageSpec &dstspec (dst->spec());
float *pel = (float *) alloca (dstspec.pixel_bytes());
for (int y = y0; y < y1; ++y) {
@@ -480,16 +169,17 @@ copy_block (ImageBuf *dst, const ImageBuf *src,
// Resize src into dst using a good quality filter,
// for the pixel range [x0,x1) x [y0,y1).
static void
-resize_block_HQ (ImageBuf *dst, const ImageBuf *src,
- int x0, int x1, int y0, int y1)
+resize_block_HQ (ImageBuf *dst, const ImageBuf *src, ROI roi, Filter2D *filter)
{
+ int x0 = roi.xbegin, x1 = roi.xend, y0 = roi.ybegin, y1 = roi.yend;
ImageBufAlgo::resize (*dst, *src, x0, x1, y0, y1, filter);
}
static void
-interppixel_NDC_clamped (const ImageBuf &buf, float x, float y, float *pixel)
+interppixel_NDC_clamped (const ImageBuf &buf, float x, float y, float *pixel,
+ bool envlatlmode)
{
int fx = buf.spec().full_x;
int fy = buf.spec().full_y;
@@ -541,9 +231,9 @@ interppixel_NDC_clamped (const ImageBuf &buf, float x, float y, float *pixel)
// interppixel_NDC_full or interppixel_NDC_clamped, for the pixel range
// [x0,x1) x [y0,y1).
static void
-resize_block (ImageBuf *dst, const ImageBuf *src,
- int x0, int x1, int y0, int y1)
+resize_block (ImageBuf *dst, const ImageBuf *src, ROI roi, bool envlatlmode)
{
+ int x0 = roi.xbegin, x1 = roi.xend, y0 = roi.ybegin, y1 = roi.yend;
const ImageSpec &srcspec (src->spec());
bool src_is_crop = (srcspec.x > srcspec.full_x ||
srcspec.y > srcspec.full_y ||
@@ -565,7 +255,7 @@ resize_block (ImageBuf *dst, const ImageBuf *src,
if (src_is_crop)
src->interppixel_NDC_full (s, t, pel);
else
- interppixel_NDC_clamped (*src, s, t, pel);
+ interppixel_NDC_clamped (*src, s, t, pel, envlatlmode);
dst->setpixel (x, y, pel);
}
}
@@ -575,9 +265,9 @@ resize_block (ImageBuf *dst, const ImageBuf *src,
// Copy src into dst, but only for the range [x0,x1) x [y0,y1).
static void
-check_nan_block (ImageBuf* /*dst*/, const ImageBuf* src,
- int x0, int x1, int y0, int y1)
+check_nan_block (const ImageBuf* src, ROI roi, int &found_nonfinite)
{
+ int x0 = roi.xbegin, x1 = roi.xend, y0 = roi.ybegin, y1 = roi.yend;
const ImageSpec &spec (src->spec());
float *pel = (float *) alloca (spec.pixel_bytes());
for (int y = y0; y < y1; ++y) {
@@ -602,7 +292,6 @@ check_nan_block (ImageBuf* /*dst*/, const ImageBuf* src,
static void
fix_latl_edges (ImageBuf &buf)
{
- ASSERT (envlatlmode && "only call fix_latl_edges for latlong maps");
int n = buf.nchannels();
float *left = ALLOCA (float, n);
float *right = ALLOCA (float, n);
@@ -665,95 +354,310 @@ formatres (const ImageSpec &spec, bool extended=false)
static void
-make_texturemap (const char *maptypename = "texture map")
+maketx_merge_spec (ImageSpec &dstspec, const ImageSpec &srcspec)
{
- if (filenames.size() != 1) {
- std::cerr << "maketx ERROR: " << maptypename
- << " requires exactly one input filename\n";
- exit (EXIT_FAILURE);
+ for (size_t i = 0, e = srcspec.extra_attribs.size(); i < e; ++i) {
+ const ImageIOParameter &p (srcspec.extra_attribs[i]);
+ ustring name = p.name();
+ if (Strutil::istarts_with (name.string(), "maketx:")) {
+ // Special instruction -- don't copy it to the destination spec
+ } else {
+ // just an attribute that should be set upon output
+ dstspec.attribute (name.string(), p.type(), p.data());
+ }
+ }
+}
+
+
+
+static bool
+write_mipmap (ImageBufAlgo::MakeTextureMode mode,
+ ImageBuf &img, const ImageSpec &outspec_template,
+ std::string outputfilename, ImageOutput *out,
+ TypeDesc outputdatatype, bool mipmap,
+ Filter2D *filter, const ImageSpec &configspec,
+ std::ostream &outstream,
+ double &stat_writetime, double &stat_miptime)
+{
+ bool envlatlmode = (mode == ImageBufAlgo::MakeTxEnvLatl);
+
+ ImageSpec outspec = outspec_template;
+ outspec.set_format (outputdatatype);
+
+ if (mipmap && !out->supports ("multiimage") && !out->supports ("mipmap")) {
+ outstream << "maketx ERROR: \"" << outputfilename
+ << "\" format does not support multires images\n";
+ return false;
+ }
+
+ if (! mipmap && ! strcmp (out->format_name(), "openexr")) {
+ // Send hint to OpenEXR driver that we won't specify a MIPmap
+ outspec.attribute ("openexr:levelmode", 0 /* ONE_LEVEL */);
+ }
+
+ if (mipmap && ! strcmp (out->format_name(), "openexr")) {
+ outspec.attribute ("openexr:roundingmode", 0 /* ROUND_DOWN */);
+ }
+
+ // OpenEXR always uses border sampling for environment maps
+ bool src_samples_border;
+ if (envlatlmode && !strcmp(out->format_name(), "openexr")) {
+ src_samples_border = true;
+ outspec.attribute ("oiio:updirection", "y");
+ outspec.attribute ("oiio:sampleborder", 1);
+ }
+ if (envlatlmode && src_samples_border)
+ fix_latl_edges (img);
+
+ Timer writetimer;
+ if (! out->open (outputfilename.c_str(), outspec)) {
+ outstream << "maketx ERROR: Could not open \"" << outputfilename
+ << "\" : " << out->geterror() << "\n";
+ return false;
}
- if (! Filesystem::exists (filenames[0])) {
- std::cerr << "maketx ERROR: \"" << filenames[0] << "\" does not exist\n";
- exit (EXIT_FAILURE);
+ // Write out the image
+ bool verbose = configspec.get_int_attribute ("maketx:verbose");
+ if (verbose) {
+ outstream << " Writing file: " << outputfilename << std::endl;
+ outstream << " Filter \"" << filter->name() << "\" width = "
+ << filter->width() << "\n";
+ outstream << " Top level is " << formatres(outspec) << std::endl;
}
- if (outputfilename.empty())
- outputfilename = Filesystem::replace_extension (filenames[0], ".tx");
+
+ if (! img.write (out)) {
+ // ImageBuf::write transfers any errors from the ImageOutput to
+ // the ImageBuf.
+ outstream << "maketx ERROR: Write failed \" : " << img.geterror() << "\n";
+ out->close ();
+ return false;
+ }
+
+ stat_writetime += writetimer();
+
+ if (mipmap) { // Mipmap levels:
+ if (verbose)
+ outstream << " Mipmapping...\n" << std::flush;
+ std::vector<std::string> mipimages;
+ std::string mipimages_unsplit = configspec.get_string_attribute ("maketx:mipimages");
+ if (mipimages_unsplit.length())
+ Strutil::split (mipimages_unsplit, mipimages, ";");
+ ImageBuf tmp;
+ ImageBuf *big = &img, *small = &tmp;
+ while (outspec.width > 1 || outspec.height > 1) {
+ Timer miptimer;
+ ImageSpec smallspec;
+
+ if (mipimages.size()) {
+ // Special case -- the user specified a custom MIP level
+ small->reset (mipimages[0]);
+ small->read (0, 0, true, TypeDesc::FLOAT);
+ smallspec = small->spec();
+ if (smallspec.nchannels != outspec.nchannels) {
+ outstream << "WARNING: Custom mip level \"" << mipimages[0]
+ << " had the wrong number of channels.\n";
+ ImageBuf *t = new ImageBuf (mipimages[0], smallspec);
+ ImageBufAlgo::setNumChannels(*t, *small, outspec.nchannels);
+ std::swap (t, small);
+ delete t;
+ }
+ smallspec.tile_width = outspec.tile_width;
+ smallspec.tile_height = outspec.tile_height;
+ smallspec.tile_depth = outspec.tile_depth;
+ mipimages.erase (mipimages.begin());
+ } else {
+ // Resize a factor of two smaller
+ smallspec = outspec;
+ smallspec.width = big->spec().width;
+ smallspec.height = big->spec().height;
+ smallspec.depth = big->spec().depth;
+ if (smallspec.width > 1)
+ smallspec.width /= 2;
+ if (smallspec.height > 1)
+ smallspec.height /= 2;
+ smallspec.full_width = smallspec.width;
+ smallspec.full_height = smallspec.height;
+ smallspec.full_depth = smallspec.depth;
+ smallspec.set_format (TypeDesc::FLOAT);
+
+ // Trick: to get the resize working properly, we reset
+ // both display and pixel windows to match, and have 0
+ // offset, AND doctor the big image to have its display
+ // and pixel windows match. Don't worry, the texture
+ // engine doesn't care what the upper MIP levels have
+ // for the window sizes, it uses level 0 to determine
+ // the relatinship between texture 0-1 space (display
+ // window) and the pixels.
+ smallspec.x = 0;
+ smallspec.y = 0;
+ smallspec.full_x = 0;
+ smallspec.full_y = 0;
+ small->alloc (smallspec); // Realocate with new size
+ big->set_full (big->xbegin(), big->xend(), big->ybegin(),
+ big->yend(), big->zbegin(), big->zend());
+
+ if (filter->name() == "box" && filter->width() == 1.0f)
+ ImageBufAlgo::parallel_image (boost::bind(resize_block, small, big, _1, envlatlmode),
+ OIIO::get_roi(small->spec()));
+ else
+ ImageBufAlgo::parallel_image (boost::bind(resize_block_HQ, small, big, _1, filter),
+ OIIO::get_roi(small->spec()));
+ }
+
+ stat_miptime += miptimer();
+ outspec = smallspec;
+ outspec.set_format (outputdatatype);
+ if (envlatlmode && src_samples_border)
+ fix_latl_edges (*small);
+
+ Timer writetimer;
+ // If the format explicitly supports MIP-maps, use that,
+ // otherwise try to simulate MIP-mapping with multi-image.
+ ImageOutput::OpenMode mode = out->supports ("mipmap") ?
+ ImageOutput::AppendMIPLevel : ImageOutput::AppendSubimage;
+ if (! out->open (outputfilename.c_str(), outspec, mode)) {
+ outstream << "maketx ERROR: Could not append \"" << outputfilename
+ << "\" : " << out->geterror() << "\n";
+ return false;
+ }
+ if (! small->write (out)) {
+ // ImageBuf::write transfers any errors from the
+ // ImageOutput to the ImageBuf.
+ outstream << "maketx ERROR writing \"" << outputfilename
+ << "\" : " << small->geterror() << "\n";
+ out->close ();
+ return false;
+ }
+ stat_writetime += writetimer();
+ if (verbose) {
+ outstream << " " << formatres(smallspec) << std::endl;
+ }
+ std::swap (big, small);
+ }
+ }
+
+ if (verbose)
+ outstream << " Wrote file: " << outputfilename << std::endl;
+ writetimer.reset ();
+ writetimer.start ();
+ if (! out->close ()) {
+ outstream << "maketx ERROR writing \"" << outputfilename
+ << "\" : " << out->geterror() << "\n";
+ return false;
+ }
+ stat_writetime += writetimer ();
+ return true;
+}
+
+
+
+bool
+ImageBufAlgo::make_texture (ImageBufAlgo::MakeTextureMode mode,
+ const std::string &filename,
+ const std::string &outputfilename,
+ const ImageSpec &configspec,
+ std::ostream *outstream)
+{
+ std::vector<std::string> filenames;
+ filenames.push_back (filename);
+ return make_texture (mode, filenames, outputfilename, configspec, outstream);
+}
+
+
+
+bool
+ImageBufAlgo::make_texture (ImageBufAlgo::MakeTextureMode mode,
+ const std::vector<std::string> &filenames,
+ const std::string &_outputfilename,
+ const ImageSpec &_configspec,
+ std::ostream *outstream_ptr)
+{
+ ASSERT (mode >= 0 && mode < ImageBufAlgo::_MakeTxLast);
+ Timer alltime;
+ ImageSpec configspec = _configspec;
+// const char *modenames[] = { "texture map", "shadow map",
+// "latlong environment map" };
+ std::stringstream localstream; // catch output when user doesn't want it
+ std::ostream &outstream (outstream_ptr ? *outstream_ptr : localstream);
+
+ double stat_readtime = 0;
+ double stat_writetime = 0;
+ double stat_resizetime = 0;
+ double stat_miptime = 0;
+ double stat_colorconverttime = 0;
+
+ std::string filename = filenames[0];
+ if (! Filesystem::exists (filename)) {
+ outstream << "maketx ERROR: \"" << filename << "\" does not exist\n";
+ return false;
+ }
+ std::string outputfilename = _outputfilename.length() ? _outputfilename
+ : Filesystem::replace_extension (filename, ".tx");
// When was the input file last modified?
- std::time_t in_time = Filesystem::last_write_time (filenames[0]);
+ std::time_t in_time = Filesystem::last_write_time (filename);
// When in update mode, skip making the texture if the output already
// exists and has the same file modification time as the input file.
+ bool updatemode = configspec.get_int_attribute ("maketx:updatemode");
if (updatemode && Filesystem::exists (outputfilename) &&
(in_time == Filesystem::last_write_time (outputfilename))) {
- std::cout << "maketx: no update required for \""
+ outstream << "maketx: no update required for \""
<< outputfilename << "\"\n";
- return;
+ return true;
}
+ bool shadowmode = (mode == ImageBufAlgo::MakeTxShadow);
+ bool envlatlmode = (mode == ImageBufAlgo::MakeTxEnvLatl);
// Find an ImageIO plugin that can open the output file, and open it
- std::string outformat = fileformatname.empty() ? outputfilename : fileformatname;
+ std::string outformat = configspec.get_string_attribute ("maketx:fileformatname",
+ outputfilename);
ImageOutput *out = ImageOutput::create (outformat.c_str());
if (! out) {
- std::cerr
+ outstream
<< "maketx ERROR: Could not find an ImageIO plugin to write "
<< outformat << " files:" << geterror() << "\n";
- exit (EXIT_FAILURE);
+ return false;
}
if (! out->supports ("tiles")) {
- std::cerr << "maketx ERROR: \"" << outputfilename
+ outstream << "maketx ERROR: \"" << outputfilename
<< "\" format does not support tiled images\n";
- exit (EXIT_FAILURE);
+ return false;
}
- ImageBuf src (filenames[0]);
- src.init_spec (filenames[0], 0, 0); // force it to get the spec, not read
+ ImageBuf src (filename);
+ src.init_spec (filename, 0, 0); // force it to get the spec, not read
// The cache might mess with the apparent data format. But for the
// purposes of what we should output, figure it out now, before the
// file has been read and cached.
TypeDesc out_dataformat = src.spec().format;
- // Figure out which data format we want for output
- if (! dataformatname.empty()) {
- if (dataformatname == "uint8")
- out_dataformat = TypeDesc::UINT8;
- else if (dataformatname == "int8" || dataformatname == "sint8")
- out_dataformat = TypeDesc::INT8;
- else if (dataformatname == "uint16")
- out_dataformat = TypeDesc::UINT16;
- else if (dataformatname == "int16" || dataformatname == "sint16")
- out_dataformat = TypeDesc::INT16;
- else if (dataformatname == "half")
- out_dataformat = TypeDesc::HALF;
- else if (dataformatname == "float")
- out_dataformat = TypeDesc::FLOAT;
- else if (dataformatname == "double")
- out_dataformat = TypeDesc::DOUBLE;
- }
-
+ if (configspec.format != TypeDesc::UNKNOWN)
+ out_dataformat = configspec.format;
// We cannot compute the prman / oiio options until after out_dataformat
// has been determined, as it's required (and can potentially change
// out_dataformat too!)
-
- if (prman) out_dataformat = set_prman_options (out_dataformat);
- else if (oiio) out_dataformat = set_oiio_options (out_dataformat);
-
+ if (configspec.get_int_attribute("maketx:prman_options"))
+ out_dataformat = set_prman_options (out_dataformat, configspec);
+ else if (configspec.get_int_attribute("maketx:oiio_options"))
+ out_dataformat = set_oiio_options (out_dataformat, configspec);
+
// Read the full file locally if it's less than 1 GB, otherwise
// allow the ImageBuf to use ImageCache to manage memory.
bool read_local = (src.spec().image_bytes() < size_t(1024*1024*1024));
+ bool verbose = configspec.get_int_attribute ("maketx:verbose");
if (verbose)
- std::cout << "Reading file: " << filenames[0] << std::endl;
+ outstream << "Reading file: " << filename << std::endl;
Timer readtimer;
if (! src.read (0, 0, read_local)) {
- std::cerr
+ outstream
<< "maketx ERROR: Could not read \""
- << filenames[0] << "\" : " << src.geterror() << "\n";
- exit (EXIT_FAILURE);
+ << filename << "\" : " << src.geterror() << "\n";
+ return false;
}
stat_readtime += readtimer();
@@ -763,7 +667,7 @@ make_texturemap (const char *maptypename = "texture map")
// wrap mode at runtime.
std::vector<float> constantColor(src.nchannels());
bool isConstantColor = false;
- if (constant_color_detect &&
+ if (configspec.get_int_attribute("maketx:constant_color_detect") &&
src.spec().x == 0 && src.spec().y == 0 && src.spec().z == 0 &&
src.spec().full_x == 0 && src.spec().full_y == 0 &&
src.spec().full_z == 0 && src.spec().full_width == src.spec().width &&
@@ -773,9 +677,9 @@ make_texturemap (const char *maptypename = "texture map")
if (isConstantColor) {
// Reset the image, to a new image, at the tile size
ImageSpec newspec = src.spec();
- newspec.width = std::min (tile[0], src.spec().width);
- newspec.height = std::min (tile[1], src.spec().height);
- newspec.depth = std::min (tile[2], src.spec().depth);
+ newspec.width = std::min (configspec.tile_width, src.spec().width);
+ newspec.height = std::min (configspec.tile_height, src.spec().height);
+ newspec.depth = std::min (configspec.tile_depth, src.spec().depth);
newspec.full_width = newspec.width;
newspec.full_height = newspec.height;
newspec.full_depth = newspec.depth;
@@ -783,33 +687,37 @@ make_texturemap (const char *maptypename = "texture map")
src.reset(name, newspec);
ImageBufAlgo::fill (src, &constantColor[0]);
if (verbose) {
- std::cout << " Constant color image detected. ";
- std::cout << "Creating " << newspec.width << "x" << newspec.height << " texture instead.\n";
+ outstream << " Constant color image detected. ";
+ outstream << "Creating " << newspec.width << "x" << newspec.height << " texture instead.\n";
}
}
}
+ int nchannels = configspec.get_int_attribute ("maketx:nchannels", -1);
+
// If requested -- and alpha is 1.0 everywhere -- drop it.
- if (opaque_detect && src.spec().alpha_channel == src.nchannels()-1 &&
- nchannels < 0 &&
+ if (configspec.get_int_attribute("maketx:opaque_detect") &&
+ src.spec().alpha_channel == src.nchannels()-1 &&
+ nchannels <= 0 &&
ImageBufAlgo::isConstantChannel(src,src.spec().alpha_channel,1.0f)) {
ImageBuf newsrc(src.name() + ".noalpha", src.spec());
ImageBufAlgo::setNumChannels (newsrc, src, src.nchannels()-1);
src.copy (newsrc);
if (verbose) {
- std::cout << " Alpha==1 image detected. Dropping the alpha channel.\n";
+ outstream << " Alpha==1 image detected. Dropping the alpha channel.\n";
}
}
// If requested - and we're a monochrome image - drop the extra channels
- if (monochrome_detect && nchannels < 0 &&
+ if (configspec.get_int_attribute("maketx:monochrome_detect") &&
+ nchannels <= 0 &&
src.nchannels() == 3 && src.spec().alpha_channel < 0 && // RGB only
ImageBufAlgo::isMonochrome(src)) {
ImageBuf newsrc(src.name() + ".monochrome", src.spec());
ImageBufAlgo::setNumChannels (newsrc, src, 1);
src.copy (newsrc);
if (verbose) {
- std::cout << " Monochrome image detected. Converting to single channel texture.\n";
+ outstream << " Monochrome image detected. Converting to single channel texture.\n";
}
}
@@ -820,17 +728,17 @@ make_texturemap (const char *maptypename = "texture map")
ImageBufAlgo::setNumChannels (newsrc, src, nchannels);
src.copy (newsrc);
if (verbose) {
- std::cout << " Overriding number of channels to " << nchannels << "\n";
+ outstream << " Overriding number of channels to " << nchannels << "\n";
}
}
if (shadowmode) {
// Some special checks for shadow maps
if (src.spec().nchannels != 1) {
- std::cerr << "maketx ERROR: shadow maps require 1-channel images,\n"
- << "\t\"" << filenames[0] << "\" is "
+ outstream << "maketx ERROR: shadow maps require 1-channel images,\n"
+ << "\t\"" << filename << "\" is "
<< src.spec().nchannels << " channels\n";
- exit (EXIT_FAILURE);
+ return false;
}
// Shadow maps only make sense for floating-point data.
if (out_dataformat != TypeDesc::FLOAT &&
@@ -839,7 +747,7 @@ make_texturemap (const char *maptypename = "texture map")
out_dataformat = TypeDesc::FLOAT;
}
- if (set_full_to_pixels) {
+ if (configspec.get_int_attribute("maketx:set_full_to_pixels")) {
// User requested that we treat the image as uncropped or not
// overscan
ImageSpec &spec (src.specmod());
@@ -882,10 +790,8 @@ make_texturemap (const char *maptypename = "texture map")
dstspec.full_height = dstspec.height;
dstspec.full_depth = dstspec.depth;
}
- if (orig_was_overscan) {
- swrap = "black";
- twrap = "black";
- }
+ if (orig_was_overscan)
+ configspec.attribute ("wrapmodes", "black,black");
if ((dstspec.x < 0 || dstspec.y < 0 || dstspec.z < 0) &&
(out && !out->supports("negativeorigin"))) {
@@ -907,13 +813,18 @@ make_texturemap (const char *maptypename = "texture map")
}
// Make the output tiled, regardless of input
- dstspec.tile_width = tile[0];
- dstspec.tile_height = tile[1];
- dstspec.tile_depth = tile[2];
-
- dstspec.attribute ("compression", compression);
-
- if (ignore_unassoc)
+ dstspec.tile_width = configspec.tile_width ? configspec.tile_width : 64;
+ dstspec.tile_height = configspec.tile_height ? configspec.tile_height : 64;
+ dstspec.tile_depth = configspec.tile_depth ? configspec.tile_depth : 1;
+
+ // Try to force zip (still can be overriden by configspec
+ dstspec.attribute ("compression", "zip");
+ // Always prefer contiguous channels, unless overridden by configspec
+ dstspec.attribute ("planarconfig", "contig");
+ // Default to black wrap mode, unless overridden by configspec
+ dstspec.attribute ("wrapmodes", "black,black");
+
+ if (configspec.get_int_attribute ("maketx:ignore_unassoc"))
dstspec.erase_attribute ("oiio:UnassociatedAlpha");
// Put a DateTime in the out file, either now, or matching the date
@@ -925,57 +836,32 @@ make_texturemap (const char *maptypename = "texture map")
time (&date); // not update: get the time now
dstspec.attribute ("DateTime", datestring(date));
- std::string software = Strutil::format ("OpenImageIO %s : %s",
- OIIO_VERSION_STRING, full_command_line);
- dstspec.attribute ("Software", software);
+ std::string cmdline = configspec.get_string_attribute ("maketx:full_command_line");
+ if (! cmdline.empty()) {
+ // Append command to image history
+ std::string history = dstspec.get_string_attribute ("Exif:ImageHistory");
+ if (history.length() && ! Strutil::iends_with (history, "\n"))
+ history += std::string("\n");
+ history += cmdline;
+ dstspec.attribute ("Exif:ImageHistory", history);
+ }
- // Append command to image history
- std::string history = dstspec.get_string_attribute ("Exif:ImageHistory");
- if (history.length() && ! Strutil::iends_with (history, "\n"))
- history += std::string("\n");
- history += full_command_line;
- dstspec.attribute ("Exif:ImageHistory", history);
-
+ bool prman_metadata = configspec.get_int_attribute ("maketx:prman_metadata");
if (shadowmode) {
dstspec.attribute ("textureformat", "Shadow");
if (prman_metadata)
dstspec.attribute ("PixarTextureFormat", "Shadow");
} else if (envlatlmode) {
dstspec.attribute ("textureformat", "LatLong Environment");
- swrap = "periodic";
- twrap = "clamp";
+ configspec.attribute ("wrapmodes", "periodic,clamp");
if (prman_metadata)
dstspec.attribute ("PixarTextureFormat", "Latlong Environment");
} else {
dstspec.attribute ("textureformat", "Plain Texture");
- if(prman_metadata)
+ if (prman_metadata)
dstspec.attribute ("PixarTextureFormat", "Plain Texture");
}
- if (Mcam != Imath::M44f(0.0f))
- dstspec.attribute ("worldtocamera", TypeDesc::TypeMatrix, &Mcam);
- if (Mscr != Imath::M44f(0.0f))
- dstspec.attribute ("worldtoscreen", TypeDesc::TypeMatrix, &Mscr);
-
- // FIXME - check for valid strings in the wrap mode
- if (! shadowmode) {
- std::string wrapmodes = (swrap.size() ? swrap : wrap) + ',' +
- (twrap.size() ? twrap : wrap);
- dstspec.attribute ("wrapmodes", wrapmodes);
- }
-
- if(fovcot == 0.0f) {
- fovcot = static_cast<float>(srcspec.full_width) /
- static_cast<float>(srcspec.full_height);
- }
- dstspec.attribute ("fovcot", fovcot);
-
- if (separate)
- dstspec.attribute ("planarconfig", "separate");
- else {
- dstspec.erase_attribute("planarconfig");
- dstspec.erase_attribute("tiff:planarconfig");
- }
// FIXME -- should we allow tile sizes to reduce if the image is
// smaller than the tile size? And when we do, should we also try
// to make it bigger in the other direction to make the total tile
@@ -983,39 +869,40 @@ make_texturemap (const char *maptypename = "texture map")
// If --checknan was used and it's a floating point image, check for
// nonfinite (NaN or Inf) values and abort if they are found.
- if (checknan && (srcspec.format.basetype == TypeDesc::FLOAT ||
+ if (configspec.get_int_attribute("maketx:checknan") &&
+ (srcspec.format.basetype == TypeDesc::FLOAT ||
srcspec.format.basetype == TypeDesc::HALF ||
srcspec.format.basetype == TypeDesc::DOUBLE)) {
- found_nonfinite = false;
- parallel_image (check_nan_block, &src, &src,
- dstspec.x, dstspec.x+dstspec.width,
- dstspec.y, dstspec.y+dstspec.height, nthreads);
+ int found_nonfinite = 0;
+ ImageBufAlgo::parallel_image (boost::bind(check_nan_block, &src, _1, boost::ref(found_nonfinite)),
+ OIIO::get_roi(dstspec));
if (found_nonfinite) {
if (found_nonfinite > 3)
- std::cerr << "maketx ERROR: ...and Nan/Inf at "
+ outstream << "maketx ERROR: ...and Nan/Inf at "
<< (found_nonfinite-3) << " other pixels\n";
- exit (EXIT_FAILURE);
+ return false;
}
}
// Fix nans/infs (if requested
ImageBufAlgo::NonFiniteFixMode fixmode = ImageBufAlgo::NONFINITE_NONE;
+ std::string fixnan = configspec.get_string_attribute("maketx:fixnan");
if (fixnan.empty() || fixnan == "none") { }
else if (fixnan == "black") { fixmode = ImageBufAlgo::NONFINITE_BLACK; }
else if (fixnan == "box3") { fixmode = ImageBufAlgo::NONFINITE_BOX3; }
else {
- std::cerr << "maketx ERROR: Unknown --fixnan mode " << " fixnan\n";
- exit (EXIT_FAILURE);
+ outstream << "maketx ERROR: Unknown --fixnan mode " << " fixnan\n";
+ return false;
}
int pixelsFixed = 0;
if (!ImageBufAlgo::fixNonFinite (src, src, fixmode, &pixelsFixed)) {
- std::cerr << "maketx ERROR: Error fixing nans/infs.\n";
- exit (EXIT_FAILURE);
+ outstream << "maketx ERROR: Error fixing nans/infs.\n";
+ return false;
}
if (verbose && pixelsFixed>0) {
- std::cout << " Warning: " << pixelsFixed << " nan/inf pixels fixed.\n";
+ outstream << " Warning: " << pixelsFixed << " nan/inf pixels fixed.\n";
}
@@ -1026,6 +913,8 @@ make_texturemap (const char *maptypename = "texture map")
// independently color convert the constant color metadata
ImageBuf * ccSrc = &src; // Ptr to cc'd src image
ImageBuf colorBuffer;
+ std::string incolorspace = configspec.get_string_attribute ("incolorspace");
+ std::string outcolorspace = configspec.get_string_attribute ("outcolorspace");
if (!incolorspace.empty() && !outcolorspace.empty() && incolorspace != outcolorspace) {
if (src.spec().format != TypeDesc::FLOAT) {
ImageSpec floatSpec = src.spec();
@@ -1035,39 +924,41 @@ make_texturemap (const char *maptypename = "texture map")
}
Timer colorconverttimer;
+ ColorConfig colorconfig;
if (verbose) {
- std::cout << " Converting from colorspace " << incolorspace
+ outstream << " Converting from colorspace " << incolorspace
<< " to colorspace " << outcolorspace << std::endl;
}
if (colorconfig.error()) {
- std::cerr << "Error Creating ColorConfig\n";
- std::cerr << colorconfig.geterror() << std::endl;
- exit (EXIT_FAILURE);
+ outstream << "Error Creating ColorConfig\n";
+ outstream << colorconfig.geterror() << std::endl;
+ return false;
}
ColorProcessor * processor = colorconfig.createColorProcessor (
incolorspace.c_str(), outcolorspace.c_str());
if (!processor || colorconfig.error()) {
- std::cerr << "Error Creating Color Processor." << std::endl;
- std::cerr << colorconfig.geterror() << std::endl;
- exit (EXIT_FAILURE);
+ outstream << "Error Creating Color Processor." << std::endl;
+ outstream << colorconfig.geterror() << std::endl;
+ return false;
}
+ bool unpremult = configspec.get_int_attribute ("maketx:unpremult");
if (unpremult && verbose)
- std::cout << " Unpremulting image..." << std::endl;
+ outstream << " Unpremulting image..." << std::endl;
if (!ImageBufAlgo::colorconvert (*ccSrc, src, processor, unpremult)) {
- std::cerr << "Error applying color conversion to image.\n";
- exit (EXIT_FAILURE);
+ outstream << "Error applying color conversion to image.\n";
+ return false;
}
if (isConstantColor) {
if (!ImageBufAlgo::colorconvert (&constantColor[0],
static_cast<int>(constantColor.size()), processor, unpremult)) {
- std::cerr << "Error applying color conversion to constant color.\n";
- exit (EXIT_FAILURE);
+ outstream << "Error applying color conversion to constant color.\n";
+ return false;
}
}
@@ -1080,7 +971,7 @@ make_texturemap (const char *maptypename = "texture map")
dstspec.set_format (TypeDesc::FLOAT);
// Handle resize to power of two, if called for
- if (doresize && ! shadowmode) {
+ if (configspec.get_int_attribute("maketx:resize") && ! shadowmode) {
dstspec.width = pow2roundup (dstspec.width);
dstspec.height = pow2roundup (dstspec.height);
dstspec.full_width = dstspec.width;
@@ -1096,18 +987,26 @@ make_texturemap (const char *maptypename = "texture map")
if (orig_was_crop)
do_resize = true;
// resize if we're converting from non-border sampling to border sampling
- if (envlatlmode && ! src_samples_border &&
- (Strutil::iequals(fileformatname,"openexr") ||
+ // (converting TO an OpenEXR environment map).
+ if (envlatlmode &&
+ (Strutil::iequals(configspec.get_string_attribute("maketx:fileformatname"),"openexr") ||
Strutil::iends_with(outputfilename,".exr")))
do_resize = true;
if (do_resize && orig_was_overscan &&
out && !out->supports("displaywindow")) {
- std::cerr << "maketx ERROR: format " << out->format_name()
+ outstream << "maketx ERROR: format " << out->format_name()
<< " does not support separate display windows,\n"
<< " which is necessary when combining resizing"
<< " and an input image with overscan.";
- exit (EXIT_FAILURE);
+ return false;
+ }
+
+ std::string filtername = configspec.get_string_attribute ("maketx:filtername", "box");
+ Filter2D *filter = setup_filter (filtername);
+ if (! filter) {
+ outstream << "maketx ERROR: could not make filter '" << filtername << "\n";
+ return false;
}
Timer resizetimer;
@@ -1120,23 +1019,20 @@ make_texturemap (const char *maptypename = "texture map")
// the original copy.
toplevel = ccSrc;
} else {
- parallel_image (copy_block, &dst, ccSrc,
- dstspec.x, dstspec.x+dstspec.width,
- dstspec.y, dstspec.y+dstspec.height, nthreads);
+ ImageBufAlgo::parallel_image (boost::bind(copy_block,&dst,ccSrc,_1),
+ OIIO::get_roi(dstspec));
}
} else {
// Resize
if (verbose)
- std::cout << " Resizing image to " << dstspec.width
+ outstream << " Resizing image to " << dstspec.width
<< " x " << dstspec.height << std::endl;
if (filtername == "box" && filter->width() == 1.0f)
- parallel_image (resize_block, &dst, ccSrc,
- dstspec.x, dstspec.x+dstspec.width,
- dstspec.y, dstspec.y+dstspec.height, nthreads);
+ ImageBufAlgo::parallel_image (boost::bind(resize_block, &dst, ccSrc, _1, envlatlmode),
+ OIIO::get_roi(dstspec));
else
- parallel_image (resize_block_HQ, &dst, ccSrc,
- dstspec.x, dstspec.x+dstspec.width,
- dstspec.y, dstspec.y+dstspec.height, nthreads);
+ ImageBufAlgo::parallel_image (boost::bind(resize_block_HQ, &dst, ccSrc, _1, filter),
+ OIIO::get_roi(dstspec));
}
stat_resizetime += resizetimer();
@@ -1172,7 +1068,7 @@ make_texturemap (const char *maptypename = "texture map")
desc += "SHA-1=";
desc += hash_digest;
if (verbose)
- std::cout << " SHA-1: " << hash_digest << std::endl;
+ outstream << " SHA-1: " << hash_digest << std::endl;
updatedDesc = true;
dstspec.attribute ("oiio:SHA-1", hash_digest);
}
@@ -1191,7 +1087,7 @@ make_texturemap (const char *maptypename = "texture map")
desc += "ConstantColor=";
desc += os.str();
if (verbose)
- std::cout << " ConstantColor: " << os.str() << std::endl;
+ outstream << " ConstantColor: " << os.str() << std::endl;
updatedDesc = true;
dstspec.attribute ("oiio:ConstantColor", os.str());
}
@@ -1200,247 +1096,44 @@ make_texturemap (const char *maptypename = "texture map")
dstspec.attribute ("ImageDescription", desc);
}
+
+ if (configspec.get_float_attribute("fovcot") == 0.0f)
+ configspec.attribute("fovcot", float(srcspec.full_width) /
+ float(srcspec.full_height));
+
+
+ maketx_merge_spec (dstspec, configspec);
+
// Write out, and compute, the mipmap levels for the speicifed image
- write_mipmap (*toplevel, dstspec, outputfilename,
- out, out_dataformat, !shadowmode && !nomipmap);
+ bool nomipmap = configspec.get_int_attribute ("maketx:nomipmap");
+ bool ok = write_mipmap (mode, *toplevel, dstspec, outputfilename,
+ out, out_dataformat, !shadowmode && !nomipmap,
+ filter, configspec, outstream,
+ stat_writetime, stat_miptime);
delete out; // don't need it any more
// If using update mode, stamp the output file with a modification time
// matching that of the input file.
- if (updatemode)
+ if (ok && updatemode)
Filesystem::last_write_time (outputfilename, in_time);
-}
-
-
-
-static void
-write_mipmap (ImageBuf &img, const ImageSpec &outspec_template,
- std::string outputfilename, ImageOutput *out,
- TypeDesc outputdatatype, bool mipmap)
-{
- ImageSpec outspec = outspec_template;
- outspec.set_format (outputdatatype);
-
- if (mipmap && !out->supports ("multiimage") && !out->supports ("mipmap")) {
- std::cerr << "maketx ERROR: \"" << outputfilename
- << "\" format does not support multires images\n";
- exit (EXIT_FAILURE);
- }
- if (! mipmap && ! strcmp (out->format_name(), "openexr")) {
- // Send hint to OpenEXR driver that we won't specify a MIPmap
- outspec.attribute ("openexr:levelmode", 0 /* ONE_LEVEL */);
- }
-
- if (mipmap && ! strcmp (out->format_name(), "openexr")) {
- outspec.attribute ("openexr:roundingmode", 0 /* ROUND_DOWN */);
- }
-
- // OpenEXR always uses border sampling for environment maps
- if ((envlatlmode || envcubemode) &&
- !strcmp(out->format_name(), "openexr")) {
- src_samples_border = true;
- outspec.attribute ("oiio:updirection", "y");
- outspec.attribute ("oiio:sampleborder", 1);
- }
- if (envlatlmode && src_samples_border)
- fix_latl_edges (img);
-
- Timer writetimer;
- if (! out->open (outputfilename.c_str(), outspec)) {
- std::cerr << "maketx ERROR: Could not open \"" << outputfilename
- << "\" : " << out->geterror() << "\n";
- exit (EXIT_FAILURE);
- }
-
- // Write out the image
- if (verbose) {
- std::cout << " Writing file: " << outputfilename << std::endl;
- std::cout << " Filter \"" << filter->name() << "\" width = "
- << filter->width() << "\n";
- std::cout << " Top level is " << formatres(outspec) << std::endl;
- }
-
- if (! img.write (out)) {
- // ImageBuf::write transfers any errors from the ImageOutput to
- // the ImageBuf.
- std::cerr << "maketx ERROR: Write failed \" : " << img.geterror() << "\n";
- out->close ();
- exit (EXIT_FAILURE);
- }
-
- stat_writetime += writetimer();
-
- if (mipmap) { // Mipmap levels:
- if (verbose)
- std::cout << " Mipmapping...\n" << std::flush;
- ImageBuf tmp;
- ImageBuf *big = &img, *small = &tmp;
- while (outspec.width > 1 || outspec.height > 1) {
- Timer miptimer;
- ImageSpec smallspec;
-
- if (mipimages.size()) {
- // Special case -- the user specified a custom MIP level
- small->reset (mipimages[0]);
- small->read (0, 0, true, TypeDesc::FLOAT);
- smallspec = small->spec();
- if (smallspec.nchannels != outspec.nchannels) {
- std::cout << "WARNING: Custom mip level \"" << mipimages[0]
- << " had the wrong number of channels.\n";
- ImageBuf *t = new ImageBuf (mipimages[0], smallspec);
- ImageBufAlgo::setNumChannels(*t, *small, outspec.nchannels);
- std::swap (t, small);
- delete t;
- }
- smallspec.tile_width = outspec.tile_width;
- smallspec.tile_height = outspec.tile_height;
- smallspec.tile_depth = outspec.tile_depth;
- mipimages.erase (mipimages.begin());
- } else {
- // Resize a factor of two smaller
- smallspec = outspec;
- smallspec.width = big->spec().width;
- smallspec.height = big->spec().height;
- smallspec.depth = big->spec().depth;
- if (smallspec.width > 1)
- smallspec.width /= 2;
- if (smallspec.height > 1)
- smallspec.height /= 2;
- smallspec.full_width = smallspec.width;
- smallspec.full_height = smallspec.height;
- smallspec.full_depth = smallspec.depth;
- smallspec.set_format (TypeDesc::FLOAT);
-
- // Trick: to get the resize working properly, we reset
- // both display and pixel windows to match, and have 0
- // offset, AND doctor the big image to have its display
- // and pixel windows match. Don't worry, the texture
- // engine doesn't care what the upper MIP levels have
- // for the window sizes, it uses level 0 to determine
- // the relatinship between texture 0-1 space (display
- // window) and the pixels.
- smallspec.x = 0;
- smallspec.y = 0;
- smallspec.full_x = 0;
- smallspec.full_y = 0;
- small->alloc (smallspec); // Realocate with new size
- big->set_full (big->xbegin(), big->xend(), big->ybegin(),
- big->yend(), big->zbegin(), big->zend());
-
- if (filtername == "box" && filter->width() == 1.0f)
- parallel_image (resize_block, small, big,
- small->xbegin(), small->xend(),
- small->ybegin(), small->yend(),
- nthreads);
- else
- parallel_image (resize_block_HQ, small, big,
- small->xbegin(), small->xend(),
- small->ybegin(), small->yend(),
- nthreads);
- }
-
- stat_miptime += miptimer();
- outspec = smallspec;
- outspec.set_format (outputdatatype);
- if (envlatlmode && src_samples_border)
- fix_latl_edges (*small);
-
- Timer writetimer;
- // If the format explicitly supports MIP-maps, use that,
- // otherwise try to simulate MIP-mapping with multi-image.
- ImageOutput::OpenMode mode = out->supports ("mipmap") ?
- ImageOutput::AppendMIPLevel : ImageOutput::AppendSubimage;
- if (! out->open (outputfilename.c_str(), outspec, mode)) {
- std::cerr << "maketx ERROR: Could not append \"" << outputfilename
- << "\" : " << out->geterror() << "\n";
- exit (EXIT_FAILURE);
- }
- if (! small->write (out)) {
- // ImageBuf::write transfers any errors from the
- // ImageOutput to the ImageBuf.
- std::cerr << "maketx ERROR writing \"" << outputfilename
- << "\" : " << small->geterror() << "\n";
- out->close ();
- exit (EXIT_FAILURE);
- }
- stat_writetime += writetimer();
- if (verbose) {
- std::cout << " " << formatres(smallspec) << std::endl;
- }
- std::swap (big, small);
- }
- }
-
- if (verbose)
- std::cout << " Wrote file: " << outputfilename << std::endl;
- writetimer.reset ();
- writetimer.start ();
- if (! out->close ()) {
- std::cerr << "maketx ERROR writing \"" << outputfilename
- << "\" : " << out->geterror() << "\n";
- exit (EXIT_FAILURE);
- }
- stat_writetime += writetimer ();
-}
-
-
-
-int
-main (int argc, char *argv[])
-{
- Timer alltimer;
- getargs (argc, argv);
-
- OIIO::attribute ("threads", nthreads);
-
- // N.B. This will apply to the default IC that any ImageBuf's get.
- ImageCache *ic = ImageCache::create (); // get the shared one
- ic->attribute ("forcefloat", 1); // Force float upon read
- ic->attribute ("max_memory_MB", 1024.0); // 1 GB cache
- ic->attribute ("unassociatedalpha", (int)ignore_unassoc);
-
- if (mipmapmode) {
- make_texturemap ("texture map");
- } else if (shadowmode) {
- make_texturemap ("shadow map");
- } else if (shadowcubemode) {
- std::cerr << "Shadow cubes currently unsupported\n";
- } else if (volshadowmode) {
- std::cerr << "Volume shadows currently unsupported\n";
- } else if (envlatlmode) {
- make_texturemap ("latlong environment map");
- } else if (envcubemode) {
- std::cerr << "Environment cubes currently unsupported\n";
- } else if (lightprobemode) {
- std::cerr << "Light probes currently unsupported\n";
- } else if (vertcrossmode) {
- std::cerr << "Vertcross currently unsupported\n";
- } else if (latl2envcubemode) {
- std::cerr << "Latlong->cube conversion currently unsupported\n";
- }
+ Filter2D::destroy (filter);
- if (verbose || stats) {
- std::cout << "maketx Runtime statistics (seconds):\n";
- double alltime = alltimer();
- std::cout << Strutil::format (" total runtime: %5.2f\n", alltime);
- std::cout << Strutil::format (" file read: %5.2f\n", stat_readtime);
- std::cout << Strutil::format (" file write: %5.2f\n", stat_writetime);
- std::cout << Strutil::format (" initial resize: %5.2f\n", stat_resizetime);
- std::cout << Strutil::format (" mip computation: %5.2f\n", stat_miptime);
- std::cout << Strutil::format (" color convert: %5.2f\n", stat_colorconverttime);
- std::cout << Strutil::format (" unaccounted: %5.2f\n",
- alltime-stat_readtime-stat_writetime-stat_resizetime-stat_miptime);
+ if (verbose || configspec.get_int_attribute("maketx:stats")) {
+ double all = alltime();
+ outstream << Strutil::format ("maketx run time (seconds): %5.2f\n", all);;
+
+ outstream << Strutil::format (" file read: %5.2f\n", stat_readtime);
+ outstream << Strutil::format (" file write: %5.2f\n", stat_writetime);
+ outstream << Strutil::format (" initial resize: %5.2f\n", stat_resizetime);
+ outstream << Strutil::format (" mip computation: %5.2f\n", stat_miptime);
+ outstream << Strutil::format (" color convert: %5.2f\n", stat_colorconverttime);
+ outstream << Strutil::format (" unaccounted: %5.2f\n",
+ all-stat_readtime-stat_writetime-stat_resizetime-stat_miptime);
size_t kb = Sysutil::memory_used(true) / 1024;
- std::cout << Strutil::format ("maketx memory used: %5.1f MB\n",
+ outstream << Strutil::format ("maketx memory used: %5.1f MB\n",
(double)kb/1024.0);
}
- Filter2D::destroy (filter);
-
- if (stats) {
- std::cout << "\n" << ic->getstats();
- }
-
- return 0;
+ return ok;
}
diff --git a/src/libtexture/imagecache_pvt.h b/src/libtexture/imagecache_pvt.h
index f4c43cd..5074bff 100644
--- a/src/libtexture/imagecache_pvt.h
+++ b/src/libtexture/imagecache_pvt.h
@@ -513,9 +513,8 @@ private:
TileID m_id; ///< ID of this tile
std::vector<char> m_pixels; ///< The pixel data
bool m_valid; ///< Valid pixels
- atomic_int m_used; ///< Used recently
volatile bool m_pixels_ready; ///< The pixels have been read from disk
- float m_mindepth, m_maxdepth; ///< shadows only: min/max depth of the tile
+ atomic_int m_used; ///< Used recently
};
diff --git a/src/libutil/SHA1.cpp b/src/libutil/SHA1.cpp
index b9e6c8b..c761185 100644
--- a/src/libutil/SHA1.cpp
+++ b/src/libutil/SHA1.cpp
@@ -8,9 +8,9 @@
// If compiling with MFC, you might want to add #include "StdAfx.h"
+#include "SHA1.h"
#include "hash.h"
#include "dassert.h"
-#include "SHA1.h"
#ifdef SHA1_UTILITY_FUNCTIONS
#define SHA1_MAX_FILE_BUFFER 8000
diff --git a/src/libutil/tbb_misc.cpp b/src/libutil/tbb_misc.cpp
index a706383..b6a485e 100644
--- a/src/libutil/tbb_misc.cpp
+++ b/src/libutil/tbb_misc.cpp
@@ -30,8 +30,7 @@
// an executing program.
#include "tbb/tbb_stddef.h"
-// Out-of-line TBB assertion handling routines are instantiated here.
-#include "tbb/tbb_assert_impl.h"
+#include "tbb/tbb_machine.h"
#include "tbb/tbb_misc.h"
#include <cstdio>
diff --git a/src/maketx/maketx.cpp b/src/maketx/maketx.cpp
index ca17b9d..410cb7c 100644
--- a/src/maketx/maketx.cpp
+++ b/src/maketx/maketx.cpp
@@ -60,6 +60,7 @@ OIIO_NAMESPACE_USING
// # FIXME: Refactor all statics into a struct
// Basic runtime options
+static bool newmode = false;
static std::string full_command_line;
static std::vector<std::string> filenames;
static std::string outputfilename;
@@ -233,6 +234,8 @@ getargs (int argc, char *argv[])
"-o %s", &outputfilename, "Output filename",
"--threads %d", &nthreads, "Number of threads (default: #cores)",
"-u", &updatemode, "Update mode",
+ "--new", &newmode, "",
+ "--old %!", &newmode, "",
"--format %s", &fileformatname, "Specify output file format (default: guess from extension)",
"--nchannels %d", &nchannels, "Specify the number of output image channels.",
"-d %s", &dataformatname, "Set the output data format to one of: "
@@ -1386,6 +1389,218 @@ write_mipmap (ImageBuf &img, const ImageSpec &outspec_template,
+
+static void
+newmode_getargs (int argc, char *argv[], ImageSpec &configspec)
+{
+ bool help = false;
+ // Basic runtime options
+ std::string dataformatname = "";
+ std::string fileformatname = "";
+ std::vector<std::string> mipimages;
+ int tile[3] = { 64, 64, 1 }; // FIXME if we ever support volume MIPmaps
+ std::string compression = "zip";
+ bool updatemode = false;
+ bool checknan = false;
+ std::string fixnan; // none, black, box3
+ bool set_full_to_pixels = false;
+ std::string filtername;
+ // Options controlling file metadata or mipmap creation
+ float fovcot = 0.0f;
+ std::string wrap = "black";
+ std::string swrap;
+ std::string twrap;
+ bool doresize = false;
+ Imath::M44f Mcam(0.0f), Mscr(0.0f); // Initialize to 0
+ bool separate = false;
+ bool nomipmap = false;
+ bool prman_metadata = false;
+ bool constant_color_detect = false;
+ bool monochrome_detect = false;
+ bool opaque_detect = false;
+ int nchannels = -1;
+ bool prman = false;
+ bool oiio = false;
+ bool ignore_unassoc = false; // ignore unassociated alpha tags
+ bool unpremult = false;
+ std::string incolorspace;
+ std::string outcolorspace;
+
+ filenames.clear();
+
+ ArgParse ap;
+ ap.options ("maketx -- convert images to tiled, MIP-mapped textures\n"
+ OIIO_INTRO_STRING "\n"
+ "Usage: maketx [options] file...",
+ "%*", parse_files, "",
+ "--help", &help, "Print help message",
+ "-v", &verbose, "Verbose status messages",
+ "-o %s", &outputfilename, "Output filename",
+ "--new", NULL, "",
+ "--old", NULL, "Old mode",
+ "--threads %d", &nthreads, "Number of threads (default: #cores)",
+ "-u", &updatemode, "Update mode",
+ "--format %s", &fileformatname, "Specify output file format (default: guess from extension)",
+ "--nchannels %d", &nchannels, "Specify the number of output image channels.",
+ "-d %s", &dataformatname, "Set the output data format to one of: "
+ "uint8, sint8, uint16, sint16, half, float",
+ "--tile %d %d", &tile[0], &tile[1], "Specify tile size",
+ "--separate", &separate, "Use planarconfig separate (default: contiguous)",
+ "--compression %s", &compression, "Set the compression method (default = zip, if possible)",
+ "--fovcot %f", &fovcot, "Override the frame aspect ratio. Default is width/height.",
+ "--wrap %s", &wrap, "Specify wrap mode (black, clamp, periodic, mirror)",
+ "--swrap %s", &swrap, "Specific s wrap mode separately",
+ "--twrap %s", &twrap, "Specific t wrap mode separately",
+ "--resize", &doresize, "Resize textures to power of 2 (default: no)",
+ "--noresize %!", &doresize, "Do not resize textures to power of 2 (deprecated)",
+ "--filter %s", &filtername, filter_help_string().c_str(),
+ "--nomipmap", &nomipmap, "Do not make multiple MIP-map levels",
+ "--checknan", &checknan, "Check for NaN/Inf values (abort if found)",
+ "--fixnan %s", &fixnan, "Attempt to fix NaN/Inf values in the image (options: none, black, box3)",
+ "--fullpixels", &set_full_to_pixels, "Set the 'full' image range to be the pixel data window",
+ "--Mcamera %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f",
+ &Mcam[0][0], &Mcam[0][1], &Mcam[0][2], &Mcam[0][3],
+ &Mcam[1][0], &Mcam[1][1], &Mcam[1][2], &Mcam[1][3],
+ &Mcam[2][0], &Mcam[2][1], &Mcam[2][2], &Mcam[2][3],
+ &Mcam[3][0], &Mcam[3][1], &Mcam[3][2], &Mcam[3][3],
+ "Set the camera matrix",
+ "--Mscreen %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f",
+ &Mscr[0][0], &Mscr[0][1], &Mscr[0][2], &Mscr[0][3],
+ &Mscr[1][0], &Mscr[1][1], &Mscr[1][2], &Mscr[1][3],
+ &Mscr[2][0], &Mscr[2][1], &Mscr[2][2], &Mscr[2][3],
+ &Mscr[3][0], &Mscr[3][1], &Mscr[3][2], &Mscr[3][3],
+ "Set the screen matrix",
+ "--hash", NULL, "",
+ "--prman-metadata", &prman_metadata, "Add prman specific metadata",
+ "--constant-color-detect", &constant_color_detect, "Create 1-tile textures from constant color inputs",
+ "--monochrome-detect", &monochrome_detect, "Create 1-channel textures from monochrome inputs",
+ "--opaque-detect", &opaque_detect, "Drop alpha channel that is always 1.0",
+ "--ignore-unassoc", &ignore_unassoc, "Ignore unassociated alpha tags in input (don't autoconvert)",
+ "--stats", &stats, "Print runtime statistics",
+ "--mipimage %L", &mipimages, "Specify an individual MIP level",
+ "<SEPARATOR>", "Basic modes (default is plain texture):",
+ "--shadow", &shadowmode, "Create shadow map",
+ "--envlatl", &envlatlmode, "Create lat/long environment map",
+// "--envcube", &envcubemode, "Create cubic env map (file order: px, nx, py, ny, pz, nz) (UNIMP)",
+ "<SEPARATOR>", colortitle_help_string().c_str(),
+ "--colorconvert %s %s", &incolorspace, &outcolorspace,
+ colorconvert_help_string().c_str(),
+ "--unpremult", &unpremult, "Unpremultiply before color conversion, then premultiply "
+ "after the color conversion. You'll probably want to use this flag "
+ "if your image contains an alpha channel.",
+ "<SEPARATOR>", "Configuration Presets",
+ "--prman", &prman, "Use PRMan-safe settings for tile size, planarconfig, and metadata.",
+ "--oiio", &oiio, "Use OIIO-optimized settings for tile size, planarconfig, metadata.",
+ NULL);
+ if (ap.parse (argc, (const char**)argv) < 0) {
+ std::cerr << ap.geterror() << std::endl;
+ ap.usage ();
+ exit (EXIT_FAILURE);
+ }
+ if (help || filenames.empty()) {
+ ap.usage ();
+ exit (EXIT_FAILURE);
+ }
+
+ int optionsum = ((int)shadowmode + (int)envlatlmode + (int)envcubemode);
+ if (optionsum > 1) {
+ std::cerr << "maketx ERROR: At most one of the following options may be set:\n"
+ << "\t--shadow --envlatl --envcube\n";
+ ap.usage ();
+ exit (EXIT_FAILURE);
+ }
+ if (optionsum == 0)
+ mipmapmode = true;
+
+ if (prman && oiio) {
+ std::cerr << "maketx ERROR: '--prman' compatibility, and '--oiio' optimizations are mutually exclusive.\n";
+ std::cerr << "\tIf you'd like both prman and oiio compatibility, you should choose --prman\n";
+ std::cerr << "\t(at the expense of oiio-specific optimizations)\n";
+ ap.usage ();
+ exit (EXIT_FAILURE);
+ }
+
+ if (filenames.size() != 1) {
+ std::cerr << "maketx ERROR: requires exactly one input filename\n";
+ exit (EXIT_FAILURE);
+ }
+
+
+// std::cout << "Converting " << filenames[0] << " to " << outputfilename << "\n";
+
+ // Figure out which data format we want for output
+ if (! dataformatname.empty()) {
+ if (dataformatname == "uint8")
+ configspec.format = TypeDesc::UINT8;
+ else if (dataformatname == "int8" || dataformatname == "sint8")
+ configspec.format = TypeDesc::INT8;
+ else if (dataformatname == "uint16")
+ configspec.format = TypeDesc::UINT16;
+ else if (dataformatname == "int16" || dataformatname == "sint16")
+ configspec.format = TypeDesc::INT16;
+ else if (dataformatname == "half")
+ configspec.format = TypeDesc::HALF;
+ else if (dataformatname == "float")
+ configspec.format = TypeDesc::FLOAT;
+ else if (dataformatname == "double")
+ configspec.format = TypeDesc::DOUBLE;
+ }
+
+ configspec.tile_width = tile[0];
+ configspec.tile_height = tile[1];
+ configspec.tile_depth = tile[2];
+ configspec.attribute ("compression", compression);
+ if (fovcot != 0.0f)
+ configspec.attribute ("fovcot", fovcot);
+ configspec.attribute ("planarconfig", separate ? "separate" : "contig");
+ if (Mcam != Imath::M44f(0.0f))
+ configspec.attribute ("worldtocamera", TypeDesc::TypeMatrix, &Mcam);
+ if (Mscr != Imath::M44f(0.0f))
+ configspec.attribute ("worldtoscreen", TypeDesc::TypeMatrix, &Mscr);
+ std::string wrapmodes = (swrap.size() ? swrap : wrap) + ',' +
+ (twrap.size() ? twrap : wrap);
+ configspec.attribute ("wrapmodes", wrapmodes);
+
+ configspec.attribute ("maketx:verbose", verbose);
+ configspec.attribute ("maketx:stats", stats);
+ configspec.attribute ("maketx:resize", doresize);
+ configspec.attribute ("maketx:nomipmap", nomipmap);
+ configspec.attribute ("maketx:updatemode", updatemode);
+ configspec.attribute ("maketx:constant_color_detect", constant_color_detect);
+ configspec.attribute ("maketx:monochrome_detect", monochrome_detect);
+ configspec.attribute ("maketx:opaque_detect", opaque_detect);
+ configspec.attribute ("maketx:unpremult", unpremult);
+ configspec.attribute ("maketx:incolorspace", incolorspace);
+ configspec.attribute ("maketx:outcolorspace", outcolorspace);
+ configspec.attribute ("maketx:checknan", checknan);
+ configspec.attribute ("maketx:fixnan", fixnan);
+ configspec.attribute ("maketx:set_full_to_pixels", set_full_to_pixels);
+ if (filtername.size())
+ configspec.attribute ("maketx:filtername", filtername);
+ configspec.attribute ("maketx:nchannels", nchannels);
+ if (fileformatname.size())
+ configspec.attribute ("maketx:fileformatname", fileformatname);
+ configspec.attribute ("maketx:prman_metadata", prman_metadata);
+ configspec.attribute ("maketx:oiio_options", oiio);
+ configspec.attribute ("maketx:prman_options", prman);
+ if (mipimages.size())
+ configspec.attribute ("maketx:mipimages", Strutil::join(mipimages,";"));
+
+ std::string cmdline = Strutil::format ("OpenImageIO %s : %s",
+ OIIO_VERSION_STRING, ap.command_line());
+ configspec.attribute ("Software", cmdline);
+ configspec.attribute ("maketx:full_command_line", cmdline);
+
+ if (ignore_unassoc) {
+ configspec.attribute ("maketx:ignore_unassoc", (int)ignore_unassoc);
+ ImageCache *ic = ImageCache::create (); // get the shared one
+ ic->attribute ("unassociatedalpha", (int)ignore_unassoc);
+ }
+}
+
+
+
+
int
main (int argc, char *argv[])
{
@@ -1400,6 +1615,23 @@ main (int argc, char *argv[])
ic->attribute ("max_memory_MB", 1024.0); // 1 GB cache
ic->attribute ("unassociatedalpha", (int)ignore_unassoc);
+ if (newmode) {
+ ImageSpec configspec;
+ newmode_getargs (argc, argv, configspec);
+ ImageBufAlgo::MakeTextureMode mode = ImageBufAlgo::MakeTxTexture;
+ if (shadowmode)
+ mode = ImageBufAlgo::MakeTxShadow;
+ if (envlatlmode)
+ mode = ImageBufAlgo::MakeTxEnvLatl;
+ bool ok = ImageBufAlgo::make_texture (mode, filenames[0],
+ outputfilename, configspec,
+ &std::cout);
+ if (stats)
+ std::cout << "\n" << ic->getstats();
+ return ok ? 0 : EXIT_FAILURE;
+ }
+
+
if (mipmapmode) {
make_texturemap ("texture map");
} else if (shadowmode) {
diff --git a/src/oiiotool/oiiotool.cpp b/src/oiiotool/oiiotool.cpp
index 0ad6a10..0f8438c 100644
--- a/src/oiiotool/oiiotool.cpp
+++ b/src/oiiotool/oiiotool.cpp
@@ -183,9 +183,13 @@ input_file (int argc, const char *argv[])
pio.subimages = ot.allsubimages;
pio.compute_stats = ot.printstats;
pio.compute_sha1 = ot.hash;
+ pio.metamatch = ot.printinfo_metamatch;
+ pio.nometamatch = ot.printinfo_nometamatch;
long long totalsize = 0;
std::string error;
- OiioTool::print_info (argv[i], pio, totalsize, error);
+ bool ok = OiioTool::print_info (argv[i], pio, totalsize, error);
+ if (! ok)
+ std::cerr << "oiiotool ERROR: " << error << "\n";
}
ot.process_pending ();
}
@@ -1615,11 +1619,8 @@ action_over (int argc, const char *argv[])
// Create output image specification.
ImageSpec specR = specA;
set_roi (specR, roi_union (get_roi(specA), get_roi(specB)));
- specR.nchannels = std::max (specA.nchannels, specB.nchannels);
- if (specR.alpha_channel < 0 && specR.nchannels == 4)
- specR.alpha_channel = 3;
- ot.push (new ImageRec ("irec", specR, ot.imagecache));
+ ot.push (new ImageRec ("over", specR, ot.imagecache));
ImageBuf &Rib ((*ot.curimg)());
bool ok = ImageBufAlgo::over (Rib, Aib, Bib);
@@ -1631,6 +1632,36 @@ action_over (int argc, const char *argv[])
static int
+action_zover (int argc, const char *argv[])
+{
+ if (ot.postpone_callback (2, action_over, argc, argv))
+ return 0;
+
+ ImageRecRef B (ot.pop());
+ ImageRecRef A (ot.pop());
+ ot.read (A);
+ ot.read (B);
+ const ImageBuf &Aib ((*A)());
+ const ImageBuf &Bib ((*B)());
+ const ImageSpec &specA = Aib.spec();
+ const ImageSpec &specB = Bib.spec();
+
+ // Create output image specification.
+ ImageSpec specR = specA;
+ set_roi (specR, roi_union (get_roi(specA), get_roi(specB)));
+
+ ot.push (new ImageRec ("zover", specR, ot.imagecache));
+ ImageBuf &Rib ((*ot.curimg)());
+
+ bool ok = ImageBufAlgo::zover (Rib, Aib, Bib);
+ if (! ok)
+ ot.error (argv[0], Rib.geterror());
+ return 0;
+}
+
+
+
+static int
action_fill (int argc, const char *argv[])
{
if (ot.postpone_callback (1, action_fill, argc, argv))
@@ -1852,6 +1883,10 @@ getargs (int argc, char *argv[])
"-q %!", &ot.verbose, "Quiet mode (turn verbose off)",
"-a", &ot.allsubimages, "Do operations on all subimages/miplevels",
"--info", &ot.printinfo, "Print resolution and metadata on all inputs",
+ "--metamatch %s", &ot.printinfo_metamatch,
+ "Regex: which metadata is printed with -info -v",
+ "--no-metamatch %s", &ot.printinfo_nometamatch,
+ "Regex: which metadata is excluded with -info -v",
"--stats", &ot.printstats, "Print pixel statistics on all inputs",
"--hash", &ot.hash, "Print SHA-1 hash of each input image",
// "-u", &ot.updatemode, "Update mode: skip outputs when the file exists and is newer than all inputs",
@@ -1908,6 +1943,7 @@ getargs (int argc, char *argv[])
"--sub %@", action_sub, NULL, "Subtract two images",
"--abs %@", action_abs, NULL, "Take the absolute value of the image pixels",
"--over %@", action_over, NULL, "'Over' composite of two images",
+ "--zover %@", action_zover, NULL, "Depth composite two images with Z channels",
"--histogram %@ %s %d", action_histogram, NULL, NULL, "Histogram one channel (args: cumulative=0)",
"--flip %@", action_flip, NULL, "Flip the image vertically (top<->bottom)",
"--flop %@", action_flop, NULL, "Flop the image horizontally (left<->right)",
diff --git a/src/oiiotool/oiiotool.h b/src/oiiotool/oiiotool.h
index 9db54aa..584f4ae 100644
--- a/src/oiiotool/oiiotool.h
+++ b/src/oiiotool/oiiotool.h
@@ -57,6 +57,8 @@ public:
bool updatemode;
int threads;
std::string full_command_line;
+ std::string printinfo_metamatch;
+ std::string printinfo_nometamatch;
// Output options
TypeDesc output_dataformat;
@@ -304,6 +306,7 @@ struct print_info_options {
bool compute_sha1;
bool compute_stats;
std::string metamatch;
+ std::string nometamatch;
size_t namefieldlength;
print_info_options ()
diff --git a/src/oiiotool/printinfo.cpp b/src/oiiotool/printinfo.cpp
index c6179e4..57f4bf0 100644
--- a/src/oiiotool/printinfo.cpp
+++ b/src/oiiotool/printinfo.cpp
@@ -291,7 +291,7 @@ print_stats (const std::string &filename,
static void
print_metadata (const ImageSpec &spec, const std::string &filename,
const print_info_options &opt,
- boost::regex &field_re)
+ boost::regex &field_re, boost::regex &field_exclude_re)
{
bool printed = false;
if (opt.metamatch.empty() ||
@@ -370,6 +370,9 @@ print_metadata (const ImageSpec &spec, const std::string &filename,
if (! opt.metamatch.empty() &&
! boost::regex_search (p.name().c_str(), field_re))
continue;
+ if (! opt.nometamatch.empty() &&
+ boost::regex_search (p.name().c_str(), field_exclude_re))
+ continue;
std::string s = spec.metadata_val (p, true);
if (opt.filenameprefix)
printf ("%s : ", filename.c_str());
@@ -415,17 +418,11 @@ static void
print_info_subimage (int current_subimage, int max_subimages, ImageSpec &spec,
ImageInput *input, const std::string &filename,
const print_info_options &opt,
- boost::regex &field_re)
+ boost::regex &field_re, boost::regex &field_exclude_re)
{
if ( ! input->seek_subimage (current_subimage, 0, spec) )
return;
- if (! opt.metamatch.empty() &&
- ! boost::regex_search ("resolution, width, height, depth, channels, sha-1, stats", field_re)) {
- // nothing to do here
- return;
- }
-
int nmip = 1;
bool printres = opt.verbose && (opt.metamatch.empty() ||
@@ -466,7 +463,7 @@ print_info_subimage (int current_subimage, int max_subimages, ImageSpec &spec,
}
if (opt.verbose)
- print_metadata (spec, filename, opt, field_re);
+ print_metadata (spec, filename, opt, field_re, field_exclude_re);
if (opt.compute_stats && (opt.metamatch.empty() ||
boost::regex_search ("stats", field_re))) {
@@ -506,9 +503,27 @@ OiioTool::print_info (const std::string &filename,
ImageSpec spec = input->spec();
boost::regex field_re;
- if (! opt.metamatch.empty())
- field_re.assign (opt.metamatch,
+ boost::regex field_exclude_re;
+ if (! opt.metamatch.empty()) {
+ try {
+ field_re.assign (opt.metamatch,
boost::regex::extended | boost::regex_constants::icase);
+ } catch (const std::exception &e) {
+ error = Strutil::format ("Regex error '%s' on metamatch regex \"%s\"",
+ e.what(), opt.metamatch);
+ return false;
+ }
+ }
+ if (! opt.nometamatch.empty()) {
+ try {
+ field_exclude_re.assign (opt.nometamatch,
+ boost::regex::extended | boost::regex_constants::icase);
+ } catch (const std::exception &e) {
+ error = Strutil::format ("Regex error '%s' on metamatch regex \"%s\"",
+ e.what(), opt.nometamatch);
+ return false;
+ }
+ }
int padlen = std::max (0, (int)opt.namefieldlength - (int)filename.length());
std::string padding (padlen, ' ');
@@ -589,7 +604,7 @@ OiioTool::print_info (const std::string &filename,
num_of_subimages = 1;
for (int i = 0; i < num_of_subimages; ++i) {
print_info_subimage (i, num_of_subimages, spec, input,
- filename, opt, field_re);
+ filename, opt, field_re, field_exclude_re);
}
input->close ();
diff --git a/src/openexr.imageio/exrinput.cpp b/src/openexr.imageio/exrinput.cpp
index 7b242f4..40c914d 100644
--- a/src/openexr.imageio/exrinput.cpp
+++ b/src/openexr.imageio/exrinput.cpp
@@ -79,6 +79,9 @@
#include "fmath.h"
#include "filesystem.h"
+#include <boost/scoped_array.hpp>
+
+
OIIO_PLUGIN_NAMESPACE_BEGIN
@@ -929,12 +932,13 @@ OpenEXRInput::read_native_tiles (int xbegin, int xend, int ybegin, int yend,
int nytiles = (yend - ybegin + m_spec.tile_height - 1) / m_spec.tile_height;
int whole_width = nxtiles * m_spec.tile_width;
int whole_height = nytiles * m_spec.tile_height;
- std::vector<char> tmpbuf;
+
+ boost::scoped_array<char> tmpbuf;
void *origdata = data;
if (whole_width != (xend-xbegin) || whole_height != (yend-ybegin)) {
// Deal with the case of reading not a whole number of tiles --
// OpenEXR will happily overwrite user memory in this case.
- tmpbuf.resize (nxtiles * nytiles * m_spec.tile_bytes(true));
+ tmpbuf.reset (new char [nxtiles * nytiles * m_spec.tile_bytes(true)]);
data = &tmpbuf[0];
}
char *buf = (char *)data
diff --git a/src/ptex.imageio/ptex/PtexUtils.cpp b/src/ptex.imageio/ptex/PtexUtils.cpp
index 59cc7b6..de0ad2c 100644
--- a/src/ptex.imageio/ptex/PtexUtils.cpp
+++ b/src/ptex.imageio/ptex/PtexUtils.cpp
@@ -45,7 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
const char* Ptex::MeshTypeName(MeshType mt)
{
static const char* names[] = { "triangle", "quad" };
- if (mt < 0 || mt >= int(sizeof(names)/sizeof(const char*)))
+ if (mt < 0 /* || mt >= int(sizeof(names)/sizeof(const char*))*/)
return "(invalid mesh type)";
return names[mt];
}
@@ -54,7 +54,7 @@ const char* Ptex::MeshTypeName(MeshType mt)
const char* Ptex::DataTypeName(DataType dt)
{
static const char* names[] = { "uint8", "uint16", "float16", "float32" };
- if (dt < 0 || dt >= int(sizeof(names)/sizeof(const char*)))
+ if (dt < 0 /* || dt >= int(sizeof(names)/sizeof(const char*))*/)
return "(invalid data type)";
return names[dt];
}
@@ -72,7 +72,7 @@ const char* Ptex::BorderModeName(BorderMode m)
const char* Ptex::EdgeIdName(EdgeId eid)
{
static const char* names[] = { "bottom", "right", "top", "left" };
- if (eid < 0 || eid >= int(sizeof(names)/sizeof(const char*)))
+ if (eid < 0 /* || eid >= int(sizeof(names)/sizeof(const char*)) */)
return "(invalid edge id)";
return names[eid];
}
diff --git a/src/tiff.imageio/tiffoutput.cpp b/src/tiff.imageio/tiffoutput.cpp
index 39a3b9c..d66c3c6 100644
--- a/src/tiff.imageio/tiffoutput.cpp
+++ b/src/tiff.imageio/tiffoutput.cpp
@@ -44,6 +44,8 @@
#include "sysutil.h"
#include "timer.h"
+#include <boost/scoped_array.hpp>
+
OIIO_PLUGIN_NAMESPACE_BEGIN
@@ -87,8 +89,7 @@ private:
}
// Convert planar contiguous to planar separate data format
- void contig_to_separate (int n, const unsigned char *contig,
- unsigned char *separate);
+ void contig_to_separate (int n, const char *contig, char *separate);
// Add a parameter to the output
bool put_parameter (const std::string &name, TypeDesc type,
const void *data);
@@ -476,8 +477,7 @@ TIFFOutput::close ()
/// Helper: Convert n pixels from contiguous (RGBRGBRGB) to separate
/// (RRRGGGBBB) planarconfig.
void
-TIFFOutput::contig_to_separate (int n, const unsigned char *contig,
- unsigned char *separate)
+TIFFOutput::contig_to_separate (int n, const char *contig, char *separate)
{
int channelbytes = m_spec.channel_bytes();
for (int p = 0; p < n; ++p) // loop over pixels
@@ -504,7 +504,7 @@ TIFFOutput::write_scanline (int y, int z, TypeDesc format,
std::vector<unsigned char> scratch2 (m_spec.scanline_bytes());
std::swap (m_scratch, scratch2);
m_scratch.resize (m_spec.scanline_bytes());
- contig_to_separate (m_spec.width, (const unsigned char *)data, &m_scratch[0]);
+ contig_to_separate (m_spec.width, (const char *)data, (char *)&m_scratch[0]);
for (int c = 0; c < m_spec.nchannels; ++c) {
if (TIFFWriteScanline (m_tif, (tdata_t)&m_scratch[plane_bytes*c], y, c) < 0) {
error ("TIFFWriteScanline failed");
@@ -562,9 +562,19 @@ TIFFOutput::write_tile (int x, int y, int z,
imagesize_t plane_bytes = tile_pixels * m_spec.format.size();
DASSERT (plane_bytes*m_spec.nchannels == m_spec.tile_bytes());
m_scratch.resize (m_spec.tile_bytes());
- contig_to_separate (tile_pixels, (const unsigned char *)data, &m_scratch[0]);
+
+ boost::scoped_array<char> separate_heap;
+ char *separate = NULL;
+ imagesize_t separate_size = plane_bytes * m_spec.nchannels;
+ if (separate_size <= (1<<16))
+ separate = ALLOCA (char, separate_size); // <=64k ? stack
+ else { // >64k ? heap
+ separate_heap.reset (new char [separate_size]); // will auto-free
+ separate = separate_heap.get();
+ }
+ contig_to_separate (tile_pixels, (const char *)data, separate);
for (int c = 0; c < m_spec.nchannels; ++c) {
- if (TIFFWriteTile (m_tif, (tdata_t)&m_scratch[plane_bytes*c], x, y, z, c) < 0) {
+ if (TIFFWriteTile (m_tif, (tdata_t)&separate[plane_bytes*c], x, y, z, c) < 0) {
error ("TIFFWriteTile failed");
return false;
}
diff --git a/testsuite/maketx/ref/out.txt b/testsuite/maketx/ref/out.txt
new file mode 100644
index 0000000..315b616
--- /dev/null
+++ b/testsuite/maketx/ref/out.txt
@@ -0,0 +1,351 @@
+Reading grid.tx
+grid.tx : 1000 x 1000, 4 channel, uint8 tiff
+ MIP-map levels: 1000x1000 500x500 250x250 125x125 62x62 31x31 15x15 7x7 3x3 1x1
+ SHA-1: 97D6548FF9E9BFD21424B773B1D84FACDF0C1797
+ channel list: R, G, B, A
+ tile size: 64 x 64
+ oiio:BitsPerSample: 8
+ ImageDescription: "SHA-1=8502BD4D9FA89E6449D73510BA008B2AEEC51E86"
+ Orientation: 1 (normal)
+ XResolution: 72
+ YResolution: 72
+ ResolutionUnit: 0
+ DocumentName: "g.tif"
+ textureformat: "Plain Texture"
+ wrapmodes: "black,black"
+ fovcot: 1
+ tiff:PhotometricInterpretation: 2
+ tiff:PlanarConfiguration: 1
+ planarconfig: "contig"
+ tiff:Compression: 8
+ compression: "zip"
+ IPTC:Caption: "SHA-1=8502BD4D9FA89E6449D73510BA008B2AEEC51E86"
+ tiff:PageNumber: "0"
+ tiff:RowsPerStrip: "8"
+Reading grid-resize.tx
+grid-resize.tx : 1024 x 1024, 4 channel, uint8 tiff
+ MIP-map levels: 1024x1024 512x512 256x256 128x128 64x64 32x32 16x16 8x8 4x4 2x2 1x1
+ SHA-1: C12F91CE509A947ACE16DECA103E73CB62D2AC09
+ channel list: R, G, B, A
+ tile size: 64 x 64
+ oiio:BitsPerSample: 8
+ ImageDescription: "SHA-1=6E041D85002929587707DA67BD1CB10F7F8A6B4D"
+ Orientation: 1 (normal)
+ XResolution: 72
+ YResolution: 72
+ ResolutionUnit: 0
+ DocumentName: "g.tif"
+ textureformat: "Plain Texture"
+ wrapmodes: "black,black"
+ fovcot: 1
+ tiff:PhotometricInterpretation: 2
+ tiff:PlanarConfiguration: 1
+ planarconfig: "contig"
+ tiff:Compression: 8
+ compression: "zip"
+ IPTC:Caption: "SHA-1=6E041D85002929587707DA67BD1CB10F7F8A6B4D"
+ tiff:PageNumber: "0"
+ tiff:RowsPerStrip: "8"
+Reading checker-uint16.tx
+checker-uint16.tx : 128 x 128, 4 channel, uint16 tiff
+ MIP-map levels: 128x128 64x64 32x32 16x16 8x8 4x4 2x2 1x1
+ SHA-1: 75BCACCE72A4275AD11FAF4A5D328C624DFF69AB
+ channel list: R, G, B, A
+ tile size: 64 x 64
+ oiio:BitsPerSample: 16
+ ImageDescription: "SHA-1=3DCC044E78762699EBEFA0644CD5CEF62000120C"
+ Orientation: 1 (normal)
+ textureformat: "Plain Texture"
+ wrapmodes: "black,black"
+ fovcot: 1
+ tiff:PhotometricInterpretation: 2
+ tiff:PlanarConfiguration: 1
+ planarconfig: "contig"
+ tiff:Compression: 5
+ compression: "zip"
+ IPTC:Caption: "SHA-1=3DCC044E78762699EBEFA0644CD5CEF62000120C"
+ tiff:RowsPerStrip: "32"
+Reading checker-1chan.tx
+checker-1chan.tx : 128 x 128, 1 channel, uint8 tiff
+ MIP-map levels: 128x128 64x64 32x32 16x16 8x8 4x4 2x2 1x1
+ SHA-1: F7DAC8772B7C6BFABDA884D61ABC84844C949AF1
+ channel list: A
+ tile size: 64 x 64
+ oiio:BitsPerSample: 8
+ ImageDescription: "SHA-1=4226806DDDE5A323C47B930B33702F73DF2EE01B"
+ Orientation: 1 (normal)
+ textureformat: "Plain Texture"
+ wrapmodes: "black,black"
+ fovcot: 1
+ tiff:PhotometricInterpretation: 2
+ tiff:PlanarConfiguration: 1
+ planarconfig: "contig"
+ tiff:Compression: 5
+ compression: "zip"
+ IPTC:Caption: "SHA-1=4226806DDDE5A323C47B930B33702F73DF2EE01B"
+ tiff:RowsPerStrip: "32"
+Reading checker-16x32tile.tx
+checker-16x32tile.tx : 128 x 128, 4 channel, uint8 tiff
+ MIP-map levels: 128x128 64x64 32x32 16x16 8x8 4x4 2x2 1x1
+ SHA-1: 1C1A7D35CCED212B768B31F002B442EA947D89A6
+ channel list: R, G, B, A
+ tile size: 16 x 32
+ oiio:BitsPerSample: 8
+ ImageDescription: "SHA-1=3DCC044E78762699EBEFA0644CD5CEF62000120C"
+ Orientation: 1 (normal)
+ textureformat: "Plain Texture"
+ wrapmodes: "black,black"
+ fovcot: 1
+ tiff:PhotometricInterpretation: 2
+ tiff:PlanarConfiguration: 1
+ planarconfig: "contig"
+ tiff:Compression: 5
+ compression: "zip"
+ IPTC:Caption: "SHA-1=3DCC044E78762699EBEFA0644CD5CEF62000120C"
+ tiff:RowsPerStrip: "32"
+Reading checker-seplzw.tx
+checker-seplzw.tx : 128 x 128, 4 channel, uint8 tiff
+ MIP-map levels: 128x128 64x64 32x32 16x16 8x8 4x4 2x2 1x1
+ SHA-1: 1C1A7D35CCED212B768B31F002B442EA947D89A6
+ channel list: R, G, B, A
+ tile size: 64 x 64
+ oiio:BitsPerSample: 8
+ ImageDescription: "SHA-1=3DCC044E78762699EBEFA0644CD5CEF62000120C"
+ Orientation: 1 (normal)
+ textureformat: "Plain Texture"
+ wrapmodes: "black,black"
+ fovcot: 1
+ tiff:PhotometricInterpretation: 2
+ tiff:PlanarConfiguration: 1
+ planarconfig: "separate"
+ tiff:Compression: 5
+ compression: "lzw"
+ IPTC:Caption: "SHA-1=3DCC044E78762699EBEFA0644CD5CEF62000120C"
+ tiff:RowsPerStrip: "32"
+Reading checker-clamp.tx
+checker-clamp.tx : 128 x 128, 4 channel, uint8 tiff
+ MIP-map levels: 128x128 64x64 32x32 16x16 8x8 4x4 2x2 1x1
+ SHA-1: 1C1A7D35CCED212B768B31F002B442EA947D89A6
+ channel list: R, G, B, A
+ tile size: 64 x 64
+ oiio:BitsPerSample: 8
+ ImageDescription: "SHA-1=3DCC044E78762699EBEFA0644CD5CEF62000120C"
+ Orientation: 1 (normal)
+ textureformat: "Plain Texture"
+ wrapmodes: "clamp,clamp"
+ fovcot: 1
+ tiff:PhotometricInterpretation: 2
+ tiff:PlanarConfiguration: 1
+ planarconfig: "contig"
+ tiff:Compression: 5
+ compression: "zip"
+ IPTC:Caption: "SHA-1=3DCC044E78762699EBEFA0644CD5CEF62000120C"
+ tiff:RowsPerStrip: "32"
+Reading checker-permir.tx
+checker-permir.tx : 128 x 128, 4 channel, uint8 tiff
+ MIP-map levels: 128x128 64x64 32x32 16x16 8x8 4x4 2x2 1x1
+ SHA-1: 1C1A7D35CCED212B768B31F002B442EA947D89A6
+ channel list: R, G, B, A
+ tile size: 64 x 64
+ oiio:BitsPerSample: 8
+ ImageDescription: "SHA-1=3DCC044E78762699EBEFA0644CD5CEF62000120C"
+ Orientation: 1 (normal)
+ textureformat: "Plain Texture"
+ wrapmodes: "periodic,mirror"
+ fovcot: 1
+ tiff:PhotometricInterpretation: 2
+ tiff:PlanarConfiguration: 1
+ planarconfig: "contig"
+ tiff:Compression: 5
+ compression: "zip"
+ IPTC:Caption: "SHA-1=3DCC044E78762699EBEFA0644CD5CEF62000120C"
+ tiff:RowsPerStrip: "32"
+Reading checker-nomip.tx
+checker-nomip.tx : 128 x 128, 4 channel, uint8 tiff
+ SHA-1: 1C1A7D35CCED212B768B31F002B442EA947D89A6
+ channel list: R, G, B, A
+ tile size: 64 x 64
+ oiio:BitsPerSample: 8
+ ImageDescription: "SHA-1=3DCC044E78762699EBEFA0644CD5CEF62000120C"
+ Orientation: 1 (normal)
+ textureformat: "Plain Texture"
+ wrapmodes: "black,black"
+ fovcot: 1
+ tiff:PhotometricInterpretation: 2
+ tiff:PlanarConfiguration: 1
+ planarconfig: "contig"
+ tiff:Compression: 5
+ compression: "zip"
+ IPTC:Caption: "SHA-1=3DCC044E78762699EBEFA0644CD5CEF62000120C"
+ tiff:RowsPerStrip: "32"
+Reading checker-camera.tx
+checker-camera.tx : 128 x 128, 4 channel, uint8 tiff
+ MIP-map levels: 128x128 64x64 32x32 16x16 8x8 4x4 2x2 1x1
+ SHA-1: 1C1A7D35CCED212B768B31F002B442EA947D89A6
+ channel list: R, G, B, A
+ tile size: 64 x 64
+ oiio:BitsPerSample: 8
+ ImageDescription: "SHA-1=3DCC044E78762699EBEFA0644CD5CEF62000120C"
+ Orientation: 1 (normal)
+ textureformat: "Plain Texture"
+ wrapmodes: "black,black"
+ fovcot: 1
+ tiff:PhotometricInterpretation: 2
+ tiff:PlanarConfiguration: 1
+ planarconfig: "contig"
+ tiff:Compression: 5
+ compression: "zip"
+ worldtocamera: 1 0 0 0 0 2 0 0 0 0 1 0 0 0 0 1
+ worldtoscreen: 3 0 0 0 0 3 0 0 0 0 3 0 1 2 3 1
+ IPTC:Caption: "SHA-1=3DCC044E78762699EBEFA0644CD5CEF62000120C"
+ tiff:RowsPerStrip: "32"
+Reading checker-opaque.tx
+checker-opaque.tx : 128 x 128, 3 channel, uint8 tiff
+ MIP-map levels: 128x128 64x64 32x32 16x16 8x8 4x4 2x2 1x1
+ SHA-1: 6827D9ED3A5674C1FAB56F96E5D7D06796D43144
+ channel list: R, G, B
+ tile size: 64 x 64
+ oiio:BitsPerSample: 8
+ ImageDescription: "SHA-1=32F1C7F592C6880B53E690F0F32A67A13936D71B"
+ Orientation: 1 (normal)
+ textureformat: "Plain Texture"
+ wrapmodes: "black,black"
+ fovcot: 1
+ tiff:PhotometricInterpretation: 2
+ tiff:PlanarConfiguration: 1
+ planarconfig: "contig"
+ tiff:Compression: 5
+ compression: "zip"
+ IPTC:Caption: "SHA-1=32F1C7F592C6880B53E690F0F32A67A13936D71B"
+ tiff:RowsPerStrip: "32"
+Reading gray-mono.tx
+gray-mono.tx : 256 x 256, 1 channel, uint8 tiff
+ MIP-map levels: 256x256 128x128 64x64 32x32 16x16 8x8 4x4 2x2 1x1
+ SHA-1: F5C1F9FA963006D501B14542F5E941AEDB4C5907
+ channel list: A
+ tile size: 64 x 64
+ oiio:BitsPerSample: 8
+ ImageDescription: "SHA-1=F01458A8FF5AEBE45EFB49BD1A2382226D9D838A"
+ Orientation: 1 (normal)
+ textureformat: "Plain Texture"
+ wrapmodes: "black,black"
+ fovcot: 1
+ tiff:PhotometricInterpretation: 2
+ tiff:PlanarConfiguration: 1
+ planarconfig: "contig"
+ tiff:Compression: 5
+ compression: "zip"
+ IPTC:Caption: "SHA-1=F01458A8FF5AEBE45EFB49BD1A2382226D9D838A"
+ tiff:RowsPerStrip: "32"
+Reading pink-mono.tx
+pink-mono.tx : 256 x 256, 3 channel, uint8 tiff
+ MIP-map levels: 256x256 128x128 64x64 32x32 16x16 8x8 4x4 2x2 1x1
+ SHA-1: D781FABF7CF958AE9D9429255C8591C77BAA9917
+ channel list: R, G, B
+ tile size: 64 x 64
+ oiio:BitsPerSample: 8
+ ImageDescription: "SHA-1=3E6BE27709F0F97E6E0383039233FB66B086C1BA"
+ Orientation: 1 (normal)
+ textureformat: "Plain Texture"
+ wrapmodes: "black,black"
+ fovcot: 1
+ tiff:PhotometricInterpretation: 2
+ tiff:PlanarConfiguration: 1
+ planarconfig: "contig"
+ tiff:Compression: 5
+ compression: "zip"
+ IPTC:Caption: "SHA-1=3E6BE27709F0F97E6E0383039233FB66B086C1BA"
+ tiff:RowsPerStrip: "32"
+Reading checker-prman.tx
+checker-prman.tx : 128 x 128, 4 channel, int16 tiff
+ MIP-map levels: 128x128 64x64 32x32 16x16 8x8 4x4 2x2 1x1
+ SHA-1: DE42A8468161DA333BABF1BEB60811EA0FEF6534
+ channel list: R, G, B, A
+ tile size: 64 x 32
+ oiio:BitsPerSample: 16
+ ImageDescription: "SHA-1=3DCC044E78762699EBEFA0644CD5CEF62000120C"
+ Orientation: 1 (normal)
+ textureformat: "Plain Texture"
+ wrapmodes: "black,black"
+ fovcot: 1
+ tiff:PhotometricInterpretation: 2
+ tiff:PlanarConfiguration: 1
+ planarconfig: "separate"
+ tiff:Compression: 5
+ compression: "zip"
+ IPTC:Caption: "SHA-1=3DCC044E78762699EBEFA0644CD5CEF62000120C"
+ tiff:RowsPerStrip: "32"
+Reading nan.exr
+nan.exr : 64 x 64, 3 channel, half openexr
+ SHA-1: 47A8E8F3E8B2C3B6B032FCC8C39D3C5FC1AAA390
+ channel list: R, G, B
+ tile size: 64 x 64
+ oiio:ColorSpace: "Linear"
+ compression: "zip"
+ ImageDescription: "SHA-1=93D431375F9CC89BC200B8CDDF6C04DB05271363"
+ fovcot: 1
+ openexr:levelmode: 0
+ PixelAspectRatio: 1
+ screenWindowCenter: 0 0
+ screenWindowWidth: 1
+ textureformat: "Plain Texture"
+ wrapmodes: "black,black"
+ Stats Min: 0.000000 0.000000 0.000000 (float)
+ Stats Max: 1.000000 1.000000 1.000000 (float)
+ Stats Avg: 0.500000 0.500000 0.500000 (float)
+ Stats StdDev: 0.500000 0.500000 0.500000 (float)
+ Stats NanCount: 0 0 0
+ Stats InfCount: 0 0 0
+ Stats FiniteCount: 4096 4096 4096
+ Constant: No
+ Monochrome: Yes
+Reading checker-exr.pdq
+checker-exr.pdq : 128 x 128, 4 channel, half openexr
+ MIP-map levels: 128x128 64x64 32x32 16x16 8x8 4x4 2x2 1x1
+ SHA-1: FA921281D5C8AF14FC50885DD54E2E17509202EC
+ channel list: R, G, B, A
+ tile size: 64 x 64
+ oiio:ColorSpace: "Linear"
+ openexr:roundingmode: 0
+ textureformat: "Plain Texture"
+ compression: "zip"
+ Orientation: 1 (normal)
+ ImageDescription: "SHA-1=3DCC044E78762699EBEFA0644CD5CEF62000120C"
+ fovcot: 1
+ PixelAspectRatio: 1
+ screenWindowCenter: 0 0
+ screenWindowWidth: 1
+ wrapmodes: "black,black"
+Reading small.tif
+small.tif : 64 x 64, 3 channel, uint8 tiff
+ SHA-1: BE1D5EA24E907A4C4B3FB3C28EAC872A20F5B414
+ channel list: R, G, B
+ oiio:BitsPerSample: 8
+ ImageDescription: "foo SHA-1=1234abcd ConstantColor=[0.0,0,-0.0] bar"
+ Orientation: 1 (normal)
+ tiff:PhotometricInterpretation: 2
+ tiff:PlanarConfiguration: 1
+ planarconfig: "contig"
+ tiff:Compression: 5
+ compression: "lzw"
+ tiff:RowsPerStrip: 32
+ IPTC:Caption: "foo SHA-1=1234abcd ConstantColor=[0.0,0,-0.0] bar"
+Reading small.tx
+small.tx : 64 x 64, 3 channel, uint8 tiff
+ MIP-map levels: 64x64 32x32 16x16 8x8 4x4 2x2 1x1
+ SHA-1: BE1D5EA24E907A4C4B3FB3C28EAC872A20F5B414
+ channel list: R, G, B
+ tile size: 64 x 64
+ oiio:BitsPerSample: 8
+ ImageDescription: "foo bar SHA-1=FFB354CFB97E56225E1FDA9484B8DE1B04470DAE ConstantColor=[1,0,0]"
+ Orientation: 1 (normal)
+ textureformat: "Plain Texture"
+ wrapmodes: "black,black"
+ fovcot: 1
+ tiff:PhotometricInterpretation: 2
+ tiff:PlanarConfiguration: 1
+ planarconfig: "contig"
+ tiff:Compression: 5
+ compression: "zip"
+ IPTC:Caption: "foo bar SHA-1=FFB354CFB97E56225E1FDA9484B8DE1B04470DAE ConstantColor=[1,0,0]"
+ tiff:RowsPerStrip: "32"
diff --git a/testsuite/maketx/run.py b/testsuite/maketx/run.py
new file mode 100644
index 0000000..e0f04ef
--- /dev/null
+++ b/testsuite/maketx/run.py
@@ -0,0 +1,102 @@
+#!/usr/bin/python
+
+# location of oiio-images directory
+oiio_images = parent + "/oiio-images/"
+
+# Just for simplicity, make a checkerboard with a solid alpha
+command += (oiio_app("oiiotool") + " --pattern checker 128x128 4 --ch R,G,B,=1.0"
+ + " -d uint8 -o " + oiio_relpath("checker.tif") + " >> out.txt;\n")
+
+# Basic test - recreate the grid texture
+command += maketx_command (oiio_images + "grid.tif", "grid.tx", showinfo=True)
+
+# Test --resize (to power of 2) with the grid, which is 1000x1000
+command += maketx_command (oiio_images + "grid.tif", "grid-resize.tx",
+ "--resize", showinfo=True)
+
+# Test -d to set output data type
+command += maketx_command ("checker.tif", "checker-uint16.tx",
+ "-d uint16", showinfo=True)
+
+# Test --nchannels to restrict the number of channels
+command += maketx_command ("checker.tif", "checker-1chan.tx",
+ "--nchannels 1", showinfo=True)
+
+# Test --tiles to set a non-default tile size
+command += maketx_command ("checker.tif", "checker-16x32tile.tx",
+ "--tile 16 32", showinfo=True)
+
+# Test --separate and --compression
+command += maketx_command ("checker.tif", "checker-seplzw.tx",
+ "--separate --compression lzw", showinfo=True)
+
+# Test --wrap
+command += maketx_command ("checker.tif", "checker-clamp.tx",
+ "--wrap clamp", showinfo=True)
+
+# Test --swrap and --twrap
+command += maketx_command ("checker.tif", "checker-permir.tx",
+ "--swrap periodic --twrap mirror", showinfo=True)
+
+# Test --nomipmap
+command += maketx_command ("checker.tif", "checker-nomip.tx",
+ "--nomipmap", showinfo=True)
+
+# Test --Mcamera, --Mscreen
+command += maketx_command ("checker.tif", "checker-camera.tx",
+ "--Mcamera 1 0 0 0 0 2 0 0 0 0 1 0 0 0 0 1 --Mscreen 3 0 0 0 0 3 0 0 0 0 3 0 1 2 3 1",
+ showinfo=True)
+
+# Test --opaque-detect (should drop the alpha channel)
+command += maketx_command ("checker.tif", "checker-opaque.tx",
+ "--opaque-detect", showinfo=True)
+
+# Test --monochrome-detect (first create a monochrome image)
+command += (oiio_app("oiiotool") + " --pattern constant:color=.25,.25,.25 256x256 3 "
+ + " -d uint8 -o " + oiio_relpath("gray.tif") + " >> out.txt;\n")
+command += maketx_command ("gray.tif", "gray-mono.tx",
+ "--monochrome-detect", showinfo=True)
+
+# Test --monochrome-detect on something that is NOT monochrome
+command += (oiio_app("oiiotool") + " --pattern constant:color=.25,.2,.15 256x256 3 "
+ + " -d uint8 -o " + oiio_relpath("pink.tif") + " >> out.txt;\n")
+command += maketx_command ("pink.tif", "pink-mono.tx",
+ "--monochrome-detect", showinfo=True)
+
+# Test --prman : should save 'separate' planarconfig, and funny 64x32 tiles
+# since we are specifying 16 bits, and it should save as 'int16' even though
+# we asked for unsigned.
+command += maketx_command ("checker.tif", "checker-prman.tx",
+ "-d uint16 --prman", showinfo=True)
+
+# Test --fixnan : take advantage of the bad.exr images in
+# testsuite/oiiotool-fixnan. (Use --nomipmap to cut down on stats output)
+# FIXME: would also like to test --checknan, but the problem with that is
+# that is actually FAILS if there's a nan.
+command += maketx_command ("../oiiotool-fixnan/bad.exr",
+ "nan.exr", "--fixnan box3 --nomipmap",
+ showinfo=True, showinfo_extra="--stats")
+
+# Test --format to force exr even though it can't be deduced from the name.
+command += maketx_command ("checker.tif", "checker-exr.pdq",
+ "--format exr", showinfo=True)
+
+# Test that we cleanly replace any existing SHA-1 hash and ConstantColor
+# hint in the ImageDescription of the input file.
+command += (oiio_app("oiiotool") + " --pattern constant:color=1,0,0 64x64 3 "
+ + " --caption \"foo SHA-1=1234abcd ConstantColor=[0.0,0,-0.0] bar\""
+ + " -d uint8 -o " + oiio_relpath("small.tif") + " >> out.txt;\n")
+command += info_command ("small.tif", safematch=1);
+command += maketx_command ("small.tif", "small.tx",
+ "--oiio --constant-color-detect", showinfo=True)
+
+
+outputs = [ "out.txt" ]
+
+
+
+# To do: --filter --checknan --fullpixels
+# --prman-metadata --ignore-unassoc
+# --mipimage
+# --envlatl TIFF, --envlatl EXR
+# --colorconvert --unpremult -u --fovcot
diff --git a/testsuite/oiiotool-fixnan/ref/out.txt b/testsuite/oiiotool-fixnan/ref/out.txt
index 9b45b4b..4b6a46c 100644
--- a/testsuite/oiiotool-fixnan/ref/out.txt
+++ b/testsuite/oiiotool-fixnan/ref/out.txt
@@ -4,7 +4,6 @@ bad.exr : 64 x 64, 3 channel, half openexr
channel list: R, G, B
oiio:ColorSpace: "Linear"
compression: "zip"
- DateTime: "2012:02:24 23:11:09"
PixelAspectRatio: 1
screenWindowCenter: 0 0
screenWindowWidth: 1
@@ -23,9 +22,6 @@ black.exr : 64 x 64, 3 channel, half openexr
channel list: R, G, B
oiio:ColorSpace: "Linear"
compression: "zip"
- Exif:ImageHistory: "../../oiiotool/oiiotool bad.exr --fixnan black -o black.exr"
- Software: "OpenImageIO 1.1.2 : ../../oiiotool/oiiotool bad.exr --fixnan black -o black.exr"
- DateTime: "2012:02:24 23:11:09"
PixelAspectRatio: 1
screenWindowCenter: 0 0
screenWindowWidth: 1
@@ -44,9 +40,6 @@ box3.exr : 64 x 64, 3 channel, half openexr
channel list: R, G, B
oiio:ColorSpace: "Linear"
compression: "zip"
- Exif:ImageHistory: "../../oiiotool/oiiotool bad.exr --fixnan box3 -o box3.exr"
- Software: "OpenImageIO 1.1.2 : ../../oiiotool/oiiotool bad.exr --fixnan box3 -o box3.exr"
- DateTime: "2012:02:24 23:11:09"
PixelAspectRatio: 1
screenWindowCenter: 0 0
screenWindowWidth: 1
diff --git a/testsuite/oiiotool-fixnan/run.py b/testsuite/oiiotool-fixnan/run.py
index 61f6653..fdf8116 100755
--- a/testsuite/oiiotool-fixnan/run.py
+++ b/testsuite/oiiotool-fixnan/run.py
@@ -4,9 +4,9 @@ command += (oiio_app ("oiiotool") +
" bad.exr --fixnan black -o black.exr >> out.txt ;\n")
command += (oiio_app ("oiiotool") +
" bad.exr --fixnan box3 -o box3.exr >> out.txt ;\n")
-command += info_command ("bad.exr", "--stats")
-command += info_command ("black.exr", "--stats")
-command += info_command ("box3.exr", "--stats")
+command += info_command ("bad.exr", "--stats", safematch=True)
+command += info_command ("black.exr", "--stats", safematch=True)
+command += info_command ("box3.exr", "--stats", safematch=True)
# Outputs to check against references
outputs = [ "black.exr", "box3.exr", "out.txt" ]
diff --git a/testsuite/runtest.py b/testsuite/runtest.py
index 71826fe..33da090 100755
--- a/testsuite/runtest.py
+++ b/testsuite/runtest.py
@@ -101,8 +101,11 @@ def oiio_app (app):
# Construct a command that will compare two images, appending output to
-# the file "out.txt".
-def info_command (file, extraargs="") :
+# the file "out.txt". If 'safematch' is nonzero, it will exclude printing
+# of fields that tend to change from run to run or release to release.
+def info_command (file, extraargs="", safematch=0) :
+ if safematch :
+ extraargs += " --no-metamatch \"DateTime|Software|OriginatingProgram|ImageHistory\""
return (oiio_app("oiiotool") + "--info -v -a --hash " + extraargs
+ " " + oiio_relpath(file,tmpdir) + " >> out.txt ;\n")
@@ -111,7 +114,7 @@ def info_command (file, extraargs="") :
# the file "out.txt". We allow a small number of pixels to have up to
# 1 LSB (8 bit) error, it's very hard to make different platforms and
# compilers always match to every last floating point bit.
-def diff_command (fileA, fileB, extraargs="", silent=0, concat=True) :
+def diff_command (fileA, fileB, extraargs="", silent=False, concat=True) :
command = (oiio_app("idiff") + "-a "
+ "-failpercent 0.01 -hardfail 0.004 -warn 0.004 "
+ extraargs + " " + oiio_relpath(fileA,tmpdir)
@@ -123,6 +126,25 @@ def diff_command (fileA, fileB, extraargs="", silent=0, concat=True) :
return command
+# Construct a command that will create a texture, appending console
+# output to the file "out.txt".
+def maketx_command (infile, outfile, extraargs="",
+ showinfo=False, showinfo_extra="",
+ silent=False, concat=True) :
+ command = (oiio_app("maketx")
+ + " " + oiio_relpath(infile,tmpdir)
+ + " " + extraargs
+ + " -o " + oiio_relpath(outfile,tmpdir) )
+ if not silent :
+ command += " >> out.txt"
+ if concat:
+ command += " ;\n"
+ if showinfo:
+ command += info_command (outfile, extraargs=showinfo_extra, safematch=1)
+ return command
+
+
+
# Construct a command that will test the basic ability to read and write
# an image, appending output to the file "out.txt". First, iinfo the
# file, including a hash (VERY unlikely not to match if we've read
diff --git a/testsuite/tiff-misc/ref/check1.tif b/testsuite/tiff-misc/ref/check1.tif
new file mode 100644
index 0000000..0e7cca2
Binary files /dev/null and b/testsuite/tiff-misc/ref/check1.tif differ
diff --git a/testsuite/tiff-misc/run.py b/testsuite/tiff-misc/run.py
new file mode 100755
index 0000000..3bf4be9
--- /dev/null
+++ b/testsuite/tiff-misc/run.py
@@ -0,0 +1,11 @@
+#!/usr/bin/python
+
+# Miscellaneous TIFF-related tests
+
+
+
+# Regression test -- we once had a bug where 'separate' planarconfig
+# tiled float files would have data corrupted by a buffer overwrite.
+command += (oiio_app("oiiotool") + "--pattern checker 128x128 4 --tile 64 64 --planarconfig separate -d float -o check1.tif")
+
+outputs = [ "check1.tif" ]
--
OpenImageIO packaging
More information about the Pkg-phototools-commits
mailing list