📄 imftiledoutputfile.cpp
字号:
// Create a new BufferedTile, copy the pixelData into it, and // insert it into the tileMap. // ofd->tileMap[currentTile] = new BufferedTile ((const char *)pixelData, pixelDataSize); }}voidconvertToXdr (TiledOutputFile::Data *ofd, Array<char>& tileBuffer, int numScanLines, int numPixelsPerScanLine){ // // Convert the contents of a TiledOutputFile's tileBuffer from the // machine's native representation to Xdr format. This function is called // by writeTile(), 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. // // // Set these to point to the start of the tile. // We will write to toPtr, and read from fromPtr. // char *writePtr = tileBuffer; const char *readPtr = writePtr; // // Iterate over all scan lines in the tile. // for (int y = 0; y < numScanLines; ++y) { // // Iterate over all slices in the file. // for (unsigned int i = 0; i < ofd->slices.size(); ++i) { const TOutSliceInfo &slice = ofd->slices[i]; // // Convert the samples in place. // convertInPlace (writePtr, readPtr, slice.type, numPixelsPerScanLine); } } #ifdef DEBUG assert (writePtr == readPtr); #endif}//// A TileBufferTask encapsulates the task of copying a tile from// the user's framebuffer into a LineBuffer and compressing the data// if necessary.//class TileBufferTask: public Task{ public: TileBufferTask (TaskGroup *group, TiledOutputFile::Data *ofd, int number, int dx, int dy, int lx, int ly); virtual ~TileBufferTask (); virtual void execute (); private: TiledOutputFile::Data * _ofd; TileBuffer * _tileBuffer;};TileBufferTask::TileBufferTask (TaskGroup *group, TiledOutputFile::Data *ofd, int number, int dx, int dy, int lx, int ly): Task (group), _ofd (ofd), _tileBuffer (_ofd->getTileBuffer (number)){ // // Wait for the tileBuffer to become available // _tileBuffer->wait (); _tileBuffer->tileCoord = TileCoord (dx, dy, lx, ly);}TileBufferTask::~TileBufferTask (){ // // Signal that the tile buffer is now free // _tileBuffer->post ();}voidTileBufferTask::execute (){ try { // // First copy the pixel data from the frame buffer // into the tile buffer // // Convert one tile's worth of pixel data to // a machine-independent representation, and store // the result in _tileBuffer->buffer. // char *writePtr = _tileBuffer->buffer; Box2i tileRange = Imf::dataWindowForTile (_ofd->tileDesc, _ofd->minX, _ofd->maxX, _ofd->minY, _ofd->maxY, _tileBuffer->tileCoord.dx, _tileBuffer->tileCoord.dy, _tileBuffer->tileCoord.lx, _tileBuffer->tileCoord.ly); int numScanLines = tileRange.max.y - tileRange.min.y + 1; int numPixelsPerScanLine = tileRange.max.x - tileRange.min.x + 1; // // Iterate over the scan lines in the tile. // for (int y = tileRange.min.y; y <= tileRange.max.y; ++y) { // // Iterate over all image channels. // for (unsigned int i = 0; i < _ofd->slices.size(); ++i) { const TOutSliceInfo &slice = _ofd->slices[i]; // // These offsets are used to facilitate both absolute // and tile-relative pixel coordinates. // int xOffset = slice.xTileCoords * tileRange.min.x; int yOffset = slice.yTileCoords * tileRange.min.y; // // Fill the tile buffer with pixel data. // if (slice.zero) { // // The frame buffer contains no data for this channel. // Store zeroes in _data->tileBuffer. // fillChannelWithZeroes (writePtr, _ofd->format, slice.type, numPixelsPerScanLine); } else { // // The frame buffer contains data for this channel. // const char *readPtr = slice.base + (y - yOffset) * slice.yStride + (tileRange.min.x - xOffset) * slice.xStride; const char *endPtr = readPtr + (numPixelsPerScanLine - 1) * slice.xStride; copyFromFrameBuffer (writePtr, readPtr, endPtr, slice.xStride, _ofd->format, slice.type); } } } // // Compress the contents of the tileBuffer, // and store the compressed data in the output file. // _tileBuffer->dataSize = writePtr - _tileBuffer->buffer; _tileBuffer->dataPtr = _tileBuffer->buffer; if (_tileBuffer->compressor) { const char *compPtr; int compSize = _tileBuffer->compressor->compressTile (_tileBuffer->dataPtr, _tileBuffer->dataSize, tileRange, compPtr); if (compSize < _tileBuffer->dataSize) { _tileBuffer->dataSize = compSize; _tileBuffer->dataPtr = compPtr; } else if (_ofd->format == Compressor::NATIVE) { // // The data did not shrink during compression, but // we cannot write to the file using native format, // so we need to convert the lineBuffer to Xdr. // convertToXdr (_ofd, _tileBuffer->buffer, numScanLines, numPixelsPerScanLine); } } } catch (std::exception &e) { if (!_tileBuffer->hasException) { _tileBuffer->exception = e.what (); _tileBuffer->hasException = true; } } catch (...) { if (!_tileBuffer->hasException) { _tileBuffer->exception = "unrecognized exception"; _tileBuffer->hasException = true; } }}} // namespaceTiledOutputFile::TiledOutputFile (const char fileName[], const Header &header, int numThreads): _data (new Data (true, numThreads)){ try { header.sanityCheck (true); _data->os = new StdOFStream (fileName); initialize (header); } catch (Iex::BaseExc &e) { delete _data; REPLACE_EXC (e, "Cannot open image file " "\"" << fileName << "\". " << e); throw; } catch (...) { delete _data; throw; }}TiledOutputFile::TiledOutputFile (OStream &os, const Header &header, int numThreads): _data (new Data (false, numThreads)){ try { header.sanityCheck(true); _data->os = &os; initialize (header); } catch (Iex::BaseExc &e) { delete _data; REPLACE_EXC (e, "Cannot open image file " "\"" << os.fileName() << "\". " << e); throw; } catch (...) { delete _data; throw; }}voidTiledOutputFile::initialize (const Header &header){ _data->header = header; _data->lineOrder = _data->header.lineOrder(); // // Check that the file is indeed tiled // _data->tileDesc = _data->header.tileDescription(); // // Save the dataWindow information // const Box2i &dataWindow = _data->header.dataWindow(); _data->minX = dataWindow.min.x; _data->maxX = dataWindow.max.x; _data->minY = dataWindow.min.y; _data->maxY = dataWindow.max.y; // // Precompute level and tile information to speed up utility functions // precalculateTileInfo (_data->tileDesc, _data->minX, _data->maxX, _data->minY, _data->maxY, _data->numXTiles, _data->numYTiles, _data->numXLevels, _data->numYLevels); // // Determine the first tile coordinate that we will be writing // if the file is not RANDOM_Y. // _data->nextTileToWrite = (_data->lineOrder == INCREASING_Y)? TileCoord (0, 0, 0, 0): TileCoord (0, _data->numYTiles[0] - 1, 0, 0); _data->maxBytesPerTileLine = calculateBytesPerPixel (_data->header) * _data->tileDesc.xSize; _data->tileBufferSize = _data->maxBytesPerTileLine * _data->tileDesc.ySize; // // Create all the TileBuffers and allocate their internal buffers // for (size_t i = 0; i < _data->tileBuffers.size(); i++) { _data->tileBuffers[i] = new TileBuffer (newTileCompressor (_data->header.compression(), _data->maxBytesPerTileLine, _data->tileDesc.ySize, _data->header)); _data->tileBuffers[i]->buffer.resizeErase(_data->tileBufferSize); } _data->format = defaultFormat (_data->tileBuffers[0]->compressor); _data->tileOffsets = TileOffsets (_data->tileDesc.mode, _data->numXLevels, _data->numYLevels, _data->numXTiles, _data->numYTiles); _data->previewPosition = _data->header.writeTo (*_data->os, true); _data->tileOffsetsPosition = _data->tileOffsets.writeTo (*_data->os); _data->currentPosition = _data->os->tellp();}TiledOutputFile::~TiledOutputFile (){ if (_data) { { if (_data->tileOffsetsPosition > 0) { try { _data->os->seekp (_data->tileOffsetsPosition); _data->tileOffsets.writeTo (*_data->os); } catch (...) { // // We cannot safely throw any exceptions from here. // This destructor may have been called because the // stack is currently being unwound for another // exception. // } } } delete _data; }}const char *TiledOutputFile::fileName () const{ return _data->os->fileName();}const Header &TiledOutputFile::header () const{ return _data->header;}void TiledOutputFile::setFrameBuffer (const FrameBuffer &frameBuffer){ Lock lock (*_data); // // Check if the new frame buffer descriptor // is compatible with the image file header. // const ChannelList &channels = _data->header.channels(); for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) { FrameBuffer::ConstIterator j = frameBuffer.find (i.name()); if (j == frameBuffer.end()) continue; if (i.channel().type != j.slice().type) THROW (Iex::ArgExc, "Pixel type of \"" << i.name() << "\" channel " "of output file \"" << fileName() << "\" is " "not compatible with the frame buffer's " "pixel type."); if (j.slice().xSampling != 1 || j.slice().ySampling != 1) THROW (Iex::ArgExc, "All channels in a tiled file must have" "sampling (1,1)."); } // // Initialize slice table for writePixels(). // vector<TOutSliceInfo> slices; for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) { FrameBuffer::ConstIterator j = frameBuffer.find (i.name()); if (j == frameBuffer.end()) { // // Channel i is not present in the frame buffer. // In the file, channel i will contain only zeroes. // slices.push_back (TOutSliceInfo (i.channel().type, 0, // base 0, // xStride, 0, // yStride, true)); // zero } else { // // Channel i is present in the frame buffer. // slices.push_back (TOutSliceInfo (j.slice().type, j.slice().base, j.slice().xStride, j.slice().yStride, false, // zero (j.slice().xTileCoords)? 1: 0, (j.slice().yTileCoords)? 1: 0)); } } // // Store the new frame buffer. // _data->frameBuffer = frameBuffer; _data->slices = slices;}const FrameBuffer &TiledOutputFile::frameBuffer () const{ Lock lock (*_data); return _data->frameBuffer;}void TiledOutputFile::writeTiles (int dx1, int dx2, int dy1, int dy2, int lx, int ly){ try { Lock lock (*_data); if (_data->slices.size() == 0) throw Iex::ArgExc ("No frame buffer specified " "as pixel data source."); if (!isValidTile (dx1, dy1, lx, ly) || !isValidTile (dx2, dy2, lx, ly)) throw Iex::ArgExc ("Tile coordinates are invalid."); // // Determine the first and last tile coordinates in both dimensions // based on the file's lineOrder // if (dx1 > dx2) swap (dx1, dx2); if (dy1 > dy2) swap (dy1, dy2); int dyStart = dy1; int dyStop = dy2 + 1; int dY = 1; if (_data->lineOrder == DECREASING_Y) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -