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

📄 imftiledoutputfile.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 TiledOutputFile
//
//-----------------------------------------------------------------------------

#include <ImfTiledOutputFile.h>
#include <ImfTiledInputFile.h>
#include <ImfInputFile.h>
#include <ImfTileDescriptionAttribute.h>
#include <ImfPreviewImageAttribute.h>
#include <ImfChannelList.h>
#include <ImfMisc.h>
#include <ImfTiledMisc.h>
#include <ImfStdIO.h>
#include <ImfCompressor.h>
#include "ImathBox.h"
#include <ImfArray.h>
#include <ImfXdr.h>
#include <ImfVersion.h>
#include <ImfTileOffsets.h>
#include <ImfThreading.h>
#include "IlmThreadPool.h"
#include "IlmThreadSemaphore.h"
#include "IlmThreadMutex.h"
#include "Iex.h"
#include <string>
#include <vector>
#include <fstream>
#include <assert.h>
#include <map>


namespace Imf {

using Imath::Box2i;
using Imath::V2i;
using std::string;
using std::vector;
using std::ofstream;
using std::map;
using std::min;
using std::max;
using std::swap;
using IlmThread::Mutex;
using IlmThread::Lock;
using IlmThread::Semaphore;
using IlmThread::Task;
using IlmThread::TaskGroup;
using IlmThread::ThreadPool;

namespace {

struct TOutSliceInfo
{
    PixelType		type;
    const char *	base;
    size_t		xStride;
    size_t		yStride;
    bool		zero;
    int                 xTileCoords;
    int                 yTileCoords;

    TOutSliceInfo (PixelType type = HALF,
	           const char *base = 0,
	           size_t xStride = 0,
	           size_t yStride = 0,
	           bool zero = false,
                   int xTileCoords = 0,
                   int yTileCoords = 0);
};


TOutSliceInfo::TOutSliceInfo (PixelType t,
		              const char *b,
			      size_t xs, size_t ys,
			      bool z,
                              int xtc,
                              int ytc)
:
    type (t),
    base (b),
    xStride (xs),
    yStride (ys),
    zero (z),
    xTileCoords (xtc),
    yTileCoords (ytc)
{
    // empty
}


struct TileCoord
{
    int		dx;
    int		dy;
    int		lx;
    int		ly;
    

    TileCoord (int xTile = 0, int yTile = 0,
	       int xLevel = 0, int yLevel = 0)
    :
        dx (xTile),  dy (yTile),
	lx (xLevel), ly (yLevel)
    {
        // empty
    }
    

    bool
    operator < (const TileCoord &other) const
    {
        return (ly < other.ly) ||
	       (ly == other.ly && lx < other.lx) ||
	       ((ly == other.ly && lx == other.lx) &&
		    ((dy < other.dy) || (dy == other.dy && dx < other.dx)));
    }


    bool
    operator == (const TileCoord &other) const
    {
        return lx == other.lx &&
	       ly == other.ly &&
	       dx == other.dx &&
	       dy == other.dy;
    }
};


struct BufferedTile
{
    char *	pixelData;
    int		pixelDataSize;

    BufferedTile (const char *data, int size):
	pixelData (0),
	pixelDataSize(size)
    {
	pixelData = new char[pixelDataSize];
	memcpy (pixelData, data, pixelDataSize);
    }

    ~BufferedTile()
    {
	delete [] pixelData;
    }
};


typedef map <TileCoord, BufferedTile *> TileMap;


struct TileBuffer
{
    Array<char>		buffer;
    const char *	dataPtr;
    int			dataSize;
    Compressor *	compressor;
    TileCoord		tileCoord;
    bool		hasException;
    string		exception;

     TileBuffer (Compressor *comp);
    ~TileBuffer ();

    inline void		wait () {_sem.wait();}
    inline void		post () {_sem.post();}

  protected:

    Semaphore		_sem;
};


TileBuffer::TileBuffer (Compressor *comp):
    dataPtr (0),
    dataSize (0),
    compressor (comp),
    hasException (false),
    exception (),
    _sem (1)
{
    // empty
}


TileBuffer::~TileBuffer ()
{
    delete compressor;
}


} // namespace


struct TiledOutputFile::Data: public Mutex
{
    Header		header;			// the image header
    int			version;		// file format version
    TileDescription	tileDesc;		// describes the tile layout
    FrameBuffer		frameBuffer;		// framebuffer to write into
    Int64		previewPosition;
    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

    int			numXLevels;		// number of x levels
    int			numYLevels;		// number of y levels
    int *		numXTiles;		// number of x tiles at a level
    int *		numYTiles;		// number of y tiles at a level

    TileOffsets		tileOffsets;		// stores offsets in file for
						// each tile

    Compressor::Format	format;			// compressor's data format
    vector<TOutSliceInfo> slices;		// info about channels in file
    OStream *		os;			// file stream to write to
    bool		deleteStream;

    size_t		maxBytesPerTileLine;	// combined size of a tile line
						// over all channels

    
    vector<TileBuffer*> tileBuffers;
    size_t		tileBufferSize;         // size of a tile buffer

    Int64		tileOffsetsPosition;	// position of the tile index
    Int64		currentPosition;	// current position in the file
    
    TileMap		tileMap;
    TileCoord		nextTileToWrite;

     Data (bool del, int numThreads);
    ~Data ();
    
    inline TileBuffer *	getTileBuffer (int number);
    						// hash function from tile
						// buffer coords into our
						// vector of tile buffers
    
    TileCoord		nextTileCoord (const TileCoord &a);
};


TiledOutputFile::Data::Data (bool del, int numThreads):
    numXTiles(0),
    numYTiles(0),
    os (0),
    deleteStream (del),
    tileOffsetsPosition (0)
{
    //
    // We need at least one tileBuffer, but if threading is used,
    // to keep n threads busy we need 2*n tileBuffers
    //

    tileBuffers.resize (max (1, 2 * numThreads));
}


TiledOutputFile::Data::~Data ()
{
    delete [] numXTiles;
    delete [] numYTiles;

    if (deleteStream)
	delete os;
    
    //
    // Delete all the tile buffers, if any still happen to exist
    //
    
    for (TileMap::iterator i = tileMap.begin(); i != tileMap.end(); ++i)
	delete i->second;

    for (size_t i = 0; i < tileBuffers.size(); i++)
        delete tileBuffers[i];
}


TileBuffer*
TiledOutputFile::Data::getTileBuffer (int number)
{
    return tileBuffers[number % tileBuffers.size()];
}


TileCoord
TiledOutputFile::Data::nextTileCoord (const TileCoord &a)
{
    TileCoord b = a;
    
    if (lineOrder == INCREASING_Y)
    {
        b.dx++;

        if (b.dx >= numXTiles[b.lx])
        {
            b.dx = 0;
            b.dy++;

            if (b.dy >= numYTiles[b.ly])
            {
		//
		// the next tile is in the next level
		//

                b.dy = 0;

                switch (tileDesc.mode)
                {
                  case ONE_LEVEL:
                  case MIPMAP_LEVELS:

                    b.lx++;
                    b.ly++;
                    break;

                  case RIPMAP_LEVELS:

                    b.lx++;

                    if (b.lx >= numXLevels)
                    {
                        b.lx = 0;
                        b.ly++;

			#ifdef DEBUG
			    assert (b.ly <= numYLevels);
			#endif
                    }
                    break;
                }
            }
        }
    }
    else if (lineOrder == DECREASING_Y)
    {
        b.dx++;

        if (b.dx >= numXTiles[b.lx])
        {
            b.dx = 0;
            b.dy--;

            if (b.dy < 0)
            {
		//
		// the next tile is in the next level
		//

                switch (tileDesc.mode)
                {
                  case ONE_LEVEL:
                  case MIPMAP_LEVELS:

                    b.lx++;
                    b.ly++;
                    break;

                  case RIPMAP_LEVELS:

                    b.lx++;

                    if (b.lx >= numXLevels)
                    {
                        b.lx = 0;
                        b.ly++;

			#ifdef DEBUG
			    assert (b.ly <= numYLevels);
			#endif
                    }
                    break;
                }

		if (b.ly < numYLevels)
		    b.dy = numYTiles[b.ly] - 1;
            }
        }
    }
    
    return b;   
}


namespace {

void
writeTileData (TiledOutputFile::Data *ofd,
               int dx, int dy,
	       int lx, int ly, 
               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->tileOffsets (dx, dy, lx, ly) = currentPosition;

    #ifdef DEBUG
	assert (ofd->os->tellp() == currentPosition);
    #endif

    //
    // Write the tile header.
    //

    Xdr::write <StreamIO> (*ofd->os, dx);
    Xdr::write <StreamIO> (*ofd->os, dy);
    Xdr::write <StreamIO> (*ofd->os, lx);
    Xdr::write <StreamIO> (*ofd->os, ly);
    Xdr::write <StreamIO> (*ofd->os, pixelDataSize);

    ofd->os->write (pixelData, pixelDataSize);    

    //
    // Keep current position in the file so that we can avoid 
    // redundant seekg() operations (seekg() can be fairly expensive).
    //

    ofd->currentPosition = currentPosition +
                           5 * Xdr::size<int>() +
                           pixelDataSize;
}



void
bufferedTileWrite (TiledOutputFile::Data *ofd,
                   int dx, int dy,
		   int lx, int ly, 
                   const char pixelData[],
                   int pixelDataSize)
{
    //
    // Check if a tile with coordinates (dx,dy,lx,ly) has already been written.
    //

    if (ofd->tileOffsets (dx, dy, lx, ly))
    {
	THROW (Iex::ArgExc,
	       "Attempt to write tile "
	       "(" << dx << ", " << dy << ", " << lx << "," << ly << ") "
	       "more than once.");
    }

    //
    // If tiles can be written in random order, then don't buffer anything.
    //
    
    if (ofd->lineOrder == RANDOM_Y)
    {
        writeTileData (ofd, dx, dy, lx, ly, pixelData, pixelDataSize);
        return;
    }
    
    //
    // If the tiles cannot be written in random order, then check if a
    // tile with coordinates (dx,dy,lx,ly) has already been buffered.
    //

    TileCoord currentTile = TileCoord(dx, dy, lx, ly);

    if (ofd->tileMap.find (currentTile) != ofd->tileMap.end())
    {
	THROW (Iex::ArgExc,
	       "Attempt to write tile "
	       "(" << dx << ", " << dy << ", " << lx << "," << ly << ") "
	       "more than once.");
    }

    //
    // If all the tiles before this one have already been written to the file,
    // then write this tile immediately and check if we have buffered tiles
    // that can be written after this tile.
    //
    // Otherwise, buffer the tile so it can be written to file later.
    //
    
    if (ofd->nextTileToWrite == currentTile)
    {
        writeTileData (ofd, dx, dy, lx, ly, pixelData, pixelDataSize);        
        ofd->nextTileToWrite = ofd->nextTileCoord (ofd->nextTileToWrite);

        TileMap::iterator i = ofd->tileMap.find (ofd->nextTileToWrite);
        
        //
        // Step through the tiles and write all successive buffered tiles after
        // the current one.
        //
        
        while(i != ofd->tileMap.end())
        {
            //
            // Write the tile, and then delete the tile's buffered data
            //

            writeTileData (ofd,
			   i->first.dx, i->first.dy,
			   i->first.lx, i->first.ly,
			   i->second->pixelData,
			   i->second->pixelDataSize);

            delete i->second;
            ofd->tileMap.erase (i);
            
            //
            // Proceed to the next tile
            //
            
            ofd->nextTileToWrite = ofd->nextTileCoord (ofd->nextTileToWrite);
            i = ofd->tileMap.find (ofd->nextTileToWrite);
        }
    }
    else
    {
        //

⌨️ 快捷键说明

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