ImageInput: Reading Images#
Image Input Made Simple#
Here is the simplest sequence required to open an image file, find out its resolution, and read the pixels (converting them into 8-bit values in memory, even if that’s not the way they’re stored in the file):
#include <OpenImageIO/imageio.h>
using namespace OIIO;
void simple_read()
{
const char* filename = "tahoe.tif";
auto inp = ImageInput::open(filename);
if (! inp)
return;
const ImageSpec &spec = inp->spec();
int xres = spec.width;
int yres = spec.height;
int nchannels = spec.nchannels;
auto pixels = std::unique_ptr<unsigned char[]>(new unsigned char[xres * yres * nchannels]);
inp->read_image(0, 0, 0, nchannels, TypeDesc::UINT8, &pixels[0]);
inp->close();
}
import OpenImageIO as oiio
def simple_read():
filename = "tahoe.tif"
inp = oiio.ImageInput.open(filename)
if inp :
spec = inp.spec()
xres = spec.width
yres = spec.height
nchannels = spec.nchannels
pixels = inp.read_image(0, 0, 0, nchannels, "uint8")
inp.close()
Here is a breakdown of what work this code is doing:
Search for an ImageIO plugin that is capable of reading the file (
foo.jpg
), first by trying to deduce the correct plugin from the file extension, but if that fails, by opening every ImageIO plugin it can find until one will open the file without error. When it finds the right plugin, it creates a subclass instance of ImageInput that reads the right kind of file format, and tries to fully open the file. Theopen()
method returns astd::unique_ptr<ImageInput>
that will be automatically freed when it exits scope.auto inp = ImageInput::open (filename);
inp = ImageInput.open (filename)
The specification, accessible as
inp->spec()
, contains vital information such as the dimensions of the image, number of color channels, and data type of the pixel values. This is enough to allow us to allocate enough space for the image in C++ (for Python, this is unnecessary, sinceread_image()
will return a NumPy array to us).const ImageSpec &spec = inp->spec(); int xres = spec.width; int yres = spec.height; int nchannels = spec.nchannels; auto pixels = std::unique_ptr<unsigned char[]>(new unsigned char[xres * yres * nchannels]);
spec = inp.spec() xres = spec.width yres = spec.height channels = spec.nchannels
Note that in this example, we don’t care what data format is used for the pixel data in the file — we will request unsigned 8 bit integers and rely on OpenImageIO’s ability to convert to our requested format from the native data format of the file.
Read the entire image, hiding all details of the encoding of image data in the file, whether the file is scanline- or tile-based, or what is the native format of the data in the file (in this case, we request that it be automatically converted to unsigned 8-bit integers). Note that the exact set of channels are specified as well as the explicit subimage and miplevel for efficiency and thread-safety.
inp->read_image(0, 0, 0, nchannels, TypeDesc::UINT8, &pixels[0]);
pixels = inp->read_image(0, 0, 0, nchannels, "uint8") # Note: pixels now contains a NumPy array of the image data.
Close the file.
inp->close();
inp.close()
When
inp
exits its scope, the ImageInput will automatically be destroyed and any resources used by the plugin will be released.
Advanced Image Input#
Let’s walk through some of the most common things you might want to do, but that are more complex than the simple example above.
Reading individual scanlines and tiles#
The simple example of Section Image Input Made Simple read an entire image with one call. But sometimes you want to read a large image a little at a time and do not wish to retain the entire image in memory as you process it. OpenImageIO allows you to read images one scanline at a time or one tile at a time.
Examining the ImageSpec reveals whether the file is scanline or
tile-oriented: a scanline image will have spec.tile_width
and
spec.tile_height
set to 0, whereas a tiled images will have nonzero
values for the tile dimensions.
Reading scanlines#
Individual scanlines may be read using the read_scanline()
API call:
auto inp = ImageInput::open (filename);
const ImageSpec &spec = inp->spec();
if (spec.tile_width == 0) {
auto scanline = std::unique_ptr<unsigned char[]>(new unsigned char[spec.width * spec.nchannels]);
for (int y = 0; y < spec.height; ++y) {
inp->read_scanline (y, 0, TypeDesc::UINT8, &scanline[0]);
// ... process data in scanline[0..width*channels-1] ...
}
} else {
//... handle tiles, or reject the file ...
}
inp->close ();
= oiio.ImageInput.open (filename)
= inp.spec()
pec.tile_width == 0 :
for y in range(spec.height) :
scanline = inp.read_scanline (y, 0, "uint8")
# ... process data in scanline[0..width*channels-1] ...
se :
# ... handle tiles, or reject the file ...
close ()
The first two arguments to read_scanline()
specify which scanline
is being read by its vertical (y
) scanline number (beginning with 0)
and, for volume images, its slice (z
) number (the slice number should
be 0 for 2D non-volume images). This is followed by a TypeDesc
describing the data type of the pixel buffer you are supplying, and a
pointer to the pixel buffer itself. Additional optional arguments
describe the data stride, which can be ignored for contiguous data (use
of strides is explained in Section Data Strides).
Nearly all ImageInput implementations will be most efficient reading
scanlines in strict order (starting with scanline 0, then 1, up to
yres-1
, without skipping any). An ImageInput is required to accept
read_scanline()
requests in arbitrary order, but depending on the file
format and reader implementation, out-of-order scanline reads may be
inefficient.
There is also a read_scanlines()
function that operates similarly,
except that it takes a ybegin
and yend
that specify a range,
reading all scanlines ybegin <= y < yend
. For most image
format readers, this is implemented as a loop over individual scanlines,
but some image format readers may be able to read a contiguous block of
scanlines more efficiently than reading each one individually.
The full descriptions of the read_scanline()
and read_scanlines()
functions may be found in Section ImageInput Class Reference.
Reading tiles#
Once you open()
an image file, you can find out if it is a tiled image
(and the tile size) by examining the ImageSpec’s tile_width
,
tile_height
, and tile_depth
fields. If they are zero, it’s a
scanline image and you should read pixels using read_scanline()
, not
read_tile()
.
auto inp = ImageInput::open(filename);
const ImageSpec &spec = inp->spec();
if (spec.tile_width == 0) {
// ... read scanline by scanline ...
} else {
// Tiles
int tilesize = spec.tile_width * spec.tile_height;
auto tile = std::unique_ptr<unsigned char[]>(new unsigned char[tilesize * spec.nchannels]);
for (int y = 0; y < spec.height; y += spec.tile_height) {
for (int x = 0; x < spec.width; x += spec.tile_width) {
inp->read_tile(x, y, 0, TypeDesc::UINT8, &tile[0]);
// ... process the pixels in tile[] ..
}
}
}
inp->close ();
= oiio.ImageInput.open(filename)
= inp.spec()
pec.tile_width == 0 :
# ... read scanline by scanline ...
pass
:
# Tiles
tilesize = spec.tile_width * spec.tile_height
for y in range(0, spec.height, spec.tile_height) :
for x in range(0, spec.width, spec.tile_width) :
tile = inp.read_tile (x, y, 0, "uint8")
# ... process the pixels in tile[][] ..
close ()
The first three arguments to read_tile()
specify which tile is
being read by the pixel coordinates of any pixel contained in the
tile: x
(column), y
(scanline), and z
(slice, which should always
be 0 for 2D non-volume images). This is followed by a TypeDesc
describing the data format of the pixel buffer you are supplying, and a
pointer to the pixel buffer. Pixel data will be written to your buffer
in order of increasing slice, increasing
scanline within each slice, and increasing column within each scanline.
Additional optional arguments describe the data stride, which can be
ignored for contiguous data (use of strides is explained in
Section Data Strides).
All ImageInput implementations are required to support reading tiles in
arbitrary order (i.e., not in strict order of increasing y
rows, and
within each row, increasing x
column, without missing any tiles).
The full description of the read_tile()
function may be found
in Section ImageInput Class Reference.
Converting formats#
The code examples of the previous sections all assumed that your internal pixel data is stored as unsigned 8-bit integers (i.e., 0-255 range). But OpenImageIO is significantly more flexible.
You may request that the pixels be stored in any of several formats. This is
done merely by passing the read
function the data type of your pixel
buffer, as one of the enumerated type TypeDesc
.
It is not required that the pixel data buffer passed to read_image()
,
read_scanline()
, or read_tile()
actually be in the same data format
as the data in the file being read. OpenImageIO will automatically convert
from native data type of the file to the internal data format of your
choice. For example, the following code will open a TIFF and read pixels
into your internal buffer represented as float
values. This will work
regardless of whether the TIFF file itself is using 8-bit, 16-bit, or float
values.
std::unique_ptr<ImageInput> inp = ImageInput::open ("myfile.tif");
const ImageSpec &spec = inp->spec();
int numpixels = spec.image_pixels();
int nchannels = spec.nchannels;
auto pixels = std::unique_ptr<float[]>(new float[numpixels * nchannels]);
inp->read_image (0, 0, 0, nchannels, TypeDesc::FLOAT, &pixels[0]);
inp = ImageInput.open("myfile.tif")
pixels = inp.read_image(0, 0, 0, nchannels, "float")
Note that read_scanline()
and read_tile()
have a parameter that
works in a corresponding manner.
You can, of course, find out the native type of the file simply by examining
spec.format
. If you wish, you may then allocate a buffer big enough for
an image of that type and request the native type when reading, therefore
eliminating any translation among types and seeing the actual numerical
values in the file.
Data Strides#
In the preceding examples, we have assumed that the buffer passed to
the read
functions (i.e., the place where you want your pixels
to be stored) is contiguous, that is:
each pixel in memory consists of a number of data values equal to the number of channels in the file;
successive column pixels within a row directly follow each other in memory, with the first channel of pixel
x
immediately following last channel of pixelx-1
of the same row;for whole images or tiles, the data for each row immediately follows the previous one in memory (the first pixel of row
y
immediately follows the last column of rowy-1
);for 3D volumetric images, the first pixel of slice
z
immediately follows the last pixel of of slicez-1
.
Please note that this implies that read_tile()
will write pixel data into
your buffer so that it is contiguous in the shape of a single tile, not
just an offset into a whole image worth of pixels.
The read_scanline()
function takes an optional xstride
argument, and
the read_image()
and read_tile()
functions take optional
xstride
, ystride
, and zstride
values that describe the distance,
in bytes, between successive pixel columns, rows, and slices,
respectively, of your pixel buffer. For any of these values that are not
supplied, or are given as the special constant AutoStride
, contiguity
will be assumed.
By passing different stride values, you can achieve some surprisingly flexible functionality. A few representative examples follow:
Flip an image vertically upon reading, by using negative
y
stride:auto pixels = std::unique_ptr<unsigned char[]>(new unsigned char[spec.width * spec.height * spec.nchannels]); int scanlinesize = spec.width * spec.nchannels * sizeof(pixels[0]); ... in->read_image (0, 0, 0, spec.nchannels, TypeDesc::UINT8, (char *)pixels+(yres-1)*scanlinesize, // offset to last AutoStride, // default x stride -scanlinesize, // special y stride AutoStride); // default z stride
Read a tile into its spot in a buffer whose layout matches a whole image of pixel data, rather than having a one-tile-only memory layout:
int pixelsize = spec.nchannels * sizeof(pixels[0]); int scanlinesize = xpec.width * pixelsize; ... in->read_tile (x, y, 0, TypeDesc::UINT8, (char *)pixels + y*scanlinesize + x*pixelsize, pixelsize, scanlinesize);
Please consult Section ImageInput Class Reference for detailed
descriptions of the stride parameters to each read
function.
Reading channels to separate buffers#
While specifying data strides allows writing entire pixels to buffers with arbitrary layouts, it is not possible to separate those pixels into multiple buffers (i.e. to write image data to a separate or planar memory layout: RRRRGGGGBBBB instead of the interleaved RGBRGBRGBRGB).
A workaround for this is to call read_scanlines
, read_tiles
or
read_image
repeatedly with arguments chbegin
and chend
of
0 <= chbegin < spec.nchannels
and chend == chbegin + 1
:
// one buffer for all three channels
auto pixels = std::unique_ptr<unsigned char[]>(new unsigned char[spec.width * spec.height * spec.nchannels]);
for (int channel = 0; channel < spec.nchannels; ++channel) {
file->read_image(
0, 0,
// reading one channel at a time
channel, channel + 1,
TypeDesc::UINT8,
// writing the data to offsets spaced `spec.width * spec.height`
// apart
&pixels[spec.width * spec.height * channel]);
}
pixels = numpy.zeros((spec.nchannels, spec.height, spec.width), "uint8")
for channel in range(spec.nchannels) :
pixels[channel] = file.read_image(0, 0, channel, channel + 1, "uint8")
For many formats, this is nearly as fast as reading the image with interleaved pixel data if the format stores the pixels in an interleaved layout and even slightly faster if the pixels are stored in separate planes in the file.
Reading metadata#
The ImageSpec that is filled in by ImageInput::open()
specifies all the
common properties that describe an image: data format, dimensions, number of
channels, tiling. However, there may be a variety of additional metadata
that are present in the image file and could be queried by your application.
The remainder of this section explains how to query additional metadata in the ImageSpec. It is up to the ImageInput to read these from the file, if indeed the file format is able to carry additional data. Individual ImageInput implementations should document which metadata they read.
Channel names#
In addition to specifying the number of color channels, the ImageSpec also
stores the names of those channels in its channelnames
field, which is a
std::vector<std::string>
in C++, or a tuple of strings in Python. Its
length should always be equal to the number of channels (it’s the
responsibility of the ImageInput to ensure this).
Only a few file formats (and thus ImageInput implementations) have a way of
specifying custom channel names, so most of the time you will see that the
channel names follow the default convention of being named "R"
, "G"
,
"B"
, and "A"
, for red, green, blue, and alpha, respectively.
Here is example code that prints the names of the channels in an image:
auto inp = ImageInput::open (filename);
const ImageSpec &spec = inp->spec();
for (int i = 0; i < spec.nchannels; ++i)
std::cout << "Channel " << i << " is "
<< spec.channelnames[i] << "\n";
inp = ImageInput.open (filename)
spec = inp.spec()
for i in range(spec.nchannels) :
print("Channel", i, "is", spec.channelnames[i])
Specially-designated channels#
The ImageSpec contains two fields, alpha_channel
and z_channel
,
which designate which channel numbers represent alpha and z
depth, if
any. If either is set to -1
, it indicates that it is not known which
channel is used for that data.
If you are doing something special with alpha or depth, it is probably safer
to respect the alpha_channel
and z_channel
designations (if not set
to -1
) rather than merely assuming that, for example, channel 3 is
always the alpha channel.
Arbitrary metadata#
All other metadata found in the file will be stored in the ImageSpec’s
extra_attribs
field, which is a ParamValueList, which is itself
essentially a vector of ParamValue instances. Each ParamValue stores one
meta-datum consisting of a name, type (specified by a TypeDesc
), number
of values, and data pointer.
If you know the name and type of a specific piece of metadata you want to use,
you can retrieve it using the ImageSpec::getattribute()
method. In C++,
this copies the value into your variable and returns true
if the attribute
was found, or false
if it was not. In Python, getattribute()
simply
returns the value of the attribute itself, or None
if no match was found.
auto in; = ImageInput::open(filename);
const ImageSpec &spec = inp->spec();
...
int orientation = 0;
bool ok = spec.getattribute("Orientation", TypeInt, &orientation);
if (!ok) {
std::cout << "No integer orientation in the file\n";
}
inp = ImageInput.open (filename)
spec = in.spec()
orientation = spec.getattribute("Orientation")
if orientation is None :
print("No integer orientation in the file")
By convention, ImageInput plugins will save all integer metadata as 32-bit
integers (TypeDesc::INT
or TypeDesc::UINT
), even if the file format
dictates that a particular item is stored in the file as a 8- or 16-bit
integer. This is just to keep client applications from having to deal with
all the types. Since there is relatively little metadata compared to pixel
data, there’s no real memory waste of promoting all integer types to int32
metadata. Floating-point metadata and string metadata may also exist, of
course.
For certain common types, there is an even simpler method for retrieving the metadata:
int i = spec.get_int_attribute ("Orientation", 0);
float f = spec.get_float_attribute ("PixelAspectRatio", 1.0f);
std::string s = spec.get_string_attribute ("ImageDescription", "");
i = spec.get_int_attribute ("Orientation", 0)
f = spec.get_float_attribute ("PixelAspectRatio", 1.0)
s = spec.get_string_attribute ("ImageDescription", "")
This method simply returns the value. The second argument is the default
value to use if the attribute named is not found. These versions will do
automatic type conversion as well — for example, if you ask for a float
and the attribute is really an int, it will return the proper float for it;
or if the attribute is a UINT16 and you call get_int_attribute()
, it
will succeed, promoting to an int.
And finally, another convenience method lets you treat the spec itself as an associative array or dictionary:
// spec["key"].get<TYPE> tries to retrieve that type, or a default
// value (generally 0 or empty string) if not found.
int i = spec["Orientation"].get<int>();
float f = spec["PixelAspectRatio"].get<float>();
std::string s = spec["ImageDescription"].get<std::string>();
// An optional argument to get() lets you specify a different default
// value to return if the attribute is not found.
float f = spec["PixelAspectRatio"].get<float>(1.0f);
# spec["key"] returns the attribute if present, or raises KeyError
# if not found.
i = spec["Orientation"]
f = spec["PixelAspectRatio"]
s = spec["ImageDescription"]
# spec.get("key", default=None) returns the attribute if present,
# or the default value if not found.
val = spec.get("Orientation", 1)
Note that when retrieving with this “dictionary” syntax, the C++ and
Python behaviors are different: C++ requires a get<TYPE>()
call to
retrieve the full value, and a missing key will return a default value.
Python will return the value directly (no get()
needed), and a missing
key will raise a KeyError
exception.
It is also possible to step through all the metadata, item by item. This can be accomplished using the technique of the following example:
for (const auto &p : spec.extra_attribs) {
printf (" %s: %s\n", p.name().c_str(), p.get_string().c_str());
}
for p in spec.attribs :
printf (" ", p.name, ":", p.value)
Each individual ImageInput implementation should document the names, types, and meanings of all metadata attributes that they understand.
Color space hints#
We certainly hope that you are using only modern file formats that support high precision and extended range pixels (such as OpenEXR) and keeping all your images in a linear color space. But you may have to work with file formats that dictate the use of nonlinear color values. This is prevalent in formats that store pixels only as 8-bit values, since 256 values are not enough to linearly represent colors without banding artifacts in the dim values.
The ImageSpec::extra_attribs
field may store metadata that reveals the
color space the image file in the "oiio:ColorSpace"
attribute (see
Section Color information for explanations of particular values).
The ImageInput sets the "oiio:ColorSpace"
metadata in a purely advisory
capacity — the read
will not convert pixel values among color spaces.
Many image file formats only support nonlinear color spaces (for example,
JPEG/JFIF dictates use of sRGB). So your application should intelligently
deal with gamma-corrected and sRGB input, at the very least.
The color space hints only describe color channels. You should assume that
alpha or depth (z
) channels (designated by the alpha_channel
and
z_channel
fields, respectively) always represent linear values and
should never be transformed by your application.
Multi-image files and MIP-maps#
Some image file formats support multiple discrete subimages to be stored
in one file, and/or miltiple resolutions for each image to form a
MIPmap. When you open()
an ImageInput, it will by default point
to the first (i.e., number 0) subimage in the file, and the highest
resolution (level 0) MIP-map level. You can switch to viewing another
subimage or MIP-map level using the seek_subimage()
function:
auto inp = ImageInput::open (filename);
int subimage = 1;
int miplevel = 0;
if (inp->seek_subimage (subimage, miplevel)) {
... process the subimage/miplevel ...
} else {
... no such subimage/miplevel ...
}
inp = ImageInput.open(filename)
subimage = 1
miplevel = 0
if inp.seek_subimage (subimage, miplevel) :
# ... process the subimage/miplevel ...
else :
# ... no such subimage/miplevel ...
The seek_subimage()
function takes three arguments: the index of the
subimage to switch to (starting with 0), the MIPmap level (starting with 0
for the highest-resolution level), and a reference to an ImageSpec, into
which will be stored the spec of the new subimage/miplevel. The
seek_subimage()
function returns true
upon success, and false
if
no such subimage or MIP level existed. It is legal to visit subimages and
MIP levels out of order; the ImageInput is responsible for making it work
properly. It is also possible to find out which subimage and MIP level is
currently being viewed, using the current_subimage()
and
current_miplevel()
functions, which return the index of the current
subimage and MIP levels, respectively.
Below is pseudocode for reading all the levels of a MIP-map (a multi-resolution image used for texture mapping) that shows how to read multi-image files:
auto inp = ImageInput::open (filename);
int miplevel = 0;
while (inp->seek_subimage (0, miplevel)) {
const ImageSpec &spec = inp->spec();
int npixels = spec.width * spec.height;
int nchannels = spec.nchannels;
auto pixels = std::unique_ptr<unsigned char[]>(new unsigned char[npixels * nchannels]);
inp->read_image(0, miplevel, 0, nchannels, TypeDesc::UINT8, pixels);
// ... do whatever you want with this level, in pixels ...
++miplevel;
}
// Note: we break out of the while loop when seek_subimage fails
// to find a next MIP level.
inp->close();
inp = ImageInput::open (filename)
miplevel = 0
while inp.seek_subimage(0, miplevel) :
spec = inp.spec()
nchannels = spec.nchannels
pixels = inp.read_image (0, miplevel, 0, nchannels, "uint8")
# ... do whatever you want with this level, in pixels ...
miplevel += 1
}
# Note: we break out of the while loop when seek_subimage fails
# to find a next MIP level.
inp.close()
In this example, we have used read_image()
, but of course
read_scanline()
and read_tile()
work as you would expect, on the
current subimage and MIP level.
Per-channel formats#
Some image formats allow separate per-channel data formats (for example,
half
data for colors and float
data for depth). If you want to read
the pixels in their true native per-channel formats, the following steps are
necessary:
Check the ImageSpec’s
channelformats
vector. If non-empty, the channels in the file do not all have the same format.When calling
read_scanline
,read_scanlines
,read_tile
,read_tiles
, orread_image
, pass a format ofTypeUnknown
to indicate that you would like the raw data in native per-channel format of the file written to yourdata
buffer.
For example, the following code fragment will read a 5-channel image to an
OpenEXR file, consisting of R/G/B/A channels in half
and a Z channel in
float
:
auto inp = ImageInput::open (filename);
const ImageSpec &spec = inp->spec();
// Allocate enough space
auto pixels = std::unique_ptr<unsigned char[]>(new unsigned char[spec.image_bytes(true)]);
int nchannels = spec.nchannels;
inp->read_image(0, 0, 0, nchannels,
TypeDesc::UNKNOWN, /* use native channel formats */
pixels); /* data buffer */
if (spec.channelformats.size() > 0) {
... the buffer contains packed data in the native
per-channel formats ...
} else {
... the buffer contains all data per spec.format ...
}
Reading “deep” data#
Some image file formats (OpenEXR only, at this time) support the concept of
“deep” pixels – those containing multiple samples per pixel (and a
potentially differing number of them in each pixel). You can tell an image
is “deep” from its ImageSpec: the deep
field will be true
.
Deep files cannot be read with the usual read_scanline()
,
read_scanlines()
, read_tile()
, read_tiles()
, read_image()
functions, due to the nature of their variable number of samples per pixel.
Instead, ImageInput has three special member functions used only for reading
deep data:
bool read_native_deep_scanlines (int subimage, int miplevel,
int ybegin, int yend, int z,
int chbegin, int chend,
DeepData &deepdata);
bool read_native_deep_tiles (int subimage, int miplevel,
int xbegin, int xend, int ybegin int yend,
int zbegin, int zend,
int chbegin, int chend, DeepData &deepdata);
bool read_native_deep_image (int subimage, int miplevel,
DeepData &deepdata);
ImageInput.read_native_deep_scanlines (subimage, miplevel,
ybegin, yend, z, chbegin, chend)
ImageInput.read_native_deep_tiles (subimage, miplevel, xbegin, xend,
ybegin yend, zbegin, zend, chbegin, chend)
ImageInput.read_native_deep_image (subimage, miplevel)
It is only possible to read “native” data types from deep files; that is, there is no automatic translation into arbitrary data types as there is for ordinary images. All three of these functions store the resulting deep data in a special DeepData structure, described in detail in Section Reading “deep” data.
Here is an example of using these methods to read a deep image from a file and print all its values:
auto inp = ImageInput::open (filename);
if (! inp)
return;
const ImageSpec &spec = inp.spec();
if (spec.deep) {
DeepData deepdata;
inp.read_native_deep_image (0, 0, deepdata);
int p = 0; // absolute pixel number
for (int y = 0; y < spec.height; ++y) {
for (int x = 0; x < spec.width; ++x, ++p) {
std::cout << "Pixel " << x << "," << y << ":\n";
if (deepdata.samples(p) == 0)
std::cout << " no samples\n";
else
for (int c = 0; c < spec.nchannels; ++c) {
TypeDesc type = deepdata.channeltype(c);
std::cout << " " << spec.channelnames[c] << ": ";
void *ptr = deepdata.pointers[p*spec.nchannels+c]
for (int s = 0; s < deepdata.samples(p); ++s) {
if (type.basetype == TypeDesc::FLOAT ||
type.basetype == TypeDesc::HALF)
std::cout << deepdata.deep_value(p, c, s) << ' ';
else if (type.basetype == TypeDesc::UINT32)
std::cout << deepdata.deep_value_uint(p, c, s) << ' ';
}
std::cout << "\n";
}
}
}
}
inp.close ();
inp = ImageInput::open (filename)
if inp is None :
return
spec = inp.spec()
if spec.deep :
deepdata = inp.read_native_deep_image (0, 0)
p = 0 # absolute pixel number
for y in range(spec.height) :
for x in range(spec.width) :
print ("Pixel", x, ",", y, ":")
if deepdata.samples(p) == 0 :
print(" no samples)
else :
for c in range(spec.nchannels) :
type = deepdata.channeltype(c)
print (" ", spec.channelnames[c], ":")
for s in range(deepdata.samples(p) :
print (deepdata.deep_value(p, c, s), end="")
print("")
inp.close()
Opening for input with configuration settings/hints#
Sometimes you will want to give the image file reader hints or requests for how to open the file or present its data, hints which must be made in time for the initial opening of the file. For example, in specific circumstances, you might want to request that an image with unassociated alpha not be automatically converted to associated alpha by multiplying the color channel values by the alpha (as would be customary by OIIO convention).
This is accomplished by using the ImageInput::open()
or
ImageInput::create()
method varieties that take an additional config
parameter. This is an ImageSpec
object whose metadata contains the
configuration hints.
Configuration hints are optional and advisory only – meaning that not all image file readers will respect them (and indeed, many of them are only sensible for certain file formats).
Some common input configuration hints that tend to be respected across many readers (but not all, check Chapter Bundled ImageIO Plugins to see what hints are supported by each reader) are:
Input Configuration Attribute |
Type |
Meaning |
---|---|---|
|
ptr |
Pointer to a |
|
int |
If nonzero, reading images with non-RGB color models (such as YCbCr) will return unaltered pixel values (versus the default OIIO behavior of automatically converting to RGB). |
|
int |
If nonzero, and the file contains unassociated alpha, this will cause the reader to leave alpha unassociated (versus the default of premultiplying color channels by alpha if the alpha channel is unassociated). |
|
int |
If zero, disables any automatic reorientation that the reader may ordinarily do to present te pixels in the preferred display orientation. |
Examples:
Below is an example where we wish to read in an RGBA image in a format that tends to store it as unassociated alpha, but we DON’T want it to automatically be converted to associated alpha.
// Set up an ImageSpec that holds the configuration hints. ImageSpec config; config["oiio:UnassociatedAlpha"] = 1; // Open the file, passing in the config. auto inp = ImageInput::open (filename, &config); const ImageSpec &spec = inp->spec(); auto pixels = std::unique_ptr<unsigned char[]>(new unsigned char[spec.image_pixels() * spec.nchannels]); inp->read_image (0, 0, 0, spec.nchannels, TypeDesc::UINT8, &pixels[0]); if (spec.get_int_attribute("oiio:UnassociatedAlpha")) printf("pixels holds unassociated alpha\n"); else printf("pixels holds associated alpha\n");# Set up an ImageSpec that holds the configuration hints. config = oiio.ImageSpec() config["oiio:UnassociatedAlpha"] = 1 # Open the file, passing in the config. inp = oiio.ImageInput.open (filename, config) spec = inp.spec() pixels = inp.read_image (0, 0, 0, spec.nchannels, "uint8") if (spec["oiio:UnassociatedAlpha"] == 1): print("pixels holds unassociated alpha") else: print("pixels holds associated alpha")
Custom I/O proxies (and reading the file from a memory buffer)#
Some file format readers allow you to supply a custom I/O proxy object that can allow bypassing the usual file I/O with custom behavior, including the ability to read the file form an in-memory buffer rather than reading from disk.
Only some input format readers support this feature. To find out if a
particular file format supports this feature, you can create an ImageInput
of the right type, and check if it supports the feature name "ioproxy"
:
auto in = ImageInput::create(filename);
if (! in || ! in->supports ("ioproxy")) {
return;
}
ImageInput readers that support "ioproxy"
will respond to a special
attribute, "oiio:ioproxy"
, which passes a pointer to a
Filesystem::IOProxy*
(see OpenImageIO’s filesystem.h
for this
type and its subclasses). IOProxy is an abstract type, and concrete
subclasses include IOFile
(which wraps I/O to an open FILE*
) and
IOMemReader
(which reads input from a block of memory).
Here is an example of using a proxy that reads the “file” from a memory buffer:
const void *buf = ...; // pointer to memory block
size_t size = ...; // length of memory block
Filesystem::IOMemReader memreader (buf, size); // I/O proxy object
auto in = ImageInput::open ("in.exr", nullptr, &memreader);
in->read_image (...);
in->close();
// That will have read the "file" from the memory buffer
Custom search paths for plugins#
Please see Section Global Attributes for discussion about setting the
plugin search path via the attribute()
function. For example:
std::string mysearch = "/usr/myapp/lib:/home/jane/plugins";
OIIO::attribute ("plugin_searchpath", mysearch);
auto inp = ImageInput::open (filename);
// ...
mysearch = "/usr/myapp/lib:/home/jane/plugins"
OpenImageIO.attribute ("plugin_searchpath", mysearch)
inp = ImageInput.open(filename)
# ...
Error checking#
Nearly every ImageInput API function returns a bool
indicating whether
the operation succeeded (true
) or failed (false
). In the case of a
failure, the ImageInput will have saved an error message describing in more
detail what went wrong, and the latest error message is accessible using the
ImageInput method geterror()
, which returns the message as a
std::string
.
The exceptions to this rule are static methods such as the static
ImageInput::open()
and ImageInput::create()
, which return an empty
pointer if it could not create an appropriate ImageInput (and open it, in
the case of open()
. In such a case, since no ImageInput is returned for
which you can call its geterror()
function, there exists a global
geterror()
function (in the OpenImageIO
namespace) that retrieves
the latest error message resulting from a call to static open()
or
create()
.
Here is another version of the simple image reading code from Section Image Input Made Simple, but this time it is fully elaborated with error checking and reporting:
#include <OpenImageIO/imageio.h>
using namespace OIIO;
void error_checking()
{
const char *filename = "tahoe.tif";
auto inp = ImageInput::open (filename);
if (! inp) {
std::cerr << "Could not open " << filename
<< ", error = " << OIIO::geterror() << "\n";
return;
}
const ImageSpec &spec = inp->spec();
int xres = spec.width;
int yres = spec.height;
int nchannels = spec.nchannels;
auto pixels = std::unique_ptr<unsigned char[]>(new unsigned char[xres * yres * nchannels]);
if (! inp->read_image(0, 0, 0, nchannels, TypeDesc::UINT8, &pixels[0])) {
std::cerr << "Could not read pixels from " << filename
<< ", error = " << inp->geterror() << "\n";
return;
}
if (! inp->close ()) {
std::cerr << "Error closing " << filename
<< ", error = " << inp->geterror() << "\n";
return;
}
}
import OpenImageIO as oiio
import numpy as np
filename = "tahoe.tif"
inp = oiio.ImageInput.open(filename)
if inp is None :
print("Could not open", filename, ", error =", oiio.geterror())
return
spec = inp.spec()
xres = spec.width
yres = spec.height
nchannels = spec.nchannels
pixels = inp.read_image(0, 0, 0, nchannels, "uint8")
if pixels is None :
print("Could not read pixels from", filename, ", error =", inp.geterror())
return
if not inp.close() :
print("Error closing", filename, ", error =", inp.geterror())
return
ImageInput Class Reference#
-
class ImageInput#
ImageInput abstracts the reading of an image file in a file format-agnostic manner.
IOProxy aids for ImageInput implementations.
This set of utility functions are not meant to be called by user code. They are protected methods of ImageInput, and are used internally by the ImageInput implementation to help it properly implement support of IOProxy.
Creating an ImageInput
-
static unique_ptr open(const std::string &filename, const ImageSpec *config = nullptr, Filesystem::IOProxy *ioproxy = nullptr)#
Create an ImageInput subclass instance that is able to read the given file and open it, returning a
unique_ptr
to the ImageInput if successful. Theunique_ptr
is set up with an appropriate deleter so the ImageInput will be properly closed and deleted when theunique_ptr
goes out of scope or is reset. If the open fails, return an emptyunique_ptr
and set an error that can be retrieved byOIIO::geterror()
.The
config
, if not nullptr, points to an ImageSpec giving hints, requests, or special instructions. ImageInput implementations are free to not respond to any such requests, so the default implementation is just to ignoreconfig
.open()
will first try to make an ImageInput corresponding to the format implied by the file extension (for example,"foo.tif"
will try the TIFF plugin), but if one is not found or if the inferred one does not open the file, every known ImageInput type will be tried until one is found that will open the file.- Parameters:
filename – The name of the file to open, UTF-8 encoded.
config – Optional pointer to an ImageSpec whose metadata contains “configuration hints.”
ioproxy – Optional pointer to an IOProxy to use (not supported by all formats, see
supports("ioproxy")
). The caller retains ownership of the proxy.
- Returns:
A
unique_ptr
that will close and free the ImageInput when it exits scope or is reset. The pointer will be empty if the required writer was not able to be created.
-
static inline unique_ptr open(const std::wstring &filename, const ImageSpec *config = nullptr, Filesystem::IOProxy *ioproxy = nullptr)#
Create and open an ImageInput using a UTF-16 encoded wstring filename.
-
static unique_ptr create(string_view filename, bool do_open = false, const ImageSpec *config = nullptr, Filesystem::IOProxy *ioproxy = nullptr, string_view plugin_searchpath = "")#
Create and return an ImageInput implementation that is able to read the given file or format. If
do_open
is true (and thefilename
is the name of a file, not just a format), fully open it if possible (using the optionalconfig
configuration spec, if supplied), otherwise just create the ImageInput but don’t open it. The plugin_searchpath parameter is an override of the searchpath. colon-separated list of directories to search for ImageIO plugin DSO/DLL’s (not a searchpath for the image itself!).If the
filename
parameter is the name of a file format (such as “openexr”), it will create an ImageInput that reads that particular format. If the name is a file extension (such as “exr” or “.exr”), it will guess the file format from the extension and return that type of ImageInput.If
filename
is a full file name (such as “hawaii.exr”), it will create an ImageInput that reads the format implied by the file extension (“.tif”) and try to open the file with that reader. If the file can be opened and appears to be of the correct type, then that ImageInput (after being closed) will be returned to the caller. But if it fails (say, because the file type does not match the extension), then every known kind of image reader will be tried in turn, until one can be found that succeeds in opening that file. Thecreate()
file will fail entirely only if no known image reader type succeeds.If the caller intends to immediately open the file, then it is often simpler to call static
ImageInput::open()
.- Parameters:
filename – The name of an image file, or a file extension, or the name of a file format. The filename is UTF-8 encoded.
do_open – If
true
, not only create but also open the file.config – Optional pointer to an ImageSpec whose metadata contains “configuration hints” for the ImageInput implementation.
ioproxy – Optional pointer to an IOProxy to use (not supported by all formats, see
supports("ioproxy")
). The caller retains ownership of the proxy. If this is not supplied, it is still possible to set the proxy with a call toset_proxy()
prior toopen()
.plugin_searchpath – An optional colon-separated list of directories to search for OpenImageIO plugin DSO/DLL’s.
- Returns:
A
unique_ptr
that will close and free the ImageInput when it exits scope or is reset. The pointer will be empty if the required writer was not able to be created.
-
static inline unique_ptr create(const std::wstring &filename, bool do_open = false, const ImageSpec *config = nullptr, Filesystem::IOProxy *ioproxy = nullptr, string_view plugin_searchpath = "")#
Create an ImageInput using a UTF-16 encoded wstring filename.
Reading pixels
Common features of all the
read
methods:The
format
parameter describes the data type of thedata[]
buffer. The read methods automatically convert the data from the data type it is stored in the file into theformat
of thedata
buffer. Ifformat
isTypeUnknown
it will just copy pixels of file’s native data layout (including, possibly, per-channel data formats as specified by the ImageSpec’schannelformats
field).The
stride
values describe the layout of thedata
buffer:xstride
is the distance in bytes between successive pixels within each scanline.ystride
is the distance in bytes between successive scanlines. For volumetric imageszstride
is the distance in bytes between successive “volumetric planes”. Strides set to the special valueAutoStride
imply contiguous data, i.e.,xstride = format.size() * nchannels ystride = xstride * width zstride = ystride * height
Any range parameters (such as
ybegin
andyend
) describe a “half open interval”, meaning thatbegin
is the first item andend
is one past the last item. That means that the number of items isend - begin
.For ordinary 2D (non-volumetric) images, any
z
orzbegin
coordinates should be 0 and anyzend
should be 1, indicating that only a single image “plane” exists.Some read methods take a channel range [chbegin,chend) to allow reading of a contiguous subset of channels (chbegin=0, chend=spec.nchannels reads all channels).
ImageInput readers are expected to give the appearance of random access — in other words, if it can’t randomly seek to the given scanline or tile, it should transparently close, reopen, and sequentially read through prior scanlines.
All read functions return
true
for success,false
for failure (after which a call togeterror()
may retrieve a specific error message).
-
virtual bool read_scanline(int y, int z, TypeDesc format, void *data, stride_t xstride = AutoStride)#
Read the scanline that includes pixels (*,y,z) from the “current” subimage and MIP level. The
xstride
value gives the distance between successive pixels (in bytes). Strides set toAutoStride
imply “contiguous” data.Note
This variety of
read_scanline
is not re-entrant nor thread-safe. If you require concurrent reads to the same open ImageInput, you should useread_scanlines
that has thesubimage
andmiplevel
passed explicitly.- Parameters:
y/z – The y & z coordinates of the scanline. For 2D images, z should be 0.
format – A TypeDesc describing the type of
data
.data – Pointer to the pixel data buffer.
xstride – The distance in bytes between successive pixels in
data
(orAutoStride
).
- Returns:
true
upon success, orfalse
upon failure.
-
inline bool read_scanline(int y, int z, float *data)#
Simple read_scanline reads into contiguous float pixels.
-
virtual bool read_scanlines(int subimage, int miplevel, int ybegin, int yend, int z, int chbegin, int chend, TypeDesc format, void *data, stride_t xstride = AutoStride, stride_t ystride = AutoStride)#
Read multiple scanlines that include pixels (*,y,z) for all ybegin <= y < yend in the specified subimage and mip level, into
data
, using the strides given and converting to the requested dataformat
(TypeUnknown indicates no conversion, just copy native data types). Only channels [chbegin,chend) will be read/copied (chbegin=0, chend=spec.nchannels reads all channels, yielding equivalent behavior to the simpler variant ofread_scanlines
).This version of read_scanlines, because it passes explicit subimage/miplevel, does not require a separate call to seek_subimage, and is guaranteed to be thread-safe against other concurrent calls to any of the read_* methods that take an explicit subimage/miplevel (but not against any other ImageInput methods).
Note
This call was changed for OpenImageIO 2.0 to include the explicit subimage and miplevel parameters.
- Parameters:
subimage – The subimage to read from (starting with 0).
miplevel – The MIP level to read (0 is the highest resolution level).
ybegin/yend – The y range of the scanlines being passed.
z – The z coordinate of the scanline.
chbegin/chend – The channel range to read.
format – A TypeDesc describing the type of
data
.data – Pointer to the pixel data.
xstride/ystride – The distance in bytes between successive pixels and scanlines (or
AutoStride
).
- Returns:
true
upon success, orfalse
upon failure.
-
virtual bool read_tile(int x, int y, int z, TypeDesc format, void *data, stride_t xstride = AutoStride, stride_t ystride = AutoStride, stride_t zstride = AutoStride)#
Read the tile whose upper-left origin is (x,y,z) into
data[]
, converting if necessary from the native data format of the file into theformat
specified. The stride values give the data spacing of adjacent pixels, scanlines, and volumetric slices (measured in bytes). Strides set to AutoStride imply ‘contiguous’ data in the shape of a full tile, i.e.,xstride = format.size() * spec.nchannels ystride = xstride * spec.tile_width zstride = ystride * spec.tile_height
Note
This variety of
read_tile
is not re-entrant nor thread-safe. If you require concurrent reads to the same open ImageInput, you should useread_tiles()
that has thesubimage
andmiplevel
passed explicitly.Note
This call will fail if the image is not tiled, or if (x,y,z) is not the upper left corner coordinates of a tile.
- Parameters:
x/y/z – The upper left coordinate of the tile being passed.
format – A TypeDesc describing the type of
data
.data – Pointer to the pixel data.
xstride/ystride/zstride – The distance in bytes between successive pixels, scanlines, and image planes (or
AutoStride
to indicate a “contiguous” single tile).
- Returns:
true
upon success, orfalse
upon failure.
-
inline bool read_tile(int x, int y, int z, float *data)#
Simple read_tile reads into contiguous float pixels.
-
virtual bool read_tiles(int subimage, int miplevel, int xbegin, int xend, int ybegin, int yend, int zbegin, int zend, int chbegin, int chend, TypeDesc format, void *data, stride_t xstride = AutoStride, stride_t ystride = AutoStride, stride_t zstride = AutoStride)#
Read the block of multiple tiles that include all pixels in
This is analogous to calling[xbegin,xend) X [ybegin,yend) X [zbegin,zend)
read_tile(x,y,z,...)
for each tile in turn (but for some file formats, reading multiple tiles may allow it to read more efficiently or in parallel).The begin/end pairs must correctly delineate tile boundaries, with the exception that it may also be the end of the image data if the image resolution is not a whole multiple of the tile size. The stride values give the data spacing of adjacent pixels, scanlines, and volumetric slices (measured in bytes). Strides set to AutoStride imply contiguous data in the shape of the [begin,end) region, i.e.,
This version of read_tiles, because it passes explicit subimage and miplevel, does not require a separate call to seek_subimage, and is guaranteed to be thread-safe against other concurrent calls to any of the read_* methods that take an explicit subimage/miplevel (but not against any other ImageInput methods).xstride = format.size() * spec.nchannels ystride = xstride * (xend-xbegin) zstride = ystride * (yend-ybegin)
Note
The call will fail if the image is not tiled, or if the pixel ranges do not fall along tile (or image) boundaries, or if it is not a valid tile range.
- Parameters:
subimage – The subimage to read from (starting with 0).
miplevel – The MIP level to read (0 is the highest resolution level).
xbegin/xend – The x range of the pixels covered by the group of tiles being read.
ybegin/yend – The y range of the pixels covered by the tiles.
zbegin/zend – The z range of the pixels covered by the tiles (for a 2D image, zbegin=0 and zend=1).
chbegin/chend – The channel range to read.
format – A TypeDesc describing the type of
data
.data – Pointer to the pixel data.
xstride/ystride/zstride – The distance in bytes between successive pixels, scanlines, and image planes (or
AutoStride
).
- Returns:
true
upon success, orfalse
upon failure.
-
virtual bool read_image(int subimage, int miplevel, int chbegin, int chend, TypeDesc format, void *data, stride_t xstride = AutoStride, stride_t ystride = AutoStride, stride_t zstride = AutoStride, ProgressCallback progress_callback = NULL, void *progress_callback_data = NULL)#
Read the entire image of
spec.width x spec.height x spec.depth
pixels into a buffer with the given strides and in the desired data format.Depending on the spec, this will read either all tiles or all scanlines. Assume that data points to a layout in row-major order.
This version of read_image, because it passes explicit subimage and miplevel, does not require a separate call to seek_subimage, and is guaranteed to be thread-safe against other concurrent calls to any of the read_* methods that take an explicit subimage/miplevel (but not against any other ImageInput methods).
Because this may be an expensive operation, a progress callback may be passed. Periodically, it will be called as follows:
whereprogress_callback (progress_callback_data, float done);
done
gives the portion of the image (between 0.0 and 1.0) that has been written thus far.- Parameters:
subimage – The subimage to read from (starting with 0).
miplevel – The MIP level to read (0 is the highest resolution level).
chbegin/chend – The channel range to read. If chend is -1, it will be set to spec.nchannels.
format – A TypeDesc describing the type of
data
.data – Pointer to the pixel data.
xstride/ystride/zstride – The distance in bytes between successive pixels, scanlines, and image planes (or
AutoStride
).progress_callback/progress_callback_data – Optional progress callback.
- Returns:
true
upon success, orfalse
upon failure.
-
virtual bool read_native_deep_scanlines(int subimage, int miplevel, int ybegin, int yend, int z, int chbegin, int chend, DeepData &deepdata)#
Read deep scanlines containing pixels (*,y,z), for all y in the range [ybegin,yend) into
deepdata
. This will fail if it is not a deep file.- Parameters:
subimage – The subimage to read from (starting with 0).
miplevel – The MIP level to read (0 is the highest resolution level).
chbegin/chend – The channel range to read.
ybegin/yend – The y range of the scanlines being passed.
z – The z coordinate of the scanline.
deepdata – A
DeepData
object into which the data for these scanlines will be placed.
- Returns:
true
upon success, orfalse
upon failure.
-
virtual bool read_native_deep_tiles(int subimage, int miplevel, int xbegin, int xend, int ybegin, int yend, int zbegin, int zend, int chbegin, int chend, DeepData &deepdata)#
Read into
deepdata
the block of native deep data tiles that include all pixels and channels specified by pixel range.Note
The call will fail if the image is not tiled, or if the pixel ranges do not fall along tile (or image) boundaries, or if it is not a valid tile range.
- Parameters:
subimage – The subimage to read from (starting with 0).
miplevel – The MIP level to read (0 is the highest resolution level).
xbegin/xend – The x range of the pixels covered by the group of tiles being read.
ybegin/yend – The y range of the pixels covered by the tiles.
zbegin/zend – The z range of the pixels covered by the tiles (for a 2D image, zbegin=0 and zend=1).
chbegin/chend – The channel range to read.
deepdata – A
DeepData
object into which the data for these tiles will be placed.
- Returns:
true
upon success, orfalse
upon failure.
-
virtual bool read_native_deep_image(int subimage, int miplevel, DeepData &deepdata)#
Read the entire deep data image of spec.width x spec.height x spec.depth pixels, all channels, into
deepdata
.- Parameters:
subimage – The subimage to read from (starting with 0).
miplevel – The MIP level to read (0 is the highest resolution level).
deepdata – A
DeepData
object into which the data for the image will be placed.
- Returns:
true
upon success, orfalse
upon failure.
Reading native pixels – implementation overloads
Note
read_native_* methods are usually not directly called by user code (except for read_native_deep_* varieties). These are the methods that are overloaded by the ImageInput subclasses that implement the individual file format readers.
-
virtual bool read_native_scanline(int subimage, int miplevel, int y, int z, void *data) = 0#
Read a single scanline (all channels) of native data into contiguous memory.
-
virtual bool read_native_scanlines(int subimage, int miplevel, int ybegin, int yend, int z, void *data)#
Read a range of scanlines (all channels) of native data into contiguous memory.
-
virtual bool read_native_scanlines(int subimage, int miplevel, int ybegin, int yend, int z, int chbegin, int chend, void *data)#
Read a range of scanlines (with optionally a subset of channels) of native data into contiguous memory.
-
virtual bool read_native_tile(int subimage, int miplevel, int x, int y, int z, void *data)#
Read a single tile (all channels) of native data into contiguous memory. The base class read_native_tile fails. A format reader that supports tiles MUST overload this virtual method that reads a single tile (all channels).
-
virtual bool read_native_tiles(int subimage, int miplevel, int xbegin, int xend, int ybegin, int yend, int zbegin, int zend, void *data)#
Read multiple tiles (all channels) of native data into contiguous memory. A format reader that supports reading multiple tiles at once (in a way that’s more efficient than reading the tiles one at a time) is advised (but not required) to overload this virtual method. If an ImageInput subclass does not overload this, the default implementation here is simply to loop over the tiles, calling the single-tile read_native_tile() for each one.
-
virtual bool read_native_tiles(int subimage, int miplevel, int xbegin, int xend, int ybegin, int yend, int zbegin, int zend, int chbegin, int chend, void *data)#
Read multiple tiles (potentially a subset of channels) of native data into contiguous memory. A format reader that supports reading multiple tiles at once, and can handle a channel subset while doing so, is advised (but not required) to overload this virtual method. If an ImageInput subclass does not overload this, the default implementation here is simply to loop over the tiles, calling the single-tile read_native_tile() for each one (and copying carefully to handle the channel subset issues).
Public Types
-
using unique_ptr = std::unique_ptr<ImageInput>#
unique_ptr to an ImageInput
-
typedef std::lock_guard<const ImageInput&> lock_guard#
The presence of lock() and unlock() establish an ImageInput itself as having the BasicLockable concept and therefore can be used by std::lock_guard.
-
typedef ImageInput *(*Creator)()#
Call signature of a function that creates and returns an
ImageInput*
.
Public Functions
-
virtual const char *format_name(void) const = 0#
Return the name of the format implemented by this class.
-
inline virtual int supports(string_view feature) const#
Given the name of a “feature”, return whether this ImageInput supports output of images with the given properties. Most queries will simply return 0 for “doesn’t support” and 1 for “supports it,” but it is acceptable to have queries return other nonzero integers to indicate varying degrees of support or limits (but should be clearly documented as such).
Feature names that ImageInput implementations are expected to recognize include:
"arbitrary_metadata"
: Does this format allow metadata with arbitrary names and types?"exif"
: Can this format store Exif camera data?"ioproxy"
: Does this format reader support reading from anIOProxy
?"iptc"
: Can this format store IPTC data?"procedural"
: Can this format create images without reading from a disk file?"thumbnail"
: Does this format reader support retrieving a reduced resolution copy of the image via thethumbnail()
method?"multiimage"
: Does this format support multiple subimages within a file? (Note: this doesn’t necessarily mean that the particular file this ImageInput is reading has multiple subimages.)"noimage"
: Does this format allow 0x0 sized images, i.e. an image file with metadata only and no pixels?
This list of queries may be extended in future releases. Since this can be done simply by recognizing new query strings, and does not require any new API entry points, addition of support for new queries does not break `link compatibility’ with previously-compiled plugins.
-
virtual bool valid_file(const std::string &filename) const#
Return true if the
filename
names a file of the type for this ImageInput. The implementation will try to determine this as efficiently as possible, in most cases much less expensively than doing a fullopen()
. Note that there can be false positives: a file can appear to be of the right type (i.e.,valid_file()
returningtrue
) but still fail a subsequent call toopen()
, such as if the contents of the file are truncated, nonsensical, or otherwise corrupted. The filename is UTF-8 encoded.- Returns:
true
upon success, orfalse
upon failure.
-
inline bool valid_file(const std::wstring &filename) const#
Check valid file using a UTF-16 encoded wstring filename.
-
virtual bool valid_file(Filesystem::IOProxy *ioproxy) const#
Return true if the
ioproxy
represents a file of the type for this ImageInput. The implementation will try to determine this as efficiently as possible, in most cases much less expensively than doing a fullopen()
. Note that there can be false positives: a file can appear to be of the right type (i.e.,valid_file()
returningtrue
) but still fail a subsequent call toopen()
, such as if the contents of the file are truncated, nonsensical, or otherwise corrupted.- Returns:
true
upon success, orfalse
upon failure.
-
virtual bool open(const std::string &name, ImageSpec &newspec) = 0#
Opens the file with given name and seek to the first subimage in the file. Various file attributes are put in
newspec
and a copy is also saved internally to theImageInput
(retrievable viaspec()
. From examiningnewspec
orspec()
, you can discern the resolution, if it’s tiled, number of channels, native data format, and other metadata about the image.- Parameters:
name – Filename to open, UTF-8 encoded.
newspec – Reference to an ImageSpec in which to deposit a full description of the contents of the first subimage of the file.
- Returns:
true
if the file was found and opened successfully.
-
inline bool open(const std::wstring &name, ImageSpec &newspec)#
Open the ImageInput using a UTF-16 encoded wstring filename.
-
inline virtual bool open(const std::string &name, ImageSpec &newspec, const ImageSpec &config)#
Open file with given name, similar to
open(name,newspec)
. Theconfig
is an ImageSpec giving requests or special instructions. ImageInput implementations are free to not respond to any such requests, so the default implementation is just to ignore config and call regularopen(name,newspec)
.- Parameters:
name – Filename to open, UTF-8 encoded.
newspec – Reference to an ImageSpec in which to deposit a full description of the contents of the first subimage of the file.
config – An ImageSpec whose metadata contains “configuration hints” for the ImageInput implementation.
- Returns:
true
if the file was found and opened successfully.
-
inline bool open(const std::wstring &name, ImageSpec &newspec, const ImageSpec &config)#
Open the ImageInput using a UTF-16 encoded wstring filename.
-
inline virtual const ImageSpec &spec(void) const#
Return a reference to the image specification of the current subimage/MIPlevel. Note that the contents of the spec are invalid before
open()
or afterclose()
, and may change with a call toseek_subimage()
. It is thus not thread-safe, since the spec may change if another thread callsseek_subimage
, or any of theread_*()
functions that take explicit subimage/miplevel.
-
virtual ImageSpec spec(int subimage, int miplevel = 0)#
Return a full copy of the ImageSpec of the designated subimage and MIPlevel. This method is thread-safe, but it is potentially expensive, due to the work that needs to be done to fully copy an ImageSpec if there is lots of named metadata to allocate and copy. See also the less expensive
spec_dimensions()
. Errors (such as having requested a nonexistent subimage) are indicated by returning an ImageSpec withformat==TypeUnknown
.
-
virtual ImageSpec spec_dimensions(int subimage, int miplevel = 0)#
Return a copy of the ImageSpec of the designated subimage and miplevel, but only the dimension and type fields. Just as with a call to
ImageSpec::copy_dimensions()
, neither the channel names nor any of the arbitrary named metadata will be copied, thus this is a relatively inexpensive operation if you don’t need that information. It is guaranteed to be thread-safe. Errors (such as having requested a nonexistent subimage) are indicated by returning an ImageSpec withformat==TypeUnknown
.
-
inline virtual bool get_thumbnail(ImageBuf &thumb, int subimage)#
Retrieve a reduced-resolution (“thumbnail”) version of the given subimage. It is guaranteed to be thread-safe.
Note
This method was added to OpenImageIO 2.3.
- Parameters:
thumb – A reference to an
ImageBuf
which will be overwritten with the thumbnail image.subimage – The index of the subimage in the file whose thumbnail is to be retrieved.
- Returns:
true
upon success,false
if no thumbnail was available, or if this file format (or reader) does not support thumbnails.
-
virtual bool close() = 0#
Close an open ImageInput. The call to close() is not strictly necessary if the ImageInput is destroyed immediately afterwards, since it is required for the destructor to close if the file is still open.
- Returns:
true
upon success, orfalse
upon failure.
-
inline virtual int current_subimage(void) const#
Returns the index of the subimage that is currently being read. The first subimage (or the only subimage, if there is just one) is number 0.
-
inline virtual int current_miplevel(void) const#
Returns the index of the MIPmap image that is currently being read. The highest-res MIP level (or the only level, if there is just one) is number 0.
-
inline virtual bool seek_subimage(int subimage, int miplevel)#
Seek to the given subimage and MIP-map level within the open image file. The first subimage of the file has index 0, the highest- resolution MIP level has index 0. The new subimage’s vital statistics=may be retrieved by
this->spec()
. The reader is expected to give the appearance of random access to subimages and MIP levels — in other words, if it can’t randomly seek to the given subimage/level, it should transparently close, reopen, and sequentially read through prior subimages and levels.- Returns:
true
upon success, orfalse
upon failure. A failure may indicate that no such subimage or MIP level exists in the file.
-
virtual bool set_ioproxy(Filesystem::IOProxy *ioproxy)#
Set an IOProxy for this reader. This must be called prior to
open()
, and only for readers that support them (supports("ioproxy")
). The caller retains ownership of the proxy.- Returns:
true
for success,false
for failure.
-
bool has_error() const#
Is there a pending error message waiting to be retrieved, that resulted from an ImageInput API call made by the this thread?
Note that any
error()
calls issued are thread-specific, and thegeterror()/has_error()
are expected to be called by the same thread that called whichever API function encountered an error.
-
std::string geterror(bool clear = true) const#
Return the text of all pending error messages issued against this ImageInput by the calling thread, and clear the pending error message unless
clear
is false. If no error message is pending, it will return an empty string.Note that any
error()
calls issued are thread-specific, and thegeterror()/has_error()
are expected to be called by the same thread that called whichever API function encountered an error.
-
template<typename ...Args>
inline void errorfmt(const char *fmt, const Args&... args) const# Error reporting for the plugin implementation: call this with std::format-like arguments. It is not necessary to have the error message contain a trailing newline.
-
void threads(int n)#
Set the threading policy for this ImageInput, controlling the maximum amount of parallelizing thread “fan-out” that might occur during large read 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; see SectionGlobal Attributes
_).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.
-
int threads() const#
Retrieve the current thread-spawning policy.
See also
-
void lock() const#
There is a (hidden) internal recursive mutex to each ImageInput that can be used by the II to enforce thread safety. This is exposed via the obvious lock()/unlock()/try_lock() semantics.
-
virtual size_t heapsize() const#
Memory tracking method. Return the total heap memory allocated by
ImageInput
. Overridable version of heapsize defined in memory.h.
-
virtual size_t footprint() const#
Memory tracking method. Return the total memory footprint of
ImageInput
. Overridable version of footprint defined in memory.h.
-
static unique_ptr open(const std::string &filename, const ImageSpec *config = nullptr, Filesystem::IOProxy *ioproxy = nullptr)#