1 | /////////////////////////////////////////////////////////////////////////// |
2 | // |
3 | // Copyright (c) 2004, Industrial Light & Magic, a division of Lucas |
4 | // Digital Ltd. LLC |
5 | // |
6 | // All rights reserved. |
7 | // |
8 | // Redistribution and use in source and binary forms, with or without |
9 | // modification, are permitted provided that the following conditions are |
10 | // met: |
11 | // * Redistributions of source code must retain the above copyright |
12 | // notice, this list of conditions and the following disclaimer. |
13 | // * Redistributions in binary form must reproduce the above |
14 | // copyright notice, this list of conditions and the following disclaimer |
15 | // in the documentation and/or other materials provided with the |
16 | // distribution. |
17 | // * Neither the name of Industrial Light & Magic nor the names of |
18 | // its contributors may be used to endorse or promote products derived |
19 | // from this software without specific prior written permission. |
20 | // |
21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
22 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
23 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
24 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
25 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
26 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
27 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
28 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
29 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
30 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
31 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
32 | // |
33 | /////////////////////////////////////////////////////////////////////////// |
34 | |
35 | |
36 | |
37 | #ifndef INCLUDED_IMF_RGBA_FILE_H |
38 | #define INCLUDED_IMF_RGBA_FILE_H |
39 | |
40 | |
41 | //----------------------------------------------------------------------------- |
42 | // |
43 | // Simplified RGBA image I/O |
44 | // |
45 | // class RgbaOutputFile |
46 | // class RgbaInputFile |
47 | // |
48 | //----------------------------------------------------------------------------- |
49 | |
50 | #include "ImfHeader.h" |
51 | #include "ImfFrameBuffer.h" |
52 | #include "ImfRgba.h" |
53 | #include "ImathVec.h" |
54 | #include "ImathBox.h" |
55 | #include "half.h" |
56 | #include "ImfThreading.h" |
57 | #include <string> |
58 | #include "ImfNamespace.h" |
59 | #include "ImfForward.h" |
60 | |
61 | OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER |
62 | |
63 | //------------------------------------------------------- |
64 | // Utility to compute the origin-based pointer address |
65 | // |
66 | // With large offsets for the data window, the naive code |
67 | // can wrap around, especially on 32-bit machines. |
68 | // This can be used to avoid that |
69 | //------------------------------------------------------- |
70 | |
71 | inline const Rgba * |
72 | ComputeBasePointer ( |
73 | const Rgba* ptr, |
74 | const IMATH_NAMESPACE::V2i& origin, |
75 | int64_t w, |
76 | size_t xStride = 1, |
77 | size_t yStride = 0) |
78 | { |
79 | if (yStride == 0) |
80 | yStride = w; |
81 | int64_t offx = static_cast<int64_t> (origin.x); |
82 | offx *= xStride; |
83 | int64_t offy = static_cast<int64_t> (origin.y); |
84 | offy *= yStride; |
85 | return ptr - offx - offy; |
86 | } |
87 | |
88 | inline const Rgba * |
89 | ComputeBasePointer (const Rgba* ptr, const IMATH_NAMESPACE::Box2i& dataWindow) |
90 | { |
91 | return ComputeBasePointer (ptr, origin: dataWindow.min, |
92 | w: static_cast<int64_t> (dataWindow.max.x) - |
93 | static_cast<int64_t> (dataWindow.min.x) + 1); |
94 | } |
95 | |
96 | inline Rgba* |
97 | ComputeBasePointer ( |
98 | Rgba* ptr, |
99 | const IMATH_NAMESPACE::V2i& origin, |
100 | int64_t w, |
101 | size_t xStride = 1, |
102 | size_t yStride = 0) |
103 | { |
104 | if (yStride == 0) |
105 | yStride = w; |
106 | int64_t offx = static_cast<int64_t> (origin.x); |
107 | offx *= xStride; |
108 | int64_t offy = static_cast<int64_t> (origin.y); |
109 | offy *= yStride; |
110 | return ptr - offx - offy; |
111 | } |
112 | |
113 | inline Rgba* |
114 | ComputeBasePointer (Rgba* ptr, const IMATH_NAMESPACE::Box2i& dataWindow) |
115 | { |
116 | return ComputeBasePointer ( |
117 | ptr, |
118 | origin: dataWindow.min, |
119 | w: static_cast<int64_t> (dataWindow.max.x) - |
120 | static_cast<int64_t> (dataWindow.min.x) + 1); |
121 | } |
122 | |
123 | // |
124 | // RGBA output file. |
125 | // |
126 | |
127 | class RgbaOutputFile |
128 | { |
129 | public: |
130 | |
131 | //--------------------------------------------------- |
132 | // Constructor -- header is constructed by the caller |
133 | //--------------------------------------------------- |
134 | |
135 | IMF_EXPORT |
136 | (const char name[], |
137 | const Header &, |
138 | RgbaChannels rgbaChannels = WRITE_RGBA, |
139 | int numThreads = globalThreadCount()); |
140 | |
141 | |
142 | //---------------------------------------------------- |
143 | // Constructor -- header is constructed by the caller, |
144 | // file is opened by the caller, destructor will not |
145 | // automatically close the file. |
146 | //---------------------------------------------------- |
147 | |
148 | IMF_EXPORT |
149 | (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, |
150 | const Header &, |
151 | RgbaChannels rgbaChannels = WRITE_RGBA, |
152 | int numThreads = globalThreadCount()); |
153 | |
154 | |
155 | //---------------------------------------------------------------- |
156 | // Constructor -- header data are explicitly specified as function |
157 | // call arguments (empty dataWindow means "same as displayWindow") |
158 | //---------------------------------------------------------------- |
159 | |
160 | IMF_EXPORT |
161 | RgbaOutputFile (const char name[], |
162 | const IMATH_NAMESPACE::Box2i &displayWindow, |
163 | const IMATH_NAMESPACE::Box2i &dataWindow = IMATH_NAMESPACE::Box2i(), |
164 | RgbaChannels rgbaChannels = WRITE_RGBA, |
165 | float pixelAspectRatio = 1, |
166 | const IMATH_NAMESPACE::V2f screenWindowCenter = IMATH_NAMESPACE::V2f (0, 0), |
167 | float screenWindowWidth = 1, |
168 | LineOrder lineOrder = INCREASING_Y, |
169 | Compression compression = PIZ_COMPRESSION, |
170 | int numThreads = globalThreadCount()); |
171 | |
172 | |
173 | //----------------------------------------------- |
174 | // Constructor -- like the previous one, but both |
175 | // the display window and the data window are |
176 | // Box2i (V2i (0, 0), V2i (width - 1, height -1)) |
177 | //----------------------------------------------- |
178 | |
179 | IMF_EXPORT |
180 | RgbaOutputFile (const char name[], |
181 | int width, |
182 | int height, |
183 | RgbaChannels rgbaChannels = WRITE_RGBA, |
184 | float pixelAspectRatio = 1, |
185 | const IMATH_NAMESPACE::V2f screenWindowCenter = IMATH_NAMESPACE::V2f (0, 0), |
186 | float screenWindowWidth = 1, |
187 | LineOrder lineOrder = INCREASING_Y, |
188 | Compression compression = PIZ_COMPRESSION, |
189 | int numThreads = globalThreadCount()); |
190 | |
191 | |
192 | //----------- |
193 | // Destructor |
194 | //----------- |
195 | |
196 | IMF_EXPORT |
197 | virtual ~RgbaOutputFile (); |
198 | |
199 | |
200 | //------------------------------------------------ |
201 | // Define a frame buffer as the pixel data source: |
202 | // Pixel (x, y) is at address |
203 | // |
204 | // base + x * xStride + y * yStride |
205 | // |
206 | //------------------------------------------------ |
207 | |
208 | IMF_EXPORT |
209 | void setFrameBuffer (const Rgba *base, |
210 | size_t xStride, |
211 | size_t yStride); |
212 | |
213 | |
214 | //--------------------------------------------- |
215 | // Write pixel data (see class Imf::OutputFile) |
216 | //--------------------------------------------- |
217 | |
218 | IMF_EXPORT |
219 | void writePixels (int numScanLines = 1); |
220 | IMF_EXPORT |
221 | int currentScanLine () const; |
222 | |
223 | |
224 | //-------------------------- |
225 | // Access to the file header |
226 | //-------------------------- |
227 | |
228 | IMF_EXPORT |
229 | const Header & () const; |
230 | IMF_EXPORT |
231 | const FrameBuffer & frameBuffer () const; |
232 | IMF_EXPORT |
233 | const IMATH_NAMESPACE::Box2i & displayWindow () const; |
234 | IMF_EXPORT |
235 | const IMATH_NAMESPACE::Box2i & dataWindow () const; |
236 | IMF_EXPORT |
237 | float pixelAspectRatio () const; |
238 | IMF_EXPORT |
239 | const IMATH_NAMESPACE::V2f screenWindowCenter () const; |
240 | IMF_EXPORT |
241 | float screenWindowWidth () const; |
242 | IMF_EXPORT |
243 | LineOrder lineOrder () const; |
244 | IMF_EXPORT |
245 | Compression compression () const; |
246 | IMF_EXPORT |
247 | RgbaChannels channels () const; |
248 | |
249 | |
250 | // -------------------------------------------------------------------- |
251 | // Update the preview image (see Imf::OutputFile::updatePreviewImage()) |
252 | // -------------------------------------------------------------------- |
253 | |
254 | IMF_EXPORT |
255 | void updatePreviewImage (const PreviewRgba[]); |
256 | |
257 | |
258 | //----------------------------------------------------------------------- |
259 | // Rounding control for luminance/chroma images: |
260 | // |
261 | // If the output file contains luminance and chroma channels (WRITE_YC |
262 | // or WRITE_YCA), then the the significands of the luminance and |
263 | // chroma values are rounded to roundY and roundC bits respectively (see |
264 | // function half::round()). Rounding improves compression with minimal |
265 | // image degradation, usually much less than the degradation caused by |
266 | // chroma subsampling. By default, roundY is 7, and roundC is 5. |
267 | // |
268 | // If the output file contains RGB channels or a luminance channel, |
269 | // without chroma, then no rounding is performed. |
270 | //----------------------------------------------------------------------- |
271 | |
272 | IMF_EXPORT |
273 | void setYCRounding (unsigned int roundY, |
274 | unsigned int roundC); |
275 | |
276 | |
277 | //---------------------------------------------------- |
278 | // Break a scan line -- for testing and debugging only |
279 | // (see Imf::OutputFile::updatePreviewImage() |
280 | // |
281 | // Warning: Calling this function usually results in a |
282 | // broken image file. The file or parts of it may not |
283 | // be readable, or the file may contain bad data. |
284 | // |
285 | //---------------------------------------------------- |
286 | |
287 | IMF_EXPORT |
288 | void breakScanLine (int y, |
289 | int offset, |
290 | int length, |
291 | char c); |
292 | private: |
293 | |
294 | RgbaOutputFile (const RgbaOutputFile &) = delete; |
295 | RgbaOutputFile & operator = (const RgbaOutputFile &) = delete; |
296 | RgbaOutputFile (RgbaOutputFile &&) = delete; |
297 | RgbaOutputFile & operator = (RgbaOutputFile &&) = delete; |
298 | |
299 | class ToYca; |
300 | |
301 | OutputFile * _outputFile; |
302 | ToYca * _toYca; |
303 | }; |
304 | |
305 | |
306 | // |
307 | // RGBA input file |
308 | // |
309 | |
310 | class RgbaInputFile |
311 | { |
312 | public: |
313 | |
314 | //------------------------------------------------------- |
315 | // Constructor -- opens the file with the specified name, |
316 | // destructor will automatically close the file. |
317 | //------------------------------------------------------- |
318 | |
319 | IMF_EXPORT |
320 | RgbaInputFile (const char name[], int numThreads = globalThreadCount()); |
321 | |
322 | |
323 | //----------------------------------------------------------- |
324 | // Constructor -- attaches the new RgbaInputFile object to a |
325 | // file that has already been opened by the caller. |
326 | // Destroying the RgbaInputFile object will not automatically |
327 | // close the file. |
328 | //----------------------------------------------------------- |
329 | |
330 | IMF_EXPORT |
331 | RgbaInputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int numThreads = globalThreadCount()); |
332 | |
333 | |
334 | //-------------------------------------------------------------- |
335 | // Constructors -- the same as the previous two, but the names |
336 | // of the red, green, blue, alpha, luminance and chroma channels |
337 | // are expected to be layerName.R, layerName.G, etc. |
338 | //-------------------------------------------------------------- |
339 | |
340 | IMF_EXPORT |
341 | RgbaInputFile (const char name[], |
342 | const std::string &layerName, |
343 | int numThreads = globalThreadCount()); |
344 | |
345 | IMF_EXPORT |
346 | RgbaInputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, |
347 | const std::string &layerName, |
348 | int numThreads = globalThreadCount()); |
349 | |
350 | |
351 | //----------- |
352 | // Destructor |
353 | //----------- |
354 | |
355 | IMF_EXPORT |
356 | virtual ~RgbaInputFile (); |
357 | |
358 | |
359 | //----------------------------------------------------- |
360 | // Define a frame buffer as the pixel data destination: |
361 | // Pixel (x, y) is at address |
362 | // |
363 | // base + x * xStride + y * yStride |
364 | // |
365 | //----------------------------------------------------- |
366 | |
367 | IMF_EXPORT |
368 | void setFrameBuffer (Rgba *base, |
369 | size_t xStride, |
370 | size_t yStride); |
371 | |
372 | |
373 | //---------------------------------------------------------------- |
374 | // Switch to a different layer -- subsequent calls to readPixels() |
375 | // will read channels layerName.R, layerName.G, etc. |
376 | // After each call to setLayerName(), setFrameBuffer() must be |
377 | // called at least once before the next call to readPixels(). |
378 | //---------------------------------------------------------------- |
379 | |
380 | IMF_EXPORT |
381 | void setLayerName (const std::string &layerName); |
382 | |
383 | |
384 | //------------------------------------------- |
385 | // Read pixel data (see class Imf::InputFile) |
386 | //------------------------------------------- |
387 | |
388 | IMF_EXPORT |
389 | void readPixels (int scanLine1, int scanLine2); |
390 | IMF_EXPORT |
391 | void readPixels (int scanLine); |
392 | |
393 | |
394 | //-------------------------- |
395 | // Access to the file header |
396 | //-------------------------- |
397 | |
398 | IMF_EXPORT |
399 | const Header & () const; |
400 | IMF_EXPORT |
401 | const FrameBuffer & frameBuffer () const; |
402 | IMF_EXPORT |
403 | const IMATH_NAMESPACE::Box2i & displayWindow () const; |
404 | IMF_EXPORT |
405 | const IMATH_NAMESPACE::Box2i & dataWindow () const; |
406 | IMF_EXPORT |
407 | float pixelAspectRatio () const; |
408 | IMF_EXPORT |
409 | const IMATH_NAMESPACE::V2f screenWindowCenter () const; |
410 | IMF_EXPORT |
411 | float screenWindowWidth () const; |
412 | IMF_EXPORT |
413 | LineOrder lineOrder () const; |
414 | IMF_EXPORT |
415 | Compression compression () const; |
416 | IMF_EXPORT |
417 | RgbaChannels channels () const; |
418 | IMF_EXPORT |
419 | const char * fileName () const; |
420 | IMF_EXPORT |
421 | bool isComplete () const; |
422 | |
423 | |
424 | //---------------------------------- |
425 | // Access to the file format version |
426 | //---------------------------------- |
427 | |
428 | IMF_EXPORT |
429 | int version () const; |
430 | |
431 | private: |
432 | |
433 | RgbaInputFile (const RgbaInputFile &) = delete; |
434 | RgbaInputFile & operator = (const RgbaInputFile &) = delete; |
435 | RgbaInputFile (RgbaInputFile &&) = delete; |
436 | RgbaInputFile & operator = (RgbaInputFile &&) = delete; |
437 | |
438 | class FromYca; |
439 | |
440 | InputFile * _inputFile; |
441 | FromYca * _fromYca; |
442 | std::string _channelNamePrefix; |
443 | }; |
444 | |
445 | |
446 | OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT |
447 | |
448 | |
449 | |
450 | |
451 | |
452 | #endif |
453 | |