\chapter{Python Bindings}
\label{chap:pythonbindings}
\indexapi{Python|()}

\section{Overview}

\OpenImageIO provides Python language bindings for much of its
functionality.

\smallskip

You must ensure that the environment variable {\cf PYTHONPATH} includes
the {\cf python} subdirectory of the \OpenImageIO installation.

\smallskip

A Python program must import the {\cf OpenImageIO} package:
\begin{code}
    import OpenImageIO
\end{code}
\noindent In most of our examples below, we assume that for the sake
of brevity, we will alias the package name as follows:
\begin{code}
    import OpenImageIO as oiio
    from OpenImageIO import ImageInput, ImageOutput
    from OpenImageIO import ImageBuf, ImageSpec, ImageBufAlgo
\end{code}

\section{TypeDesc}
\label{sec:pythontypedesc}

The \TypeDesc class that describes data types of pixels and metadata,
described in detail in Section~\ref{sec:TypeDesc}, is replicated for Python.

\apiitem{BASETYPE}
The {\cf BASETYPE} enum corresponds to the C++ {\cf TypeDesc::BASETYPE} and
contains the following values: \\
{\cf UNKNOWN NONE UINT8 INT8 UINT16 INT16 UINT32 INT32 UINT64 INT64 \\
HALF FLOAT DOUBLE STRING PTR} \\
These names are also exported to the {\cf OpenImageIO} namespace.
\apiend

\apiitem{AGGREGATE}
The {\cf AGGREGATE} enum corresponds to the C++ {\cf TypeDesc::AGGREGATE} and
contains the following values: \\
{\cf SCALAR VEC2 VEC3 VEC4 MATRIX33 MATRIX44} \\
These names are also exported to the {\cf OpenImageIO} namespace.
\apiend

\apiitem{VECSEMANTICS}
The {\cf VECSEMANTICS} enum corresponds to the C++ {\cf TypeDesc::VECSEMANTICS} and
contains the following values: \\
{\cf NOSEMANTICS COLOR POINT VECTOR NORMAL TIMECODE KEYCODE RATIONAL} \\
These names are also exported to the {\cf OpenImageIO} namespace.
\apiend

\apiitem{TypeDesc.{\ce TypeDesc} (typename='unknown')}

Construct a {\cf TypeDesc} object the easy way: from a string description.
If the type name is omitted, it will default to {\cf UNKNOWN}.

\noindent Examples:
\begin{code}
    import OpenImageIO as oiio

    # make a default (UNKNOWN) TypeDesc
    t = TypeDesc()

    # make a TypeDesc describing an unsigned 8 bit int
    t = TypeDesc("uint8")

    # make a TypeDesc describing an array of 14 'float' values
    t = TypeDesc("float[14]")

    # make a TypeDesc describing 3-vector with point semantics
    t = TypeDesc("point")
\end{code}
\apiend

\apiitem{TypeDesc.{\ce TypeDesc} (basetype=oiio.UNKNOWN, aggregate=oiio.SCALAR, \\
\bigspc\spc\spc vecsemantics=NOSEMANTICS, arraylen=0)}

Construct a {\cf TypeDesc} object the hard way: from individual enum tokens
describing the base type, aggregate class, semantic hints, and array length.

\noindent Examples:
\begin{code}
    import OpenImageIO as oiio

    # make a default (UNKNOWN) TypeDesc
    t = TypeDesc()

    # make a TypeDesc describing an unsigned 8 bit int
    t = TypeDesc(oiio.UINT8)

    # make a TypeDesc describing an array of 14 'float' values
    t = TypeDesc(oiio.FLOAT, oiio.SCALAR, oiio.NOSEMANTICS, 14)

    # make a TypeDesc describing a float point
    t = TypeDesc(oiio.FLOAT, oiio.VEC3, oiio.POINT)
\end{code}
\apiend

\apiitem{TypeUnknown TypeString \\
TypeFloat TypeHalf \\
TypeInt TypeUInt TypeInt16 TypeUInt16 \\
TypeColor TypePoint TypeVector TypeNormal TypeFloat4 \\
TypeMatrix TypeMatrix33 \\
TypeTimeCode TypeKeyCode \\
TypeRational \\
}
Pre-constructed \TypeDesc objects for some common types, available in the
outer OpenImageIO scope.

\noindent Example:
\begin{code}
    t = TypeFloat
\end{code}
\apiend

\apiitem{string {\ce str} (TypeDesc)}
Returns a string that describes the \TypeDesc.

\noindent Example:
\begin{code}
    print str(TypeDesc(oiio.UINT16))

    > int16
\end{code}
\apiend

\apiitem{TypeDesc.{\ce basetype} \\
TypeDesc.{\ce aggregate} \\
TypeDesc.{\ce vecsemantics} \\
TypeDesc.{\ce arraylen}}
Access to the raw fields in the \TypeDesc.

\noindent Example:
\begin{code}
    t = TypeDesc(...)
    if t.basetype == oiio.FLOAT :
        print "It's made of floats"
\end{code}
\apiend

\apiitem{int TypeDesc.{\ce size} () \\
int TypeDesc.{\ce basesize} () \\
TypeDesc TypeDesc.{\ce elementtype} () \\
int TypeDesc.{\ce numelements} () \\
int TypeDesc.{\ce elementsize} ()}
The {\cf size()} is the size in bytes, of the type described.  The
{\cf basesize()} is the size in bytes of the {\cf basetype}.

The {\cf elementtype()} is the type of each array element, if it is an
array, or just the full type if it is not an array.  The {\cf elementsize()}
is the size, in bytes, of the {\cf elementtype} (thus, returning the same
value as {\cf size()} if the type is not an array).  The {\cf numelements()}
method returns {\cf arraylen} if it is an array, or {\cf 1} if it is not
an array.

\noindent Example:
\begin{code}
    t = TypeDesc("point[2]")
    print "size =", t.size()
    print "elementtype =", t.elementtype()
    print "elementsize =", t.elementsize()

    > size = 24
    > elementtype = point
    > elementsize = 12
\end{code}
\apiend

\apiitem{bool typedesc {\ce ==} typedesc \\
bool typedesc {\ce !=} typedesc \\
bool TypeDesc.{\ce equivalent} (typedesc) \\}
Test for equality or inequality.  The {\cf equivalent()} method is more
forgiving than {\cf ==}, in that it considers {\cf POINT}, {\cf VECTOR},
and {\cf NORMAL} vector semantics to not constitute a difference from one
another.

\noindent Example:
\begin{code}
    f = TypeDesc("float")
    p = TypeDesc("point")
    v = TypeDesc("vector")
    print "float==point?", (f == p)
    print "vector==point?", (v == p)
    print "float.equivalent(point)?", f.equivalent(p)
    print "vector.equivalent(point)?", v.equivalent(p)

    > float==point? False
    > vector==point? False
    > float.equivalent(point)? False
    > vector.equivalent(point)? True
\end{code}
\apiend


\section{ROI}
\label{sec:pythonroi}

The \ROI class that describes an image extent or region of interest,
explained in deail in Section~\ref{sec:ROI}, is replicated for Python.

\apiitem{{\ce ROI} () \\
{\ce ROI} (xbegin, xend, ybegin, yend) \\
{\ce ROI} (xbegin, xend, ybegin, yend, zbegin, zend) \\
{\ce ROI} (xbegin, xend, ybegin, yend, zbegin, zend, chbegin, chend)}
Construct an \ROI with the given bounds.  The constructor with no 
arguments makes an \ROI that is ``undefined.''

\noindent Example:
\begin{code}
    import OpenImageIO as oiio
    ...
    roi = ROI (0, 640, 0, 480, 0, 1, 0, 4)   # video res RGBA
\end{code}
\apiend

\apiitem{int ROI.{\ce xbegin} \\
int ROI.{\ce xend} \\
int ROI.{\ce ybegin} \\
int ROI.{\ce yend} \\
int ROI.{\ce zbegin} \\
int ROI.{\ce zend} \\
int ROI.{\ce chbegin} \\
int ROI.{\ce chend}}
The basic fields of the \ROI.
\apiend

\apiitem{ROI ROI.{\ce All}}
A pre-constructed undefined \ROI.
\apiend

\apiitem{bool ROI.{\ce defined}}
{\cf True} if the \ROI is defined, {\cf False} if the \ROI is undefined.
\apiend

\apiitem{int ROI.{\ce width} \\
int ROI.{\ce height} \\
int ROI.{\ce depth} \\
int ROI.{\ce nchannels}}
The number of pixels in each dimension, and the number of channels,
as described by the \ROI.
\apiend

\apiitem{int ROI.{\ce npixels}}
The total number of pixels in the region described by the \ROI.
\apiend

\apiitem{int ROI.{\ce contains} (x, y, z=0, ch=0)}
Returns {\cf True} if the ROI contains the coordinate.
\apiend

\apiitem{int ROI.{\ce contains} (other)}
Returns {\cf True} if the ROI {\cf other} is entirel contained within
this ROI.
\apiend


\apiitem{ROI {\ce get_roi} (imagespec) \\
ROI {\ce get_roi_full} (imagespec)}
Returns the \ROI corresponding to the pixel data window of the given
\ImageSpec, or the display/full window, respectively.

\noindent Example:
\begin{code}
    spec = ImageSpec(...)
    roi = oiio.get_roi(spec)
\end{code}
\apiend

\apiitem{{\ce set_roi} (imagespec, roi) \\
{\ce set_roi_full} (imagespec, roi)}
Alter the \ImageSpec's resolution and offset to match the passed \ROI.

\noindent Example:
\begin{code}
    # spec is an ImageSpec
    # The following sets the full (display) window to be equal to the
    # pixel data window:
    oiio.set_roi_full (spec, oiio.get_roi(spec))
\end{code}
\apiend


\section{ImageSpec}
\label{sec:pythonimagespec}

The \ImageSpec class that describes an image, explained in deail in
Section~\ref{sec:ImageSpec}, is replicated for Python.

\apiitem{{\ce ImageSpec} ()\\
{\ce ImageSpec} (typedesc) \\
{\ce ImageSpec} (xres, yres, nchannels, typedesc) \\
{\ce ImageSpec} (roi, typedesc)}
Constructors of an \ImageSpec. These correspond directly to the constructors
in the C++ bindings.

\noindent Example:
\begin{code}
    import OpenImageIO as oiio
    ...

    # default ctr
    s = ImageSpec()

    # construct with known pixel type, unknown resolution
    s = ImageSpec(oiio.UINT8)

    # construct with known resolution, channels, pixel data type
    s = ImageSpec(640, 480, 4, "half")

    # construct from an ROI
    s = ImageSpec (ROI(0,640,0,480,0,1,0,3), TypeFloat)
\end{code}
\apiend

\apiitem{ImageSpec.{\ce width}, ImageSpec.{\ce height}, ImageSpec.{\ce depth} \\
ImageSpec.{\ce x}, ImageSpec.{\ce y}, ImageSpec.{\ce z}}
Resolution and offset of the image data ({\cf int} values).

\noindent Example:
\begin{code}
    s = ImageSpec (...)
    print "Data window is ({},{})-({},{})".format (s.x, s.x+s.width-1,
                                                   s.y, s.y+s.height-1)
\end{code}
\apiend

\apiitem{ImageSpec.{\ce full_width}, ImageSpec.{\ce full_height}, ImageSpec.{\ce full_depth} \\
ImageSpec.{\ce full_x}, ImageSpec.{\ce full_y}, ImageSpec.{\ce full_z}}
Resolution and offset of the ``full'' display window ({\cf int} values).
\apiend

\apiitem{ImageSpec.{\ce tile_width}, ImageSpec.{\ce tile_height}, ImageSpec.{\ce tile_depth}}
For tiled images, the resolution of the tiles ({\cf int} values).  Will be
{\cf 0} for  untiled images.
\apiend

\apiitem{typedesc ImageSpec.{\ce format}}
A \TypeDesc describing the pixel data.
\apiend

\apiitem{int ImageSpec.{\ce nchannels}}
An {\cf int} giving the number of color channels in the image.
\apiend

\apiitem{ImageSpec.{\ce channelnames}}
A tuple of strings containing the names of each color channel.
\apiend

\apiitem{ImageSpec.{\ce channelformats}}
If all color channels have the same format, that will be {\cf ImageSpec.format},
and {\cf channelformats} will be {\cf None}.  However, if there are different
formats per channel, they will be stored in {\cf channelformats} as a tuple
of {\cf TypeDesc} objects.

\noindent Example:
\begin{code}
    if spec.channelformats == None:
        print "All color channels are", str(spec.format)
    else:
        print "Channel formats: "
        for t in spec.channelformats:
            print "\t", t
\end{code}
\apiend

\apiitem{ImageSpec.{\ce alpha_channel} \\
ImageSpec.{\ce z_channel}}
The channel index containing the alpha or depth channel, respectively, or
-1 if either one does not exist or cannot be identified.
\apiend

\apiitem{ImageSpec.{\ce deep}}
Hold {\cf True} if the image is a \emph{deep} (multiple samples per pixel)
image, of {\cf False} if it is an ordinary image.
\apiend

\apiitem{ImageSpec.{\ce extra_attribs}}
Direct access to the {\cf extra_attribs} named metadata, appropriate for
iterating over the entire list rather than searching for a particular named
value.

\vspace{-10pt}
\apiitem{len(extra_attribs)}
\vspace{10pt}
Returns the number of extra attributes.
\apiend
\vspace{-24pt}
\apiitem{extra_attribs[i].name}
\vspace{10pt}
The name of the indexed attribute.
\apiend
\vspace{-24pt}
\apiitem{extra_attribs[i].type}
\vspace{10pt}
The type of the indexed attribute, as a \TypeDesc.
\apiend
\vspace{-24pt}
\apiitem{extra_attribs[i].value}
\vspace{10pt}
The value of the indexed attribute.
\apiend

\noindent Example:
\begin{code}
    s = ImageSpec(...)
    ...
    print "extra_attribs size is", len(s.extra_attribs)
    for i in range(len(s.extra_attribs)) :
        print i, s.extra_attribs[i].name, str(s.extra_attribs[i].type), " :"
        print "\t", s.extra_attribs[i].value
    print
\end{code}
\apiend

\apiitem{Imagespec.{\ce roi}}
The ROI describing the pixel data window.
\apiend

\apiitem{ImageSpec.{\ce roi_full}}
The ROI describing the ``display window'' (or ``full size'').
\apiend

\apiitem{ImageSpec.{\ce set_format} (typedesc)}
Given a \TypeDesc, sets the {\cf format} field and
clear any per-channel formats in {\cf channelformats}.

\noindent Example:
\begin{code}
    s = ImageSpec ()
    s.set_format (TypeDesc("uint8"))
\end{code}
\apiend

\apiitem{ImageSpec.{\ce default_channel_names} ()}
Sets {\cf channel_names} to the default names given the value of
the {\cf nchannels} field.
\apiend

\apiitem{int ImageSpec.{\ce channelindex} (name)}
Return (as an int) the index of the channel with the given name, or -1
if it does not exist.
\apiend

\apiitem{ImageSpec.{\ce channel_bytes} () \\
ImageSpec.{\ce channel_bytes} (channel, native=False)}
Returns the size of a single channel value, in bytes (as an
{\cf int}).
(Analogous to the C++ member functions, see 
Section~\ref{sec:ImageSpecMemberFuncs} for details.)
\apiend

\apiitem{ImageSpec.{\ce pixel_bytes} () \\
ImageSpec.{\ce pixel_bytes} (native=False) \\
ImageSpec.{\ce pixel_bytes} (chbegin, chend, native=False)}
Returns the size of a pixel, in bytes (as an {\cf int}).
(Analogous to the C++ member functions, see 
Section~\ref{sec:ImageSpecMemberFuncs} for details.)
\apiend

\apiitem{ImageSpec.{\ce scanline_bytes} (native=False) \\
ImageSpec.{\ce tile_bytes} (native=False) \\
ImageSpec.{\ce image_bytes} (native=False)}
Returns the size of a scanline, tile, or the full image, in bytes (as an
{\cf int}). (Analogous to the C++ member functions, see 
Section~\ref{sec:ImageSpecMemberFuncs} for details.)
\apiend

\apiitem{ImageSpec.{\ce tile_pixels} () \\
ImageSpec.{\ce image_pixels} ()}
Returns the number of pixels in a tile or the full image, respectively
(as an {\cf int}). (Analogous to the C++ member functions, see 
Section~\ref{sec:ImageSpecMemberFuncs} for details.)
\apiend

\apiitem{ImageSpec.{\ce erase_attribute} (name, searchtype=TypeUnknown,\\
\bigspc\bigspc\spc casesensitive=False)}
Remove any specified attributes matching the regular expression {\cf name}
from the list of extra_attribs.
\apiend

\apiitem{ImageSpec.{\ce attribute} (name, int) \\
ImageSpec.{\ce attribute} (name, float) \\
ImageSpec.{\ce attribute} (name, string) \\
ImageSpec.{\ce attribute} (name, typedesc, data) \\}
Sets a metadata value in the {\cf extra_attribs}.  If the metadata item
is a single {\cf int}, {\cf float}, or {\cf string}, you can pass it
directly. For other types, you must pass the \TypeDesc and then the
data (for aggregate types or arrays, pass multiple values as a tuple).

\noindent Example:
\begin{code}
    s = ImageSpec (...)
    s.attribute ("foo_str", "blah")
    s.attribute ("foo_int", 14)
    s.attribute ("foo_float", 3.14)
    s.attribute ("foo_vector", TypeDesc.TypeVector, (1, 0, 11))
    s.attribute ("foo_matrix", TypeDesc.TypeMatrix,
                 (1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 1, 2, 3, 1))
\end{code}
\apiend

\apiitem{ImageSpec.{\ce getattribute} (name) \\
ImageSpec.{\ce getattribute} (name, typedesc)}
Retrieves a named metadata value from {\cf extra_attribs}.  The generic
{\cf getattribute()} function returns it regardless of type, or {\cf None}
if the attribute does not exist.  The typed variety will only succeed
if the attribute is actually of that type specified.

\noindent Example:
\begin{code}
    foo = s.getattribute ("foo")   # None if not found
    foo = s.getattribute ("foo", oiio.FLOAT)  # None if not found AND float
\end{code}
\apiend

\apiitem{ImageSpec.{\ce get_int_attribute} (name, defaultval=0) \\
ImageSpec.{\ce get_float_attribute} (name, defaultval=0.0) \\
ImageSpec.{\ce get_string_attribute} (name, defaultval="")}
Retrieves a named metadata value from {\cf extra_attribs}, if it is
found and is of the given type; returns the default value (or a passed
value) if not found.

\noindent Example:
\begin{code}
    # If "foo" is not found, or if it's not an int, return 0
    foo = s.get_int_attribute ("foo")

    # If "foo" is not found, or if it's not a string, return "blah"
    foo = s.get_string_attribute ("foo", "blah")
\end{code}
\apiend

\apiitem{ImageSpec{\ce [name]}}
\NEW % 2.1
Retrieve or set metadata using a dictionary-like syntax, rather than
{\cf attribute()} and {\cf getattribute()}. This is best illustrated by
example:

\begin{code}
    comp = spec["Compression"]
    # Same as:  comp = spec.getattribute("Compression")

    spec["Compression"] = comp
    # Same as: spec.attribute("Compression", comp)
\end{code}
\apiend

%\apiitem{static ImageSpec.{\ce metadata_val} (paramval, human=False)}
%For a \ParamValue, format its value as a string.
%\apiend

\apiitem{ImageSpec.{\ce serialize} (format="text", verbose="Detailed")}
Return a string containing the serialization of the \ImageSpec. The {\cf format}
may be either \qkw{text} or \qkw{XML}. The {\cf verbose} may be one of
\qkw{brief}, \qkw{detailed}, or \qkw{detailedhuman}.
\apiend

\apiitem{ImageSpec.{\ce to_xml} ()}
Equivalent to {\cf serialize ("xml", "detailedhuman")}.
\apiend

\apiitem{ImageSpec.{\ce from_xml} (xml)}
Initializes the \ImageSpec from the information in the string {\cf xml}
containing an XML-serialized \ImageSpec.
\apiend

\apiitem{ImageSpec.{\ce channel_name} (chan)}
Returns a string containing the name of the channel with index {\cf chan}.
\apiend

\apiitem{ImageSpec.{\ce channelindex} (name)}
Return the integer index of the channel with the given {\cf name}, or
-1 if the name is not a name of one of the channels.
\apiend

\apiitem{ImageSpec.{\ce channelformat} (chan)}
Returns a \TypeDesc of the channel with index {\cf chan}.
\apiend

\apiitem{ImageSpec.{\ce get_channelformats} ()}
Returns a tuple containing all the channel formats.
\apiend

\apiitem{ImageSpec.{\ce valid_tile_range} (xbegin, xend, ybegin, yend, zbegin, zend)}
Returns {\cf True} if the given tile range exactly covers a set of tiles, or
{\cf False} if it isn't (or if the image is not tiled).
\apiend

\apiitem{ImageSpec.{\ce copy_dimensions} (other)}
Copies from \ImageSpec {\cf other} only the fields describing the size
and data types, but not the arbitrary named metadata or channel names.
\apiend

\apiitem{ImageSpec.{\ce undefined}()}
Returns {\cf True} for a newly initialized (undefined) \ImageSpec.
\apiend

\newpage
\subsection*{Example: Header info}

Here is an illustrative example of the use of \ImageSpec, a working Python
function that opens a file and prints all the relevant header
information:

\begin{tinycode}
#!/usr/bin/env python 
import OpenImageIO as oiio

# Print the contents of an ImageSpec
def print_imagespec (spec, subimage=0, mip=0) :
    if spec.depth <= 1 :
        print ("  resolution %dx%d%+d%+d" % (spec.width, spec.height, spec.x, spec.y))
    else :
        print ("  resolution %dx%d%x%d+d%+d%+d" % 
               (spec.width, spec.height, spec.depth, spec.x, spec.y, spec.z))
    if (spec.width != spec.full_width or spec.height != spec.full_height
        or spec.depth != spec.full_depth) :
        if spec.full_depth <= 1 :
            print ("  full res   %dx%d%+d%+d" % 
                   (spec.full_width, spec.full_height, spec.full_x, spec.full_y))
        else :
            print ("  full res   %dx%d%x%d+d%+d%+d" % 
                   (spec.full_width, spec.full_height, spec.full_depth,
                    spec.full_x, spec.full_y, spec.full_z))
    if spec.tile_width :
        print ("  tile size  %dx%dx%d" % 
               (spec.tile_width, spec.tile_height, spec.tile_depth))
    else :
        print "  untiled"
    if mip >= 1 :
        return
    print "  " + str(spec.nchannels), "channels:", spec.channelnames
    print "  format = ", str(spec.format)
    if len(spec.channelformats) > 0 :
        print "  channelformats = ", spec.channelformats
    print "  alpha channel = ", spec.alpha_channel
    print "  z channel = ", spec.z_channel
    print "  deep = ", spec.deep
    for i in spec.extra_attribs) :
        if type(i.value) == str :
            print " ", i.name, "= \"" + i.value + "\""
        else :
            print " ", i.name, "=", i.value


def poor_mans_iinfo (filename) :
    input = ImageInput.open (filename)
    if not input :
        print 'Could not open "' + filename + '"'
        print "\tError: ", oiio.geterror()
        return
    print 'Opened "' + filename + '" as a ' + input.format_name()
    sub = 0
    mip = 0
    while True :
        if sub > 0 or mip > 0 :
            print "Subimage", sub, "MIP level", mip, ":"
        print_imagespec (input.spec(), mip=mip)
        mip = mip + 1
        if input.seek_subimage (sub, mip) :
            continue    # proceed to next MIP level
        else :
            sub = sub + 1
            mip = 0
            if input.seek_subimage (sub, mip) :
                continue    # proceed to next subimage
        break  # no more MIP levels or subimages
    input.close ()
\end{tinycode}


\section{DeepData}
\label{sec:pythondeepdata}

The \DeepData class describing ``deep'' image data (multiple depth
sample per pixel), which is explained in deail in
Section~\ref{sec:imageinput:deepdata}, is replicated for Python.

\apiitem{{\ce DeepData} ()}
Constructs a \DeepData object. It needs to have its {\cf init()} and
{\cf alloc()} methods called before it can hold any meaningful data.
\apiend

\apiitem{DeepData.{\ce init} (npixels, nchannels, channeltypes, channelnames)}
Initializes this \DeepData to hold {\cf npixels} total pixels, with
{\cf nchannels} color channels. The data types of the channels are
described by {\cf channeltypes}, a tuple of \TypeDesc values (one per
channel), and the names are provided in a tuple of {\cf string}s
{\cf channelnames}. After calling {\cf init}, you still need to set the number of
samples for each pixel (using {\cf set_nsamples}) and then call {\cf alloc()}
to actually allocate the sample memory.
\apiend

\apiitem{bool {\ce DeepData}.initialized ()}
Returns {\cf True} if the \DeepData is initialized at all.
\apiend

\apiitem{bool {\ce DeepData}.allocated ()}
Returns {\cf True} if the \DeepData has already had pixel memory allocated.
\apiend

\apiitem{DeepData.{\ce pixels}}
This {\cf int} field constains the total number of pixels in this
collection of deep data.
\apiend

\apiitem{DeepData.{\ce channels}}
This {\cf int} field constains the number of channels.
\apiend

\apiitem{int DeepData.{\ce A_channel} \\
int DeepData.{\ce AR_channel} \\
int DeepData.{\ce AG_channel} \\
int DeepData.{\ce AB_channel} \\
int DeepData.{\ce Z_channel} \\
int DeepData.{\ce Zback_channel}}
The channel index of certain named channels, or -1 if they don't exist. For
{\cf AR_channel}, {\cf AG_channel}, {\cf AB_channel}, if they don't exist,
they will contain the value of {\cf A_channel}, and {\cf Zback_channel} will
contain the value of {\cf Z_channel} if there is no actual {\cf Zback}.
\apiend

\apiitem{string DeepData.{\ce channelname} (c)}
Retrieve the name of channel {\cf c}.
\apiend

\apiitem{TypeDesc DeepData.{\ce channeltype} (c)}
Retrieve the data type of channel {\cf c}.
\apiend

\apiitem{int DeepData.{\ce channelsize} (c)}
Retrieve the size (in bytes) of one datum of channel {\cf c}.
\apiend

\apiitem{int DeepData.{\ce samplesize} ()}
Retrieve the packed size (in bytes) of all channels of one sample.
\apiend


\apiitem{DeepData.{\ce set_samples} (pixel, nsamples) \\
int DeepData.{\ce samples} (pixel)}
Set or get the number of samples for a given pixel (specified by integer
index).
\apiend

\apiitem{DeepData.{\ce insert_samples} (pixel, samplepos, n) \\
int DeepData.{\ce erase_samples} (pixel, samplepos, n)}
Insert or erase \emph{n} samples starting at the given position of an
indexed pixel.
\apiend

\apiitem{DeepData.{\ce set_deep_value} (pixel, channel, sample, value) \\
DeepData.{\ce set_deep_value_uint} (pixel, channel, sample, value)}
Set specific float or unsigned int value of a given pixel, channel, and
sample index.
\apiend

\apiitem{DeepData.{\ce deep_value} (pixel, channel, sample, value) \\
int DeepData.{\ce deep_value_uint} (pixel, channel, sample)}
Retrieve the specific value of a given pixel,
channel, and sample index (for float or uint channels, respectively).
\apiend

\apiitem{DeepData.{\ce copy_deep_sample} (pixel, sample, src, srcpixel, srcsample)}
Copy a deep sample from \DeepData {\cf src} into this \DeepData.
\apiend

\apiitem{DeepData.{\ce copy_deep_pixel} (pixel, src, srcpixel)}
Copy a deep pixel from \DeepData {\cf src} into this \DeepData.
\apiend

\apiitem{bool DeepData.{\ce split} (pixel, depth)}
Split any samples of the pixel that cross {\cf depth}. Return {\cf True} if
any splits occurred, {\cf False} if the pixel was unmodified.
\apiend

\apiitem{DeepData.{\ce sort} (pixel)}
Sort the samples of the pixel by their Z depth.
\apiend

\apiitem{DeepData.{\ce merge_overlaps} (pixel)}
Merge any adjacent samples in the pixel that exactly overlap in $z$
range. This is only useful if the pixel has previously been split at
all sample starts and ends, and sorted by depth.
\apiend

\apiitem{DeepData.{\ce merge_deep_pixels} (pixel, src, srcpixel)}
Merge the samples of {\cf src}'s pixel into this \DeepData's pixel.
\apiend

\apiitem{DeepData.{\ce occlusion_cull} (pixel)}
Eliminate any samples beyond an opaque sample.
\apiend

\apiitem{float DeepData.{\ce opaque_z} (pixel)}
For the given pixel index. return the $z$ value at which the pixel reaches
full opacity.
\apiend



\section{ImageInput}
\label{sec:pythonimageinput}

See Chapter~\ref{chap:imageinput} for detailed explanations of the
C++ \ImageInput class APIs. The Python APIs are very similar. The biggest
difference is that in C++, the various {\cf read_*} functions write the
pixel values into an already-allocated array that belongs to the caller,
whereas the Python versions allocate and return an array holding the pixel
values (or {\cf None} if the read failed).


\apiitem{ImageInput.{\ce open} (filename) \\
ImageInput.{\ce open} (filename, config_imagespec)}
Creates an \ImageInput object and opens the named file.  Returns the
open \ImageInput upon success, or {\cf None} if it failed to open the
file (after which, {\cf OpenImageIO.geterror()} will contain an error
message).  In the second form, the optional \ImageSpec argument 
{\cf config} contains attributes that may set certain options when opening
the file.

\noindent Example:
\begin{code}
    input = ImageInput.open ("tahoe.jpg")
    if input == None :
        print "Error:", oiio.geterror()
        return
\end{code}
\apiend

\apiitem{bool ImageInput.{\ce close} ()}
Closes an open image file, returning {\cf True} if successful, {\cf False}
otherwise.

\noindent Example:
\begin{code}
    input = ImageInput.open (filename)
    ...
    input.close ()
\end{code}
\apiend


\apiitem{str ImageInput.{\ce format_name} ()}
Returns the format name of the open file.

\noindent Example:
\begin{code}
    input = ImageInput.open (filename)
    if input :
        print filename, "was a", input.format_name(), "file."
        input.close ()
  
\end{code}
\apiend

\apiitem{ImageSpec ImageInput.{\ce spec} ()}
Returns the \ImageSpec corresponding to the currently open subimage and
MIP level of the file.

\noindent Example:
\begin{code}
    input = ImageInput.open (filename)
    spec = input.spec()
    print "resolution ", spec.width, "x", spec.height
\end{code}
\apiend

\apiitem{ImageSpec ImageInput.{\ce spec} (subimage, miplevel=0) \\
ImageSpec ImageInput.{\ce spec_dimensions} (subimage, miplevel=0)}
Returns a copy of the \ImageSpec corresponding to the designated subimage
and MIP level. Note that {\cf spec()} copies the entire \ImageSpec including
all metadata, whereas {\cf spec_dimensions()} only copies the dimension
fields and not any of the arbitrary named metadata (and is thus much less
expensive).
\apiend

\apiitem{int ImageInput.{\ce current_subimage} () \\
int ImageInput.{\ce current_miplevel} ()}
Returns the current subimage and/or MIP level of the file.
\apiend

\apiitem{bool ImageInput.{\ce seek_subimage} (subimage, miplevel)}
Repositions the file pointer to the given subimage and MIP level within the
file (starting with {\cf 0}).  This function returns {\cf True} upon success,
{\cf False} upon failure (which may include the file not having the
specified subimage or MIP level).

\noindent Example:
\begin{code}
    input = ImageInput.open (filename)
    mip = 0
    while True :
        ok = input.seek_subimage (0, mip)
        if not ok :
            break
        spec = input.spec()
        print "MIP level", mip, "is", spec.width, "x", spec.height
\end{code}
\apiend

\apiitem{ImageInput.{\ce read_image} (format="float") \\
ImageInput.{\ce read_image} (chbegin, chend, format="float") \\
ImageInput.{\ce read_image} (subimage, miplevel, chbegin, chend, format="float")}

Read the entire image and return the pixels as a NumPy array of values of
the given {\cf type} (described by a \TypeDesc or a string, float by
default). If the {\cf type} is {\cf TypeUnknown}, the pixels will be
returned in the native format of the file. If an error occurs, {\cf None}
will be returned.

For a normal (2D) image, the array returned will be 3D indexed as
{\cf [y][x][channel]}. For 3D volumetric images, the array returned will be
4D with shape indexed as {\cf [z][y][x][channel]}.

\noindent Example:
\begin{code}
    input = ImageInput.open (filename)
    spec = input.spec ()
    pixels = input.read_image ()
    print "The first pixel is", pixels[0][0]
    print "The second pixel is", pixels[0][1]
    input.close ()
\end{code}
\apiend

\apiitem{ndarray ImageInput.{\ce read_scanline} (y, z, format="float")}
Read scanline number {\cf y} from depth plane {\cf z} from the open file,
returning the pixels as a NumPy array of values of
the given {\cf type} (described by a \TypeDesc or a string, float by
default). If the {\cf type} is {\cf TypeUnknown}, the pixels will be
returned in the native format of the file. If an error occurs, {\cf None}
will be returned.

The pixel array returned be 2D, indexed as {\cf [x][channel]}.

\noindent Example:
\begin{code}
    input = ImageInput.open (filename)
    spec = input.spec ()
    if spec.tile_width == 0 :
        for y in range(spec.y, spec.y+spec.height) :
            pixels = input.read_scanline (y, spec.z, "float")
            # process the scanline
    else :
        print "It's a tiled file"
    input.close ()
\end{code}
\apiend

\apiitem{ndarray ImageInput.{\ce read_tile} (x, y, z, format="float")}
Read the tile whose upper left corner is pixel {\cf (x,y,z)} from the open
file, returning the pixels as a NumPy array of values of
the given {\cf type} (described by a \TypeDesc or a string, float by
default). If the {\cf type} is {\cf TypeUnknown}, the pixels will be
returned in the native format of the file. If an error occurs, {\cf None}
will be returned.

For a normal (2D) image, the array of tile pixels returned will be 3D
indexed as {\cf [y][x][channel]}. For 3D volumetric images, the array
returned will be 4D with shape indexed as {\cf [z][y][x][channel]}.

\noindent Example:
\begin{code}
    input = ImageInput.open (filename)
    spec = input.spec ()
    if spec.tile_width > 0 :
        for z in range(spec.z, spec.z+spec.depth, spec.tile_depth) :
            for y in range(spec.y, spec.y+spec.height, spec.tile_height) :
                for x in range(spec.x, spec.x+spec.width, spec.tile_width) :
                    pixels = input.read_tile (x, y, z, oiio.FLOAT)
                    # process the tile
    else :
        print "It's a scanline file"
    input.close ()
\end{code}
\apiend

\apiitem{ndarray ImageInput.{\ce read_scanlines} (subimage, miplevel, \\
\bigspc\bigspc\spc ybegin, yend, z, chbegin, chend, format="float") \\
ndarray ImageInput.{\ce read_scanlines} (ybegin, yend, z, chbegin, chend, \\
\bigspc\bigspc\spc format="float") \\
ndarray ImageInput.{\ce read_tiles} (xbegin, xend, ybegin, yend, zbegin, zend, \\
    \bigspc\bigspc\spc chbegin, chend, format="float") \\
ndarray ImageInput.{\ce read_tiles} (subimage, miplevel, \\
    \bigspc\bigspc\spc xbegin, xend, ybegin, yend, zbegin, zend, format="float")}
Similar to the C++ routines, these functions read multiple scanlines or
tiles at once, which in some cases may be more efficient than reading
each scanline or tile separately.  Additionally, they allow you to read only
a subset of channels.

For normal 2D images, both {\cf read_scanlines} and {\cf read_tiles} will
return a 3D array indexed as {\cf [z][y][x][channel]}.

For 3D volumetric images, both {\cf read_scanlines} will return a 3D array
indexed as {\cf [y][x][channel]}, and {\cf read_tiles} will return a 4D
array indexed as {\cf [z][y][x][channel]},

\noindent Example:
\begin{code}
    input = ImageInput.open (filename)
    spec = input.spec ()

    # Read the whole image, the equivalent of
    #     pixels = input.read_image (type)
    # but do it using read_scanlines or read_tiles:
    if spec.tile_width == 0 :
        pixels = input.read_scanlines (spec.y, spec.y+spec.height, 0,
                                       0, spec.nchannels)
    else :
        pixels = input.read_tiles (spec.x, spec.x+spec.width,
                                   spec.y, spec.y+spec.height,
                                   spec.z, spec.z+spec.depth,
                                   0, spec.nchannels)
\end{code}
\apiend

\apiitem{DeepData ImageInput.{\ce read_native_deep_scanlines} (subimage, miplevel, \\
\bigspc\bigspc ybegin, yend, z, chbegin, chend) \\
DeepData ImageInput.{\ce read_native_deep_tiles} (subimage, miplevel, \\
\bigspc\bigspc xbegin, xend, ybegin, yend, zbegin, zend, chbegin, chend) \\
DeepData ImageInput.{\ce read_native_deep_image} (subimage=0, miplevel=0)}
Read a collection of scanlines, tiles, or an entire image of ``deep'' pixel
data from the specified subimage and MIP level. The begin/end coordinates
are all integer values. The value returned will be a \DeepData if the read
succeeds, or {\cf None} if the read fails.

These methods are guaranteed to be thread-safe against simultaneous calls to
any of the other other {\cf read_native} calls that take an explicit
subimage/miplevel.
\apiend

\apiitem{str ImageInput.{\ce geterror} ()}
Retrieves the error message from the latest failed operation on an
ImageInput.

\noindent Example:
\begin{code}
    input = ImageInput.open (filename)
    if not input :
        print "Open error:", oiio.geterror()
        # N.B. error on open must be retrieved with the global geterror(),
        # since there is no ImageInput object!
    else :
        pixels = input.read_image (oiio.FLOAT)
        if not pixels :
            print "Read_image error:", input.geterror()
        input.close ()
\end{code}
\apiend

\newpage
\subsection*{Example: Reading pixel values from a file to find min/max}

\begin{code}
#!/usr/bin/env python 
import OpenImageIO as oiio

def find_min_max (filename) :
    input = ImageInput.open (filename)
    if not input :
        print 'Could not open "' + filename + '"'
        print "\tError: ", oiio.geterror()
        return
    spec = input.spec()
    nchans = spec.nchannels
    pixels = input.read_image()
    if not pixels :
        print "Could not read:", input.geterror()
        return
    input.close()    # we're done with the file at this point
    minval = pixels[0][0]   # initialize to the first pixel value
    maxval = pixels[0][0]
    for y in range(spec.height) :
        for x in range(spec.width) :
            p = pixels[y][x]
            for c in range(nchans) :
                if p[c] < minval[c] :
                    minval[c] = p[c]
                if p[c] > maxval[c] :
                    maxval[c] = p[c]
    print "Min values per channel were", minval
    print "Max values per channel were", maxval
\end{code}
\newpage


\section{ImageOutput}
\label{sec:pythonimageoutput}

See Chapter~\ref{chap:imageoutput} for detailed explanations of the
C++ \ImageOutput class APIs. The Python APIs are very similar.

\apiitem{ImageOutput ImageOutput.{\ce create} (filename, plugin_searchpath="")}

Create a new \ImageOutput capable of writing the named file format (which may
also be a file name, with the type deduced from the extension).  There
is an optional parameter giving an colon-separated search path for finding
\ImageOutput plugins.  The function returns an \ImageOutput object, or
{\cf None} upon error (in which case, {OpenImageIO.geterror()} may be used
to retrieve the error message).

\noindent Example:
\begin{code}
    import OpenImageIO as oiio
    output = ImageOutput.create ("myfile.tif")
    if not output :
        print "Error:", oiio.geterror()
\end{code}
\apiend

\apiitem{str ImageOutput.{\ce format_name} ()}
The file format name of a created \ImageOutput.

\noindent Example:
\begin{code}
    output = ImageOutput.create (filename)
    if output :
        print "Created output", filename, "as a", output.format_name()
\end{code}
\apiend

\apiitem{int ImageOutput.{\ce supports} (feature)}
For a created \ImageOutput, returns {\cf True} if the file format supports
the named feature (such as \qkw{tiles}, \qkw{mipmap}, etc., see
Section~\ref{sec:supportsfeaturelist} for the full list), or {\cf False}
if this file format does not support the feature.

\noindent Example:
\begin{code}
    output = ImageOutput.create (filename)
    if output :
        print output.format_name(), "supports..."
        print "tiles?", output.supports("tiles")
        print "multi-image?", output.supports("multiimage")
        print "MIP maps?", output.supports("mipmap")
        print "per-channel formats?", output.supports("channelformats")
\end{code}
\apiend

\apiitem{bool ImageOutput.{\ce open} (filename, spec, mode="Create")}
Opens the named output file, with an \ImageSpec describing the image to
be output.  The {\cf mode} may be one of \qkw{create}, \qkw{AppendSubimage},
or \qkw{AppendMIPLevel}.
See Section~\ref{sec:imageoutputopen} for details.  Returns {\cf True}
upon success, {\cf False} upon failure (error messages retrieved via
{\cf ImageOutput.geterror()}.)

\noindent Example:
\begin{code}
    output = ImageOutput.create (filename)
    if not output :
        print "Error:", oiio.geterror()
    spec = ImageSpec (640, 480, 3, "uint8")
    ok = output.open (filename, spec)
    if not ok :
        print "Could not open", filename, ":", output.geterror()
\end{code}
\apiend

\apiitem{bool ImageOutput.{\ce open} (filename, (imagespec, ...))}
This variety of {\cf open()} is used specifically for multi-subimage files.
A \emph{tuple} of \ImageSpec objects is passed, one for each subimage
that will be written to the file.  After each subimage is written, then
a regular call to {\cf open(name, newspec, {\ce AppendSubimage})} moves
on to the next subimage.
\apiend

\apiitem{bool ImageOutput.{\ce close} ()}
Closes an open output.
\apiend

\apiitem{ImageSpec ImageOutput.{\ce spec} ()}
Retrieves the \ImageSpec of the currently-open output image.
\apiend

\apiitem{bool ImageOutput.{\ce write_image} (pixels)}
Write the currently opened image all at once.  The {\cf pixels} parameter
should be a Numpy {\cf ndarray} containing data elements indexed as
{\cf [y][x][channel]} for normal 2D images, or for 3D volumetric images,
as {\cf [z][y][x][channel]}, in other words, exactly matching the shape of
array returned by {\cf ImageInput.read_image}. (It will also work fine if
the array is 1D ``flattened'' version, as long as it contains the correct
total number of values.) The data type is deduced from the contents of the
array itself. Returns {\cf True} upon success, {\cf False} upon failure.

\noindent Example:
\begin{code}
    # This example reads a scanline file, then converts it to tiled
    # and writes to the same name.

    input = ImageInput.open (filename)
    spec = input.spec ()
    pixels = input.read_image ()
    input.close ()

    output = ImageOutput.create (filename)
    if output.supports("tiles") :
        spec.tile_width = 64
        spec.tile_height = 64
        output.open (filename, spec)
        output.write_image (pixels)
        output.close ()
\end{code}
\apiend

\apiitem{bool ImageOutput.{\ce write_scanline} (y, z, pixels) \\
bool ImageOutput.{\ce write_scanlines} (ybegin, yend, z, pixels)}

Write one or many scanlines to the currently open file.
Returns {\cf True} upon success, {\cf False} upon failure.

The {\cf pixels} parameter
should be a Numpy {\cf ndarray} containing data elements indexed as
{\cf [x][channel]} for {\cf write_scanline} or as {\cf [y][x][channels}
for {\cf write_scanlines}, exactly matching the shape returned by
{\cf ImageInput.read_scanline} or {\cf ImageInput.read_scanlines}.
(It will also work fine if the array is 1D ``flattened'' version, as long
as it contains the correct total number of values.)

\noindent Example:
\begin{code}
    # Copy a TIFF image to JPEG by copying scanline by scanline.
    input = ImageInput.open ("in.tif")
    spec = input.spec ()
    output = ImageOutput.create ("out.jpg")
    output.open (filename, spec)
    for z in range(spec.z, spec.z+spec.depth) :
        for y in range(spec.y, spec.y+spec.height) :
            pixels = input.read_scanline (y, z)
            output.write_scanline (y, z, pixels)
    output.close ()
    input.close ()

    # The same example, but copying a whole "plane" of scanlines at a time:
    ...
    for z in range(spec.z, spec.z+spec.depth) :
        pixels = input.read_scanlines (spec.y, spec.y+spec.height, z)
        output.write_scanlines (spec.y, spec.y+spec.height, z, pixels)
    ...
\end{code}
\apiend

\apiitem{bool ImageOutput.{\ce write_tile} (x, y, z, pixels) \\
bool ImageOutput.{\ce write_tiles} (xbegin, xend, ybegin, yend, zbegin, zend, pixels)}

Write one or many tiles to the currently open file.
Returns {\cf True} upon success, {\cf False} upon failure.

The {\cf pixels} parameter
should be a Numpy {\cf ndarray} containing data elements indexed as
{\cf [y][x][channel]} for normal 2D images, or as {\cf [z][y][x][channels}
3D volumetric images, exactly matching the shape returned by
{\cf ImageInput.read_tile} or {\cf ImageInput.read_tiles}.
(It will also work fine if the array is 1D ``flattened'' version, as long
as it contains the correct total number of values.)

\noindent Example:
\begin{code}
    input = ImageInput.open (in_filename)
    spec = input.spec ()
    output = ImageOutput.create (out_filename)
    output.open (out_filename, spec)
    for z in range(spec.z, spec.z+spec.depth, spec.tile_depth) :
        for y in range(spec.y, spec.y+spec.height, spec.tile_height) :
            for x in range(spec.x, spec.x+spec.width, spec.tile_width) :
                pixels = input.read_tile (x, y, z)
                output.write_tile (x, y, z, pixels)
    output.close ()
    input.close ()

    # The same example, but copying a whole row of of tiles at a time:
    ...
    for z in range(spec.z, spec.z+spec.depth, spec.tile_depth) :
        for y in range(spec.y, spec.y+spec.height, spec.tile_height) :
            pixels = input.read_tiles (spec.x, spec.x+spec.width,
                                       y, y+tile_width, z, z+tile_width)
            output.write_tiles (spec.x, spec.x+spec.width,
                                y, y+tile_width, z, z+tile_width, pixels)
    ...
\end{code}
\apiend

\apiitem{bool ImageOutput.{\ce write_deep_scanlines} (ybegin, yend, z, deepdata) \\
bool ImageOutput.{\ce write_deep_tiles} (xbegin, xend, ybegin, yend, \\
\bigspc\bigspc\bigspc zbegin, zend, deepdata) \\
bool ImageOutput.{\ce write_deep_image} (deepdata)}

Write a collection of scanlines, tiles, or an entire image of ``deep''
pixel data. The begin/end coordinates are all integer values, and
{\cf deepdata} should be a \DeepData.
\apiend

\apiitem{bool ImageOutput.{\ce copy_image} (imageinput)}
Copy the current image of the open input to the open output. (The reason
this may be preferred in some circumstances is that, if input and
output were the same kind of input file format, they may have a special
efficient technique to copy pixels unaltered, for example by avoiding the 
decompression/recompression round trip.)

\noindent Example:
\begin{code}
    input = ImageInput.open (in_filename)
    spec = input.spec ()
    output = ImageOutput.create (out_filename)
    output.open (filename, spec)
    output.copy_image (input)
    output.close ()
    input.close ()
\end{code}
\apiend

\apiitem{str ImageOuput.{\ce geterror} ()}
Retrieves the error message from the latest failed operation on an open
file.

\noindent Example:
\begin{code}
    output = ImageOutput.create (filename)
    if not output :
        print "Create error:", oiio.geterror()
        # N.B. error on create must be retrieved with the global geterror(),
        # since there is no ImageOutput object!
    else :
        ok = output.open (filename, spec)
        if not ok :
            print "Open error:", output.geterror()
        ok = output.write_image (pixels)
        if not ok :
            print "Write error:", output.geterror()
        output.close ()
\end{code}
\apiend



\section{ImageBuf}
\label{sec:pythonimagebuf}

See Chapter~\ref{chap:imagebuf} for detailed explanations of the
C++ \ImageBuf class APIs. The Python APIs are very similar.

\apiitem{ImageBuf {\ce ImageBuf} ()}
Construct a new, empty \ImageBuf. The \ImageBuf is uninitialized and is
awaiting a call to {\cf reset()} or {\cf copy()} before it is useful.
\apiend

\apiitem{ImageBuf {\ce ImageBuf} (filename) \\
ImageBuf {\ce ImageBuf} (filename, subimage, miplevel)}

Construct a read-only \ImageBuf that will read from the named file.
Optionally, a specific subimage or MIP level may be specified (defaulting to
0).

\noindent Example:
\begin{code}
    import OpenImageIO as oiio
    ...
    buf = ImageBuf ("grid.tif")
\end{code}
\apiend

\apiitem{ImageBuf {\ce ImageBuf} (imagespec, zero = True)}

Construct a writeable \ImageBuf of the dimensions and data format specified
by an \ImageSpec. The pixels will be initialized to black/empty values if
{\cf zero} is True, otherwise the pixel values will remain uninitialized.

\noindent Example:
\begin{code}
    spec = ImageSpec (640, 480, 3, "float")
    buf = ImageBuf (spec)
\end{code}
\apiend

\apiitem{ImageBuf.{\ce clear} ()}
Resets the \ImageBuf to a pristine state identical to that of a freshly
constructed \ImageBuf using the default constructor.

\noindent Example:
\begin{code}
    buf = ImageBuf (...)

    # The following two commands are equivalent:
    buf = ImageBuf()     # 1 - assign a new blank ImageBuf
    buf.clear()          # 2 - clear the existing ImageBuf
\end{code}
\apiend

\apiitem{ImageBuf.{\ce reset} (filename, subimage=0, miplevel=0, config=ImageSpec())}
Restore the \ImageBuf to a newly-constructed state, to read from
a filename (optionally specifying a subimage, MIP level, and/or 
a ``configuration'' \ImageSpec).
\apiend

\apiitem{ImageBuf.{\ce reset} (imagespec, zero = True)}
Restore the \ImageBuf to the newly-constructed state of a writeable
\ImageBuf specified by an \ImageSpec.
The pixels will be iniialized to black/empty if {\cf zero} is True,
otherwise the pixel values will remain uninitialized.
\apiend

\apiitem{bool ImageBuf.{\ce read} (subimage=0, miplevel=0, force=False, convert=oiio.UNKNOWN) \\
bool ImageBuf.{\ce read} (subimage, miplevel, chbegin, chend, force, convert)}
Explicitly read the image from the file (of a file-reading \ImageBuf), optionally
specifying a particular subimage, MIP level, and channel range.  If {\cf force} is {\cf True},
will force an allocation of memory and a full read (versus the default of
relying on an underlying \ImageCache).  If {\cf convert} is not
the default of {\cf UNKNOWN}, it will force the \ImageBuf to convert the
image to the specified data format (versus keeping it in the native 
format or relying on the \ImageCache to make a data formatting decision).

Note that a call to {\cf read()} is not necessary --- any \ImageBuf API call
that accesses pixel values will trigger a file read if it has not yet been
done. An explicit {\cf read()} is generally only needed to change the
subimage or miplevel, or to force an in-buffer read or format conversion.

The {\cf read()} method will return {\cf True} for success, or {\cf False}
if the read could not be performed (in which case, a {\cf geterror()} call
will retrieve the specific error message).

\noindent Example:
\begin{code}
    buf = ImageBuf ("mytexture.exr")
    buf.read (0, 2, True)
    # That forces an allocation and read of MIP level 2
\end{code}
\apiend

\apiitem{bool ImageBuf.{\ce init_spec} (filename, subimage=0, miplevel=0)}

Explicitly read just the header from a file-reading \ImageBuf (if the header
has not yet been read), optionally specifying a particular subimage and MIP
level. The {\cf init_spec()} method will return {\cf True} for success, or
{\cf False} if the read could not be performed (in which case, a {\cf
geterror()} call will retrieve the specific error message).

Note that a call to {\cf init_spec()} is not necessary --- any \ImageBuf API
call that accesses the spec will read it automatically it has not yet been
done.
\apiend

\apiitem{bool ImageBuf.{\ce write} (filename, dtype="", fileformat="")}
Write the contents of the \ImageBuf to the named file.  Optionally,
{\cf dtype} can override the pixel data type (by default, the pixel data
type of the buffer), and {\cf fileformat} can specify a particular file
format to use (by default, it will infer it from the extension of the file
name).

\noindent Example:
\begin{code}
    # No-frills conversion of a TIFF file to JPEG
    buf = ImageBuf ("in.tif")
    buf.write ("out.jpg")

    # Convert to uint16 TIFF
    buf = ImageBuf ("in.exr")
    buf.write ("out.tif", "uint16")
\end{code}
\apiend

\apiitem{bool ImageBuf.{\ce make_writeable} (keep_cache_type = false)}
Force the \ImageBuf to be writeable. That means that if it was previously
backed by an \ImageCache (storage was {\cf IMAGECACHE}), it will force a
full read so that the whole image is in local memory.
\apiend


\apiitem{bool ImageBuf.{\ce set_write_format} (format=oiio.UNKNOWN) \\
bool ImageBuf.{\ce set_write_tiles} (width=0, height=0, depth=0)}
Override the data format or tile size in a subsequent call to {\cf write()}.
The {\cf format}argument to {\cf set_write_format} may be either a single
data type description for all channels, or a tuple giving the data type for
each channel in order.

\noindent Example:
\begin{code}
    # Conversion to a tiled unsigned 16 bit integer file
    buf = ImageBuf ("in.tif")
    buf.set_write_format ("uint16")
    buf.set_write_tiles (64, 64)
    buf.write ("out.tif")
\end{code}
\apiend

\apiitem{ImageSpec ImageBuf.{\ce spec}() \\
ImageSpec ImageBuf.{\ce nativespec}()}
{\cf ImageBuf.spec()} returns the \ImageSpec that describes the contents of
the \ImageBuf.  {\cf ImageBuf.nativespec()} returns an \ImageSpec that
describes the contents of the file that the \ImageBuf was read from (this
may differ from {\cf ImageBuf.spec()} due to format conversions, or any
changes made to the \ImageBuf after the file was read, such as adding
metadata).

Handy rule of thumb: {\cf spec()} describes the buffer, {\cf nativespec()}
describes the original file it came from.

\noindent Example:
\begin{code}
    buf = ImageBuf ("in.tif")
    print "Resolution is", buf.spec().width, "x", buf.spec().height
\end{code}
\apiend

\apiitem{ImageSpec ImageBuf.{\ce specmod}()}
{\cf ImageBuf.specmod()} provides writeable access to the \ImageSpec that
describes the contents of the \ImageBuf.  Be very careful!  It is safe
to modify certain metadata, but if you change the data format or resolution
fields, you will get the chaos you deserve.

\noindent Example:
\begin{code}
    # Read an image, add a caption metadata, write it back out in place
    buf = ImageBuf ("file.tif")
    buf.specmod().attribute ("ImageDescription", "my photo")
    buf.write ("file.tif")
\end{code}
\apiend

\apiitem{str ImageBuf.{\ce name} \\
str ImageBuf.{\ce file_format_name}}
The file name and name of the file format of the image.
\apiend

\apiitem{int ImageBuf.{\ce subimage} \\
int ImageBuf.{\ce miplevel} \\
int ImageBuf.{\ce nsubimages} \\
int ImageBuf.{\ce nmiplevels}}
Several fields giving information about the current subimage and MIP
level, and the total numbers thereof in the file.
\apiend

\apiitem{int ImageBuf.{\ce xbegin} \\
int ImageBuf.{\ce xend} \\
int ImageBuf.{\ce ybegin} \\
int ImageBuf.{\ce yend} \\
int ImageBuf.{\ce zbegin} \\
int ImageBuf.{\ce zend}}
The range of valid pixel data window. Remember that the {\cf end} is 
\emph{one past} the last pixel.
\apiend

\apiitem{int ImageBuf.{\ce xmin} \\
int ImageBuf.{\ce xmax} \\
int ImageBuf.{\ce ymin} \\
int ImageBuf.{\ce ymax} \\
int ImageBuf.{\ce zmin} \\
int ImageBuf.{\ce zmax}}
The minimum and maximum (inclusive) coordinates of the pixel data window.
\apiend

\apiitem{int ImageBuf.{\ce orientation} \\
int ImageBuf.{\ce oriented_width} \\
int ImageBuf.{\ce oriented_height} \\
int ImageBuf.{\ce oriented_x} \\
int ImageBuf.{\ce oriented_y} \\
int ImageBuf.{\ce oriented_full_width} \\
int ImageBuf.{\ce oriented_full_height} \\
int ImageBuf.{\ce oriented_full_x} \\
int ImageBuf.{\ce oriented_full_y}}
The {\cf orientation} field gives the suggested display oriententation of
the image (see Section~\ref{metadata:orientation}).

The other fields are helpers that give the width, height, and origin
(as well as ``full'' or ``display'' resolution and origin), taking the
intended orientation into consideration.
\apiend

\apiitem{ROI ImageBuf.{\ce roi} \\
ROI ImageBuf.{\ce roi_full}}
These fields return an \ROI description of the pixel data window
({\cf roi}) and the full (a.k.a.\ ``display'') window ({\cf roi_full}).

\noindent Example:
\begin{code}
    buf = ImageBuf ("tahoe.jpg")
    print "Resolution is", buf.roi.width, "x", buf.roi.height
\end{code}
\apiend

\apiitem{ImageBuf.{\ce set_origin} (x, y, z=0)}
Changes the ``origin'' of the data pixel data window to the specified
coordinates.

\noindent Example:
\begin{code}
    # Shift the pixel data so the upper left is at pixel (10, 10)
    buf.set_origin (10, 10)
\end{code}
\apiend

\apiitem{ImageBuf.{\ce set_full} (roi)}
Changes the ``full'' (a.k.a. ``display'') window to the specified ROI.

\noindent Example:
\begin{code}
    newroi = ROI (0, 1024, 0, 768)
    buf.set_full (newroi)
\end{code}
\apiend

\apiitem{bool ImageBuf.{\ce pixels_valid}}
Will be {\cf True} if the file has already been read and the pixels are
valid. (It is always {\cf True} for writeable \ImageBuf's.)
There should be few good reasons to access these, since the spec and pixels
will be automatically be read when they are needed. 
\apiend

\apiitem{TypeDesc ImageBuf.{\ce pixeltype}}
Returns the description of the data type of the pixels stored within the
\ImageBuf.
\apiend

\apiitem{ImageBuf.{\ce copy_metadata} (other_imagebuf)}
Replaces the metadata (all \ImageSpec items, except for the data format
and pixel data window size) with the corresponding metadata from the
other \ImageBuf.
\apiend

\apiitem{ImageBuf.{\ce copy_pixels} (other_imagebuf)}
Replace the pixels in this \ImageBuf with the values from the other
\ImageBuf.
\apiend

\apiitem{ImageBuf ImageBuf.{\ce copy} (format=TypeUnknown)}
Return a full copy of this \ImageBuf (with optional data format conversion,
if {\cf format} is supplied).

\noindent Example:
\begin{code}
    A = ImageBuf("A.tif")

    # Make a separate, duplicate copy of A
    B = A.copy()

    # Make another copy of A, but converting to float pixels
    C = A.copy ("float")
\end{code}
\apiend

\apiitem{ImageBuf.{\ce copy} (other_imagebuf, format=TypeUnknown)}
Make this \ImageBuf a complete copy of the other \ImageBuf.
If a {\cf format} is provided, {\cf this} will get the specified pixel
data type rather than using the same pixel format as the source \ImageBuf.

\noindent Example:
\begin{code}
    A = ImageBuf("A.tif")

    # Make a separate, duplicate copy of A
    B = ImageBuf()
    B.copy (A)

    # Make another copy of A, but converting to float pixels
    C = ImageBuf()
    C.copy (A, oiio.FLOAT)
\end{code}
\apiend

\apiitem{ImageBuf.{\ce swap} (other_imagebuf)}
Swaps the content of this \ImageBuf and the other \ImageBuf.

\noindent Example:
\begin{code}
    A = ImageBuf("A.tif")
    B = ImageBuf("B.tif")
    A.swap (B)
    # Now B contains the "A.tif" image and A contains the "B.tif" image
\end{code}
\apiend

\apiitem{tuple ImageBuf.{\ce getpixel} (x, y, z=0, wrap="black")}
Retrieves pixel $(x,y,z)$ from the buffer and return it as a tuple of
{\cf float} values, one for each color channel.  The {\cf x, y, z} values
are {\cf int} pixel coordinates.  The optional {\cf wrap} parameter
describes what should happen if the coordinates are outside the pixel data
window (and may be: \qkw{black}, \qkw{clamp}, \qkw{periodic}, \qkw{mirror}).

\noindent Example:
\begin{code}
    buf = ImageBuf ("tahoe.jpg")
    p = buf.getpixel (50, 50)
    print p

    > (0.37, 0.615, 0.97)
\end{code}
\apiend

\apiitem{float ImageBuf.{\ce getchannel} (x, y, z, channel, wrap="black")}
Retrieves just a single channel value from pixel $(x,y,z)$ from the buffer
and returns it as a {\cf float} value.  The optional {\cf wrap} parameter
describes what should happen if the coordinates are outside the pixel data
window (and may be: \qkw{black}, \qkw{clamp}, \qkw{periodic}, \qkw{mirror}).

\noindent Example:
\begin{code}
    buf = ImageBuf ("tahoe.jpg")
    green = buf.getchannel (50, 50, 0, 1)
\end{code}
\apiend

\apiitem{tuple ImageBuf.{\ce interppixel} (x, y, wrap="black") \\
tuple ImageBuf.{\ce interppixel_bicubic} (x, y, wrap="black")}
Interpolates the image value (bilinearly or bicubically)
at coordinates $(x,y)$ and return it as a tuple
of {\cf float} values, one for each color channel.  The {\cf x, y} values
are continuous {\cf float} coordinates in ``pixel space.''   The optional
{\cf wrap} parameter describes what should happen if the coordinates are
outside the pixel data window (and may be: 
\qkw{black}, \qkw{clamp}, \qkw{periodic}, \qkw{mirror}).

\noindent Example:
\begin{code}
    buf = ImageBuf ("tahoe.jpg")
    midx = float(buf.xbegin + buf.xend) / 2.0
    midy = float(buf.ybegin + buf.yend) / 2.0
    p = buf.interpixel (midx, midy)
    # Now p is the interpolated value from right in the center of
    # the data window
\end{code}
\apiend

\apiitem{tuple ImageBuf.{\ce interppixel_NDC} (x, y, wrap="black") \\
tuple ImageBuf.{\ce interppixel_bicubic_NDC} (x, y, wrap="black")}

Interpolates the image value (bilinearly or bicubically)
at coordinates $(x,y)$ and return it as a tuple
of {\cf float} values, one for each color channel.  The {\cf x, y} values
are continuous, normalized {\cf float} coordinates in ``NDC space,'' where
{\cf (0,0)} is the upper left corner of the full (a.k.a.\ ``display'')
window, and {\cf (1,1)} is the lower right corner of the full/display
window. The  {\cf wrap} parameter describes what should happen if the
coordinates are outside the pixel data window (and may be: 
\qkw{black}, \qkw{clamp}, \qkw{periodic}, \qkw{mirror}).

\noindent Example:
\begin{code}
    buf = ImageBuf ("tahoe.jpg")
    p = buf.interpixel_NDC (0.5, 0.5)
    # Now p is the interpolated value from right in the center of
    # the display window
\end{code}
\apiend

\apiitem{ImageBuf.{\ce setpixel} (x, y, pixel_value) \\
ImageBuf.{\ce setpixel} (x, y, z, pixel_value)}
Sets pixel $(x,y,z)$ to be the {\cf pixel_value}, expressed as a tuple of
{\cf float}s (one for each color channel).

\noindent Example:
\begin{code}
    buf = ImageBuf (ImageSpec (640, 480, 3, oiio.UINT8))

    # Set the whole image to red (the dumb slow way, but it works):
    for y in range(buf.ybegin, buf.yend) :
        for x in range(buf.xbegin, buf.xend) :
            buf.setpixel (x, y, (1.0, 0.0, 0.0))
\end{code}
\apiend

\apiitem{array ImageBuf.{\ce get_pixels} (format=TypeFloat, roi=ROI.All)}

Retrieves the rectangle of pixels (and channels) specified by {\cf roi} from
the image and returns them as an array of values with type specified by
{\cf format}.

As with the {\cf ImageInput} read functions, the return value is a NumPy
{\cf ndarray} containing data elements indexed as
{\cf [y][x][channel]} for normal 2D images, or for 3D volumetric images,
as {\cf [z][y][x][channel]}).
Returns {\cf True} upon success, {\cf False} upon failure.

\noindent Example:
\begin{code}
    buf = ImageBuf ("tahoe.jpg")
    pixels = buf.get_pixels (oiio.FLOAT)  # no ROI means the whole image
\end{code}
\apiend

\apiitem{ImageBuf.{\ce set_pixels} (roi, data)}

Sets the rectangle of pixels (and channels) specified by {\cf roi} with
values in the {\cf data}, which is a NumPy {\cf ndarray} of values
indexed as {\cf [y][x][channel]} for normal 2D images, or for 3D volumetric images,
as {\cf [z][y][x][channel]}. (It will also work fine if
the array is 1D ``flattened'' version, as long as it contains the correct
total number of values.) The data type is deduced from the contents of the
array itself.

\noindent Example:
\begin{code}
    buf = ImageBuf (...)
    pixels = (....)
    buf.set_pixels (ROI(), pixels)
\end{code}
\apiend

\apiitem{bool ImageBuf.{\ce has_error} \\
str ImageBuf.{\ce geterror} ()}
The {\cf ImageBuf.has_error} field will be {\cf True} if an error has
occurred in the \ImageBuf, in which case the {\cf geterror()} method will
retrieve the error message (and clear it afterwards).

\noindent Example:
\begin{code}
    buf = ImageBuf ("in.tif")
    buf.read ()   # force a read
    if buf.has_error :
        print "Error reading the file:", buf.geterror()
    buf.write ("out.jpg")
    if buf.has_error :
        print "Could not convert the file:", buf.geterror()
\end{code}
\apiend

\apiitem{int ImageBuf.{\ce pixelindex} (x, y, z, check_range=False)}
Return the index of pixel (x,y,z).
\apiend

\apiitem{bool ImageBuf.{\ce deep}}
Will be {\cf True} if the file contains ``deep'' pixel data, or {\cf False}
for an ordinary images.
\apiend

\apiitem{int ImageBuf.{\ce deep_samples} (x, y, z=0)}
Return the number of deep samples for pixel (x,y,z).
\apiend

\apiitem{ImageBuf.{\ce set_deep_samples} (x, y, z, nsamples)}
Set the number of deep samples for pixel (x,y,z).
\apiend

\apiitem{ImageBuf.{\ce deep_insert_samples} (x, y, z, samplepos, nsamples) \\
int ImageBuf.{\ce deep_erase_samples} (x, y, z, samplepos, nsamples)}
Insert or erase \emph{nsamples} samples starting at the given position of
pixel {\cf (x,y,z)}.
\apiend

\apiitem{float ImageBuf.{\ce deep_value} (x, y, z, channel, sample) \\
uint ImageBuf.{\ce deep_value_uint} (x, y, z, channel, sample)}
Return the value of the given deep sample (particular pixel, channel, and
sample number) for a channel that is a float or an unsigned integer type,
respectively.
\apiend

\apiitem{ImageBuf.{\ce set_deep_value} (x, y, z, channel, sample, value) \\
ImageBuf.{\ce set_deep_value_uint} (x, y, z, channel, sample, value)}
Set the value of the given deep sample (particular pixel, channel, and
sample number) for a channel that is a float or an unsigned integer type,
respectively.
\apiend

\apiitem{DeepData ImageBuf.{\ce deepdata}}
Returns a reference to the underlying {\cf DeepData} of the image.
\apiend




\newpage
\section{ImageBufAlgo}
\label{sec:pythonimagebufalgo}

The C++ \IBA functions are described in detail in
Chapter~\ref{chap:imagebufalgo}.  They are also exposed to Python.
For the majority of \IBA functions, their use in Python is identical
to C++; in those cases, we will keep our descriptions of the Python
bindings minimal and refer you to Chapter~\ref{chap:imagebufalgo}, saving
the extended descriptions for those functions that differ from the C++
counterparts.

A few things about the paramters of the \IBA function calls are identical
among the functions, so we will explain once here rather than separately for
each function:

\begin{itemize}
\item {\cf dst} is an existing \ImageBuf, which will be modified (it may be
an uninitialized \ImageBuf, but it must be an \ImageBuf).
\item {\cf src} parameter is an initialized \ImageBuf, which will not be
modified (unless it happens to refer to the same image as {\cf dst}.
\item {\cf roi}, if supplied, is an {\cf ROI} specifying a region of interst
over which to operate. If omitted, the region will be the entire size of the
source image(s).
\item {\cf nthreads} is the maximum number of threads to use. If not
supplied, it defaults to 0, meaning to use as many threads as hardware cores
available.
\end{itemize}

Just as with the C++ \IBA functions, if {\cf dst} is an uninitialized
\ImageBuf, it will be sized to reflect the {\cf roi} (which, in turn, if
undefined, will be sized to be the union of the ROI's of the source 
images).

\subsection{Pattern generation}
\label{sec:iba:py:patterns}

\apiitem{ImageBuf ImageBufAlgo.{\ce zero} (roi, nthreads=0) \\
bool ImageBufAlgo.{\ce zero} (dst, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!zero} \indexapi{zero}

Zero out the destination buffer (or a specific region of it).

\smallskip
\noindent Example:
\begin{code}
    # Initialize buf to a 640x480 3-channel FLOAT buffer of 0 values
    buf = ImageBufAlgo.zero (ROI(0, 640, 0, 480, 0, 1, 0, 3))
\end{code}
\apiend

\apiitem{ImageBuf ImageBufAlgo.{\ce fill} (values, roi=ROI.All, nthreads=0) \\
ImageBuf ImageBufAlgo.{\ce fill} (top, bottom, roi=ROI.All, nthreads=0) \\
ImageBuf ImageBufAlgo.{\ce fill} (topleft, topright, \\
\bigspc bottomleft, bottomright, roi=ROI.All, nthreads=0) \\[0.5ex]
bool ImageBufAlgo.{\ce fill} (dst, values, roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce fill} (dst, top, bottom, roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce fill} (dst, topleft, topright, \\
\bigspc bottomleft, bottomright, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!fill} \indexapi{fill}

Return a filled float image of size ROI, or set the the pixels of image
{\cf dst} within the ROI to a color or gradient.

Three fill optins are available: (a) if one color tuple is supplied, the
whole ROI will be filled with that constant value, (b) if two color tuples
are supplied, a linear gradient will be applied from top to bottom, (c) if
four color cuples are supplied, the ROI will be be filled with values
bilinearly interpolated from the four corner colors supplied.

\smallskip
\noindent Examples:
\begin{code}
    # Draw a red rectangle into buf
    buf = ImageBuf (ImageSpec(640, 480, 3, TypeDesc.FLOAT)
    ImageBufAlgo.fill (buf, (1,0,0), ROI(50, 100, 75, 85))
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce checker} (width, height, depth, 
 color1, color2, \\ \bigspc xoffset=0, yoffset=0, zoffset=0, 
 roi=ROI.All, nthreads=0) \\
 bool ImageBufAlgo.{\ce checker} (dst, width, height, depth, 
 color1, color2, \\ \bigspc xoffset=0, yoffset=0, zoffset=0, 
 roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!checker} \indexapi{checker}

Return (or copy into {\cf dst}) a checkerboard pattern. The colors are specified as
tuples giving the values for each color channel.

\smallskip
\noindent Examples:
\begin{code}
    buf = ImageBuf(ImageSpec(640, 480, 3, oiio.UINT8))
    ImageBufAlgo.checker (buf, 64, 64, 1, (0.1,0.1,0.1), (0.4,0.4,0.4))
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce noise} (noisetype, A=0.0, B=0.1, \\
\bigspc\bigspc mono=False, seed=0, roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce noise} (dst, noisetype, A=0.0, B=0.1,\\
\bigspc\bigspc mono=False, seed=0, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!noise} \indexapi{noise}

Return an image of pseudorandom noise, or add pseudorandom noise
to the specified region of existing region {\cf dst}.

For noise type \qkw{uniform}, the noise is uniformly distributed on the
range {\cf [A,B)}. For noise \qkw{gaussian}, the noise will have a normal
distribution with mean A and standard deviation B. For noise \qkw{salt}, the
value A will be stored in a random set of pixels whose proportion (of the
overall image) is B. For all noise types, choosing different {\cf seed}
values will result in a different pattern. If the {\cf mono} flag is {\cf
true}, a single noise value will be applied to all channels specified by
{\cf roi}, but if {\cf mono} is {\cf false}, a separate noise value will be
computed for each channel in the region.

\smallskip
\noindent Examples:
\begin{code}
    buf = ImageBuf(ImageSpec(640, 480, 3, oiio.UINT8))
    ImageBufAlgo.zero (buf)
    ImageBufAlgo.noise (buf, 'uniform', 0.25, 0.75)
\end{code}
\apiend



\apiitem{bool ImageBufAlgo.{\ce render_point} (dst, x, y, color=(1,1,1,1))}
\index{ImageBufAlgo!render_point} \indexapi{render_point}

Render a point at pixel $(x,y)$ of {\cf dst}.  The {\cf color} (if supplied)
is a tuple giving the per-channel colors.

\smallskip
\noindent Examples:
\begin{code}
    buf = ImageBuf(ImageSpec (640, 480, 4, oiio.FLOAT))
    ImageBufAlgo.render_point (buf, 10, 20, (1,0,0,1))
\end{code}
\apiend


\apiitem{bool ImageBufAlgo.{\ce render_line} (dst, x1, y1, x2, y2, \\
\bigspc\bigspc color=(1,1,1,1), skip_first_point=False)}
\index{ImageBufAlgo!render_line} \indexapi{render_line}

Render a line from pixel $(x_1,y_1)$ to $(x_2,y_2)$ into {\cf dst}.  The
{\cf color} (if supplied) is a tuple giving the per-channel colors.

\smallskip
\noindent Examples:
\begin{code}
    buf = ImageBuf(ImageSpec (640, 480, 4, oiio.FLOAT))
    ImageBufAlgo.render_line (buf, 10, 10, 500, 20, (1,0,0,1))
\end{code}
\apiend


\apiitem{bool ImageBufAlgo.{\ce render_box} (dst, x1, y1, x2, y2, \\
\bigspc\bigspc color=(1,1,1,1), filled=False)}
\index{ImageBufAlgo!render_box} \indexapi{render_box}

Render a filled or unfilled box with corners at pixels $(x_1,y_1)$ and
$(x_2,y_2)$ into {\cf dst}.  The {\cf color} (if supplied) is a tuple giving
the per-channel colors.

\smallskip
\noindent Examples:
\begin{code}
    buf = ImageBuf(ImageSpec (640, 480, 4, oiio.FLOAT))
    ImageBufAlgo.render_box (buf, 150, 100, 240, 180, (0,1,1,1))
    ImageBufAlgo.render_box (buf, 100, 50, 180, 140, (0.5, 0.5, 0, 0.5), True)
\end{code}
\apiend


\apiitem{bool ImageBufAlgo.{\ce render_text} (dst, x, y, text, fontsize=16, \\
  \bigspc\bigspc  fontname="", textcolor=(1,1,1,1),\\
  \bigspc\bigspc  alignx="left", aligny="baseline", shadow=0,\\
  \bigspc\bigspc  roi=ROI.All, nthreads=0}
\index{ImageBufAlgo!render_text} \indexapi{render_text}

Render antialiased text into {\cf dst}.  The {\cf textcolor} (if supplied)
is a tuple giving the per-channel colors. Choices for {\cf alignx} are
\qkw{left}, \qkw{right}, and \qkw{center}, and choices for {\cf aligny} are
\qkw{baseline}, \qkw{top}, \qkw{bottom}, and \qkw{center}.

\smallskip
\noindent Examples:
\begin{code}
    buf = ImageBuf(ImageSpec (640, 480, 4, oiio.FLOAT))
    ImageBufAlgo.render_text (buf, 50, 100, "Hello, world")
    ImageBufAlgo.render_text (buf, 100, 200, "Go Big Red!",
                              60, "Arial Bold", (1,0,0,1))
\end{code}
% \spc \includegraphics[width=2.5in]{figures/text.jpg}
\apiend


\apiitem{ROI ImageBufAlgo.{\ce text_size} (text, fontsize=16, fontname="")}
\index{ImageBufAlgo!text_size} \indexapi{text_size}

Compute the size that will be needed for the text as an ROI and return it.
The size will not be {\cf defined} if an error occurred (such as not being a
valid font name).

\smallskip
\noindent Examples:
\begin{code}
    A = ImageBuf(ImageSpec (640, 480, 4, oiio.FLOAT))
    Aroi = A.roi
    size = ImageBufAlgo.text_size ("Centered", 40, "Courier New")
    if size.defined :
        x = Aroi.xbegin + Aroi.width/2  - (size.xbegin + size.width/2)
        y = Aroi.ybegin + Aroi.height/2 - (size.ybegin + size.height/2)
        ImageBufAlgo.render_text (A, x, y, "Centered", 40, "Courier New")

    # Note: this was for illustration. An easier way to do this is:
    #   render_text (A, x, y, "Centered", 40, "Courier New", alignx="center")
\end{code}
% \spc \includegraphics[width=2.5in]{figures/textcentered.jpg}
\apiend



\subsection{Image transformations and data movement}
\label{sec:iba:py:transforms}

\apiitem{ImageBuf ImageBufAlgo.{\ce channels} (src, channelorder, newchannelnames=(), \\
        \bigspc\bigspc shuffle_channel_names=False, nthreads=0) \\
bool ImageBufAlgo.{\ce channels} (dst, src, channelorder, newchannelnames=(), \\
        \bigspc\bigspc shuffle_channel_names=False, nthreads=0)}
\index{ImageBufAlgo!channels} \indexapi{channels}

Return (or store in {\cf dst}) shuffled channels of {\cf src}, with channels in
the order specified by the tuple {\cf channelorder}. 
The length of {\cf channelorder} specifies the number of channels to copy.
Each element in the tuple {\cf channelorder} may be one of the following:
\begin{itemize}
\item {}
\item {\cf int} : specifies the index (beginning at 0) of the channel
    to copy.
\item {\cf str} : specifies the name of the channel to copy.
\item {\cf float} : specifies a constant value to use for that channel.
\end{itemize}

If {\cf newchannelnames} is supplied, it is a tuple of new channel
names. (See the C++ version for more full explanation.)

\smallskip
\noindent Examples:
\begin{code}
    # Copy the first 3 channels of an RGBA, drop the alpha
    RGBA = ImageBuf("rgba.tif")
    RGB = ImageBufAlgo.channels (RGBA, (0,1,2))

    # Copy just the alpha channel, making a 1-channel image
    Alpha = ImageBufAlgo.channels (RGBA, ("A",))

    # Swap the R and B channels
    BGRA = ImageBufAlgo.channels (RGBA, (2, 1, 0, 3))

    # Add an alpha channel with value 1.0 everywhere to an RGB image
    RGBA = ImageBufAlgo.channels (RGB, ("R", "G", "B", 1.0),
                                  ("R", "G", "B", "A"))
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce channel_append} (A, B, roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce channel_append} (dst, A, B, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!channel_append} \indexapi{channel_append}
Append the channels of images {\cf A} and {\cf B} together into one image.

\smallskip
\noindent Examples:
\begin{code}
    RGBA = ImageBuf ("rgba.exr")
    Z = ImageBuf ("z.exr")
    RGBAZ = ImageBufAlgo.channel_append (RGBA, Z)
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce copy} (src, convert=TypeDesc.UNKNOWN, \\
        \bigspc roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce copy} (dst, src, convert=TypeDesc.UNKNOWN, \\
        \bigspc roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!copy} \indexapi{copy}
Copy the specified region of pixels of {\cf src} at the same
locations, optionally with the pixel
type overridden by {\cf convert} (if it is not {\cf UNKNOWN}).

\smallskip
\noindent Examples:
\begin{code}
    # Copy A's upper left 200x100 region into B
    B = ImageBufAlgo.copy (A, ROI(0,200,0,100))
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce crop} (src, roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce crop} (dst, src, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!crop} \indexapi{crop}
Reset {\cf dst} to be the specified region of {\cf src}.

\smallskip
\noindent Examples:
\begin{code}
    # Set B to be the upper left 200x100 region of A
    A = ImageBuf ("a.tif")
    B = ImageBufAlgo.crop (A, ROI(0,200,0,100))
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce cut} (src, roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce cut} (dst, src, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!cut} \indexapi{cut}
Reset {\cf dst} to be the specified region of {\cf src}, but moved so
that the resulting new image has its pixel data at the image plane origin.

\smallskip
\noindent Examples:
\begin{code}
    # Set B to be the lower left 200x100 region of A, moved to the origin
    A = ImageBuf ("a.tif")
    B = ImageBufAlgo.cut (A, ROI(0,200,380,480))
\end{code}
\apiend


\apiitem{bool ImageBufAlgo.{\ce paste} (dst, xbegin, ybegin, zbegin, chbegin, \\
  \bigspc\bigspc src, ROI srcroi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!paste} \indexapi{paste}
Copy the specified region of {\cf src} into {\cf dst} beginning at 
offset {\cf (xbegin, ybegin, zbegin)}.

\smallskip
\noindent Examples:
\begin{code}
    # Paste small.exr on top of big.exr at offset (100,100)
    Big = ImageBuf ("big.exr")
    Small = ImageBuf ("small.exr")
    ImageBufAlgo.paste (Big, 100, 100, 0, 0, Small)
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce rotate90} (src, roi=ROI.All, nthreads=0) \\
ImageBuf ImageBufAlgo.{\ce rotate180} (src, roi=ROI.All, nthreads=0) \\
ImageBuf ImageBufAlgo.{\ce rotate270} (src, roi=ROI.All, nthreads=0) \\[1.0ex]
bool ImageBufAlgo.{\ce rotate90} (dst, src, roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce rotate180} (dst, src, roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce rotate270} (dst, src, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!roate90} \indexapi{roate90}
\index{ImageBufAlgo!rotate180} \indexapi{rotate180}
\index{ImageBufAlgo!rotate270} \indexapi{rotate270}
Copy while rotating the image by a multiple of 90 degrees.

\smallskip
\noindent Examples:
\begin{code}
    A = ImageBuf ("tahoe.exr")
    B = ImageBufAlgo.rotate90 (A)
\end{code}
\apiend



\apiitem{ImageBuf ImageBufAlgo.{\ce flip} (src, roi=ROI.All, nthreads=0) \\
ImageBuf ImageBufAlgo.{\ce flop} (src, roi=ROI.All, nthreads=0) \\
ImageBuf ImageBufAlgo.{\ce transpose} (src, roi=ROI.All, nthreads=0) \\[1.0ex]
bool ImageBufAlgo.{\ce flip} (dst, src, roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce flop} (dst, src, roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce transpose} (dst, src, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!flip} \indexapi{flip}
\index{ImageBufAlgo!flop} \indexapi{flop}
\index{ImageBufAlgo!transpose} \indexapi{transpose}
Copy while reversing orientation vertically (flip) or horizontally (flop),
or diagonally (transpose).

\smallskip
\noindent Examples:
\begin{code}
    A = ImageBuf ("tahoe.exr")
    B = ImageBufAlgo.flip (A)
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce reorient} (src, nthreads=0) \\
bool ImageBufAlgo.{\ce reorient} (dst, src, nthreads=0)}
\index{ImageBufAlgo!reorient} \indexapi{reorient}

Copy {\cf src}, applying whatever seties of rotations, flips,
or flops are necessary to transform the pixels into the configuration
suggested by the \qkw{Orientation} metadata of the image (and the
\qkw{Orientation} metadata is then set to 1, ordinary orientation).

\smallskip
\noindent Examples:
\begin{code}
    A = ImageBuf ("tahoe.jpg")
    ImageBufAlgo.reorient (A, A)
\end{code}
\apiend



\apiitem{ImageBuf ImageBufAlgo.{\ce circular_shift} (src, xshift, yshift, zshift=0, \\
        \bigspc  roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce circular_shift} (dst, src, xshift, yshift, zshift=0, \\
        \bigspc  roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!circular_shift} \indexapi{circular_shift}

Copy while circularly shifting by the given amount. 

\smallskip
\noindent Examples:
\begin{code}
    A = ImageBuf ("tahoe.exr")
    B = ImageBufAlgo.circular_shift (A, 200, 100)
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce rotate} (src, angle, filtername="", filtersize=0.0, \\
        \bigspc\bigspc recompute_roi=False, roi=ROI.All, nthreads=0) \\
ImageBuf ImageBufAlgo.{\ce rotate} (src, angle, \\
        \bigspc\bigspc center_x, center_y, filtername="", filtersize=0.0, \\
        \bigspc\bigspc  recompute_roi=False, roi=ROI.All, nthreads=0) \\[1.0ex]
bool ImageBufAlgo.{\ce rotate} (dst, src, angle, filtername="", filtersize=0.0, \\
        \bigspc\bigspc recompute_roi=False, roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce rotate} (dst, src, angle, \\
        \bigspc\bigspc center_x, center_y, filtername="", filtersize=0.0, \\
        \bigspc\bigspc  recompute_roi=False, roi=ROI.All, nthreads=0) }
\index{ImageBufAlgo!rotate} \indexapi{rotate}

Copy arotated version of the
corresponding portion of {\cf src}.  The angle is in radians, with positive
values indicating clockwise rotation. If the filter and size are not
specified, an appropriate default will be chosen.

\smallskip
\noindent Examples:
\begin{code}
    Src = ImageBuf ("tahoe.exr")
    Dst = ImageBufAlgo.rotate (Src, math.radians(45.0))
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce warp} (src, M, filtername="", filtersize=0.0, \\
        \bigspc\bigspc wrap="default", recompute_roi=False, \\
        \bigspc\bigspc roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce warp} (dst, src, M, filtername="", filtersize=0.0, \\
        \bigspc\bigspc wrap="default", recompute_roi=False, \\
        \bigspc\bigspc roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!warp} \indexapi{warp}

Compute a warped (transformed) copy of {\cf src},
with the warp specified by {\cf M} consisting of 9 floating-point numbers
representing a $3 \times 3$ transformation matrix.  If the filter and size
are not specified, an appropriate default will be chosen.

\smallskip
\noindent Examples:
\begin{code}
    M = (0.7071068, 0.7071068, 0, -0.7071068, 0.7071068, 0, 20, -8.284271, 1)
    Src = ImageBuf ("tahoe.exr")
    Dst = ImageBufAlgo.warp (Src, M)
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce resize} (src, filtername="", filtersize=0.0, \\
        \bigspc\bigspc  roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce resize} (dst, src, filtername="", filtersize=0.0, \\
        \bigspc\bigspc  roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!resize} \indexapi{resize}
Compute a high-quality resized version of the
corresponding portion of {\cf src}.  If the filter and size are not
specified, an appropriate default will be chosen.

\smallskip
\noindent Examples:
\begin{code}
    # Resize the image to 640x480, using the default filter
    Src = ImageBuf ("tahoe.exr")
    Dst = ImageBufAlgo.resize (Src, roi=ROI(0,640,0,480,0,1,0,3))
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce resample} (src, interpolate=True, \\
        \bigspc\bigspc roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce resample} (dst, src, interpolate=True, \\
        \bigspc\bigspc roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!resample} \indexapi{resample}
Set {\cf dst}, over the ROI, to be a low-quality (but fast) resized version
of the corresponding portion of {\cf src}, either using a simple ``closest
pixel'' choice or by bilinaerly interpolating (depending on {\cf
interpolate}).

\smallskip
\noindent Examples:
\begin{code}
    # Resample quickly to 320x240 to make a low-quality thumbnail
    Src = ImageBuf ("tahoe.exr")
    Dst = ImageBufAlgo.resample (Src, roi=ROI(0,640,0,480,0,1,0,3))
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce fit} (src, filtername="", filtersize=0.0, \\
        \bigspc\bigspc  exact=false, roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce fit} (dst, src, filtername="", filtersize=0.0, \\
        \bigspc\bigspc  exact=false, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!fit} \indexapi{fit}
Fit {\cf src} into the {\cf roi} while preserving the
original aspect ratio, without stretching.  If the filter and size are not
specified, an appropriate default will be chosen.

\smallskip
\noindent Examples:
\begin{code}
    # Resize to fit into a max of 640x480, preserving the aspect ratio
    Src = ImageBuf ("tahoe.exr")
    Dst = ImageBufAlgo.fit (Src, roi=ROI(0,640,0,480,0,1,0,3))
\end{code}
\apiend



\subsection{Image arithmetic}
\label{sec:iba:py:arith}

\apiitem{ImageBuf ImageBufAlgo.{\ce add} (A, B, roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce add} (dst, A, B, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!add} \indexapi{add}

Compute {\cf A + B}.  {\cf A} and {\cf B} each may
be an \ImageBuf, a {\cf float} value (for all channels) or a tuple giving a
{\cf float} for each color channel.

\smallskip
\noindent Examples:
\begin{code}
    # Add two images
    buf = ImageBufAlgo.add (ImageBuf("a.exr"), ImageBuf("b.exr"))

    # Add 0.2 to channels 0-2 
    ImageBufAlgo.add (buf, buf, (0.2,0.2,0.2,0))
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce sub} (A, B, roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce sub} (dst, A, B, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!sub} \indexapi{sub}

Compute {\cf A - B}.  {\cf A} and {\cf B} each may
be an \ImageBuf, a {\cf float} value (for all channels) or a tuple giving a
{\cf float} for each color channel.

\smallskip
\noindent Examples:
\begin{code}
    buf = ImageBufAlgo.sub (ImageBuf("a.exr"), ImageBuf("b.exr"))
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce absdiff} (A, B, roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce absdiff} (dst, A, B, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!absdiff} \indexapi{absdiff}

Compute {\cf abs(A - B)}.  {\cf A} and {\cf B} each may
be an \ImageBuf, a {\cf float} value (for all channels) or a tuple giving a
{\cf float} for each color channel.

\smallskip
\noindent Examples:
\begin{code}
    buf = ImageBufAlgo.absdiff (ImageBuf("a.exr"), ImageBuf("b.exr"))
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce abs} (A, roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce abs} (dst, A, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!abs} \indexapi{abs}

Compute {\cf abs(A)}.  {\cf A} is an \ImageBuf.

\smallskip
\noindent Examples:
\begin{code}
    buf = ImageBufAlgo.abs (ImageBuf("a.exr"))
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce mul} (A, B, roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce mul} (dst, A, B, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!mul} \indexapi{mul}

Compute {\cf A * B} (channel-by-channel multiplication). {\cf A} and {\cf B}
each may be an \ImageBuf, a {\cf float} value (for all channels) or a tuple
giving a {\cf float} for each color channel.

\smallskip
\noindent Examples:
\begin{code}
    # Multiply the two images
    buf = ImageBufAlgo.mul (ImageBuf("a.exr"), ImageBuf("b.exr"))

    # Reduce intensity of buf's channels 0-2 by 50%, in place
    ImageBufAlgo.mul (buf, buf, (0.5, 0.5, 0.5, 1.0))
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce div} (A, B, roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce div} (dst, A, B, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!div} \indexapi{div}

Compute {\cf A / B} (channel-by-channel division), where $x/0$
is defined to be $0$.  {\cf A} and {\cf B} each may
be an \ImageBuf, a {\cf float} value (for all channels) or a tuple giving a
{\cf float} for each color channel.

\smallskip
\noindent Examples:
\begin{code}
    # Divide a.exr by b.exr
    buf = ImageBufAlgo.div (ImageBuf("a.exr"), ImageBuf("b.exr"))

    # Reduce intensity of buf's channels 0-2 by 50%, in place
    ImageBufAlgo.div (buf, buf, (2.0, 2.0, 2.0, 1.0))
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce mad} (A, B, C, roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce mad} (dst, A, B, C, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!mad} \indexapi{mad}

Compute {\cf A * B + C} (channel-by-channel multiplication
and addition).  {\cf A}, {\cf B}, and {\cf C} each may
be an \ImageBuf, a {\cf float} value (for all channels) or a tuple giving a
{\cf float} for each color channel.

\smallskip
\noindent Examples:
\begin{code}
    # Multiply a and b, then add c
    buf = ImageBufAlgo.mad (ImageBuf("a.exr"),
                            (1.0f, 0.5f, 0.25f), ImageBuf("c.exr"))
\end{code}
\apiend



\apiitem{ImageBuf ImageBufAlgo.{\ce invert} (A, roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce invert} (dst, A, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!invert} \indexapi{invert}

Compute {\cf 1-A} (channel by channel color inverse).
{\cf A} is an \ImageBuf.

\smallskip
\noindent Examples:
\begin{code}
    buf = ImageBufAlgo.invert (ImageBuf("a.exr"))
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce pow} (A, B, roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce pow} (dst, A, B, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!pow} \indexapi{pow}

Compute {\cf pow (A, B} (channel-by-channel exponentiation).
{\cf A} is an \ImageBuf, and {\cf B} may be a {\cf float} (a single power
for all channels) or a tuple giving a {\cf float} for each color channel.

\smallskip
\noindent Examples:
\begin{code}
    # Linearize a 2.2 gamma-corrected image (channels 0-2 only)
    img = ImageBuf ("a.exr")
    buf = ImageBufAlgo.pow (img, (2.2, 2.2, 2.2, 1.0))
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce channel_sum} (src, weights=(), roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce channel_sum} (dst, src, weights=(), roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!channel_sum} \indexapi{channel_sum}
Converts a multi-channel image into a 1-channel image via a weighted sum
of channels. The {\cf weights} is a tuple providing the weight for each 
channel (if not supplied, all channels will have weight 1.0).

\smallskip
\noindent Examples:
\begin{code}
    # Compute luminance via a weighted sum of R,G,B
    # (assuming Rec709 primaries and a linear scale)
    ImageBuf()
    weights = (.2126, .7152, .0722)
    luma = ImageBufAlgo.channel_sum (ImageBuf("a.exr"), weights)
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce contrast_remap} (src, \\
        \bigspc\spc black=0.0, white=1.0, min=0.0, max=1.0, \\
        \bigspc\spc sthresh=0.0, scontrast=1.0, \\
        \bigspc\spc ROI roi=\{\}, int nthreads=0) \\
bool ImageBufAlgo.{\ce contrast_remap} (ImageBuf \&dst, src,\\
        \bigspc\spc black=0.0, white=1.0, min=0.0, max=1.0, \\
        \bigspc\spc sthresh=0.0, scontrast=1.0, \\
        \bigspc\spc ROI roi=\{\}, int nthreads=0)}
\index{ImageBufAlgo!contrast_remap} \indexapi{contrast_remap}

Return (or copy into {\cf dst}) pixel values that are a contrast-remap
of the corresponding values of the {\cf src} image, transforming pixel
value domain [black, white] to range [min, max], either linearly or with
optional application of a smooth sigmoidal remapping (if scontrast != 1.0).

\smallskip
\noindent Examples:
\begin{code}
    A = ImageBuf('tahoe.tif');

    # Simple linear remap that stretches input 0.1 to black, and input
    # 0.75 to white.
    linstretch = ImageBufAlgo.contrast_remap (A, black=0.1, white=0.75)

    // Remapping 0->1 and 1->0 inverts the colors of the image,
    // equivalent to ImageBufAlgo.invert().
    inverse = ImageBufAlgo.contrast_remap (A, black=1.0, white=0.0)

    // Use a sigmoid curve to add contrast but without any hard cutoffs.
    // Use a contrast parameter of 5.0.
    sigmoid = ImageBufAlgo.contrast_remap (a, contrast=5.0)
\end{code}
\apiend

\apiitem{ImageBuf ImageBufAlgo.{\ce color_map} (src, srcchannel, \\
\bigspc\bigspc        nknots, channels, knots, roi=ROI.All, nthreads=0) \\
ImageBuf ImageBufAlgo.{\ce color_map} (src, srcchannel, \\
\bigspc\bigspc        mapname, roi=ROI.All, nthreads=0) \\[1.0ex]
bool ImageBufAlgo.{\ce color_map} (dst, src, srcchannel, \\
\bigspc\bigspc        nknots, channels, knots, roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce color_map} (dst, src, srcchannel, \\
\bigspc\bigspc        mapname, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!color_map} \indexapi{color_map}
Return an image (or copy into {\cf dst}) pixel values determined by applying
the color map to the values of {\cf src}, using either the channel specified
by {\cf srcchannel}, or the luminance of {\cf src}'s RGB if {\cf srcchannel}
is -1.

In the first variant, the values linearly-interpolated color map are
given by the tuple {\cf knots[nknots*channels]}.

In the second variant, just the name of a color map is specified. Recognized
map names include: \qkw{inferno}, \qkw{viridis},\qkw{magma}, \qkw{plasma},
all of which are perceptually uniform, strictly increasing in luminance,
look good when converted to grayscale, and work for people with all types of
colorblindness. Also supported are the following color maps that do not have
those desirable qualities (and are this not recommended): \qkw{blue-red},
\qkw{spectrum}, and \qkw{heat}. In all cases, the implied {\cf channels} is
3.

\smallskip
\noindent Examples:
\begin{code}
    heatmap = ImageBufAlgo.color_map (ImageBuf("a.jpg"), -1, "inferno")

    heatmap = ImageBufAlgo.color_map (ImageBuf("a.jpg"), -1, 3, 3,
                            (0.25, 0.25, 0.25,  0, 0.5, 0,  1, 0, 0))
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce clamp} (src, min, max,
  bool clampalpha01=False, \\ \bigspc\bigspc roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce clamp} (dst, src, min, max,
  bool clampalpha01=False, \\ \bigspc\bigspc roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!clamp} \indexapi{clamp}

Copy pixels while clamping
between the {\cf min} and {\cf max} values.  The {\cf min} and {\cf max}
may either be tuples (one min and max value per channel), or single
{\cf floats} (same value for all channels).  Additionally, if
{\cf clampalpha01} is {\cf True}, then any alpha 
channel is clamped to the 0--1 range.

\smallskip
\noindent Examples:
\begin{code}
    # Clamp image buffer A in-place to the [0,1] range for all channels.
    ImageBufAlgo.clamp (A, A, 0.0, 1.0)
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce rangecompress} (src, useluma=False, \\
   \bigspc\bigspc     roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce rangecompress} (dst, src, useluma=False, \\
   \bigspc\bigspc     roi=ROI.All, nthreads=0) \\[1.0ex]
ImageBuf ImageBufAlgo.{\ce rangeexpand} (src, useluma=False, \\
    \bigspc\bigspc    roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce rangeexpand} (dst, src, useluma=False, \\
    \bigspc\bigspc    roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!rangecompress} \indexapi{rangecompress}
\index{ImageBufAlgo!rangeexpand} \indexapi{rangeexpand}

Copy from {\cf src}, compressing (logarithmically) or expanding
(by the inverse of the compressive transformation) the range of pixel
values.  Alpha and z channels are copied but not transformed.

If {\cf useluma} is {\cf True}, the luma of the first three channels (presumed
to be R, G, and B) are used to compute a single scale factor for all
color channels, rather than scaling all channels individually (which
could result in a big color shift when performing {\cf rangecompress}
and {\cf rangeexpand}).

\smallskip
\noindent Examples:
\begin{code}
    # Resize the image to 640x480, using a Lanczos3 filter, which
    # has negative lobes. To prevent those negative lobes from
    # producing ringing or negative pixel values for HDR data,
    # do range compression, then resize, then re-expand the range.

    # 1. Read the original image
    Src = ImageBuf ("tahoeHDR.exr")

    # 2. Range compress to a logarithmic scale
    Compressed = ImageBufAlgo.rangecompress (Src)

    # 3. Now do the resize
    roi = ROI (0, 640, 0, 480, 0, 1, 0, Compressed.nchannels)
    Dst = ImageBufAlgo.resize (Compressed, "lanczos3", 6.0, roi)

    # 4. Expand range to be linear again (operate in-place)
    ImageBufAlgo.rangeexpand (Dst, Dst)
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce over} (A, B, roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce over} (dst, A, B, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!over} \indexapi{over}

Composite \ImageBuf\ {\cf A} \emph{over} \ImageBuf\ {\cf B}.

\smallskip
\noindent Examples:
\begin{code}
    Comp = ImageBufAlgo.over (ImageBuf("fg.exr"), ImageBuf("bg.exr"))
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce zover} (A, B, bool z_zeroisinf=False,\\
        \bigspc\bigspc roi=ROI.All, nthreads=0\\
bool ImageBufAlgo.{\ce zover} (dst, A, B, bool z_zeroisinf=False,\\
        \bigspc\bigspc roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!zover} \indexapi{zover}

Composite \ImageBuf\ {\cf A} and \ImageBuf\ {\cf B} using their respective
$Z$ channels to decide which is in front on a pixel-by-pixel basis.

\smallskip
\noindent Examples:
\begin{code}
    Comp = ImageBufAlgo.zover (ImageBuf("fg.exr"), ImageBuf("bg.exr"))
\end{code}
\apiend



\subsection{Image comparison and statistics}
\label{sec:iba:py:stats}


\apiitem{PixelStats ImageBufAlgo.{\ce computePixelStats} (src, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!computePixelStats} \indexapi{computePixelStats}

Compute statistics about the ROI of the image {\cf src}.
The {\cf PixelStats} structure is defined as contining the following
data fields: {\cf min}, {\cf max}, {\cf avg}, {\cf stddev},
{\cf nancount}, {\cf infcount}, {\cf finitecount}, {\cf sum}, {\cf sum2},
each of which is a \emph{tuple} with one value for each channel of the image.

\smallskip
\noindent Examples:
\begin{code}
    A = ImageBuf("a.exr")
    stats = ImageBufAlgo.computePixelStats (A)
    print "   min = ", stats.min
    print "   max = ", stats.max
    print "   average = ", stats.avg
    print "   standard deviation  = ", stats.stddev
    print "   # NaN values    = ", stats.nancount
    print "   # Inf values    = ", stats.infcount
    print "   # finite values = ", stats.finitecount
\end{code}
\apiend


\apiitem{CompareResults ImageBufAlgo.{\ce compare} (A, B, failthresh, warnthresh, 
   \\ \bigspc\bigspc roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!compare} \indexapi{compare}

Numerically compare two \ImageBuf's, {\cf A} and {\cf B}. The {\cf failthresh}
and {\cf warnthresh} supply failure and warning difference thresholds.
The return value is a {\cf CompareResults} object,
which is defined as a class having the following members:
\begin{code}
    meanerror, rms_error, PSNR, maxerror  # error statistics
    maxx, maxy, maxz, maxc                # pixel of biggest difference
    nwarn, nfail                          # number of warnings and failures
    error                                 # True if there was an error
\end{code}

\smallskip
\noindent Examples:
\begin{code}
    A = ImageBuf ("a.exr")
    B = ImageBuf ("b.exr")
    comp = ImageBufAlgo.compare (A, B, 1.0/255.0, 0.0)
    if comp.nwarn == 0 and comp.nfail == 0 :
        print "Images match within tolerance"
    else :
        print comp.nfail, "failures,", comp.nwarn, " warnings."
        print "Average error was " , comp.meanerror
        print "RMS error was" , comp.rms_error
        print "PSNR was" , comp.PSNR
        print "largest error was ", comp.maxerror
        print "  on pixel", (comp.maxx, comp.maxy, comp.maxz)
        print "  channel", comp.maxc
\end{code}
\apiend


\apiitem{tuple ImageBufAlgo.{\ce isConstantColor} (src, threshold=0.0, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!isConstantColor} \indexapi{isConstantColor}

If all pixels of {\cf src} within the ROI have the same values (for the
subset of channels described by {\cf roi}), return a tuple giving that
color (one {\cf float} for each channel), otherwise return {\cf None}.

\smallskip
\noindent Examples:
\begin{code}
    A = ImageBuf ("a.exr")
    color = ImageBufAlgo.isConstantColor (A)
    if color != None :
        print "The image has the same value in all pixels:", color
    else :
        print "The image is not a solid color."
\end{code}
\apiend


\apiitem{bool ImageBufAlgo.{\ce isConstantChannel} (src, channel, val, \\
 \bigspc\bigspc         threshold=0.0, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!isConstantChannel} \indexapi{isConstantChannel}

Returns {\cf True} if all pixels of {\cf src} within the ROI have the
given {\cf channel} value {\cf val}.

\smallskip
\noindent Examples:
\begin{code}
    A = ImageBuf ("a.exr")
    alpha = A.spec.alpha_channel
    if alpha < 0 :
        print "The image does not have an alpha channel"
    elif ImageBufAlgo.isConstantChannel (A, alpha, 1.0) :
        print "The image has alpha = 1.0 everywhere"
    else :
        print "The image has alpha < 1 in at least one pixel"
\end{code}
\apiend


\apiitem{bool ImageBufAlgo.{\ce isMonochrome} (src, threshold=0.0,
          roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!isMonochrome} \indexapi{isMonochrome}

Returns {\cf True} if the image is monochrome within the ROI.

\smallskip
\noindent Examples:
\begin{code}
    A = ImageBuf ("a.exr")
    roi = A.roi
    roi.chend = min (3, roi.chend)  # only test RGB, not alpha
    if ImageBufAlgo.isMonochrome (A, roi) :
        print "a.exr is really grayscale"
\end{code}
\apiend


\begin{comment}
\apiitem{bool ImageBufAlgo.{\ce color_count} (src, imagesize_t *count,\\
        \bigspc  int ncolors, const float *color, const float *eps=NULL,  \\
        \bigspc  roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!color_count} \indexapi{color_count}

Count how many pixels in the image (within the ROI) match a list of colors.
The colors to match are in:

\begin{code}
  colors[0 ... nchans-1]
  colors[nchans ... 2*nchans-1]
  ...
  colors[(ncolors-1)*nchans ... (ncolors*nchans)-1]
\end{code}

\noindent and so on, a total of {\cf ncolors} consecutively stored
colors of {\cf nchans} channels each ({\cf nchans} is the number of
channels in the image, itself, it is not passed as a parameter).


The values in {\cf eps[0..nchans-1]} are the error tolerances for a
match, for each channel.  Setting {\cf eps[c]} to 
{\cf numeric_limits<float>::max()} will effectively make it ignore the
channel.  Passing {\cf eps == NULL} will be interpreted as a tolerance
of 0.001 for all channels (requires exact matches for 8 bit images, but
allows a wee bit of imprecision for {\cf float} images.

\smallskip
\noindent Examples:
\begin{code}
    A = ImageBuf ("a.exr")
    n = A.nchannels

    # Try to match two colors: pure red and green
    std::vector<float> colors (2*n, numeric_limits<float>::max());
    colors[0] = 1.0; colors[1] = 0.0; colors[2] = 0.0;
    colors[n+0] = 0.0; colors[n+1] = 1.0; colors[n+2] = 0.0;

    const int ncolors = 2;
    imagesize_t count[ncolors];
    ImageBufAlgo.color_count (A, count, ncolors);
    print "Number of red pixels   : ", count[0]
    print "Number of green pixels : ", count[1]
\end{code}
\apiend


\apiitem{bool {\ce color_range_check} (src, 
   imagesize_t *lowcount, \\ \bigspc imagesize_t *highcount, imagesize_t
  *inrangecount, \\
  \bigspc const float *low, const float *high, \\
        \bigspc  roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!color_range_check} \indexapi{color_range_check}

Count how many pixels in the image (within the ROI) are outside the
value range described by {\cf low[roi.chbegin..roi.chend-1]} and
{\cf high[roi.chbegin..roi.chend-1]} 
as the low and high acceptable values for each color channel.  

The number of pixels containing values that fall below the lower bound
will be stored in {\cf *lowcount}, the number of pixels containing
values that fall above the upper bound will be stored in 
{\cf *highcount}, and the number of pixels for which all channels fell
within the bounds will be stored in {\cf *inrangecount}.  Any of these
may be NULL, which simply means that the counts need not be collected or
stored.

\smallskip
\noindent Examples:
\begin{code}
    A = ImageBuf ("a.exr")
    ROI roi = get_roi (A.spec())
    roi.chend = std::min (roi.chend, 4);  # only compare RGBA

    float low[] = {0, 0, 0, 0};
    float high[] = {1, 1, 1, 1};

    imagesize_t lowcount, highcount, inrangecount;
    ImageBufAlgo.color_range_check (A, &lowcount, &highcount, &inrangecount,
                                     low, high, roi);
    print lowcount, " pixels had components < 0"
    print highcount, " pixels had components > 1"
    print inrangecount, " pixels were fully within [0,1] range"
\end{code}
\apiend
\end{comment}


\apiitem{std::string ImageBufAlgo.{\ce computePixelHashSHA1} (src, 
  extrainfo = "", \\
  \bigspc\bigspc  roi=ROI.All, blocksize=0, nthreads=0)}
\index{ImageBufAlgo!computePixelHashSHA1} \indexapi{computePixelHashSHA1}

Compute the SHA-1 byte hash for all the pixels in the ROI of {\cf src}.

\smallskip
\noindent Examples:
\begin{code}
    A = ImageBuf ("a.exr")
    hash = ImageBufAlgo.computePixelHashSHA1 (A, blocksize=64)
\end{code}
\apiend


\apiitem{tuple {\ce histogram} (src, channel=0, bins=256, min=0.0, max=1.0, \\
\bigspc ignore_empty=False, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!histogram} \indexapi{histogram}
\apiend

Computes a histogram of the given {\cf channel} of image {\cf src}, within
the ROI, returning a tuple of length {\cf bins} containing count of pixels
whose value was in each of the equally-sized range bins between {\cf min}
and {\cf max}. If {\cf ignore_empty} is {\cf True}, pixels that are empty
(all channels 0 including alpha) will not be counted in the total.



\subsection{Convolutions}
\label{sec:iba:py:convolutions}

\apiitem{ImageBuf ImageBufAlgo.{\ce make_kernel} (name, width, height, \\
  \bigspc\bigspc depth=1.0, normalize=True)}
\index{ImageBufAlgo!make_kernel} \indexapi{make_kernel}
Create a 1-channel {\cf float} image of the named kernel
and dimensions.  If {\cf normalize} is {\cf True}, the values will be
normalized so that they sum to $1.0$.

If {\cf depth} $> 1$, a volumetric kernel will be created.  Use with
caution!

Kernel names can be: \qkw{gaussian}, \qkw{sharp-gaussian}, \qkw{box},
\qkw{triangle}, \qkw{mitchell}, \qkw{blackman-harris}, \qkw{b-spline},
\qkw{catmull-rom}, \qkw{lanczos3}, \qkw{cubic}, \qkw{keys}, \qkw{simon},
\qkw{rifman}, \qkw{disk}, \qkw{binomial}, \qkw{laplacian}. Note that
\qkw{catmull-rom} and \qkw{lanczos3} are fixed-size kernels that don't
scale with the width, and are therefore probably less useful in most
cases.

\smallskip
\noindent Examples:
\begin{code}
    K = ImageBufAlgo.make_kernel ("gaussian", 5.0, 5.0)
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce convolve} (src, kernel, normalize=True, \\
  \bigspc\bigspc  roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce convolve} (dst, src, kernel, normalize=True, \\
  \bigspc\bigspc  roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!convolve} \indexapi{convolve}
Replace the given ROI of {\cf dst} with the convolution of {\cf src} and
a kernel (also an \ImageBuf).

\smallskip
\noindent Examples:
\begin{code}
    # Blur an image with a 5x5 Gaussian kernel
    Src = ImageBuf ("tahoe.exr")
    K = ImageBufAlgo.make_kernel (K, "gaussian", 5.0, 5.0)
    Blurred = ImageBufAlgo.convolve (Src, K)
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce laplacian} (src, roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce laplacian} (dst, src, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!laplacian} \indexapi{laplacian}
Replace the given ROI of {\cf dst} with the Laplacian of the corresponding
part of {\cf src}.

\smallskip
\noindent Examples:
\begin{code}
    Src = ImageBuf ("tahoe.exr")
    L = ImageBufAlgo.laplacian (Src)
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce fft} (src, roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce fft} (dst, src, roi=ROI.All, nthreads=0) \\[1.0ex]
ImageBuf ImageBufAlgo.{\ce ifft} (src, roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce ifft} (dst, src, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!fft} \indexapi{fft}
\index{ImageBufAlgo!ifft} \indexapi{ifft}

Compute the forward or inverse discrete Fourier Transform.

\smallskip
\noindent Examples:
\begin{code}
    Src = ImageBuf ("tahoe.exr")

    # Take the DFT of the first channel of Src
    Freq = ImageBufAlgo.fft (Src)

    # At this point, Freq is a 2-channel float image (real, imag)
    # Convert it back from frequency domain to a spatial iamge
    Spatial = ImageBufAlgo.ifft (Freq)
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce complex_to_polar} (src, roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce complex_to_polar} (dst, src, roi=ROI.All, nthreads=0) \\[1.0ex]
ImageBuf ImageBufAlgo.{\ce polar_to_complex} (src, roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce polar_to_complex} (dst, src, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!polar_to_complex} \indexapi{polar_to_complex}
\index{ImageBufAlgo!complex_to_polar} \indexapi{complex_to_polar}

Transform a 2-channel image from complex (real, imaginary) representation
to polar (amplitude, phase), or vice versa.

\smallskip
\noindent Examples:
\begin{code}
    Polar = ImageBuf ("polar.exr")

    Complex = ImageBufAlgo.polar_to_complex (Polar)

    # At this point, Complex is a 2-channel complex image (real, imag)
    # Convert it back from frequency domain to a spatial iamge
    Spatial = ImageBufAlgo.ifft (Complex)
\end{code}
\apiend



\subsection{Image Enhancement / Restoration}
\label{sec:iba:py:enhance}

\apiitem{ImageBuf ImageBufAlgo.{\ce fixNonFinite} (src,
  mode=NONFINITE_BOX3, \\ \bigspc\bigspc\spc roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce fixNonFinite} (dst, src,
  mode=NONFINITE_BOX3, \\ \bigspc\bigspc\spc roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!fixNonFinite} \indexapi{fixNonFinite}

Copy pixel values from {\cf src} and repair any non-finite ({\cf NaN} or {\cf
Inf}) pixels.

How the non-finite values are repaired is specified by one of the
following modes: \\
{\cf OpenImageIO.NONFINITE_NONE}, \\
{\cf OpenImageIO.NONFINITE_BLACK} \\ 
{\cf OpenImageIO.NONFINITE_BOX3}

\smallskip
\noindent Examples:
\begin{code}
    Src = ImageBuf ("tahoe.exr")
    ImageBufAlgo.fixNonFinite (Src, Src, OpenImageIO.NONFINITE_BOX3)
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce fillholes_pushpull} (src, roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce fillholes_pushpull} (dst, src, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!fillholes_pushpull} \indexapi{fillholes_pushpull}

Copy the specified ROI of {\cf src} and fill any 
holes (pixels where alpha $< 1$) with plausible values using a push-pull
technique.  The {\cf src} image must have
an alpha channel.  The {\cf dst} image will end up with a copy of src, but
will have an alpha of 1.0 everywhere, and any place where the alpha
of src was < 1, dst will have a pixel color that is a plausible
``filling'' of the original alpha hole.

\smallskip
\noindent Examples:
\begin{code}
    Src = ImageBuf ("holes.exr")
    Filled = ImageBufAlgo.fillholes_pushpull (Src)
\end{code}
\apiend


\apiitem{bool ImageBufAlgo.{\ce median_filter} (dst, src, width=3, height=-1, \\
  \bigspc\spc  roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!median_filter} \indexapi{median_filter}


Replace the given ROI of {\cf dst} with the
${\mathit width} \times {\mathit height}$ median filter of the corresponding
region of {\cf src} using the ``unsharp mask'' technique.

\smallskip
\noindent Examples:
\begin{code}
    Noisy = ImageBuf ("tahoe.exr")
    Clean = ImageBuf ()
    ImageBufAlgo.median_filter (Clean, Noisy, 3, 3)
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce dilate} (src, width=3, height=-1, roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce dilate} (dst, src, width=3, height=-1, roi=ROI.All, nthreads=0) \\[1.0ex]
ImageBuf ImageBufAlgo.{\ce erode} (src, width=3, height=-1, roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce erode} (dst, src, width=3, height=-1, roi=ROI.All, nthreads=0) }
\index{ImageBufAlgo!dilate} \indexapi{dilate}
\index{ImageBufAlgo!erode} \indexapi{erode}

Compute a dilated or eroded version of the corresponding region of {\cf src}.

\smallskip
\noindent Examples:
\begin{code}
    Source = ImageBuf ("source.tif")
    Dilated = ImageBufAlgo.dilate (Source, 3, 3)
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce unsharp_mask} (src, kernel="gaussian", width=3.0, \\
  \bigspc\spc contrast=1.0, threshold=0.0, roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce unsharp_mask} (dst, src, kernel="gaussian", width=3.0, \\
  \bigspc\spc contrast=1.0, threshold=0.0, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!unsharp_mask} \indexapi{unsharp_mask}

Compute a sharpened version of the corresponding region of {\cf src} using
the ``unsharp mask'' technique.

\smallskip
\noindent Examples:
\begin{code}
    Blurry = ImageBuf ("tahoe.exr")
    Sharp = ImageBufAlgo.unsharp_mask (Blurry, "gaussian", 5.0)
\end{code}
\apiend



\subsection{Color manipulation}
\label{sec:iba:py:color}

\apiitem{ImageBuf ImageBufAlgo.{\ce colorconvert} (src, fromspace, tospace, unpremult=True, \\
  \bigspc\bigspc context_key="", context_value="", \\
  \bigspc\bigspc  colorconfig="", roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce colorconvert} (dst, src, fromspace, tospace, unpremult=True, \\
  \bigspc\bigspc context_key="", context_value="", \\
  \bigspc\bigspc  colorconfig="", roi=ROI.All, nthreads=0)
}
\index{ImageBufAlgo!colorconvert} \indexapi{colorconvert}
Apply a color transform to the pixel values.

\smallskip
\noindent Examples:
\begin{code}
    Src = ImageBuf ("tahoe.jpg")
    Dst = ImageBufAlgo.colorconvert (Src, "sRGB", "linear")
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce colormatrixtransform} (src, M, unpremult=True, \\
  \bigspc\bigspc  roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce colormatrixtransform} (dst, src, M, unpremult=True, \\
  \bigspc\bigspc  roi=ROI.All, nthreads=0)
}
\index{ImageBufAlgo!colormatrixtransform} \indexapi{colormatrixtransform}
\NEW % 2.1
Apply a $4 \times 4$ matrix color transform to the pixel values. The matrix
can be any tuple of 16 float values.

\smallskip
\noindent Examples:
\begin{code}
    Src = ImageBuf ("tahoe.jpg")
    M = ( .8047379,  .5058794, -.3106172, 0,
         -.3106172,  .8047379,  .5058794, 0,
          .5058794, -.3106172,  .8047379, 0,
          0,         0,         0,       1)
    Dst = ImageBufAlgo.colormatrixtransform (Src, M)
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce ociolook} (src, looks, fromspace, tospace,  \\
  \bigspc\bigspc  inverse=False, unpremult=True, \\
  \bigspc\bigspc context_key="", context_value="", colorconfig="", \\
  \bigspc\bigspc roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce ociolook} (dst, src, looks, fromspace, tospace,  \\
  \bigspc\bigspc  inverse=False, unpremult=True, \\
  \bigspc\bigspc context_key="", context_value="", colorconfig="", \\
  \bigspc\bigspc roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!ociolook} \indexapi{ociolook}
Apply an OpenColorIO ``look'' transform to the pixel values.

\smallskip
\noindent Examples:
\begin{code}
    Src = ImageBuf ("tahoe.jpg")
    Dst = ImageBufAlgo.ociolook (Src, "look", "vd8", "lnf",
                            context_key="SHOT", context_value="pe0012")
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce ociodisplay} (src, display, view, \\
  \bigspc\bigspc fromspace="", looks="", unpremult=True, \\
  \bigspc\bigspc context_key="", context_value="", colorconfig="", \\
  \bigspc\bigspc roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce ociodisplay} (dst, src, display, view, \\
  \bigspc\bigspc fromspace="", looks="", unpremult=True, \\
  \bigspc\bigspc context_key="", context_value="", colorconfig="", \\
  \bigspc\bigspc roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!ociodisplay} \indexapi{ociodisplay}
Apply an OpenColorIO ``display'' transform to the pixel values.

\smallskip
\noindent Examples:
\begin{code}
    Src = ImageBuf ("tahoe.exr")
    Dst = ImageBufAlgo.ociodisplay (Src, "sRGB", "Film", "lnf",
                              context_key="SHOT", context_value="pe0012")
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce ociofiletransform} (src, name, \\
  \bigspc\bigspc unpremult=True, invert=False, colorconfig="", \\
  \bigspc\bigspc roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce ociofiletransform} (dst, src, name, \\
  \bigspc\bigspc unpremult=True, invert=False, colorconfig="", \\
  \bigspc\bigspc roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!ociofiletransform} \indexapi{ociofiletransform}
Apply an OpenColorIO ``file'' transform to the pixel values.
In-place operations ({\cf dst} and {\cf src} being the same image)
are supported.

\smallskip
\noindent Examples:
\begin{code}
    Src = ImageBuf ("tahoe.exr")
    Dst = ImageBufAlgo.ociofiletransform (Src, "foottransform.csp")
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce unpremult} (src, roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce unpremult} (dst, src, roi=ROI.All, nthreads=0) \\[1.0ex]
ImageBuf ImageBufAlgo.{\ce premult} (src, roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce premult} (dst, src, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!unpremult} \indexapi{unpremult}
\index{ImageBufAlgo!premult} \indexapi{premult}
Copy pixels from {\cf src} to {\cf dst}, and un-premultiply (or
premultiply) the colors by alpha.

\smallskip
\noindent Examples:
\begin{code}
    # Convert in-place from associated alpha to unassociated alpha
    A = ImageBuf ("a.exr")
    ImageBufAlgo.unpremult (A, A)
\end{code}
\apiend



\subsection{Import / export}
\label{sec:iba:py:importexport}

\apiitem{bool ImageBufAlgo.{\ce make_texture} (mode, input,\\
\bigspc\bigspc outputfilename, config=ImageSpec())}
\index{ImageBufAlgo!make_texture} \indexapi{make_texture}

Turn an input image (either an \ImageBuf or a string giving a filename)
into a tiled, MIP-mapped, texture file and write to the
file named by ({\cf outputfilename}).  The {\cf mode} describes what type of texture file we
are creating and may be one of the following:

\noindent \begin{tabular}{p{4in}}
{\cf OpenImageIO.MakeTxTexture} \\
{\cf OpenImageIO.MakeTxEnvLatl} \\
{\cf OpenImageIO.MakeTxEnvLatlFromLightProbe} \\
\end{tabular}

The {\cf config}, if supplied, is an \ImageSpec that contains all the
information and special instructions for making the texture. The full list
of supported configuration options is given in
Section~\ref{sec:iba:importexport}.

\smallskip
\noindent Examples:
\begin{code}
    # This command line:
    #    maketx in.exr --hicomp --filter lanczos3 --opaque-detect \
    #             -o texture.exr
    # is equivalent to:

    Input = ImageBuf ("in.exr")
    config = ImageSpec()
    config.attribute ("maketx:highlightcomp", 1)
    config.attribute ("maketx:filtername", "lanczos3")
    config.attribute ("maketx:opaquedetect", 1)
    ImageBufAlgo.make_texture (oiio.MakeTxTexture, Input,
                               "texture.exr", config)
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo::{\ce capture_image} (cameranum, convert = OpenImageIO.UNKNOWN)}
\index{ImageBufAlgo!capture_image} \indexapi{capture_image}
Capture a still image from a designated camera. 

\smallskip
\noindent Examples:
\begin{code}
    WebcamImage = ImageBufAlgo.capture_image (0, OpenImageIO.UINT8)
    WebcamImage.write ("webcam.jpg")
\end{code}
\apiend


\subsection{Functions specific to deep images}

\apiitem{ImageBuf ImageBufAlgo.{\ce deepen} (src, zvalue=1.0, roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce deepen} (dst, src, zvalue=1.0, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!deepen} \indexapi{deepen} \index{deep images}

Convert a flat image to a deep one that has one depth sample per pixel
(but no depth samples for the pixels corresponding to those in the source
image that have infinite \qkw{Z} or that had 0 for all color channels and no
\qkw{Z} channel).

\smallskip
\noindent Examples:
\begin{code}
    Deep = ImageBufAlgo.deepen (ImageBuf("az.exr"))
\end{code}
\apiend


\apiitem{ImageBuf ImageBufAlgo.{\ce flatten} (src, roi=ROI.All, nthreads=0)\\
bool ImageBufAlgo.{\ce flatten} (dst, src, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!flatten} \indexapi{flatten} \index{deep images}

Composite the depth samples within each pixel of ``deep'' \ImageBuf\ {\cf
src} to produce a ``flat'' \ImageBuf.

\smallskip
\noindent Examples:
\begin{code}
    Flat = ImageBufAlgo.flatten (ImageBuf("deepalpha.exr"))
\end{code}
\apiend

\apiitem{ImageBuf ImageBufAlgo.{\ce deep_merge} (A, B, occlusion_cull, roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce deep_merge} (dst, A, B, occlusion_cull, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!deep_merge} \indexapi{deep_merge} \index{deep images}

Merge the samples of two \emph{deep} images {\cf A} and {\cf B} into a deep
result. If {\cf occlusion_cull} is {\cf True}, samples beyond
the first opaque sample will be discarded, otherwise they will be kept.

\smallskip
\noindent Examples:
\begin{code}
    DeepA = ImageBuf("hardsurf.exr")
    DeepB = ImageBuf("volume.exr")
    Merged = ImageBufAlgo.deep_merge (DeepA, DeepB)
\end{code}
\apiend

\apiitem{ImageBuf ImageBufAlgo.{\ce deep_holdout} (src, holdout, roi=ROI.All, nthreads=0) \\
bool ImageBufAlgo.{\ce deep_holdout} (dst, src, holdout, roi=ROI.All, nthreads=0)}
\index{ImageBufAlgo!deep_holdout} \indexapi{deep_holdout} \index{deep images}

Return the pixels of {\cf src}, but only copying the
samples that are closer than the opaque frontier of image {\cf holdout}.
That is, {\cf holdout} will serve as a depth holdout mask, but no samples
from {\cf holdout} will actually be copied to {\cf dst}.

\smallskip
\noindent Examples:
\begin{code}
    Img = ImageBuf("image.exr")
    Mask = ImageBuf("mask.exr")
    Thresholded = ImageBufAlgo.deep_holdout (Img, Mask)
\end{code}
\apiend


\subsection*{Other ImageBufAlgo methods that understand deep images}

In addition to the previously described methods that are specific to
deep images, the following \ImageBufAlgo methods (described in their
respective sections) work with deep inputs:

\medskip

\noindent
{\cf ImageBufAlgo.add} \\
{\cf ImageBufAlgo.channels} \\
{\cf ImageBufAlgo.compare} \\
{\cf ImageBufAlgo.computePixelStats} \\
{\cf ImageBufAlgo.crop} \\
{\cf ImageBufAlgo.div} \\
{\cf ImageBufAlgo.fixNonFinite} \\
{\cf ImageBufAlgo.mul} \\
{\cf ImageBufAlgo.nonzero_region} \\
{\cf ImageBufAlgo.resample} \\
{\cf ImageBufAlgo.sub} \\


\newpage
\section{Miscellaneous Utilities}
\label{sec:pythonmiscapi}

In the main {\cf OpenImageIO} module, there are a number of values and
functions that are useful.  These correspond to the C++ API functions
explained in Section~\ref{sec:miscapi}, please refer there for details.

\apiitem{int {\ce openimageio_version}}
The \product version number, 10000 for each
major version, 100 for each minor version, 1 for each patch.  For
example, \product 1.2.3 would return a value of 10203.
\apiend

\apiitem{str {\ce geterror} ()}
Retrieves the latest global error.
\apiend

\apiitem{bool {\ce attribute} (name, typedesc, value) \\
bool {\ce attribute} (name, int_value) \\
bool {\ce attribute} (name, float_value) \\
bool {\ce attribute} (name, str_value)}
Sets a global attribute (see Section~\ref{sec:miscapi} for details),
returning {\cf True} upon success, or {\cf False} if it was not a
recognized attribute.  

\noindent Example:
\begin{code}
    oiio.attribute ("threads", 0)
\end{code}
\apiend

\apiitem{{\ce getattribute} (name, typedesc) \\
{\ce get_int_attribute} (name, defaultval=0) \\
{\ce get_float_attribute} (name, defaultval=0.0) \\
{\ce get_string_attribute} (name, defaultval="")}
Retrieves an attribute value from the named set of global OIIO options. (See
Section~\ref{sec:globalattribute}.) The {\cf getattribute()} function
returns the value regardless of type, or {\cf None} if the attribute does
not exist.  The typed variety will only succeed if the attribute is actually
of that type specified. Type varity with the type in the name also takes a
default value.

\noindent Example:
\begin{code}
    formats = oiio.get_string_attribute ("format_list")
\end{code}
\apiend



\section{Python Recipes}
\label{sec:pythonrecipes}

This section illustrates the Python syntax for doing many common image
operations from Python scripts, but that aren't already given as examples
in the earlier function descriptions.  All example code fragments assume the
following boilerplate:

\begin{code}
    #!/usr/bin/env python 
    
    import OpenImageIO as oiio
    from OpenImageIO import ImageBuf, ImageSpec, ImageBufAlgo
\end{code}


\subsubsection*{Subroutine to create a constant-colored image}
\begin{code}
    # Create an ImageBuf holding a n image of constant color, given the
    # resolution, data format (defaulting to UINT8), fill value, and image
    # origin.
    def make_constimage (xres, yres, chans=3, format=oiio.UINT8, value=(0,0,0),
                         xoffset=0, yoffset=0) :
        spec = ImageSpec (xres,yres,chans,format)
        spec.x = xoffset
        spec.y = yoffset
        b = ImageBuf (spec)
        oiio.ImageBufAlgo.fill (b, value)
        return b
\end{code}

\noindent The image is returned as an \ImageBuf, then up to the caller 
what to do with it next.

\subsubsection*{Subroutine to save an image to disk, printing errors}
\begin{code}
    # Save an ImageBuf to a given file name, with optional forced image format
    # and error handling.
    def write_image (image, filename, format=oiio.UNKNOWN) :
        if not image.has_error :
            image.write (filename, format)
        if image.has_error :
            print "Error writing", filename, ":", image.geterror()
\end{code}


\subsubsection*{Converting between file formats}

\begin{code}
    img = ImageBuf ("input.png")
    write_image (img, "output.tif")
\end{code}


\subsubsection*{Comparing two images and writing a difference image}

\begin{code}
    A = ImageBuf ("A.tif")
    B = ImageBuf ("B.tif")
    compresults = ImageBufAlgo.compare (A, B, 1.0e-6, 1.0e-6)
    if compresults.nfail > 0 :
        print "Images did not match, writing difference image diff.tif"
        diff = ImageBufAlgo.absdiff (A, B)
        image_write (diff, "diff.tif")
\end{code}


\subsubsection*{Changing the data format or bit depth}

\begin{code}
    img = ImageBuf ("input.exr")
    # presume that it's a "half" OpenEXR file
    # write it back out as a "float" file:
    write_image (img, "output.exr", oiio.FLOAT)
\end{code}


\subsubsection*{Changing the compression}

The following command converts writes a TIFF file, specifically using
LZW compression:

\begin{code}
    img = ImageBuf ("in.tif")
    img.specmod().attribute ("compression", "lzw")
    write_image (img, "compressed.tif")
\end{code}

The following command writes its results as a JPEG file at a 
compression quality of 50 (pretty severe compression):

\begin{code}
    img = ImageBuf ("big.jpg")
    img.specmod().attribute ("quality", 50)
    write_image (img, "small.jpg")
\end{code}


\subsubsection*{Converting between scanline and tiled images}

\begin{code}
    img = ImageBuf ("scan.tif")
    img.set_write_tiles (16, 16)
    write_image (img, "tile.tif")

    img = ImageBuf ("tile.tif")
    img.set_write_tiles (0, 0)
    write_image (img, "scan.tif")
\end{code}


\subsubsection*{Adding captions or metadata}

\begin{code}
    img = ImageBuf ("foo.jpg")
    # Add a caption:
    img.specmod().attribute ("ImageDescription", "Hawaii vacation")
    # Add keywords:
    img.specmod().attribute ("keywords", "volcano,lava")
    write_image (img, "foo.jpg")
\end{code}


\subsubsection*{Changing image boundaries}

\noindent Change the origin of the pixel data window:
\begin{code}
    img = ImageBuf ("in.exr")
    img.set_origin (256, 80)
    write_image (img, "offset.exr")
\end{code}

\noindent Change the display window:
\begin{code}
    img = ImageBuf ("in.exr")
    img.set_full (16, 1040, 16, 784)
    write_image (img, "out.exr")
\end{code}

\noindent Change the display window to match the data window:
\begin{code}
    img = ImageBuf ("in.exr")
    img.set_full (img.roi())
    write_image (img, "out.exr")
\end{code}

\noindent Cut (trim and extract) a 128x128 region whose upper left corner
is at location (900,300), moving the result to the origin (0,0) of the image
plane and setting the display window to the new pixel data window:
\begin{code}
    img = ImageBuf ("in.exr")
    b = ImageBufAlgo.cut (img, oiio.ROI(900,1028,300,428))
    write_image (b, "out.exr")
\end{code}


\subsubsection*{Extract just the named channels from a complicted many-channel
image, and add an alpha channel that is 1 everywhere}
\begin{code}
    img = ImageBuf ("allmyaovs.exr")
    b = ImageBufAlgo.channels (img, ("spec.R", "spec.G", "spec.B", 1.0))
    write_image (b, "spec.tif")
\end{code}


\subsubsection*{Fade 30\% of the way between two images}

\begin{code}
    a = ImageBufAlgo.mul (ImageBuf("A.exr"), 0.7)
    b = ImageBufAlgo.mul (ImageBuf("B.exr"), 0.3)
    fade = ImageBufAlgo.add (a, b)
    write_image (fade, "fade.exr")
\end{code}


\subsubsection*{Composite of small foreground over background, with offset}

\begin{code}
    fg = ImageBuf ("fg.exr")
    fg.set_origin (512, 89)
    bg = ImageBuf ("bg.exr")
    comp = ImageBufAlgo.over (fg, bg)
    write_image (comp, "composite.exr")
\end{code}




\index{Python|)}

\chapwidthend
