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

📄 imfoutputfile.cpp

📁 对gif
💻 CPP
📖 第 1 页 / 共 3 页
字号:
///////////////////////////////////////////////////////////////////////////
//
// 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;
}

} // namespace


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


Int64
writeLineOffsets (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;
}


void
writePixelData (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 void
writePixelData (OutputFile::Data *ofd, const LineBuffer *lineBuffer)
{
    writePixelData (ofd,
		    lineBuffer->minY,
                    lineBuffer->dataPtr,
		    lineBuffer->dataSize);
}


void
convertToXdr (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 + -