1.. _chap-imagebuf:
2
3ImageBuf: Image Buffers
4#######################
5
6
7ImageBuf Introduction and Theory of Operation
8=============================================
9
10ImageBuf is a utility class that stores an entire image.  It provides a
11nice API for reading, writing, and manipulating images as a single unit,
12without needing to worry about any of the details of storage or I/O.
13
14All I/O involving ImageBuf (that is, calls to `read` or `write`) are
15implemented underneath in terms of ImageCache, ImageInput, and ImageOutput,
16and so support all of the image file formats supported by OIIO.
17
18The ImageBuf class definition requires that you::
19
20    #include <OpenImageIO/imagebuf.h>
21
22
23.. doxygenenum:: OIIO::ImageBuf::IBStorage
24
25
26Constructing, destructing, resetting an ImageBuf
27================================================
28
29There are several ways to construct an ImageBuf. Each constructor has a
30corresponding `reset` method that takes the same arguments. Calling `reset`
31on an existing ImageBuf is equivalent to constructing a new ImageBuf from
32scratch (even if the ImageBuf, prior to reset, previously held an image).
33
34
35Making an empty or uninitialized ImageBuf
36-----------------------------------------
37
38.. doxygenfunction:: OIIO::ImageBuf::ImageBuf()
39.. doxygenfunction:: OIIO::ImageBuf::reset()
40
41
42Constructing a readable ImageBuf
43--------------------------------
44
45.. doxygenfunction:: OIIO::ImageBuf::ImageBuf(string_view name, int subimage = 0, int miplevel = 0, ImageCache *imagecache = nullptr, const ImageSpec *config = nullptr, Filesystem::IOProxy *ioproxy = nullptr)
46.. doxygenfunction:: OIIO::ImageBuf::reset(string_view name, int subimage = 0, int miplevel = 0, ImageCache *imagecache = nullptr, const ImageSpec *config = nullptr, Filesystem::IOProxy *ioproxy = nullptr)
47
48
49Constructing a writable ImageBuf
50--------------------------------------------------
51
52.. doxygenfunction:: OIIO::ImageBuf::ImageBuf(const ImageSpec &spec, InitializePixels zero = InitializePixels::Yes)
53.. doxygenfunction:: OIIO::ImageBuf::reset(const ImageSpec &spec, InitializePixels zero = InitializePixels::Yes)
54.. doxygenfunction:: OIIO::ImageBuf::make_writable
55
56
57Constructing an ImageBuf that "wraps" an application buffer
58-------------------------------------------------------------
59
60.. doxygenfunction:: OIIO::ImageBuf::ImageBuf(const ImageSpec &spec, void *buffer)
61.. doxygenfunction:: OIIO::ImageBuf::reset(const ImageSpec &spec, void *buffer)
62
63
64
65Reading and Writing disk images
66-------------------------------
67
68.. doxygenfunction:: 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)
69.. doxygenfunction:: OIIO::ImageBuf::read(int subimage, int miplevel, int chbegin, int chend, bool force, TypeDesc convert, ProgressCallback progress_callback = nullptr, void *progress_callback_data = nullptr)
70.. doxygenfunction:: OIIO::ImageBuf::init_spec
71
72.. doxygenfunction:: OIIO::ImageBuf::write(string_view filename, TypeDesc dtype = TypeUnknown, string_view fileformat = string_view(), ProgressCallback progress_callback = nullptr, void *progress_callback_data = nullptr) const
73.. doxygenfunction:: OIIO::ImageBuf::write(ImageOutput *out, ProgressCallback progress_callback = nullptr, void *progress_callback_data = nullptr) const
74.. doxygenfunction:: OIIO::ImageBuf::set_write_format(TypeDesc format)
75.. doxygenfunction:: OIIO::ImageBuf::set_write_format(cspan<TypeDesc> format)
76.. doxygenfunction:: OIIO::ImageBuf::set_write_tiles
77.. doxygenfunction:: OIIO::ImageBuf::set_write_ioproxy
78
79
80
81Getting and setting information about an ImageBuf
82=================================================
83
84.. doxygenfunction:: OIIO::ImageBuf::initialized
85.. doxygenfunction:: OIIO::ImageBuf::storage
86.. doxygenfunction:: OIIO::ImageBuf::spec
87.. doxygenfunction:: OIIO::ImageBuf::nativespec
88.. doxygenfunction:: OIIO::ImageBuf::specmod
89.. doxygenfunction:: OIIO::ImageBuf::name
90.. doxygenfunction:: OIIO::ImageBuf::file_format_name
91.. doxygenfunction:: OIIO::ImageBuf::subimage
92.. doxygenfunction:: OIIO::ImageBuf::nsubimages
93.. doxygenfunction:: OIIO::ImageBuf::miplevel
94.. doxygenfunction:: OIIO::ImageBuf::nmiplevels
95.. doxygenfunction:: OIIO::ImageBuf::nchannels
96
97
98.. cpp:function:: int xbegin() const
99                  int xend() const
100                  int ybegin() const
101                  int yend() const
102                  int zbegin() const
103                  int zend() const
104
105    Returns the `[begin,end)` range of the pixel data window of the buffer.
106    These are equivalent to `spec().x`, `spec().x+spec().width`, `spec().y`,
107    `spec().y+spec().height`, `spec().z`, and `spec().z+spec().depth`,
108    respectively.
109
110.. doxygenfunction:: OIIO::ImageBuf::orientation
111.. doxygenfunction:: OIIO::ImageBuf::set_orientation
112
113.. cpp:function:: int oriented_width() const
114                  int oriented_height() const
115                  int oriented_x() const
116                  int oriented_y() const
117                  int oriented_full_width() const
118                  int oriented_full_height() const
119                  int oriented_full_x() const
120                  int oriented_full_y() const
121
122    The oriented width, height, x, and y describe the pixel data window
123    after taking the display orientation into consideration.  The *full*
124    versions the "full" (a.k.a. display) window after taking the display
125    orientation into consideration.
126
127
128.. doxygenfunction:: OIIO::ImageBuf::roi
129.. doxygenfunction:: OIIO::ImageBuf::roi_full
130.. doxygenfunction:: OIIO::ImageBuf::set_origin
131.. doxygenfunction:: OIIO::ImageBuf::set_full
132.. doxygenfunction:: OIIO::ImageBuf::set_roi_full
133.. doxygenfunction:: OIIO::ImageBuf::contains_roi
134.. doxygenfunction:: OIIO::ImageBuf::pixeltype
135.. doxygenfunction:: OIIO::ImageBuf::threads() const
136.. doxygenfunction:: OIIO::ImageBuf::threads(int n) const
137
138
139
140Copying ImageBuf's and blocks of pixels
141========================================
142
143.. doxygenfunction:: OIIO::ImageBuf::operator=(const ImageBuf &src)
144.. doxygenfunction:: OIIO::ImageBuf::operator=(ImageBuf &&src)
145.. doxygenfunction:: OIIO::ImageBuf::copy(const ImageBuf &src, TypeDesc format = TypeUnknown)
146.. doxygenfunction:: OIIO::ImageBuf::copy(TypeDesc format) const
147.. doxygenfunction:: OIIO::ImageBuf::copy_metadata
148.. doxygenfunction:: OIIO::ImageBuf::copy_pixels
149.. doxygenfunction:: OIIO::ImageBuf::swap
150
151
152
153Getting and setting pixel values
154================================
155
156**Getting and setting individual pixels -- slow**
157
158.. doxygenfunction:: OIIO::ImageBuf::getchannel
159.. doxygenfunction:: OIIO::ImageBuf::getpixel(int x, int y, int z, float *pixel, int maxchannels = 1000, WrapMode wrap = WrapBlack) const
160
161.. doxygenfunction:: OIIO::ImageBuf::interppixel
162.. doxygenfunction:: OIIO::ImageBuf::interppixel_bicubic
163.. doxygenfunction:: OIIO::ImageBuf::interppixel_NDC
164.. doxygenfunction:: OIIO::ImageBuf::interppixel_bicubic_NDC
165
166.. doxygenfunction:: OIIO::ImageBuf::setpixel(int x, int y, int z, cspan<float> pixel)
167.. doxygenfunction:: OIIO::ImageBuf::setpixel(int i, cspan<float> pixel)
168
169|
170
171**Getting and setting regions of pixels -- fast**
172
173.. doxygenfunction:: OIIO::ImageBuf::get_pixels
174.. doxygenfunction:: OIIO::ImageBuf::set_pixels
175
176
177
178Deep data in an ImageBuf
179========================
180
181.. doxygenfunction:: OIIO::ImageBuf::deep
182.. doxygenfunction:: OIIO::ImageBuf::deep_samples
183.. doxygenfunction:: OIIO::ImageBuf::set_deep_samples
184.. doxygenfunction:: OIIO::ImageBuf::deep_insert_samples
185.. doxygenfunction:: OIIO::ImageBuf::deep_erase_samples
186.. doxygenfunction:: OIIO::ImageBuf::deep_value(int x, int y, int z, int c, int s) const
187.. doxygenfunction:: OIIO::ImageBuf::deep_value_uint(int x, int y, int z, int c, int s) const
188.. doxygenfunction:: OIIO::ImageBuf::set_deep_value(int x, int y, int z, int c, int s, float value)
189.. doxygenfunction:: OIIO::ImageBuf::set_deep_value(int x, int y, int z, int c, int s, uint32_t value)
190.. doxygenfunction:: OIIO::ImageBuf::deep_pixel_ptr
191
192.. cpp:function:: DeepData& OIIO::ImageBuf::deepdata()
193                  const DeepData& OIIO::ImageBuf::deepdata() const
194
195    Returns a reference to the underlying `DeepData` for a deep image.
196
197
198
199Error Handling
200==============
201
202.. doxygenfunction:: OIIO::ImageBuf::errorf
203.. doxygenfunction:: OIIO::ImageBuf::has_error
204.. doxygenfunction:: OIIO::ImageBuf::geterror
205
206
207Miscellaneous
208=============
209
210.. cpp:function:: void* localpixels()
211                  const void* localpixels() const
212
213    Return a raw pointer to the "local" pixel memory, if they are fully in
214    RAM and not backed by an ImageCache, or `nullptr` otherwise. You can
215    also test it like a `bool` to find out if pixels are local.
216
217.. cpp:function:: void* pixeladdr(int x, int y, int z = 0, int ch = 0)
218                  const void* pixeladdr(int x, int y, int z = 0, int ch = 0) const
219
220    Return the address where pixel `(x,y,z)`, channel `ch`, is stored in the
221    image buffer.  Use with extreme caution!  Will return `nullptr` if the
222    pixel values aren't local in RAM.
223
224
225.. doxygenfunction:: OIIO::ImageBuf::pixelindex
226.. doxygenfunction:: OIIO::ImageBuf::WrapMode_from_string
227
228
229
230Iterators -- the fast way of accessing individual pixels
231========================================================
232
233Sometimes you need to visit every pixel in an ImageBuf (or at least, every
234pixel in a large region).  Using the `getpixel()` and `setpixel()` for this
235purpose is simple but very slow.  But ImageBuf provides templated `Iterator`
236and `ConstIterator` types that are very inexpensive and hide all the details
237of local versus cached storage.
238
239    .. note:: `ImageBuf::ConstIterator` is identical to the Iterator,
240        except that `ConstIterator` may be used on a `const ImageBuf` and
241        may not be used to alter the contents of the ImageBuf.  For
242        simplicity, the remainder of this section will only discuss the
243        `Iterator`.
244
245An Iterator is associated with a particular ImageBuf. The Iterator has a
246*current pixel* coordinate that it is visiting, and an *iteration range*
247that describes a rectangular region of pixels that it will visits as it
248advances.  It always starts at the upper left corner of the iteration
249region.  We say that the iterator is *done* after it has visited every pixel
250in its iteration range.  We say that a pixel coordinate *exists* if it is
251within the pixel data window of the ImageBuf.  We say that a pixel
252coordinate is *valid* if it is within the iteration range of the iterator.
253
254The `Iterator<BUFT,USERT>` is templated based on two types: `BUFT` the type
255of the data stored in the ImageBuf, and `USERT` type type of the data that
256you want to manipulate with your code.  `USERT` defaults to `float`, since
257usually you will want to do all your pixel math with `float`.  We will
258thus use `Iterator<T>` synonymously with `Iterator<T,float>`.
259
260For the remainder of this section, we will assume that you have a
261`float`-based ImageBuf, for example, if it were set up like this::
262
263    ImageBuf buf ("myfile.exr");
264    buf.read (0, 0, true, TypeDesc::FLOAT);
265
266
267.. cpp:function:: Iterator<BUFT> (ImageBuf &buf, WrapMode wrap=WrapDefault)
268
269    Initialize an iterator that will visit every pixel in the data window
270    of `buf`, and start it out pointing to the upper left corner of
271    the data window.  The `wrap` describes what values will be retrieved
272    if the iterator is positioned outside the data window of the buffer.
273
274.. cpp:function:: Iterator<BUFT> (ImageBuf &buf, const ROI &roi, WrapMode wrap=WrapDefault)
275
276    Initialize an iterator that will visit every pixel of `buf` within the
277    region described by `roi`, and start it out pointing to pixel
278    (`roi.xbegin, roi.ybegin, roi.zbegin`). The `wrap` describes what values
279    will be retrieved if the iterator is positioned outside the data window
280    of the buffer.
281
282.. cpp:function:: Iterator<BUFT> (ImageBuf &buf, int x, int y, int z, WrapMode wrap=WrapDefault)
283
284    Initialize an iterator that will visit every pixel in the data window
285    of `buf`, and start it out pointing to pixel (x, y, z).
286    The `wrap` describes what values will be retrieved
287    if the iterator is positioned outside the data window of the buffer.
288
289.. cpp:function:: Iterator::operator++ ()
290
291    The `++` operator advances the iterator to the next pixel in its
292    iteration range.  (Both prefix and postfix increment operator are
293    supported.)
294
295.. cpp:function:: bool Iterator::done () const
296
297    Returns `true` if the iterator has completed its visit of all pixels in
298    its iteration range.
299
300.. cpp:function:: ROI Iterator::range () const
301
302    Returns the iteration range of the iterator, expressed as an ROI.
303
304.. cpp:function:: int Iterator::x () const
305                  int Iterator::y () const
306                  int Iterator::z () const
307
308    Returns the x, y, and z pixel coordinates, respectively, of the pixel
309    that the iterator is currently visiting.
310
311.. cpp:function:: bool Iterator::valid () const
312
313    Returns `true` if the iterator's current pixel coordinates are within
314    its iteration range.
315
316.. cpp:function:: bool Iterator::valid (int x, int y, int z=0) const
317
318    Returns `true` if pixel coordinate (x, y, z) are within the iterator's
319    iteration range (regardless of where the iterator itself is currently
320    pointing).
321
322.. cpp:function:: bool Iterator::exists () const
323
324    Returns `true` if the iterator's current pixel coordinates are within
325    the data window of the ImageBuf.
326
327.. cpp:function:: bool Iterator::exists (int x, int y, int z=0) const
328
329    Returns `true` if pixel coordinate (x, y, z) are within the pixel data
330    window of the ImageBuf (regardless of where the iterator itself is
331    currently pointing).
332
333.. cpp:function:: USERT& Iterator::operator[] (int i)
334
335    The value of channel `i` of the current pixel.  (The wrap mode, set up
336    when the iterator was constructed, determines what value is returned if
337    the iterator points outside the pixel data window of its buffer.)
338
339.. cpp:function:: int Iterator::deep_samples () const
340
341    For deep images only, retrieves the number of deep samples for the
342    current pixel.
343
344.. cpp:function:: void Iterator::set_deep_samples ()
345
346    For deep images only (and non-const ImageBuf), set the number of deep
347    samples for the current pixel. This only is useful if the ImageBuf has
348    not yet had the `deep_alloc()` method called.
349
350.. cpp:function:: USERT Iterator::deep_value (int c, int s) const
351                  uint32_t Iterator::deep_value_int (int c, int s) const
352
353    For deep images only, returns the value of channel `c`, sample number
354    `s`, at the current pixel.
355
356.. cpp:function:: void Iterator::set_deep_value (int c, int s, float value)
357                  void Iterator::set_deep_value (int c, int s, uint32_t value)
358
359    For deep images only (and non-cconst ImageBuf, sets the value of channel
360    `c`, sample number `s`, at the current pixel. This only is useful if the
361    ImageBuf has already had the `deep_alloc()` method called.
362
363
364Example: Visiting all pixels to compute an average color
365--------------------------------------------------------
366
367.. code-block:: cpp
368
369    void print_channel_averages (const std::string &filename)
370    {
371        // Set up the ImageBuf and read the file
372        ImageBuf buf (filename);
373        bool ok = buf.read (0, 0, true, TypeDesc::FLOAT);  // Force a float buffer
374        if (! ok)
375            return;
376
377        // Initialize a vector to contain the running total
378        int nc = buf.nchannels();
379        std::vector<float> total (n, 0.0f);
380
381        // Iterate over all pixels of the image, summing channels separately
382        for (ImageBuf::ConstIterator<float> it (buf);  ! it.done();  ++it)
383            for (int c = 0;  c < nc;  ++c)
384                total[c] += it[c];
385
386        // Print the averages
387        imagesize_t npixels = buf.spec().image_pixels();
388        for (int c = 0;  c < nc;  ++c)
389            std::cout << "Channel " << c << " avg = " (total[c] / npixels) << "\n";
390    }
391
392
393.. _sec-make-black:
394
395Example: Set all pixels in a region to black
396--------------------------------------------
397
398.. code-block:: cpp
399
400    bool make_black (ImageBuf &buf, ROI region)
401    {
402        if (buf.spec().format != TypeDesc::FLOAT)
403            return false;    // Assume it's a float buffer
404
405        // Clamp the region's channel range to the channels in the image
406        roi.chend = std::min (roi.chend, buf.nchannels);
407
408        // Iterate over all pixels in the region...
409        for (ImageBuf::Iterator<float> it (buf, region);  ! it.done();  ++it) {
410            if (! it.exists())   // Make sure the iterator is pointing
411                continue;        //   to a pixel in the data window
412            for (int c = roi.chbegin;  c < roi.chend;  ++c)
413                it[c] = 0.0f;  // clear the value
414        }
415        return true;
416    }
417
418
419Dealing with buffer data types
420==============================
421
422The previous section on iterators presented examples and discussion based on
423the assumption that the ImageBuf was guaranteed to store `float` data and
424that you wanted all math to also be done as `float` computations.  Here we
425will explain how to deal with buffers and files that contain different data
426types.
427
428Strategy 1: Only have `float` data in your ImageBuf
429-----------------------------------------------------
430
431When creating your own buffers, make sure they are `float`::
432
433    ImageSpec spec (640, 480, 3, TypeDesc::FLOAT); // <-- float buffer
434    ImageBuf buf ("mybuf", spec);
435
436When using ImageCache-backed buffers, force the ImageCache
437to convert everything to `float`::
438
439    // Just do this once, to set up the cache:
440    ImageCache *cache = ImageCache::create (true /* shared cache */);
441    cache->attribute ("forcefloat", 1);
442    ...
443    ImageBuf buf ("myfile.exr");   // Backed by the shared cache
444
445Or force the read to convert to `float` in the buffer if
446it's not a native type that would automatically stored as a `float`
447internally to the ImageCache:[#]_
448
449.. [#] ImageCache only supports a limited set of types internally, currently
450       float, half, uint8, uint16, and all other data types are converted to
451       these automatically as they are read into the cache.
452
453.. code-block:: cpp
454
455    ImageBuf buf ("myfile.exr");   // Backed by the shared cache
456    buf.read (0, 0, false /* don't force read to local mem */,
457              TypeDesc::FLOAT /* but do force conversion to float*/);
458
459Or force a read into local memory unconditionally (rather
460than relying on the ImageCache), and convert to `float`::
461
462    ImageBuf buf ("myfile.exr");
463    buf.read (0, 0, true /*force read*/,
464              TypeDesc::FLOAT /* force conversion */);
465
466Strategy 2: Template your iterating functions based on buffer type
467------------------------------------------------------------------
468
469Consider the following alternate version of the `make_black` function
470from Section `Example: Set all pixels in a region to black`_ ::
471
472    template<type BUFT>
473    static bool make_black_impl (ImageBuf &buf, ROI region)
474    {
475        // Clamp the region's channel range to the channels in the image
476        roi.chend = std::min (roi.chend, buf.nchannels);
477
478        // Iterate over all pixels in the region...
479        for (ImageBuf::Iterator<BUFT> it (buf, region);  ! it.done();  ++it) {
480            if (! it.exists())   // Make sure the iterator is pointing
481                continue;        //   to a pixel in the data window
482            for (int c = roi.chbegin;  c < roi.chend;  ++c)
483                it[c] = 0.0f;  // clear the value
484        }
485        return true;
486    }
487
488    bool make_black (ImageBuf &buf, ROI region)
489    {
490        if (buf.spec().format == TypeDesc::FLOAT)
491            return make_black_impl<float> (buf, region);
492        else if (buf.spec().format == TypeDesc::HALF)
493            return make_black_impl<half> (buf, region);
494        else if (buf.spec().format == TypeDesc::UINT8)
495            return make_black_impl<unsigned char> (buf, region);
496        else if (buf.spec().format == TypeDesc::UINT16)
497            return make_black_impl<unsigned short> (buf, region);
498        else {
499            buf.error ("Unsupported pixel data format %s", buf.spec().format);
500            retrn false;
501        }
502    }
503
504In this example, we make an implementation that is templated on the buffer
505type, and then a wrapper that calls the appropriate template specialization
506for each of 4 common types (and logs an error in the buffer for any other
507types it encounters).
508
509In fact, :file:`imagebufalgo_util.h` provides a macro to do this (and
510several variants, which will be discussed in more detail in the next
511chapter).  You could rewrite the example even more simply::
512
513    #include <OpenImageIO/imagebufalgo_util.h>
514
515    template<type BUFT>
516    static bool make_black_impl (ImageBuf &buf, ROI region)
517    {
518        ... same as before ...
519    }
520
521    bool make_black (ImageBuf &buf, ROI region)
522    {
523        bool ok;
524        OIIO_DISPATCH_COMMON_TYPES (ok, "make_black", make_black_impl,
525                                     buf.spec().format, buf, region);
526        return ok;
527    }
528
529This other type-dispatching helper macros will be discussed in more
530detail in Chapter :ref:`chap-imagebufalgo`.
531
532