1 //
2 // SPDX-License-Identifier: BSD-3-Clause
3 // Copyright (c) Contributors to the OpenEXR Project.
4 //
5 
6 #ifndef INCLUDED_IMAGE_H
7 #define INCLUDED_IMAGE_H
8 
9 //----------------------------------------------------------------------------
10 //
11 //	Classes for storing OpenEXR images in memory.
12 //
13 //----------------------------------------------------------------------------
14 
15 #include <ImfChannelList.h>
16 #include <ImfFrameBuffer.h>
17 #include <ImfArray.h>
18 #include <ImathBox.h>
19 #include <half.h>
20 #include <Iex.h>
21 
22 #include <string>
23 #include <map>
24 
25 #include "namespaceAlias.h"
26 
27 class Image;
28 
29 
30 class ImageChannel
31 {
32   public:
33 
34     friend class Image;
35 
36     ImageChannel (Image &image);
37     virtual ~ImageChannel();
38 
39     virtual IMF::Slice	slice () const = 0;
40 
image()41     Image &		image ()		{return _image;}
image()42     const Image &	image () const		{return _image;}
43     virtual void                         black() =0;
44   private:
45 
46     virtual void	resize () = 0;
47 
48     Image &		_image;
49 };
50 
51 
52 template <class T>
53 class TypedImageChannel: public ImageChannel
54 {
55   public:
56 
57     TypedImageChannel (Image &image, int xSampling, int ySampling);
58 
59     virtual ~TypedImageChannel ();
60 
61     IMF::PixelType	pixelType () const;
62 
63     virtual IMF::Slice	slice () const;
64 
65 
66   private:
67 
68     virtual void	resize ();
69     virtual void black();
70 
71     int			_xSampling;
72     int			_ySampling;
73     IMF::Array2D<T>	_pixels;
74 };
75 
76 
77 typedef TypedImageChannel<half>		HalfChannel;
78 typedef TypedImageChannel<float>	FloatChannel;
79 typedef TypedImageChannel<unsigned int>	UIntChannel;
80 
81 
82 class Image
83 {
84   public:
85 
86     Image ();
87     Image (const IMATH_NAMESPACE::Box2i &dataWindow);
88    ~Image ();
89 
90     Image (const Image& other) = delete;
91     Image & operator = (const Image& other) = delete;
92     Image (Image&& other) = delete;
93     Image & operator = (Image&& other) = delete;
94 
95    const IMATH_NAMESPACE::Box2i &		dataWindow () const;
96    void				resize (const IMATH_NAMESPACE::Box2i &dataWindow);
97 
98    int				width () const;
99    int				height () const;
100 
101    void				addChannel (const std::string &name,
102 					    const IMF::Channel &channel);
103 
104    ImageChannel &		channel (const std::string &name);
105    const ImageChannel &		channel (const std::string &name) const;
106 
107    template <class T>
108    TypedImageChannel<T> &	typedChannel (const std::string &name);
109 
110    template <class T>
111    const TypedImageChannel<T> &	typedChannel (const std::string &name) const;
112 
113 
114 
115   private:
116 
117    typedef std::map <std::string, ImageChannel *> ChannelMap;
118 
119    IMATH_NAMESPACE::Box2i			_dataWindow;
120    ChannelMap			_channels;
121 };
122 
123 
124 //
125 // Implementation of templates and inline functions.
126 //
127 
128 template <class T>
TypedImageChannel(Image & image,int xSampling,int ySampling)129 TypedImageChannel<T>::TypedImageChannel
130     (Image &image,
131      int xSampling,
132      int ySampling)
133 :
134     ImageChannel (image),
135     _xSampling (xSampling),
136     _ySampling (ySampling),
137     _pixels (0, 0)
138 {
139     if ( _xSampling < 1 || _ySampling < 1 )
140         throw IEX_NAMESPACE::ArgExc ("Invalid x/y sampling values");
141     resize();
142 }
143 
144 
145 template <class T>
~TypedImageChannel()146 TypedImageChannel<T>::~TypedImageChannel ()
147 {
148     // empty
149 }
150 
151 
152 template <>
153 inline IMF::PixelType
pixelType()154 HalfChannel::pixelType () const
155 {
156     return IMF::HALF;
157 }
158 
159 
160 template <>
161 inline IMF::PixelType
pixelType()162 FloatChannel::pixelType () const
163 {
164     return IMF::FLOAT;
165 }
166 
167 
168 template <>
169 inline IMF::PixelType
pixelType()170 UIntChannel::pixelType () const
171 {
172     return IMF::UINT;
173 }
174 
175 
176 template <class T>
177 IMF::Slice
slice()178 TypedImageChannel<T>::slice () const
179 {
180     const IMATH_NAMESPACE::Box2i &dw = image().dataWindow();
181     int w = dw.max.x - dw.min.x + 1;
182 
183     return IMF::Slice::Make (
184         pixelType(),
185         &_pixels[0][0],
186         dw,
187         sizeof(T),
188         (w / _xSampling) * sizeof (T),
189         _xSampling,
190         _ySampling);
191 }
192 
193 
194 template <class T>
195 void
resize()196 TypedImageChannel<T>::resize ()
197 {
198     int width  = image().width()  / _xSampling;
199     int height = image().height() / _ySampling;
200 
201     _pixels.resizeEraseUnsafe (height, width);
202 }
203 
204 
205 template <class T>
206 void
black()207 TypedImageChannel<T>::black ()
208 {
209     size_t nx = static_cast<size_t>( image().width() ) / static_cast<size_t>( _xSampling );
210     size_t ny = static_cast<size_t>( image().height() ) / static_cast<size_t>( _ySampling );
211     memset(&_pixels[0][0],0,nx*ny*sizeof(T));
212 }
213 
214 
215 inline const IMATH_NAMESPACE::Box2i &
dataWindow()216 Image::dataWindow () const
217 {
218     return _dataWindow;
219 }
220 
221 
222 inline int
width()223 Image::width () const
224 {
225     return _dataWindow.max.x - _dataWindow.min.x + 1;
226 }
227 
228 
229 inline int
height()230 Image::height () const
231 {
232     return _dataWindow.max.y - _dataWindow.min.y + 1;
233 }
234 
235 
236 template <class T>
237 TypedImageChannel<T> &
typedChannel(const std::string & name)238 Image::typedChannel (const std::string &name)
239 {
240     return dynamic_cast <TypedImageChannel<T>&> (channel (name));
241 }
242 
243 
244 template <class T>
245 const TypedImageChannel<T> &
typedChannel(const std::string & name)246 Image::typedChannel (const std::string &name) const
247 {
248     return dynamic_cast <const TypedImageChannel<T>&> (channel (name));
249 }
250 
251 
252 #endif
253