📄 imfoutputfile.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 OutputFile////-----------------------------------------------------------------------------#include <ImfOutputFile.h>#include <ImfInputFile.h>#include <ImfChannelList.h>#include <ImfMisc.h>#include <ImfStdIO.h>#include <ImfCompressor.h>#include "ImathBox.h"#include "ImathFun.h"#include <ImfArray.h>#include <ImfXdr.h>#include <ImfPreviewImageAttribute.h>#include "IlmThreadPool.h"#include "IlmThreadSemaphore.h"#include "IlmThreadMutex.h"#include "Iex.h"#include <string>#include <vector>#include <fstream>#include <assert.h>namespace Imf {using Imath::Box2i;using Imath::divp;using Imath::modp;using std::string;using std::vector;using std::ofstream;using std::min;using std::max;using IlmThread::Mutex;using IlmThread::Lock;using IlmThread::Semaphore;using IlmThread::Task;using IlmThread::TaskGroup;using IlmThread::ThreadPool;namespace {struct OutSliceInfo{ PixelType type; const char * base; size_t xStride; size_t yStride; int xSampling; int ySampling; bool zero; OutSliceInfo (PixelType type = HALF, const char *base = 0, size_t xStride = 0, size_t yStride = 0, int xSampling = 1, int ySampling = 1, bool zero = false);};OutSliceInfo::OutSliceInfo (PixelType t, const char *b, size_t xs, size_t ys, int xsm, int ysm, bool z): type (t), base (b), xStride (xs), yStride (ys), xSampling (xsm), ySampling (ysm), zero (z){ // empty}struct LineBuffer{ Array<char> buffer; const char * dataPtr; int dataSize; char * endOfLineBufferData; int minY; int maxY; int scanLineMin; int scanLineMax; Compressor * compressor; bool partiallyFull; // has incomplete data bool hasException; string exception; LineBuffer (Compressor *comp); ~LineBuffer (); void wait () {_sem.wait();} void post () {_sem.post();} private: Semaphore _sem;};LineBuffer::LineBuffer (Compressor *comp) : dataPtr (0), dataSize (0), compressor (comp), partiallyFull (false), hasException (false), exception (), _sem (1){ // empty}LineBuffer::~LineBuffer (){ delete compressor;}} // namespacestruct OutputFile::Data: public Mutex{ Header header; // the image header int version; // file format version Int64 previewPosition; // file position for preview FrameBuffer frameBuffer; // framebuffer to write into int currentScanLine; // next scanline to be written int missingScanLines; // number of lines to write LineOrder lineOrder; // the file's lineorder int minX; // data window's min x coord int maxX; // data window's max x coord int minY; // data window's min y coord int maxY; // data window's max x coord vector<Int64> lineOffsets; // stores offsets in file for // each scanline vector<size_t> bytesPerLine; // combined size of a line over // all channels vector<size_t> offsetInLineBuffer; // offset for each scanline in // its linebuffer Compressor::Format format; // compressor's data format vector<OutSliceInfo> slices; // info about channels in file OStream * os; // file stream to write to bool deleteStream; Int64 lineOffsetsPosition; // file position for line // offset table Int64 currentPosition; // current file position vector<LineBuffer*> lineBuffers; // each holds one line buffer int linesInBuffer; // number of scanlines each // buffer holds size_t lineBufferSize; // size of the line buffer Data (bool deleteStream, int numThreads); ~Data (); inline LineBuffer * getLineBuffer (int number); // hash function from line // buffer indices into our // vector of line buffers};OutputFile::Data::Data (bool deleteStream, int numThreads): os (0), deleteStream (deleteStream), lineOffsetsPosition (0){ // // We need at least one lineBuffer, but if threading is used, // to keep n threads busy we need 2*n lineBuffers. // lineBuffers.resize (max (1, 2 * numThreads));}OutputFile::Data::~Data (){ if (deleteStream) delete os; for (size_t i = 0; i < lineBuffers.size(); i++) delete lineBuffers[i];}LineBuffer*OutputFile::Data::getLineBuffer (int number){ return lineBuffers[number % lineBuffers.size()];}namespace {Int64writeLineOffsets (OStream &os, const vector<Int64> &lineOffsets){ Int64 pos = os.tellp(); if (pos == -1) Iex::throwErrnoExc ("Cannot determine current file position (%T)."); for (unsigned int i = 0; i < lineOffsets.size(); i++) Xdr::write <StreamIO> (os, lineOffsets[i]); return pos;}voidwritePixelData (OutputFile::Data *ofd, int lineBufferMinY, const char pixelData[], int pixelDataSize){ // // Store a block of pixel data in the output file, and try // to keep track of the current writing position the file // without calling tellp() (tellp() can be fairly expensive). // Int64 currentPosition = ofd->currentPosition; ofd->currentPosition = 0; if (currentPosition == 0) currentPosition = ofd->os->tellp(); ofd->lineOffsets[(ofd->currentScanLine - ofd->minY) / ofd->linesInBuffer] = currentPosition; #ifdef DEBUG assert (ofd->os->tellp() == currentPosition); #endif Xdr::write <StreamIO> (*ofd->os, lineBufferMinY); Xdr::write <StreamIO> (*ofd->os, pixelDataSize); ofd->os->write (pixelData, pixelDataSize); ofd->currentPosition = currentPosition + Xdr::size<int>() + Xdr::size<int>() + pixelDataSize;}inline voidwritePixelData (OutputFile::Data *ofd, const LineBuffer *lineBuffer){ writePixelData (ofd, lineBuffer->minY, lineBuffer->dataPtr, lineBuffer->dataSize);}voidconvertToXdr (OutputFile::Data *ofd, Array<char> &lineBuffer, int lineBufferMinY, int lineBufferMaxY, int inSize){ // // Convert the contents of a lineBuffer from the machine's native // representation to Xdr format. This function is called by // CompressLineBuffer::execute(), below, if the compressor wanted // its input pixel data in the machine's native format, but then // failed to compress the data (most compressors will expand rather // than compress random input data). // // Note that this routine assumes that the machine's native // representation of the pixel data has the same size as the // Xdr representation. This makes it possible to convert the // pixel data in place, without an intermediate temporary buffer. // int startY, endY; // The first and last scanlines in // the file that are in the lineBuffer. int step; if (ofd->lineOrder == INCREASING_Y) { startY = max (lineBufferMinY, ofd->minY); endY = min (lineBufferMaxY, ofd->maxY) + 1; step = 1; } else { startY = min (lineBufferMaxY, ofd->maxY); endY = max (lineBufferMinY, ofd->minY) - 1; step = -1; } // // Iterate over all scanlines in the lineBuffer to convert. // for (int y = startY; y != endY; y += step) { // // Set these to point to the start of line y. // We will write to writePtr from readPtr. // char *writePtr = lineBuffer + ofd->offsetInLineBuffer[y - ofd->minY]; const char *readPtr = writePtr; // // Iterate over all slices in the file. // for (unsigned int i = 0; i < ofd->slices.size(); ++i) { // // Test if scan line y of this channel is // contains any data (the scan line contains // data only if y % ySampling == 0). // const OutSliceInfo &slice = ofd->slices[i]; if (modp (y, slice.ySampling) != 0) continue; // // Find the number of sampled pixels, dMaxX-dMinX+1, for // slice i in scan line y (i.e. pixels within the data window // for which x % xSampling == 0). // int dMinX = divp (ofd->minX, slice.xSampling); int dMaxX = divp (ofd->maxX, slice.xSampling); // // Convert the samples in place. // convertInPlace (writePtr, readPtr, slice.type, dMaxX - dMinX + 1); } }}//// A LineBufferTask encapsulates the task of copying a set of scanlines// from the user's frame buffer into a LineBuffer object, compressing// the data if necessary.//class LineBufferTask: public Task{ public: LineBufferTask (TaskGroup *group, OutputFile::Data *ofd, int number, int scanLineMin, int scanLineMax); virtual ~LineBufferTask (); virtual void execute (); private: OutputFile::Data * _ofd; LineBuffer * _lineBuffer;};LineBufferTask::LineBufferTask (TaskGroup *group, OutputFile::Data *ofd, int number, int scanLineMin, int scanLineMax): Task (group),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -