⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 imfrgbafile.cpp

📁 对gif
💻 CPP
📖 第 1 页 / 共 2 页
字号:
///////////////////////////////////////////////////////////////////////////
//
// 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)
{
    int i = 0;

    if (ch.findChannel ("R"))
	i |= WRITE_R;

    if (ch.findChannel ("G"))
	i |= WRITE_G;
    
    if (ch.findChannel ("B"))
	i |= WRITE_B;

    if (ch.findChannel ("A"))
	i |= WRITE_A;

    if (ch.findChannel ("Y"))
	i |= WRITE_Y;

    if (ch.findChannel ("RY") || ch.findChannel ("BY"))
	i |= WRITE_C;

    return RgbaChannels (i);
}


V3f
ywFromHeader (const Header &header)
{
    Chromaticities cr;

    if (hasChromaticities (header))
	cr = chromaticities (header);

    return computeYw (cr);
}

} // 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 *		_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());

    for (int i = 0; i < N; ++i)
	_buf[i] = new Rgba[_width];

    _tmpBuf = new Rgba[_width + N - 1];

    _fbBase = 0;
    _fbXStride = 0;
    _fbYStride = 0;

    _roundY = 7;
    _roundC = 5;
}


RgbaOutputFile::ToYca::~ToYca ()
{
    for (int i = 0; i < N; ++i)
	delete [] _buf[i];

    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)
    {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -