OpenImageIO
 All Classes Files Friends Macros Pages
imagebuf.h
Go to the documentation of this file.
1 /*
2  Copyright 2008 Larry Gritz and the other authors and contributors.
3  All Rights Reserved.
4 
5  Redistribution and use in source and binary forms, with or without
6  modification, are permitted provided that the following conditions are
7  met:
8  * Redistributions of source code must retain the above copyright
9  notice, this list of conditions and the following disclaimer.
10  * Redistributions in binary form must reproduce the above copyright
11  notice, this list of conditions and the following disclaimer in the
12  documentation and/or other materials provided with the distribution.
13  * Neither the name of the software's owners nor the names of its
14  contributors may be used to endorse or promote products derived from
15  this software without specific prior written permission.
16  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28  (This is the Modified BSD License)
29 */
30 
31 
35 
36 
37 #ifndef OPENIMAGEIO_IMAGEBUF_H
38 #define OPENIMAGEIO_IMAGEBUF_H
39 
40 #if defined(_MSC_VER)
41 // Ignore warnings about DLL exported classes with member variables that are template classes.
42 // This happens with the std::vector and std::string protected members of ImageBuf below.
43 # pragma warning (disable : 4251)
44 #endif
45 
46 #include "imageio.h"
47 #include "fmath.h"
48 #include "imagecache.h"
49 #include "dassert.h"
50 
51 #include <limits>
52 
53 
54 OIIO_NAMESPACE_ENTER
55 {
56 
57 class ImageBuf;
58 
59 
64 struct ROI {
65  int xbegin, xend, ybegin, yend, zbegin, zend;
66  int chbegin, chend;
67 
70  ROI () : xbegin(std::numeric_limits<int>::min()) { }
71 
74  ROI (int xbegin, int xend, int ybegin, int yend,
75  int zbegin=0, int zend=1, int chbegin=0, int chend=10000)
76  : xbegin(xbegin), xend(xend), ybegin(ybegin), yend(yend),
77  zbegin(zbegin), zend(zend), chbegin(chbegin), chend(chend)
78  { }
79 
81  bool defined () const { return (xbegin != std::numeric_limits<int>::min()); }
82 
83  // Region dimensions.
84  int width () const { return xend - xbegin; }
85  int height () const { return yend - ybegin; }
86  int depth () const { return zend - zbegin; }
87 
91  int nchannels () const { return chend - chbegin; }
92 
94  imagesize_t npixels () const {
95  if (! defined())
96  return 0;
97  imagesize_t w = width(), h = height(), d = depth();
98  return w*h*d;
99  }
100 
107  static ROI All () { return ROI(); }
108 
110  friend bool operator== (const ROI &a, const ROI &b) {
111  return (a.xbegin == b.xbegin && a.xend == b.xend &&
112  a.ybegin == b.ybegin && a.yend == b.yend &&
113  a.zbegin == b.zbegin && a.zend == b.zend &&
114  a.chbegin == b.chbegin && a.chend == b.chend);
115  }
117  friend bool operator!= (const ROI &a, const ROI &b) {
118  return (a.xbegin != b.xbegin || a.xend != b.xend ||
119  a.ybegin != b.ybegin || a.yend != b.yend ||
120  a.zbegin != b.zbegin || a.zend != b.zend ||
121  a.chbegin != b.chbegin || a.chend != b.chend);
122  }
123 
125  friend std::ostream & operator<< (std::ostream &out, const ROI &roi) {
126  out << roi.xbegin << ' ' << roi.xend << ' ' << roi.ybegin << ' '
127  << roi.yend << ' ' << roi.zbegin << ' ' << roi.zend << ' '
128  << roi.chbegin << ' ' << roi.chend;
129  return out;
130  }
131 };
132 
133 
135 OIIO_API ROI roi_union (const ROI &A, const ROI &B);
136 
138 OIIO_API ROI roi_intersection (const ROI &A, const ROI &B);
139 
141 OIIO_API ROI get_roi (const ImageSpec &spec);
142 
144 OIIO_API ROI get_roi_full (const ImageSpec &spec);
145 
148 OIIO_API void set_roi (ImageSpec &spec, const ROI &newroi);
149 
152 OIIO_API void set_roi_full (ImageSpec &spec, const ROI &newroi);
153 
154 
155 
156 class ImageBufImpl; // Opaque pointer
157 
158 
159 
165 class OIIO_API ImageBuf {
166 public:
169  ImageBuf ();
170 
175  ImageBuf (const std::string &name, ImageCache *imagecache = NULL);
176 
180  ImageBuf (const std::string &name, const ImageSpec &spec);
181 
185  ImageBuf (const std::string &name, const ImageSpec &spec, void *buffer);
186 
189  ImageBuf (const ImageBuf &src);
190 
193  ~ImageBuf ();
194 
197  void clear ();
198 
201  void reset (const std::string &name, ImageCache *imagecache = NULL);
202 
205  void reset (const std::string &name, const ImageSpec &spec);
206 
212  void alloc (const ImageSpec &spec);
213 
215  bool initialized () const;
216 
222  bool read (int subimage=0, int miplevel=0, bool force=false,
223  TypeDesc convert=TypeDesc::UNKNOWN,
224  ProgressCallback progress_callback=NULL,
225  void *progress_callback_data=NULL);
226 
231  bool init_spec (const std::string &filename,
232  int subimage, int miplevel);
233 
238  bool save (const std::string &filename = std::string(),
239  const std::string &fileformat = std::string(),
240  ProgressCallback progress_callback=NULL,
241  void *progress_callback_data=NULL) const;
242 
247  bool write (ImageOutput *out,
248  ProgressCallback progress_callback=NULL,
249  void *progress_callback_data=NULL) const;
250 
253  void copy_metadata (const ImageBuf &src);
254 
260  bool copy_pixels (const ImageBuf &src);
261 
276  bool copy (const ImageBuf &src);
277 
279  void swap (ImageBuf &other) { std::swap (m_impl, other.m_impl); }
280 
284  TINYFORMAT_WRAP_FORMAT (void, error, const,
285  std::ostringstream msg;, msg, append_error(msg.str());)
286 
289  bool has_error (void) const;
290 
294  std::string geterror (void) const;
295 
298  const ImageSpec & spec () const;
299 
304  ImageSpec & specmod ();
305 
311  const ImageSpec & nativespec () const;
312 
315  const std::string & name (void) const;
316 
320  const std::string & file_format_name (void) const;
321 
324  int subimage () const;
325 
328  int nsubimages () const;
329 
332  int miplevel () const;
333 
336  int nmiplevels () const;
337 
340  int nchannels () const;
341 
344  enum WrapMode { WrapDefault, WrapBlack, WrapClamp, WrapPeriodic,
345  WrapMirror, _WrapLast };
346 
349  float getchannel (int x, int y, int z, int c, WrapMode wrap=WrapBlack) const;
350 
354  void getpixel (int x, int y, float *pixel, int maxchannels=1000) const {
355  getpixel (x, y, 0, pixel, maxchannels);
356  }
357 
361  void getpixel (int x, int y, int z, float *pixel, int maxchannels=1000,
362  WrapMode wrap=WrapBlack) const;
363 
367  void interppixel (float x, float y, float *pixel,
368  WrapMode wrap=WrapBlack) const;
369 
376  void interppixel_NDC (float s, float t, float *pixel,
377  WrapMode wrap=WrapBlack) const;
378 
382  void interppixel_NDC_full (float s, float t, float *pixel,
383  WrapMode wrap=WrapBlack) const;
384 
388  void setpixel (int x, int y, const float *pixel, int maxchannels=1000) {
389  setpixel (x, y, 0, pixel, maxchannels);
390  }
391 
395  void setpixel (int x, int y, int z,
396  const float *pixel, int maxchannels=1000);
397 
401  void setpixel (int i, const float *pixel, int maxchannels=1000);
402 
414  bool get_pixel_channels (int xbegin, int xend, int ybegin, int yend,
415  int zbegin, int zend, int chbegin, int chend,
416  TypeDesc format, void *result,
417  stride_t xstride=AutoStride,
418  stride_t ystride=AutoStride,
419  stride_t zstride=AutoStride) const;
420 
431  bool get_pixels (int xbegin, int xend, int ybegin, int yend,
432  int zbegin, int zend,
433  TypeDesc format, void *result,
434  stride_t xstride=AutoStride,
435  stride_t ystride=AutoStride,
436  stride_t zstride=AutoStride) const;
437 
448  template<typename T>
449  bool get_pixel_channels (int xbegin, int xend, int ybegin, int yend,
450  int zbegin, int zend, int chbegin, int chend,
451  T *result, stride_t xstride=AutoStride,
452  stride_t ystride=AutoStride,
453  stride_t zstride=AutoStride) const;
454 
455  template<typename T>
456  bool get_pixels (int xbegin, int xend, int ybegin, int yend,
457  int zbegin, int zend, T *result,
458  stride_t xstride=AutoStride, stride_t ystride=AutoStride,
459  stride_t zstride=AutoStride) const
460  {
461  return get_pixel_channels (xbegin, xend, ybegin, yend, zbegin, zend,
462  0, nchannels(), result,
463  xstride, ystride, zstride);
464  }
465 
472  template<typename T>
473  bool get_pixels (int xbegin_, int xend_, int ybegin_, int yend_,
474  int zbegin_, int zend_,
475  std::vector<T> &result) const
476  {
477  result.resize (nchannels() * ((zend_-zbegin_)*(yend_-ybegin_)*(xend_-xbegin_)));
478  return get_pixels (xbegin_, xend_, ybegin_, yend_, zbegin_, zend_,
479  &result[0]);
480  }
481 
482  int orientation () const;
483 
484  int oriented_width () const;
485  int oriented_height () const;
486  int oriented_x () const;
487  int oriented_y () const;
488  int oriented_full_width () const;
489  int oriented_full_height () const;
490  int oriented_full_x () const;
491  int oriented_full_y () const;
492 
494  int xbegin () const;
495 
497  int xend () const;
498 
500  int ybegin () const;
501 
503  int yend () const;
504 
506  int zbegin () const;
507 
509  int zend () const;
510 
512  int xmin () const;
513 
515  int xmax () const;
516 
518  int ymin () const;
519 
521  int ymax () const;
522 
524  int zmin () const;
525 
527  int zmax () const;
528 
532  void set_full (int xbegin, int xend, int ybegin, int yend,
533  int zbegin, int zend, const float *bordercolor=NULL);
534 
535  bool pixels_valid (void) const;
536 
537  TypeDesc pixeltype () const;
538 
542  void *localpixels ();
543  const void *localpixels () const;
544 
547  bool cachedpixels () const;
548 
549  ImageCache *imagecache () const;
550 
554  const void *pixeladdr (int x, int y, int z=0) const;
555 
559  void *pixeladdr (int x, int y) { return pixeladdr (x, y, 0); }
560 
564  void *pixeladdr (int x, int y, int z);
565 
567  bool deep () const;
568 
572  int deep_samples (int x, int y, int z=0) const;
573 
578  const void *deep_pixel_ptr (int x, int y, int z, int c) const;
579 
584  float deep_value (int x, int y, int z, int c, int s) const;
585 
587  DeepData *deepdata ();
588  const DeepData *deepdata () const;
589 
590  friend class IteratorBase;
591 
592  class IteratorBase {
593  public:
594  IteratorBase (const ImageBuf &ib, WrapMode wrap)
595  : m_ib(&ib), m_tile(NULL), m_proxydata(NULL)
596  {
597  init_ib (wrap);
598  range_is_image ();
599  }
600 
602  IteratorBase (const ImageBuf &ib, const ROI &roi, WrapMode wrap)
603  : m_ib(&ib), m_tile(NULL), m_proxydata(NULL)
604  {
605  init_ib (wrap);
606  if (roi.defined()) {
607  m_rng_xbegin = roi.xbegin;
608  m_rng_xend = roi.xend;
609  m_rng_ybegin = roi.ybegin;
610  m_rng_yend = roi.yend;
611  m_rng_zbegin = roi.zbegin;
612  m_rng_zend = roi.zend;
613  } else {
614  range_is_image ();
615  }
616  }
617 
620  IteratorBase (const ImageBuf &ib, int xbegin, int xend,
621  int ybegin, int yend, int zbegin, int zend,
622  WrapMode wrap)
623  : m_ib(&ib), m_tile(NULL), m_proxydata(NULL)
624  {
625  init_ib (wrap);
626  m_rng_xbegin = xbegin;
627  m_rng_xend = xend;
628  m_rng_ybegin = ybegin;
629  m_rng_yend = yend;
630  m_rng_zbegin = zbegin;
631  m_rng_zend = zend;
632  }
633 
634  IteratorBase (const IteratorBase &i)
635  : m_ib (i.m_ib),
636  m_rng_xbegin(i.m_rng_xbegin), m_rng_xend(i.m_rng_xend),
637  m_rng_ybegin(i.m_rng_ybegin), m_rng_yend(i.m_rng_yend),
638  m_rng_zbegin(i.m_rng_zbegin), m_rng_zend(i.m_rng_zend),
639  m_tile(NULL), m_proxydata(i.m_proxydata)
640  {
641  init_ib (i.m_wrap);
642  }
643 
644  ~IteratorBase () {
645  if (m_tile)
646  m_ib->imagecache()->release_tile (m_tile);
647  }
648 
651  const IteratorBase & assign_base (const IteratorBase &i) {
652  if (m_tile)
653  m_ib->imagecache()->release_tile (m_tile);
654  m_tile = NULL;
655  m_proxydata = i.m_proxydata;
656  m_ib = i.m_ib;
657  init_ib (i.m_wrap);
658  m_rng_xbegin = i.m_rng_xbegin; m_rng_xend = i.m_rng_xend;
659  m_rng_ybegin = i.m_rng_ybegin; m_rng_yend = i.m_rng_yend;
660  m_rng_zbegin = i.m_rng_zbegin; m_rng_zend = i.m_rng_zend;
661  return *this;
662  }
663 
666  int x () const { return m_x; }
669  int y () const { return m_y; }
672  int z () const { return m_z; }
673 
675  bool valid () const {
676  return m_valid;
677  }
678 
681  bool valid (int x_, int y_, int z_=0) const {
682  return (x_ >= m_rng_xbegin && x_ < m_rng_xend &&
683  y_ >= m_rng_ybegin && y_ < m_rng_yend &&
684  z_ >= m_rng_zbegin && z_ < m_rng_zend);
685  }
686 
689  bool exists (int x_, int y_, int z_=0) const {
690  return (x_ >= m_img_xbegin && x_ < m_img_xend &&
691  y_ >= m_img_ybegin && y_ < m_img_yend &&
692  z_ >= m_img_zbegin && z_ < m_img_zend);
693  }
696  bool exists () const {
697  return m_exists;
698  }
699 
701  //
702  bool done () const {
703  // We're "done" if we are both invalid and in exactly the
704  // spot that we would end up after iterating off of the last
705  // pixel in the range. (The m_valid test is just a quick
706  // early-out for when we're in the correct pixel range.)
707  return (m_valid == false && m_x == m_rng_xbegin &&
708  m_y == m_rng_ybegin && m_z == m_rng_zend);
709  }
710 
712  int deep_samples () { return m_ib->deep_samples (m_x, m_y, m_z); }
713 
715  WrapMode wrap () const { return m_wrap; }
716 
719  void pos (int x_, int y_, int z_=0) {
720  if (x_ == m_x+1 && x_ < m_rng_xend && y_ == m_y && z_ == m_z &&
721  m_valid && m_exists) {
722  // Special case for what is in effect just incrementing x
723  // within the iteration region.
724  m_x = x_;
725  pos_xincr ();
726  // Not necessary? m_exists = (x_ < m_img_xend);
727  DASSERT ((x_ < m_img_xend) == m_exists);
728  return;
729  }
730  bool v = valid(x_,y_,z_);
731  bool e = exists(x_,y_,z_);
732  if (m_localpixels) {
733  if (! e) {
734  m_x = x_; m_y = y_; m_z = z_;
735  if (m_wrap == WrapBlack) {
736  m_proxydata = (char *)m_ib->blackpixel();
737  } else {
738  m_ib->do_wrap (x_, y_, z_, m_wrap);
739  m_proxydata = (char *)m_ib->pixeladdr (x_, y_, z_);
740  }
741  m_valid = v;
742  m_exists = e;
743  return;
744  }
745  else
746  m_proxydata = (char *)m_ib->pixeladdr (x_, y_, z_);
747  }
748  else if (! m_deep)
749  m_proxydata = (char *)m_ib->retile (x_, y_, z_, m_tile,
750  m_tilexbegin, m_tileybegin,
751  m_tilezbegin, m_tilexend,
752  e, m_wrap);
753  m_x = x_; m_y = y_; m_z = z_;
754  m_valid = v;
755  m_exists = e;
756  }
757 
760  void operator++ () {
761  if (++m_x < m_rng_xend) {
762  // Special case: we only incremented x, didn't change y
763  // or z, and the previous position was within the data
764  // window. Call a shortcut version of pos.
765  if (m_exists) {
766  pos_xincr ();
767  return;
768  }
769  } else {
770  // Wrap to the next scanline
771  m_x = m_rng_xbegin;
772  if (++m_y >= m_rng_yend) {
773  m_y = m_rng_ybegin;
774  if (++m_z >= m_rng_zend) {
775  m_valid = false; // shortcut -- finished iterating
776  return;
777  }
778  }
779  }
780  pos (m_x, m_y, m_z);
781  }
784  void operator++ (int) {
785  ++(*this);
786  }
787 
789  ROI range () const {
790  return ROI (m_rng_xbegin, m_rng_xend, m_rng_ybegin, m_rng_yend,
791  m_rng_zbegin, m_rng_zend, 0, m_ib->nchannels());
792  }
793 
794  protected:
795  friend class ImageBuf;
796  friend class ImageBufImpl;
797  const ImageBuf *m_ib;
798  bool m_valid, m_exists;
799  bool m_deep;
800  bool m_localpixels;
801  // Image boundaries
802  int m_img_xbegin, m_img_xend, m_img_ybegin, m_img_yend,
803  m_img_zbegin, m_img_zend;
804  // Iteration range
805  int m_rng_xbegin, m_rng_xend, m_rng_ybegin, m_rng_yend,
806  m_rng_zbegin, m_rng_zend;
807  int m_x, m_y, m_z;
808  ImageCache::Tile *m_tile;
809  int m_tilexbegin, m_tileybegin, m_tilezbegin;
810  int m_tilexend;
811  int m_nchannels;
812  size_t m_pixel_bytes;
813  char *m_proxydata;
814  WrapMode m_wrap;
815 
816  // Helper called by ctrs -- set up some locally cached values
817  // that are copied or derived from the ImageBuf.
818  void init_ib (WrapMode wrap) {
819  const ImageSpec &spec (m_ib->spec());
820  m_deep = spec.deep;
821  m_localpixels = m_ib->localpixels() != NULL;
822  m_img_xbegin = spec.x; m_img_xend = spec.x+spec.width;
823  m_img_ybegin = spec.y; m_img_yend = spec.y+spec.height;
824  m_img_zbegin = spec.z; m_img_zend = spec.z+spec.depth;
825  m_nchannels = spec.nchannels;
826 // m_tilewidth = spec.tile_width;
827  m_pixel_bytes = spec.pixel_bytes();
828  m_x = 0xffffffff;
829  m_y = 0xffffffff;
830  m_z = 0xffffffff;
831  m_wrap = (wrap == WrapDefault ? WrapBlack : wrap);
832  }
833 
834  // Helper called by ctrs -- make the iteration range the full
835  // image data window.
836  void range_is_image () {
837  m_rng_xbegin = m_img_xbegin; m_rng_xend = m_img_xend;
838  m_rng_ybegin = m_img_ybegin; m_rng_yend = m_img_yend;
839  m_rng_zbegin = m_img_zbegin; m_rng_zend = m_img_zend;
840  }
841 
842  // Helper called by pos(), but ONLY for the case where we are
843  // moving from an existing pixel to the next spot in +x.
844  // Note: called *after* m_x was incremented!
845  void pos_xincr () {
846  DASSERT (m_exists && m_valid); // precondition
847  DASSERT (valid(m_x,m_y,m_z)); // should be true by definition
848  bool e = (m_x < m_img_xend);
849  if (m_localpixels) {
850  if (e)
851  // Haven't run off the end, just increment
852  m_proxydata += m_pixel_bytes;
853  else {
854  m_exists = false;
855  if (m_wrap == WrapBlack) {
856  m_proxydata = (char *)m_ib->blackpixel();
857  } else {
858  int x = m_x, y = m_y, z = m_z;
859  m_ib->do_wrap (x, y, z, m_wrap);
860  m_proxydata = (char *)m_ib->pixeladdr (x, y, z);
861  }
862  }
863  } else if (m_deep) {
864  m_proxydata = NULL;
865  } else {
866  // Cached image
867  if (e && m_x < m_tilexend)
868  // Haven't crossed a tile boundary, don't retile!
869  m_proxydata += m_pixel_bytes;
870  else {
871  m_proxydata = (char *)m_ib->retile (m_x, m_y, m_z, m_tile,
872  m_tilexbegin, m_tileybegin, m_tilezbegin,
873  m_tilexend, e, m_wrap);
874  m_exists = e;
875  }
876  }
877  }
878  };
879 
898  template<typename BUFT, typename USERT=float>
899  class Iterator : public IteratorBase {
900  public:
903  Iterator (ImageBuf &ib, WrapMode wrap=WrapDefault)
904  : IteratorBase(ib,wrap)
905  {
906  pos (m_rng_xbegin,m_rng_ybegin,m_rng_zbegin);
907  }
910  Iterator (ImageBuf &ib, int x, int y, int z=0,
911  WrapMode wrap=WrapDefault)
912  : IteratorBase(ib,wrap)
913  {
914  pos (x, y, z);
915  }
917  Iterator (ImageBuf &ib, const ROI &roi, WrapMode wrap=WrapDefault)
918  : IteratorBase (ib, roi, wrap)
919  {
920  pos (m_rng_xbegin, m_rng_ybegin, m_rng_zbegin);
921  }
924  Iterator (ImageBuf &ib, int xbegin, int xend,
925  int ybegin, int yend, int zbegin=0, int zend=1,
926  WrapMode wrap=WrapDefault)
927  : IteratorBase(ib, xbegin, xend, ybegin, yend, zbegin, zend, wrap)
928  {
929  pos (m_rng_xbegin, m_rng_ybegin, m_rng_zbegin);
930  }
933  Iterator (Iterator &i)
934  : IteratorBase (i.m_ib, i.m_wrap)
935  {
936  pos (i.m_x, i.m_y, i.m_z);
937  }
938 
939  ~Iterator () { }
940 
943  const Iterator & operator= (const Iterator &i) {
944  assign_base (i);
945  pos (i.m_x, i.m_y, i.m_z);
946  return *this;
947  }
948 
951  DataArrayProxy<BUFT,USERT>& operator* () {
952  return *(DataArrayProxy<BUFT,USERT> *)(void *)&m_proxydata;
953  }
954 
957  USERT operator[] (int i) const {
958  DataArrayProxy<BUFT,USERT> proxy((BUFT*)m_proxydata);
959  return proxy[i];
960  }
961 
965  DataProxy<BUFT,USERT> operator[] (int i) {
966  DataArrayProxy<BUFT,USERT> proxy((BUFT*)m_proxydata);
967  return proxy[i];
968  }
969 
970  void * rawptr () const { return m_proxydata; }
971 
973  USERT deep_value (int c, int s) const {
974  return convert_type<float,USERT>(m_ib->deep_value (m_x, m_y, m_z, c, s));
975  }
976  };
977 
978 
981  template<typename BUFT, typename USERT=float>
982  class ConstIterator : public IteratorBase {
983  public:
986  ConstIterator (const ImageBuf &ib, WrapMode wrap=WrapDefault)
987  : IteratorBase(ib,wrap)
988  {
989  pos (m_rng_xbegin,m_rng_ybegin,m_rng_zbegin);
990  }
993  ConstIterator (const ImageBuf &ib, int x_, int y_, int z_=0,
994  WrapMode wrap=WrapDefault)
995  : IteratorBase(ib,wrap)
996  {
997  pos (x_, y_, z_);
998  }
1000  ConstIterator (const ImageBuf &ib, const ROI &roi,
1001  WrapMode wrap=WrapDefault)
1002  : IteratorBase (ib, roi, wrap)
1003  {
1004  pos (m_rng_xbegin, m_rng_ybegin, m_rng_zbegin);
1005  }
1008  ConstIterator (const ImageBuf &ib, int xbegin, int xend,
1009  int ybegin, int yend, int zbegin=0, int zend=1,
1010  WrapMode wrap=WrapDefault)
1011  : IteratorBase(ib, xbegin, xend, ybegin, yend, zbegin, zend, wrap)
1012  {
1013  pos (m_rng_xbegin, m_rng_ybegin, m_rng_zbegin);
1014  }
1017  ConstIterator (const ConstIterator &i)
1018  : IteratorBase (i)
1019  {
1020  pos (i.m_x, i.m_y, i.m_z);
1021  }
1022 
1023  ~ConstIterator () { }
1024 
1027  const ConstIterator & operator= (const ConstIterator &i) {
1028  assign_base (i);
1029  pos (i.m_x, i.m_y, i.m_z);
1030  return *this;
1031  }
1032 
1035  ConstDataArrayProxy<BUFT,USERT>& operator* () const {
1036  return *(ConstDataArrayProxy<BUFT,USERT> *)&m_proxydata;
1037  }
1038 
1041  USERT operator[] (int i) const {
1042  ConstDataArrayProxy<BUFT,USERT> proxy ((BUFT*)m_proxydata);
1043  return proxy[i];
1044  }
1045 
1046  const void * rawptr () const { return m_proxydata; }
1047 
1049  USERT deep_value (int c, int s) const {
1050  return convert_type<float,USERT>(m_ib->deep_value (m_x, m_y, m_z, c, s));
1051  }
1052  };
1053 
1054 
1055 protected:
1056  ImageBufImpl *m_impl; //< PIMPL idiom
1057 
1058  ImageBufImpl * impl () { return m_impl; }
1059  const ImageBufImpl * impl () const { return m_impl; }
1060 
1061  // Copy src's pixels into *this. Pixels must already be local
1062  // (either owned or wrapped) and the resolution and number of
1063  // channels must match src. Data type is allowed to be different,
1064  // however, with automatic conversion upon copy.
1065  void copy_from (const ImageBuf &src);
1066 
1067  // Reset the ImageCache::Tile * to reserve and point to the correct
1068  // tile for the given pixel, and return the ptr to the actual pixel
1069  // within the tile.
1070  const void * retile (int x, int y, int z,
1071  ImageCache::Tile* &tile, int &tilexbegin,
1072  int &tileybegin, int &tilezbegin,
1073  int &tilexend, bool exists,
1074  WrapMode wrap=WrapDefault) const;
1075 
1076  const void *blackpixel () const;
1077 
1078  void do_wrap (int &x, int &y, int &z, WrapMode wrap) const;
1079 
1081  const ImageBuf& operator= (const ImageBuf &src);
1082 
1084  void append_error (const std::string& message) const;
1085 
1086 };
1087 
1088 
1089 }
1090 OIIO_NAMESPACE_EXIT
1091 
1092 #endif // OPENIMAGEIO_IMAGEBUF_H