📄 imfrgbafile.cpp
字号:
/////////////////////////////////////////////////////////////////////////////// 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 {voidinsertChannels (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;}RgbaChannelsrgbaChannels (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);}V3fywFromHeader (const Header &header){ Chromaticities cr; if (hasChromaticities (header)) cr = chromaticities (header); return computeYw (cr);}} // namespaceclass 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;}voidRgbaOutputFile::ToYca::setYCRounding (unsigned int roundY, unsigned int roundC){ _roundY = roundY; _roundC = roundC;}voidRgbaOutputFile::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;}voidRgbaOutputFile::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; } }}intRgbaOutputFile::ToYca::currentScanLine () const{ return _currentScanLine;}voidRgbaOutputFile::ToYca::padTmpBuf (){ for (int i = 0; i < N2; ++i) { _tmpBuf[i] = _tmpBuf[N2]; _tmpBuf[_width + N2 + i] = _tmpBuf[_width + N2 - 2]; }}voidRgbaOutputFile::ToYca::rotateBuffers (){ Rgba *tmp = _buf[0]; for (int i = 0; i < N - 1; ++i) _buf[i] = _buf[i + 1]; _buf[N - 1] = tmp;}voidRgbaOutputFile::ToYca::duplicateLastBuffer (){ rotateBuffers(); memcpy (_buf[N - 1], _buf[N - 2], _width * sizeof (Rgba));}voidRgbaOutputFile::ToYca::duplicateSecondToLastBuffer (){ rotateBuffers(); memcpy (_buf[N - 1], _buf[N - 3], _width * sizeof (Rgba));}voidRgbaOutputFile::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;}voidRgbaOutputFile::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 + -