/////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2004, Industrial Light & Magic, a division of Lucas // Digital Ltd. LLC // // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Industrial Light & Magic nor the names of // its contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // /////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------------- // // Miscellaneous helper functions for OpenEXR image file I/O // //----------------------------------------------------------------------------- #include #include #include #include #include #include #include #include #include namespace Imf { using Imath::Box2i; using Imath::divp; using Imath::modp; using std::vector; int pixelTypeSize (PixelType type) { int size; switch (type) { case UINT: size = Xdr::size (); break; case HALF: size = Xdr::size (); break; case FLOAT: size = Xdr::size (); break; default: throw Iex::ArgExc ("Unknown pixel type."); } return size; } int numSamples (int s, int a, int b) { int a1 = divp (a, s); int b1 = divp (b, s); return b1 - a1 + ((a1 * s < a)? 0: 1); } size_t bytesPerLineTable (const Header &header, vector &bytesPerLine) { const Box2i &dataWindow = header.dataWindow(); const ChannelList &channels = header.channels(); bytesPerLine.resize (dataWindow.max.y - dataWindow.min.y + 1); for (ChannelList::ConstIterator c = channels.begin(); c != channels.end(); ++c) { int nBytes = pixelTypeSize (c.channel().type) * (dataWindow.max.x - dataWindow.min.x + 1) / c.channel().xSampling; for (int y = dataWindow.min.y, i = 0; y <= dataWindow.max.y; ++y, ++i) if (modp (y, c.channel().ySampling) == 0) bytesPerLine[i] += nBytes; } size_t maxBytesPerLine = 0; for (int y = dataWindow.min.y, i = 0; y <= dataWindow.max.y; ++y, ++i) if (maxBytesPerLine < bytesPerLine[i]) maxBytesPerLine = bytesPerLine[i]; return maxBytesPerLine; } void offsetInLineBufferTable (const vector &bytesPerLine, int linesInLineBuffer, vector &offsetInLineBuffer) { offsetInLineBuffer.resize (bytesPerLine.size()); size_t offset = 0; for (int i = 0; i < bytesPerLine.size(); ++i) { if (i % linesInLineBuffer == 0) offset = 0; offsetInLineBuffer[i] = offset; offset += bytesPerLine[i]; } } int lineBufferMinY (int y, int minY, int linesInLineBuffer) { return ((y - minY) / linesInLineBuffer) * linesInLineBuffer + minY; } int lineBufferMaxY (int y, int minY, int linesInLineBuffer) { return lineBufferMinY (y, minY, linesInLineBuffer) + linesInLineBuffer - 1; } Compressor::Format defaultFormat (Compressor * compressor) { return compressor? compressor->format(): Compressor::XDR; } int numLinesInBuffer (Compressor * compressor) { return compressor? compressor->numScanLines(): 1; } void copyIntoFrameBuffer (const char *& readPtr, char * writePtr, char * endPtr, size_t xStride, bool fill, double fillValue, Compressor::Format format, PixelType typeInFrameBuffer, PixelType typeInFile) { // // Copy a horizontal row of pixels from an input // file's line or tile buffer to a frame buffer. // if (fill) { // // The file contains no data for this channel. // Store a default value in the frame buffer. // switch (typeInFrameBuffer) { case UINT: { unsigned int fillVal = (unsigned int) (fillValue); while (writePtr <= endPtr) { *(unsigned int *) writePtr = fillVal; writePtr += xStride; } } break; case HALF: { half fillVal = half (fillValue); while (writePtr <= endPtr) { *(half *) writePtr = fillVal; writePtr += xStride; } } break; case FLOAT: { float fillVal = float (fillValue); while (writePtr <= endPtr) { *(float *) writePtr = fillVal; writePtr += xStride; } } break; default: throw Iex::ArgExc ("Unknown pixel data type."); } } else if (format == Compressor::XDR) { // // The the line or tile buffer is in XDR format. // // Convert the pixels from the file's machine- // independent representation, and store the // results in the frame buffer. // switch (typeInFrameBuffer) { case UINT: switch (typeInFile) { case UINT: while (writePtr <= endPtr) { Xdr::read (readPtr, *(unsigned int *) writePtr); writePtr += xStride; } break; case HALF: while (writePtr <= endPtr) { half h; Xdr::read (readPtr, h); *(unsigned int *) writePtr = halfToUint (h); writePtr += xStride; } break; case FLOAT: while (writePtr <= endPtr) { float f; Xdr::read (readPtr, f); *(unsigned int *)writePtr = floatToUint (f); writePtr += xStride; } break; } break; case HALF: switch (typeInFile) { case UINT: while (writePtr <= endPtr) { unsigned int ui; Xdr::read (readPtr, ui); *(half *) writePtr = uintToHalf (ui); writePtr += xStride; } break; case HALF: while (writePtr <= endPtr) { Xdr::read (readPtr, *(half *) writePtr); writePtr += xStride; } break; case FLOAT: while (writePtr <= endPtr) { float f; Xdr::read (readPtr, f); *(half *) writePtr = floatToHalf (f); writePtr += xStride; } break; } break; case FLOAT: switch (typeInFile) { case UINT: while (writePtr <= endPtr) { unsigned int ui; Xdr::read (readPtr, ui); *(float *) writePtr = float (ui); writePtr += xStride; } break; case HALF: while (writePtr <= endPtr) { half h; Xdr::read (readPtr, h); *(float *) writePtr = float (h); writePtr += xStride; } break; case FLOAT: while (writePtr <= endPtr) { Xdr::read (readPtr, *(float *) writePtr); writePtr += xStride; } break; } break; default: throw Iex::ArgExc ("Unknown pixel data type."); } } else { // // The the line or tile buffer is in NATIVE format. // Copy the results into the frame buffer. // switch (typeInFrameBuffer) { case UINT: switch (typeInFile) { case UINT: while (writePtr <= endPtr) { for (size_t i = 0; i < sizeof (unsigned int); ++i) writePtr[i] = readPtr[i]; readPtr += sizeof (unsigned int); writePtr += xStride; } break; case HALF: while (writePtr <= endPtr) { half h = *(half *) readPtr; *(unsigned int *) writePtr = halfToUint (h); readPtr += sizeof (half); writePtr += xStride; } break; case FLOAT: while (writePtr <= endPtr) { float f; for (size_t i = 0; i < sizeof (float); ++i) ((char *)&f)[i] = readPtr[i]; *(unsigned int *)writePtr = floatToUint (f); readPtr += sizeof (float); writePtr += xStride; } break; } break; case HALF: switch (typeInFile) { case UINT: while (writePtr <= endPtr) { unsigned int ui; for (size_t i = 0; i < sizeof (unsigned int); ++i) ((char *)&ui)[i] = readPtr[i]; *(half *) writePtr = uintToHalf (ui); readPtr += sizeof (unsigned int); writePtr += xStride; } break; case HALF: while (writePtr <= endPtr) { *(half *) writePtr = *(half *)readPtr; readPtr += sizeof (half); writePtr += xStride; } break; case FLOAT: while (writePtr <= endPtr) { float f; for (size_t i = 0; i < sizeof (float); ++i) ((char *)&f)[i] = readPtr[i]; *(half *) writePtr = floatToHalf (f); readPtr += sizeof (float); writePtr += xStride; } break; } break; case FLOAT: switch (typeInFile) { case UINT: while (writePtr <= endPtr) { unsigned int ui; for (size_t i = 0; i < sizeof (unsigned int); ++i) ((char *)&ui)[i] = readPtr[i]; *(float *) writePtr = float (ui); readPtr += sizeof (unsigned int); writePtr += xStride; } break; case HALF: while (writePtr <= endPtr) { half h = *(half *) readPtr; *(float *) writePtr = float (h); readPtr += sizeof (half); writePtr += xStride; } break; case FLOAT: while (writePtr <= endPtr) { for (size_t i = 0; i < sizeof (float); ++i) writePtr[i] = readPtr[i]; readPtr += sizeof (float); writePtr += xStride; } break; } break; default: throw Iex::ArgExc ("Unknown pixel data type."); } } } void skipChannel (const char *& readPtr, PixelType typeInFile, size_t xSize) { switch (typeInFile) { case UINT: Xdr::skip (readPtr, Xdr::size () * xSize); break; case HALF: Xdr::skip (readPtr, Xdr::size () * xSize); break; case FLOAT: Xdr::skip (readPtr, Xdr::size () * xSize); break; default: throw Iex::ArgExc ("Unknown pixel data type."); } } void convertInPlace (char *& writePtr, const char *& readPtr, PixelType type, size_t numPixels) { switch (type) { case UINT: for (int j = 0; j < numPixels; ++j) { Xdr::write (writePtr, *(const unsigned int *) readPtr); readPtr += sizeof(unsigned int); } break; case HALF: for (int j = 0; j < numPixels; ++j) { Xdr::write (writePtr, *(const half *) readPtr); readPtr += sizeof(half); } break; case FLOAT: for (int j = 0; j < numPixels; ++j) { Xdr::write (writePtr, *(const float *) readPtr); readPtr += sizeof(float); } break; default: throw Iex::ArgExc ("Unknown pixel data type."); } } void copyFromFrameBuffer (char *& writePtr, const char *& readPtr, const char * endPtr, size_t xStride, Compressor::Format format, PixelType type) { // // Copy a horizontal row of pixels from a frame // buffer to an output file's line or tile buffer. // if (format == Compressor::XDR) { // // The the line or tile buffer is in XDR format. // switch (type) { case UINT: while (readPtr <= endPtr) { Xdr::write (writePtr, *(const unsigned int *) readPtr); readPtr += xStride; } break; case HALF: while (readPtr <= endPtr) { Xdr::write (writePtr, *(const half *) readPtr); readPtr += xStride; } break; case FLOAT: while (readPtr <= endPtr) { Xdr::write (writePtr, *(const float *) readPtr); readPtr += xStride; } break; default: throw Iex::ArgExc ("Unknown pixel data type."); } } else { // // The the line or tile buffer is in NATIVE format. // switch (type) { case UINT: while (readPtr <= endPtr) { for (size_t i = 0; i < sizeof (unsigned int); ++i) *writePtr++ = readPtr[i]; readPtr += xStride; } break; case HALF: while (readPtr <= endPtr) { *(half *) writePtr = *(const half *) readPtr; writePtr += sizeof (half); readPtr += xStride; } break; case FLOAT: while (readPtr <= endPtr) { for (size_t i = 0; i < sizeof (float); ++i) *writePtr++ = readPtr[i]; readPtr += xStride; } break; default: throw Iex::ArgExc ("Unknown pixel data type."); } } } void fillChannelWithZeroes (char *& writePtr, Compressor::Format format, PixelType type, size_t xSize) { if (format == Compressor::XDR) { // // Fill with data in XDR format. // switch (type) { case UINT: for (int j = 0; j < xSize; ++j) Xdr::write (writePtr, (unsigned int) 0); break; case HALF: for (int j = 0; j < xSize; ++j) Xdr::write (writePtr, (half) 0); break; case FLOAT: for (int j = 0; j < xSize; ++j) Xdr::write (writePtr, (float) 0); break; default: throw Iex::ArgExc ("Unknown pixel data type."); } } else { // // Fill with data in NATIVE format. // switch (type) { case UINT: for (int j = 0; j < xSize; ++j) { static const unsigned int ui = 0; for (size_t i = 0; i < sizeof (ui); ++i) *writePtr++ = ((char *) &ui)[i]; } break; case HALF: for (int j = 0; j < xSize; ++j) { *(half *) writePtr = half (0); writePtr += sizeof (half); } break; case FLOAT: for (int j = 0; j < xSize; ++j) { static const float f = 0; for (size_t i = 0; i < sizeof (f); ++i) *writePtr++ = ((char *) &f)[i]; } break; default: throw Iex::ArgExc ("Unknown pixel data type."); } } } } // namespace Imf