ImageBuf: Image Buffers#
ImageBuf Introduction and Theory of Operation#
ImageBuf is a utility class that stores an entire image. It provides a nice API for reading, writing, and manipulating images as a single unit, without needing to worry about any of the details of storage or I/O.
All I/O involving ImageBuf (that is, calls to read
or write
) are
implemented underneath in terms of ImageCache, ImageInput, and ImageOutput,
and so support all of the image file formats supported by OIIO.
The ImageBuf class definition requires that you:
#include <OpenImageIO/imagebuf.h>
-
enum OIIO::ImageBuf::IBStorage#
An ImageBuf can store its pixels in one of several ways (each identified by an
IBStorage
enumerated value):Values:
-
enumerator UNINITIALIZED#
An ImageBuf that doesn’t represent any image at all (either because it is newly constructed with the default constructor, or had an error during construction).
-
enumerator LOCALBUFFER#
“Local storage” is allocated to hold the image pixels internal to the ImageBuf. This memory will be freed when the ImageBuf is destroyed.
-
enumerator APPBUFFER#
The ImageBuf “wraps” pixel memory already allocated and owned by the calling application. The caller will continue to own that memory and be responsible for freeing it after the ImageBuf is destroyed.
-
enumerator IMAGECACHE#
The ImageBuf is “backed” by an ImageCache, which will automatically be used to retrieve pixels when requested, but the ImageBuf will not allocate separate storage for it. This brings all the advantages of the ImageCache, but can only be used for read-only ImageBuf’s that reference a stored image file.
-
enumerator UNINITIALIZED#
Constructing, destructing, resetting an ImageBuf#
There are several ways to construct an ImageBuf. Each constructor has a
corresponding reset
method that takes the same arguments. Calling reset
on an existing ImageBuf is equivalent to constructing a new ImageBuf from
scratch (even if the ImageBuf, prior to reset, previously held an image).
Making an empty or uninitialized ImageBuf#
-
OIIO::ImageBuf::ImageBuf()#
Default constructor makes an empty/uninitialized ImageBuf. There isn’t much you can do with an uninitialized buffer until you call
reset()
. The storage type of a default-constructed ImageBuf isIBStorage::UNINITIALIZED
.
-
inline void OIIO::ImageBuf::reset()#
Destroy any previous contents of the ImageBuf and re-initialize it to resemble a freshly constructed ImageBuf using the default constructor (holding no image, with storage
IBStorage::UNINITIALIZED
).
Constructing a readable ImageBuf#
-
explicit OIIO::ImageBuf::ImageBuf(string_view name, int subimage = 0, int miplevel = 0, ImageCache *imagecache = nullptr, const ImageSpec *config = nullptr, Filesystem::IOProxy *ioproxy = nullptr)#
Construct a read-only ImageBuf that will be used to read the named file (at the given subimage and MIP-level, defaulting to the first in the file). But don’t read it yet! The image will actually be read lazily, only when other methods need to access the spec and/or pixels, or when an explicit call to
init_spec()
orread()
is made, whichever comes first.The implementation may end up either reading the entire image internally owned memory (if so, the storage will be
LOCALBUFFER
), or it may rely on being backed by an ImageCache (in this case, the storage will beIMAGECACHE
) — depending on the image size and other factors.- Parameters:
name – The image to read.
subimage/miplevel – The subimage and MIP level to read (defaults to the first subimage of the file, highest-res MIP level).
imagecache – Optionally, a particular ImageCache to use. If nullptr, the default global/shared image cache will be used. If a custom ImageCache (not the global/shared one), it is important that the IC should not be destroyed while the ImageBuf is still alive.
config – Optionally, a pointer to an ImageSpec whose metadata contains configuration hints that set options related to the opening and reading of the file.
ioproxy – Optional pointer to an IOProxy to use when reading from the file. The caller retains ownership of the proxy, and must ensure that it remains valid for the lifetime of the ImageBuf.
-
void OIIO::ImageBuf::reset(string_view name, int subimage = 0, int miplevel = 0, ImageCache *imagecache = nullptr, const ImageSpec *config = nullptr, Filesystem::IOProxy *ioproxy = nullptr)#
Destroy any previous contents of the ImageBuf and re-initialize it as if newly constructed with the same arguments, as a read-only representation of an existing image file.
Constructing a writable ImageBuf#
-
explicit OIIO::ImageBuf::ImageBuf(const ImageSpec &spec, InitializePixels zero = InitializePixels::Yes)#
Construct a writable ImageBuf with the given specification (including resolution, data type, metadata, etc.). The ImageBuf will allocate and own its own pixel memory and will free that memory automatically upon destruction, clear(), or reset(). Upon successful initialization, the storage will be reported as
LOCALBUFFER
.- Parameters:
spec – An ImageSpec describing the image and its metadata. If not enough information is given to know how much memory to allocate (width, height, depth, channels, and data format), the ImageBuf will remain in an UNINITIALIZED state and will have no local pixel storage.
zero – After a successful allocation of the local pixel storage, this parameter controls whether the pixels will be initialized to hold zero (black) values (
InitializePixels::Yes
) or if the pixel memory will remain uninitialized (InitializePixels::No
) and thus may hold nonsensical values. ChoosingNo
may save the time of writing to the pixel memory if you know for sure that you are about to overwrite it completely before you will need to read any pixel values.
-
void OIIO::ImageBuf::reset(const ImageSpec &spec, InitializePixels zero = InitializePixels::Yes)#
Destroy any previous contents of the ImageBuf and re-initialize it as if newly constructed with the same arguments, as a read/write image with locally allocated storage that can hold an image as described by
spec
. The optionalzero
parameter controls whether the pixel values are filled with black/empty, or are left uninitialized after being allocated.Note that if the ImageSpec does not contain enough information to specify how much memory to allocate (width, height, channels, and data format), the ImageBuf will remain uninitialized (regardless of how
zero
is set).
-
bool OIIO::ImageBuf::make_writable(bool keep_cache_type = false)#
Make the ImageBuf be writable. That means that if it was previously backed by an ImageCache (storage was
IMAGECACHE
), it will force a full read so that the whole image is in local memory. This will invalidate any current iterators on the image. It has no effect if the image storage is notIMAGECACHE
.- Parameters:
keep_cache_type – If true, preserve any ImageCache-forced data types (you might want to do this if it is critical that the apparent data type doesn’t change, for example if you are calling
make_writable()
from within a type-specialized function).- Returns:
Return
true
if it works (including if no read was necessary),false
if something went horribly wrong.
Constructing an ImageBuf that “wraps” an application buffer#
-
OIIO::ImageBuf::ImageBuf(const ImageSpec &spec, void *buffer, stride_t xstride = AutoStride, stride_t ystride = AutoStride, stride_t zstride = AutoStride)#
Construct a writable ImageBuf that “wraps” existing pixel memory owned by the calling application. The ImageBuf does not own the pixel storage and will will not free/delete that memory, even when the ImageBuf is destroyed. Upon successful initialization, the storage will be reported as
APPBUFFER
.- Parameters:
spec – An ImageSpec describing the image and its metadata. If not enough information is given to know the “shape” of the image (width, height, depth, channels, and data format), the ImageBuf will remain in an UNINITIALIZED state.
buffer – A pointer to the caller-owned memory containing the storage for the pixels. It must be already allocated with enough space to hold a full image as described by
spec
.xstride/ystride/zstride – The distance in bytes between successive pixels, scanlines, and image planes in the buffer (or
AutoStride
to indicate “contiguous” data in any of those dimensions).
-
void OIIO::ImageBuf::reset(const ImageSpec &spec, void *buffer, stride_t xstride = AutoStride, stride_t ystride = AutoStride, stride_t zstride = AutoStride)#
Destroy any previous contents of the ImageBuf and re-initialize it as if newly constructed with the same arguments, to “wrap” existing pixel memory owned by the calling application.
Reading and Writing disk images#
-
bool OIIO::ImageBuf::read(int subimage = 0, int miplevel = 0, bool force = false, TypeDesc convert = TypeDesc::UNKNOWN, ProgressCallback progress_callback = nullptr, void *progress_callback_data = nullptr)#
Read the particular subimage and MIP level of the image. Generally, this will skip the expensive read if the file has already been read into the ImageBuf (at the specified subimage and MIP level). It will clear and re-allocate memory if the previously allocated space was not appropriate for the size or data type of the image being read.
In general,
read()
will try not to do any I/O at the time of theread()
call, but rather to have the ImageBuf “backed” by an ImageCache, which will do the file I/O on demand, as pixel values are needed, and in that case the ImageBuf doesn’t actually allocate memory for the pixels (the data lives in the ImageCache). However, there are several conditions for which the ImageCache will be bypassed, the ImageBuf will allocate “local” memory, and the disk file will be read directly into allocated buffer at the time of theread()
call: (a) if theforce
parameter istrue
; (b) if theconvert
parameter requests a data format conversion to a type that is not the native file type and also is not one of the internal types supported by the ImageCache (specifically,float
andUINT8
); (c) if the ImageBuf already has local pixel memory allocated, or “wraps” an application buffer.Note that
read()
is not strictly necessary. If you are happy with the filename, subimage and MIP level specified by the ImageBuf constructor (or the last call toreset()
), and you want the storage to be backed by the ImageCache (including storing the pixels in whatever data format that implies), then the file contents will be automatically read the first time you make any other ImageBuf API call that requires the spec or pixel values. The only reason to callread()
yourself is if you are changing the filename, subimage, or MIP level, or if you want to useforce = true
or a specificconvert
value to force data format conversion.- Parameters:
subimage/miplevel – The subimage and MIP level to read.
force – If
true
, will force an immediate full read into ImageBuf-owned local pixel memory (yielding aLOCALPIXELS
storage buffer). Otherwise, it is up to the implementation whether to immediately read or have the image backed by an ImageCache (storageIMAGECACHE
.)convert – If set to a specific type (not
UNKNOWN
), the ImageBuf memory will be allocated for that type specifically and converted upon read.progress_callback/progress_callback_data – If
progress_callback
is non-NULL, the underlying read, if expensive, may make several calls toprogress_callback(progress_callback_data, portion_done)
which allows you to implement some sort of progress meter. Note that if the ImageBuf is backed by an ImageCache, the progress callback will never be called, since no actual file I/O will occur at this time (ImageCache will load tiles or scanlines on demand, as individual pixel values are needed).
- Returns:
true
upon success, orfalse
if the read failed (in which case, you should be able to retrieve an error message viageterror()
).
-
bool OIIO::ImageBuf::read(int subimage, int miplevel, int chbegin, int chend, bool force, TypeDesc convert, ProgressCallback progress_callback = nullptr, void *progress_callback_data = nullptr)#
Read the file, if possible only allocating and reading a subset of channels,
[chbegin..chend-1]
. This can be a performance and memory improvement for some image file formats, if you know that any use of the ImageBuf will only access a subset of channels from a many-channel file.Additional parameters:
- Parameters:
chbegin/chend – The subset (a range with “exclusive end”) of channels to read, if the implementation is able to read only a subset of channels and have a performance advantage by doing so. If
chbegin
is 0 andchend
is either negative or greater than the number of channels in the file, all channels will be read. Please note that it is “advisory” and not guaranteed to be honored by the underlying implementation.
-
bool OIIO::ImageBuf::init_spec(string_view filename, int subimage, int miplevel)#
Read the ImageSpec for the given file, subimage, and MIP level into the ImageBuf, but will not read the pixels or allocate any local storage (until a subsequent call to
read()
). This is helpful if you have an ImageBuf and you need to know information about the image, but don’t want to do a full read yet, and maybe won’t need to do the full read, depending on what’s found in the spec.Note that
init_spec()
is not strictly necessary. If you are happy with the filename, subimage and MIP level specified by the ImageBuf constructor (or the last call toreset()
), then the spec will be automatically read the first time you make any other ImageBuf API call that requires it. The only reason to callread()
yourself is if you are changing the filename, subimage, or MIP level, or if you want to useforce=true
or a specificconvert
value to force data format conversion.- Parameters:
filename – The filename to read from (should be the same as the filename used when the ImageBuf was constructed or reset.)
subimage/miplevel – The subimage and MIP level to read.
- Returns:
true
upon success, orfalse
if the read failed (in which case, you should be able to retrieve an error message viageterror()
).
-
bool OIIO::ImageBuf::write(string_view filename, TypeDesc dtype = TypeUnknown, string_view fileformat = string_view(), ProgressCallback progress_callback = nullptr, void *progress_callback_data = nullptr) const#
Write the image to the named file, converted to the specified pixel data type
dtype
(TypeUnknown
signifies to use the data type of the buffer), and file format (an emptyfileformat
means to infer the type from the filename extension).By default, it will always try to write a scanline-oriented file, unless the
set_write_tiles()
method has been used to override this.- Parameters:
filename – The filename to write to.
dtype – Optional override of the pixel data format to use in the file being written. The default (
UNKNOWN
) means to try writing the same data format that as pixels are stored within the ImageBuf memory (or whatever type was specified by a prior call toset_write_format()
). In either case, if the file format does not support that data type, another will be automatically chosen that is supported by the file type and loses as little precision as possible.fileformat – Optional override of the file format to write. The default (empty string) means to infer the file format from the extension of the
filename
(for example, “foo.tif” will write a TIFF file).progress_callback/progress_callback_data – If
progress_callback
is non-NULL, the underlying write, if expensive, may make several calls toprogress_callback(progress_callback_data, portion_done)
which allows you to implement some sort of progress meter.
- Returns:
true
upon success, orfalse
if the write failed (in which case, you should be able to retrieve an error message viageterror()
).
-
bool OIIO::ImageBuf::write(ImageOutput *out, ProgressCallback progress_callback = nullptr, void *progress_callback_data = nullptr) const#
Write the pixels of the ImageBuf to an open ImageOutput. The ImageOutput must have already been opened with a spec that indicates a resolution identical to that of this ImageBuf (but it may have specified a different pixel data type, in which case data conversions will happen automatically). This method does NOT close the file when it’s done (and so may be called in a loop to write a multi-image file).
Note that since this uses an already-opened
ImageOutput
, which is too late to change how it was opened, it does not honor any prior calls toset_write_format
orset_write_tiles
.The main application of this method is to allow an ImageBuf (which by design may hold only a single image) to be used for the output of one image of a multi-subimage and/or MIP-mapped image file.
- Parameters:
out – A pointer to an already-opened
ImageOutput
to which the pixels of the ImageBuf will be written.progress_callback/progress_callback_data – If
progress_callback
is non-NULL, the underlying write, if expensive, may make several calls toprogress_callback(progress_callback_data, portion_done)
which allows you to implement some sort of progress meter.
- Returns:
true
if all went ok,false
if there were errors writing.
-
void OIIO::ImageBuf::set_write_format(TypeDesc format)#
Set the pixel data format that will be used for subsequent
write()
calls that do not themselves request a specific data type request.Note that this does not affect the variety of
write()
that takes an openImageOutput*
as a parameter.- Parameters:
format – The data type to be used for all channels.
-
void OIIO::ImageBuf::set_write_format(cspan<TypeDesc> format)#
Set the per-channel pixel data format that will be used for subsequent
write()
calls that do not themselves request a specific data type request.- Parameters:
format – The type of each channel (in order). Any channel’s format specified as
TypeUnknown
will default to be whatever type is described in the ImageSpec of the buffer.
-
void OIIO::ImageBuf::set_write_tiles(int width = 0, int height = 0, int depth = 0)#
Override the tile sizing for subsequent calls to the
write()
method (the variety that does not take an openImageOutput*
). Setting all three dimensions to 0 indicates that the output should be a scanline-oriented file.This lets you write a tiled file from an ImageBuf that may have been read originally from a scanline file, or change the dimensions of a tiled file, or to force the file written to be scanline even if it was originally read from a tiled file.
In all cases, if the file format ultimately written does not support tiling, or the tile dimensions requested, a suitable supported tiling choice will be made automatically.
Getting and setting information about an ImageBuf#
-
bool OIIO::ImageBuf::initialized() const#
Returns
true
if the ImageBuf is initialized,false
if not yet initialized.
-
IBStorage OIIO::ImageBuf::storage() const#
Which type of storage is being used for the pixels? Returns an enumerated type describing the type of storage currently employed by the ImageBuf:
UNINITIALIZED
(no storage),LOCALBUFFER
(the ImageBuf has allocated and owns the pixel memory),APPBUFFER
(the ImageBuf “wraps” memory owned by the calling application), orIMAGECACHE
(the image is backed by an ImageCache).
-
const ImageSpec &OIIO::ImageBuf::spec() const#
Return a read-only (const) reference to the image spec that describes the buffer.
-
const ImageSpec &OIIO::ImageBuf::nativespec() const#
Return a read-only (const) reference to the “native” image spec (that describes the file, which may be slightly different than the spec of the ImageBuf, particularly if the IB is backed by an ImageCache that is imposing some particular data format or tile size).
This may differ from
spec()
— for example, if a data format conversion was requested, if the buffer is backed by an ImageCache which stores the pixels internally in a different data format than that of the file, or if the file had differing per-channel data formats (ImageBuf must contain a single data format for all channels).
-
ImageSpec &OIIO::ImageBuf::specmod()#
Return a writable reference to the ImageSpec that describes the buffer. It’s ok to modify most of the metadata, but if you modify the spec’s
format
,width
,height
, ordepth
fields, you get the pain you deserve, as the ImageBuf will no longer have correct knowledge of its pixel memory layout. USE WITH EXTREME CAUTION.
-
string_view OIIO::ImageBuf::name(void) const#
Returns the name of the buffer (name of the file, for an ImageBuf read from disk).
-
string_view OIIO::ImageBuf::file_format_name(void) const#
Return the name of the image file format of the file this ImageBuf refers to (for example
"openexr"
). Returns an empty string for an ImageBuf that was not constructed as a direct reference to a file.
-
int OIIO::ImageBuf::subimage() const#
Return the index of the subimage within the file that the ImageBuf refers to. This will always be 0 for an ImageBuf that was not constructed as a direct reference to a file, or if the file contained only one image.
-
int OIIO::ImageBuf::nsubimages() const#
Return the number of subimages in the file this ImageBuf refers to. This will always be 1 for an ImageBuf that was not constructed as a direct reference to a file.
-
int OIIO::ImageBuf::miplevel() const#
Return the index of the miplevel with a file’s subimage that the ImageBuf is currently holding. This will always be 0 for an ImageBuf that was not constructed as a direct reference to a file, or if the subimage within that file was not MIP-mapped.
-
int OIIO::ImageBuf::nmiplevels() const#
Return the number of MIP levels of the current subimage within the file this ImageBuf refers to. This will always be 1 for an ImageBuf that was not constructed as a direct reference to a file, or if this subimage within the file was not MIP-mapped.
-
int OIIO::ImageBuf::nchannels() const#
Return the number of color channels in the image. This is equivalent to
spec().nchannels
.
-
int xbegin() const#
-
int xend() const#
-
int ybegin() const#
-
int yend() const#
-
int zbegin() const#
-
int zend() const#
Returns the
[begin,end)
range of the pixel data window of the buffer. These are equivalent tospec().x
,spec().x+spec().width
,spec().y
,spec().y+spec().height
,spec().z
, andspec().z+spec().depth
, respectively.
-
int OIIO::ImageBuf::orientation() const#
Return the current
"Orientation"
metadata for the image, per the table insec-metadata-orientation
_
-
void OIIO::ImageBuf::set_orientation(int orient)#
Set the
"Orientation"
metadata for the image.
-
int oriented_width() const#
-
int oriented_height() const#
-
int oriented_x() const#
-
int oriented_y() const#
-
int oriented_full_width() const#
-
int oriented_full_height() const#
-
int oriented_full_x() const#
-
int oriented_full_y() const#
The oriented width, height, x, and y describe the pixel data window after taking the display orientation into consideration. The full versions the “full” (a.k.a. display) window after taking the display orientation into consideration.
-
void OIIO::ImageBuf::set_origin(int x, int y, int z = 0)#
Alters the metadata of the spec in the ImageBuf to reset the “origin” of the pixel data window to be the specified coordinates. This does not affect the size of the pixel data window, only its position.
-
void OIIO::ImageBuf::set_full(int xbegin, int xend, int ybegin, int yend, int zbegin, int zend)#
Set the “full” (a.k.a. display) window to Alters the metadata of the spec in the ImageBuf to reset the “full” image size (a.k.a. “display window”) to
[xbegin,xend) x [ybegin,yend) x [zbegin,zend)`
This does not affect the size of the pixel data window.
-
void OIIO::ImageBuf::set_roi_full(const ROI &newroi)#
Set full/display window for this ImageBuf to a ROI. Does NOT change the channels of the spec, regardless of
newroi
.
-
bool OIIO::ImageBuf::contains_roi(ROI roi) const#
Is the specified roi completely contained in the data window of this ImageBuf?
-
TypeDesc OIIO::ImageBuf::pixeltype() const#
The data type of the pixels stored in the buffer (equivalent to
spec().format
).
-
int OIIO::ImageBuf::threads() const#
Retrieve the current thread-spawning policy of this ImageBuf.
-
void OIIO::ImageBuf::threads(int n) const#
Set the threading policy for this ImageBuf, controlling the maximum amount of parallelizing thread “fan-out” that might occur during expensive operations. The default of 0 means that the global
attribute("threads")
value should be used (which itself defaults to using as many threads as cores).The main reason to change this value is to set it to 1 to indicate that the calling thread should do all the work rather than spawning new threads. That is probably the desired behavior in situations where the calling application has already spawned multiple worker threads.
Copying ImageBuf’s and blocks of pixels#
-
const ImageBuf &OIIO::ImageBuf::operator=(const ImageBuf &src)#
Copy assignment.
-
const ImageBuf &OIIO::ImageBuf::operator=(ImageBuf &&src)#
Move assignment.
-
bool OIIO::ImageBuf::copy(const ImageBuf &src, TypeDesc format = TypeUnknown)#
Try to copy the pixels and metadata from
src
to*this
(optionally with an explicit data format conversion).If the previous state of
*this
was uninitialized, owning its own local pixel memory, or referring to a read-only image backed by ImageCache, then local pixel memory will be allocated to hold the new pixels and the call always succeeds unless the memory cannot be allocated. In this case, theformat
parameter may request a pixel data type that is different from that of the source buffer.If
*this
previously referred to an app-owned memory buffer, the memory cannot be re-allocated, so the call will only succeed if the app-owned buffer is already the correct resolution and number of channels. The data type of the pixels will be converted automatically to the data type of the app buffer.- Parameters:
src – Another ImageBuf from which to copy the pixels and metadata.
format – Optionally request the pixel data type to be used. The default of
TypeUnknown
means to use whatever data type is used by thesrc
. If*this
is already initialized and hasAPPBUFFER
storage (“wrapping” an application buffer), this parameter is ignored.
- Returns:
true
upon success orfalse
upon error/failure.
-
ImageBuf OIIO::ImageBuf::copy(TypeDesc format) const#
Return a full copy of
this
ImageBuf (optionally with an explicit data format conversion).
-
void OIIO::ImageBuf::copy_metadata(const ImageBuf &src)#
Copy all the metadata from
src
to*this
(except for pixel data resolution, channel types and names, and data format).
-
bool OIIO::ImageBuf::copy_pixels(const ImageBuf &src)#
Copy the pixel data from
src
to*this
, automatically converting to the existing data format of*this
. It only copies pixels in the overlap regions (and channels) of the two images; pixel data in*this
that do exist insrc
will be set to 0, and pixel data insrc
that do not exist in*this
will not be copied.
-
inline void OIIO::ImageBuf::swap(ImageBuf &other)#
Swap the entire contents with another ImageBuf.
Getting and setting pixel values#
Getting and setting individual pixels – slow
-
float OIIO::ImageBuf::getchannel(int x, int y, int z, int c, WrapMode wrap = WrapBlack) const#
Retrieve a single channel of one pixel.
- Parameters:
x/y/z – The pixel coordinates.
c – The channel index to retrieve.
wrap – WrapMode that determines the behavior if the pixel coordinates are outside the data window:
WrapBlack
,WrapClamp
,WrapPeriodic
,WrapMirror
.
- Returns:
The data value, converted to a
float
.
-
void OIIO::ImageBuf::getpixel(int x, int y, int z, float *pixel, int maxchannels = 1000, WrapMode wrap = WrapBlack) const#
Retrieve the pixel value by x, y, z pixel indices, placing its contents in
pixel[0..n-1]
where n is the smaller ofmaxchannels
the actual number of channels stored in the buffer.- Parameters:
x/y/z – The pixel coordinates.
pixel – The results are stored in
pixel[0..nchannels-1]
. It is up to the caller to ensure thatpixel
points to enough memory to hold the required number of channels.maxchannels – Optional clamp to the number of channels retrieved.
wrap – WrapMode that determines the behavior if the pixel coordinates are outside the data window:
WrapBlack
,WrapClamp
,WrapPeriodic
,WrapMirror
.
-
void OIIO::ImageBuf::interppixel(float x, float y, float *pixel, WrapMode wrap = WrapBlack) const#
Sample the image plane at pixel coordinates (x,y), using linear interpolation between pixels, placing the result in
pixel[]
.- Parameters:
x/y – The pixel coordinates. Note that pixel data values themselves are at the pixel centers, so pixel (i,j) is at image plane coordinate (i+0.5, j+0.5).
pixel – The results are stored in
pixel[0..nchannels-1]
. It is up to the caller to ensure thatpixel
points to enough memory to hold the number of channels in the image.wrap – WrapMode that determines the behavior if the pixel coordinates are outside the data window:
WrapBlack
,WrapClamp
,WrapPeriodic
,WrapMirror
.
-
void OIIO::ImageBuf::interppixel_bicubic(float x, float y, float *pixel, WrapMode wrap = WrapBlack) const#
Bicubic interpolation at pixel coordinates (x,y).
-
void OIIO::ImageBuf::interppixel_NDC(float s, float t, float *pixel, WrapMode wrap = WrapBlack) const#
Linearly interpolate at NDC coordinates (s,t), where (0,0) is the upper left corner of the display window, (1,1) the lower right corner of the display window.
Note
interppixel()
uses pixel coordinates (ranging 0..resolution) whereasinterppixel_NDC()
uses NDC coordinates (ranging 0..1).
-
void OIIO::ImageBuf::interppixel_bicubic_NDC(float s, float t, float *pixel, WrapMode wrap = WrapBlack) const#
Bicubic interpolation at NDC space coordinates (s,t), where (0,0) is the upper left corner of the display (a.k.a. “full”) window, (1,1) the lower right corner of the display window.
-
inline void OIIO::ImageBuf::setpixel(int x, int y, int z, cspan<float> pixel)#
Set the pixel with coordinates (x,y,z) to have the values in span
pixel[]
. The number of channels copied is the minimum of the span length and the actual number of channels in the image.
-
inline void OIIO::ImageBuf::setpixel(int i, cspan<float> pixel)#
Set the
i
-th pixel value of the image (out of width*height*depth), from floating-point values in spanpixel[]
. The number of channels copied is the minimum of the span length and the actual number of channels in the image.
Getting and setting regions of pixels – fast
-
bool OIIO::ImageBuf::get_pixels(ROI roi, TypeDesc format, void *result, stride_t xstride = AutoStride, stride_t ystride = AutoStride, stride_t zstride = AutoStride) const#
Retrieve the rectangle of pixels spanning the ROI (including channels) at the current subimage and MIP-map level, storing the pixel values beginning at the address specified by result and with the given strides (by default, AutoStride means the usual contiguous packing of pixels) and converting into the data type described by
format
. It is up to the caller to ensure that result points to an area of memory big enough to accommodate the requested rectangle. Return true if the operation could be completed, otherwise return false.
-
bool OIIO::ImageBuf::set_pixels(ROI roi, TypeDesc format, const void *data, stride_t xstride = AutoStride, stride_t ystride = AutoStride, stride_t zstride = AutoStride)#
Copy the data into the given ROI of the ImageBuf. The data points to values specified by
format
, with layout detailed by the stride values (in bytes, with AutoStride indicating “contiguous” layout). It is up to the caller to ensure that data points to an area of memory big enough to account for the ROI. Ifroi
is set toROI::all()
, the data buffer is assumed to have the same resolution as the ImageBuf itself. Return true if the operation could be completed, otherwise return false.
Deep data in an ImageBuf#
-
bool OIIO::ImageBuf::deep() const#
Does this ImageBuf store deep data? Returns
true
if the ImageBuf holds a “deep” image,false
if the ImageBuf holds an ordinary pixel-based image.
-
int OIIO::ImageBuf::deep_samples(int x, int y, int z = 0) const#
Retrieve the number of deep data samples corresponding to pixel (x,y,z). Return 0 if not a deep image, or if the pixel is outside of the data window, or if the designated pixel has no deep samples.
-
void OIIO::ImageBuf::set_deep_samples(int x, int y, int z, int nsamples)#
Set the number of deep samples for pixel (x,y,z). If data has already been allocated, this is equivalent to inserting or erasing samples.
-
void OIIO::ImageBuf::deep_insert_samples(int x, int y, int z, int samplepos, int nsamples)#
Insert
nsamples
new samples, starting at positionsamplepos
of pixel (x,y,z).
-
void OIIO::ImageBuf::deep_erase_samples(int x, int y, int z, int samplepos, int nsamples)#
Remove
nsamples
samples, starting at positionsamplepos
of pixel (x,y,z).
-
float OIIO::ImageBuf::deep_value(int x, int y, int z, int c, int s) const#
Return the value (as a
float
) of samples
of channelc
of pixel(x,y,z)
. Return 0 if not a deep image or if the pixel coordinates or channel number are out of range or if that pixel has no deep samples.
-
uint32_t OIIO::ImageBuf::deep_value_uint(int x, int y, int z, int c, int s) const#
Return the value (as a
uint32_t
) of samples
of channelc
of pixel(x,y,z)
. Return 0 if not a deep image or if the pixel coordinates or channel number are out of range or if that pixel has no deep samples.
-
void OIIO::ImageBuf::set_deep_value(int x, int y, int z, int c, int s, float value)#
Set the value of sample
s
of channelc
of pixel(x,y,z)
to afloat
value (it is expected that channelc
is a floating point type).
-
void OIIO::ImageBuf::set_deep_value(int x, int y, int z, int c, int s, uint32_t value)#
Set the value of sample
s
of channelc
of pixel(x,y,z)
to auint32_t
value (it is expected that channelc
is an integer type).
-
const void *OIIO::ImageBuf::deep_pixel_ptr(int x, int y, int z, int c, int s = 0) const#
Return a pointer to the raw data of pixel
(x,y,z)
, channelc
, samples
. Returnnullptr
if the pixel coordinates or channel number are out of range, if the pixel/channel has no deep samples, or if the image is not deep. Use with caution — these pointers may be invalidated by calls that adjust the number of samples in any pixel.
Error Handling#
-
template<typename ...Args>
inline void OIIO::ImageBuf::errorf(const char *fmt, const Args&... args) const# Error reporting for ImageBuf: call this with printf-like arguments to report an error. It is not necessary to have the error message contain a trailing newline.
-
bool OIIO::ImageBuf::has_error(void) const#
Returns
true
if the ImageBuf has had an error and has an error message ready to retrieve viageterror()
.
-
std::string OIIO::ImageBuf::geterror(bool clear = true) const#
Return the text of all pending error messages issued against this ImageBuf, and clear the pending error message unless
clear
is false. If no error message is pending, it will return an empty string.
Miscellaneous#
-
void *localpixels()#
-
const void *localpixels() const#
Return a raw pointer to the “local” pixel memory, if they are fully in RAM and not backed by an ImageCache, or
nullptr
otherwise. You can also test it like abool
to find out if pixels are local.
-
void *pixeladdr(int x, int y, int z = 0, int ch = 0)#
-
const void *pixeladdr(int x, int y, int z = 0, int ch = 0) const#
Return the address where pixel
(x,y,z)
, channelch
, is stored in the image buffer. Use with extreme caution! Will returnnullptr
if the pixel values aren’t local in RAM.
-
int OIIO::ImageBuf::pixelindex(int x, int y, int z, bool check_range = false) const#
Return the index of pixel (x,y,z). If check_range is true, return -1 for an invalid coordinate that is not within the data window.
-
static WrapMode OIIO::ImageBuf::WrapMode_from_string(string_view name)#
Return the
WrapMode
corresponding to the name ("default"
,"black"
,"clamp"
,"periodic"
,"mirror"
). For an unknown name, this will returnWrapDefault
.
Iterators – the fast way of accessing individual pixels#
Sometimes you need to visit every pixel in an ImageBuf (or at least, every
pixel in a large region). Using the getpixel()
and setpixel()
for this
purpose is simple but very slow. But ImageBuf provides templated Iterator
and ConstIterator
types that are very inexpensive and hide all the details
of local versus cached storage.
Note
ImageBuf::ConstIterator
is identical to the Iterator, except thatConstIterator
may be used on aconst ImageBuf
and may not be used to alter the contents of the ImageBuf. For simplicity, the remainder of this section will only discuss theIterator
.
An Iterator is associated with a particular ImageBuf. The Iterator has a current pixel coordinate that it is visiting, and an iteration range that describes a rectangular region of pixels that it will visits as it advances. It always starts at the upper left corner of the iteration region. We say that the iterator is done after it has visited every pixel in its iteration range. We say that a pixel coordinate exists if it is within the pixel data window of the ImageBuf. We say that a pixel coordinate is valid if it is within the iteration range of the iterator.
The Iterator<BUFT,USERT>
is templated based on two types: BUFT
the type
of the data stored in the ImageBuf, and USERT
type type of the data that
you want to manipulate with your code. USERT
defaults to float
, since
usually you will want to do all your pixel math with float
. We will
thus use Iterator<T>
synonymously with Iterator<T,float>
.
For the remainder of this section, we will assume that you have a
float
-based ImageBuf, for example, if it were set up like this:
ImageBuf buf ("myfile.exr");
buf.read (0, 0, true, TypeDesc::FLOAT);
-
template<>
Iterator<BUFT>(ImageBuf &buf, WrapMode wrap = WrapDefault)# Initialize an iterator that will visit every pixel in the data window of
buf
, and start it out pointing to the upper left corner of the data window. Thewrap
describes what values will be retrieved if the iterator is positioned outside the data window of the buffer.
-
template<>
Iterator<BUFT>(ImageBuf &buf, const ROI &roi, WrapMode wrap = WrapDefault)# Initialize an iterator that will visit every pixel of
buf
within the region described byroi
, and start it out pointing to pixel (roi.xbegin, roi.ybegin, roi.zbegin
). Thewrap
describes what values will be retrieved if the iterator is positioned outside the data window of the buffer.
-
template<>
Iterator<BUFT>(ImageBuf &buf, int x, int y, int z, WrapMode wrap = WrapDefault)# Initialize an iterator that will visit every pixel in the data window of
buf
, and start it out pointing to pixel (x, y, z). Thewrap
describes what values will be retrieved if the iterator is positioned outside the data window of the buffer.
-
Iterator::operator++()#
The
++
operator advances the iterator to the next pixel in its iteration range. (Both prefix and postfix increment operator are supported.)
-
bool Iterator::done() const#
Returns
true
if the iterator has completed its visit of all pixels in its iteration range.
-
ROI Iterator::range() const#
Returns the iteration range of the iterator, expressed as an ROI.
-
int Iterator::x() const#
-
int Iterator::y() const#
-
int Iterator::z() const#
Returns the x, y, and z pixel coordinates, respectively, of the pixel that the iterator is currently visiting.
-
bool Iterator::valid() const#
Returns
true
if the iterator’s current pixel coordinates are within its iteration range.
-
bool Iterator::valid(int x, int y, int z = 0) const#
Returns
true
if pixel coordinate (x, y, z) are within the iterator’s iteration range (regardless of where the iterator itself is currently pointing).
-
bool Iterator::exists() const#
Returns
true
if the iterator’s current pixel coordinates are within the data window of the ImageBuf.
-
bool Iterator::exists(int x, int y, int z = 0) const#
Returns
true
if pixel coordinate (x, y, z) are within the pixel data window of the ImageBuf (regardless of where the iterator itself is currently pointing).
-
USERT &Iterator::operator[](int i)#
The value of channel
i
of the current pixel. (The wrap mode, set up when the iterator was constructed, determines what value is returned if the iterator points outside the pixel data window of its buffer.)
-
int Iterator::deep_samples() const#
For deep images only, retrieves the number of deep samples for the current pixel.
-
void Iterator::set_deep_samples()#
For deep images only (and non-const ImageBuf), set the number of deep samples for the current pixel. This only is useful if the ImageBuf has not yet had the
deep_alloc()
method called.
-
USERT Iterator::deep_value(int c, int s) const#
-
uint32_t Iterator::deep_value_int(int c, int s) const#
For deep images only, returns the value of channel
c
, sample numbers
, at the current pixel.
-
void Iterator::set_deep_value(int c, int s, float value)#
-
void Iterator::set_deep_value(int c, int s, uint32_t value)#
For deep images only (and non-cconst ImageBuf, sets the value of channel
c
, sample numbers
, at the current pixel. This only is useful if the ImageBuf has already had thedeep_alloc()
method called.
Example: Visiting all pixels to compute an average color#
void print_channel_averages (const std::string &filename)
{
// Set up the ImageBuf and read the file
ImageBuf buf (filename);
bool ok = buf.read (0, 0, true, TypeDesc::FLOAT); // Force a float buffer
if (! ok)
return;
// Initialize a vector to contain the running total
int nc = buf.nchannels();
std::vector<float> total (n, 0.0f);
// Iterate over all pixels of the image, summing channels separately
for (ImageBuf::ConstIterator<float> it (buf); ! it.done(); ++it)
for (int c = 0; c < nc; ++c)
total[c] += it[c];
// Print the averages
imagesize_t npixels = buf.spec().image_pixels();
for (int c = 0; c < nc; ++c)
std::cout << "Channel " << c << " avg = " (total[c] / npixels) << "\n";
}
Example: Set all pixels in a region to black#
bool make_black (ImageBuf &buf, ROI region)
{
if (buf.spec().format != TypeDesc::FLOAT)
return false; // Assume it's a float buffer
// Clamp the region's channel range to the channels in the image
roi.chend = std::min (roi.chend, buf.nchannels);
// Iterate over all pixels in the region...
for (ImageBuf::Iterator<float> it (buf, region); ! it.done(); ++it) {
if (! it.exists()) // Make sure the iterator is pointing
continue; // to a pixel in the data window
for (int c = roi.chbegin; c < roi.chend; ++c)
it[c] = 0.0f; // clear the value
}
return true;
}
Dealing with buffer data types#
The previous section on iterators presented examples and discussion based on
the assumption that the ImageBuf was guaranteed to store float
data and
that you wanted all math to also be done as float
computations. Here we
will explain how to deal with buffers and files that contain different data
types.
Strategy 1: Only have float
data in your ImageBuf#
When creating your own buffers, make sure they are float
:
ImageSpec spec (640, 480, 3, TypeDesc::FLOAT); // <-- float buffer
ImageBuf buf ("mybuf", spec);
When using ImageCache-backed buffers, force the ImageCache
to convert everything to float
:
// Just do this once, to set up the cache:
ImageCache *cache = ImageCache::create (true /* shared cache */);
cache->attribute ("forcefloat", 1);
...
ImageBuf buf ("myfile.exr"); // Backed by the shared cache
Or force the read to convert to float
in the buffer if
it’s not a native type that would automatically stored as a float
internally to the ImageCache:[1]
ImageBuf buf ("myfile.exr"); // Backed by the shared cache
buf.read (0, 0, false /* don't force read to local mem */,
TypeDesc::FLOAT /* but do force conversion to float*/);
Or force a read into local memory unconditionally (rather
than relying on the ImageCache), and convert to float
:
ImageBuf buf ("myfile.exr");
buf.read (0, 0, true /*force read*/,
TypeDesc::FLOAT /* force conversion */);
Strategy 2: Template your iterating functions based on buffer type#
Consider the following alternate version of the make_black
function
from Section Example: Set all pixels in a region to black
template<typename BUFT>
static bool make_black_impl (ImageBuf &buf, ROI region)
{
// Clamp the region's channel range to the channels in the image
roi.chend = std::min (roi.chend, buf.nchannels);
// Iterate over all pixels in the region...
for (ImageBuf::Iterator<BUFT> it (buf, region); ! it.done(); ++it) {
if (! it.exists()) // Make sure the iterator is pointing
continue; // to a pixel in the data window
for (int c = roi.chbegin; c < roi.chend; ++c)
it[c] = 0.0f; // clear the value
}
return true;
}
bool make_black (ImageBuf &buf, ROI region)
{
if (buf.spec().format == TypeDesc::FLOAT)
return make_black_impl<float> (buf, region);
else if (buf.spec().format == TypeDesc::HALF)
return make_black_impl<half> (buf, region);
else if (buf.spec().format == TypeDesc::UINT8)
return make_black_impl<unsigned char> (buf, region);
else if (buf.spec().format == TypeDesc::UINT16)
return make_black_impl<unsigned short> (buf, region);
else {
buf.error ("Unsupported pixel data format %s", buf.spec().format);
return false;
}
}
In this example, we make an implementation that is templated on the buffer type, and then a wrapper that calls the appropriate template specialization for each of 4 common types (and logs an error in the buffer for any other types it encounters).
In fact, imagebufalgo_util.h
provides a macro to do this (and
several variants, which will be discussed in more detail in the next
chapter). You could rewrite the example even more simply:
#include <OpenImageIO/imagebufalgo_util.h>
template<typename BUFT>
static bool make_black_impl (ImageBuf &buf, ROI region)
{
... same as before ...
}
bool make_black (ImageBuf &buf, ROI region)
{
bool ok;
OIIO_DISPATCH_COMMON_TYPES (ok, "make_black", make_black_impl,
buf.spec().format, buf, region);
return ok;
}
This other type-dispatching helper macros will be discussed in more detail in Chapter ImageBufAlgo: Image Processing.