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