📄 imfoutputfile.cpp
字号:
//
slices.push_back (OutSliceInfo (i.channel().type,
0, // base
0, // xStride,
0, // yStride,
i.channel().xSampling,
i.channel().ySampling,
true)); // zero
}
else
{
//
// Channel i is present in the frame buffer.
//
slices.push_back (OutSliceInfo (j.slice().type,
j.slice().base,
j.slice().xStride,
j.slice().yStride,
j.slice().xSampling,
j.slice().ySampling,
false)); // zero
}
}
//
// Store the new frame buffer.
//
_data->frameBuffer = frameBuffer;
_data->slices = slices;
}
const FrameBuffer &
OutputFile::frameBuffer () const
{
Lock lock (*_data);
return _data->frameBuffer;
}
void
OutputFile::writePixels (int numScanLines)
{
try
{
Lock lock (*_data);
if (_data->slices.size() == 0)
throw Iex::ArgExc ("No frame buffer specified "
"as pixel data source.");
//
// Maintain two iterators:
// nextWriteBuffer: next linebuffer to be written to the file
// nextCompressBuffer: next linebuffer to compress
//
int first = (_data->currentScanLine - _data->minY) /
_data->linesInBuffer;
int nextWriteBuffer = first;
int nextCompressBuffer;
int stop;
int step;
int scanLineMin;
int scanLineMax;
{
//
// Create a task group for all line buffer tasks. When the
// taskgroup goes out of scope, the destructor waits until
// all tasks are complete.
//
TaskGroup taskGroup;
//
// Determine the range of lineBuffers that intersect the scan
// line range. Then add the initial compression tasks to the
// thread pool. We always add in at least one task but the
// individual task might not do anything if numScanLines == 0.
//
if (_data->lineOrder == INCREASING_Y)
{
int last = (_data->currentScanLine + (numScanLines - 1) -
_data->minY) / _data->linesInBuffer;
scanLineMin = _data->currentScanLine;
scanLineMax = _data->currentScanLine + numScanLines - 1;
int numTasks = max (min ((int)_data->lineBuffers.size(),
last - first + 1),
1);
for (int i = 0; i < numTasks; i++)
{
ThreadPool::addGlobalTask
(new LineBufferTask (&taskGroup, _data, first + i,
scanLineMin, scanLineMax));
}
nextCompressBuffer = first + numTasks;
stop = last + 1;
step = 1;
}
else
{
int last = (_data->currentScanLine - (numScanLines - 1) -
_data->minY) / _data->linesInBuffer;
scanLineMax = _data->currentScanLine;
scanLineMin = _data->currentScanLine - numScanLines + 1;
int numTasks = max (min ((int)_data->lineBuffers.size(),
first - last + 1),
1);
for (int i = 0; i < numTasks; i++)
{
ThreadPool::addGlobalTask
(new LineBufferTask (&taskGroup, _data, first - i,
scanLineMin, scanLineMax));
}
nextCompressBuffer = first - numTasks;
stop = last - 1;
step = -1;
}
while (true)
{
if (_data->missingScanLines <= 0)
{
throw Iex::ArgExc ("Tried to write more scan lines "
"than specified by the data window.");
}
//
// Wait until the next line buffer is ready to be written
//
LineBuffer *writeBuffer =
_data->getLineBuffer (nextWriteBuffer);
writeBuffer->wait();
int numLines = writeBuffer->scanLineMax -
writeBuffer->scanLineMin + 1;
_data->missingScanLines -= numLines;
//
// If the line buffer is only partially full, then it is
// not complete and we cannot write it to disk yet.
//
if (writeBuffer->partiallyFull)
{
_data->currentScanLine = _data->currentScanLine +
step * numLines;
writeBuffer->post();
return;
}
//
// Write the line buffer
//
writePixelData (_data, writeBuffer);
nextWriteBuffer += step;
_data->currentScanLine = _data->currentScanLine +
step * numLines;
#ifdef DEBUG
assert (_data->currentScanLine ==
((_data->lineOrder == INCREASING_Y) ?
writeBuffer->scanLineMax + 1:
writeBuffer->scanLineMin - 1));
#endif
//
// Release the lock on the line buffer
//
writeBuffer->post();
//
// If this was the last line buffer in the scanline range
//
if (nextWriteBuffer == stop)
break;
//
// If there are no more line buffers to compress,
// then only continue to write out remaining lineBuffers
//
if (nextCompressBuffer == stop)
continue;
//
// Add nextCompressBuffer as a compression task
//
ThreadPool::addGlobalTask
(new LineBufferTask (&taskGroup, _data, nextCompressBuffer,
scanLineMin, scanLineMax));
//
// Update the next line buffer we need to compress
//
nextCompressBuffer += step;
}
//
// Finish all tasks
//
}
//
// Exeption handling:
//
// LineBufferTask::execute() may have encountered exceptions, but
// those exceptions occurred in another thread, not in the thread
// that is executing this call to OutputFile::writePixels().
// LineBufferTask::execute() has caught all exceptions and stored
// the exceptions' what() strings in the line buffers.
// Now we check if any line buffer contains a stored exception; if
// this is the case then we re-throw the exception in this thread.
// (It is possible that multiple line buffers contain stored
// exceptions. We re-throw the first exception we find and
// ignore all others.)
//
const string *exception = 0;
for (int i = 0; i < _data->lineBuffers.size(); ++i)
{
LineBuffer *lineBuffer = _data->lineBuffers[i];
if (lineBuffer->hasException && !exception)
exception = &lineBuffer->exception;
lineBuffer->hasException = false;
}
if (exception)
throw Iex::IoExc (*exception);
}
catch (Iex::BaseExc &e)
{
REPLACE_EXC (e, "Failed to write pixel data to image "
"file \"" << fileName() << "\". " << e);
throw;
}
}
int
OutputFile::currentScanLine () const
{
Lock lock (*_data);
return _data->currentScanLine;
}
void
OutputFile::copyPixels (InputFile &in)
{
Lock lock (*_data);
//
// Check if this file's and and the InputFile's
// headers are compatible.
//
const Header &hdr = _data->header;
const Header &inHdr = in.header();
if (inHdr.find("tiles") != inHdr.end())
THROW (Iex::ArgExc, "Cannot copy pixels from image "
"file \"" << in.fileName() << "\" to image "
"file \"" << fileName() << "\". "
"The input file is tiled, but the output file is "
"not. Try using TiledOutputFile::copyPixels "
"instead.");
if (!(hdr.dataWindow() == inHdr.dataWindow()))
THROW (Iex::ArgExc, "Cannot copy pixels from image "
"file \"" << in.fileName() << "\" to image "
"file \"" << fileName() << "\". "
"The files have different data windows.");
if (!(hdr.lineOrder() == inHdr.lineOrder()))
THROW (Iex::ArgExc, "Quick pixel copy from image "
"file \"" << in.fileName() << "\" to image "
"file \"" << fileName() << "\" failed. "
"The files have different line orders.");
if (!(hdr.compression() == inHdr.compression()))
THROW (Iex::ArgExc, "Quick pixel copy from image "
"file \"" << in.fileName() << "\" to image "
"file \"" << fileName() << "\" failed. "
"The files use different compression methods.");
if (!(hdr.channels() == inHdr.channels()))
THROW (Iex::ArgExc, "Quick pixel copy from image "
"file \"" << in.fileName() << "\" to image "
"file \"" << fileName() << "\" failed. "
"The files have different channel lists.");
//
// Verify that no pixel data have been written to this file yet.
//
const Box2i &dataWindow = hdr.dataWindow();
if (_data->missingScanLines != dataWindow.max.y - dataWindow.min.y + 1)
THROW (Iex::LogicExc, "Quick pixel copy from image "
"file \"" << in.fileName() << "\" to image "
"file \"" << fileName() << "\" failed. "
"\"" << fileName() << "\" already contains "
"pixel data.");
//
// Copy the pixel data.
//
while (_data->missingScanLines > 0)
{
const char *pixelData;
int pixelDataSize;
in.rawPixelData (_data->currentScanLine, pixelData, pixelDataSize);
writePixelData (_data, lineBufferMinY (_data->currentScanLine,
_data->minY,
_data->linesInBuffer),
pixelData, pixelDataSize);
_data->currentScanLine += (_data->lineOrder == INCREASING_Y)?
_data->linesInBuffer: -_data->linesInBuffer;
_data->missingScanLines -= _data->linesInBuffer;
}
}
void
OutputFile::updatePreviewImage (const PreviewRgba newPixels[])
{
Lock lock (*_data);
if (_data->previewPosition <= 0)
THROW (Iex::LogicExc, "Cannot update preview image pixels. "
"File \"" << fileName() << "\" does not "
"contain a preview image.");
//
// Store the new pixels in the header's preview image attribute.
//
PreviewImageAttribute &pia =
_data->header.typedAttribute <PreviewImageAttribute> ("preview");
PreviewImage &pi = pia.value();
PreviewRgba *pixels = pi.pixels();
int numPixels = pi.width() * pi.height();
for (int i = 0; i < numPixels; ++i)
pixels[i] = newPixels[i];
//
// Save the current file position, jump to the position in
// the file where the preview image starts, store the new
// preview image, and jump back to the saved file position.
//
Int64 savedPosition = _data->os->tellp();
try
{
_data->os->seekp (_data->previewPosition);
pia.writeValueTo (*_data->os, _data->version);
_data->os->seekp (savedPosition);
}
catch (Iex::BaseExc &e)
{
REPLACE_EXC (e, "Cannot update preview image pixels for "
"file \"" << fileName() << "\". " << e);
throw;
}
}
void
OutputFile::breakScanLine (int y, int offset, int length, char c)
{
Lock lock (*_data);
Int64 position =
_data->lineOffsets[(y - _data->minY) / _data->linesInBuffer];
if (!position)
THROW (Iex::ArgExc, "Cannot overwrite scan line " << y << ". "
"The scan line has not yet been stored in "
"file \"" << fileName() << "\".");
_data->currentPosition = 0;
_data->os->seekp (position + offset);
for (int i = 0; i < length; ++i)
_data->os->write (&c, 1);
}
} // namespace Imf
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -