[Pkg-phototools-commits] [SCM] openimageio branch, upstream, updated. upstream/1.1.5+dfsg0-1-g8c78cc0
Matteo F. Vescovi
mfv.debian at gmail.com
Tue Feb 12 09:15:01 UTC 2013
The following commit has been merged in the upstream branch:
commit 8c78cc01cbc6fc9d4a5c038e828845e50654c7c6
Author: Matteo F. Vescovi <mfv.debian at gmail.com>
Date: Tue Feb 12 10:12:19 2013 +0100
Imported Upstream version 1.1.6+dfsg0
diff --git a/CHANGES b/CHANGES
index ebb2394..e8c2b5b 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,32 @@
Changes:
+Release 1.1.6 (11 Feb 2013)
+---------------------------
+* Fix bug that could generate NaNs or other bad values near the poles of
+ very blurry environment lookups specifically from OpenEXR latlong env maps.
+* Fix bug in oiiotool --crop where it could mis-parse the geometric parameter.
+* Fix bug in ImageCache::invalidate() where it did not properly delete the
+ fingerprint of an invalidated file.
+* Cleanup and fixes in the oiiotool command line help messages.
+* New function ImageBufAlgo::paste() copies a region from one IB to another.
+* oiiotool --fit resizes an image to fit into a given resolution (keeping the
+ original aspect ratio and padding with black if needed).
+* ImageBufAlgo::channels() and "oiiotool --ch" have been extended to allow
+ new channels (specified to be filled with numeric constants) to also be
+ named.
+* New function ImageBufAlgo::mul() and "oiiotool --cmul" let you multiply
+ an image by a scalar constant (or per-channel constant).
+* Important maketx bug fix: when creating latlong environment maps as
+ OpenEXR files, it was adding energy near the poles, making low-res
+ MIP levels too bright near the poles.
+* Fix to "oiiotool --text" and "oiiotool --fill" -- both were
+ incorrectly making the base image black rather than drawing overtop of
+ the previous image.
+* Fix FreeBSD compile when not using TBB.
+* New oiiotool --swap exchanges the top two items on the image stack.
+
+
Release 1.1.5 (29 Jan 2013)
---------------------------
* Bug fix in ImageBufAlgo::parallel_image utility template -- care when
@@ -11,6 +37,7 @@ Release 1.1.5 (29 Jan 2013)
treat z=0 pixels as infinitely far away, not super close. You can turn
this on from oiiotool with: oiiotool --zover:zeroisinf=1 ...
+
Release 1.1.4 (27 Jan 2013)
---------------------------
* ImageBufAlgo::make_texture() allows you to do the same thing that
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 42523b4..d9aa5b9 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 5)
+set (OIIO_VERSION_PATCH 6)
cmake_minimum_required (VERSION 2.6)
if (NOT CMAKE_VERSION VERSION_LESS 2.8.4)
diff --git a/src/cmake/platform.cmake b/src/cmake/platform.cmake
index 768c645..df778c9 100644
--- a/src/cmake/platform.cmake
+++ b/src/cmake/platform.cmake
@@ -23,6 +23,13 @@ if (UNIX)
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
set (platform "FreeBSD")
set (CXXFLAGS "${CXXFLAGS} -DFREEBSD")
+ if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i386")
+ if (NOT USE_TBB)
+ # to use gcc atomics we need cpu instructions only available
+ # with arch of i586 or higher
+ set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=i586")
+ endif()
+ endif()
else ()
string (TOLOWER ${CMAKE_SYSTEM_NAME} platform)
endif ()
diff --git a/src/doc/oiiotool.tex b/src/doc/oiiotool.tex
index fe7c510..ed83d12 100644
--- a/src/doc/oiiotool.tex
+++ b/src/doc/oiiotool.tex
@@ -189,17 +189,41 @@ Convert a scanline file to a tiled file with $16 \times 16$ tiles:
\begin{code}
oiiotool foo.jpg --caption "Hawaii vacation" -o bar.jpg
oiiotool foo.jpg --keyword "volcano,lava" -o bar.jpg
+ oiiotool in.exr --attrib "FStop" 22.0 -o out.exr
\end{code}
+\subsection*{Scale the values in an image}
+
+Reduce the brightness of the R, G, and B channels by 10%%,
+but leave the A channel at its original value:
+
+\begin{code}
+ oiiotool original.exr --cmul 0.9,0.9,0.9,1.0 -o out.exr
+\end{code}
+
\subsection*{Resize an image}
+Resize by a known scale factor:
+
\begin{code}
oiiotool original.tif --resize 200% -o big.tif
oiiotool original.tif --resize 25% -o small.tif
+\end{code}
+
+\noindent Resize to a specific resolution:
+
+\begin{code}
oiiotool original.tif --resize 1024x768 -o specific.tif
\end{code}
+\noindent Resize to fit into a given resolution, keeping the original
+aspect ratio and padding with black where necessary:
+
+\begin{code}
+ oiiotool original.tif --fit 640x480 -o fit.tif
+\end{code}
+
\subsection*{Color convert an image}
@@ -253,6 +277,12 @@ image, and add an alpha channel that is 1 everywhere:
oiiotool allmyaovs.exr --ch spec.R,spec.G,spec.B,=1 -o spec.exr
\end{code}
+\noindent Add a channel to an RGBA image, setting it to 3.0 everywhere,
+and naming it ``Z'' so it will be recognized as a $z$ channel:
+\begin{code}
+ oiiotool rgba.exr --ch R,G,B,A,Z=3.0 -o rgbaz.exr
+\end{code}
+
\newpage
@@ -590,14 +620,19 @@ Note that this results in both the current and the next image
on the stack being identical copies.
\apiend
+\apiitem{--swap}
+\NEW
+Swap the current image and the next one on the stack.
+\apiend
+
\apiitem{--ch {\rm \emph{channellist}}}
Replaces the top image with a new copy whose channels have been
reordered as given by the \emph{channellist}. The {\cf channellist}
is a comma-separated list of channel names and/or numbers (e.g.,
-\qkw{R,G,B}, \emph{A}, \emph{B,G,R}, \emph{4,5,6,A}). Channel numbers outside
+\qkw{R,G,B}, \qkw{A}, \qkw{B,G,R}, \qkw{4,5,6,A}). Channel numbers outside
the valid range of input channels, or unknown names, will be replaced
by black channels.
-A channel designation beginning with the {\cf =} character and followed
+\NEW A channel designation beginning with the {\cf =} character and followed
by a number is a \emph{literal value} that will be used to fill that
channel. If the \emph{channellist} is shorter than the number of
channels in the source image, unspecified channels will be omitted.
@@ -720,6 +755,16 @@ Replace the current image with a new image that has each pixel
consisting of the \emph{absolute value} of he old pixel value.
\apiend
+\apiitem{--cmul {\rm \emph{value}} \\
+--cmul {\rm \emph{value0,value1,value2...}}}
+\NEW
+Multiply all the pixel values in the top image by a constant value.
+If a single constant value is given, all color channels will have their values
+multiplied by the same value. Alternatively, a series of
+comma-separated constant values (with no spaces!) may be used to specifiy a
+different multiplier for each channel in the image, respectively.
+\apiend
+
\apiitem{--over}
\index{composite}
Replace the \emph{two} top images with a new image that is the
@@ -791,7 +836,7 @@ the full/display window.
\apiitem{--resize {\rm \emph{size}}}
Replace the current image with a new image that is resized to the
-given pixel data resolution. The size is in the form
+given pixel data resolution. The \emph{size} is in the form
\\ \spc\spc \emph{width}\,{\cf x}\,\emph{height}
\\ or~~~~ \spc \emph{scale}{\verb|%|} \\
@@ -806,13 +851,31 @@ decreasing resolution. \\
\noindent Examples:
\begin{tabular}{p{2in} p{4in}}
- {\cf --resize 1024x768} & new resolution w=100, h=120, offset x=35, y=40 \\
+ {\cf --resize 1024x768} & new resolution w=100, h=120 \\
{\cf --resize 50{\verb|%|}} & reduce resolution to 50\verb|%| \\
{\cf --resize 300{\verb|%|}} & increase resolution by 3x
\end{tabular}
\apiend
+\apiitem{--fit {\rm \emph{size}}}
+\NEW
+Replace the current image with a new image that is resized to fit
+into the given pixel data resolution, keeping the original aspect ratio
+and padding with black pixels if the requested image size does not
+have the same aspect ratio. The \emph{size} is in the form
+\\ \spc\spc \emph{width}\,{\cf x}\,\emph{height}
+\\ or~~~~ \spc \emph{width}\,{\cf x}\,\emph{height}{\cf [+-]}\emph{xorigin}{\cf [+-]}\emph{yorigin} \\
+
+Optional appended arguments include:
+
+\begin{tabular}{p{10pt} p{1in} p{3.75in}}
+ & {\cf filter=}\emph{name} & Filter name. The default is {\cf
+ blackman-harris} when increasing resolution, {\cf lanczos3} when
+decreasing resolution. \\
+\end{tabular}
+\apiend
+
\apiitem{--fixnan {\rm \emph{streategy}}}
Replace the new image with a copy in which any pixels that contained
{\cf NaN} or {\cf Inf} values (hereafter referred to collectively as
diff --git a/src/doc/openimageio.tex b/src/doc/openimageio.tex
index 2f2a299..7d237b8 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, 29 Jan 2013)
+\\ (with corrections, 5 Feb 2013)
}}
diff --git a/src/include/imagebufalgo.h b/src/include/imagebufalgo.h
index afbc3a7..fe5cb4c 100644
--- a/src/include/imagebufalgo.h
+++ b/src/include/imagebufalgo.h
@@ -124,12 +124,17 @@ bool OIIO_API setNumChannels(ImageBuf &dst, const ImageBuf &src, int numChannels
/// Generic channel shuffling -- copy src to dst, but with channels in
/// the order channelorder[0..nchannels-1]. Does not support in-place
-/// operation. If channelorder[i] < 0, it will just make dst channel i
-/// be black (0.0) rather than copying from src.
-///
+/// operation. For any channel in which channelorder[i] < 0, it will
+/// just make dst channel i a constant color -- set to channelvalues[i]
+/// (if channelvalues != NULL) or 0.0 (if channelvalues == NULL).
+//
/// If channelorder is NULL, it will be interpreted as
-/// {0, 1, ..., nchannels-1}.
+/// {0, 1, ..., nchannels-1} (meaning that it's only renaming channels,
+/// not reordering them.
///
+/// If newchannelnames is not NULL, it points to an array of new channel
+/// names. Channels for which newchannelnames[i] is the empty string (or
+/// all channels, if newchannelnames == NULL) will be named as follows:
/// If shuffle_channel_names is false, the resulting dst image will have
/// default channel names in the usual order ("R", "G", etc.), but if
/// shuffle_channel_names is true, the names will be taken from the
@@ -137,8 +142,15 @@ bool OIIO_API setNumChannels(ImageBuf &dst, const ImageBuf &src, int numChannels
/// shuffling both channel ordering and their names could result in no
/// semantic change at all, if you catch the drift.
bool OIIO_API channels (ImageBuf &dst, const ImageBuf &src,
+ int nchannels, const int *channelorder,
+ const float *channelvalues=NULL,
+ const std::string *newchannelnames=NULL,
+ bool shuffle_channel_names=false);
+
+/// DEPRECATED -- for back-compatibility
+bool OIIO_API channels (ImageBuf &dst, const ImageBuf &src,
int nchannels, const int *channelorder,
- bool shuffle_channel_names=false);
+ bool shuffle_channel_names);
/// Make dst be a cropped copy of src, but with the new pixel data
/// window range [xbegin..xend) x [ybegin..yend). Source pixel data
@@ -151,6 +163,14 @@ bool OIIO_API crop (ImageBuf &dst, const ImageBuf &src,
const float *bordercolor=NULL);
+/// Copy into dst, beginning at (xbegin,ybegin,zbegin), the pixels of
+/// src described by srcroi. If srcroi is ROI(), the entirety of src
+/// will be used. It will copy into channels [chbegin...], as many
+/// channels as are described by srcroi.
+bool OIIO_API paste (ImageBuf &dst, int xbegin, int ybegin,
+ int zbegin, int chbegin,
+ const ImageBuf &src, ROI srcroi=ROI());
+
/// Add the pixels of two images A and B, putting the sum in dst.
/// The 'options' flag controls behaviors, particular of what happens
@@ -172,6 +192,18 @@ enum OIIO_API AddOptions
};
+/// For all pixels of R within region roi (defaulting to all the defined
+/// pixels in R), multiply their value by 'val'. Use the given number
+/// of threads.
+bool OIIO_API mul (ImageBuf &R, float val, ROI roi=ROI(), int threads=0);
+
+/// For all pixels of R within region roi (defaulting to all the defined
+/// pixels in R), multiply their value by val[0..nchans-1]. Use the
+/// given number of threads.
+bool OIIO_API mul (ImageBuf &R, const float *val, ROI roi=ROI(), int threads=0);
+
+
+
/// Apply a color transform to the pixel values
///
/// In-place operations (dst == src) are supported
@@ -595,6 +627,39 @@ parallel_image (Func f, ROI roi, int nthreads=0)
}
+
+// Macro to call a type-specialzed version func<type>(R,...)
+#define OIIO_DISPATCH_TYPES(name,func,type,R,...) \
+ switch (type.basetype) { \
+ case TypeDesc::FLOAT : \
+ return func<float> (R, __VA_ARGS__); break; \
+ case TypeDesc::UINT8 : \
+ return func<unsigned char> (R, __VA_ARGS__); break; \
+ case TypeDesc::HALF : \
+ return func<half> (R, __VA_ARGS__); break; \
+ case TypeDesc::UINT16: \
+ return func<unsigned short> (R, __VA_ARGS__); break; \
+ case TypeDesc::INT8 : \
+ return func<char> (R, __VA_ARGS__); break; \
+ case TypeDesc::INT16 : \
+ return func<short> (R, __VA_ARGS__); break; \
+ case TypeDesc::UINT : \
+ return func<unsigned int> (R, __VA_ARGS__); break; \
+ case TypeDesc::INT : \
+ return func<int> (R, __VA_ARGS__); break; \
+ case TypeDesc::UINT64: \
+ return func<unsigned long long> (R, __VA_ARGS__); break; \
+ case TypeDesc::INT64 : \
+ return func<long long> (R, __VA_ARGS__); break; \
+ case TypeDesc::DOUBLE: \
+ return func<double> (R, __VA_ARGS__); break; \
+ default: \
+ (R).error ("%s: Unsupported pixel data format '%s'", name, type); \
+ return false; \
+ }
+
+
+
}; // end namespace ImageBufAlgo
diff --git a/src/include/thread.h b/src/include/thread.h
index 5682f9b..92267f8 100644
--- a/src/include/thread.h
+++ b/src/include/thread.h
@@ -98,9 +98,9 @@
#endif
#if defined(__GNUC__) && (defined(_GLIBCXX_ATOMIC_BUILTINS) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 401))
-#if !defined(__FreeBSD__) || defined(__x86_64__)
-#define USE_GCC_ATOMICS
-#endif
+# if !USE_TBB
+# define USE_GCC_ATOMICS 1
+# endif
#endif
OIIO_NAMESPACE_ENTER
diff --git a/src/libOpenImageIO/imagebufalgo.cpp b/src/libOpenImageIO/imagebufalgo.cpp
index 961c787..0e70f0b 100644
--- a/src/libOpenImageIO/imagebufalgo.cpp
+++ b/src/libOpenImageIO/imagebufalgo.cpp
@@ -62,7 +62,6 @@
#endif
-
OIIO_NAMESPACE_ENTER
{
@@ -70,7 +69,7 @@ namespace
{
template<typename T>
-static inline void
+static inline bool
fill_ (ImageBuf &dst, const float *values, ROI roi=ROI())
{
int chbegin = roi.chbegin;
@@ -78,6 +77,7 @@ fill_ (ImageBuf &dst, const float *values, ROI roi=ROI())
for (ImageBuf::Iterator<T> p (dst, roi); !p.done(); ++p)
for (int c = chbegin, i = 0; c < chend; ++c, ++i)
p[c] = values[i];
+ return true;
}
}
@@ -86,23 +86,7 @@ bool
ImageBufAlgo::fill (ImageBuf &dst, const float *pixel, ROI roi)
{
ASSERT (pixel && "fill must have a non-NULL pixel value pointer");
- switch (dst.spec().format.basetype) {
- case TypeDesc::FLOAT : fill_<float> (dst, pixel, roi); break;
- case TypeDesc::UINT8 : fill_<unsigned char> (dst, pixel, roi); break;
- case TypeDesc::UINT16: fill_<unsigned short> (dst, pixel, roi); break;
- case TypeDesc::HALF : fill_<half> (dst, pixel, roi); break;
- case TypeDesc::INT8 : fill_<char> (dst, pixel, roi); break;
- case TypeDesc::INT16 : fill_<short> (dst, pixel, roi); break;
- case TypeDesc::UINT : fill_<unsigned int> (dst, pixel, roi); break;
- case TypeDesc::INT : fill_<int> (dst, pixel, roi); break;
- case TypeDesc::UINT64: fill_<unsigned long long> (dst, pixel, roi); break;
- case TypeDesc::INT64 : fill_<long long> (dst, pixel, roi); break;
- case TypeDesc::DOUBLE: fill_<double> (dst, pixel, roi); break;
- default:
- dst.error ("Unsupported pixel data format '%s'", dst.spec().format);
- return false;
- }
-
+ OIIO_DISPATCH_TYPES ("fill", fill_, dst.spec().format, dst, pixel, roi);
return true;
}
@@ -144,6 +128,84 @@ ImageBufAlgo::checker (ImageBuf &dst,
namespace {
template<class T>
+bool paste_ (ImageBuf &dst, int xbegin, int ybegin,
+ int zbegin, int chbegin,
+ const ImageBuf &src, ROI srcroi)
+{
+ const ImageSpec &dstspec (dst.spec());
+ if (dstspec.format.basetype != TypeDesc::FLOAT) {
+ dst.error ("paste: only 'float' destination images are supported");
+ return false;
+ }
+
+ ImageBuf::ConstIterator<T,float> s (src, srcroi.xbegin, srcroi.xend,
+ srcroi.ybegin, srcroi.yend,
+ srcroi.zbegin, srcroi.zend, true);
+ ImageBuf::Iterator<float,float> d (dst, xbegin, xbegin+srcroi.width(),
+ ybegin, ybegin+srcroi.height(),
+ zbegin, zbegin+srcroi.depth(), true);
+ int src_nchans = src.nchannels ();
+ int dst_nchans = dst.nchannels ();
+ for ( ; ! s.done(); ++s, ++d) {
+ if (! d.exists())
+ continue; // Skip paste-into pixels that don't overlap dst's data
+ if (s.exists()) {
+ for (int c = srcroi.chbegin, c_dst = chbegin;
+ c < srcroi.chend; ++c, ++c_dst) {
+ if (c_dst >= 0 && c_dst < dst_nchans)
+ d[c_dst] = c < src_nchans ? s[c] : 0.0f;
+ }
+ } else {
+ // Copying from outside src's data -- black
+ for (int c = srcroi.chbegin, c_dst = chbegin;
+ c < srcroi.chend; ++c, ++c_dst) {
+ if (c_dst >= 0 && c_dst < dst_nchans)
+ d[c_dst] = 0.0f;
+ }
+ }
+ }
+ return true;
+}
+
+}; // anon namespace
+
+
+
+bool
+ImageBufAlgo::paste (ImageBuf &dst, int xbegin, int ybegin,
+ int zbegin, int chbegin,
+ const ImageBuf &src, ROI srcroi)
+{
+ if (! srcroi.defined())
+ srcroi = get_roi(src.spec());
+
+ // If dst is uninitialized, size it like the region
+ if (!dst.initialized()) {
+ std::cerr << "Allocating space\n";
+ ImageSpec dst_spec = src.spec();
+ dst_spec.x = srcroi.xbegin;
+ dst_spec.y = srcroi.ybegin;
+ dst_spec.z = srcroi.zbegin;
+ dst_spec.width = srcroi.width();
+ dst_spec.height = srcroi.height();
+ dst_spec.depth = srcroi.depth();
+ dst_spec.nchannels = srcroi.nchannels();
+ dst_spec.set_format (TypeDesc::FLOAT);
+ dst.alloc (dst_spec);
+ }
+
+ // do the actual copying
+ OIIO_DISPATCH_TYPES ("paste", paste_, src.spec().format,
+ dst, xbegin, ybegin, zbegin, chbegin, src, srcroi);
+ return false;
+}
+
+
+
+
+namespace {
+
+template<class T>
bool crop_ (ImageBuf &dst, const ImageBuf &src,
int xbegin, int xend, int ybegin, int yend,
const float *bordercolor)
@@ -194,47 +256,8 @@ ImageBufAlgo::crop (ImageBuf &dst, const ImageBuf &src,
if (!dst.pixels_valid())
dst.alloc (dst_spec);
- // do the actual copying
- switch (src.spec().format.basetype) {
- case TypeDesc::FLOAT :
- return crop_<float> (dst, src, xbegin, xend, ybegin, yend, bordercolor);
- break;
- case TypeDesc::UINT8 :
- return crop_<unsigned char> (dst, src, xbegin, xend, ybegin, yend, bordercolor);
- break;
- case TypeDesc::INT8 :
- return crop_<char> (dst, src, xbegin, xend, ybegin, yend, bordercolor);
- break;
- case TypeDesc::UINT16:
- return crop_<unsigned short> (dst, src, xbegin, xend, ybegin, yend, bordercolor);
- break;
- case TypeDesc::INT16 :
- return crop_<short> (dst, src, xbegin, xend, ybegin, yend, bordercolor);
- break;
- case TypeDesc::UINT :
- return crop_<unsigned int> (dst, src, xbegin, xend, ybegin, yend, bordercolor);
- break;
- case TypeDesc::INT :
- return crop_<int> (dst, src, xbegin, xend, ybegin, yend, bordercolor);
- break;
- case TypeDesc::UINT64:
- return crop_<unsigned long long> (dst, src, xbegin, xend, ybegin, yend, bordercolor);
- break;
- case TypeDesc::INT64 :
- return crop_<long long> (dst, src, xbegin, xend, ybegin, yend, bordercolor);
- break;
- case TypeDesc::HALF :
- return crop_<half> (dst, src, xbegin, xend, ybegin, yend, bordercolor);
- break;
- case TypeDesc::DOUBLE:
- return crop_<double> (dst, src, xbegin, xend, ybegin, yend, bordercolor);
- break;
- default:
- dst.error ("Unsupported pixel data format '%s'", src.spec().format);
- return false;
- }
-
- ASSERT (0);
+ OIIO_DISPATCH_TYPES ("crop", crop_, src.spec().format,
+ dst, src, xbegin, xend, ybegin, yend, bordercolor);
return false;
}
@@ -246,6 +269,20 @@ ImageBufAlgo::channels (ImageBuf &dst, const ImageBuf &src,
int nchannels, const int *channelorder,
bool shuffle_channel_names)
{
+ // DEPRECATED -- just provide link compatibility
+ return channels (dst, src, nchannels, channelorder, NULL, NULL,
+ shuffle_channel_names);
+}
+
+
+
+bool
+ImageBufAlgo::channels (ImageBuf &dst, const ImageBuf &src,
+ int nchannels, const int *channelorder,
+ const float *channelvalues,
+ const std::string *newchannelnames,
+ bool shuffle_channel_names)
+{
// Not intended to create 0-channel images.
if (nchannels <= 0) {
dst.error ("%d-channel images not supported", nchannels);
@@ -280,19 +317,30 @@ ImageBufAlgo::channels (ImageBuf &dst, const ImageBuf &src,
ImageSpec newspec = src.spec();
newspec.nchannels = nchannels;
newspec.default_channel_names ();
- if (shuffle_channel_names) {
- newspec.alpha_channel = -1;
- newspec.z_channel = -1;
- for (int c = 0; c < nchannels; ++c) {
- int csrc = channelorder[c];
- if (csrc >= 0 && csrc < src.spec().nchannels) {
- newspec.channelnames[c] = src.spec().channelnames[csrc];
- if (csrc == src.spec().alpha_channel)
- newspec.alpha_channel = c;
- if (csrc == src.spec().z_channel)
- newspec.z_channel = c;
- }
- }
+ newspec.alpha_channel = -1;
+ newspec.z_channel = -1;
+ for (int c = 0; c < nchannels; ++c) {
+ int csrc = channelorder[c];
+ // If the user gave an explicit name for this channel, use it...
+ if (newchannelnames && newchannelnames[c].size())
+ newspec.channelnames[c] = newchannelnames[c];
+ // otherwise, if shuffle_channel_names, use the channel name of
+ // the src channel we're using (otherwise stick to the default name)
+ else if (shuffle_channel_names &&
+ csrc >= 0 && csrc < src.spec().nchannels)
+ newspec.channelnames[c] = src.spec().channelnames[csrc];
+ // otherwise, use the name of the source in that slot
+ else if (csrc >= 0 && csrc < src.spec().nchannels)
+ newspec.channelnames[c] = src.spec().channelnames[c];
+ // Use the names (or designation of the src image, if
+ // shuffle_channel_names is true) to deduce the alpha and z channels.
+ if ((shuffle_channel_names && csrc == src.spec().alpha_channel) ||
+ Strutil::iequals (newspec.channelnames[c], "A") ||
+ Strutil::iequals (newspec.channelnames[c], "alpha"))
+ newspec.alpha_channel = c;
+ if ((shuffle_channel_names && csrc == src.spec().z_channel) ||
+ Strutil::iequals (newspec.channelnames[c], "Z"))
+ newspec.z_channel = c;
}
// Update the image (realloc with the new spec)
@@ -307,6 +355,7 @@ ImageBufAlgo::channels (ImageBuf &dst, const ImageBuf &src,
char *pixels = (char *) dst.pixeladdr (dst.xbegin(), dst.ybegin(),
dst.zbegin());
for (int c = 0; c < nchannels; ++c) {
+ // Copy shuffled channels
if (channelorder[c] >= 0 && channelorder[c] < src.spec().nchannels) {
int csrc = channelorder[c];
src.get_pixel_channels (src.xbegin(), src.xend(),
@@ -315,6 +364,13 @@ ImageBufAlgo::channels (ImageBuf &dst, const ImageBuf &src,
csrc, csrc+1, newspec.format, pixels,
dstxstride, dstystride, dstzstride);
}
+ // Set channels that are literals
+ if (channelorder[c] < 0 && channelvalues && channelvalues[c]) {
+ ROI roi = get_roi (dst.spec());
+ roi.chbegin = c;
+ roi.chend = c+1;
+ ImageBufAlgo::fill (dst, &channelvalues[c], roi);
+ }
pixels += channelsize;
}
return true;
@@ -458,6 +514,54 @@ ImageBufAlgo::add (ImageBuf &dst, const ImageBuf &A, const ImageBuf &B,
}
+
+namespace {
+
+template<class Rtype>
+static bool
+mul_impl (ImageBuf &R, const float *val, ROI roi, int nthreads)
+{
+ if (nthreads == 1 || roi.npixels() < 1000) {
+ // For-sure single thread case
+ for (ImageBuf::Iterator<Rtype> r (R, roi); !r.done(); ++r)
+ for (int c = roi.chbegin; c < roi.chend; ++c)
+ r[c] = r[c] * val[c];
+ } else {
+ // Possible multiple thread case -- recurse via parallel_image
+ ImageBufAlgo::parallel_image (boost::bind(mul_impl<Rtype>,
+ boost::ref(R), val, _1, 1),
+ roi, nthreads);
+ }
+ return true;
+}
+
+
+} // anon namespace
+
+
+bool
+ImageBufAlgo::mul (ImageBuf &R, const float *val, ROI roi, int nthreads)
+{
+ roi.chend = std::min (roi.chend, R.nchannels()); // clamp
+ OIIO_DISPATCH_TYPES ("mul", mul_impl, R.spec().format,
+ R, val, roi, nthreads);
+ return true;
+}
+
+
+
+bool
+ImageBufAlgo::mul (ImageBuf &R, float val, ROI roi, int nthreads)
+{
+ int nc = R.nchannels();
+ float *vals = ALLOCA (float, nc);
+ for (int c = 0; c < nc; ++c)
+ vals[c] = val;
+ return mul (R, vals, roi, nthreads);
+}
+
+
+
bool
ImageBufAlgo::computePixelStats (PixelStats &stats, const ImageBuf &src)
{
@@ -744,22 +848,8 @@ isConstantColor_ (const ImageBuf &src, float *color)
bool
ImageBufAlgo::isConstantColor (const ImageBuf &src, float *color)
{
- switch (src.spec().format.basetype) {
- case TypeDesc::FLOAT : return isConstantColor_<float> (src, color); break;
- case TypeDesc::UINT8 : return isConstantColor_<unsigned char> (src, color); break;
- case TypeDesc::INT8 : return isConstantColor_<char> (src, color); break;
- case TypeDesc::UINT16: return isConstantColor_<unsigned short> (src, color); break;
- case TypeDesc::INT16 : return isConstantColor_<short> (src, color); break;
- case TypeDesc::UINT : return isConstantColor_<unsigned int> (src, color); break;
- case TypeDesc::INT : return isConstantColor_<int> (src, color); break;
- case TypeDesc::UINT64: return isConstantColor_<unsigned long long> (src, color); break;
- case TypeDesc::INT64 : return isConstantColor_<long long> (src, color); break;
- case TypeDesc::HALF : return isConstantColor_<half> (src, color); break;
- case TypeDesc::DOUBLE: return isConstantColor_<double> (src, color); break;
- default:
- src.error ("Unsupported pixel data format '%s'", src.spec().format);
- return false;
- }
+ OIIO_DISPATCH_TYPES ("isConstantColor", isConstantColor_,
+ src.spec().format, src, color);
};
@@ -782,22 +872,8 @@ isConstantChannel_ (const ImageBuf &src, int channel, float val)
bool
ImageBufAlgo::isConstantChannel (const ImageBuf &src, int channel, float val)
{
- switch (src.spec().format.basetype) {
- case TypeDesc::FLOAT : return isConstantChannel_<float> (src, channel, val); break;
- case TypeDesc::UINT8 : return isConstantChannel_<unsigned char> (src, channel, val); break;
- case TypeDesc::INT8 : return isConstantChannel_<char> (src, channel, val); break;
- case TypeDesc::UINT16: return isConstantChannel_<unsigned short> (src, channel, val); break;
- case TypeDesc::INT16 : return isConstantChannel_<short> (src, channel, val); break;
- case TypeDesc::UINT : return isConstantChannel_<unsigned int> (src, channel, val); break;
- case TypeDesc::INT : return isConstantChannel_<int> (src, channel, val); break;
- case TypeDesc::UINT64: return isConstantChannel_<unsigned long long> (src, channel, val); break;
- case TypeDesc::INT64 : return isConstantChannel_<long long> (src, channel, val); break;
- case TypeDesc::HALF : return isConstantChannel_<half> (src, channel, val); break;
- case TypeDesc::DOUBLE: return isConstantChannel_<double> (src, channel, val); break;
- default:
- src.error ("Unsupported pixel data format '%s'", src.spec().format);
- return false;
- }
+ OIIO_DISPATCH_TYPES ("isConstantChannel", isConstantChannel_,
+ src.spec().format, src, channel, val);
};
namespace
@@ -805,7 +881,7 @@ namespace
template<typename T>
static inline bool
-isMonochrome_ (const ImageBuf &src)
+isMonochrome_ (const ImageBuf &src, int dummy)
{
int nchannels = src.nchannels();
if (nchannels < 2) return true;
@@ -829,22 +905,8 @@ isMonochrome_ (const ImageBuf &src)
bool
ImageBufAlgo::isMonochrome(const ImageBuf &src)
{
- switch (src.spec().format.basetype) {
- case TypeDesc::FLOAT : return isMonochrome_<float> (src); break;
- case TypeDesc::UINT8 : return isMonochrome_<unsigned char> (src); break;
- case TypeDesc::INT8 : return isMonochrome_<char> (src); break;
- case TypeDesc::UINT16: return isMonochrome_<unsigned short> (src); break;
- case TypeDesc::INT16 : return isMonochrome_<short> (src); break;
- case TypeDesc::UINT : return isMonochrome_<unsigned int> (src); break;
- case TypeDesc::INT : return isMonochrome_<int> (src); break;
- case TypeDesc::UINT64: return isMonochrome_<unsigned long long> (src); break;
- case TypeDesc::INT64 : return isMonochrome_<long long> (src); break;
- case TypeDesc::HALF : return isMonochrome_<half> (src); break;
- case TypeDesc::DOUBLE: return isMonochrome_<double> (src); break;
- default:
- src.error ("Unsupported pixel data format '%s'", src.spec().format);
- return false;
- }
+ OIIO_DISPATCH_TYPES ("isMonochrome", isMonochrome_, src.spec().format,
+ src, 0);
};
std::string
@@ -1068,35 +1130,8 @@ ImageBufAlgo::resize (ImageBuf &dst, const ImageBuf &src,
int xbegin, int xend, int ybegin, int yend,
Filter2D *filter)
{
- switch (src.spec().format.basetype) {
- case TypeDesc::FLOAT :
- return resize_<float> (dst, src, xbegin, xend, ybegin, yend, filter);
- case TypeDesc::UINT8 :
- return resize_<unsigned char> (dst, src, xbegin, xend, ybegin, yend, filter);
- case TypeDesc::INT8 :
- return resize_<char> (dst, src, xbegin, xend, ybegin, yend, filter);
- case TypeDesc::UINT16:
- return resize_<unsigned short> (dst, src, xbegin, xend, ybegin, yend, filter);
- case TypeDesc::INT16 :
- return resize_<short> (dst, src, xbegin, xend, ybegin, yend, filter);
- case TypeDesc::UINT :
- return resize_<unsigned int> (dst, src, xbegin, xend, ybegin, yend, filter);
- case TypeDesc::INT :
- return resize_<int> (dst, src, xbegin, xend, ybegin, yend, filter);
- case TypeDesc::UINT64:
- return resize_<unsigned long long> (dst, src, xbegin, xend, ybegin, yend, filter);
- case TypeDesc::INT64 :
- return resize_<long long> (dst, src, xbegin, xend, ybegin, yend, filter);
- case TypeDesc::HALF :
- return resize_<half> (dst, src, xbegin, xend, ybegin, yend, filter);
- case TypeDesc::DOUBLE:
- return resize_<double> (dst, src, xbegin, xend, ybegin, yend, filter);
- default:
- dst.error ("Unsupported pixel data format '%s'", src.spec().format);
- return false;
- }
-
- ASSERT (0);
+ OIIO_DISPATCH_TYPES ("resize", resize_, src.spec().format,
+ dst, src, xbegin, xend, ybegin, yend, filter);
return false;
}
diff --git a/src/libOpenImageIO/imagebufalgo_test.cpp b/src/libOpenImageIO/imagebufalgo_test.cpp
index a4c2c6b..8ac29c9 100644
--- a/src/libOpenImageIO/imagebufalgo_test.cpp
+++ b/src/libOpenImageIO/imagebufalgo_test.cpp
@@ -149,6 +149,49 @@ void test_crop ()
+void test_paste ()
+{
+ // Create the source image, make it a gradient
+ ImageSpec Aspec (4, 4, 3, TypeDesc::FLOAT);
+ ImageBuf A ("A", Aspec);
+ for (ImageBuf::Iterator<float> it (A); !it.done(); ++it) {
+ it[0] = float(it.x()) / float(Aspec.width-1);
+ it[1] = float(it.y()) / float(Aspec.height-1);
+ it[2] = 0.1f;
+ }
+
+ // Create destination image -- black it out
+ ImageSpec Bspec (8, 8, 3, TypeDesc::FLOAT);
+ ImageBuf B ("B", Bspec);
+ float gray[3] = { .1, .1, .1 };
+ ImageBufAlgo::fill (B, gray);
+
+ // Paste a few pixels from A into B -- include offsets
+ ImageBufAlgo::paste (B, 2, 2, 0, 1 /* chan offset */,
+ A, ROI(1, 4, 1, 4));
+
+ // Spot check
+ float a[3], b[3];
+ B.getpixel (1, 1, 0, b);
+ OIIO_CHECK_EQUAL (b[0], gray[0]);
+ OIIO_CHECK_EQUAL (b[1], gray[1]);
+ OIIO_CHECK_EQUAL (b[2], gray[2]);
+
+ B.getpixel (2, 2, 0, b);
+ A.getpixel (1, 1, 0, a);
+ OIIO_CHECK_EQUAL (b[0], gray[0]);
+ OIIO_CHECK_EQUAL (b[1], a[0]);
+ OIIO_CHECK_EQUAL (b[2], a[1]);
+
+ B.getpixel (3, 4, 0, b);
+ A.getpixel (2, 3, 0, a);
+ OIIO_CHECK_EQUAL (b[0], gray[0]);
+ OIIO_CHECK_EQUAL (b[1], a[0]);
+ OIIO_CHECK_EQUAL (b[2], a[1]);
+}
+
+
+
// Tests ImageBufAlgo::add
void test_add ()
{
@@ -231,6 +274,7 @@ main (int argc, char **argv)
{
test_zero_fill ();
test_crop ();
+ test_paste ();
test_add ();
test_compare ();
diff --git a/src/libOpenImageIO/maketexture.cpp b/src/libOpenImageIO/maketexture.cpp
index 503bada..af92848 100644
--- a/src/libOpenImageIO/maketexture.cpp
+++ b/src/libOpenImageIO/maketexture.cpp
@@ -310,8 +310,6 @@ fix_latl_edges (ImageBuf &buf)
left[c] += right[c];
}
for (int c = 0; c < n; ++c)
- left[c] += right[c];
- for (int c = 0; c < n; ++c)
left[c] *= wscale;
for (int x = buf.xbegin(); x < buf.xend(); ++x)
buf.setpixel (x, y, left);
diff --git a/src/libtexture/imagecache.cpp b/src/libtexture/imagecache.cpp
index ce5ea47..a919401 100644
--- a/src/libtexture/imagecache.cpp
+++ b/src/libtexture/imagecache.cpp
@@ -2419,6 +2419,8 @@ ImageCacheImpl::invalidate (ustring filename)
tilemutex_holder (NULL);
}
+ ustring fingerprint = file->fingerprint();
+
{
ic_write_lock fileguard (m_filemutex);
file->invalidate ();
@@ -2427,7 +2429,7 @@ ImageCacheImpl::invalidate (ustring filename)
// Remove the fingerprint corresponding to this file
{
spin_lock lock (m_fingerprints_mutex);
- FilenameMap::iterator f = m_fingerprints.find (filename);
+ FilenameMap::iterator f = m_fingerprints.find (fingerprint);
if (f != m_fingerprints.end())
m_fingerprints.erase (f);
}
diff --git a/src/libtexture/texturesys.cpp b/src/libtexture/texturesys.cpp
index c5fdd90..34b7b1a 100644
--- a/src/libtexture/texturesys.cpp
+++ b/src/libtexture/texturesys.cpp
@@ -161,16 +161,17 @@ bool
TextureSystemImpl::wrap_periodic_sharedborder (int &coord, int origin, int width)
{
// Like periodic, but knowing that the first column and last are
- // actually the same position, so we essentially skip the first
- // column in the next cycle. We only need this to work for one wrap
- // in each direction since it's only used for latlong maps.
- coord -= origin;
- if (coord >= width) {
- coord = coord - width + 1;
- } else if (coord < 0) {
- coord = coord + width - 1;
+ // actually the same position, so we essentially skip the last
+ // column in the next cycle.
+ if (width <= 2) {
+ coord = origin; // special case -- just 1 pixel wide
+ } else {
+ coord -= origin;
+ coord %= (width-1);
+ if (coord < 0) // Fix negative values
+ coord += width;
+ coord += origin;
}
- coord += origin;
return true;
}
diff --git a/src/maketx/maketx.cpp b/src/maketx/maketx.cpp
index 410cb7c..6f0fd52 100644
--- a/src/maketx/maketx.cpp
+++ b/src/maketx/maketx.cpp
@@ -624,8 +624,6 @@ fix_latl_edges (ImageBuf &buf)
left[c] += right[c];
}
for (int c = 0; c < n; ++c)
- left[c] += right[c];
- for (int c = 0; c < n; ++c)
left[c] *= wscale;
for (int x = buf.xbegin(); x < buf.xend(); ++x)
buf.setpixel (x, y, left);
diff --git a/src/oiiotool/imagerec.cpp b/src/oiiotool/imagerec.cpp
index 65a7479..dbb7c75 100644
--- a/src/oiiotool/imagerec.cpp
+++ b/src/oiiotool/imagerec.cpp
@@ -86,18 +86,8 @@ ImageRec::ImageRec (ImageRec &img, int subimage_to_copy,
if (writable || img.pixels_modified() || !copy_pixels) {
// Make our own copy of the pixels
ib = new ImageBuf (img.name(), srcspec);
- if (copy_pixels) {
- ImageBuf::ConstIterator<float> src (srcib);
- ASSERT (src.rawptr());
- ImageBuf::Iterator<float> dst (*ib);
- int nchans = ib->nchannels();
- while (! src.done()) {
- for (int c = 0; c < nchans; ++c)
- dst[c] = src[c];
- ++src;
- ++dst;
- }
- }
+ if (copy_pixels)
+ ib->copy_pixels (srcib);
} else {
// The other image is not modified, and we don't need to be
// writable, either.
diff --git a/src/oiiotool/oiiotool.cpp b/src/oiiotool/oiiotool.cpp
index 424d52b..9a70423 100644
--- a/src/oiiotool/oiiotool.cpp
+++ b/src/oiiotool/oiiotool.cpp
@@ -64,6 +64,22 @@ static Oiiotool ot;
+std::string
+format_resolution (int w, int h, int x, int y)
+{
+#if 0
+ // This should work...
+ return Strutil::format ("%dx%d%+d%+d", w, h, x, y);
+ // ... but tinyformat doesn't print the sign for '0' values! It
+ // appears to be a bug with iostream use of 'showpos' format flag,
+ // specific to certain gcc libs, perhaps only on OSX. Workaround:
+#else
+ return Strutil::format ("%dx%d%c%d%c%d", w, h,
+ x >= 0 ? '+' : '-', abs(x),
+ y >= 0 ? '+' : '-', abs(y));
+#endif
+}
+
// FIXME -- lots of things we skimped on so far:
// FIXME: check binary ops for compatible image dimensions
@@ -880,11 +896,18 @@ action_unmip (int argc, const char *argv[])
// For a given spec (which contains the channel names for an image), and
// a comma separated list of channels (e.g., "B,G,R,A"), compute the
// vector of integer indices for those channels (e.g., {2,1,0,3}).
+// A channel may be a literal assignment (e.g., "=0.5"), or a literal
+// assignment with channel naming (e.g., "Z=0.5").
// Return true for success, false for failure, including if any of the
-// channels were not present in the image.
+// channels were not present in the image. Upon return, channels
+// will be the indices of the source image channels to copy (-1 for
+// channels that are not filled with source data), values will hold
+// the value to fill un-sourced channels (defaulting to zero), and
+// newchannelnames will be the name of renamed or non-default-named
+// channels (defaulting to "" if no special name is needed).
static bool
decode_channel_set (const ImageSpec &spec, std::string chanlist,
- std::vector<std::string> &channelnames,
+ std::vector<std::string> &newchannelnames,
std::vector<int> &channels, std::vector<float> &values)
{
channels.clear ();
@@ -899,18 +922,26 @@ decode_channel_set (const ImageSpec &spec, std::string chanlist,
chanlist = chanlist.substr (pos+1, std::string::npos);
// Find the index corresponding to that channel
+ newchannelnames.push_back (std::string());
float value = 0.0f;
int ch = -1;
for (int i = 0; i < spec.nchannels; ++i)
- if (spec.channelnames[i] == onechan) {
- ch = i; break;
+ if (spec.channelnames[i] == onechan) { // name of a known channel?
+ ch = i;
+ break;
}
if (ch < 0 && onechan.length() &&
(isdigit(onechan[0]) || onechan[0] == '-'))
- ch = atoi (onechan.c_str());
- if (ch < 0 && onechan.length() && onechan[0] == '=')
- value = atof (onechan.c_str()+1);
- channelnames.push_back (onechan);
+ ch = atoi (onechan.c_str()); // numeric channel index
+ if (ch < 0 && onechan.length()) {
+ // Look for Either =val or name=val
+ size_t equal_pos = onechan.find ('=');
+ if (equal_pos != std::string::npos) {
+ value = atof (onechan.c_str()+equal_pos+1);
+ onechan.erase (equal_pos);
+ newchannelnames.back() = onechan;
+ }
+ }
channels.push_back (ch);
values.push_back (value);
}
@@ -940,11 +971,11 @@ action_channels (int argc, const char *argv[])
std::vector<ImageSpec> allspecs;
for (int s = 0, subimages = ot.allsubimages ? A->subimages() : 1;
s < subimages; ++s) {
- std::vector<std::string> channelnames;
+ std::vector<std::string> newchannelnames;
std::vector<int> channels;
std::vector<float> values;
bool ok = decode_channel_set (*A->spec(s,0), chanlist,
- channelnames, channels, values);
+ newchannelnames, channels, values);
if (! ok) {
ot.error (argv[0], Strutil::format("Invalid or unknown channel selection \"%s\"", chanlist));
ot.push (A);
@@ -954,9 +985,9 @@ action_channels (int argc, const char *argv[])
allmiplevels.push_back (miplevels);
for (int m = 0; m < miplevels; ++m) {
ImageSpec spec = *A->spec(s,m);
- spec.nchannels = (int)channelnames.size();
- spec.default_channel_names ();
+ spec.nchannels = (int)newchannelnames.size();
spec.channelformats.clear();
+ spec.default_channel_names ();
allspecs.push_back (spec);
}
}
@@ -969,23 +1000,16 @@ action_channels (int argc, const char *argv[])
// Subimage by subimage, MIP level by MIP level, copy/shuffle the
// channels individually from the source image into the result.
for (int s = 0, subimages = R->subimages(); s < subimages; ++s) {
- std::vector<std::string> channelnames;
+ std::vector<std::string> newchannelnames;
std::vector<int> channels;
std::vector<float> values;
- decode_channel_set (*A->spec(s,0), chanlist, channelnames,
+ decode_channel_set (*A->spec(s,0), chanlist, newchannelnames,
channels, values);
for (int m = 0, miplevels = R->miplevels(s); m < miplevels; ++m) {
// Shuffle the indexed/named channels
ImageBufAlgo::channels ((*R)(s,m), (*A)(s,m), (int)channels.size(),
- &channels[0], false);
- // Set channels that are literals
- for (int c = 0; c < (int)channels.size(); ++c)
- if (channels[c] < 0) {
- ROI roi = get_roi (*R->spec(s,m));
- roi.chbegin = c;
- roi.chend = c+1;
- ImageBufAlgo::fill ((*R)(s,m), &values[c], roi);
- }
+ &channels[0], &values[0], &newchannelnames[0],
+ false);
// Tricky subtlety: IBA::channels changed the underlying IB,
// we may need to update the IRR's copy of the spec.
R->update_spec_from_imagebuf(s,m);
@@ -1165,6 +1189,48 @@ action_abs (int argc, const char *argv[])
static int
+action_cmul (int argc, const char *argv[])
+{
+ if (ot.postpone_callback (1, action_abs, argc, argv))
+ return 0;
+
+ std::vector<std::string> scalestrings;
+ Strutil::split (std::string(argv[1]), scalestrings, ",");
+ if (scalestrings.size() < 1)
+ return 0; // Implicit multiplication by 1 if we can't figure it out
+
+ ImageRecRef A = ot.pop();
+ A->read ();
+ ImageRecRef R (new ImageRec (*A, ot.allsubimages ? -1 : 0,
+ ot.allsubimages ? -1 : 0,
+ true /*writable*/, true /*copy_pixels*/));
+ ot.push (R);
+
+ std::vector<float> scale;
+ int subimages = ot.curimg->subimages();
+ for (int s = 0; s < subimages; ++s) {
+ int nchans = R->spec(s,0)->nchannels;
+ scale.clear ();
+ scale.resize (nchans, atof(scalestrings[0].c_str()));
+ if (scalestrings.size() > 1) {
+ for (int c = 0; c < nchans; ++c) {
+ if (c < (int)scalestrings.size())
+ scale[c] = atof(scalestrings[c].c_str());
+ else
+ scale[c] = 1.0f;
+ }
+ }
+ int miplevels = ot.curimg->miplevels(s);
+ for (int m = 0; m < miplevels; ++m)
+ ImageBufAlgo::mul ((*R)(s,m), &scale[0]);
+ }
+
+ return 0;
+}
+
+
+
+static int
action_flip (int argc, const char *argv[])
{
if (ot.postpone_callback (1, action_flip, argc, argv))
@@ -1291,6 +1357,21 @@ action_dup (int argc, const char *argv[])
}
+static int
+action_swap (int argc, const char *argv[])
+{
+ ASSERT (argc == 1);
+ if (ot.image_stack.size() < 1) {
+ ot.error (argv[0], "requires at least two loaded images");
+ return 0;
+ }
+ ImageRecRef B (ot.pop());
+ ImageRecRef A (ot.pop());
+ ot.push (B);
+ ot.push (A);
+ return 0;
+}
+
static int
action_create (int argc, const char *argv[])
@@ -1301,7 +1382,7 @@ action_create (int argc, const char *argv[])
std::cout << "Invalid number of channels: " << nchans << "\n";
nchans = 3;
}
- ImageSpec spec (64, 64, nchans);
+ ImageSpec spec (64, 64, nchans, TypeDesc::FLOAT);
adjust_geometry (spec.width, spec.height, spec.x, spec.y, argv[1]);
spec.full_x = spec.x;
spec.full_y = spec.y;
@@ -1467,21 +1548,8 @@ action_croptofull (int argc, const char *argv[])
const ImageSpec &Aspec (*A->spec(0,0));
// Implement by calling action_crop with a geometry specifier built
// from the current full image size.
-#if 0
- // This should work...
- std::string size = Strutil::format ("%dx%d%+d%+d",
- Aspec.full_width, Aspec.full_height,
- Aspec.full_x, Aspec.full_y);
- // ... but tinyformat doesn't print the sign for '0' values! It
- // appears to be a bug with iostream use of 'showpos' format flag,
- // specific to certain gcc libs, perhaps only on OSX. Workaround:
-#else
- std::string size = Strutil::format ("%dx%d%c%d%c%d",
- Aspec.full_width, Aspec.full_height,
- Aspec.full_x >= 0 ? '+' : '-',
- Aspec.full_y >= 0 ? '+' : '-',
- abs(Aspec.full_x), abs(Aspec.full_y));
-#endif
+ std::string size = format_resolution (Aspec.full_width, Aspec.full_height,
+ Aspec.full_x, Aspec.full_y);
const char *newargv[2] = { "crop", size.c_str() };
return action_crop (2, newargv);
}
@@ -1566,6 +1634,85 @@ action_resize (int argc, const char *argv[])
+static int
+action_fit (int argc, const char *argv[])
+{
+ if (ot.postpone_callback (1, action_fit, argc, argv))
+ return 0;
+
+ // Examine the top of stack
+ ImageRecRef A = ot.top();
+ ot.read ();
+ const ImageSpec *Aspec = A->spec(0,0);
+
+ // Parse the user request for resolution to fit
+ int fit_full_width = Aspec->full_width;
+ int fit_full_height = Aspec->full_height;
+ int fit_full_x = Aspec->full_x;
+ int fit_full_y = Aspec->full_y;
+ adjust_geometry (fit_full_width, fit_full_height, fit_full_x, fit_full_y,
+ argv[1], false);
+
+ // Compute scaling factors and use action_resize to do the heavy lifting
+ float wfactor = float(fit_full_width) / Aspec->full_width;
+ float hfactor = float(fit_full_height) / Aspec->full_height;
+ int resize_full_width = fit_full_width;
+ int resize_full_height = fit_full_height;
+ if (wfactor <= hfactor)
+ resize_full_height = int(Aspec->full_height * wfactor);
+ else
+ resize_full_width = int(Aspec->full_width * hfactor);
+ if (ot.verbose) {
+ std::cout << "Fitting "
+ << format_resolution(Aspec->full_width, Aspec->full_height,
+ Aspec->x, Aspec->y)
+ << " into "
+ << format_resolution(fit_full_width, fit_full_height,
+ fit_full_x, fit_full_y)
+ << "\n";
+ std::cout << " Resizing to "
+ << format_resolution(resize_full_width, resize_full_height,
+ fit_full_x, fit_full_y) << "\n";
+ }
+ if (resize_full_width != Aspec->full_width ||
+ resize_full_height != Aspec->full_height ||
+ fit_full_x != Aspec->full_x || fit_full_y != Aspec->full_y) {
+ std::string resize = format_resolution (resize_full_width,
+ resize_full_height,
+ fit_full_x, fit_full_y);
+ const char *newargv[2] = { "resize", resize.c_str() };
+ action_resize (2, newargv);
+ A = ot.top ();
+ Aspec = A->spec(0,0);
+ // Now A,Aspec are for the NEW resized top of stack
+ }
+
+ if (fit_full_width != resize_full_width ||
+ fit_full_height != Aspec->full_height) {
+ // Needs padding
+ ImageSpec newspec = *Aspec;
+ newspec.width = newspec.full_width = fit_full_width;
+ newspec.height = newspec.full_height = fit_full_height;
+ newspec.x = newspec.full_x = fit_full_x;
+ newspec.y = newspec.full_y = fit_full_y;
+ newspec.set_format (TypeDesc::FLOAT);
+ ImageRecRef B (new ImageRec (A->name(), newspec, ot.imagecache));
+ ImageBuf &Rib ((*B)(0,0));
+ ot.curimg = B;
+ ImageBufAlgo::zero (Rib);
+ if (Aspec->full_width == fit_full_width)
+ ImageBufAlgo::paste (Rib, 0, (fit_full_height-Aspec->full_height)/2,
+ 0, 0, (*A)(0,0));
+ else
+ ImageBufAlgo::paste (Rib, (fit_full_width-Aspec->full_height)/2, 0,
+ 0, 0, (*A)(0,0));
+ }
+
+ return 0;
+}
+
+
+
int
action_fixnan (int argc, const char *argv[])
{
@@ -1680,12 +1827,9 @@ action_fill (int argc, const char *argv[])
// Read and copy the top-of-stack image
ImageRecRef A (ot.pop());
ot.read (A);
- ot.push (new ImageRec (*A, 0, 0, true, false));
+ ot.push (new ImageRec (*A, 0, 0, true, true /*copy_pixels*/));
ImageBuf &Rib ((*ot.curimg)(0,0));
const ImageSpec &Rspec = Rib.spec();
- bool ok = ImageBufAlgo::zero (Rib);
- if (! ok)
- ot.error (argv[0], Rib.geterror());
int w = Rib.spec().width, h = Rib.spec().height;
int x = Rib.spec().x, y = Rib.spec().y;
@@ -1715,7 +1859,7 @@ action_fill (int argc, const char *argv[])
}
}
- ok = ImageBufAlgo::fill (Rib, color, ROI(x, x+w, y, y+h));
+ bool ok = ImageBufAlgo::fill (Rib, color, ROI(x, x+w, y, y+h));
if (! ok)
ot.error (argv[0], Rib.geterror());
@@ -1733,12 +1877,9 @@ action_text (int argc, const char *argv[])
// Read and copy the top-of-stack image
ImageRecRef A (ot.pop());
ot.read (A);
- ot.push (new ImageRec (*A, 0, 0, true, false));
+ ot.push (new ImageRec (*A, 0, 0, true, true /*copy_pixels*/));
ImageBuf &Rib ((*ot.curimg)(0,0));
const ImageSpec &Rspec = Rib.spec();
- bool ok = ImageBufAlgo::zero (Rib);
- if (! ok)
- ot.error (argv[0], Rib.geterror());
// Set up defaults for text placement, size, font, color
int x = Rspec.x + Rspec.width/2;
@@ -1781,8 +1922,8 @@ action_text (int argc, const char *argv[])
}
}
- ok = ImageBufAlgo::render_text (Rib, x, y, argv[1] /* the text */,
- fontsize, font, textcolor);
+ bool ok = ImageBufAlgo::render_text (Rib, x, y, argv[1] /* the text */,
+ fontsize, font, textcolor);
if (! ok)
ot.error (argv[0], Rib.geterror());
@@ -1943,26 +2084,28 @@ getargs (int argc, char *argv[])
"--hardwarn %g", &ot.diff_hardwarn, "Warn if any one pixel difference exceeds this error (infinity)",
"<SEPARATOR>", "Actions:",
"--create %@ %s %d", action_create, NULL, NULL,
- "Create a blank image (optional args: geom, channels)",
+ "Create a blank image (args: geom, channels)",
"--pattern %@ %s %s %d", action_pattern, NULL, NULL, NULL,
- "Create a patterned image (optional args: pattern, geom, channels)",
+ "Create a patterned image (args: pattern, geom, channels)",
"--capture %@", action_capture, NULL,
- "Capture an image (optional args: camera=%d)",
+ "Capture an image (options: camera=%d)",
"--diff %@", action_diff, NULL, "Print report on the difference of two images (modified by --fail, --failpercent, --hardfail, --warn, --warnpercent --hardwarn)",
"--add %@", action_add, NULL, "Add two images",
"--sub %@", action_sub, NULL, "Subtract two images",
"--abs %@", action_abs, NULL, "Take the absolute value of the image pixels",
+ "--cmul %s %@", action_cmul, NULL, "Multiply the image values by a constant or per-channel constants (e.g.: 0.5 or 1,1.25,0.5)",
"--over %@", action_over, NULL, "'Over' composite of two images",
- "--zover %@", action_zover, NULL, "Depth composite two images with Z channels (optional args: zeroisinf=%d)",
- "--histogram %@ %s %d", action_histogram, NULL, NULL, "Histogram one channel (optional args: cumulative=0)",
+ "--zover %@", action_zover, NULL, "Depth composite two images with Z channels (options: zeroisinf=%d)",
+ "--histogram %@ %s %d", action_histogram, NULL, NULL, "Histogram one channel (options: cumulative=0)",
"--flip %@", action_flip, NULL, "Flip the image vertically (top<->bottom)",
"--flop %@", action_flop, NULL, "Flop the image horizontally (left<->right)",
"--flipflop %@", action_flipflop, NULL, "Flip and flop the image (180 degree rotation)",
"--crop %@ %s", action_crop, NULL, "Set pixel data resolution and offset, cropping or padding if necessary (WxH+X+Y or xmin,ymin,xmax,ymax)",
"--croptofull %@", action_croptofull, NULL, "Crop or pad to make pixel data region match the \"full\" region",
- "--resize %@ %s", action_resize, NULL, "Resize (640x480, 50%)",
+ "--resize %@ %s", action_resize, NULL, "Resize (640x480, 50%) (optional args: filter=%s)",
+ "--fit %@ %s", action_fit, NULL, "Resize to fit within a window size (optional args: filter=%s)",
"--fixnan %@ %s", action_fixnan, NULL, "Fix NaN/Inf values in the image (options: none, black, box3)",
- "--fill %@ %s", action_fill, NULL, "Fill a region (options: x=, y=, size=, color=)",
+ "--fill %@ %s", action_fill, NULL, "Fill a region (options: color=)",
"--text %@ %s", action_text, NULL,
"Render text into the current image (options: x=, y=, size=, color=)",
"<SEPARATOR>", "Image stack manipulation:",
@@ -1976,6 +2119,8 @@ getargs (int argc, char *argv[])
"Throw away the current image",
"--dup %@", action_dup, NULL,
"Duplicate the current image (push a copy onto the stack)",
+ "--swap %@", action_swap, NULL,
+ "Swap the top two images on the stack.",
"<SEPARATOR>", "Color management:",
"--iscolorspace %@ %s", set_colorspace, NULL,
"Set the assumed color space (without altering pixels)",
diff --git a/src/oiiotool/oiiotool.h b/src/oiiotool/oiiotool.h
index 584f4ae..e844ac3 100644
--- a/src/oiiotool/oiiotool.h
+++ b/src/oiiotool/oiiotool.h
@@ -146,6 +146,8 @@ public:
return r;
}
+ ImageRecRef top () { return curimg; }
+
void error (const std::string &command, const std::string &explanation);
private:
diff --git a/testsuite/maketx/ref/out.txt b/testsuite/maketx/ref/out.txt
index 315b616..d886a7f 100644
--- a/testsuite/maketx/ref/out.txt
+++ b/testsuite/maketx/ref/out.txt
@@ -349,3 +349,37 @@ small.tx : 64 x 64, 3 channel, uint8 tiff
compression: "zip"
IPTC:Caption: "foo bar SHA-1=FFB354CFB97E56225E1FDA9484B8DE1B04470DAE ConstantColor=[1,0,0]"
tiff:RowsPerStrip: "32"
+whiteenv.exr : 4 x 2, 3 channel, half openexr (+mipmap)
+ MIP 0 of 3 (4 x 2):
+ Stats Min: 1.000000 1.000000 1.000000 (float)
+ Stats Max: 1.000000 1.000000 1.000000 (float)
+ Stats Avg: 1.000000 1.000000 1.000000 (float)
+ Stats StdDev: 0.000000 0.000000 0.000000 (float)
+ Stats NanCount: 0 0 0
+ Stats InfCount: 0 0 0
+ Stats FiniteCount: 8 8 8
+ Constant: Yes
+ Constant Color: 1.000000 1.000000 1.000000 (float)
+ Monochrome: Yes
+ MIP 1 of 3 (2 x 1):
+ Stats Min: 1.000000 1.000000 1.000000 (float)
+ Stats Max: 1.000000 1.000000 1.000000 (float)
+ Stats Avg: 1.000000 1.000000 1.000000 (float)
+ Stats StdDev: 0.000000 0.000000 0.000000 (float)
+ Stats NanCount: 0 0 0
+ Stats InfCount: 0 0 0
+ Stats FiniteCount: 2 2 2
+ Constant: Yes
+ Constant Color: 1.000000 1.000000 1.000000 (float)
+ Monochrome: Yes
+ MIP 2 of 3 (1 x 1):
+ Stats Min: 1.000000 1.000000 1.000000 (float)
+ Stats Max: 1.000000 1.000000 1.000000 (float)
+ Stats Avg: 1.000000 1.000000 1.000000 (float)
+ Stats StdDev: 0.000000 0.000000 0.000000 (float)
+ Stats NanCount: 0 0 0
+ Stats InfCount: 0 0 0
+ Stats FiniteCount: 1 1 1
+ Constant: Yes
+ Constant Color: 1.000000 1.000000 1.000000 (float)
+ Monochrome: Yes
diff --git a/testsuite/maketx/run.py b/testsuite/maketx/run.py
index e0f04ef..a79b6ba 100644
--- a/testsuite/maketx/run.py
+++ b/testsuite/maketx/run.py
@@ -90,6 +90,16 @@ command += info_command ("small.tif", safematch=1);
command += maketx_command ("small.tif", "small.tx",
"--oiio --constant-color-detect", showinfo=True)
+# Regression test -- at one point, we had a bug where we were botching
+# the poles of OpenEXR env maps, adding energy. Check it by creating an
+# all-white image, turning it into an env map, and calculating its
+# statistics (should be 1.0 everywhere).
+command += (oiio_app("oiiotool") + " --pattern constant:color=1,1,1 4x2 3 "
+ + " -d half -o " + oiio_relpath("white.exr") + " >> out.txt;\n")
+command += maketx_command ("white.exr", "whiteenv.exr",
+ "--envlatl")
+command += (oiio_app("oiiotool") + "--stats whiteenv.exr"
+ + " >> out.txt;\n")
outputs = [ "out.txt" ]
diff --git a/testsuite/oiiotool/ref/cmul1.exr b/testsuite/oiiotool/ref/cmul1.exr
new file mode 100644
index 0000000..8e3b039
Binary files /dev/null and b/testsuite/oiiotool/ref/cmul1.exr differ
diff --git a/testsuite/oiiotool/ref/cmul2.exr b/testsuite/oiiotool/ref/cmul2.exr
new file mode 100644
index 0000000..2248d57
Binary files /dev/null and b/testsuite/oiiotool/ref/cmul2.exr differ
diff --git a/testsuite/oiiotool/ref/filled.tif b/testsuite/oiiotool/ref/filled.tif
new file mode 100644
index 0000000..0f41983
Binary files /dev/null and b/testsuite/oiiotool/ref/filled.tif differ
diff --git a/testsuite/oiiotool/ref/fit.tif b/testsuite/oiiotool/ref/fit.tif
new file mode 100644
index 0000000..2dbf304
Binary files /dev/null and b/testsuite/oiiotool/ref/fit.tif differ
diff --git a/testsuite/oiiotool/ref/out.txt b/testsuite/oiiotool/ref/out.txt
index 6d8f11a..26b80d1 100644
--- a/testsuite/oiiotool/ref/out.txt
+++ b/testsuite/oiiotool/ref/out.txt
@@ -20,13 +20,21 @@ constant.tif : 320 x 240, 4 channel, float tiff
Constant: Yes
Constant Color: 0.100000 0.200000 0.300000 1.000000 (float)
Monochrome: No
+Comparing "filled.tif" and "ref/filled.tif"
+PASS
Comparing "resize.tif" and "ref/resize.tif"
PASS
Comparing "resize2.tif" and "ref/resize2.tif"
PASS
+Comparing "fit.tif" and "ref/fit.tif"
+PASS
Comparing "histogram_regular.tif" and "ref/histogram_regular.tif"
PASS
Comparing "histogram_cumulative.tif" and "ref/histogram_cumulative.tif"
PASS
Comparing "chanshuffle.tif" and "ref/chanshuffle.tif"
PASS
+Comparing "cmul1.exr" and "ref/cmul1.exr"
+PASS
+Comparing "cmul2.exr" and "ref/cmul2.exr"
+PASS
diff --git a/testsuite/oiiotool/run.py b/testsuite/oiiotool/run.py
index 713ad9f..eed1ab2 100755
--- a/testsuite/oiiotool/run.py
+++ b/testsuite/oiiotool/run.py
@@ -2,7 +2,7 @@
# test --create
command += (oiio_app("oiiotool")
- + " --create 320x240 3 -o black.tif >> out.txt ;\n")
+ + " --create 320x240 3 -d uint8 -o black.tif >> out.txt ;\n")
command += oiio_app("oiiotool") + " --stats black.tif >> out.txt ;\n"
# test --pattern constant
@@ -11,6 +11,11 @@ command += (oiio_app("oiiotool")
+ " -o constant.tif >> out.txt ;\n")
command += oiio_app("oiiotool") + " --stats constant.tif >> out.txt ;\n"
+# test --fill
+command += (oiio_app("oiiotool")
+ + " --create 256x256 3 --fill:color=1,.5,.5 256x256"
+ + " --fill:color=0,1,0 80x80+100+100 -d uint8 -o filled.tif >> out.txt ;\n")
+
# test resize
command += (oiio_app ("oiiotool") + " "
+ parent + "/oiio-images/grid.tif"
@@ -19,6 +24,21 @@ command += (oiio_app ("oiiotool") + " "
+ parent + "/oiio-images/grid.tif"
+ " --resize 25% -o resize2.tif >> out.txt ;\n")
+# test fit
+command += (oiio_app ("oiiotool") + " "
+ + parent + "/oiio-images/grid.tif"
+ + " --fit 360x240 -d uint8 -o fit.tif >> out.txt ;\n")
+
+# test --cmul
+# First, make a small gray swatch
+command += (oiio_app ("oiiotool") + " --pattern constant:color=0.5,0.5,0.5 128x128 3 -d half -o cmul-input.exr >> out.txt ;\n")
+# Test --cmul val (multiply all channels by the same scalar)
+command += (oiio_app ("oiiotool")
+ + " cmul-input.exr --cmul 1.5 -o cmul1.exr >> out.txt ;\n")
+# Test --cmul val,val,val... (multiply per-channel scalars)
+command += (oiio_app ("oiiotool")
+ + " cmul-input.exr --cmul 1.5,1,0.5 -o cmul2.exr >> out.txt ;\n")
+
# test histogram generation
command += (oiio_app ("oiiotool") + " "
+ "ref/histogram_input.png"
@@ -40,9 +60,9 @@ command += (oiio_app ("oiiotool") + " "
# Outputs to check against references
-outputs = [ "resize.tif", "resize2.tif",
+outputs = [ "filled.tif", "resize.tif", "resize2.tif", "fit.tif",
"histogram_regular.tif", "histogram_cumulative.tif",
- "chanshuffle.tif",
+ "chanshuffle.tif", "cmul1.exr", "cmul2.exr",
"out.txt" ]
#print "Running this command:\n" + command + "\n"
--
OpenImageIO packaging
More information about the Pkg-phototools-commits
mailing list