Blame IlmImf/ImfDeepTiledOutputFile.cpp

Packit 0d464f
///////////////////////////////////////////////////////////////////////////
Packit 0d464f
//
Packit 0d464f
// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
Packit 0d464f
// Digital Ltd. LLC
Packit 0d464f
//
Packit 0d464f
// All rights reserved.
Packit 0d464f
//
Packit 0d464f
// Redistribution and use in source and binary forms, with or without
Packit 0d464f
// modification, are permitted provided that the following conditions are
Packit 0d464f
// met:
Packit 0d464f
// *       Redistributions of source code must retain the above copyright
Packit 0d464f
// notice, this list of conditions and the following disclaimer.
Packit 0d464f
// *       Redistributions in binary form must reproduce the above
Packit 0d464f
// copyright notice, this list of conditions and the following disclaimer
Packit 0d464f
// in the documentation and/or other materials provided with the
Packit 0d464f
// distribution.
Packit 0d464f
// *       Neither the name of Industrial Light & Magic nor the names of
Packit 0d464f
// its contributors may be used to endorse or promote products derived
Packit 0d464f
// from this software without specific prior written permission.
Packit 0d464f
//
Packit 0d464f
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit 0d464f
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit 0d464f
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
Packit 0d464f
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
Packit 0d464f
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
Packit 0d464f
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
Packit 0d464f
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit 0d464f
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit 0d464f
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit 0d464f
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
Packit 0d464f
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 0d464f
//
Packit 0d464f
///////////////////////////////////////////////////////////////////////////
Packit 0d464f
Packit 0d464f
//-----------------------------------------------------------------------------
Packit 0d464f
//
Packit 0d464f
//      class DeepTiledOutputFile
Packit 0d464f
//
Packit 0d464f
//-----------------------------------------------------------------------------
Packit 0d464f
Packit 0d464f
#include "ImfDeepTiledOutputFile.h"
Packit 0d464f
#include "ImfDeepTiledInputFile.h"
Packit 0d464f
#include "ImfDeepTiledInputPart.h"
Packit 0d464f
#include "ImfInputFile.h"
Packit 0d464f
#include "ImfTileDescriptionAttribute.h"
Packit 0d464f
#include "ImfPreviewImageAttribute.h"
Packit 0d464f
#include "ImfChannelList.h"
Packit 0d464f
#include "ImfMisc.h"
Packit 0d464f
#include "ImfTiledMisc.h"
Packit 0d464f
#include "ImfStdIO.h"
Packit 0d464f
#include "ImfCompressor.h"
Packit 0d464f
#include "ImfOutputStreamMutex.h"
Packit 0d464f
#include "ImfOutputPartData.h"
Packit 0d464f
#include "ImfArray.h"
Packit 0d464f
#include "ImfXdr.h"
Packit 0d464f
#include "ImfVersion.h"
Packit 0d464f
#include "ImfTileOffsets.h"
Packit 0d464f
#include "ImfThreading.h"
Packit 0d464f
#include "ImfPartType.h"
Packit 0d464f
Packit 0d464f
#include "ImathBox.h"
Packit 0d464f
Packit 0d464f
#include "IlmThreadPool.h"
Packit 0d464f
#include "IlmThreadSemaphore.h"
Packit 0d464f
#include "IlmThreadMutex.h"
Packit 0d464f
Packit 0d464f
#include "Iex.h"
Packit 0d464f
Packit 0d464f
#include <string>
Packit 0d464f
#include <vector>
Packit 0d464f
#include <fstream>
Packit 0d464f
#include <assert.h>
Packit 0d464f
#include <map>
Packit 0d464f
#include <algorithm>
Packit 0d464f
Packit 0d464f
#include "ImfNamespace.h"
Packit 0d464f
Packit 0d464f
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
Packit 0d464f
Packit 0d464f
using IMATH_NAMESPACE::Box2i;
Packit 0d464f
using IMATH_NAMESPACE::V2i;
Packit 0d464f
using std::string;
Packit 0d464f
using std::vector;
Packit 0d464f
using std::ofstream;
Packit 0d464f
using std::map;
Packit 0d464f
using std::min;
Packit 0d464f
using std::max;
Packit 0d464f
using std::swap;
Packit 0d464f
using ILMTHREAD_NAMESPACE::Mutex;
Packit 0d464f
using ILMTHREAD_NAMESPACE::Lock;
Packit 0d464f
using ILMTHREAD_NAMESPACE::Semaphore;
Packit 0d464f
using ILMTHREAD_NAMESPACE::Task;
Packit 0d464f
using ILMTHREAD_NAMESPACE::TaskGroup;
Packit 0d464f
using ILMTHREAD_NAMESPACE::ThreadPool;
Packit 0d464f
Packit 0d464f
namespace {
Packit 0d464f
Packit 0d464f
struct TOutSliceInfo
Packit 0d464f
{
Packit 0d464f
    PixelType                   type;
Packit 0d464f
    const char *                base;
Packit 0d464f
    size_t                      sampleStride;
Packit 0d464f
    size_t                      xStride;
Packit 0d464f
    size_t                      yStride;
Packit 0d464f
    bool                        zero;
Packit 0d464f
    int                         xTileCoords;
Packit 0d464f
    int                         yTileCoords;
Packit 0d464f
Packit 0d464f
    TOutSliceInfo (PixelType type = HALF,
Packit 0d464f
                   size_t sampleStride = 0,
Packit 0d464f
                   size_t xStride = 0,
Packit 0d464f
                   size_t yStride = 0,
Packit 0d464f
                   bool zero = false,
Packit 0d464f
                   int xTileCoords = 0,
Packit 0d464f
                   int yTileCoords = 0);
Packit 0d464f
};
Packit 0d464f
Packit 0d464f
Packit 0d464f
TOutSliceInfo::TOutSliceInfo (PixelType t,
Packit 0d464f
                              size_t spst,
Packit 0d464f
                              size_t xStride,
Packit 0d464f
                              size_t yStride,
Packit 0d464f
                              bool z,
Packit 0d464f
                              int xtc,
Packit 0d464f
                              int ytc)
Packit 0d464f
:
Packit 0d464f
    type (t),
Packit 0d464f
    sampleStride (spst),
Packit 0d464f
    xStride(xStride),
Packit 0d464f
    yStride(yStride),
Packit 0d464f
    zero (z),
Packit 0d464f
    xTileCoords (xtc),
Packit 0d464f
    yTileCoords (ytc)
Packit 0d464f
{
Packit 0d464f
    // empty
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
struct TileCoord
Packit 0d464f
{
Packit 0d464f
    int         dx;
Packit 0d464f
    int         dy;
Packit 0d464f
    int         lx;
Packit 0d464f
    int         ly;
Packit 0d464f
Packit 0d464f
Packit 0d464f
    TileCoord (int xTile = 0, int yTile = 0,
Packit 0d464f
               int xLevel = 0, int yLevel = 0)
Packit 0d464f
    :
Packit 0d464f
        dx (xTile),  dy (yTile),
Packit 0d464f
        lx (xLevel), ly (yLevel)
Packit 0d464f
    {
Packit 0d464f
        // empty
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
Packit 0d464f
    bool
Packit 0d464f
    operator < (const TileCoord &other) const
Packit 0d464f
    {
Packit 0d464f
        return (ly < other.ly) ||
Packit 0d464f
               (ly == other.ly && lx < other.lx) ||
Packit 0d464f
               ((ly == other.ly && lx == other.lx) &&
Packit 0d464f
                    ((dy < other.dy) || (dy == other.dy && dx < other.dx)));
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
Packit 0d464f
    bool
Packit 0d464f
    operator == (const TileCoord &other) const
Packit 0d464f
    {
Packit 0d464f
        return lx == other.lx &&
Packit 0d464f
               ly == other.ly &&
Packit 0d464f
               dx == other.dx &&
Packit 0d464f
               dy == other.dy;
Packit 0d464f
    }
Packit 0d464f
};
Packit 0d464f
Packit 0d464f
Packit 0d464f
struct BufferedTile
Packit 0d464f
{
Packit 0d464f
    char *      pixelData;
Packit 0d464f
    Int64         pixelDataSize;
Packit 0d464f
    Int64         unpackedDataSize;
Packit 0d464f
    char *      sampleCountTableData;
Packit 0d464f
    Int64         sampleCountTableSize;
Packit 0d464f
Packit 0d464f
    BufferedTile (const char *data, int size, int unpackedSize,
Packit 0d464f
                  const char *tableData, int tableSize):
Packit 0d464f
        pixelData (0),
Packit 0d464f
        pixelDataSize(size),
Packit 0d464f
        unpackedDataSize(unpackedSize),
Packit 0d464f
        sampleCountTableData(0),
Packit 0d464f
        sampleCountTableSize(tableSize)
Packit 0d464f
    {
Packit 0d464f
        pixelData = new char[pixelDataSize];
Packit 0d464f
        memcpy (pixelData, data, pixelDataSize);
Packit 0d464f
Packit 0d464f
        sampleCountTableData = new char[tableSize];
Packit 0d464f
        memcpy (sampleCountTableData, tableData, tableSize);
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    ~BufferedTile()
Packit 0d464f
    {
Packit 0d464f
        delete [] pixelData;
Packit 0d464f
        delete [] sampleCountTableData;
Packit 0d464f
    }
Packit 0d464f
};
Packit 0d464f
Packit 0d464f
Packit 0d464f
typedef map <TileCoord, BufferedTile *> TileMap;
Packit 0d464f
Packit 0d464f
Packit 0d464f
struct TileBuffer
Packit 0d464f
{
Packit 0d464f
    Array<char>         buffer;
Packit 0d464f
    const char *        dataPtr;
Packit 0d464f
    Int64               dataSize;
Packit 0d464f
    Int64               uncompressedSize;
Packit 0d464f
    Compressor *        compressor;
Packit 0d464f
    Array<char>         sampleCountTableBuffer;
Packit 0d464f
    const char *        sampleCountTablePtr;
Packit 0d464f
    Int64               sampleCountTableSize;
Packit 0d464f
    Compressor*         sampleCountTableCompressor;
Packit 0d464f
    TileCoord           tileCoord;
Packit 0d464f
    bool                hasException;
Packit 0d464f
    string              exception;
Packit 0d464f
Packit 0d464f
     TileBuffer ();
Packit 0d464f
    ~TileBuffer ();
Packit 0d464f
Packit 0d464f
    inline void         wait () {_sem.wait();}
Packit 0d464f
    inline void         post () {_sem.post();}
Packit 0d464f
Packit 0d464f
  protected:
Packit 0d464f
Packit 0d464f
    Semaphore           _sem;
Packit 0d464f
};
Packit 0d464f
Packit 0d464f
Packit 0d464f
TileBuffer::TileBuffer ():
Packit 0d464f
    dataPtr (0),
Packit 0d464f
    dataSize (0),
Packit 0d464f
    compressor (0),
Packit 0d464f
    sampleCountTablePtr (0),
Packit 0d464f
    sampleCountTableCompressor (0),
Packit 0d464f
    hasException (false),
Packit 0d464f
    exception (),
Packit 0d464f
    _sem (1)
Packit 0d464f
{
Packit 0d464f
    // empty
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
TileBuffer::~TileBuffer ()
Packit 0d464f
{
Packit 0d464f
    if (compressor != 0)
Packit 0d464f
        delete compressor;
Packit 0d464f
Packit 0d464f
    if (sampleCountTableCompressor != 0)
Packit 0d464f
        delete sampleCountTableCompressor;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
} // namespace
Packit 0d464f
Packit 0d464f
Packit 0d464f
struct DeepTiledOutputFile::Data
Packit 0d464f
{
Packit 0d464f
    Header              header;                 // the image header
Packit 0d464f
    int                 version;                // file format version
Packit 0d464f
    bool                multipart;              // file is multipart
Packit 0d464f
    TileDescription     tileDesc;               // describes the tile layout
Packit 0d464f
    DeepFrameBuffer     frameBuffer;            // framebuffer to write into
Packit 0d464f
    Int64               previewPosition;
Packit 0d464f
    LineOrder           lineOrder;              // the file's lineorder
Packit 0d464f
    int                 minX;                   // data window's min x coord
Packit 0d464f
    int                 maxX;                   // data window's max x coord
Packit 0d464f
    int                 minY;                   // data window's min y coord
Packit 0d464f
    int                 maxY;                   // data window's max x coord
Packit 0d464f
Packit 0d464f
    int                 numXLevels;             // number of x levels
Packit 0d464f
    int                 numYLevels;             // number of y levels
Packit 0d464f
    int *               numXTiles;              // number of x tiles at a level
Packit 0d464f
    int *               numYTiles;              // number of y tiles at a level
Packit 0d464f
Packit 0d464f
    TileOffsets         tileOffsets;            // stores offsets in file for
Packit 0d464f
                                                // each tile
Packit 0d464f
Packit 0d464f
    Compressor::Format  format;                 // compressor's data format
Packit 0d464f
    vector<TOutSliceInfo*> slices;              // info about channels in file
Packit 0d464f
Packit 0d464f
    vector<TileBuffer*> tileBuffers;
Packit 0d464f
Packit 0d464f
    Int64               tileOffsetsPosition;    // position of the tile index
Packit 0d464f
Packit 0d464f
    TileMap             tileMap;                // the map of buffered tiles
Packit 0d464f
    TileCoord           nextTileToWrite;
Packit 0d464f
Packit 0d464f
    int                 partNumber;             // the output part number
Packit 0d464f
Packit 0d464f
    char*               sampleCountSliceBase;   // the pointer to the number
Packit 0d464f
                                                // of samples in each pixel
Packit 0d464f
    int                 sampleCountXStride;     // the x stride for sampleCountSliceBase
Packit 0d464f
    int                 sampleCountYStride;     // the y stride for sampleCountSliceBase
Packit 0d464f
    int                 sampleCountXTileCoords; // using x coordinates relative to current tile
Packit 0d464f
    int                 sampleCountYTileCoords; // using y coordinates relative to current tile
Packit 0d464f
Packit 0d464f
    Int64                 maxSampleCountTableSize;// the max size in bytes for a pixel
Packit 0d464f
                                                // sample count table
Packit 0d464f
    OutputStreamMutex*  _streamData;
Packit 0d464f
    bool                _deleteStream;
Packit 0d464f
                                                
Packit 0d464f
     Data (int numThreads);
Packit 0d464f
    ~Data ();
Packit 0d464f
Packit 0d464f
    inline TileBuffer * getTileBuffer (int number);
Packit 0d464f
                                                // hash function from tile
Packit 0d464f
                                                // buffer coords into our
Packit 0d464f
                                                // vector of tile buffers
Packit 0d464f
Packit 0d464f
    int&                getSampleCount(int x, int y);
Packit 0d464f
                                                // get the number of samples
Packit 0d464f
                                                // in each pixel
Packit 0d464f
Packit 0d464f
    TileCoord           nextTileCoord (const TileCoord &a);
Packit 0d464f
};
Packit 0d464f
Packit 0d464f
Packit 0d464f
DeepTiledOutputFile::Data::Data (int numThreads):
Packit 0d464f
    numXTiles(0),
Packit 0d464f
    numYTiles(0),
Packit 0d464f
    tileOffsetsPosition (0),
Packit 0d464f
    partNumber(-1),
Packit 0d464f
    _streamData(NULL),
Packit 0d464f
    _deleteStream(true)
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // We need at least one tileBuffer, but if threading is used,
Packit 0d464f
    // to keep n threads busy we need 2*n tileBuffers
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    tileBuffers.resize (max (1, 2 * numThreads));
Packit 0d464f
    for (size_t i = 0; i < tileBuffers.size(); i++)
Packit 0d464f
        tileBuffers[i] = 0;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
DeepTiledOutputFile::Data::~Data ()
Packit 0d464f
{
Packit 0d464f
    delete [] numXTiles;
Packit 0d464f
    delete [] numYTiles;
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Delete all the tile buffers, if any still happen to exist
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    for (TileMap::iterator i = tileMap.begin(); i != tileMap.end(); ++i)
Packit 0d464f
        delete i->second;
Packit 0d464f
Packit 0d464f
    for (size_t i = 0; i < tileBuffers.size(); i++)
Packit 0d464f
        if (tileBuffers[i] != 0)
Packit 0d464f
            delete tileBuffers[i];
Packit 0d464f
Packit 0d464f
    for (size_t i = 0; i < slices.size(); i++)
Packit 0d464f
        delete slices[i];
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int&
Packit 0d464f
DeepTiledOutputFile::Data::getSampleCount(int x, int y)
Packit 0d464f
{
Packit 0d464f
    return sampleCount(sampleCountSliceBase,
Packit 0d464f
                       sampleCountXStride,
Packit 0d464f
                       sampleCountYStride,
Packit 0d464f
                       x, y);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
TileBuffer*
Packit 0d464f
DeepTiledOutputFile::Data::getTileBuffer (int number)
Packit 0d464f
{
Packit 0d464f
    return tileBuffers[number % tileBuffers.size()];
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
TileCoord
Packit 0d464f
DeepTiledOutputFile::Data::nextTileCoord (const TileCoord &a)
Packit 0d464f
{
Packit 0d464f
    TileCoord b = a;
Packit 0d464f
Packit 0d464f
    if (lineOrder == INCREASING_Y)
Packit 0d464f
    {
Packit 0d464f
        b.dx++;
Packit 0d464f
Packit 0d464f
        if (b.dx >= numXTiles[b.lx])
Packit 0d464f
        {
Packit 0d464f
            b.dx = 0;
Packit 0d464f
            b.dy++;
Packit 0d464f
Packit 0d464f
            if (b.dy >= numYTiles[b.ly])
Packit 0d464f
            {
Packit 0d464f
                //
Packit 0d464f
                // the next tile is in the next level
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                b.dy = 0;
Packit 0d464f
Packit 0d464f
                switch (tileDesc.mode)
Packit 0d464f
                {
Packit 0d464f
                  case ONE_LEVEL:
Packit 0d464f
                  case MIPMAP_LEVELS:
Packit 0d464f
Packit 0d464f
                    b.lx++;
Packit 0d464f
                    b.ly++;
Packit 0d464f
                    break;
Packit 0d464f
Packit 0d464f
                  case RIPMAP_LEVELS:
Packit 0d464f
Packit 0d464f
                    b.lx++;
Packit 0d464f
Packit 0d464f
                    if (b.lx >= numXLevels)
Packit 0d464f
                    {
Packit 0d464f
                        b.lx = 0;
Packit 0d464f
                        b.ly++;
Packit 0d464f
Packit 0d464f
                        #ifdef DEBUG
Packit 0d464f
                            assert (b.ly <= numYLevels);
Packit 0d464f
                        #endif
Packit 0d464f
                    }
Packit 0d464f
                    break;
Packit 0d464f
                  case NUM_LEVELMODES :
Packit 0d464f
                      throw IEX_NAMESPACE::LogicExc("unknown level mode computing nextTileCoord");
Packit 0d464f
                }
Packit 0d464f
            }
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
    else if (lineOrder == DECREASING_Y)
Packit 0d464f
    {
Packit 0d464f
        b.dx++;
Packit 0d464f
Packit 0d464f
        if (b.dx >= numXTiles[b.lx])
Packit 0d464f
        {
Packit 0d464f
            b.dx = 0;
Packit 0d464f
            b.dy--;
Packit 0d464f
Packit 0d464f
            if (b.dy < 0)
Packit 0d464f
            {
Packit 0d464f
                //
Packit 0d464f
                // the next tile is in the next level
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                switch (tileDesc.mode)
Packit 0d464f
                {
Packit 0d464f
                  case ONE_LEVEL:
Packit 0d464f
                  case MIPMAP_LEVELS:
Packit 0d464f
Packit 0d464f
                    b.lx++;
Packit 0d464f
                    b.ly++;
Packit 0d464f
                    break;
Packit 0d464f
Packit 0d464f
                  case RIPMAP_LEVELS:
Packit 0d464f
Packit 0d464f
                    b.lx++;
Packit 0d464f
Packit 0d464f
                    if (b.lx >= numXLevels)
Packit 0d464f
                    {
Packit 0d464f
                        b.lx = 0;
Packit 0d464f
                        b.ly++;
Packit 0d464f
Packit 0d464f
                        #ifdef DEBUG
Packit 0d464f
                            assert (b.ly <= numYLevels);
Packit 0d464f
                        #endif
Packit 0d464f
                    }
Packit 0d464f
                    break;
Packit 0d464f
                  case NUM_LEVELMODES :
Packit 0d464f
                      throw IEX_NAMESPACE::LogicExc("unknown level mode computing nextTileCoord");
Packit 0d464f
                }
Packit 0d464f
Packit 0d464f
                if (b.ly < numYLevels)
Packit 0d464f
                    b.dy = numYTiles[b.ly] - 1;
Packit 0d464f
            }
Packit 0d464f
        }
Packit 0d464f
    }else if(lineOrder==RANDOM_Y)
Packit 0d464f
    {                 
Packit 0d464f
        THROW (IEX_NAMESPACE::ArgExc,
Packit 0d464f
              "can't compute next tile from randomly ordered image: use getTilesInOrder instead");
Packit 0d464f
        
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    return b;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
namespace {
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
writeTileData (DeepTiledOutputFile::Data *ofd,
Packit 0d464f
               int dx, int dy,
Packit 0d464f
               int lx, int ly,
Packit 0d464f
               const char pixelData[],
Packit 0d464f
               Int64 pixelDataSize,
Packit 0d464f
               Int64 unpackedDataSize,
Packit 0d464f
               const char sampleCountTableData[],
Packit 0d464f
               Int64 sampleCountTableSize)
Packit 0d464f
{
Packit 0d464f
    
Packit 0d464f
    //
Packit 0d464f
    // Store a block of pixel data in the output file, and try
Packit 0d464f
    // to keep track of the current writing position the file,
Packit 0d464f
    // without calling tellp() (tellp() can be fairly expensive).
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    Int64 currentPosition = ofd->_streamData->currentPosition;
Packit 0d464f
    ofd->_streamData->currentPosition = 0;
Packit 0d464f
Packit 0d464f
    if (currentPosition == 0)
Packit 0d464f
        currentPosition = ofd->_streamData->os->tellp();
Packit 0d464f
Packit 0d464f
    ofd->tileOffsets (dx, dy, lx, ly) = currentPosition;
Packit 0d464f
Packit 0d464f
    #ifdef DEBUG
Packit 0d464f
        assert (ofd->_streamData->os->tellp() == currentPosition);
Packit 0d464f
    #endif
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Write the tile header.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (ofd->multipart)
Packit 0d464f
    {
Packit 0d464f
        Xdr::write <StreamIO> (*ofd->_streamData->os, ofd->partNumber);
Packit 0d464f
    }
Packit 0d464f
    Xdr::write <StreamIO> (*ofd->_streamData->os, dx);
Packit 0d464f
    Xdr::write <StreamIO> (*ofd->_streamData->os, dy);
Packit 0d464f
    Xdr::write <StreamIO> (*ofd->_streamData->os, lx);
Packit 0d464f
    Xdr::write <StreamIO> (*ofd->_streamData->os, ly);
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Write the packed size of the pixel sample count table (64 bits)
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    Xdr::write <StreamIO> (*ofd->_streamData->os, sampleCountTableSize);
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Write the packed and unpacked data size (64 bits each)
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    Xdr::write <StreamIO> (*ofd->_streamData->os, pixelDataSize);
Packit 0d464f
    Xdr::write <StreamIO> (*ofd->_streamData->os, unpackedDataSize);
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Write the compressed pixel sample count table.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    ofd->_streamData->os->write (sampleCountTableData, sampleCountTableSize);
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Write the compressed data.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    ofd->_streamData->os->write (pixelData, pixelDataSize);
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Keep current position in the file so that we can avoid
Packit 0d464f
    // redundant seekg() operations (seekg() can be fairly expensive).
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    ofd->_streamData->currentPosition = currentPosition        +
Packit 0d464f
                                  4 * Xdr::size<int>()   + // dx, dy, lx, ly,
Packit 0d464f
                                  3 * Xdr::size<Int64>() + // sampleCountTableSize,
Packit 0d464f
                                                           // pixelDataSize,
Packit 0d464f
                                                           // unpackedDataSize
Packit 0d464f
                                  sampleCountTableSize   +
Packit 0d464f
                                  pixelDataSize;
Packit 0d464f
Packit 0d464f
    if (ofd->multipart)
Packit 0d464f
    {
Packit 0d464f
        ofd->_streamData->currentPosition += Xdr::size<int>();
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
bufferedTileWrite (
Packit 0d464f
                   DeepTiledOutputFile::Data *ofd,
Packit 0d464f
                   int dx, int dy,
Packit 0d464f
                   int lx, int ly,
Packit 0d464f
                   const char pixelData[],
Packit 0d464f
                   Int64 pixelDataSize,
Packit 0d464f
                   Int64 unpackedDataSize,
Packit 0d464f
                   const char sampleCountTableData[],
Packit 0d464f
                   Int64 sampleCountTableSize)
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // Check if a tile with coordinates (dx,dy,lx,ly) has already been written.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (ofd->tileOffsets (dx, dy, lx, ly))
Packit 0d464f
    {
Packit 0d464f
        THROW (IEX_NAMESPACE::ArgExc,
Packit 0d464f
               "Attempt to write tile "
Packit 0d464f
               "(" << dx << ", " << dy << ", " << lx << ", " << ly << ") "
Packit 0d464f
               "more than once.");
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // If tiles can be written in random order, then don't buffer anything.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (ofd->lineOrder == RANDOM_Y)
Packit 0d464f
    {
Packit 0d464f
        writeTileData (ofd, dx, dy, lx, ly,
Packit 0d464f
                       pixelData, pixelDataSize, unpackedDataSize,
Packit 0d464f
                       sampleCountTableData, sampleCountTableSize);
Packit 0d464f
        return;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // If the tiles cannot be written in random order, then check if a
Packit 0d464f
    // tile with coordinates (dx,dy,lx,ly) has already been buffered.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    TileCoord currentTile = TileCoord(dx, dy, lx, ly);
Packit 0d464f
Packit 0d464f
    if (ofd->tileMap.find (currentTile) != ofd->tileMap.end())
Packit 0d464f
    {
Packit 0d464f
        THROW (IEX_NAMESPACE::ArgExc,
Packit 0d464f
               "Attempt to write tile "
Packit 0d464f
               "(" << dx << ", " << dy << ", " << lx << ", " << ly << ") "
Packit 0d464f
               "more than once.");
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // If all the tiles before this one have already been written to the file,
Packit 0d464f
    // then write this tile immediately and check if we have buffered tiles
Packit 0d464f
    // that can be written after this tile.
Packit 0d464f
    //
Packit 0d464f
    // Otherwise, buffer the tile so it can be written to file later.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (ofd->nextTileToWrite == currentTile)
Packit 0d464f
    {
Packit 0d464f
        writeTileData (ofd, dx, dy, lx, ly,
Packit 0d464f
                       pixelData, pixelDataSize, unpackedDataSize,
Packit 0d464f
                       sampleCountTableData, sampleCountTableSize);
Packit 0d464f
        ofd->nextTileToWrite = ofd->nextTileCoord (ofd->nextTileToWrite);
Packit 0d464f
Packit 0d464f
        TileMap::iterator i = ofd->tileMap.find (ofd->nextTileToWrite);
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // Step through the tiles and write all successive buffered tiles after
Packit 0d464f
        // the current one.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        while(i != ofd->tileMap.end())
Packit 0d464f
        {
Packit 0d464f
            //
Packit 0d464f
            // Write the tile, and then delete the tile's buffered data
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            writeTileData (ofd,
Packit 0d464f
                           i->first.dx, i->first.dy,
Packit 0d464f
                           i->first.lx, i->first.ly,
Packit 0d464f
                           i->second->pixelData,
Packit 0d464f
                           i->second->pixelDataSize,
Packit 0d464f
                           i->second->unpackedDataSize,
Packit 0d464f
                           i->second->sampleCountTableData,
Packit 0d464f
                           i->second->sampleCountTableSize);
Packit 0d464f
Packit 0d464f
            delete i->second;
Packit 0d464f
            ofd->tileMap.erase (i);
Packit 0d464f
Packit 0d464f
            //
Packit 0d464f
            // Proceed to the next tile
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            ofd->nextTileToWrite = ofd->nextTileCoord (ofd->nextTileToWrite);
Packit 0d464f
            i = ofd->tileMap.find (ofd->nextTileToWrite);
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
    else
Packit 0d464f
    {
Packit 0d464f
        //
Packit 0d464f
        // Create a new BufferedTile, copy the pixelData into it, and
Packit 0d464f
        // insert it into the tileMap.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        ofd->tileMap[currentTile] =
Packit 0d464f
            new BufferedTile ((const char *)pixelData, pixelDataSize, unpackedDataSize,
Packit 0d464f
                              sampleCountTableData, sampleCountTableSize);
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
convertToXdr (DeepTiledOutputFile::Data *ofd,
Packit 0d464f
              Array<char>& tileBuffer,
Packit 0d464f
              int numScanLines,
Packit 0d464f
              vector<Int64>& bytesPerLine)
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // Convert the contents of a TiledOutputFile's tileBuffer from the
Packit 0d464f
    // machine's native representation to Xdr format. This function is called
Packit 0d464f
    // by writeTile(), below, if the compressor wanted its input pixel data
Packit 0d464f
    // in the machine's native format, but then failed to compress the data
Packit 0d464f
    // (most compressors will expand rather than compress random input data).
Packit 0d464f
    //
Packit 0d464f
    // Note that this routine assumes that the machine's native representation
Packit 0d464f
    // of the pixel data has the same size as the Xdr representation.  This
Packit 0d464f
    // makes it possible to convert the pixel data in place, without an
Packit 0d464f
    // intermediate temporary buffer.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Set these to point to the start of the tile.
Packit 0d464f
    // We will write to toPtr, and read from fromPtr.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    char *writePtr = tileBuffer;
Packit 0d464f
    const char *readPtr = writePtr;
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Iterate over all scan lines in the tile.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    for (int y = 0; y < numScanLines; ++y)
Packit 0d464f
    {
Packit 0d464f
        //
Packit 0d464f
        // Iterate over all slices in the file.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        for (unsigned int i = 0; i < ofd->slices.size(); ++i)
Packit 0d464f
        {
Packit 0d464f
            const TOutSliceInfo &slice = *ofd->slices[i];
Packit 0d464f
Packit 0d464f
            //
Packit 0d464f
            // Convert the samples in place.
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            Int64 numPixelsPerScanLine = bytesPerLine[y];
Packit 0d464f
Packit 0d464f
            convertInPlace (writePtr, readPtr, slice.type,
Packit 0d464f
                            numPixelsPerScanLine);
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    #ifdef DEBUG
Packit 0d464f
Packit 0d464f
        assert (writePtr == readPtr);
Packit 0d464f
Packit 0d464f
    #endif
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
//
Packit 0d464f
// A TileBufferTask encapsulates the task of copying a tile from
Packit 0d464f
// the user's framebuffer into a LineBuffer and compressing the data
Packit 0d464f
// if necessary.
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
class TileBufferTask: public Task
Packit 0d464f
{
Packit 0d464f
  public:
Packit 0d464f
Packit 0d464f
    TileBufferTask (TaskGroup *group,
Packit 0d464f
                    DeepTiledOutputFile::Data *ofd,
Packit 0d464f
                    int number,
Packit 0d464f
                    int dx, int dy,
Packit 0d464f
                    int lx, int ly);
Packit 0d464f
Packit 0d464f
    virtual ~TileBufferTask ();
Packit 0d464f
Packit 0d464f
    virtual void                execute ();
Packit 0d464f
Packit 0d464f
  private:
Packit 0d464f
Packit 0d464f
    DeepTiledOutputFile::Data *     _ofd;
Packit 0d464f
    TileBuffer *                _tileBuffer;
Packit 0d464f
};
Packit 0d464f
Packit 0d464f
Packit 0d464f
TileBufferTask::TileBufferTask
Packit 0d464f
    (TaskGroup *group,
Packit 0d464f
     DeepTiledOutputFile::Data *ofd,
Packit 0d464f
     int number,
Packit 0d464f
     int dx, int dy,
Packit 0d464f
     int lx, int ly)
Packit 0d464f
:
Packit 0d464f
    Task (group),
Packit 0d464f
    _ofd (ofd),
Packit 0d464f
    _tileBuffer (_ofd->getTileBuffer (number))
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // Wait for the tileBuffer to become available
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    _tileBuffer->wait ();
Packit 0d464f
    _tileBuffer->tileCoord = TileCoord (dx, dy, lx, ly);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
TileBufferTask::~TileBufferTask ()
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // Signal that the tile buffer is now free
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    _tileBuffer->post ();
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
TileBufferTask::execute ()
Packit 0d464f
{
Packit 0d464f
    try
Packit 0d464f
    {
Packit 0d464f
        //
Packit 0d464f
        // First copy the pixel data from the frame buffer
Packit 0d464f
        // into the tile buffer
Packit 0d464f
        //
Packit 0d464f
        // Convert one tile's worth of pixel data to
Packit 0d464f
        // a machine-independent representation, and store
Packit 0d464f
        // the result in _tileBuffer->buffer.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        Box2i tileRange = OPENEXR_IMF_INTERNAL_NAMESPACE::dataWindowForTile (
Packit 0d464f
                _ofd->tileDesc,
Packit 0d464f
                _ofd->minX, _ofd->maxX,
Packit 0d464f
                _ofd->minY, _ofd->maxY,
Packit 0d464f
                _tileBuffer->tileCoord.dx,
Packit 0d464f
                _tileBuffer->tileCoord.dy,
Packit 0d464f
                _tileBuffer->tileCoord.lx,
Packit 0d464f
                _tileBuffer->tileCoord.ly);
Packit 0d464f
Packit 0d464f
        int numScanLines = tileRange.max.y - tileRange.min.y + 1;
Packit 0d464f
//        int numPixelsPerScanLine = tileRange.max.x - tileRange.min.x + 1;
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // Get the bytes for each line.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        vector<Int64> bytesPerLine(_ofd->tileDesc.ySize);
Packit 0d464f
        vector<int> xOffsets(_ofd->slices.size());
Packit 0d464f
        vector<int> yOffsets(_ofd->slices.size());
Packit 0d464f
        for (size_t i = 0; i < _ofd->slices.size(); i++)
Packit 0d464f
        {
Packit 0d464f
            const TOutSliceInfo &slice = *_ofd->slices[i];
Packit 0d464f
            xOffsets[i] = slice.xTileCoords * tileRange.min.x;
Packit 0d464f
            yOffsets[i] = slice.yTileCoords * tileRange.min.y;
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        calculateBytesPerLine(_ofd->header,
Packit 0d464f
                              _ofd->sampleCountSliceBase,
Packit 0d464f
                              _ofd->sampleCountXStride,
Packit 0d464f
                              _ofd->sampleCountYStride,
Packit 0d464f
                              tileRange.min.x, tileRange.max.x,
Packit 0d464f
                              tileRange.min.y, tileRange.max.y,
Packit 0d464f
                              xOffsets, yOffsets,
Packit 0d464f
                              bytesPerLine);
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // Allocate the memory for internal buffer.
Packit 0d464f
        // (TODO) more efficient memory management?
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        Int64 totalBytes = 0;
Packit 0d464f
        Int64 maxBytesPerTileLine = 0;
Packit 0d464f
        for (size_t i = 0; i < bytesPerLine.size(); i++)
Packit 0d464f
        {
Packit 0d464f
            totalBytes += bytesPerLine[i];
Packit 0d464f
            if (bytesPerLine[i] > maxBytesPerTileLine)
Packit 0d464f
                maxBytesPerTileLine = bytesPerLine[i];
Packit 0d464f
        }
Packit 0d464f
        _tileBuffer->buffer.resizeErase(totalBytes);
Packit 0d464f
Packit 0d464f
        char *writePtr = _tileBuffer->buffer;
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // Iterate over the scan lines in the tile.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        int xOffsetForSampleCount =
Packit 0d464f
                (_ofd->sampleCountXTileCoords == 0) ? 0 : tileRange.min.x;
Packit 0d464f
        int yOffsetForSampleCount =
Packit 0d464f
                (_ofd->sampleCountYTileCoords == 0) ? 0 : tileRange.min.y;
Packit 0d464f
Packit 0d464f
        for (int y = tileRange.min.y; y <= tileRange.max.y; ++y)
Packit 0d464f
        {
Packit 0d464f
            //
Packit 0d464f
            // Iterate over all image channels.
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            for (unsigned int i = 0; i < _ofd->slices.size(); ++i)
Packit 0d464f
            {
Packit 0d464f
                const TOutSliceInfo &slice = *_ofd->slices[i];
Packit 0d464f
Packit 0d464f
Packit 0d464f
                //
Packit 0d464f
                // Fill the tile buffer with pixel data.
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                if (slice.zero)
Packit 0d464f
                {
Packit 0d464f
                    //
Packit 0d464f
                    // The frame buffer contains no data for this channel.
Packit 0d464f
                    // Store zeroes in _data->tileBuffer.
Packit 0d464f
                    //
Packit 0d464f
Packit 0d464f
                    fillChannelWithZeroes (writePtr, _ofd->format, slice.type,
Packit 0d464f
                                           bytesPerLine[y - tileRange.min.y]);
Packit 0d464f
                }
Packit 0d464f
                else
Packit 0d464f
                {
Packit 0d464f
                    //
Packit 0d464f
                    // The frame buffer contains data for this channel.
Packit 0d464f
                    //
Packit 0d464f
Packit 0d464f
                
Packit 0d464f
                    int xOffsetForData = slice.xTileCoords ? tileRange.min.x : 0;
Packit 0d464f
                    int yOffsetForData = slice.yTileCoords ? tileRange.min.y : 0;
Packit 0d464f
Packit 0d464f
                    // (TOOD) treat sample count offsets differently.
Packit 0d464f
                    copyFromDeepFrameBuffer (writePtr,
Packit 0d464f
                                             slice.base,
Packit 0d464f
                                             _ofd->sampleCountSliceBase,
Packit 0d464f
                                             _ofd->sampleCountXStride,
Packit 0d464f
                                             _ofd->sampleCountYStride,
Packit 0d464f
                                             y,
Packit 0d464f
                                             tileRange.min.x,
Packit 0d464f
                                             tileRange.max.x,
Packit 0d464f
                                             xOffsetForSampleCount,
Packit 0d464f
                                             yOffsetForSampleCount,
Packit 0d464f
                                             xOffsetForData,
Packit 0d464f
                                             yOffsetForData,
Packit 0d464f
                                             slice.sampleStride,
Packit 0d464f
                                             slice.xStride,
Packit 0d464f
                                             slice.yStride,
Packit 0d464f
                                             _ofd->format,
Packit 0d464f
                                             slice.type);
Packit 0d464f
#if defined(DEBUG)
Packit 0d464f
                      assert(writePtr-_tileBuffer->buffer<=totalBytes);
Packit 0d464f
#endif
Packit 0d464f
                }
Packit 0d464f
            }
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // Compress the pixel sample count table.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        char* ptr = _tileBuffer->sampleCountTableBuffer;
Packit 0d464f
        Int64 tableDataSize = 0;
Packit 0d464f
        for (int i = tileRange.min.y; i <= tileRange.max.y; i++)
Packit 0d464f
        {
Packit 0d464f
            int count = 0;
Packit 0d464f
            for (int j = tileRange.min.x; j <= tileRange.max.x; j++)
Packit 0d464f
            {
Packit 0d464f
                count += _ofd->getSampleCount(j - xOffsetForSampleCount,
Packit 0d464f
                                              i - yOffsetForSampleCount);
Packit 0d464f
                Xdr::write <CharPtrIO> (ptr, count);
Packit 0d464f
                tableDataSize += sizeof (int);
Packit 0d464f
            }
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
       if(_tileBuffer->sampleCountTableCompressor)
Packit 0d464f
       {
Packit 0d464f
           _tileBuffer->sampleCountTableSize =
Packit 0d464f
                _tileBuffer->sampleCountTableCompressor->compress (
Packit 0d464f
                                                    _tileBuffer->sampleCountTableBuffer,
Packit 0d464f
                                                    tableDataSize,
Packit 0d464f
                                                    tileRange.min.y,
Packit 0d464f
                                                    _tileBuffer->sampleCountTablePtr);
Packit 0d464f
       }
Packit 0d464f
       
Packit 0d464f
        //
Packit 0d464f
        // If we can't make data shrink (or compression was disabled), then just use the raw data.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        if ( ! _tileBuffer->sampleCountTableCompressor ||
Packit 0d464f
            _tileBuffer->sampleCountTableSize >= _ofd->maxSampleCountTableSize)
Packit 0d464f
        {
Packit 0d464f
            _tileBuffer->sampleCountTableSize = _ofd->maxSampleCountTableSize;
Packit 0d464f
            _tileBuffer->sampleCountTablePtr = _tileBuffer->sampleCountTableBuffer;
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // Compress the contents of the tileBuffer,
Packit 0d464f
        // and store the compressed data in the output file.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        _tileBuffer->dataSize = writePtr - _tileBuffer->buffer;
Packit 0d464f
        _tileBuffer->uncompressedSize = _tileBuffer->dataSize;
Packit 0d464f
        _tileBuffer->dataPtr = _tileBuffer->buffer;
Packit 0d464f
Packit 0d464f
        // (TODO) don't do this all the time.
Packit 0d464f
        if (_tileBuffer->compressor != 0)
Packit 0d464f
            delete _tileBuffer->compressor;
Packit 0d464f
        _tileBuffer->compressor = newTileCompressor
Packit 0d464f
                                    (_ofd->header.compression(),
Packit 0d464f
                                     maxBytesPerTileLine,
Packit 0d464f
                                     _ofd->tileDesc.ySize,
Packit 0d464f
                                     _ofd->header);
Packit 0d464f
Packit 0d464f
        if (_tileBuffer->compressor)
Packit 0d464f
        {
Packit 0d464f
            const char *compPtr;
Packit 0d464f
Packit 0d464f
            Int64 compSize = _tileBuffer->compressor->compressTile
Packit 0d464f
                                                (_tileBuffer->dataPtr,
Packit 0d464f
                                                 _tileBuffer->dataSize,
Packit 0d464f
                                                 tileRange, compPtr);
Packit 0d464f
Packit 0d464f
            if (compSize < _tileBuffer->dataSize)
Packit 0d464f
            {
Packit 0d464f
                _tileBuffer->dataSize = compSize;
Packit 0d464f
                _tileBuffer->dataPtr = compPtr;
Packit 0d464f
            }
Packit 0d464f
            else if (_ofd->format == Compressor::NATIVE)
Packit 0d464f
            {
Packit 0d464f
                //
Packit 0d464f
                // The data did not shrink during compression, but
Packit 0d464f
                // we cannot write to the file using native format,
Packit 0d464f
                // so we need to convert the lineBuffer to Xdr.
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                convertToXdr (_ofd, _tileBuffer->buffer, numScanLines,
Packit 0d464f
                              bytesPerLine);
Packit 0d464f
            }
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
    catch (std::exception &e)
Packit 0d464f
    {
Packit 0d464f
        if (!_tileBuffer->hasException)
Packit 0d464f
        {
Packit 0d464f
            _tileBuffer->exception = e.what ();
Packit 0d464f
            _tileBuffer->hasException = true;
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
    catch (...)
Packit 0d464f
    {
Packit 0d464f
        if (!_tileBuffer->hasException)
Packit 0d464f
        {
Packit 0d464f
            _tileBuffer->exception = "unrecognized exception";
Packit 0d464f
            _tileBuffer->hasException = true;
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
} // namespace
Packit 0d464f
Packit 0d464f
Packit 0d464f
DeepTiledOutputFile::DeepTiledOutputFile
Packit 0d464f
    (const char fileName[],
Packit 0d464f
     const Header &header,
Packit 0d464f
     int numThreads)
Packit 0d464f
:
Packit 0d464f
    _data (new Data (numThreads))
Packit 0d464f
Packit 0d464f
{
Packit 0d464f
    _data->_streamData=new OutputStreamMutex();
Packit 0d464f
    _data->_deleteStream =true;
Packit 0d464f
    try
Packit 0d464f
    {
Packit 0d464f
        header.sanityCheck (true);
Packit 0d464f
        _data->_streamData->os = new StdOFStream (fileName);
Packit 0d464f
        initialize (header);
Packit 0d464f
        _data->_streamData->currentPosition = _data->_streamData->os->tellp();
Packit 0d464f
Packit 0d464f
        // Write header and empty offset table to the file.
Packit 0d464f
        writeMagicNumberAndVersionField(*_data->_streamData->os, _data->header);
Packit 0d464f
        _data->previewPosition = _data->header.writeTo (*_data->_streamData->os, true);
Packit 0d464f
        _data->tileOffsetsPosition = _data->tileOffsets.writeTo (*_data->_streamData->os);
Packit 0d464f
	_data->multipart = false;
Packit 0d464f
    }
Packit 0d464f
    catch (IEX_NAMESPACE::BaseExc &e)
Packit 0d464f
    {
Packit 0d464f
        if (_data && _data->_streamData && _data->_streamData->os) delete _data->_streamData->os;
Packit 0d464f
        if (_data && _data->_streamData)     delete _data->_streamData;
Packit 0d464f
        if (_data)           delete _data;
Packit 0d464f
Packit 0d464f
        REPLACE_EXC (e, "Cannot open image file "
Packit 0d464f
                        "\"" << fileName << "\". " << e);
Packit 0d464f
        throw;
Packit 0d464f
    }
Packit 0d464f
    catch (...)
Packit 0d464f
    {
Packit 0d464f
        if (_data && _data->_streamData && _data->_streamData->os) delete _data->_streamData->os;
Packit 0d464f
        if (_data->_streamData)     delete _data->_streamData;
Packit 0d464f
        if (_data)           delete _data;
Packit 0d464f
Packit 0d464f
        throw;
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
DeepTiledOutputFile::DeepTiledOutputFile
Packit 0d464f
    (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os,
Packit 0d464f
     const Header &header,
Packit 0d464f
     int numThreads)
Packit 0d464f
:
Packit 0d464f
    _data (new Data (numThreads))
Packit 0d464f
{
Packit 0d464f
    _data->_streamData=new OutputStreamMutex();
Packit 0d464f
    _data->_deleteStream=false;
Packit 0d464f
    
Packit 0d464f
    try
Packit 0d464f
    {
Packit 0d464f
        header.sanityCheck(true);
Packit 0d464f
        _data->_streamData->os = &os;
Packit 0d464f
        initialize (header);
Packit 0d464f
        _data->_streamData->currentPosition = _data->_streamData->os->tellp();
Packit 0d464f
Packit 0d464f
        // Write header and empty offset table to the file.
Packit 0d464f
        writeMagicNumberAndVersionField(*_data->_streamData->os, _data->header);
Packit 0d464f
        _data->previewPosition = _data->header.writeTo (*_data->_streamData->os, true);
Packit 0d464f
        _data->tileOffsetsPosition = _data->tileOffsets.writeTo (*_data->_streamData->os);
Packit 0d464f
	_data->multipart = false;
Packit 0d464f
    }
Packit 0d464f
    catch (IEX_NAMESPACE::BaseExc &e)
Packit 0d464f
    {
Packit 0d464f
        if (_data && _data->_streamData) delete _data->_streamData;
Packit 0d464f
        if (_data)       delete _data;
Packit 0d464f
Packit 0d464f
        REPLACE_EXC (e, "Cannot open image file "
Packit 0d464f
                        "\"" << os.fileName() << "\". " << e);
Packit 0d464f
        throw;
Packit 0d464f
    }
Packit 0d464f
    catch (...)
Packit 0d464f
    {
Packit 0d464f
        if (_data && _data->_streamData) delete _data->_streamData;
Packit 0d464f
        if (_data)       delete _data;
Packit 0d464f
Packit 0d464f
        throw;
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
DeepTiledOutputFile::DeepTiledOutputFile(const OutputPartData* part) 
Packit 0d464f
{
Packit 0d464f
   
Packit 0d464f
    try
Packit 0d464f
    {
Packit 0d464f
        if (part->header.type() != DEEPTILE)
Packit 0d464f
            throw IEX_NAMESPACE::ArgExc("Can't build a DeepTiledOutputFile from "
Packit 0d464f
                              "a type-mismatched part.");
Packit 0d464f
Packit 0d464f
        _data = new Data (part->numThreads);
Packit 0d464f
        _data->_streamData=part->mutex;
Packit 0d464f
        _data->_deleteStream=false;
Packit 0d464f
        initialize(part->header);
Packit 0d464f
        _data->partNumber = part->partNumber;
Packit 0d464f
        _data->tileOffsetsPosition = part->chunkOffsetTablePosition;
Packit 0d464f
        _data->previewPosition = part->previewPosition;
Packit 0d464f
	_data->multipart = part->multipart;
Packit 0d464f
    }
Packit 0d464f
    catch (IEX_NAMESPACE::BaseExc &e)
Packit 0d464f
    {
Packit 0d464f
        if (_data) delete _data;
Packit 0d464f
Packit 0d464f
        REPLACE_EXC (e, "Cannot initialize output part "
Packit 0d464f
                        "\"" << part->partNumber << "\". " << e);
Packit 0d464f
        throw;
Packit 0d464f
    }
Packit 0d464f
    catch (...)
Packit 0d464f
    {
Packit 0d464f
        if (_data) delete _data;
Packit 0d464f
Packit 0d464f
        throw;
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepTiledOutputFile::initialize (const Header &header)
Packit 0d464f
{
Packit 0d464f
    _data->header = header;
Packit 0d464f
    _data->header.setType(DEEPTILE);
Packit 0d464f
    _data->lineOrder = _data->header.lineOrder();
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Check that the file is indeed tiled
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    _data->tileDesc = _data->header.tileDescription();
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Save the dataWindow information
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    const Box2i &dataWindow = _data->header.dataWindow();
Packit 0d464f
    _data->minX = dataWindow.min.x;
Packit 0d464f
    _data->maxX = dataWindow.max.x;
Packit 0d464f
    _data->minY = dataWindow.min.y;
Packit 0d464f
    _data->maxY = dataWindow.max.y;
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Precompute level and tile information to speed up utility functions
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    precalculateTileInfo (_data->tileDesc,
Packit 0d464f
                          _data->minX, _data->maxX,
Packit 0d464f
                          _data->minY, _data->maxY,
Packit 0d464f
                          _data->numXTiles, _data->numYTiles,
Packit 0d464f
                          _data->numXLevels, _data->numYLevels);
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Determine the first tile coordinate that we will be writing
Packit 0d464f
    // if the file is not RANDOM_Y.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    _data->nextTileToWrite = (_data->lineOrder == INCREASING_Y)?
Packit 0d464f
                               TileCoord (0, 0, 0, 0):
Packit 0d464f
                               TileCoord (0, _data->numYTiles[0] - 1, 0, 0);
Packit 0d464f
Packit 0d464f
    Compressor* compressor = newTileCompressor
Packit 0d464f
                                (_data->header.compression(),
Packit 0d464f
                                 0,
Packit 0d464f
                                 _data->tileDesc.ySize,
Packit 0d464f
                                 _data->header);
Packit 0d464f
Packit 0d464f
    _data->format = defaultFormat (compressor);
Packit 0d464f
Packit 0d464f
    if (compressor != 0)
Packit 0d464f
        delete compressor;
Packit 0d464f
Packit 0d464f
    _data->tileOffsets = TileOffsets (_data->tileDesc.mode,
Packit 0d464f
                                      _data->numXLevels,
Packit 0d464f
                                      _data->numYLevels,
Packit 0d464f
                                      _data->numXTiles,
Packit 0d464f
                                      _data->numYTiles);
Packit 0d464f
                                      
Packit 0d464f
    //ignore the existing value of chunkCount - correct it if it's wrong
Packit 0d464f
    _data->header.setChunkCount(getChunkOffsetTableSize(_data->header,true));                                   
Packit 0d464f
                                      
Packit 0d464f
    _data->maxSampleCountTableSize = _data->tileDesc.ySize *
Packit 0d464f
                                     _data->tileDesc.xSize *
Packit 0d464f
                                     sizeof(int);
Packit 0d464f
Packit 0d464f
                                     
Packit 0d464f
    for (size_t i = 0; i < _data->tileBuffers.size(); i++)
Packit 0d464f
    {
Packit 0d464f
        _data->tileBuffers[i] = new TileBuffer ();
Packit 0d464f
Packit 0d464f
        _data->tileBuffers[i]->sampleCountTableBuffer.
Packit 0d464f
                resizeErase(_data->maxSampleCountTableSize);
Packit 0d464f
Packit 0d464f
        char * p = &(_data->tileBuffers[i]->sampleCountTableBuffer[0]);
Packit 0d464f
        memset (p, 0, _data->maxSampleCountTableSize);
Packit 0d464f
Packit 0d464f
        _data->tileBuffers[i]->sampleCountTableCompressor =
Packit 0d464f
                newCompressor (_data->header.compression(),
Packit 0d464f
                               _data->maxSampleCountTableSize,
Packit 0d464f
                               _data->header);
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
DeepTiledOutputFile::~DeepTiledOutputFile ()
Packit 0d464f
{
Packit 0d464f
    if (_data)
Packit 0d464f
    {
Packit 0d464f
        {
Packit 0d464f
            Lock lock(*_data->_streamData);
Packit 0d464f
            Int64 originalPosition = _data->_streamData->os->tellp();
Packit 0d464f
Packit 0d464f
            if (_data->tileOffsetsPosition > 0)
Packit 0d464f
            {
Packit 0d464f
                try
Packit 0d464f
                {
Packit 0d464f
                    _data->_streamData->os->seekp (_data->tileOffsetsPosition);
Packit 0d464f
                    _data->tileOffsets.writeTo (*_data->_streamData->os);
Packit 0d464f
Packit 0d464f
                    //
Packit 0d464f
                    // Restore the original position.
Packit 0d464f
                    //
Packit 0d464f
                    _data->_streamData->os->seekp (originalPosition);
Packit 0d464f
                }
Packit 0d464f
                catch (...)
Packit 0d464f
                {
Packit 0d464f
                    //
Packit 0d464f
                    // We cannot safely throw any exceptions from here.
Packit 0d464f
                    // This destructor may have been called because the
Packit 0d464f
                    // stack is currently being unwound for another
Packit 0d464f
                    // exception.
Packit 0d464f
                    //
Packit 0d464f
                }
Packit 0d464f
            }
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        if (_data->_deleteStream && _data->_streamData)
Packit 0d464f
            delete _data->_streamData->os;
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // (TODO) we should have a way to tell if the stream data is owned by
Packit 0d464f
        // this file or by a parent multipart file.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        if (_data->partNumber == -1 && _data->_streamData)
Packit 0d464f
            delete _data->_streamData;
Packit 0d464f
Packit 0d464f
        delete _data;
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
const char *
Packit 0d464f
DeepTiledOutputFile::fileName () const
Packit 0d464f
{
Packit 0d464f
    return _data->_streamData->os->fileName();
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
const Header &
Packit 0d464f
DeepTiledOutputFile::header () const
Packit 0d464f
{
Packit 0d464f
    return _data->header;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepTiledOutputFile::setFrameBuffer (const DeepFrameBuffer &frameBuffer)
Packit 0d464f
{
Packit 0d464f
    Lock lock (*_data->_streamData);
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Check if the new frame buffer descriptor
Packit 0d464f
    // is compatible with the image file header.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    const ChannelList &channels = _data->header.channels();
Packit 0d464f
Packit 0d464f
    for (ChannelList::ConstIterator i = channels.begin();
Packit 0d464f
         i != channels.end();
Packit 0d464f
         ++i)
Packit 0d464f
    {
Packit 0d464f
        DeepFrameBuffer::ConstIterator j = frameBuffer.find (i.name());
Packit 0d464f
Packit 0d464f
        if (j == frameBuffer.end())
Packit 0d464f
            continue;
Packit 0d464f
Packit 0d464f
        if (i.channel().type != j.slice().type)
Packit 0d464f
            THROW (IEX_NAMESPACE::ArgExc, "Pixel type of \"" << i.name() << "\" channel "
Packit 0d464f
                                "of output file \"" << fileName() << "\" is "
Packit 0d464f
                                "not compatible with the frame buffer's "
Packit 0d464f
                                "pixel type.");
Packit 0d464f
Packit 0d464f
        if (j.slice().xSampling != 1 || j.slice().ySampling != 1)
Packit 0d464f
            THROW (IEX_NAMESPACE::ArgExc, "All channels in a tiled file must have"
Packit 0d464f
                                "sampling (1,1).");
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Store the pixel sample count table.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    const Slice& sampleCountSlice = frameBuffer.getSampleCountSlice();
Packit 0d464f
    if (sampleCountSlice.base == 0)
Packit 0d464f
    {
Packit 0d464f
        throw IEX_NAMESPACE::ArgExc ("Invalid base pointer, please set a proper sample count slice.");
Packit 0d464f
    }
Packit 0d464f
    else
Packit 0d464f
    {
Packit 0d464f
        _data->sampleCountSliceBase = sampleCountSlice.base;
Packit 0d464f
        _data->sampleCountXStride = sampleCountSlice.xStride;
Packit 0d464f
        _data->sampleCountYStride = sampleCountSlice.yStride;
Packit 0d464f
        _data->sampleCountXTileCoords = sampleCountSlice.xTileCoords;
Packit 0d464f
        _data->sampleCountYTileCoords = sampleCountSlice.yTileCoords;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Initialize slice table for writePixels().
Packit 0d464f
    // Pixel sample count slice is not presented in the header,
Packit 0d464f
    // so it wouldn't be added here.
Packit 0d464f
    // Store the pixel base pointer table.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    vector<TOutSliceInfo*> slices;
Packit 0d464f
Packit 0d464f
    for (ChannelList::ConstIterator i = channels.begin();
Packit 0d464f
         i != channels.end();
Packit 0d464f
         ++i)
Packit 0d464f
    {
Packit 0d464f
        DeepFrameBuffer::ConstIterator j = frameBuffer.find (i.name());
Packit 0d464f
Packit 0d464f
        if (j == frameBuffer.end())
Packit 0d464f
        {
Packit 0d464f
            //
Packit 0d464f
            // Channel i is not present in the frame buffer.
Packit 0d464f
            // In the file, channel i will contain only zeroes.
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            slices.push_back (new TOutSliceInfo (i.channel().type,
Packit 0d464f
                                                 0, // sampleStride,
Packit 0d464f
                                                 0, // xStride
Packit 0d464f
                                                 0, // yStride
Packit 0d464f
                                                 true)); // zero
Packit 0d464f
        }
Packit 0d464f
        else
Packit 0d464f
        {
Packit 0d464f
            //
Packit 0d464f
            // Channel i is present in the frame buffer.
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            slices.push_back (new TOutSliceInfo (j.slice().type,
Packit 0d464f
                                                 j.slice().sampleStride,
Packit 0d464f
                                                 j.slice().xStride,
Packit 0d464f
                                                 j.slice().yStride,
Packit 0d464f
                                                 false, // zero
Packit 0d464f
                                                 (j.slice().xTileCoords)? 1: 0,
Packit 0d464f
                                                 (j.slice().yTileCoords)? 1: 0));
Packit 0d464f
Packit 0d464f
            TOutSliceInfo* slice = slices.back();
Packit 0d464f
            slice->base = j.slice().base;
Packit 0d464f
            
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Store the new frame buffer.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    _data->frameBuffer = frameBuffer;
Packit 0d464f
Packit 0d464f
    for (size_t i = 0; i < _data->slices.size(); i++)
Packit 0d464f
        delete _data->slices[i];
Packit 0d464f
    _data->slices = slices;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
const DeepFrameBuffer &
Packit 0d464f
DeepTiledOutputFile::frameBuffer () const
Packit 0d464f
{
Packit 0d464f
    Lock lock (*_data->_streamData);
Packit 0d464f
    return _data->frameBuffer;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepTiledOutputFile::writeTiles (int dx1, int dx2, int dy1, int dy2,
Packit 0d464f
                             int lx, int ly)
Packit 0d464f
{
Packit 0d464f
    try
Packit 0d464f
    {
Packit 0d464f
        Lock lock (*_data->_streamData);
Packit 0d464f
Packit 0d464f
        if (_data->slices.size() == 0)
Packit 0d464f
            throw IEX_NAMESPACE::ArgExc ("No frame buffer specified "
Packit 0d464f
                               "as pixel data source.");
Packit 0d464f
Packit 0d464f
        if (!isValidTile (dx1, dy1, lx, ly) || !isValidTile (dx2, dy2, lx, ly))
Packit 0d464f
            throw IEX_NAMESPACE::ArgExc ("Tile coordinates are invalid.");
Packit 0d464f
Packit 0d464f
        if (!isValidLevel (lx, ly))
Packit 0d464f
            THROW (IEX_NAMESPACE::ArgExc,
Packit 0d464f
                   "Level coordinate "
Packit 0d464f
                   "(" << lx << ", " << ly << ") "
Packit 0d464f
                   "is invalid.");
Packit 0d464f
        //
Packit 0d464f
        // Determine the first and last tile coordinates in both dimensions
Packit 0d464f
        // based on the file's lineOrder
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        if (dx1 > dx2)
Packit 0d464f
            swap (dx1, dx2);
Packit 0d464f
Packit 0d464f
        if (dy1 > dy2)
Packit 0d464f
            swap (dy1, dy2);
Packit 0d464f
Packit 0d464f
        int dyStart = dy1;
Packit 0d464f
        int dyStop  = dy2 + 1;
Packit 0d464f
        int dY      = 1;
Packit 0d464f
Packit 0d464f
        if (_data->lineOrder == DECREASING_Y)
Packit 0d464f
        {
Packit 0d464f
            dyStart = dy2;
Packit 0d464f
            dyStop  = dy1 - 1;
Packit 0d464f
            dY      = -1;
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        int numTiles = (dx2 - dx1 + 1) * (dy2 - dy1 + 1);
Packit 0d464f
        int numTasks = min ((int)_data->tileBuffers.size(), numTiles);
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // Create a task group for all tile buffer tasks.  When the
Packit 0d464f
        // task group goes out of scope, the destructor waits until
Packit 0d464f
        // all tasks are complete.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        {
Packit 0d464f
            TaskGroup taskGroup;
Packit 0d464f
Packit 0d464f
            //
Packit 0d464f
            // Add in the initial compression tasks to the thread pool
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            int nextCompBuffer = 0;
Packit 0d464f
            int dxComp         = dx1;
Packit 0d464f
            int dyComp         = dyStart;
Packit 0d464f
Packit 0d464f
            while (nextCompBuffer < numTasks)
Packit 0d464f
            {
Packit 0d464f
                ThreadPool::addGlobalTask (new TileBufferTask (&taskGroup,
Packit 0d464f
                                                               _data,
Packit 0d464f
                                                               nextCompBuffer++,
Packit 0d464f
                                                               dxComp, dyComp,
Packit 0d464f
                                                               lx, ly));
Packit 0d464f
                dxComp++;
Packit 0d464f
Packit 0d464f
                if (dxComp > dx2)
Packit 0d464f
                {
Packit 0d464f
                    dxComp = dx1;
Packit 0d464f
                    dyComp += dY;
Packit 0d464f
                }
Packit 0d464f
            }
Packit 0d464f
Packit 0d464f
            //
Packit 0d464f
            // Write the compressed buffers and add in more compression
Packit 0d464f
            // tasks until done
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            int nextWriteBuffer = 0;
Packit 0d464f
            int dxWrite         = dx1;
Packit 0d464f
            int dyWrite         = dyStart;
Packit 0d464f
Packit 0d464f
            while (nextWriteBuffer < numTiles)
Packit 0d464f
            {
Packit 0d464f
                //
Packit 0d464f
                // Wait until the nextWriteBuffer is ready to be written
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                TileBuffer* writeBuffer =
Packit 0d464f
                                    _data->getTileBuffer (nextWriteBuffer);
Packit 0d464f
Packit 0d464f
                writeBuffer->wait();
Packit 0d464f
Packit 0d464f
                //
Packit 0d464f
                // Write the tilebuffer
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                bufferedTileWrite ( _data, dxWrite, dyWrite, lx, ly,
Packit 0d464f
                                   writeBuffer->dataPtr,
Packit 0d464f
                                   writeBuffer->dataSize,
Packit 0d464f
                                   writeBuffer->uncompressedSize,
Packit 0d464f
                                   writeBuffer->sampleCountTablePtr,
Packit 0d464f
                                   writeBuffer->sampleCountTableSize);
Packit 0d464f
Packit 0d464f
                //
Packit 0d464f
                // Release the lock on nextWriteBuffer
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                writeBuffer->post();
Packit 0d464f
Packit 0d464f
                //
Packit 0d464f
                // If there are no more tileBuffers to compress, then
Packit 0d464f
                // only continue to write out remaining tileBuffers,
Packit 0d464f
                // otherwise keep adding compression tasks.
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                if (nextCompBuffer < numTiles)
Packit 0d464f
                {
Packit 0d464f
                    //
Packit 0d464f
                    // add nextCompBuffer as a compression Task
Packit 0d464f
                    //
Packit 0d464f
Packit 0d464f
                    ThreadPool::addGlobalTask
Packit 0d464f
                        (new TileBufferTask (&taskGroup,
Packit 0d464f
                                             _data,
Packit 0d464f
                                             nextCompBuffer,
Packit 0d464f
                                             dxComp, dyComp,
Packit 0d464f
                                             lx, ly));
Packit 0d464f
                }
Packit 0d464f
Packit 0d464f
                nextWriteBuffer++;
Packit 0d464f
                dxWrite++;
Packit 0d464f
Packit 0d464f
                if (dxWrite > dx2)
Packit 0d464f
                {
Packit 0d464f
                    dxWrite = dx1;
Packit 0d464f
                    dyWrite += dY;
Packit 0d464f
                }
Packit 0d464f
Packit 0d464f
                nextCompBuffer++;
Packit 0d464f
                dxComp++;
Packit 0d464f
Packit 0d464f
                if (dxComp > dx2)
Packit 0d464f
                {
Packit 0d464f
                    dxComp = dx1;
Packit 0d464f
                    dyComp += dY;
Packit 0d464f
                }
Packit 0d464f
            }
Packit 0d464f
Packit 0d464f
            //
Packit 0d464f
            // finish all tasks
Packit 0d464f
            //
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // Exeption handling:
Packit 0d464f
        //
Packit 0d464f
        // TileBufferTask::execute() may have encountered exceptions, but
Packit 0d464f
        // those exceptions occurred in another thread, not in the thread
Packit 0d464f
        // that is executing this call to TiledOutputFile::writeTiles().
Packit 0d464f
        // TileBufferTask::execute() has caught all exceptions and stored
Packit 0d464f
        // the exceptions' what() strings in the tile buffers.
Packit 0d464f
        // Now we check if any tile buffer contains a stored exception; if
Packit 0d464f
        // this is the case then we re-throw the exception in this thread.
Packit 0d464f
        // (It is possible that multiple tile buffers contain stored
Packit 0d464f
        // exceptions.  We re-throw the first exception we find and
Packit 0d464f
        // ignore all others.)
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        const string *exception = 0;
Packit 0d464f
Packit 0d464f
        for (size_t i = 0; i < _data->tileBuffers.size(); ++i)
Packit 0d464f
        {
Packit 0d464f
            TileBuffer *tileBuffer = _data->tileBuffers[i];
Packit 0d464f
Packit 0d464f
            if (tileBuffer->hasException && !exception)
Packit 0d464f
                exception = &tileBuffer->exception;
Packit 0d464f
Packit 0d464f
            tileBuffer->hasException = false;
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        if (exception)
Packit 0d464f
            throw IEX_NAMESPACE::IoExc (*exception);
Packit 0d464f
    }
Packit 0d464f
    catch (IEX_NAMESPACE::BaseExc &e)
Packit 0d464f
    {
Packit 0d464f
        REPLACE_EXC (e, "Failed to write pixel data to image "
Packit 0d464f
                        "file \"" << fileName() << "\". " << e);
Packit 0d464f
        throw;
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepTiledOutputFile::writeTiles (int dx1, int dxMax, int dyMin, int dyMax, int l)
Packit 0d464f
{
Packit 0d464f
    writeTiles (dx1, dxMax, dyMin, dyMax, l, l);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepTiledOutputFile::writeTile (int dx, int dy, int lx, int ly)
Packit 0d464f
{
Packit 0d464f
    writeTiles (dx, dx, dy, dy, lx, ly);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepTiledOutputFile::writeTile (int dx, int dy, int l)
Packit 0d464f
{
Packit 0d464f
    writeTile(dx, dy, l, l);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepTiledOutputFile::copyPixels (DeepTiledInputFile &in)
Packit 0d464f
{
Packit 0d464f
Packit 0d464f
   //
Packit 0d464f
   // Check if this file's and and the InputFile's
Packit 0d464f
   // headers are compatible.
Packit 0d464f
   //
Packit 0d464f
Packit 0d464f
   const Header &hdr = _data->header;
Packit 0d464f
   const Header &inHdr = in.header();
Packit 0d464f
Packit 0d464f
   
Packit 0d464f
   
Packit 0d464f
   if (!(hdr.tileDescription() == inHdr.tileDescription()))
Packit 0d464f
        THROW (IEX_NAMESPACE::ArgExc, "Quick pixel copy from image "
Packit 0d464f
                            "file \"" << in.fileName() << "\" to image "
Packit 0d464f
                            "file \"" << fileName() << "\" failed. "
Packit 0d464f
                            "The files have different tile descriptions.");
Packit 0d464f
Packit 0d464f
   if (!(hdr.dataWindow() == inHdr.dataWindow()))
Packit 0d464f
        THROW (IEX_NAMESPACE::ArgExc, "Cannot copy pixels from image "
Packit 0d464f
                            "file \"" << in.fileName() << "\" to image "
Packit 0d464f
                            "file \"" << fileName() << "\". The "
Packit 0d464f
                            "files have different data windows.");
Packit 0d464f
Packit 0d464f
    if (!(hdr.lineOrder() == inHdr.lineOrder()))
Packit 0d464f
        THROW (IEX_NAMESPACE::ArgExc, "Quick pixel copy from image "
Packit 0d464f
                            "file \"" << in.fileName() << "\" to image "
Packit 0d464f
                            "file \"" << fileName() << "\" failed. "
Packit 0d464f
                            "The files have different line orders.");
Packit 0d464f
Packit 0d464f
    if (!(hdr.compression() == inHdr.compression()))
Packit 0d464f
        THROW (IEX_NAMESPACE::ArgExc, "Quick pixel copy from image "
Packit 0d464f
                            "file \"" << in.fileName() << "\" to image "
Packit 0d464f
                            "file \"" << fileName() << "\" failed. "
Packit 0d464f
                            "The files use different compression methods.");
Packit 0d464f
Packit 0d464f
    if (!(hdr.channels() == inHdr.channels()))
Packit 0d464f
        THROW (IEX_NAMESPACE::ArgExc, "Quick pixel copy from image "
Packit 0d464f
                             "file \"" << in.fileName() << "\" to image "
Packit 0d464f
                             "file \"" << fileName() << "\" "
Packit 0d464f
                             "failed.  The files have different channel "
Packit 0d464f
                             "lists.");
Packit 0d464f
Packit 0d464f
Packit 0d464f
    // Verify that no pixel data have been written to this file yet.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (!_data->tileOffsets.isEmpty())
Packit 0d464f
        THROW (IEX_NAMESPACE::LogicExc, "Quick pixel copy from image "
Packit 0d464f
                              "file \"" << in.fileName() << "\" to image "
Packit 0d464f
                              "file \"" << _data->_streamData->os->fileName() << "\" "
Packit 0d464f
                              "failed. \"" << fileName() << "\" "
Packit 0d464f
                              "already contains pixel data.");
Packit 0d464f
Packit 0d464f
 
Packit 0d464f
    int numAllTiles = in.totalTiles();                              
Packit 0d464f
                              
Packit 0d464f
    Lock lock (*_data->_streamData);
Packit 0d464f
    
Packit 0d464f
    //
Packit 0d464f
    // special handling for random tiles
Packit 0d464f
    //
Packit 0d464f
    
Packit 0d464f
    vector<int> dx_list(_data->lineOrder==RANDOM_Y ? numAllTiles : 1);
Packit 0d464f
    vector<int> dy_list(_data->lineOrder==RANDOM_Y ? numAllTiles : 1);
Packit 0d464f
    vector<int> lx_list(_data->lineOrder==RANDOM_Y ? numAllTiles : 1);
Packit 0d464f
    vector<int> ly_list(_data->lineOrder==RANDOM_Y ? numAllTiles : 1);
Packit 0d464f
    
Packit 0d464f
    if(_data->lineOrder==RANDOM_Y)
Packit 0d464f
    {
Packit 0d464f
        in.getTileOrder(&dx_list[0],&dy_list[0],&lx_list[0],&ly_list[0]);
Packit 0d464f
        _data->nextTileToWrite.dx=dx_list[0];
Packit 0d464f
        _data->nextTileToWrite.dy=dy_list[0];
Packit 0d464f
        _data->nextTileToWrite.lx=lx_list[0];
Packit 0d464f
        _data->nextTileToWrite.ly=ly_list[0];
Packit 0d464f
    }
Packit 0d464f
    
Packit 0d464f
Packit 0d464f
    vector<char> data(4096);
Packit 0d464f
    for (int i = 0; i < numAllTiles; ++i)
Packit 0d464f
    {
Packit 0d464f
Packit 0d464f
        int dx = _data->nextTileToWrite.dx;
Packit 0d464f
        int dy = _data->nextTileToWrite.dy;
Packit 0d464f
        int lx = _data->nextTileToWrite.lx;
Packit 0d464f
        int ly = _data->nextTileToWrite.ly;
Packit 0d464f
Packit 0d464f
        Int64 dataSize = data.size();
Packit 0d464f
Packit 0d464f
        in.rawTileData (dx, dy, lx, ly, &data[0], dataSize);
Packit 0d464f
        if(dataSize>data.size())
Packit 0d464f
        {
Packit 0d464f
            data.resize(dataSize);
Packit 0d464f
            in.rawTileData (dx, dy, lx, ly, &data[0], dataSize);
Packit 0d464f
        }
Packit 0d464f
        Int64 sampleCountTableSize = *(Int64 *)(&data[0] + 16);
Packit 0d464f
        Int64 pixelDataSize = *(Int64 *)(&data[0] + 24);
Packit 0d464f
        Int64 unpackedPixelDataSize = *(Int64 *)(&data[0] + 32);
Packit 0d464f
        char * sampleCountTable = &data[0]+40;
Packit 0d464f
        char * pixelData = sampleCountTable + sampleCountTableSize;
Packit 0d464f
        
Packit 0d464f
        writeTileData (_data, dx, dy, lx, ly, pixelData, pixelDataSize,unpackedPixelDataSize,sampleCountTable,sampleCountTableSize);
Packit 0d464f
        
Packit 0d464f
        
Packit 0d464f
        if(_data->lineOrder==RANDOM_Y)
Packit 0d464f
        {
Packit 0d464f
            if(i
Packit 0d464f
            {
Packit 0d464f
              _data->nextTileToWrite.dx=dx_list[i+1];
Packit 0d464f
              _data->nextTileToWrite.dy=dy_list[i+1];
Packit 0d464f
              _data->nextTileToWrite.lx=lx_list[i+1];
Packit 0d464f
              _data->nextTileToWrite.ly=ly_list[i+1];
Packit 0d464f
            }
Packit 0d464f
        }else{   
Packit 0d464f
          _data->nextTileToWrite = _data->nextTileCoord (_data->nextTileToWrite);
Packit 0d464f
        }
Packit 0d464f
        
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepTiledOutputFile::copyPixels (DeepTiledInputPart &in)
Packit 0d464f
{
Packit 0d464f
  copyPixels(*in.file);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
unsigned int
Packit 0d464f
DeepTiledOutputFile::tileXSize () const
Packit 0d464f
{
Packit 0d464f
    return _data->tileDesc.xSize;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
unsigned int
Packit 0d464f
DeepTiledOutputFile::tileYSize () const
Packit 0d464f
{
Packit 0d464f
    return _data->tileDesc.ySize;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
LevelMode
Packit 0d464f
DeepTiledOutputFile::levelMode () const
Packit 0d464f
{
Packit 0d464f
    return _data->tileDesc.mode;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
LevelRoundingMode
Packit 0d464f
DeepTiledOutputFile::levelRoundingMode () const
Packit 0d464f
{
Packit 0d464f
    return _data->tileDesc.roundingMode;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
DeepTiledOutputFile::numLevels () const
Packit 0d464f
{
Packit 0d464f
    if (levelMode() == RIPMAP_LEVELS)
Packit 0d464f
        THROW (IEX_NAMESPACE::LogicExc, "Error calling numLevels() on image "
Packit 0d464f
                              "file \"" << fileName() << "\" "
Packit 0d464f
                              "(numLevels() is not defined for RIPMAPs).");
Packit 0d464f
    return _data->numXLevels;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
DeepTiledOutputFile::numXLevels () const
Packit 0d464f
{
Packit 0d464f
    return _data->numXLevels;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
DeepTiledOutputFile::numYLevels () const
Packit 0d464f
{
Packit 0d464f
    return _data->numYLevels;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
bool
Packit 0d464f
DeepTiledOutputFile::isValidLevel (int lx, int ly) const
Packit 0d464f
{
Packit 0d464f
    if (lx < 0 || ly < 0)
Packit 0d464f
        return false;
Packit 0d464f
Packit 0d464f
    if (levelMode() == MIPMAP_LEVELS && lx != ly)
Packit 0d464f
        return false;
Packit 0d464f
Packit 0d464f
    if (lx >= numXLevels() || ly >= numYLevels())
Packit 0d464f
        return false;
Packit 0d464f
Packit 0d464f
    return true;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
DeepTiledOutputFile::levelWidth (int lx) const
Packit 0d464f
{
Packit 0d464f
    try
Packit 0d464f
    {
Packit 0d464f
        int retVal = levelSize (_data->minX, _data->maxX, lx,
Packit 0d464f
                                _data->tileDesc.roundingMode);
Packit 0d464f
Packit 0d464f
        return retVal;
Packit 0d464f
    }
Packit 0d464f
    catch (IEX_NAMESPACE::BaseExc &e)
Packit 0d464f
    {
Packit 0d464f
        REPLACE_EXC (e, "Error calling levelWidth() on image "
Packit 0d464f
                        "file \"" << fileName() << "\". " << e);
Packit 0d464f
        throw;
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
DeepTiledOutputFile::levelHeight (int ly) const
Packit 0d464f
{
Packit 0d464f
    try
Packit 0d464f
    {
Packit 0d464f
        return levelSize (_data->minY, _data->maxY, ly,
Packit 0d464f
                          _data->tileDesc.roundingMode);
Packit 0d464f
    }
Packit 0d464f
    catch (IEX_NAMESPACE::BaseExc &e)
Packit 0d464f
    {
Packit 0d464f
        REPLACE_EXC (e, "Error calling levelHeight() on image "
Packit 0d464f
                        "file \"" << fileName() << "\". " << e);
Packit 0d464f
        throw;
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
DeepTiledOutputFile::numXTiles (int lx) const
Packit 0d464f
{
Packit 0d464f
    if (lx < 0 || lx >= _data->numXLevels)
Packit 0d464f
        THROW (IEX_NAMESPACE::LogicExc, "Error calling numXTiles() on image "
Packit 0d464f
                              "file \"" << _data->_streamData->os->fileName() << "\" "
Packit 0d464f
                              "(Argument is not in valid range).");
Packit 0d464f
Packit 0d464f
    return _data->numXTiles[lx];
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
DeepTiledOutputFile::numYTiles (int ly) const
Packit 0d464f
{
Packit 0d464f
   if (ly < 0 || ly >= _data->numYLevels)
Packit 0d464f
        THROW (IEX_NAMESPACE::LogicExc, "Error calling numXTiles() on image "
Packit 0d464f
                              "file \"" << _data->_streamData->os->fileName() << "\" "
Packit 0d464f
                              "(Argument is not in valid range).");
Packit 0d464f
Packit 0d464f
    return _data->numYTiles[ly];
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
Box2i
Packit 0d464f
DeepTiledOutputFile::dataWindowForLevel (int l) const
Packit 0d464f
{
Packit 0d464f
    return dataWindowForLevel (l, l);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
Box2i
Packit 0d464f
DeepTiledOutputFile::dataWindowForLevel (int lx, int ly) const
Packit 0d464f
{
Packit 0d464f
    try
Packit 0d464f
    {
Packit 0d464f
        return OPENEXR_IMF_INTERNAL_NAMESPACE::dataWindowForLevel (
Packit 0d464f
                _data->tileDesc,
Packit 0d464f
                _data->minX, _data->maxX,
Packit 0d464f
                _data->minY, _data->maxY,
Packit 0d464f
                lx, ly);
Packit 0d464f
    }
Packit 0d464f
    catch (IEX_NAMESPACE::BaseExc &e)
Packit 0d464f
    {
Packit 0d464f
        REPLACE_EXC (e, "Error calling dataWindowForLevel() on image "
Packit 0d464f
                        "file \"" << fileName() << "\". " << e);
Packit 0d464f
        throw;
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
Box2i
Packit 0d464f
DeepTiledOutputFile::dataWindowForTile (int dx, int dy, int l) const
Packit 0d464f
{
Packit 0d464f
    return dataWindowForTile (dx, dy, l, l);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
Box2i
Packit 0d464f
DeepTiledOutputFile::dataWindowForTile (int dx, int dy, int lx, int ly) const
Packit 0d464f
{
Packit 0d464f
    try
Packit 0d464f
    {
Packit 0d464f
        if (!isValidTile (dx, dy, lx, ly))
Packit 0d464f
            throw IEX_NAMESPACE::ArgExc ("Arguments not in valid range.");
Packit 0d464f
Packit 0d464f
        return OPENEXR_IMF_INTERNAL_NAMESPACE::dataWindowForTile (
Packit 0d464f
                _data->tileDesc,
Packit 0d464f
                _data->minX, _data->maxX,
Packit 0d464f
                _data->minY, _data->maxY,
Packit 0d464f
                dx, dy,
Packit 0d464f
                lx, ly);
Packit 0d464f
    }
Packit 0d464f
    catch (IEX_NAMESPACE::BaseExc &e)
Packit 0d464f
    {
Packit 0d464f
        REPLACE_EXC (e, "Error calling dataWindowForTile() on image "
Packit 0d464f
                        "file \"" << fileName() << "\". " << e);
Packit 0d464f
        throw;
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
bool
Packit 0d464f
DeepTiledOutputFile::isValidTile (int dx, int dy, int lx, int ly) const
Packit 0d464f
{
Packit 0d464f
    return ((lx < _data->numXLevels && lx >= 0) &&
Packit 0d464f
            (ly < _data->numYLevels && ly >= 0) &&
Packit 0d464f
            (dx < _data->numXTiles[lx] && dx >= 0) &&
Packit 0d464f
            (dy < _data->numYTiles[ly] && dy >= 0));
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepTiledOutputFile::updatePreviewImage (const PreviewRgba newPixels[])
Packit 0d464f
{
Packit 0d464f
    Lock lock (*_data->_streamData);
Packit 0d464f
Packit 0d464f
    if (_data->previewPosition <= 0)
Packit 0d464f
        THROW (IEX_NAMESPACE::LogicExc, "Cannot update preview image pixels. "
Packit 0d464f
                              "File \"" << fileName() << "\" does not "
Packit 0d464f
                              "contain a preview image.");
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Store the new pixels in the header's preview image attribute.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    PreviewImageAttribute &pia =
Packit 0d464f
        _data->header.typedAttribute <PreviewImageAttribute> ("preview");
Packit 0d464f
Packit 0d464f
    PreviewImage &pi = pia.value();
Packit 0d464f
    PreviewRgba *pixels = pi.pixels();
Packit 0d464f
    int numPixels = pi.width() * pi.height();
Packit 0d464f
Packit 0d464f
    for (int i = 0; i < numPixels; ++i)
Packit 0d464f
        pixels[i] = newPixels[i];
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Save the current file position, jump to the position in
Packit 0d464f
    // the file where the preview image starts, store the new
Packit 0d464f
    // preview image, and jump back to the saved file position.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    Int64 savedPosition = _data->_streamData->os->tellp();
Packit 0d464f
Packit 0d464f
    try
Packit 0d464f
    {
Packit 0d464f
        _data->_streamData->os->seekp (_data->previewPosition);
Packit 0d464f
        pia.writeValueTo (*_data->_streamData->os, _data->version);
Packit 0d464f
        _data->_streamData->os->seekp (savedPosition);
Packit 0d464f
    }
Packit 0d464f
    catch (IEX_NAMESPACE::BaseExc &e)
Packit 0d464f
    {
Packit 0d464f
        REPLACE_EXC (e, "Cannot update preview image pixels for "
Packit 0d464f
                        "file \"" << fileName() << "\". " << e);
Packit 0d464f
        throw;
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepTiledOutputFile::breakTile
Packit 0d464f
    (int dx, int dy,
Packit 0d464f
     int lx, int ly,
Packit 0d464f
     int offset,
Packit 0d464f
     int length,
Packit 0d464f
     char c)
Packit 0d464f
{
Packit 0d464f
    Lock lock (*_data->_streamData);
Packit 0d464f
Packit 0d464f
    Int64 position = _data->tileOffsets (dx, dy, lx, ly);
Packit 0d464f
Packit 0d464f
    if (!position)
Packit 0d464f
        THROW (IEX_NAMESPACE::ArgExc,
Packit 0d464f
               "Cannot overwrite tile "
Packit 0d464f
               "(" << dx << ", " << dy << ", " << lx << "," << ly << "). "
Packit 0d464f
               "The tile has not yet been stored in "
Packit 0d464f
               "file \"" << fileName() << "\".");
Packit 0d464f
Packit 0d464f
    _data->_streamData->currentPosition = 0;
Packit 0d464f
    _data->_streamData->os->seekp (position + offset);
Packit 0d464f
Packit 0d464f
    for (int i = 0; i < length; ++i)
Packit 0d464f
        _data->_streamData->os->write (&c, 1);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT