📄 imfscanlineinputfile.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 ScanLineInputFile////-----------------------------------------------------------------------------#include <ImfScanLineInputFile.h>#include <ImfChannelList.h>#include <ImfMisc.h>#include <ImfStdIO.h>#include <ImfCompressor.h>#include "ImathBox.h"#include "ImathFun.h"#include <ImfXdr.h>#include <ImfConvert.h>#include <ImfThreading.h>#include "IlmThreadPool.h"#include "IlmThreadSemaphore.h"#include "IlmThreadMutex.h"#include "Iex.h"#include <string>#include <vector>#include <assert.h>namespace Imf {using Imath::Box2i;using Imath::divp;using Imath::modp;using std::string;using std::vector;using std::ifstream;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 InSliceInfo{ PixelType typeInFrameBuffer; PixelType typeInFile; char * base; size_t xStride; size_t yStride; int xSampling; int ySampling; bool fill; bool skip; double fillValue; InSliceInfo (PixelType typeInFrameBuffer = HALF, PixelType typeInFile = HALF, char *base = 0, size_t xStride = 0, size_t yStride = 0, int xSampling = 1, int ySampling = 1, bool fill = false, bool skip = false, double fillValue = 0.0);};InSliceInfo::InSliceInfo (PixelType tifb, PixelType tifl, char *b, size_t xs, size_t ys, int xsm, int ysm, bool f, bool s, double fv): typeInFrameBuffer (tifb), typeInFile (tifl), base (b), xStride (xs), yStride (ys), xSampling (xsm), ySampling (ysm), fill (f), skip (s), fillValue (fv){ // empty}struct LineBuffer{ const char * uncompressedData; char * buffer; int dataSize; int minY; int maxY; Compressor * compressor; Compressor::Format format; int number; bool hasException; string exception; LineBuffer (Compressor * const comp); ~LineBuffer (); inline void wait () {_sem.wait();} inline void post () {_sem.post();} private: Semaphore _sem;};LineBuffer::LineBuffer (Compressor *comp): uncompressedData (0), buffer (0), dataSize (0), compressor (comp), format (defaultFormat(compressor)), number (-1), hasException (false), exception (), _sem (1){ // empty}LineBuffer::~LineBuffer (){ delete compressor;}} // namespacestruct ScanLineInputFile::Data: public Mutex{ Header header; // the image header int version; // file's version FrameBuffer frameBuffer; // framebuffer to write into LineOrder lineOrder; // order of the scanlines in file 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 line bool fileIsComplete; // True if no scanlines are missing // in the file int nextLineBufferMinY; // minimum y of the next linebuffer vector<size_t> bytesPerLine; // combined size of a line over all // channels vector<size_t> offsetInLineBuffer; // offset for each scanline in its // linebuffer vector<InSliceInfo> slices; // info about channels in file IStream * is; // file stream to read from 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 (IStream *is, int numThreads); ~Data (); inline LineBuffer * getLineBuffer (int number); // hash function from line // buffer indices into our // vector of line buffers};ScanLineInputFile::Data::Data (IStream *is, int numThreads): is (is){ // // 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));}ScanLineInputFile::Data::~Data (){ for (size_t i = 0; i < lineBuffers.size(); i++) delete lineBuffers[i];}inline LineBuffer *ScanLineInputFile::Data::getLineBuffer (int lineBufferNumber){ return lineBuffers[lineBufferNumber % lineBuffers.size()];}namespace {voidreconstructLineOffsets (IStream &is, LineOrder lineOrder, vector<Int64> &lineOffsets){ Int64 position = is.tellg(); try { for (unsigned int i = 0; i < lineOffsets.size(); i++) { Int64 lineOffset = is.tellg(); int y; Xdr::read <StreamIO> (is, y); int dataSize; Xdr::read <StreamIO> (is, dataSize); Xdr::skip <StreamIO> (is, dataSize); if (lineOrder == INCREASING_Y) lineOffsets[i] = lineOffset; else lineOffsets[lineOffsets.size() - i - 1] = lineOffset; } } catch (...) { // // Suppress all exceptions. This functions is // called only to reconstruct the line offset // table for incomplete files, and exceptions // are likely. // } is.clear(); is.seekg (position);}voidreadLineOffsets (IStream &is, LineOrder lineOrder, vector<Int64> &lineOffsets, bool &complete){ for (unsigned int i = 0; i < lineOffsets.size(); i++) { Xdr::read <StreamIO> (is, lineOffsets[i]); } complete = true; for (unsigned int i = 0; i < lineOffsets.size(); i++) { if (lineOffsets[i] <= 0) { // // Invalid data in the line offset table mean that // the file is probably incomplete (the table is // the last thing written to the file). Either // some process is still busy writing the file, // or writing the file was aborted. // // We should still be able to read the existing // parts of the file. In order to do this, we // have to make a sequential scan over the scan // line data to reconstruct the line offset table. // complete = false; reconstructLineOffsets (is, lineOrder, lineOffsets); break; } }}voidreadPixelData (ScanLineInputFile::Data *ifd, int minY, char *&buffer, int &dataSize){ // // Read a single line buffer from the input file. // // If the input file is not memory-mapped, we copy the pixel data into // into the array pointed to by buffer. If the file is memory-mapped, // then we change where buffer points to instead of writing into the // array (hence buffer needs to be a reference to a char *). // Int64 lineOffset = ifd->lineOffsets[(minY - ifd->minY) / ifd->linesInBuffer]; if (lineOffset == 0) THROW (Iex::InputExc, "Scan line " << minY << " is missing."); // // Seek to the start of the scan line in the file, // if necessary. // if (ifd->nextLineBufferMinY != minY) ifd->is->seekg (lineOffset); // // Read the data block's header. // int yInFile; Xdr::read <StreamIO> (*ifd->is, yInFile); Xdr::read <StreamIO> (*ifd->is, dataSize); if (yInFile != minY) throw Iex::InputExc ("Unexpected data block y coordinate."); if (dataSize > (int) ifd->lineBufferSize) throw Iex::InputExc ("Unexpected data block length."); // // Read the pixel data. // if (ifd->is->isMemoryMapped ()) buffer = ifd->is->readMemoryMapped (dataSize); else ifd->is->read (buffer, dataSize); // // Keep track of which scan line is the next one in // the file, so that we can avoid redundant seekg() // operations (seekg() can be fairly expensive). // if (ifd->lineOrder == INCREASING_Y) ifd->nextLineBufferMinY = minY + ifd->linesInBuffer; else ifd->nextLineBufferMinY = minY - ifd->linesInBuffer;}//// A LineBufferTask encapsulates the task uncompressing a set of// scanlines (line buffer) and copying them into the frame buffer.//class LineBufferTask : public Task{ public: LineBufferTask (TaskGroup *group, ScanLineInputFile::Data *ifd, LineBuffer *lineBuffer, int scanLineMin, int scanLineMax); virtual ~LineBufferTask (); virtual void execute (); private: ScanLineInputFile::Data * _ifd; LineBuffer * _lineBuffer; int _scanLineMin; int _scanLineMax;};LineBufferTask::LineBufferTask (TaskGroup *group, ScanLineInputFile::Data *ifd, LineBuffer *lineBuffer, int scanLineMin, int scanLineMax): Task (group), _ifd (ifd), _lineBuffer (lineBuffer), _scanLineMin (scanLineMin), _scanLineMax (scanLineMax){ // empty}LineBufferTask::~LineBufferTask (){ // // Signal that the line buffer is now free // _lineBuffer->post ();}voidLineBufferTask::execute (){ try { // // Uncompress the data, if necessary // if (_lineBuffer->uncompressedData == 0) { int uncompressedSize = 0; int maxY = min (_lineBuffer->maxY, _ifd->maxY); for (int i = _lineBuffer->minY - _ifd->minY; i <= maxY - _ifd->minY; ++i) { uncompressedSize += (int) _ifd->bytesPerLine[i]; } if (_lineBuffer->compressor && _lineBuffer->dataSize < uncompressedSize) { _lineBuffer->format = _lineBuffer->compressor->format(); _lineBuffer->dataSize = _lineBuffer->compressor->uncompress (_lineBuffer->buffer, _lineBuffer->dataSize, _lineBuffer->minY, _lineBuffer->uncompressedData); } else { // // If the line is uncompressed, it's in XDR format, // regardless of the compressor's output format. // _lineBuffer->format = Compressor::XDR; _lineBuffer->uncompressedData = _lineBuffer->buffer; } } int yStart, yStop, dy; if (_ifd->lineOrder == INCREASING_Y) { yStart = _scanLineMin; yStop = _scanLineMax + 1; dy = 1; } else { yStart = _scanLineMax; yStop = _scanLineMin - 1; dy = -1; } for (int y = yStart; y != yStop; y += dy) { // // Convert one scan line's worth of pixel data back // from the machine-independent representation, and // store the result in the frame buffer.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -