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