1 // Copyright 2008-present Contributors to the OpenImageIO project.
2 // SPDX-License-Identifier: BSD-3-Clause
3 // https://github.com/OpenImageIO/oiio/blob/master/LICENSE.md
4 
5 
6 #pragma once
7 #define OPENIMAGEIO_IMAGEBUF_H
8 
9 #if defined(_MSC_VER)
10 // Ignore warnings about DLL exported classes with member variables that are template classes.
11 // This happens with the std::vector and std::string protected members of ImageBuf below.
12 #    pragma warning(disable : 4251)
13 #endif
14 
15 #include <OpenImageIO/dassert.h>
16 #include <OpenImageIO/fmath.h>
17 #include <OpenImageIO/imagecache.h>
18 #include <OpenImageIO/imageio.h>
19 
20 #include <limits>
21 #include <memory>
22 
23 
24 OIIO_NAMESPACE_BEGIN
25 
26 class ImageBuf;
27 class ImageBufImpl;  // Opaque type for the unique_ptr.
28 
29 
30 
31 /// Return pixel data window for this ImageSpec as a ROI.
32 OIIO_API ROI
33 get_roi(const ImageSpec& spec);
34 
35 /// Return full/display window for this ImageSpec as a ROI.
36 OIIO_API ROI
37 get_roi_full(const ImageSpec& spec);
38 
39 /// Set pixel data window for this ImageSpec to a ROI.
40 /// Does NOT change the channels of the spec, regardless of newroi.
41 OIIO_API void
42 set_roi(ImageSpec& spec, const ROI& newroi);
43 
44 /// Set full/display window for this ImageSpec to a ROI.
45 /// Does NOT change the channels of the spec, regardless of newroi.
46 OIIO_API void
47 set_roi_full(ImageSpec& spec, const ROI& newroi);
48 
49 
50 enum class InitializePixels { No = 0, Yes = 1 };
51 
52 
53 
54 /// An ImageBuf is a simple in-memory representation of a 2D image.  It uses
55 /// ImageInput and ImageOutput underneath for its file I/O, and has simple
56 /// routines for setting and getting individual pixels, that hides most of
57 /// the details of memory layout and data representation (translating
58 /// to/from float automatically).
59 class OIIO_API ImageBuf {
60 public:
61     /// An ImageBuf can store its pixels in one of several ways (each
62     /// identified by an `IBStorage` enumerated value):
63     enum IBStorage {
64         // clang-format off
65         UNINITIALIZED,
66             ///< An ImageBuf that doesn't represent any image at all
67             /// (either because it is newly constructed with the default
68             /// constructor, or had an error during construction).
69         LOCALBUFFER,
70             ///< "Local storage" is allocated to hold the image pixels
71             /// internal to the ImageBuf.  This memory will be freed when
72             /// the ImageBuf is destroyed.
73         APPBUFFER,
74             ///< The ImageBuf "wraps" pixel memory already allocated and
75             /// owned by the calling application. The caller will continue
76             /// to own that memory and be responsible for freeing it after
77             /// the ImageBuf is destroyed.
78         IMAGECACHE
79             ///< The ImageBuf is "backed" by an ImageCache, which will
80             /// automatically be used to retrieve pixels when requested, but
81             /// the ImageBuf will not allocate separate storage for it.
82             /// This brings all the advantages of the ImageCache, but can
83             /// only be used for read-only ImageBuf's that reference a
84             /// stored image file.
85         // clang-format on
86     };
87 
88     /// @{
89     /// @name Constructing and destructing an ImageBuf.
90 
91     /// Default constructor makes an empty/uninitialized ImageBuf.  There
92     /// isn't much you can do with an uninitialized buffer until you call
93     /// `reset()`. The storage type of a default-constructed ImageBuf is
94     /// `IBStorage::UNINITIALIZED`.
95     ImageBuf();
96 
97     /// Destructor for an ImageBuf.
98     ~ImageBuf();
99 
100     /// Construct a read-only ImageBuf that will be used to read the named
101     /// file (at the given subimage and MIP-level, defaulting to the first
102     /// in the file).  But don't read it yet!  The image will actually be
103     /// read lazily, only when other methods need to access the spec and/or
104     /// pixels, or when an explicit call to `init_spec()` or `read()` is
105     /// made, whichever comes first.
106     ///
107     /// The implementation may end up either reading the entire image
108     /// internally owned memory (if so, the storage will be `LOCALBUFFER`),
109     /// or it may rely on being backed by an ImageCache (in this case, the
110     /// storage will be `IMAGECACHE`) -- depending on the image size and
111     /// other factors.
112     ///
113     /// @param name
114     ///             The image to read.
115     /// @param subimage/miplevel
116     ///             The subimage and MIP level to read (defaults to the
117     ///             first subimage of the file, highest-res MIP level).
118     /// @param imagecache
119     ///             Optionally, a particular ImageCache to use. If nullptr,
120     ///             the default global/shared image cache will be used. If
121     ///             a custom ImageCache (not the global/shared one), it is
122     ///             important that the IC should not be destroyed while the
123     ///             ImageBuf is still alive.
124     /// @param config
125     ///             Optionally, a pointer to an ImageSpec whose metadata
126     ///             contains configuration hints that set options related
127     ///             to the opening and reading of the file.
128     /// @param ioproxy
129     ///         Optional pointer to an IOProxy to use when reading from the
130     ///         file. The caller retains ownership of the proxy.
131     ///
132     explicit ImageBuf(string_view name, int subimage = 0, int miplevel = 0,
133                       ImageCache* imagecache       = nullptr,
134                       const ImageSpec* config      = nullptr,
135                       Filesystem::IOProxy* ioproxy = nullptr);
136 
137     // Deprecated synonym for `ImageBuf(name, 0, 0, imagecache, nullptr)`.
138     ImageBuf(string_view name, ImageCache* imagecache);
139 
140     /// Construct a writable ImageBuf with the given specification
141     /// (including resolution, data type, metadata, etc.). The ImageBuf will
142     /// allocate and own its own pixel memory and will free that memory
143     /// automatically upon destruction, clear(), or reset(). Upon successful
144     /// initialization, the storage will be reported as `LOCALBUFFER`.
145     ///
146     /// @param spec
147     ///             An ImageSpec describing the image and its metadata. If
148     ///             not enough information is given to know how much memory
149     ///             to allocate (width, height, depth, channels, and data
150     ///             format), the ImageBuf will remain in an UNINITIALIZED
151     ///             state and will have no local pixel storage.
152     /// @param zero
153     ///             After a successful allocation of the local pixel
154     ///             storage, this parameter controls whether the pixels
155     ///             will be initialized to hold zero (black) values
156     ///             (`InitializePixels::Yes`) or if the pixel memory will
157     ///             remain uninitialized (`InitializePixels::No`) and thus
158     ///             may hold nonsensical values. Choosing `No` may save the
159     ///             time of writing to the pixel memory if you know for sure
160     ///             that you are about to overwrite it completely before you
161     ///             will need to read any pixel values.
162     ///
163     explicit ImageBuf(const ImageSpec& spec,
164                       InitializePixels zero = InitializePixels::Yes);
165 
166     // Deprecated/useless synonym for `ImageBuf(spec,zero)` but also gives
167     // it an internal name.
168     ImageBuf(string_view name, const ImageSpec& spec,
169              InitializePixels zero = InitializePixels::Yes);
170 
171     /// Construct a writable ImageBuf that "wraps" existing pixel memory
172     /// owned by the calling application. The ImageBuf does not own the
173     /// pixel storage and will will not free/delete that memory, even when
174     /// the ImageBuf is destroyed. Upon successful initialization, the
175     /// storage will be reported as `APPBUFFER`.
176     ///
177     /// @param spec
178     ///             An ImageSpec describing the image and its metadata. If
179     ///             not enough information is given to know the "shape" of
180     ///             the image (width, height, depth, channels, and data
181     ///             format), the ImageBuf will remain in an UNINITIALIZED
182     ///             state.
183     /// @param buffer
184     ///             A pointer to the caller-owned memory containing the
185     ///             storage for the pixels. It must be already allocated
186     ///             with enough space to hold a full image as described by
187     ///             `spec`.
188     ///
189     ImageBuf(const ImageSpec& spec, void* buffer);
190 
191     // Deprecated/useless synonym for `ImageBuf(spec,buffer)` but also gives
192     // it an internal name.
193     ImageBuf(string_view name, const ImageSpec& spec, void* buffer);
194 
195     /// Construct a copy of an ImageBuf.
196     ImageBuf(const ImageBuf& src);
197 
198     /// Move the contents of an ImageBuf to another ImageBuf.
199     ImageBuf(ImageBuf&& src);
200 
201     // Old name for reset().
202     void clear();
203 
204     /// Destroy any previous contents of the ImageBuf and re-initialize it
205     /// to resemble a freshly constructed ImageBuf using the default
206     /// constructor (holding no image, with storage
207     /// `IBStorage::UNINITIALIZED`).
reset()208     void reset() { clear(); }
209 
210     // Deprecated/useless synonym for `reset(name, 0, 0, imagecache, nullptr)`
211     void reset(string_view name, ImageCache* imagecache);
212 
213     /// Destroy any previous contents of the ImageBuf and re-initialize it
214     /// as if newly constructed with the same arguments, as a read-only
215     /// representation of an existing image file.
216     void reset(string_view name, int subimage = 0, int miplevel = 0,
217                ImageCache* imagecache       = nullptr,
218                const ImageSpec* config      = nullptr,
219                Filesystem::IOProxy* ioproxy = nullptr);
220 
221     /// Destroy any previous contents of the ImageBuf and re-initialize it
222     /// as if newly constructed with the same arguments, as a read/write
223     /// image with locally allocated storage that can hold an image as
224     /// described by `spec`. The optional `zero` parameter controls whether
225     /// the pixel values are filled with black/empty, or are left
226     /// uninitialized after being allocated.
227     ///
228     /// Note that if the ImageSpec does not contain enough information to
229     /// specify how much memory to allocate (width, height, channels, and
230     /// data format), the ImageBuf will remain uninitialized (regardless of
231     /// how `zero` is set).
232     void reset(const ImageSpec& spec,
233                InitializePixels zero = InitializePixels::Yes);
234 
235     // Deprecated/useless synonym for `reset(spec, spec, zero)` and also
236     // give it an internal name.
237     void reset(string_view name, const ImageSpec& spec,
238                InitializePixels zero = InitializePixels::Yes);
239 
240     /// Destroy any previous contents of the ImageBuf and re-initialize it
241     /// as if newly constructed with the same arguments, to "wrap" existing
242     /// pixel memory owned by the calling application.
243     void reset(const ImageSpec& spec, void* buffer);
244 
245     /// Make the ImageBuf be writable. That means that if it was previously
246     /// backed by an ImageCache (storage was `IMAGECACHE`), it will force a
247     /// full read so that the whole image is in local memory. This will
248     /// invalidate any current iterators on the image. It has no effect if
249     /// the image storage is not `IMAGECACHE`.
250     ///
251     /// @param keep_cache_type
252     ///             If true, preserve any ImageCache-forced data types (you
253     ///             might want to do this if it is critical that the
254     ///             apparent data type doesn't change, for example if you
255     ///             are calling `make_writable()` from within a
256     ///             type-specialized function).
257     /// @returns
258     ///             Return `true` if it works (including if no read was
259     ///             necessary), `false` if something went horribly wrong.
260     bool make_writable(bool keep_cache_type = false);
261 
262     // DEPRECATED(2.2): This is an alternate, and less common, spelling.
263     // Let's standardize on "writable". We will eventually remove this.
264     bool make_writeable(bool keep_cache_type = false);
265 
266     /// @}
267 
268 
269     /// Wrap mode describes what happens when an iterator points to
270     /// a value outside the usual data range of an image.
271     enum WrapMode {
272         WrapDefault,
273         WrapBlack,
274         WrapClamp,
275         WrapPeriodic,
276         WrapMirror,
277         _WrapLast
278     };
279 
280 
281     /// @{
282     /// @name  Reading and Writing disk images
283 
284     /// Read the particular subimage and MIP level of the image.  Generally,
285     /// this will skip the expensive read if the file has already been read
286     /// into the ImageBuf (at the specified subimage and MIP level).  It
287     /// will clear and re-allocate memory if the previously allocated space
288     /// was not appropriate for the size or data type of the image being
289     /// read.
290     ///
291     /// In general, `read()` will try not to do any I/O at the time of the
292     /// `read()` call, but rather to have the ImageBuf "backed" by an
293     /// ImageCache, which will do the file I/O on demand, as pixel values
294     /// are needed, and in that case the ImageBuf doesn't actually allocate
295     /// memory for the pixels (the data lives in the ImageCache).  However,
296     /// there are several conditions for which the ImageCache will be
297     /// bypassed, the ImageBuf will allocate "local" memory, and the disk
298     /// file will be read directly into allocated buffer at the time of the
299     /// `read()` call: (a) if the `force` parameter is `true`; (b) if the
300     /// `convert` parameter requests a data format conversion to a type that
301     /// is not the native file type and also is not one of the internal
302     /// types supported by the ImageCache (specifically, `float` and
303     /// `UINT8`); (c) if the ImageBuf already has local pixel memory
304     /// allocated, or "wraps" an application buffer.
305     ///
306     /// Note that `read()` is not strictly necessary. If you are happy with
307     /// the filename, subimage and MIP level specified by the ImageBuf
308     /// constructor (or the last call to `reset()`), and you want the
309     /// storage to be backed by the ImageCache (including storing the
310     /// pixels in whatever data format that implies), then the file contents
311     /// will be automatically read the first time you make any other
312     /// ImageBuf API call that requires the spec or pixel values.  The only
313     /// reason to call `read()` yourself is if you are changing the
314     /// filename, subimage, or MIP level, or if you want to use `force =
315     /// true` or a specific `convert` value to force data format conversion.
316     ///
317     /// @param  subimage/miplevel
318     ///             The subimage and MIP level to read.
319     /// @param  force
320     ///             If `true`, will force an immediate full read into
321     ///             ImageBuf-owned local pixel memory (yielding a
322     ///             `LOCALPIXELS` storage buffer). Otherwise, it is up to
323     ///             the implementation whether to immediately read or have
324     ///             the image backed by an ImageCache (storage
325     ///             `IMAGECACHE`.)
326     /// @param  convert
327     ///             If set to a specific type (not`UNKNOWN`), the ImageBuf
328     ///             memory will be allocated for that type specifically and
329     ///             converted upon read.
330     /// @param  progress_callback/progress_callback_data
331     ///             If `progress_callback` is non-NULL, the underlying
332     ///             read, if expensive, may make several calls to
333     ///                 `progress_callback(progress_callback_data, portion_done)`
334     ///             which allows you to implement some sort of progress
335     ///             meter. Note that if the ImageBuf is backed by an
336     ///             ImageCache, the progress callback will never be called,
337     ///             since no actual file I/O will occur at this time
338     ///             (ImageCache will load tiles or scanlines on demand, as
339     ///             individual pixel values are needed).
340     ///
341     /// @returns
342     ///             `true` upon success, or `false` if the read failed (in
343     ///             which case, you should be able to retrieve an error
344     ///             message via `geterror()`).
345     ///
346     bool read(int subimage = 0, int miplevel = 0, bool force = false,
347               TypeDesc convert                   = TypeDesc::UNKNOWN,
348               ProgressCallback progress_callback = nullptr,
349               void* progress_callback_data       = nullptr);
350 
351     /// Read the file, if possible only allocating and reading a subset of
352     /// channels, `[chbegin..chend-1]`. This can be a performance and memory
353     /// improvement for some image file formats, if you know that any use of
354     /// the ImageBuf will only access a subset of channels from a
355     /// many-channel file.
356     ///
357     /// Additional parameters:
358     ///
359     /// @param  chbegin/chend
360     ///             The subset (a range with "exclusive end") of channels to
361     ///             read, if the implementation is able to read only a
362     ///             subset of channels and have a performance advantage by
363     ///             doing so. If `chbegin` is 0 and `chend` is either
364     ///             negative or greater than the number of channels in the
365     ///             file, all channels will be read. Please note that it is
366     ///             "advisory" and not guaranteed to be honored by the
367     ///             underlying implementation.
368     bool read(int subimage, int miplevel, int chbegin, int chend, bool force,
369               TypeDesc convert, ProgressCallback progress_callback = nullptr,
370               void* progress_callback_data = nullptr);
371 
372     /// Read the ImageSpec for the given file, subimage, and MIP level into
373     /// the ImageBuf, but will not read the pixels or allocate any local
374     /// storage (until a subsequent call to `read()`).  This is helpful if
375     /// you have an ImageBuf and you need to know information about the
376     /// image, but don't want to do a full read yet, and maybe won't need to
377     /// do the full read, depending on what's found in the spec.
378     ///
379     /// Note that `init_spec()` is not strictly necessary. If you are happy
380     /// with the filename, subimage and MIP level specified by the ImageBuf
381     /// constructor (or the last call to `reset()`), then the spec will be
382     /// automatically read the first time you make any other ImageBuf API
383     /// call that requires it. The only reason to call `read()` yourself is
384     /// if you are changing the filename, subimage, or MIP level, or if you
385     /// want to use `force=true` or a specific `convert` value to force
386     /// data format conversion.
387     ///
388     /// @param  filename
389     ///             The filename to read from (should be the same as the
390     ///             filename used when the ImageBuf was constructed or
391     ///             reset.)
392     /// @param  subimage/miplevel
393     ///             The subimage and MIP level to read.
394     ///
395     /// @returns
396     ///             `true` upon success, or `false` if the read failed (in
397     ///             which case, you should be able to retrieve an error
398     ///             message via `geterror()`).
399     ///
400     bool init_spec(string_view filename, int subimage, int miplevel);
401 
402     /// Write the image to the named file, converted to the specified pixel
403     /// data type `dtype` (`TypeUnknown` signifies to use the data type of
404     /// the buffer), and file format (an empty `fileformat` means to infer
405     /// the type from the filename extension).
406     ///
407     /// By default, it will always try to write a scanline-oriented file,
408     /// unless the `set_write_tiles()` method has been used to override
409     /// this.
410     ///
411     /// @param  filename
412     ///             The filename to write to.
413     /// @param  dtype
414     ///             Optional override of the pixel data format to use in the
415     ///             file being written. The default (`UNKNOWN`) means to try
416     ///             writing the same data format that as pixels are stored
417     ///             within the ImageBuf memory (or whatever type was
418     ///             specified by a prior call to `set_write_format()`). In
419     ///             either case, if the file format does not support that
420     ///             data type, another will be automatically chosen that is
421     ///             supported by the file type and loses as little precision
422     ///             as possible.
423     /// @param  fileformat
424     ///             Optional override of the file format to write. The
425     ///             default (empty string) means to infer the file format
426     ///             from the extension of the `filename` (for
427     ///             example, "foo.tif" will write a TIFF file).
428     /// @param  progress_callback/progress_callback_data
429     ///             If `progress_callback` is non-NULL, the underlying
430     ///             write, if expensive, may make several calls to
431     ///                 `progress_callback(progress_callback_data, portion_done)`
432     ///             which allows you to implement some sort of progress
433     ///             meter.
434     ///
435     /// @returns
436     ///             `true` upon success, or `false` if the write failed (in
437     ///             which case, you should be able to retrieve an error
438     ///             message via `geterror()`).
439     ///
440 
441     bool write(string_view filename, TypeDesc dtype = TypeUnknown,
442                string_view fileformat             = string_view(),
443                ProgressCallback progress_callback = nullptr,
444                void* progress_callback_data       = nullptr) const;
445 
446 #ifndef DOXYGEN_SHOULD_SKIP_THIS
447     // DEPRECATED(1.9): old version did not have the data type
448     bool write(string_view filename, string_view fileformat,
449                ProgressCallback progress_callback = nullptr,
450                void* progress_callback_data       = nullptr) const
451     {
452         return write(filename, TypeUnknown, fileformat, progress_callback,
453                      progress_callback_data);
454     }
455 #endif  // DOXYGEN_SHOULD_SKIP_THIS
456 
457     /// Set the pixel data format that will be used for subsequent `write()`
458     /// calls that do not themselves request a specific data type request.
459     ///
460     /// Note that this does not affect the variety of `write()` that takes
461     /// an open `ImageOutput*` as a parameter.
462     ///
463     /// @param  format
464     ///             The data type to be used for all channels.
465     void set_write_format(TypeDesc format);
466 
467     /// Set the per-channel pixel data format that will be used for
468     /// subsequent `write()` calls that do not themselves request a specific
469     /// data type request.
470     ///
471     /// @param  format
472     ///             The type of each channel (in order). Any channel's
473     ///             format specified as `TypeUnknown` will default to be
474     ///             whatever type is described in the ImageSpec of the
475     ///             buffer.
476     void set_write_format(cspan<TypeDesc> format);
477 
478     /// Override the tile sizing for subsequent calls to the `write()`
479     /// method (the variety that does not take an open `ImageOutput*`).
480     /// Setting all three dimensions to 0 indicates that the output should
481     /// be a scanline-oriented file.
482     ///
483     /// This lets you write a tiled file from an ImageBuf that may have been
484     /// read originally from a scanline file, or change the dimensions of a
485     /// tiled file, or to force the file written to be scanline even if it
486     /// was originally read from a tiled file.
487     ///
488     /// In all cases, if the file format ultimately written does not support
489     /// tiling, or the tile dimensions requested, a suitable supported
490     /// tiling choice will be made automatically.
491     void set_write_tiles(int width = 0, int height = 0, int depth = 0);
492 
493     /// Supply an IOProxy to use for a subsequent call to `write()`.
494     ///
495     /// If a proxy is set but it later turns out that the file format
496     /// selected does not support write proxies, then `write()` will fail
497     /// with an error.
498     void set_write_ioproxy(Filesystem::IOProxy* ioproxy);
499 
500     /// Write the pixels of the ImageBuf to an open ImageOutput. The
501     /// ImageOutput must have already been opened with a spec that indicates
502     /// a resolution identical to that of this ImageBuf (but it may have
503     /// specified a different pixel data type, in which case data
504     /// conversions will happen automatically). This method does NOT close
505     /// the file when it's done (and so may be called in a loop to write a
506     /// multi-image file).
507     ///
508     /// Note that since this uses an already-opened `ImageOutput`, which is
509     /// too late to change how it was opened, it does not honor any prior
510     /// calls to `set_write_format` or `set_write_tiles`.
511     ///
512     /// The main application of this method is to allow an ImageBuf (which
513     /// by design may hold only a *single* image) to be used for the output
514     /// of one image of a multi-subimage and/or MIP-mapped image file.
515     ///
516     /// @param  out
517     ///             A pointer to an already-opened `ImageOutput` to which
518     ///             the pixels of the ImageBuf will be written.
519     /// @param  progress_callback/progress_callback_data
520     ///             If `progress_callback` is non-NULL, the underlying
521     ///             write, if expensive, may make several calls to
522     ///                 `progress_callback(progress_callback_data, portion_done)`
523     ///             which allows you to implement some sort of progress
524     ///             meter.
525     /// @returns  `true` if all went ok, `false` if there were errors
526     ///           writing.
527     bool write(ImageOutput* out, ProgressCallback progress_callback = nullptr,
528                void* progress_callback_data = nullptr) const;
529 
530     /// @}
531 
532     /// @{
533     /// @name  Copying ImageBuf's and blocks of pixels
534 
535     /// Copy assignment.
536     const ImageBuf& operator=(const ImageBuf& src);
537 
538     /// Move assignment.
539     const ImageBuf& operator=(ImageBuf&& src);
540 
541     /// Copy all the metadata from `src` to `*this` (except for pixel data
542     /// resolution, channel types and names, and data format).
543     void copy_metadata(const ImageBuf& src);
544 
545     /// Copy the pixel data from `src` to `*this`, automatically converting
546     /// to the existing data format of `*this`.  It only copies pixels in
547     /// the overlap regions (and channels) of the two images; pixel data in
548     /// `*this` that do exist in `src` will be set to 0, and pixel data in
549     /// `src` that do not exist in `*this` will not be copied.
550     bool copy_pixels(const ImageBuf& src);
551 
552     /// Try to copy the pixels and metadata from `src` to `*this`
553     /// (optionally with an explicit data format conversion).
554     ///
555     /// If the previous state of `*this` was uninitialized, owning its own
556     /// local pixel memory, or referring to a read-only image backed by
557     /// ImageCache, then local pixel memory will be allocated to hold the
558     /// new pixels and the call always succeeds unless the memory cannot be
559     /// allocated. In this case, the `format` parameter may request a pixel
560     /// data type that is different from that of the source buffer.
561     ///
562     /// If `*this` previously referred to an app-owned memory buffer, the
563     /// memory cannot be re-allocated, so the call will only succeed if the
564     /// app-owned buffer is already the correct resolution and number of
565     /// channels.  The data type of the pixels will be converted
566     /// automatically to the data type of the app buffer.
567     ///
568     /// @param  src
569     ///             Another ImageBuf from which to copy the pixels and
570     ///             metadata.
571     /// @param  format
572     ///             Optionally request the pixel data type to be used. The
573     ///             default of `TypeUnknown` means to use whatever data type
574     ///             is used by the `src`. If `*this` is already initialized
575     ///             and has `APPBUFFER` storage ("wrapping" an application
576     ///             buffer), this parameter is ignored.
577     /// @returns
578     ///             `true` upon success or `false` upon error/failure.
579     bool copy(const ImageBuf& src, TypeDesc format = TypeUnknown);
580 
581     /// Return a full copy of `this` ImageBuf (optionally with an explicit
582     /// data format conversion).
583     ImageBuf copy(TypeDesc format /*= TypeDesc::UNKNOWN*/) const;
584 
585     /// Swap the entire contents with another ImageBuf.
swap(ImageBuf & other)586     void swap(ImageBuf& other) { std::swap(m_impl, other.m_impl); }
587 
588     /// @}
589 
590 
591     /// @{
592     /// @name  Getting and setting pixel values
593 
594     /// Retrieve a single channel of one pixel.
595     ///
596     /// @param x/y/z
597     ///             The pixel coordinates.
598     /// @param c
599     ///             The channel index to retrieve.
600     /// @param wrap
601     ///             WrapMode that determines the behavior if the pixel
602     ///             coordinates are outside the data window: `WrapBlack`,
603     ///             `WrapClamp`, `WrapPeriodic`, `WrapMirror`.
604     /// @returns
605     ///            The data value, converted to a `float`.
606     float getchannel(int x, int y, int z, int c,
607                      WrapMode wrap = WrapBlack) const;
608 
609     /// Retrieve the pixel value by x, y, z pixel indices, placing its
610     /// contents in `pixel[0..n-1]` where *n* is the smaller of
611     /// `maxchannels` the actual number of channels stored in the buffer.
612     ///
613     /// @param x/y/z
614     ///             The pixel coordinates.
615     /// @param pixel
616     ///             The results are stored in `pixel[0..nchannels-1]`. It is
617     ///             up to the caller to ensure that `pixel` points to enough
618     ///             memory to hold the required number of channels.
619     /// @param maxchannels
620     ///             Optional clamp to the number of channels retrieved.
621     /// @param wrap
622     ///             WrapMode that determines the behavior if the pixel
623     ///             coordinates are outside the data window: `WrapBlack`,
624     ///             `WrapClamp`, `WrapPeriodic`, `WrapMirror`.
625     void getpixel(int x, int y, int z, float* pixel, int maxchannels = 1000,
626                   WrapMode wrap = WrapBlack) const;
627 
628     // Simplified version: 2D, black wrap.
629     void getpixel(int x, int y, float* pixel, int maxchannels = 1000) const
630     {
631         getpixel(x, y, 0, pixel, maxchannels);
632     }
633 
634     /// Sample the image plane at pixel coordinates (x,y), using linear
635     /// interpolation between pixels, placing the result in `pixel[]`.
636     ///
637     /// @param x/y
638     ///             The pixel coordinates. Note that pixel data values
639     ///             themselves are at the pixel centers, so pixel (i,j) is
640     ///             at image plane coordinate (i+0.5, j+0.5).
641     /// @param pixel
642     ///             The results are stored in `pixel[0..nchannels-1]`. It is
643     ///             up to the caller to ensure that `pixel` points to enough
644     ///             memory to hold the number of channels in the image.
645     /// @param wrap
646     ///             WrapMode that determines the behavior if the pixel
647     ///             coordinates are outside the data window: `WrapBlack`,
648     ///             `WrapClamp`, `WrapPeriodic`, `WrapMirror`.
649     void interppixel(float x, float y, float* pixel,
650                      WrapMode wrap = WrapBlack) const;
651 
652     /// Linearly interpolate at NDC coordinates (s,t), where (0,0) is
653     /// the upper left corner of the display window, (1,1) the lower
654     /// right corner of the display window.
655     ///
656     /// @note `interppixel()` uses pixel coordinates (ranging 0..resolution)
657     /// whereas `interppixel_NDC()` uses NDC coordinates (ranging 0..1).
658     void interppixel_NDC(float s, float t, float* pixel,
659                          WrapMode wrap = WrapBlack) const;
660 
661     // DEPRECATED (1.5) synonym for interppixel_NDC.
662     void interppixel_NDC_full(float s, float t, float* pixel,
663                               WrapMode wrap = WrapBlack) const;
664 
665     /// Bicubic interpolation at pixel coordinates (x,y).
666     void interppixel_bicubic(float x, float y, float* pixel,
667                              WrapMode wrap = WrapBlack) const;
668 
669     /// Bicubic interpolation at NDC space coordinates (s,t), where (0,0)
670     /// is the upper left corner of the display (a.k.a. "full") window,
671     /// (1,1) the lower right corner of the display window.
672     void interppixel_bicubic_NDC(float s, float t, float* pixel,
673                                  WrapMode wrap = WrapBlack) const;
674 
675 
676     /// Set the pixel with coordinates (x,y,0) to have the values in span
677     /// `pixel[]`.  The number of channels copied is the minimum of the span
678     /// length and the actual number of channels in the image.
setpixel(int x,int y,cspan<float> pixel)679     void setpixel(int x, int y, cspan<float> pixel)
680     {
681         setpixel(x, y, 0, pixel);
682     }
683 
684     /// Set the pixel with coordinates (x,y,z) to have the values in span
685     /// `pixel[]`.  The number of channels copied is the minimum of the span
686     /// length and the actual number of channels in the image.
setpixel(int x,int y,int z,cspan<float> pixel)687     void setpixel(int x, int y, int z, cspan<float> pixel)
688     {
689         setpixel(x, y, z, pixel.data(), int(pixel.size()));
690     }
691 
692     /// Set the `i`-th pixel value of the image (out of width*height*depth),
693     /// from floating-point values in span `pixel[]`.  The number of
694     /// channels copied is the minimum of the span length and the actual
695     /// number of channels in the image.
setpixel(int i,cspan<float> pixel)696     void setpixel(int i, cspan<float> pixel)
697     {
698         setpixel(i, pixel.data(), int(pixel.size()));
699     }
700 
701     /// Set the pixel with coordinates (x,y,0) to have the values in
702     /// pixel[0..n-1].  The number of channels copied, n, is the minimum
703     /// of maxchannels and the actual number of channels in the image.
704     void setpixel(int x, int y, const float* pixel, int maxchannels = 1000)
705     {
706         setpixel(x, y, 0, pixel, maxchannels);
707     }
708 
709     /// Set the pixel with coordinates (x,y,z) to have the values in
710     /// `pixel[0..n-1]`.  The number of channels copied, n, is the minimum
711     /// of `maxchannels` and the actual number of channels in the image.
712     void setpixel(int x, int y, int z, const float* pixel,
713                   int maxchannels = 1000);
714 
715     /// Set the `i`-th pixel value of the image (out of width*height*depth),
716     /// from floating-point values in `pixel[]`.  Set at most
717     /// `maxchannels` (will be clamped to the actual number of channels).
718     void setpixel(int i, const float* pixel, int maxchannels = 1000);
719 
720     /// Retrieve the rectangle of pixels spanning the ROI (including
721     /// channels) at the current subimage and MIP-map level, storing the
722     /// pixel values beginning at the address specified by result and with
723     /// the given strides (by default, AutoStride means the usual contiguous
724     /// packing of pixels) and converting into the data type described by
725     /// `format`.  It is up to the caller to ensure that result points to an
726     /// area of memory big enough to accommodate the requested rectangle.
727     /// Return true if the operation could be completed, otherwise return
728     /// false.
729     bool get_pixels(ROI roi, TypeDesc format, void* result,
730                     stride_t xstride = AutoStride,
731                     stride_t ystride = AutoStride,
732                     stride_t zstride = AutoStride) const;
733 
734     /// Copy the data into the given ROI of the ImageBuf. The data points to
735     /// values specified by `format`, with layout detailed by the stride
736     /// values (in bytes, with AutoStride indicating "contiguous" layout).
737     /// It is up to the caller to ensure that data points to an area of
738     /// memory big enough to account for the ROI. Return true if the
739     /// operation could be completed, otherwise return false.
740     bool set_pixels(ROI roi, TypeDesc format, const void* data,
741                     stride_t xstride = AutoStride,
742                     stride_t ystride = AutoStride,
743                     stride_t zstride = AutoStride);
744 
745     /// @}
746 
747     /// @{
748     /// @name  Getting and setting information about an ImageBuf
749 
750     /// Returns `true` if the ImageBuf is initialized, `false` if not yet
751     /// initialized.
752     bool initialized() const;
753 
754     /// Which type of storage is being used for the pixels? Returns an
755     /// enumerated type describing the type of storage currently employed by
756     /// the ImageBuf: `UNINITIALIZED` (no storage), `LOCALBUFFER` (the
757     /// ImageBuf has allocated and owns the pixel memory), `APPBUFFER` (the
758     /// ImageBuf "wraps" memory owned by the calling application), or
759     /// `IMAGECACHE` (the image is backed by an ImageCache).
760     IBStorage storage() const;
761 
762     /// Return a read-only (const) reference to the image spec that
763     /// describes the buffer.
764     const ImageSpec& spec() const;
765 
766     /// Return a writable reference to the ImageSpec that describes the
767     /// buffer.  It's ok to modify most of the metadata, but if you modify
768     /// the spec's `format`, `width`, `height`, or `depth` fields, you get
769     /// the pain you deserve, as the ImageBuf will no longer have correct
770     /// knowledge of its pixel memory layout.  USE WITH EXTREME CAUTION.
771     ImageSpec& specmod();
772 
773     /// Return a read-only (const) reference to the "native" image spec
774     /// (that describes the file, which may be slightly different than
775     /// the spec of the ImageBuf, particularly if the IB is backed by an
776     /// ImageCache that is imposing some particular data format or tile
777     /// size).
778     ///
779     /// This may differ from `spec()` --- for example, if a data format
780     /// conversion was requested, if the buffer is backed by an ImageCache
781     /// which stores the pixels internally in a different data format than
782     /// that of the file, or if the file had differing per-channel data
783     /// formats (ImageBuf must contain a single data format for all
784     /// channels).
785     const ImageSpec& nativespec() const;
786 
787     /// Returns the name of the buffer (name of the file, for an ImageBuf
788     /// read from disk).
789     string_view name(void) const;
790 
791     /// Return the name of the image file format of the disk file we read
792     /// into this image, for example `"openexr"`.  Returns an empty string
793     /// if this image was not the result of a read().
794     string_view file_format_name(void) const;
795 
796     /// Return the index of the subimage the ImageBuf is currently holding.
797     int subimage() const;
798 
799     /// Return the number of subimages in the file.
800     int nsubimages() const;
801 
802     /// Return the index of the miplevel the ImageBuf is currently holding.
803     int miplevel() const;
804 
805     /// Return the number of miplevels of the current subimage.
806     int nmiplevels() const;
807 
808     /// Return the number of color channels in the image. This is equivalent
809     /// to `spec().nchannels`.
810     int nchannels() const;
811 
812     /// Return the beginning (minimum) x coordinate of the defined image.
813     int xbegin() const;
814     /// Return the end (one past maximum) x coordinate of the defined image.
815     int xend() const;
816     /// Return the beginning (minimum) y coordinate of the defined image.
817     int ybegin() const;
818     /// Return the end (one past maximum) y coordinate of the defined image.
819     int yend() const;
820     /// Return the beginning (minimum) z coordinate of the defined image.
821     int zbegin() const;
822     /// Return the end (one past maximum) z coordinate of the defined image.
823     int zend() const;
824     /// Return the minimum x coordinate of the defined image.
825     int xmin() const;
826     /// Return the maximum x coordinate of the defined image.
827     int xmax() const;
828     /// Return the minimum y coordinate of the defined image.
829     int ymin() const;
830     /// Return the maximum y coordinate of the defined image.
831     int ymax() const;
832     /// Return the minimum z coordinate of the defined image.
833     int zmin() const;
834     /// Return the maximum z coordinate of the defined image.
835     int zmax() const;
836 
837     /// Return the current `"Orientation"` metadata for the image, per the
838     /// table in `sec-metadata-orientation`_
839     int orientation() const;
840 
841     /// Set the `"Orientation"` metadata for the image.
842     void set_orientation(int orient);
843 
844     // Return the width, height, or full versions, if the image were
845     // positioned for display in its designated orientation.
846     int oriented_width() const;
847     int oriented_height() const;
848     int oriented_x() const;
849     int oriented_y() const;
850     int oriented_full_width() const;
851     int oriented_full_height() const;
852     int oriented_full_x() const;
853     int oriented_full_y() const;
854 
855     /// Alters the metadata of the spec in the ImageBuf to reset the
856     /// "origin" of the pixel data window to be the specified coordinates.
857     /// This does not affect the size of the pixel data window, only its
858     /// position.
859     void set_origin(int x, int y, int z = 0);
860 
861     /// Set the "full" (a.k.a. display) window to Alters the metadata of the
862     /// spec in the ImageBuf to reset the "full" image size (a.k.a.
863     /// "display window") to
864     ///
865     ///     [xbegin,xend) x [ybegin,yend) x [zbegin,zend)`
866     ///
867     /// This does not affect the size of the pixel data window.
868     void set_full(int xbegin, int xend, int ybegin, int yend, int zbegin,
869                   int zend);
870 
871     /// Return pixel data window for this ImageBuf as a ROI.
872     ROI roi() const;
873 
874     /// Return full/display window for this ImageBuf as a ROI.
875     ROI roi_full() const;
876 
877     /// Set full/display window for this ImageBuf to a ROI.
878     /// Does NOT change the channels of the spec, regardless of `newroi`.
879     void set_roi_full(const ROI& newroi);
880 
881     /// Is the specified roi completely contained in the data window of
882     /// this ImageBuf?
883     bool contains_roi(ROI roi) const;
884 
885     bool pixels_valid(void) const;
886 
887     /// The data type of the pixels stored in the buffer (equivalent to
888     /// `spec().format`).
889     TypeDesc pixeltype() const;
890 
891     /// Return a raw pointer to "local" pixel memory, if they are fully in
892     /// RAM and not backed by an ImageCache, or `nullptr` otherwise.  You
893     /// can also test it like a bool to find out if pixels are local.
894     void* localpixels();
895     const void* localpixels() const;
896 
897     /// Pixel-to-pixel stride within the localpixels memory.
898     stride_t pixel_stride() const;
899     /// Scanline-to-scanline stride within the localpixels memory.
900     stride_t scanline_stride() const;
901     /// Z plane stride within the localpixels memory.
902     stride_t z_stride() const;
903 
904     /// Are the pixels backed by an ImageCache, rather than the whole
905     /// image being in RAM somewhere?
906     bool cachedpixels() const;
907 
908     /// A pointer to the underlying ImageCache.
909     ImageCache* imagecache() const;
910 
911     /// Return the address where pixel `(x,y,z)`, channel `ch`, is stored in
912     /// the image buffer.  Use with extreme caution!  Will return `nullptr`
913     /// if the pixel values aren't local in RAM.
914     const void* pixeladdr(int x, int y, int z = 0, int ch = 0) const;
915     void* pixeladdr(int x, int y, int z = 0, int ch = 0);
916 
917     /// Return the index of pixel (x,y,z). If check_range is true, return
918     /// -1 for an invalid coordinate that is not within the data window.
919     int pixelindex(int x, int y, int z, bool check_range = false) const;
920 
921     /// Set the threading policy for this ImageBuf, controlling the maximum
922     /// amount of parallelizing thread "fan-out" that might occur during
923     /// expensive operations. The default of 0 means that the global
924     /// `attribute("threads")` value should be used (which itself defaults
925     /// to using as many threads as cores).
926     ///
927     /// The main reason to change this value is to set it to 1 to indicate
928     /// that the calling thread should do all the work rather than spawning
929     /// new threads. That is probably the desired behavior in situations
930     /// where the calling application has already spawned multiple worker
931     /// threads.
932     void threads(int n) const;
933 
934     /// Retrieve the current thread-spawning policy of this ImageBuf.
935     int threads() const;
936 
937     /// @}
938 
939     /// @{
940     /// @name Error handling
941 
942     /// Add simple string to the error message list for this IB.
943     void error(const std::string& message) const;
944 
945     /// Error reporting for ImageBuf: call this with Python / {fmt} /
946     /// std::format style formatting specification.
947     template<typename... Args>
errorfmt(const char * fmt,const Args &...args)948     void errorfmt(const char* fmt, const Args&... args) const
949     {
950         error(Strutil::fmt::format(fmt, args...));
951     }
952 
953     /// Error reporting for ImageBuf: call this with printf-like arguments
954     /// to report an error.
955     template<typename... Args>
errorf(const char * fmt,const Args &...args)956     void errorf(const char* fmt, const Args&... args) const
957     {
958         error(Strutil::sprintf(fmt, args...));
959     }
960 
961     /// Error reporting for ImageBuf: call this with Strutil::format
962     /// formatting conventions. Beware, this is in transition, is currently
963     /// printf-like but will someday change to python-like!
964     template<typename... Args>
error(const char * fmt,const Args &...args)965     void error(const char* fmt, const Args&... args) const
966     {
967         error(Strutil::format(fmt, args...));
968     }
969 
970     // Error reporting for ImageBuf: call this with Python / {fmt} /
971     // std::format style formatting specification.
972     template<typename... Args>
973     OIIO_DEPRECATED("use `errorfmt` instead")
fmterror(const char * fmt,const Args &...args)974     void fmterror(const char* fmt, const Args&... args) const
975     {
976         error(Strutil::fmt::format(fmt, args...));
977     }
978 
979     /// Returns `true` if the ImageBuf has had an error and has an error
980     /// message ready to retrieve via `geterror()`.
981     bool has_error(void) const;
982 
983     /// Return the text of all error messages issued since `geterror()` was
984     /// called (or an empty string if no errors are pending).  This also
985     /// clears the error message for next time.
986     std::string geterror(void) const;
987 
988     /// @}
989 
990     /// @{
991     /// @name  Deep data in an ImageBuf
992 
993     /// Does this ImageBuf store deep data? Returns `true` if the ImageBuf
994     /// holds a "deep" image, `false` if the ImageBuf holds an ordinary
995     /// pixel-based image.
996     bool deep() const;
997 
998     /// Retrieve the number of deep data samples corresponding to pixel
999     /// (x,y,z).  Return 0 if not a deep image, or if the pixel is outside
1000     /// of the data window, or if the designated pixel has no deep samples.
1001     int deep_samples(int x, int y, int z = 0) const;
1002 
1003     /// Return a pointer to the raw data of pixel `(x,y,z)`, channel `c`,
1004     /// sample `s`. Return `nullptr` if the pixel coordinates or channel
1005     /// number are out of range, if the pixel/channel has no deep samples,
1006     /// or if the image is not deep. Use with caution --- these pointers may
1007     /// be invalidated by calls that adjust the number of samples in any
1008     /// pixel.
1009     const void* deep_pixel_ptr(int x, int y, int z, int c, int s = 0) const;
1010 
1011     /// Return the value (as a `float`) of sample `s` of channel `c` of
1012     /// pixel `(x,y,z)`.  Return 0 if not a deep image or if the pixel
1013     /// coordinates or channel number are out of range or if that pixel has
1014     /// no deep samples.
1015     float deep_value(int x, int y, int z, int c, int s) const;
1016 
1017     /// Return the value (as a `uint32_t`) of sample `s` of channel `c` of
1018     /// pixel `(x,y,z)`.  Return 0 if not a deep image or if the pixel
1019     /// coordinates or channel number are out of range or if that pixel has
1020     /// no deep samples.
1021     uint32_t deep_value_uint(int x, int y, int z, int c, int s) const;
1022 
1023     /// Set the number of deep samples for pixel (x,y,z).  If data has
1024     /// already been allocated, this is equivalent to inserting or erasing
1025     /// samples.
1026     void set_deep_samples(int x, int y, int z, int nsamples);
1027 
1028     /// Insert `nsamples` new samples, starting at position `samplepos` of
1029     /// pixel (x,y,z).
1030     void deep_insert_samples(int x, int y, int z, int samplepos, int nsamples);
1031 
1032     /// Remove `nsamples` samples, starting at position `samplepos` of pixel
1033     /// (x,y,z).
1034     void deep_erase_samples(int x, int y, int z, int samplepos, int nsamples);
1035 
1036     /// Set the value of sample `s` of channel `c` of pixel `(x,y,z)` to a
1037     /// `float` value (it is expected that channel `c` is a floating point
1038     /// type).
1039     void set_deep_value(int x, int y, int z, int c, int s, float value);
1040 
1041     /// Set the value of sample `s` of channel `c` of pixel `(x,y,z)` to a
1042     /// `uint32_t` value (it is expected that channel `c` is an integer
1043     /// type).
1044     void set_deep_value(int x, int y, int z, int c, int s, uint32_t value);
1045 
1046     /// Copy a deep pixel from another ImageBuf -- it is required to have
1047     /// the same channels.
1048     bool copy_deep_pixel(int x, int y, int z, const ImageBuf& src, int srcx,
1049                          int srcy, int srcz);
1050 
1051     /// Retrieve the "deep" data.
1052     DeepData* deepdata();
1053     const DeepData* deepdata() const;
1054 
1055     /// @}
1056 
1057     /// Return the `WrapMode` corresponding to the name (`"default"`,
1058     /// `"black"`, `"clamp"`, `"periodic"`, `"mirror"`). For an unknown
1059     /// name, this will return `WrapDefault`.
1060     static WrapMode WrapMode_from_string(string_view name);
1061 
1062 
1063     friend class IteratorBase;
1064 
1065     class IteratorBase {
1066     public:
IteratorBase(const ImageBuf & ib,WrapMode wrap)1067         IteratorBase(const ImageBuf& ib, WrapMode wrap)
1068             : m_ib(&ib)
1069         {
1070             init_ib(wrap);
1071             range_is_image();
1072         }
1073 
1074         /// Construct valid iteration region from ImageBuf and ROI.
IteratorBase(const ImageBuf & ib,const ROI & roi,WrapMode wrap)1075         IteratorBase(const ImageBuf& ib, const ROI& roi, WrapMode wrap)
1076             : m_ib(&ib)
1077         {
1078             init_ib(wrap);
1079             if (roi.defined()) {
1080                 m_rng_xbegin = roi.xbegin;
1081                 m_rng_xend   = roi.xend;
1082                 m_rng_ybegin = roi.ybegin;
1083                 m_rng_yend   = roi.yend;
1084                 m_rng_zbegin = roi.zbegin;
1085                 m_rng_zend   = roi.zend;
1086             } else {
1087                 range_is_image();
1088             }
1089         }
1090 
1091         /// Construct from an ImageBuf and designated region -- iterate
1092         /// over region, starting with the upper left pixel.
IteratorBase(const ImageBuf & ib,int xbegin,int xend,int ybegin,int yend,int zbegin,int zend,WrapMode wrap)1093         IteratorBase(const ImageBuf& ib, int xbegin, int xend, int ybegin,
1094                      int yend, int zbegin, int zend, WrapMode wrap)
1095             : m_ib(&ib)
1096         {
1097             init_ib(wrap);
1098             m_rng_xbegin = xbegin;
1099             m_rng_xend   = xend;
1100             m_rng_ybegin = ybegin;
1101             m_rng_yend   = yend;
1102             m_rng_zbegin = zbegin;
1103             m_rng_zend   = zend;
1104         }
1105 
IteratorBase(const IteratorBase & i)1106         IteratorBase(const IteratorBase& i)
1107             : m_ib(i.m_ib)
1108             , m_rng_xbegin(i.m_rng_xbegin)
1109             , m_rng_xend(i.m_rng_xend)
1110             , m_rng_ybegin(i.m_rng_ybegin)
1111             , m_rng_yend(i.m_rng_yend)
1112             , m_rng_zbegin(i.m_rng_zbegin)
1113             , m_rng_zend(i.m_rng_zend)
1114             , m_proxydata(i.m_proxydata)
1115         {
1116             init_ib(i.m_wrap);
1117         }
1118 
~IteratorBase()1119         ~IteratorBase()
1120         {
1121             if (m_tile)
1122                 m_ib->imagecache()->release_tile(m_tile);
1123         }
1124 
1125         /// Assign one IteratorBase to another
1126         ///
assign_base(const IteratorBase & i)1127         const IteratorBase& assign_base(const IteratorBase& i)
1128         {
1129             if (m_tile)
1130                 m_ib->imagecache()->release_tile(m_tile);
1131             m_tile      = nullptr;
1132             m_proxydata = i.m_proxydata;
1133             m_ib        = i.m_ib;
1134             init_ib(i.m_wrap);
1135             m_rng_xbegin = i.m_rng_xbegin;
1136             m_rng_xend   = i.m_rng_xend;
1137             m_rng_ybegin = i.m_rng_ybegin;
1138             m_rng_yend   = i.m_rng_yend;
1139             m_rng_zbegin = i.m_rng_zbegin;
1140             m_rng_zend   = i.m_rng_zend;
1141             return *this;
1142         }
1143 
1144         /// Retrieve the current x location of the iterator.
1145         ///
x()1146         int x() const { return m_x; }
1147         /// Retrieve the current y location of the iterator.
1148         ///
y()1149         int y() const { return m_y; }
1150         /// Retrieve the current z location of the iterator.
1151         ///
z()1152         int z() const { return m_z; }
1153 
1154         /// Is the current location within the designated iteration range?
valid()1155         bool valid() const { return m_valid; }
1156 
1157         /// Is the location (x,y[,z]) within the designated iteration
1158         /// range?
1159         bool valid(int x_, int y_, int z_ = 0) const
1160         {
1161             return (x_ >= m_rng_xbegin && x_ < m_rng_xend && y_ >= m_rng_ybegin
1162                     && y_ < m_rng_yend && z_ >= m_rng_zbegin
1163                     && z_ < m_rng_zend);
1164         }
1165 
1166         /// Is the location (x,y[,z]) within the region of the ImageBuf
1167         /// that contains pixel values (sometimes called the "data window")?
1168         bool exists(int x_, int y_, int z_ = 0) const
1169         {
1170             return (x_ >= m_img_xbegin && x_ < m_img_xend && y_ >= m_img_ybegin
1171                     && y_ < m_img_yend && z_ >= m_img_zbegin
1172                     && z_ < m_img_zend);
1173         }
1174         /// Does the current location exist within the ImageBuf's
1175         /// data window?
exists()1176         bool exists() const { return m_exists; }
1177 
1178         /// Are we finished iterating over the region?
1179         //
done()1180         bool done() const
1181         {
1182             // We're "done" if we are both invalid and in exactly the
1183             // spot that we would end up after iterating off of the last
1184             // pixel in the range.  (The m_valid test is just a quick
1185             // early-out for when we're in the correct pixel range.)
1186             return (m_valid == false && m_x == m_rng_xbegin
1187                     && m_y == m_rng_ybegin && m_z == m_rng_zend);
1188         }
1189 
1190         /// Retrieve the number of deep data samples at this pixel.
deep_samples()1191         int deep_samples() const { return m_ib->deep_samples(m_x, m_y, m_z); }
1192 
1193         /// Return the wrap mode
wrap()1194         WrapMode wrap() const { return m_wrap; }
1195 
1196         /// Explicitly point the iterator.  This results in an invalid
1197         /// iterator if outside the previously-designated region.
1198         void pos(int x_, int y_, int z_ = 0)
1199         {
1200             if (x_ == m_x + 1 && x_ < m_rng_xend && y_ == m_y && z_ == m_z
1201                 && m_valid && m_exists) {
1202                 // Special case for what is in effect just incrementing x
1203                 // within the iteration region.
1204                 m_x = x_;
1205                 pos_xincr();
1206                 // Not necessary? m_exists = (x_ < m_img_xend);
1207                 OIIO_DASSERT((x_ < m_img_xend) == m_exists);
1208                 return;
1209             }
1210             bool v = valid(x_, y_, z_);
1211             bool e = exists(x_, y_, z_);
1212             if (m_localpixels) {
1213                 if (e)
1214                     m_proxydata = (char*)m_ib->pixeladdr(x_, y_, z_);
1215                 else {  // pixel not in data window
1216                     m_x = x_;
1217                     m_y = y_;
1218                     m_z = z_;
1219                     if (m_wrap == WrapBlack) {
1220                         m_proxydata = (char*)m_ib->blackpixel();
1221                     } else {
1222                         if (m_ib->do_wrap(x_, y_, z_, m_wrap))
1223                             m_proxydata = (char*)m_ib->pixeladdr(x_, y_, z_);
1224                         else
1225                             m_proxydata = (char*)m_ib->blackpixel();
1226                     }
1227                     m_valid  = v;
1228                     m_exists = e;
1229                     return;
1230                 }
1231             } else if (!m_deep)
1232                 m_proxydata = (char*)m_ib->retile(x_, y_, z_, m_tile,
1233                                                   m_tilexbegin, m_tileybegin,
1234                                                   m_tilezbegin, m_tilexend, e,
1235                                                   m_wrap);
1236             m_x      = x_;
1237             m_y      = y_;
1238             m_z      = z_;
1239             m_valid  = v;
1240             m_exists = e;
1241         }
1242 
1243         /// Increment to the next pixel in the region.
1244         ///
1245         OIIO_FORCEINLINE void operator++()
1246         {
1247             if (++m_x < m_rng_xend) {
1248                 // Special case: we only incremented x, didn't change y
1249                 // or z, and the previous position was within the data
1250                 // window.  Call a shortcut version of pos.
1251                 if (m_exists) {
1252                     pos_xincr();
1253                     return;
1254                 }
1255             } else {
1256                 // Wrap to the next scanline
1257                 m_x = m_rng_xbegin;
1258                 if (++m_y >= m_rng_yend) {
1259                     m_y = m_rng_ybegin;
1260                     if (++m_z >= m_rng_zend) {
1261                         m_valid = false;  // shortcut -- finished iterating
1262                         return;
1263                     }
1264                 }
1265             }
1266             pos(m_x, m_y, m_z);
1267         }
1268         /// Increment to the next pixel in the region.
1269         ///
1270         void operator++(int) { ++(*this); }
1271 
1272         /// Return the iteration range
range()1273         ROI range() const
1274         {
1275             return ROI(m_rng_xbegin, m_rng_xend, m_rng_ybegin, m_rng_yend,
1276                        m_rng_zbegin, m_rng_zend, 0, m_ib->nchannels());
1277         }
1278 
1279         /// Reset the iteration range for this iterator and reposition to
1280         /// the beginning of the range, but keep referring to the same
1281         /// image.
1282         void rerange(int xbegin, int xend, int ybegin, int yend, int zbegin,
1283                      int zend, WrapMode wrap = WrapDefault)
1284         {
1285             m_x          = 1 << 31;
1286             m_y          = 1 << 31;
1287             m_z          = 1 << 31;
1288             m_wrap       = (wrap == WrapDefault ? WrapBlack : wrap);
1289             m_rng_xbegin = xbegin;
1290             m_rng_xend   = xend;
1291             m_rng_ybegin = ybegin;
1292             m_rng_yend   = yend;
1293             m_rng_zbegin = zbegin;
1294             m_rng_zend   = zend;
1295             pos(xbegin, ybegin, zbegin);
1296         }
1297 
1298     protected:
1299         friend class ImageBuf;
1300         friend class ImageBufImpl;
1301         const ImageBuf* m_ib = nullptr;
1302         bool m_valid = false, m_exists = false;
1303         bool m_deep        = false;
1304         bool m_localpixels = false;
1305         // Image boundaries
1306         int m_img_xbegin, m_img_xend, m_img_ybegin, m_img_yend, m_img_zbegin,
1307             m_img_zend;
1308         // Iteration range
1309         int m_rng_xbegin, m_rng_xend, m_rng_ybegin, m_rng_yend, m_rng_zbegin,
1310             m_rng_zend;
1311         int m_x, m_y, m_z;
1312         ImageCache::Tile* m_tile = nullptr;
1313         int m_tilexbegin, m_tileybegin, m_tilezbegin;
1314         int m_tilexend;
1315         int m_nchannels;
1316         size_t m_pixel_bytes;
1317         char* m_proxydata = nullptr;
1318         WrapMode m_wrap   = WrapBlack;
1319 
1320         // Helper called by ctrs -- set up some locally cached values
1321         // that are copied or derived from the ImageBuf.
init_ib(WrapMode wrap)1322         void init_ib(WrapMode wrap)
1323         {
1324             const ImageSpec& spec(m_ib->spec());
1325             m_deep        = spec.deep;
1326             m_localpixels = (m_ib->localpixels() != nullptr);
1327             m_img_xbegin  = spec.x;
1328             m_img_xend    = spec.x + spec.width;
1329             m_img_ybegin  = spec.y;
1330             m_img_yend    = spec.y + spec.height;
1331             m_img_zbegin  = spec.z;
1332             m_img_zend    = spec.z + spec.depth;
1333             m_nchannels   = spec.nchannels;
1334             //            m_tilewidth = spec.tile_width;
1335             m_pixel_bytes = spec.pixel_bytes();
1336             m_x           = 1 << 31;
1337             m_y           = 1 << 31;
1338             m_z           = 1 << 31;
1339             m_wrap        = (wrap == WrapDefault ? WrapBlack : wrap);
1340         }
1341 
1342         // Helper called by ctrs -- make the iteration range the full
1343         // image data window.
range_is_image()1344         void range_is_image()
1345         {
1346             m_rng_xbegin = m_img_xbegin;
1347             m_rng_xend   = m_img_xend;
1348             m_rng_ybegin = m_img_ybegin;
1349             m_rng_yend   = m_img_yend;
1350             m_rng_zbegin = m_img_zbegin;
1351             m_rng_zend   = m_img_zend;
1352         }
1353 
1354         // Helper called by pos(), but ONLY for the case where we are
1355         // moving from an existing pixel to the next spot in +x.
1356         // Note: called *after* m_x was incremented!
pos_xincr()1357         OIIO_FORCEINLINE void pos_xincr()
1358         {
1359             OIIO_DASSERT(m_exists && m_valid);   // precondition
1360             OIIO_DASSERT(valid(m_x, m_y, m_z));  // should be true by definition
1361             m_proxydata += m_pixel_bytes;
1362             if (m_localpixels) {
1363                 if (OIIO_UNLIKELY(m_x >= m_img_xend)) {
1364                     // Ran off the end of the row
1365                     m_exists = false;
1366                     if (m_wrap == WrapBlack) {
1367                         m_proxydata = (char*)m_ib->blackpixel();
1368                     } else {
1369                         int x = m_x, y = m_y, z = m_z;
1370                         if (m_ib->do_wrap(x, y, z, m_wrap))
1371                             m_proxydata = (char*)m_ib->pixeladdr(x, y, z);
1372                         else
1373                             m_proxydata = (char*)m_ib->blackpixel();
1374                     }
1375                 }
1376             } else if (m_deep) {
1377                 m_proxydata = nullptr;
1378             } else {
1379                 // Cached image
1380                 bool e = m_x < m_img_xend;
1381                 if (OIIO_UNLIKELY(!(e && m_x < m_tilexend && m_tile))) {
1382                     // Crossed a tile boundary
1383                     m_proxydata = (char*)m_ib->retile(m_x, m_y, m_z, m_tile,
1384                                                       m_tilexbegin,
1385                                                       m_tileybegin,
1386                                                       m_tilezbegin, m_tilexend,
1387                                                       e, m_wrap);
1388                     m_exists    = e;
1389                 }
1390             }
1391         }
1392 
1393         // Set to the "done" position
pos_done()1394         void pos_done()
1395         {
1396             m_valid = false;
1397             m_x     = m_rng_xbegin;
1398             m_y     = m_rng_ybegin;
1399             m_z     = m_rng_zend;
1400         }
1401 
1402         // Make sure it's writable. Use with caution!
make_writable()1403         void make_writable()
1404         {
1405             if (!m_localpixels) {
1406                 const_cast<ImageBuf*>(m_ib)->make_writable(true);
1407                 OIIO_DASSERT(m_ib->storage() != IMAGECACHE);
1408                 m_tile      = nullptr;
1409                 m_proxydata = nullptr;
1410                 init_ib(m_wrap);
1411             }
1412         }
1413     };
1414 
1415     /// Templated class for referring to an individual pixel in an
1416     /// ImageBuf, iterating over the pixels of an ImageBuf, or iterating
1417     /// over the pixels of a specified region of the ImageBuf
1418     /// [xbegin..xend) X [ybegin..yend).  It is templated on BUFT, the
1419     /// type known to be in the internal representation of the ImageBuf,
1420     /// and USERT, the type that the user wants to retrieve or set the
1421     /// data (defaulting to float).  the whole idea is to allow this:
1422     /// \code
1423     ///   ImageBuf img (...);
1424     ///   ImageBuf::Iterator<float> pixel (img, 0, 512, 0, 512);
1425     ///   for (  ;  ! pixel.done();  ++pixel) {
1426     ///       for (int c = 0;  c < img.nchannels();  ++c) {
1427     ///           float x = pixel[c];
1428     ///           pixel[c] = ...;
1429     ///       }
1430     ///   }
1431     /// \endcode
1432     ///
1433     template<typename BUFT, typename USERT = float>
1434     class Iterator : public IteratorBase {
1435     public:
1436         /// Construct from just an ImageBuf -- iterate over the whole
1437         /// region, starting with the upper left pixel of the region.
1438         Iterator(ImageBuf& ib, WrapMode wrap = WrapDefault)
IteratorBase(ib,wrap)1439             : IteratorBase(ib, wrap)
1440         {
1441             make_writable();
1442             pos(m_rng_xbegin, m_rng_ybegin, m_rng_zbegin);
1443             if (m_rng_xbegin == m_rng_xend || m_rng_ybegin == m_rng_yend
1444                 || m_rng_zbegin == m_rng_zend)
1445                 pos_done();  // make empty range look "done"
1446         }
1447         /// Construct from an ImageBuf and a specific pixel index.
1448         /// The iteration range is the full image.
1449         Iterator(ImageBuf& ib, int x, int y, int z = 0,
1450                  WrapMode wrap = WrapDefault)
IteratorBase(ib,wrap)1451             : IteratorBase(ib, wrap)
1452         {
1453             make_writable();
1454             pos(x, y, z);
1455         }
1456         /// Construct read-write iteration region from ImageBuf and ROI.
1457         Iterator(ImageBuf& ib, const ROI& roi, WrapMode wrap = WrapDefault)
IteratorBase(ib,roi,wrap)1458             : IteratorBase(ib, roi, wrap)
1459         {
1460             make_writable();
1461             pos(m_rng_xbegin, m_rng_ybegin, m_rng_zbegin);
1462             if (m_rng_xbegin == m_rng_xend || m_rng_ybegin == m_rng_yend
1463                 || m_rng_zbegin == m_rng_zend)
1464                 pos_done();  // make empty range look "done"
1465         }
1466         /// Construct from an ImageBuf and designated region -- iterate
1467         /// over region, starting with the upper left pixel.
1468         Iterator(ImageBuf& ib, int xbegin, int xend, int ybegin, int yend,
1469                  int zbegin = 0, int zend = 1, WrapMode wrap = WrapDefault)
IteratorBase(ib,xbegin,xend,ybegin,yend,zbegin,zend,wrap)1470             : IteratorBase(ib, xbegin, xend, ybegin, yend, zbegin, zend, wrap)
1471         {
1472             make_writable();
1473             pos(m_rng_xbegin, m_rng_ybegin, m_rng_zbegin);
1474             if (m_rng_xbegin == m_rng_xend || m_rng_ybegin == m_rng_yend
1475                 || m_rng_zbegin == m_rng_zend)
1476                 pos_done();  // make empty range look "done"
1477         }
1478         /// Copy constructor.
1479         ///
Iterator(Iterator & i)1480         Iterator(Iterator& i)
1481             : IteratorBase(i.m_ib, i.m_wrap)
1482         {
1483             make_writable();
1484             pos(i.m_x, i.m_y, i.m_z);
1485         }
1486 
~Iterator()1487         ~Iterator() {}
1488 
1489         /// Assign one Iterator to another
1490         ///
1491         const Iterator& operator=(const Iterator& i)
1492         {
1493             assign_base(i);
1494             pos(i.m_x, i.m_y, i.m_z);
1495             return *this;
1496         }
1497 
1498         /// Dereferencing the iterator gives us a proxy for the pixel,
1499         /// which we can index for reading or assignment.
1500         DataArrayProxy<BUFT, USERT>& operator*()
1501         {
1502             return *(DataArrayProxy<BUFT, USERT>*)(void*)&m_proxydata;
1503         }
1504 
1505         /// Array indexing retrieves the value of the i-th channel of
1506         /// the current pixel.
1507         USERT operator[](int i) const
1508         {
1509             DataArrayProxy<BUFT, USERT> proxy((BUFT*)m_proxydata);
1510             return proxy[i];
1511         }
1512 
1513         /// Array referencing retrieve a proxy (which may be "assigned
1514         /// to") of i-th channel of the current pixel, so that this
1515         /// works: me[i] = val;
1516         DataProxy<BUFT, USERT> operator[](int i)
1517         {
1518             DataArrayProxy<BUFT, USERT> proxy((BUFT*)m_proxydata);
1519             return proxy[i];
1520         }
1521 
rawptr()1522         void* rawptr() const { return m_proxydata; }
1523 
1524         /// Set the number of deep data samples at this pixel. (Only use
1525         /// this if deep_alloc() has not yet been called on the buffer.)
set_deep_samples(int n)1526         void set_deep_samples(int n)
1527         {
1528             return const_cast<ImageBuf*>(m_ib)->set_deep_samples(m_x, m_y, m_z,
1529                                                                  n);
1530         }
1531 
1532         /// Retrieve the deep data value of sample s of channel c.
deep_value(int c,int s)1533         USERT deep_value(int c, int s) const
1534         {
1535             return convert_type<float, USERT>(
1536                 m_ib->deep_value(m_x, m_y, m_z, c, s));
1537         }
deep_value_uint(int c,int s)1538         uint32_t deep_value_uint(int c, int s) const
1539         {
1540             return m_ib->deep_value_uint(m_x, m_y, m_z, c, s);
1541         }
1542 
1543         /// Set the deep data value of sample s of channel c. (Only use this
1544         /// if deep_alloc() has been called.)
set_deep_value(int c,int s,float value)1545         void set_deep_value(int c, int s, float value)
1546         {
1547             return const_cast<ImageBuf*>(m_ib)->set_deep_value(m_x, m_y, m_z, c,
1548                                                                s, value);
1549         }
set_deep_value(int c,int s,uint32_t value)1550         void set_deep_value(int c, int s, uint32_t value)
1551         {
1552             return const_cast<ImageBuf*>(m_ib)->set_deep_value(m_x, m_y, m_z, c,
1553                                                                s, value);
1554         }
1555     };
1556 
1557 
1558     /// Just like an ImageBuf::Iterator, except that it refers to a
1559     /// const ImageBuf.
1560     template<typename BUFT, typename USERT = float>
1561     class ConstIterator : public IteratorBase {
1562     public:
1563         /// Construct from just an ImageBuf -- iterate over the whole
1564         /// region, starting with the upper left pixel of the region.
1565         ConstIterator(const ImageBuf& ib, WrapMode wrap = WrapDefault)
IteratorBase(ib,wrap)1566             : IteratorBase(ib, wrap)
1567         {
1568             pos(m_rng_xbegin, m_rng_ybegin, m_rng_zbegin);
1569             if (m_rng_xbegin == m_rng_xend || m_rng_ybegin == m_rng_yend
1570                 || m_rng_zbegin == m_rng_zend)
1571                 pos_done();  // make empty range look "done"
1572         }
1573         /// Construct from an ImageBuf and a specific pixel index.
1574         /// The iteration range is the full image.
1575         ConstIterator(const ImageBuf& ib, int x_, int y_, int z_ = 0,
1576                       WrapMode wrap = WrapDefault)
IteratorBase(ib,wrap)1577             : IteratorBase(ib, wrap)
1578         {
1579             pos(x_, y_, z_);
1580         }
1581         /// Construct read-only iteration region from ImageBuf and ROI.
1582         ConstIterator(const ImageBuf& ib, const ROI& roi,
1583                       WrapMode wrap = WrapDefault)
IteratorBase(ib,roi,wrap)1584             : IteratorBase(ib, roi, wrap)
1585         {
1586             pos(m_rng_xbegin, m_rng_ybegin, m_rng_zbegin);
1587             if (m_rng_xbegin == m_rng_xend || m_rng_ybegin == m_rng_yend
1588                 || m_rng_zbegin == m_rng_zend)
1589                 pos_done();  // make empty range look "done"
1590         }
1591         /// Construct from an ImageBuf and designated region -- iterate
1592         /// over region, starting with the upper left pixel.
1593         ConstIterator(const ImageBuf& ib, int xbegin, int xend, int ybegin,
1594                       int yend, int zbegin = 0, int zend = 1,
1595                       WrapMode wrap = WrapDefault)
IteratorBase(ib,xbegin,xend,ybegin,yend,zbegin,zend,wrap)1596             : IteratorBase(ib, xbegin, xend, ybegin, yend, zbegin, zend, wrap)
1597         {
1598             pos(m_rng_xbegin, m_rng_ybegin, m_rng_zbegin);
1599             if (m_rng_xbegin == m_rng_xend || m_rng_ybegin == m_rng_yend
1600                 || m_rng_zbegin == m_rng_zend)
1601                 pos_done();  // make empty range look "done"
1602         }
1603         /// Copy constructor.
1604         ///
ConstIterator(const ConstIterator & i)1605         ConstIterator(const ConstIterator& i)
1606             : IteratorBase(i)
1607         {
1608             pos(i.m_x, i.m_y, i.m_z);
1609         }
1610 
~ConstIterator()1611         ~ConstIterator() {}
1612 
1613         /// Assign one ConstIterator to another
1614         ///
1615         const ConstIterator& operator=(const ConstIterator& i)
1616         {
1617             assign_base(i);
1618             pos(i.m_x, i.m_y, i.m_z);
1619             return *this;
1620         }
1621 
1622         /// Dereferencing the iterator gives us a proxy for the pixel,
1623         /// which we can index for reading or assignment.
1624         ConstDataArrayProxy<BUFT, USERT>& operator*() const
1625         {
1626             return *(ConstDataArrayProxy<BUFT, USERT>*)&m_proxydata;
1627         }
1628 
1629         /// Array indexing retrieves the value of the i-th channel of
1630         /// the current pixel.
1631         USERT operator[](int i) const
1632         {
1633             ConstDataArrayProxy<BUFT, USERT> proxy((BUFT*)m_proxydata);
1634             return proxy[i];
1635         }
1636 
rawptr()1637         const void* rawptr() const { return m_proxydata; }
1638 
1639         /// Retrieve the deep data value of sample s of channel c.
deep_value(int c,int s)1640         USERT deep_value(int c, int s) const
1641         {
1642             return convert_type<float, USERT>(
1643                 m_ib->deep_value(m_x, m_y, m_z, c, s));
1644         }
deep_value_uint(int c,int s)1645         uint32_t deep_value_uint(int c, int s) const
1646         {
1647             return m_ib->deep_value_uint(m_x, m_y, m_z, c, s);
1648         }
1649     };
1650 
1651 
1652 protected:
1653     // PIMPL idiom
1654     static void impl_deleter(ImageBufImpl*);
1655     std::unique_ptr<ImageBufImpl, decltype(&impl_deleter)> m_impl;
1656 
1657     // Reset the ImageCache::Tile * to reserve and point to the correct
1658     // tile for the given pixel, and return the ptr to the actual pixel
1659     // within the tile.
1660     const void* retile(int x, int y, int z, ImageCache::Tile*& tile,
1661                        int& tilexbegin, int& tileybegin, int& tilezbegin,
1662                        int& tilexend, bool exists,
1663                        WrapMode wrap = WrapDefault) const;
1664 
1665     const void* blackpixel() const;
1666 
1667     // Given x,y,z known to be outside the pixel data range, and a wrap
1668     // mode, alter xyz to implement the wrap. Return true if the resulting
1669     // x,y,z is within the valid pixel data window, false if it still is
1670     // not.
1671     bool do_wrap(int& x, int& y, int& z, WrapMode wrap) const;
1672 };
1673 
1674 
1675 OIIO_NAMESPACE_END
1676