📄 imftiledinputfile.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 TiledInputFile
//
//-----------------------------------------------------------------------------
#include <ImfTiledInputFile.h>
#include <ImfTileDescriptionAttribute.h>
#include <ImfChannelList.h>
#include <ImfMisc.h>
#include <ImfTiledMisc.h>
#include <ImfStdIO.h>
#include <ImfCompressor.h>
#include "ImathBox.h"
#include <ImfXdr.h>
#include <ImfConvert.h>
#include <ImfVersion.h>
#include <ImfTileOffsets.h>
#include <ImfThreading.h>
#include "IlmThreadPool.h"
#include "IlmThreadSemaphore.h"
#include "IlmThreadMutex.h"
#include "ImathVec.h"
#include "Iex.h"
#include <string>
#include <vector>
#include <algorithm>
#include <assert.h>
namespace Imf {
using Imath::Box2i;
using Imath::V2i;
using std::string;
using std::vector;
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 TInSliceInfo
{
PixelType typeInFrameBuffer;
PixelType typeInFile;
char * base;
size_t xStride;
size_t yStride;
bool fill;
bool skip;
double fillValue;
int xTileCoords;
int yTileCoords;
TInSliceInfo (PixelType typeInFrameBuffer = HALF,
PixelType typeInFile = HALF,
char *base = 0,
size_t xStride = 0,
size_t yStride = 0,
bool fill = false,
bool skip = false,
double fillValue = 0.0,
int xTileCoords = 0,
int yTileCoords = 0);
};
TInSliceInfo::TInSliceInfo (PixelType tifb,
PixelType tifl,
char *b,
size_t xs, size_t ys,
bool f, bool s,
double fv,
int xtc,
int ytc)
:
typeInFrameBuffer (tifb),
typeInFile (tifl),
base (b),
xStride (xs),
yStride (ys),
fill (f),
skip (s),
fillValue (fv),
xTileCoords (xtc),
yTileCoords (ytc)
{
// empty
}
struct TileBuffer
{
const char * uncompressedData;
char * buffer;
int dataSize;
Compressor * compressor;
Compressor::Format format;
int dx;
int dy;
int lx;
int ly;
bool hasException;
string exception;
TileBuffer (Compressor * const comp);
~TileBuffer ();
inline void wait () {_sem.wait();}
inline void post () {_sem.post();}
protected:
Semaphore _sem;
};
TileBuffer::TileBuffer (Compressor *comp):
uncompressedData (0),
dataSize (0),
compressor (comp),
format (defaultFormat (compressor)),
dx (-1),
dy (-1),
lx (-1),
ly (-1),
hasException (false),
exception (),
_sem (1)
{
// empty
}
TileBuffer::~TileBuffer ()
{
delete compressor;
}
} // namespace
//
// struct TiledInputFile::Data stores things that will be
// needed between calls to readTile()
//
struct TiledInputFile::Data: public Mutex
{
Header header; // the image header
TileDescription tileDesc; // describes the tile layout
int version; // file's version
FrameBuffer frameBuffer; // framebuffer to write into
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
bool fileIsComplete; // True if no tiles are missing
// in the file
Int64 currentPosition; // file offset for current tile,
// used to prevent unnecessary
// seeking
vector<TInSliceInfo> slices; // info about channels in file
IStream * is; // file stream to read from
bool deleteStream; // should we delete the stream
// ourselves? or does someone
// else do it?
size_t bytesPerPixel; // size of an uncompressed pixel
size_t maxBytesPerTileLine; // combined size of a line
// over all channels
vector<TileBuffer*> tileBuffers; // each holds a single tile
size_t tileBufferSize; // size of the tile buffers
Data (bool deleteStream, int numThreads);
~Data ();
inline TileBuffer * getTileBuffer (int number);
// hash function from tile indices
// into our vector of tile buffers
};
TiledInputFile::Data::Data (bool del, int numThreads):
numXTiles (0),
numYTiles (0),
is (0),
deleteStream (del)
{
//
// 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));
}
TiledInputFile::Data::~Data ()
{
delete [] numXTiles;
delete [] numYTiles;
if (deleteStream)
delete is;
for (size_t i = 0; i < tileBuffers.size(); i++)
delete tileBuffers[i];
}
TileBuffer*
TiledInputFile::Data::getTileBuffer (int number)
{
return tileBuffers[number % tileBuffers.size()];
}
namespace {
void
readTileData (TiledInputFile::Data *ifd,
int dx, int dy,
int lx, int ly,
char *&buffer,
int &dataSize)
{
//
// Read a single tile block from the file and into the array pointed
// to by buffer. If the file is memory-mapped, then we change where
// buffer points instead of writing into the array (hence buffer needs
// to be a reference to a char *).
//
//
// Look up the location for this tile in the Index and
// seek to that position if necessary
//
Int64 tileOffset = ifd->tileOffsets (dx, dy, lx, ly);
if (tileOffset == 0)
{
THROW (Iex::InputExc, "Tile (" << dx << ", " << dy << ", " <<
lx << ", " << ly << ") is missing.");
}
if (ifd->currentPosition != tileOffset)
ifd->is->seekg (tileOffset);
//
// Read the first few bytes of the tile (the header).
// Verify that the tile coordinates and the level number
// are correct.
//
int tileXCoord, tileYCoord, levelX, levelY;
Xdr::read <StreamIO> (*ifd->is, tileXCoord);
Xdr::read <StreamIO> (*ifd->is, tileYCoord);
Xdr::read <StreamIO> (*ifd->is, levelX);
Xdr::read <StreamIO> (*ifd->is, levelY);
Xdr::read <StreamIO> (*ifd->is, dataSize);
if (tileXCoord != dx)
throw Iex::InputExc ("Unexpected tile x coordinate.");
if (tileYCoord != dy)
throw Iex::InputExc ("Unexpected tile y coordinate.");
if (levelX != lx)
throw Iex::InputExc ("Unexpected tile x level number coordinate.");
if (levelY != ly)
throw Iex::InputExc ("Unexpected tile y level number coordinate.");
if (dataSize > (int) ifd->tileBufferSize)
throw Iex::InputExc ("Unexpected tile 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 tile is the next one in
// the file, so that we can avoid redundant seekg()
// operations (seekg() can be fairly expensive).
//
ifd->currentPosition = tileOffset + 5 * Xdr::size<int>() + dataSize;
}
void
readNextTileData (TiledInputFile::Data *ifd,
int &dx, int &dy,
int &lx, int &ly,
char * & buffer,
int &dataSize)
{
//
// Read the next tile block from the file
//
//
// Read the first few bytes of the tile (the header).
//
Xdr::read <StreamIO> (*ifd->is, dx);
Xdr::read <StreamIO> (*ifd->is, dy);
Xdr::read <StreamIO> (*ifd->is, lx);
Xdr::read <StreamIO> (*ifd->is, ly);
Xdr::read <StreamIO> (*ifd->is, dataSize);
if (dataSize > (int) ifd->tileBufferSize)
throw Iex::InputExc ("Unexpected tile block length.");
//
// Read the pixel data.
//
ifd->is->read (buffer, dataSize);
//
// Keep track of which tile is the next one in
// the file, so that we can avoid redundant seekg()
// operations (seekg() can be fairly expensive).
//
ifd->currentPosition += 5 * Xdr::size<int>() + dataSize;
}
//
// A TileBufferTask encapsulates the task of uncompressing
// a single tile and copying it into the frame buffer.
//
class TileBufferTask : public Task
{
public:
TileBufferTask (TaskGroup *group,
TiledInputFile::Data *ifd,
TileBuffer *tileBuffer);
virtual ~TileBufferTask ();
virtual void execute ();
private:
TiledInputFile::Data * _ifd;
TileBuffer * _tileBuffer;
};
TileBufferTask::TileBufferTask
(TaskGroup *group,
TiledInputFile::Data *ifd,
TileBuffer *tileBuffer)
:
Task (group),
_ifd (ifd),
_tileBuffer (tileBuffer)
{
// empty
}
TileBufferTask::~TileBufferTask ()
{
//
// Signal that the tile buffer is now free
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -