1405 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1405 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| ///////////////////////////////////////////////////////////////////////////
 | |
| //
 | |
| // 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.
 | |
| //
 | |
| ///////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| //
 | |
| //	class RgbaOutputFile
 | |
| //	class RgbaInputFile
 | |
| //
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| #include <ImfRgbaFile.h>
 | |
| #include <ImfOutputFile.h>
 | |
| #include <ImfInputFile.h>
 | |
| #include <ImfChannelList.h>
 | |
| #include <ImfRgbaYca.h>
 | |
| #include <ImfStandardAttributes.h>
 | |
| #include <ImathFun.h>
 | |
| #include <IlmThreadMutex.h>
 | |
| #include <Iex.h>
 | |
| #include <string.h>
 | |
| #include <algorithm>
 | |
| 
 | |
| 
 | |
| namespace Imf {
 | |
| 
 | |
| using namespace std;
 | |
| using namespace Imath;
 | |
| using namespace RgbaYca;
 | |
| using namespace IlmThread;
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| void
 | |
| insertChannels (Header &header, RgbaChannels rgbaChannels)
 | |
| {
 | |
|     ChannelList ch;
 | |
| 
 | |
|     if (rgbaChannels & (WRITE_Y | WRITE_C))
 | |
|     {
 | |
|     if (rgbaChannels & WRITE_Y)
 | |
|     {
 | |
|         ch.insert ("Y", Channel (HALF, 1, 1));
 | |
|     }
 | |
| 
 | |
|     if (rgbaChannels & WRITE_C)
 | |
|     {
 | |
|         ch.insert ("RY", Channel (HALF, 2, 2, true));
 | |
|         ch.insert ("BY", Channel (HALF, 2, 2, true));
 | |
|     }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|     if (rgbaChannels & WRITE_R)
 | |
|         ch.insert ("R", Channel (HALF, 1, 1));
 | |
| 
 | |
|     if (rgbaChannels & WRITE_G)
 | |
|         ch.insert ("G", Channel (HALF, 1, 1));
 | |
| 
 | |
|     if (rgbaChannels & WRITE_B)
 | |
|         ch.insert ("B", Channel (HALF, 1, 1));
 | |
|     }
 | |
| 
 | |
|     if (rgbaChannels & WRITE_A)
 | |
|     ch.insert ("A", Channel (HALF, 1, 1));
 | |
| 
 | |
|     header.channels() = ch;
 | |
| }
 | |
| 
 | |
| 
 | |
| RgbaChannels
 | |
| rgbaChannels (const ChannelList &ch, const string &channelNamePrefix = "")
 | |
| {
 | |
|     int i = 0;
 | |
| 
 | |
|     if (ch.findChannel (channelNamePrefix + "R"))
 | |
|     i |= WRITE_R;
 | |
| 
 | |
|     if (ch.findChannel (channelNamePrefix + "G"))
 | |
|     i |= WRITE_G;
 | |
| 
 | |
|     if (ch.findChannel (channelNamePrefix + "B"))
 | |
|     i |= WRITE_B;
 | |
| 
 | |
|     if (ch.findChannel (channelNamePrefix + "A"))
 | |
|     i |= WRITE_A;
 | |
| 
 | |
|     if (ch.findChannel (channelNamePrefix + "Y"))
 | |
|     i |= WRITE_Y;
 | |
| 
 | |
|     if (ch.findChannel (channelNamePrefix + "RY") ||
 | |
|     ch.findChannel (channelNamePrefix + "BY"))
 | |
|     i |= WRITE_C;
 | |
| 
 | |
|     return RgbaChannels (i);
 | |
| }
 | |
| 
 | |
| 
 | |
| string
 | |
| prefixFromLayerName (const string &layerName, const Header &header)
 | |
| {
 | |
|     if (layerName.empty())
 | |
|     return "";
 | |
| 
 | |
|     if (hasMultiView (header) && multiView(header)[0] == layerName)
 | |
|     return "";
 | |
| 
 | |
|     return layerName + ".";
 | |
| }
 | |
| 
 | |
| 
 | |
| V3f
 | |
| ywFromHeader (const Header &header)
 | |
| {
 | |
|     Chromaticities cr;
 | |
| 
 | |
|     if (hasChromaticities (header))
 | |
|     cr = chromaticities (header);
 | |
| 
 | |
|     return computeYw (cr);
 | |
| }
 | |
| 
 | |
| 
 | |
| ptrdiff_t
 | |
| cachePadding (ptrdiff_t size)
 | |
| {
 | |
|     //
 | |
|     // Some of the buffers that are allocated by classes ToYca and
 | |
|     // FromYca, below, may need to be padded to avoid cache thrashing.
 | |
|     // If the difference between the buffer size and the nearest power
 | |
|     // of two is less than CACHE_LINE_SIZE, then we add an appropriate
 | |
|     // amount of padding.
 | |
|     //
 | |
|     // CACHE_LINE_SIZE must be a power of two, and it must be at
 | |
|     // least as big as the true size of a cache line on the machine
 | |
|     // we are running on.  (It is ok if CACHE_LINE_SIZE is larger
 | |
|     // than a real cache line.)
 | |
|     //
 | |
| 
 | |
|     static int LOG2_CACHE_LINE_SIZE = 8;
 | |
|     static const ptrdiff_t CACHE_LINE_SIZE = (1 << LOG2_CACHE_LINE_SIZE);
 | |
| 
 | |
|     int i = LOG2_CACHE_LINE_SIZE + 2;
 | |
| 
 | |
|     while ((size >> i) > 1)
 | |
|     ++i;
 | |
| 
 | |
|     if (size > (1 << (i + 1)) - 64)
 | |
|     return 64 + ((1 << (i + 1)) - size);
 | |
| 
 | |
|     if (size < (1 << i) + 64)
 | |
|     return 64 + ((1 << i) - size);
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| } // namespace
 | |
| 
 | |
| 
 | |
| class RgbaOutputFile::ToYca: public Mutex
 | |
| {
 | |
|   public:
 | |
| 
 | |
|      ToYca (OutputFile &outputFile, RgbaChannels rgbaChannels);
 | |
|     ~ToYca ();
 | |
| 
 | |
|     void		setYCRounding (unsigned int roundY,
 | |
|                            unsigned int roundC);
 | |
| 
 | |
|     void		setFrameBuffer (const Rgba *base,
 | |
|                     size_t xStride,
 | |
|                     size_t yStride);
 | |
| 
 | |
|     void		writePixels (int numScanLines);
 | |
|     int			currentScanLine () const;
 | |
| 
 | |
|   private:
 | |
| 
 | |
|     void		padTmpBuf ();
 | |
|     void		rotateBuffers ();
 | |
|     void		duplicateLastBuffer ();
 | |
|     void		duplicateSecondToLastBuffer ();
 | |
|     void		decimateChromaVertAndWriteScanLine ();
 | |
| 
 | |
|     OutputFile &	_outputFile;
 | |
|     bool		_writeY;
 | |
|     bool		_writeC;
 | |
|     bool		_writeA;
 | |
|     int			_xMin;
 | |
|     int			_width;
 | |
|     int			_height;
 | |
|     int			_linesConverted;
 | |
|     LineOrder		_lineOrder;
 | |
|     int			_currentScanLine;
 | |
|     V3f			_yw;
 | |
|     Rgba *		_bufBase;
 | |
|     Rgba *		_buf[N];
 | |
|     Rgba *		_tmpBuf;
 | |
|     const Rgba *	_fbBase;
 | |
|     size_t		_fbXStride;
 | |
|     size_t		_fbYStride;
 | |
|     int			_roundY;
 | |
|     int			_roundC;
 | |
| };
 | |
| 
 | |
| 
 | |
| RgbaOutputFile::ToYca::ToYca (OutputFile &outputFile,
 | |
|                   RgbaChannels rgbaChannels)
 | |
| :
 | |
|     _outputFile (outputFile)
 | |
| {
 | |
|     _writeY = (rgbaChannels & WRITE_Y)? true: false;
 | |
|     _writeC = (rgbaChannels & WRITE_C)? true: false;
 | |
|     _writeA = (rgbaChannels & WRITE_A)? true: false;
 | |
| 
 | |
|     const Box2i dw = _outputFile.header().dataWindow();
 | |
| 
 | |
|     _xMin = dw.min.x;
 | |
|     _width  = dw.max.x - dw.min.x + 1;
 | |
|     _height = dw.max.y - dw.min.y + 1;
 | |
| 
 | |
|     _linesConverted = 0;
 | |
|     _lineOrder = _outputFile.header().lineOrder();
 | |
| 
 | |
|     if (_lineOrder == INCREASING_Y)
 | |
|     _currentScanLine = dw.min.y;
 | |
|     else
 | |
|     _currentScanLine = dw.max.y;
 | |
| 
 | |
|     _yw = ywFromHeader (_outputFile.header());
 | |
| 
 | |
|     ptrdiff_t pad = cachePadding (_width * sizeof (Rgba)) / sizeof (Rgba);
 | |
| 
 | |
|     _bufBase = new Rgba[(_width + pad) * N];
 | |
| 
 | |
|     for (int i = 0; i < N; ++i)
 | |
|     _buf[i] = _bufBase + (i * (_width + pad));
 | |
| 
 | |
|     _tmpBuf = new Rgba[_width + N - 1];
 | |
| 
 | |
|     _fbBase = 0;
 | |
|     _fbXStride = 0;
 | |
|     _fbYStride = 0;
 | |
| 
 | |
|     _roundY = 7;
 | |
|     _roundC = 5;
 | |
| }
 | |
| 
 | |
| 
 | |
| RgbaOutputFile::ToYca::~ToYca ()
 | |
| {
 | |
|     delete [] _bufBase;
 | |
|     delete [] _tmpBuf;
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| RgbaOutputFile::ToYca::setYCRounding (unsigned int roundY,
 | |
|                       unsigned int roundC)
 | |
| {
 | |
|     _roundY = roundY;
 | |
|     _roundC = roundC;
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| RgbaOutputFile::ToYca::setFrameBuffer (const Rgba *base,
 | |
|                        size_t xStride,
 | |
|                        size_t yStride)
 | |
| {
 | |
|     if (_fbBase == 0)
 | |
|     {
 | |
|     FrameBuffer fb;
 | |
| 
 | |
|     if (_writeY)
 | |
|     {
 | |
|         fb.insert ("Y",
 | |
|                Slice (HALF,				// type
 | |
|                   (char *) &_tmpBuf[-_xMin].g,	// base
 | |
|                   sizeof (Rgba),			// xStride
 | |
|                   0,				// yStride
 | |
|                   1,				// xSampling
 | |
|                   1));				// ySampling
 | |
|     }
 | |
| 
 | |
|     if (_writeC)
 | |
|     {
 | |
|         fb.insert ("RY",
 | |
|                Slice (HALF,				// type
 | |
|                   (char *) &_tmpBuf[-_xMin].r,	// base
 | |
|                   sizeof (Rgba) * 2,		// xStride
 | |
|                   0,				// yStride
 | |
|                   2,				// xSampling
 | |
|                   2));				// ySampling
 | |
| 
 | |
|         fb.insert ("BY",
 | |
|                Slice (HALF,				// type
 | |
|                   (char *) &_tmpBuf[-_xMin].b,	// base
 | |
|                   sizeof (Rgba) * 2,		// xStride
 | |
|                   0,				// yStride
 | |
|                   2,				// xSampling
 | |
|                   2));				// ySampling
 | |
|     }
 | |
| 
 | |
|     if (_writeA)
 | |
|     {
 | |
|         fb.insert ("A",
 | |
|                Slice (HALF,				// type
 | |
|                   (char *) &_tmpBuf[-_xMin].a,	// base
 | |
|                   sizeof (Rgba),			// xStride
 | |
|                   0,				// yStride
 | |
|                   1,				// xSampling
 | |
|                   1));				// ySampling
 | |
|     }
 | |
| 
 | |
|     _outputFile.setFrameBuffer (fb);
 | |
|     }
 | |
| 
 | |
|     _fbBase = base;
 | |
|     _fbXStride = xStride;
 | |
|     _fbYStride = yStride;
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| RgbaOutputFile::ToYca::writePixels (int numScanLines)
 | |
| {
 | |
|     if (_fbBase == 0)
 | |
|     {
 | |
|     THROW (Iex::ArgExc, "No frame buffer was specified as the "
 | |
|                 "pixel data source for image file "
 | |
|                 "\"" << _outputFile.fileName() << "\".");
 | |
|     }
 | |
| 
 | |
|     if (_writeY && !_writeC)
 | |
|     {
 | |
|     //
 | |
|     // We are writing only luminance; filtering
 | |
|     // and subsampling are not necessary.
 | |
|     //
 | |
| 
 | |
|     for (int i = 0; i < numScanLines; ++i)
 | |
|     {
 | |
|         //
 | |
|         // Copy the next scan line from the caller's
 | |
|         // frame buffer into _tmpBuf.
 | |
|         //
 | |
| 
 | |
|         for (int j = 0; j < _width; ++j)
 | |
|         {
 | |
|         _tmpBuf[j] = _fbBase[_fbYStride * _currentScanLine +
 | |
|                      _fbXStride * (j + _xMin)];
 | |
|         }
 | |
| 
 | |
|         //
 | |
|         // Convert the scan line from RGB to luminance/chroma,
 | |
|         // and store the result in the output file.
 | |
|         //
 | |
| 
 | |
|         RGBAtoYCA (_yw, _width, _writeA, _tmpBuf, _tmpBuf);
 | |
|         _outputFile.writePixels (1);
 | |
| 
 | |
|         ++_linesConverted;
 | |
| 
 | |
|         if (_lineOrder == INCREASING_Y)
 | |
|         ++_currentScanLine;
 | |
|         else
 | |
|         --_currentScanLine;
 | |
|     }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|     //
 | |
|     // We are writing chroma; the pixels must be filtered and subsampled.
 | |
|     //
 | |
| 
 | |
|     for (int i = 0; i < numScanLines; ++i)
 | |
|     {
 | |
|         //
 | |
|         // Copy the next scan line from the caller's
 | |
|         // frame buffer into _tmpBuf.
 | |
|         //
 | |
| 
 | |
|         for (int j = 0; j < _width; ++j)
 | |
|         {
 | |
|         _tmpBuf[j + N2] = _fbBase[_fbYStride * _currentScanLine +
 | |
|                       _fbXStride * (j + _xMin)];
 | |
|         }
 | |
| 
 | |
|         //
 | |
|         // Convert the scan line from RGB to luminance/chroma.
 | |
|         //
 | |
| 
 | |
|         RGBAtoYCA (_yw, _width, _writeA, _tmpBuf + N2, _tmpBuf + N2);
 | |
| 
 | |
|         //
 | |
|         // Append N2 copies of the first and last pixel to the
 | |
|         // beginning and end of the scan line.
 | |
|         //
 | |
| 
 | |
|         padTmpBuf ();
 | |
| 
 | |
|         //
 | |
|         // Filter and subsample the scan line's chroma channels
 | |
|         // horizontally; store the result in _buf.
 | |
|         //
 | |
| 
 | |
|         rotateBuffers();
 | |
|         decimateChromaHoriz (_width, _tmpBuf, _buf[N - 1]);
 | |
| 
 | |
|         //
 | |
|         // If this is the first scan line in the image,
 | |
|         // store N2 more copies of the scan line in _buf.
 | |
|         //
 | |
| 
 | |
|         if (_linesConverted == 0)
 | |
|         {
 | |
|         for (int j = 0; j < N2; ++j)
 | |
|             duplicateLastBuffer();
 | |
|         }
 | |
| 
 | |
|         ++_linesConverted;
 | |
| 
 | |
|         //
 | |
|         // If we have have converted at least N2 scan lines from
 | |
|         // RGBA to luminance/chroma, then we can start to filter
 | |
|         // and subsample vertically, and store pixels in the
 | |
|         // output file.
 | |
|         //
 | |
| 
 | |
|         if (_linesConverted > N2)
 | |
|         decimateChromaVertAndWriteScanLine();
 | |
| 
 | |
|         //
 | |
|         // If we have already converted the last scan line in
 | |
|         // the image to luminance/chroma, filter, subsample and
 | |
|         // store the remaining scan lines in _buf.
 | |
|         //
 | |
| 
 | |
|         if (_linesConverted >= _height)
 | |
|         {
 | |
|         for (int j = 0; j < N2 - _height; ++j)
 | |
|             duplicateLastBuffer();
 | |
| 
 | |
|         duplicateSecondToLastBuffer();
 | |
|         ++_linesConverted;
 | |
|         decimateChromaVertAndWriteScanLine();
 | |
| 
 | |
|         for (int j = 1; j < min (_height, N2); ++j)
 | |
|         {
 | |
|             duplicateLastBuffer();
 | |
|             ++_linesConverted;
 | |
|             decimateChromaVertAndWriteScanLine();
 | |
|         }
 | |
|         }
 | |
| 
 | |
|         if (_lineOrder == INCREASING_Y)
 | |
|         ++_currentScanLine;
 | |
|         else
 | |
|         --_currentScanLine;
 | |
|     }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| RgbaOutputFile::ToYca::currentScanLine () const
 | |
| {
 | |
|     return _currentScanLine;
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| RgbaOutputFile::ToYca::padTmpBuf ()
 | |
| {
 | |
|     for (int i = 0; i < N2; ++i)
 | |
|     {
 | |
|     _tmpBuf[i] = _tmpBuf[N2];
 | |
|     _tmpBuf[_width + N2 + i] = _tmpBuf[_width + N2 - 2];
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| RgbaOutputFile::ToYca::rotateBuffers ()
 | |
| {
 | |
|     Rgba *tmp = _buf[0];
 | |
| 
 | |
|     for (int i = 0; i < N - 1; ++i)
 | |
|     _buf[i] = _buf[i + 1];
 | |
| 
 | |
|     _buf[N - 1] = tmp;
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| RgbaOutputFile::ToYca::duplicateLastBuffer ()
 | |
| {
 | |
|     rotateBuffers();
 | |
|     memcpy (_buf[N - 1], _buf[N - 2], _width * sizeof (Rgba));
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| RgbaOutputFile::ToYca::duplicateSecondToLastBuffer ()
 | |
| {
 | |
|     rotateBuffers();
 | |
|     memcpy (_buf[N - 1], _buf[N - 3], _width * sizeof (Rgba));
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| RgbaOutputFile::ToYca::decimateChromaVertAndWriteScanLine ()
 | |
| {
 | |
|     if (_linesConverted & 1)
 | |
|     memcpy (_tmpBuf, _buf[N2], _width * sizeof (Rgba));
 | |
|     else
 | |
|     decimateChromaVert (_width, _buf, _tmpBuf);
 | |
| 
 | |
|     if (_writeY && _writeC)
 | |
|     roundYCA (_width, _roundY, _roundC, _tmpBuf, _tmpBuf);
 | |
| 
 | |
|     _outputFile.writePixels (1);
 | |
| }
 | |
| 
 | |
| 
 | |
| RgbaOutputFile::RgbaOutputFile (const char name[],
 | |
|                 const Header &header,
 | |
|                 RgbaChannels rgbaChannels,
 | |
|                                 int numThreads):
 | |
|     _outputFile (0),
 | |
|     _toYca (0)
 | |
| {
 | |
|     Header hd (header);
 | |
|     insertChannels (hd, rgbaChannels);
 | |
|     _outputFile = new OutputFile (name, hd, numThreads);
 | |
| 
 | |
|     if (rgbaChannels & (WRITE_Y | WRITE_C))
 | |
|     _toYca = new ToYca (*_outputFile, rgbaChannels);
 | |
| }
 | |
| 
 | |
| 
 | |
| RgbaOutputFile::RgbaOutputFile (OStream &os,
 | |
|                 const Header &header,
 | |
|                 RgbaChannels rgbaChannels,
 | |
|                                 int numThreads):
 | |
|     _outputFile (0),
 | |
|     _toYca (0)
 | |
| {
 | |
|     Header hd (header);
 | |
|     insertChannels (hd, rgbaChannels);
 | |
|     _outputFile = new OutputFile (os, hd, numThreads);
 | |
| 
 | |
|     if (rgbaChannels & (WRITE_Y | WRITE_C))
 | |
|     _toYca = new ToYca (*_outputFile, rgbaChannels);
 | |
| }
 | |
| 
 | |
| 
 | |
| RgbaOutputFile::RgbaOutputFile (const char name[],
 | |
|                 const Imath::Box2i &displayWindow,
 | |
|                 const Imath::Box2i &dataWindow,
 | |
|                 RgbaChannels rgbaChannels,
 | |
|                 float pixelAspectRatio,
 | |
|                 const Imath::V2f screenWindowCenter,
 | |
|                 float screenWindowWidth,
 | |
|                 LineOrder lineOrder,
 | |
|                 Compression compression,
 | |
|                                 int numThreads):
 | |
|     _outputFile (0),
 | |
|     _toYca (0)
 | |
| {
 | |
|     Header hd (displayWindow,
 | |
|            dataWindow.isEmpty()? displayWindow: dataWindow,
 | |
|            pixelAspectRatio,
 | |
|            screenWindowCenter,
 | |
|            screenWindowWidth,
 | |
|            lineOrder,
 | |
|            compression);
 | |
| 
 | |
|     insertChannels (hd, rgbaChannels);
 | |
|     _outputFile = new OutputFile (name, hd, numThreads);
 | |
| 
 | |
|     if (rgbaChannels & (WRITE_Y | WRITE_C))
 | |
|     _toYca = new ToYca (*_outputFile, rgbaChannels);
 | |
| }
 | |
| 
 | |
| 
 | |
| RgbaOutputFile::RgbaOutputFile (const char name[],
 | |
|                 int width,
 | |
|                 int height,
 | |
|                 RgbaChannels rgbaChannels,
 | |
|                 float pixelAspectRatio,
 | |
|                 const Imath::V2f screenWindowCenter,
 | |
|                 float screenWindowWidth,
 | |
|                 LineOrder lineOrder,
 | |
|                 Compression compression,
 | |
|                                 int numThreads):
 | |
|     _outputFile (0),
 | |
|     _toYca (0)
 | |
| {
 | |
|     Header hd (width,
 | |
|            height,
 | |
|            pixelAspectRatio,
 | |
|            screenWindowCenter,
 | |
|            screenWindowWidth,
 | |
|            lineOrder,
 | |
|            compression);
 | |
| 
 | |
|     insertChannels (hd, rgbaChannels);
 | |
|     _outputFile = new OutputFile (name, hd, numThreads);
 | |
| 
 | |
|     if (rgbaChannels & (WRITE_Y | WRITE_C))
 | |
|     _toYca = new ToYca (*_outputFile, rgbaChannels);
 | |
| }
 | |
| 
 | |
| 
 | |
| RgbaOutputFile::~RgbaOutputFile ()
 | |
| {
 | |
|     delete _toYca;
 | |
|     delete _outputFile;
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| RgbaOutputFile::setFrameBuffer (const Rgba *base,
 | |
|                 size_t xStride,
 | |
|                 size_t yStride)
 | |
| {
 | |
|     if (_toYca)
 | |
|     {
 | |
|     Lock lock (*_toYca);
 | |
|     _toYca->setFrameBuffer (base, xStride, yStride);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|     size_t xs = xStride * sizeof (Rgba);
 | |
|     size_t ys = yStride * sizeof (Rgba);
 | |
| 
 | |
|     FrameBuffer fb;
 | |
| 
 | |
|     fb.insert ("R", Slice (HALF, (char *) &base[0].r, xs, ys));
 | |
|     fb.insert ("G", Slice (HALF, (char *) &base[0].g, xs, ys));
 | |
|     fb.insert ("B", Slice (HALF, (char *) &base[0].b, xs, ys));
 | |
|     fb.insert ("A", Slice (HALF, (char *) &base[0].a, xs, ys));
 | |
| 
 | |
|     _outputFile->setFrameBuffer (fb);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| RgbaOutputFile::writePixels (int numScanLines)
 | |
| {
 | |
|     if (_toYca)
 | |
|     {
 | |
|     Lock lock (*_toYca);
 | |
|     _toYca->writePixels (numScanLines);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|     _outputFile->writePixels (numScanLines);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| RgbaOutputFile::currentScanLine () const
 | |
| {
 | |
|     if (_toYca)
 | |
|     {
 | |
|     Lock lock (*_toYca);
 | |
|     return _toYca->currentScanLine();
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|     return _outputFile->currentScanLine();
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| const Header &
 | |
| RgbaOutputFile::header () const
 | |
| {
 | |
|     return _outputFile->header();
 | |
| }
 | |
| 
 | |
| 
 | |
| const FrameBuffer &
 | |
| RgbaOutputFile::frameBuffer () const
 | |
| {
 | |
|     return _outputFile->frameBuffer();
 | |
| }
 | |
| 
 | |
| 
 | |
| const Imath::Box2i &
 | |
| RgbaOutputFile::displayWindow () const
 | |
| {
 | |
|     return _outputFile->header().displayWindow();
 | |
| }
 | |
| 
 | |
| 
 | |
| const Imath::Box2i &
 | |
| RgbaOutputFile::dataWindow () const
 | |
| {
 | |
|     return _outputFile->header().dataWindow();
 | |
| }
 | |
| 
 | |
| 
 | |
| float
 | |
| RgbaOutputFile::pixelAspectRatio () const
 | |
| {
 | |
|     return _outputFile->header().pixelAspectRatio();
 | |
| }
 | |
| 
 | |
| 
 | |
| const Imath::V2f
 | |
| RgbaOutputFile::screenWindowCenter () const
 | |
| {
 | |
|     return _outputFile->header().screenWindowCenter();
 | |
| }
 | |
| 
 | |
| 
 | |
| float
 | |
| RgbaOutputFile::screenWindowWidth () const
 | |
| {
 | |
|     return _outputFile->header().screenWindowWidth();
 | |
| }
 | |
| 
 | |
| 
 | |
| LineOrder
 | |
| RgbaOutputFile::lineOrder () const
 | |
| {
 | |
|     return _outputFile->header().lineOrder();
 | |
| }
 | |
| 
 | |
| 
 | |
| Compression
 | |
| RgbaOutputFile::compression () const
 | |
| {
 | |
|     return _outputFile->header().compression();
 | |
| }
 | |
| 
 | |
| 
 | |
| RgbaChannels
 | |
| RgbaOutputFile::channels () const
 | |
| {
 | |
|     return rgbaChannels (_outputFile->header().channels());
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| RgbaOutputFile::updatePreviewImage (const PreviewRgba newPixels[])
 | |
| {
 | |
|     _outputFile->updatePreviewImage (newPixels);
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| RgbaOutputFile::setYCRounding (unsigned int roundY, unsigned int roundC)
 | |
| {
 | |
|     if (_toYca)
 | |
|     {
 | |
|     Lock lock (*_toYca);
 | |
|     _toYca->setYCRounding (roundY, roundC);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| RgbaOutputFile::breakScanLine  (int y, int offset, int length, char c)
 | |
| {
 | |
|     _outputFile->breakScanLine (y, offset, length, c);
 | |
| }
 | |
| 
 | |
| 
 | |
| class RgbaInputFile::FromYca: public Mutex
 | |
| {
 | |
|   public:
 | |
| 
 | |
|      FromYca (InputFile &inputFile, RgbaChannels rgbaChannels);
 | |
|     ~FromYca ();
 | |
| 
 | |
|     void		setFrameBuffer (Rgba *base,
 | |
|                     size_t xStride,
 | |
|                     size_t yStride,
 | |
|                     const string &channelNamePrefix);
 | |
| 
 | |
|     void		readPixels (int scanLine1, int scanLine2);
 | |
| 
 | |
|   private:
 | |
| 
 | |
|     void		readPixels (int scanLine);
 | |
|     void		rotateBuf1 (int d);
 | |
|     void		rotateBuf2 (int d);
 | |
|     void		readYCAScanLine (int y, Rgba buf[]);
 | |
|     void		padTmpBuf ();
 | |
| 
 | |
|     InputFile &		_inputFile;
 | |
|     bool		_readC;
 | |
|     int			_xMin;
 | |
|     int			_yMin;
 | |
|     int 		_yMax;
 | |
|     int			_width;
 | |
|     int			_height;
 | |
|     int			_currentScanLine;
 | |
|     LineOrder		_lineOrder;
 | |
|     V3f			_yw;
 | |
|     Rgba *		_bufBase;
 | |
|     Rgba *		_buf1[N + 2];
 | |
|     Rgba *		_buf2[3];
 | |
|     Rgba *		_tmpBuf;
 | |
|     Rgba *		_fbBase;
 | |
|     size_t		_fbXStride;
 | |
|     size_t		_fbYStride;
 | |
| };
 | |
| 
 | |
| 
 | |
| RgbaInputFile::FromYca::FromYca (InputFile &inputFile,
 | |
|                  RgbaChannels rgbaChannels)
 | |
| :
 | |
|     _inputFile (inputFile)
 | |
| {
 | |
|     _readC = (rgbaChannels & WRITE_C)? true: false;
 | |
| 
 | |
|     const Box2i dw = _inputFile.header().dataWindow();
 | |
| 
 | |
|     _xMin = dw.min.x;
 | |
|     _yMin = dw.min.y;
 | |
|     _yMax = dw.max.y;
 | |
|     _width  = dw.max.x - dw.min.x + 1;
 | |
|     _height = dw.max.y - dw.min.y + 1;
 | |
|     _currentScanLine = dw.min.y - N - 2;
 | |
|     _lineOrder = _inputFile.header().lineOrder();
 | |
|     _yw = ywFromHeader (_inputFile.header());
 | |
| 
 | |
|     ptrdiff_t pad = cachePadding (_width * sizeof (Rgba)) / sizeof (Rgba);
 | |
| 
 | |
|     _bufBase = new Rgba[(_width + pad) * (N + 2 + 3)];
 | |
| 
 | |
|     for (int i = 0; i < N + 2; ++i)
 | |
|     _buf1[i] = _bufBase + (i * (_width + pad));
 | |
| 
 | |
|     for (int i = 0; i < 3; ++i)
 | |
|     _buf2[i] = _bufBase + ((i + N + 2) * (_width + pad));
 | |
| 
 | |
|     _tmpBuf = new Rgba[_width + N - 1];
 | |
| 
 | |
|     _fbBase = 0;
 | |
|     _fbXStride = 0;
 | |
|     _fbYStride = 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| RgbaInputFile::FromYca::~FromYca ()
 | |
| {
 | |
|     delete [] _bufBase;
 | |
|     delete [] _tmpBuf;
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| RgbaInputFile::FromYca::setFrameBuffer (Rgba *base,
 | |
|                     size_t xStride,
 | |
|                     size_t yStride,
 | |
|                     const string &channelNamePrefix)
 | |
| {
 | |
|     if (_fbBase == 0)
 | |
|     {
 | |
|     FrameBuffer fb;
 | |
| 
 | |
|     fb.insert (channelNamePrefix + "Y",
 | |
|            Slice (HALF,					// type
 | |
|               (char *) &_tmpBuf[N2 - _xMin].g,	// base
 | |
|               sizeof (Rgba),			// xStride
 | |
|               0,					// yStride
 | |
|               1,					// xSampling
 | |
|               1,					// ySampling
 | |
|               0.5));				// fillValue
 | |
| 
 | |
|     if (_readC)
 | |
|     {
 | |
|         fb.insert (channelNamePrefix + "RY",
 | |
|                Slice (HALF,				// type
 | |
|                   (char *) &_tmpBuf[N2 - _xMin].r,	// base
 | |
|                   sizeof (Rgba) * 2,		// xStride
 | |
|                   0,				// yStride
 | |
|                   2,				// xSampling
 | |
|                   2,				// ySampling
 | |
|                   0.0));				// fillValue
 | |
| 
 | |
|         fb.insert (channelNamePrefix + "BY",
 | |
|                Slice (HALF,				// type
 | |
|                   (char *) &_tmpBuf[N2 - _xMin].b,	// base
 | |
|                   sizeof (Rgba) * 2,		// xStride
 | |
|                   0,				// yStride
 | |
|                   2,				// xSampling
 | |
|                   2,				// ySampling
 | |
|                   0.0));				// fillValue
 | |
|     }
 | |
| 
 | |
|     fb.insert (channelNamePrefix + "A",
 | |
|            Slice (HALF,					// type
 | |
|               (char *) &_tmpBuf[N2 - _xMin].a,	// base
 | |
|               sizeof (Rgba),			// xStride
 | |
|               0,					// yStride
 | |
|               1,					// xSampling
 | |
|               1,					// ySampling
 | |
|               1.0));				// fillValue
 | |
| 
 | |
|     _inputFile.setFrameBuffer (fb);
 | |
|     }
 | |
| 
 | |
|     _fbBase = base;
 | |
|     _fbXStride = xStride;
 | |
|     _fbYStride = yStride;
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| RgbaInputFile::FromYca::readPixels (int scanLine1, int scanLine2)
 | |
| {
 | |
|     int minY = min (scanLine1, scanLine2);
 | |
|     int maxY = max (scanLine1, scanLine2);
 | |
| 
 | |
|     if (_lineOrder == INCREASING_Y)
 | |
|     {
 | |
|     for (int y = minY; y <= maxY; ++y)
 | |
|         readPixels (y);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|     for (int y = maxY; y >= minY; --y)
 | |
|         readPixels (y);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| RgbaInputFile::FromYca::readPixels (int scanLine)
 | |
| {
 | |
|     if (_fbBase == 0)
 | |
|     {
 | |
|     THROW (Iex::ArgExc, "No frame buffer was specified as the "
 | |
|                 "pixel data destination for image file "
 | |
|                 "\"" << _inputFile.fileName() << "\".");
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // In order to convert one scan line to RGB format, we need that
 | |
|     // scan line plus N2+1 extra scan lines above and N2+1 scan lines
 | |
|     // below in luminance/chroma format.
 | |
|     //
 | |
|     // We allow random access to scan lines, but we buffer partially
 | |
|     // processed luminance/chroma data in order to make reading pixels
 | |
|     // in increasing y or decreasing y order reasonably efficient:
 | |
|     //
 | |
|     //	_currentScanLine	holds the y coordinate of the scan line
 | |
|     //				that was most recently read.
 | |
|     //
 | |
|     //	_buf1			contains scan lines _currentScanLine-N2-1
 | |
|     //				through _currentScanLine+N2+1 in
 | |
|     //				luminance/chroma format.  Odd-numbered
 | |
|     //				lines contain no chroma data.  Even-numbered
 | |
|     //				lines have valid chroma data for all pixels.
 | |
|     //
 | |
|     //  _buf2			contains scan lines _currentScanLine-1
 | |
|     //  			through _currentScanLine+1, in RGB format.
 | |
|     //				Super-saturated pixels (see ImfRgbaYca.h)
 | |
|     //				have not yet been eliminated.
 | |
|     //
 | |
|     // If the scan line we are trying to read now is close enough to
 | |
|     // _currentScanLine, we don't have to recompute the contents of _buf1
 | |
|     // and _buf2 from scratch.  We can rotate _buf1 and _buf2, and fill
 | |
|     // in the missing data.
 | |
|     //
 | |
| 
 | |
|     int dy = scanLine - _currentScanLine;
 | |
| 
 | |
|     if (abs (dy) < N + 2)
 | |
|     rotateBuf1 (dy);
 | |
| 
 | |
|     if (abs (dy) < 3)
 | |
|     rotateBuf2 (dy);
 | |
| 
 | |
|     if (dy < 0)
 | |
|     {
 | |
|     {
 | |
|         int n = min (-dy, N + 2);
 | |
|         int yMin = scanLine - N2 - 1;
 | |
| 
 | |
|         for (int i = n - 1; i >= 0; --i)
 | |
|         readYCAScanLine (yMin + i, _buf1[i]);
 | |
|     }
 | |
| 
 | |
|     {
 | |
|         int n = min (-dy, 3);
 | |
| 
 | |
|         for (int i = 0; i < n; ++i)
 | |
|         {
 | |
|         if ((scanLine + i) & 1)
 | |
|         {
 | |
|             YCAtoRGBA (_yw, _width, _buf1[N2 + i], _buf2[i]);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             reconstructChromaVert (_width, _buf1 + i, _buf2[i]);
 | |
|             YCAtoRGBA (_yw, _width, _buf2[i], _buf2[i]);
 | |
|         }
 | |
|         }
 | |
|     }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|     {
 | |
|         int n = min (dy, N + 2);
 | |
|         int yMax = scanLine + N2 + 1;
 | |
| 
 | |
|         for (int i = n - 1; i >= 0; --i)
 | |
|         readYCAScanLine (yMax - i, _buf1[N + 1 - i]);
 | |
|     }
 | |
| 
 | |
|     {
 | |
|         int n = min (dy, 3);
 | |
| 
 | |
|         for (int i = 2; i > 2 - n; --i)
 | |
|         {
 | |
|         if ((scanLine + i) & 1)
 | |
|         {
 | |
|             YCAtoRGBA (_yw, _width, _buf1[N2 + i], _buf2[i]);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             reconstructChromaVert (_width, _buf1 + i, _buf2[i]);
 | |
|             YCAtoRGBA (_yw, _width, _buf2[i], _buf2[i]);
 | |
|         }
 | |
|         }
 | |
|     }
 | |
|     }
 | |
| 
 | |
|     fixSaturation (_yw, _width, _buf2, _tmpBuf);
 | |
| 
 | |
|     for (int i = 0; i < _width; ++i)
 | |
|     _fbBase[_fbYStride * scanLine + _fbXStride * (i + _xMin)] = _tmpBuf[i];
 | |
| 
 | |
|     _currentScanLine = scanLine;
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| RgbaInputFile::FromYca::rotateBuf1 (int d)
 | |
| {
 | |
|     d = modp (d, N + 2);
 | |
| 
 | |
|     Rgba *tmp[N + 2];
 | |
| 
 | |
|     for (int i = 0; i < N + 2; ++i)
 | |
|     tmp[i] = _buf1[i];
 | |
| 
 | |
|     for (int i = 0; i < N + 2; ++i)
 | |
|     _buf1[i] = tmp[(i + d) % (N + 2)];
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| RgbaInputFile::FromYca::rotateBuf2 (int d)
 | |
| {
 | |
|     d = modp (d, 3);
 | |
| 
 | |
|     Rgba *tmp[3];
 | |
| 
 | |
|     for (int i = 0; i < 3; ++i)
 | |
|     tmp[i] = _buf2[i];
 | |
| 
 | |
|     for (int i = 0; i < 3; ++i)
 | |
|     _buf2[i] = tmp[(i + d) % 3];
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| RgbaInputFile::FromYca::readYCAScanLine (int y, Rgba *buf)
 | |
| {
 | |
|     //
 | |
|     // Clamp y.
 | |
|     //
 | |
| 
 | |
|     if (y < _yMin)
 | |
|     y = _yMin;
 | |
|     else if (y > _yMax)
 | |
|     y = _yMax - 1;
 | |
| 
 | |
|     //
 | |
|     // Read scan line y into _tmpBuf.
 | |
|     //
 | |
| 
 | |
|     _inputFile.readPixels (y);
 | |
| 
 | |
|     //
 | |
|     // Reconstruct missing chroma samples and copy
 | |
|     // the scan line into buf.
 | |
|     //
 | |
| 
 | |
|     if (!_readC)
 | |
|     {
 | |
|     for (int i = 0; i < _width; ++i)
 | |
|     {
 | |
|         _tmpBuf[i + N2].r = 0;
 | |
|         _tmpBuf[i + N2].b = 0;
 | |
|     }
 | |
|     }
 | |
| 
 | |
|     if (y & 1)
 | |
|     {
 | |
|     memcpy (buf, _tmpBuf + N2, _width * sizeof (Rgba));
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|     padTmpBuf();
 | |
|     reconstructChromaHoriz (_width, _tmpBuf, buf);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| RgbaInputFile::FromYca::padTmpBuf ()
 | |
| {
 | |
|     for (int i = 0; i < N2; ++i)
 | |
|     {
 | |
|     _tmpBuf[i] = _tmpBuf[N2];
 | |
|     _tmpBuf[_width + N2 + i] = _tmpBuf[_width + N2 - 2];
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| RgbaInputFile::RgbaInputFile (const char name[], int numThreads):
 | |
|     _inputFile (new InputFile (name, numThreads)),
 | |
|     _fromYca (0),
 | |
|     _channelNamePrefix ("")
 | |
| {
 | |
|     RgbaChannels rgbaChannels = channels();
 | |
| 
 | |
|     if (rgbaChannels & (WRITE_Y | WRITE_C))
 | |
|     _fromYca = new FromYca (*_inputFile, rgbaChannels);
 | |
| }
 | |
| 
 | |
| 
 | |
| RgbaInputFile::RgbaInputFile (IStream &is, int numThreads):
 | |
|     _inputFile (new InputFile (is, numThreads)),
 | |
|     _fromYca (0),
 | |
|     _channelNamePrefix ("")
 | |
| {
 | |
|     RgbaChannels rgbaChannels = channels();
 | |
| 
 | |
|     if (rgbaChannels & (WRITE_Y | WRITE_C))
 | |
|     _fromYca = new FromYca (*_inputFile, rgbaChannels);
 | |
| }
 | |
| 
 | |
| 
 | |
| RgbaInputFile::RgbaInputFile (const char name[],
 | |
|                   const string &layerName,
 | |
|                   int numThreads)
 | |
| :
 | |
|     _inputFile (new InputFile (name, numThreads)),
 | |
|     _fromYca (0),
 | |
|     _channelNamePrefix (prefixFromLayerName (layerName, _inputFile->header()))
 | |
| {
 | |
|     RgbaChannels rgbaChannels = channels();
 | |
| 
 | |
|     if (rgbaChannels & (WRITE_Y | WRITE_C))
 | |
|     _fromYca = new FromYca (*_inputFile, rgbaChannels);
 | |
| }
 | |
| 
 | |
| 
 | |
| RgbaInputFile::RgbaInputFile (IStream &is,
 | |
|                   const string &layerName,
 | |
|                   int numThreads)
 | |
| :
 | |
|     _inputFile (new InputFile (is, numThreads)),
 | |
|     _fromYca (0),
 | |
|     _channelNamePrefix (prefixFromLayerName (layerName, _inputFile->header()))
 | |
| {
 | |
|     RgbaChannels rgbaChannels = channels();
 | |
| 
 | |
|     if (rgbaChannels & (WRITE_Y | WRITE_C))
 | |
|     _fromYca = new FromYca (*_inputFile, rgbaChannels);
 | |
| }
 | |
| 
 | |
| 
 | |
| RgbaInputFile::~RgbaInputFile ()
 | |
| {
 | |
|     delete _inputFile;
 | |
|     delete _fromYca;
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| RgbaInputFile::setFrameBuffer (Rgba *base, size_t xStride, size_t yStride)
 | |
| {
 | |
|     if (_fromYca)
 | |
|     {
 | |
|     Lock lock (*_fromYca);
 | |
|     _fromYca->setFrameBuffer (base, xStride, yStride, _channelNamePrefix);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|     size_t xs = xStride * sizeof (Rgba);
 | |
|     size_t ys = yStride * sizeof (Rgba);
 | |
| 
 | |
|     FrameBuffer fb;
 | |
| 
 | |
|     fb.insert (_channelNamePrefix + "R",
 | |
|            Slice (HALF,
 | |
|               (char *) &base[0].r,
 | |
|               xs, ys,
 | |
|               1, 1,		// xSampling, ySampling
 | |
|               0.0));	// fillValue
 | |
| 
 | |
|     fb.insert (_channelNamePrefix + "G",
 | |
|            Slice (HALF,
 | |
|               (char *) &base[0].g,
 | |
|               xs, ys,
 | |
|               1, 1,		// xSampling, ySampling
 | |
|               0.0));	// fillValue
 | |
| 
 | |
|     fb.insert (_channelNamePrefix + "B",
 | |
|            Slice (HALF,
 | |
|               (char *) &base[0].b,
 | |
|               xs, ys,
 | |
|               1, 1,		// xSampling, ySampling
 | |
|               0.0));	// fillValue
 | |
| 
 | |
|     fb.insert (_channelNamePrefix + "A",
 | |
|            Slice (HALF,
 | |
|               (char *) &base[0].a,
 | |
|               xs, ys,
 | |
|               1, 1,		// xSampling, ySampling
 | |
|               1.0));	// fillValue
 | |
| 
 | |
|     _inputFile->setFrameBuffer (fb);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| RgbaInputFile::setLayerName (const string &layerName)
 | |
| {
 | |
|     delete _fromYca;
 | |
|     _fromYca = 0;
 | |
| 
 | |
|     _channelNamePrefix = prefixFromLayerName (layerName, _inputFile->header());
 | |
| 
 | |
|     RgbaChannels rgbaChannels = channels();
 | |
| 
 | |
|     if (rgbaChannels & (WRITE_Y | WRITE_C))
 | |
|     _fromYca = new FromYca (*_inputFile, rgbaChannels);
 | |
| 
 | |
|     FrameBuffer fb;
 | |
|     _inputFile->setFrameBuffer (fb);
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| RgbaInputFile::readPixels (int scanLine1, int scanLine2)
 | |
| {
 | |
|     if (_fromYca)
 | |
|     {
 | |
|     Lock lock (*_fromYca);
 | |
|     _fromYca->readPixels (scanLine1, scanLine2);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|     _inputFile->readPixels (scanLine1, scanLine2);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| RgbaInputFile::readPixels (int scanLine)
 | |
| {
 | |
|     readPixels (scanLine, scanLine);
 | |
| }
 | |
| 
 | |
| 
 | |
| bool
 | |
| RgbaInputFile::isComplete () const
 | |
| {
 | |
|     return _inputFile->isComplete();
 | |
| }
 | |
| 
 | |
| 
 | |
| const Header &
 | |
| RgbaInputFile::header () const
 | |
| {
 | |
|     return _inputFile->header();
 | |
| }
 | |
| 
 | |
| 
 | |
| const char *
 | |
| RgbaInputFile::fileName () const
 | |
| {
 | |
|     return _inputFile->fileName();
 | |
| }
 | |
| 
 | |
| 
 | |
| const FrameBuffer &
 | |
| RgbaInputFile::frameBuffer () const
 | |
| {
 | |
|     return _inputFile->frameBuffer();
 | |
| }
 | |
| 
 | |
| 
 | |
| const Imath::Box2i &
 | |
| RgbaInputFile::displayWindow () const
 | |
| {
 | |
|     return _inputFile->header().displayWindow();
 | |
| }
 | |
| 
 | |
| 
 | |
| const Imath::Box2i &
 | |
| RgbaInputFile::dataWindow () const
 | |
| {
 | |
|     return _inputFile->header().dataWindow();
 | |
| }
 | |
| 
 | |
| 
 | |
| float
 | |
| RgbaInputFile::pixelAspectRatio () const
 | |
| {
 | |
|     return _inputFile->header().pixelAspectRatio();
 | |
| }
 | |
| 
 | |
| 
 | |
| const Imath::V2f
 | |
| RgbaInputFile::screenWindowCenter () const
 | |
| {
 | |
|     return _inputFile->header().screenWindowCenter();
 | |
| }
 | |
| 
 | |
| 
 | |
| float
 | |
| RgbaInputFile::screenWindowWidth () const
 | |
| {
 | |
|     return _inputFile->header().screenWindowWidth();
 | |
| }
 | |
| 
 | |
| 
 | |
| LineOrder
 | |
| RgbaInputFile::lineOrder () const
 | |
| {
 | |
|     return _inputFile->header().lineOrder();
 | |
| }
 | |
| 
 | |
| 
 | |
| Compression
 | |
| RgbaInputFile::compression () const
 | |
| {
 | |
|     return _inputFile->header().compression();
 | |
| }
 | |
| 
 | |
| 
 | |
| RgbaChannels
 | |
| RgbaInputFile::channels () const
 | |
| {
 | |
|     return rgbaChannels (_inputFile->header().channels(), _channelNamePrefix);
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| RgbaInputFile::version () const
 | |
| {
 | |
|     return _inputFile->version();
 | |
| }
 | |
| 
 | |
| 
 | |
| } // namespace Imf
 | 
