📄 imftiledoutputfile.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 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;}} // namespacestruct 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()];}TileCoordTiledOutputFile::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 {voidwriteTileData (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;}voidbufferedTileWrite (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 + -