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 //-----------------------------------------------------------------------------
38 //
39 // Miscellaneous helper functions for OpenEXR image file I/O
40 //
41 //-----------------------------------------------------------------------------
42
43 #include <ImfMisc.h>
44 #include <ImfHeader.h>
45 #include <ImfCompressor.h>
46 #include <ImfChannelList.h>
47 #include <ImfXdr.h>
48 #include <ImathFun.h>
49 #include <Iex.h>
50 #include <ImfStdIO.h>
51 #include <ImfConvert.h>
52
53 namespace Imf {
54
55 using Imath::Box2i;
56 using Imath::divp;
57 using Imath::modp;
58 using std::vector;
59
60 int
pixelTypeSize(PixelType type)61 pixelTypeSize (PixelType type)
62 {
63 int size;
64
65 switch (type)
66 {
67 case UINT:
68
69 size = Xdr::size <unsigned int> ();
70 break;
71
72 case HALF:
73
74 size = Xdr::size <half> ();
75 break;
76
77 case FLOAT:
78
79 size = Xdr::size <float> ();
80 break;
81
82 default:
83
84 throw Iex::ArgExc ("Unknown pixel type.");
85 }
86
87 return size;
88 }
89
90
91 int
numSamples(int s,int a,int b)92 numSamples (int s, int a, int b)
93 {
94 int a1 = divp (a, s);
95 int b1 = divp (b, s);
96 return b1 - a1 + ((a1 * s < a)? 0: 1);
97 }
98
99
100 size_t
bytesPerLineTable(const Header & header,vector<size_t> & bytesPerLine)101 bytesPerLineTable (const Header &header,
102 vector<size_t> &bytesPerLine)
103 {
104 const Box2i &dataWindow = header.dataWindow();
105 const ChannelList &channels = header.channels();
106
107 bytesPerLine.resize (dataWindow.max.y - dataWindow.min.y + 1);
108
109 for (ChannelList::ConstIterator c = channels.begin();
110 c != channels.end();
111 ++c)
112 {
113 int nBytes = pixelTypeSize (c.channel().type) *
114 (dataWindow.max.x - dataWindow.min.x + 1) /
115 c.channel().xSampling;
116
117 for (int y = dataWindow.min.y, i = 0; y <= dataWindow.max.y; ++y, ++i)
118 if (modp (y, c.channel().ySampling) == 0)
119 bytesPerLine[i] += nBytes;
120 }
121
122 size_t maxBytesPerLine = 0;
123
124 for (int y = dataWindow.min.y, i = 0; y <= dataWindow.max.y; ++y, ++i)
125 if (maxBytesPerLine < bytesPerLine[i])
126 maxBytesPerLine = bytesPerLine[i];
127
128 return maxBytesPerLine;
129 }
130
131
132 void
offsetInLineBufferTable(const vector<size_t> & bytesPerLine,int linesInLineBuffer,vector<size_t> & offsetInLineBuffer)133 offsetInLineBufferTable (const vector<size_t> &bytesPerLine,
134 int linesInLineBuffer,
135 vector<size_t> &offsetInLineBuffer)
136 {
137 offsetInLineBuffer.resize (bytesPerLine.size());
138
139 size_t offset = 0;
140
141 for (int i = 0; i < bytesPerLine.size(); ++i)
142 {
143 if (i % linesInLineBuffer == 0)
144 offset = 0;
145
146 offsetInLineBuffer[i] = offset;
147 offset += bytesPerLine[i];
148 }
149 }
150
151
152 int
lineBufferMinY(int y,int minY,int linesInLineBuffer)153 lineBufferMinY (int y, int minY, int linesInLineBuffer)
154 {
155 return ((y - minY) / linesInLineBuffer) * linesInLineBuffer + minY;
156 }
157
158
159 int
lineBufferMaxY(int y,int minY,int linesInLineBuffer)160 lineBufferMaxY (int y, int minY, int linesInLineBuffer)
161 {
162 return lineBufferMinY (y, minY, linesInLineBuffer) + linesInLineBuffer - 1;
163 }
164
165
166 Compressor::Format
defaultFormat(Compressor * compressor)167 defaultFormat (Compressor * compressor)
168 {
169 return compressor? compressor->format(): Compressor::XDR;
170 }
171
172
173 int
numLinesInBuffer(Compressor * compressor)174 numLinesInBuffer (Compressor * compressor)
175 {
176 return compressor? compressor->numScanLines(): 1;
177 }
178
179
180 void
copyIntoFrameBuffer(const char * & readPtr,char * writePtr,char * endPtr,size_t xStride,bool fill,double fillValue,Compressor::Format format,PixelType typeInFrameBuffer,PixelType typeInFile)181 copyIntoFrameBuffer (const char *& readPtr,
182 char * writePtr,
183 char * endPtr,
184 size_t xStride,
185 bool fill,
186 double fillValue,
187 Compressor::Format format,
188 PixelType typeInFrameBuffer,
189 PixelType typeInFile)
190 {
191 //
192 // Copy a horizontal row of pixels from an input
193 // file's line or tile buffer to a frame buffer.
194 //
195
196 if (fill)
197 {
198 //
199 // The file contains no data for this channel.
200 // Store a default value in the frame buffer.
201 //
202
203 switch (typeInFrameBuffer)
204 {
205 case UINT:
206
207 {
208 unsigned int fillVal = (unsigned int) (fillValue);
209
210 while (writePtr <= endPtr)
211 {
212 *(unsigned int *) writePtr = fillVal;
213 writePtr += xStride;
214 }
215 }
216 break;
217
218 case HALF:
219
220 {
221 half fillVal = half (fillValue);
222
223 while (writePtr <= endPtr)
224 {
225 *(half *) writePtr = fillVal;
226 writePtr += xStride;
227 }
228 }
229 break;
230
231 case FLOAT:
232
233 {
234 float fillVal = float (fillValue);
235
236 while (writePtr <= endPtr)
237 {
238 *(float *) writePtr = fillVal;
239 writePtr += xStride;
240 }
241 }
242 break;
243
244 default:
245
246 throw Iex::ArgExc ("Unknown pixel data type.");
247 }
248 }
249 else if (format == Compressor::XDR)
250 {
251 //
252 // The the line or tile buffer is in XDR format.
253 //
254 // Convert the pixels from the file's machine-
255 // independent representation, and store the
256 // results in the frame buffer.
257 //
258
259 switch (typeInFrameBuffer)
260 {
261 case UINT:
262
263 switch (typeInFile)
264 {
265 case UINT:
266
267 while (writePtr <= endPtr)
268 {
269 Xdr::read <CharPtrIO> (readPtr, *(unsigned int *) writePtr);
270 writePtr += xStride;
271 }
272 break;
273
274 case HALF:
275
276 while (writePtr <= endPtr)
277 {
278 half h;
279 Xdr::read <CharPtrIO> (readPtr, h);
280 *(unsigned int *) writePtr = halfToUint (h);
281 writePtr += xStride;
282 }
283 break;
284
285 case FLOAT:
286
287 while (writePtr <= endPtr)
288 {
289 float f;
290 Xdr::read <CharPtrIO> (readPtr, f);
291 *(unsigned int *)writePtr = floatToUint (f);
292 writePtr += xStride;
293 }
294 break;
295 }
296 break;
297
298 case HALF:
299
300 switch (typeInFile)
301 {
302 case UINT:
303
304 while (writePtr <= endPtr)
305 {
306 unsigned int ui;
307 Xdr::read <CharPtrIO> (readPtr, ui);
308 *(half *) writePtr = uintToHalf (ui);
309 writePtr += xStride;
310 }
311 break;
312
313 case HALF:
314
315 while (writePtr <= endPtr)
316 {
317 Xdr::read <CharPtrIO> (readPtr, *(half *) writePtr);
318 writePtr += xStride;
319 }
320 break;
321
322 case FLOAT:
323
324 while (writePtr <= endPtr)
325 {
326 float f;
327 Xdr::read <CharPtrIO> (readPtr, f);
328 *(half *) writePtr = floatToHalf (f);
329 writePtr += xStride;
330 }
331 break;
332 }
333 break;
334
335 case FLOAT:
336
337 switch (typeInFile)
338 {
339 case UINT:
340
341 while (writePtr <= endPtr)
342 {
343 unsigned int ui;
344 Xdr::read <CharPtrIO> (readPtr, ui);
345 *(float *) writePtr = float (ui);
346 writePtr += xStride;
347 }
348 break;
349
350 case HALF:
351
352 while (writePtr <= endPtr)
353 {
354 half h;
355 Xdr::read <CharPtrIO> (readPtr, h);
356 *(float *) writePtr = float (h);
357 writePtr += xStride;
358 }
359 break;
360
361 case FLOAT:
362
363 while (writePtr <= endPtr)
364 {
365 Xdr::read <CharPtrIO> (readPtr, *(float *) writePtr);
366 writePtr += xStride;
367 }
368 break;
369 }
370 break;
371
372 default:
373
374 throw Iex::ArgExc ("Unknown pixel data type.");
375 }
376 }
377 else
378 {
379 //
380 // The the line or tile buffer is in NATIVE format.
381 // Copy the results into the frame buffer.
382 //
383
384 switch (typeInFrameBuffer)
385 {
386 case UINT:
387
388 switch (typeInFile)
389 {
390 case UINT:
391
392 while (writePtr <= endPtr)
393 {
394 for (size_t i = 0; i < sizeof (unsigned int); ++i)
395 writePtr[i] = readPtr[i];
396
397 readPtr += sizeof (unsigned int);
398 writePtr += xStride;
399 }
400 break;
401
402 case HALF:
403
404 while (writePtr <= endPtr)
405 {
406 half h = *(half *) readPtr;
407 *(unsigned int *) writePtr = halfToUint (h);
408 readPtr += sizeof (half);
409 writePtr += xStride;
410 }
411 break;
412
413 case FLOAT:
414
415 while (writePtr <= endPtr)
416 {
417 float f;
418
419 for (size_t i = 0; i < sizeof (float); ++i)
420 ((char *)&f)[i] = readPtr[i];
421
422 *(unsigned int *)writePtr = floatToUint (f);
423 readPtr += sizeof (float);
424 writePtr += xStride;
425 }
426 break;
427 }
428 break;
429
430 case HALF:
431
432 switch (typeInFile)
433 {
434 case UINT:
435
436 while (writePtr <= endPtr)
437 {
438 unsigned int ui;
439
440 for (size_t i = 0; i < sizeof (unsigned int); ++i)
441 ((char *)&ui)[i] = readPtr[i];
442
443 *(half *) writePtr = uintToHalf (ui);
444 readPtr += sizeof (unsigned int);
445 writePtr += xStride;
446 }
447 break;
448
449 case HALF:
450
451 while (writePtr <= endPtr)
452 {
453 *(half *) writePtr = *(half *)readPtr;
454 readPtr += sizeof (half);
455 writePtr += xStride;
456 }
457 break;
458
459 case FLOAT:
460
461 while (writePtr <= endPtr)
462 {
463 float f;
464
465 for (size_t i = 0; i < sizeof (float); ++i)
466 ((char *)&f)[i] = readPtr[i];
467
468 *(half *) writePtr = floatToHalf (f);
469 readPtr += sizeof (float);
470 writePtr += xStride;
471 }
472 break;
473 }
474 break;
475
476 case FLOAT:
477
478 switch (typeInFile)
479 {
480 case UINT:
481
482 while (writePtr <= endPtr)
483 {
484 unsigned int ui;
485
486 for (size_t i = 0; i < sizeof (unsigned int); ++i)
487 ((char *)&ui)[i] = readPtr[i];
488
489 *(float *) writePtr = float (ui);
490 readPtr += sizeof (unsigned int);
491 writePtr += xStride;
492 }
493 break;
494
495 case HALF:
496
497 while (writePtr <= endPtr)
498 {
499 half h = *(half *) readPtr;
500 *(float *) writePtr = float (h);
501 readPtr += sizeof (half);
502 writePtr += xStride;
503 }
504 break;
505
506 case FLOAT:
507
508 while (writePtr <= endPtr)
509 {
510 for (size_t i = 0; i < sizeof (float); ++i)
511 writePtr[i] = readPtr[i];
512
513 readPtr += sizeof (float);
514 writePtr += xStride;
515 }
516 break;
517 }
518 break;
519
520 default:
521
522 throw Iex::ArgExc ("Unknown pixel data type.");
523 }
524 }
525 }
526
527
528 void
skipChannel(const char * & readPtr,PixelType typeInFile,size_t xSize)529 skipChannel (const char *& readPtr,
530 PixelType typeInFile,
531 size_t xSize)
532 {
533 switch (typeInFile)
534 {
535 case UINT:
536
537 Xdr::skip <CharPtrIO> (readPtr, Xdr::size <unsigned int> () * xSize);
538 break;
539
540 case HALF:
541
542 Xdr::skip <CharPtrIO> (readPtr, Xdr::size <half> () * xSize);
543 break;
544
545 case FLOAT:
546
547 Xdr::skip <CharPtrIO> (readPtr, Xdr::size <float> () * xSize);
548 break;
549
550 default:
551
552 throw Iex::ArgExc ("Unknown pixel data type.");
553 }
554 }
555
556
557 void
convertInPlace(char * & writePtr,const char * & readPtr,PixelType type,size_t numPixels)558 convertInPlace (char *& writePtr,
559 const char *& readPtr,
560 PixelType type,
561 size_t numPixels)
562 {
563 switch (type)
564 {
565 case UINT:
566
567 for (int j = 0; j < numPixels; ++j)
568 {
569 Xdr::write <CharPtrIO> (writePtr, *(const unsigned int *) readPtr);
570 readPtr += sizeof(unsigned int);
571 }
572 break;
573
574 case HALF:
575
576 for (int j = 0; j < numPixels; ++j)
577 {
578 Xdr::write <CharPtrIO> (writePtr, *(const half *) readPtr);
579 readPtr += sizeof(half);
580 }
581 break;
582
583 case FLOAT:
584
585 for (int j = 0; j < numPixels; ++j)
586 {
587 Xdr::write <CharPtrIO> (writePtr, *(const float *) readPtr);
588 readPtr += sizeof(float);
589 }
590 break;
591
592 default:
593
594 throw Iex::ArgExc ("Unknown pixel data type.");
595 }
596 }
597
598
599 void
copyFromFrameBuffer(char * & writePtr,const char * & readPtr,const char * endPtr,size_t xStride,Compressor::Format format,PixelType type)600 copyFromFrameBuffer (char *& writePtr,
601 const char *& readPtr,
602 const char * endPtr,
603 size_t xStride,
604 Compressor::Format format,
605 PixelType type)
606 {
607 //
608 // Copy a horizontal row of pixels from a frame
609 // buffer to an output file's line or tile buffer.
610 //
611
612 if (format == Compressor::XDR)
613 {
614 //
615 // The the line or tile buffer is in XDR format.
616 //
617
618 switch (type)
619 {
620 case UINT:
621
622 while (readPtr <= endPtr)
623 {
624 Xdr::write <CharPtrIO> (writePtr,
625 *(const unsigned int *) readPtr);
626 readPtr += xStride;
627 }
628 break;
629
630 case HALF:
631
632 while (readPtr <= endPtr)
633 {
634 Xdr::write <CharPtrIO> (writePtr, *(const half *) readPtr);
635 readPtr += xStride;
636 }
637 break;
638
639 case FLOAT:
640
641 while (readPtr <= endPtr)
642 {
643 Xdr::write <CharPtrIO> (writePtr, *(const float *) readPtr);
644 readPtr += xStride;
645 }
646 break;
647
648 default:
649
650 throw Iex::ArgExc ("Unknown pixel data type.");
651 }
652 }
653 else
654 {
655 //
656 // The the line or tile buffer is in NATIVE format.
657 //
658
659 switch (type)
660 {
661 case UINT:
662
663 while (readPtr <= endPtr)
664 {
665 for (size_t i = 0; i < sizeof (unsigned int); ++i)
666 *writePtr++ = readPtr[i];
667
668 readPtr += xStride;
669 }
670 break;
671
672 case HALF:
673
674 while (readPtr <= endPtr)
675 {
676 *(half *) writePtr = *(const half *) readPtr;
677 writePtr += sizeof (half);
678 readPtr += xStride;
679 }
680 break;
681
682 case FLOAT:
683
684 while (readPtr <= endPtr)
685 {
686 for (size_t i = 0; i < sizeof (float); ++i)
687 *writePtr++ = readPtr[i];
688
689 readPtr += xStride;
690 }
691 break;
692
693 default:
694
695 throw Iex::ArgExc ("Unknown pixel data type.");
696 }
697 }
698 }
699
700
701 void
fillChannelWithZeroes(char * & writePtr,Compressor::Format format,PixelType type,size_t xSize)702 fillChannelWithZeroes (char *& writePtr,
703 Compressor::Format format,
704 PixelType type,
705 size_t xSize)
706 {
707 if (format == Compressor::XDR)
708 {
709 //
710 // Fill with data in XDR format.
711 //
712
713 switch (type)
714 {
715 case UINT:
716
717 for (int j = 0; j < xSize; ++j)
718 Xdr::write <CharPtrIO> (writePtr, (unsigned int) 0);
719
720 break;
721
722 case HALF:
723
724 for (int j = 0; j < xSize; ++j)
725 Xdr::write <CharPtrIO> (writePtr, (half) 0);
726
727 break;
728
729 case FLOAT:
730
731 for (int j = 0; j < xSize; ++j)
732 Xdr::write <CharPtrIO> (writePtr, (float) 0);
733
734 break;
735
736 default:
737
738 throw Iex::ArgExc ("Unknown pixel data type.");
739 }
740 }
741 else
742 {
743 //
744 // Fill with data in NATIVE format.
745 //
746
747 switch (type)
748 {
749 case UINT:
750
751 for (int j = 0; j < xSize; ++j)
752 {
753 static const unsigned int ui = 0;
754
755 for (size_t i = 0; i < sizeof (ui); ++i)
756 *writePtr++ = ((char *) &ui)[i];
757 }
758 break;
759
760 case HALF:
761
762 for (int j = 0; j < xSize; ++j)
763 {
764 *(half *) writePtr = half (0);
765 writePtr += sizeof (half);
766 }
767 break;
768
769 case FLOAT:
770
771 for (int j = 0; j < xSize; ++j)
772 {
773 static const float f = 0;
774
775 for (size_t i = 0; i < sizeof (f); ++i)
776 *writePtr++ = ((char *) &f)[i];
777 }
778 break;
779
780 default:
781
782 throw Iex::ArgExc ("Unknown pixel data type.");
783 }
784 }
785 }
786
787 } // namespace Imf
788