Blame IlmImf/ImfDeepTiledInputFile.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 DeepTiledInputFile
Packit 0d464f
//
Packit 0d464f
//-----------------------------------------------------------------------------
Packit 0d464f
Packit 0d464f
#include <ImfDeepTiledInputFile.h>
Packit 0d464f
#include <ImfTileDescriptionAttribute.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 "ImathBox.h"
Packit 0d464f
#include <ImfXdr.h>
Packit 0d464f
#include <ImfConvert.h>
Packit 0d464f
#include <ImfVersion.h>
Packit 0d464f
#include <ImfTileOffsets.h>
Packit 0d464f
#include <ImfThreading.h>
Packit 0d464f
#include <ImfPartType.h>
Packit 0d464f
#include <ImfMultiPartInputFile.h>
Packit 0d464f
#include "IlmThreadPool.h"
Packit 0d464f
#include "IlmThreadSemaphore.h"
Packit 0d464f
#include "IlmThreadMutex.h"
Packit 0d464f
#include "ImfInputStreamMutex.h"
Packit 0d464f
#include "ImfInputPartData.h"
Packit 0d464f
#include "ImathVec.h"
Packit 0d464f
#include "Iex.h"
Packit 0d464f
#include <string>
Packit 0d464f
#include <vector>
Packit 0d464f
#include <algorithm>
Packit 0d464f
#include <assert.h>
Packit 0d464f
#include <limits>
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::min;
Packit 0d464f
using std::max;
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 TInSliceInfo
Packit 0d464f
{
Packit 0d464f
    PixelType           typeInFrameBuffer;
Packit 0d464f
    PixelType           typeInFile;
Packit 0d464f
    char*               pointerArrayBase;
Packit 0d464f
    size_t              xStride;
Packit 0d464f
    size_t              yStride;
Packit 0d464f
    ptrdiff_t           sampleStride;
Packit 0d464f
    bool                fill;
Packit 0d464f
    bool                skip;
Packit 0d464f
    double              fillValue;
Packit 0d464f
    int                 xTileCoords;
Packit 0d464f
    int                 yTileCoords;
Packit 0d464f
Packit 0d464f
    TInSliceInfo (PixelType typeInFrameBuffer = HALF,
Packit 0d464f
                  char * base = NULL,
Packit 0d464f
                  PixelType typeInFile = HALF,
Packit 0d464f
                  size_t xStride = 0,
Packit 0d464f
                  size_t yStride = 0,
Packit 0d464f
                  ptrdiff_t sampleStride = 0,
Packit 0d464f
                  bool fill = false,
Packit 0d464f
                  bool skip = false,
Packit 0d464f
                  double fillValue = 0.0,
Packit 0d464f
                  int xTileCoords = 0,
Packit 0d464f
                  int yTileCoords = 0);
Packit 0d464f
};
Packit 0d464f
Packit 0d464f
Packit 0d464f
TInSliceInfo::TInSliceInfo (PixelType tifb,
Packit 0d464f
                            char * b,
Packit 0d464f
                            PixelType tifl,
Packit 0d464f
                            size_t xs, size_t ys,
Packit 0d464f
                            ptrdiff_t spst,
Packit 0d464f
                            bool f, bool s,
Packit 0d464f
                            double fv,
Packit 0d464f
                            int xtc,
Packit 0d464f
                            int ytc)
Packit 0d464f
:
Packit 0d464f
    typeInFrameBuffer (tifb),
Packit 0d464f
    typeInFile (tifl),
Packit 0d464f
    pointerArrayBase (b),
Packit 0d464f
    xStride (xs),
Packit 0d464f
    yStride (ys),
Packit 0d464f
    sampleStride (spst),
Packit 0d464f
    fill (f),
Packit 0d464f
    skip (s),
Packit 0d464f
    fillValue (fv),
Packit 0d464f
    xTileCoords (xtc),
Packit 0d464f
    yTileCoords (ytc)
Packit 0d464f
{
Packit 0d464f
    // empty
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
struct TileBuffer
Packit 0d464f
{
Packit 0d464f
    Array2D<unsigned int>       sampleCount;
Packit 0d464f
    const char *                uncompressedData;
Packit 0d464f
    char *                      buffer;
Packit 0d464f
    Int64                         dataSize;
Packit 0d464f
    Int64                         uncompressedDataSize;
Packit 0d464f
    Compressor *                compressor;
Packit 0d464f
    Compressor::Format          format;
Packit 0d464f
    int                         dx;
Packit 0d464f
    int                         dy;
Packit 0d464f
    int                         lx;
Packit 0d464f
    int                         ly;
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
    uncompressedData (0),
Packit 0d464f
    buffer (0),
Packit 0d464f
    dataSize (0),
Packit 0d464f
    compressor (0),
Packit 0d464f
    format (defaultFormat (compressor)),
Packit 0d464f
    dx (-1),
Packit 0d464f
    dy (-1),
Packit 0d464f
    lx (-1),
Packit 0d464f
    ly (-1),
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
    delete compressor;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
} // namespace
Packit 0d464f
Packit 0d464f
Packit 0d464f
class MultiPartInputFile;
Packit 0d464f
Packit 0d464f
Packit 0d464f
//
Packit 0d464f
// struct TiledInputFile::Data stores things that will be
Packit 0d464f
// needed between calls to readTile()
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
struct DeepTiledInputFile::Data: public Mutex
Packit 0d464f
{
Packit 0d464f
    Header          header;                         // the image header
Packit 0d464f
    TileDescription tileDesc;                       // describes the tile layout
Packit 0d464f
    int             version;                        // file's version
Packit 0d464f
    DeepFrameBuffer frameBuffer;                    // framebuffer to write into
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
    bool            fileIsComplete;                 // True if no tiles are missing
Packit 0d464f
                                                    // in the file
Packit 0d464f
Packit 0d464f
    vector<TInSliceInfo*> slices;                    // info about channels in file
Packit 0d464f
Packit 0d464f
                                                    // ourselves? or does someone
Packit 0d464f
                                                    // else do it?
Packit 0d464f
Packit 0d464f
    int             partNumber;                     // part number
Packit 0d464f
Packit 0d464f
    bool            multiPartBackwardSupport;       // if we are reading a multipart file
Packit 0d464f
                                                    // using OpenEXR 1.7 API
Packit 0d464f
Packit 0d464f
    int             numThreads;                     // number of threads
Packit 0d464f
Packit 0d464f
    MultiPartInputFile* multiPartFile;              // the MultiPartInputFile used to
Packit 0d464f
                                                    // support backward compatibility
Packit 0d464f
Packit 0d464f
    vector<TileBuffer*> tileBuffers;                // each holds a single tile
Packit 0d464f
Packit 0d464f
    bool            memoryMapped;                   // if the stream is memory mapped
Packit 0d464f
Packit 0d464f
    char*           sampleCountSliceBase;           // pointer to the start of
Packit 0d464f
                                                    // the sample count array
Packit 0d464f
    ptrdiff_t       sampleCountXStride;             // x stride of the sample count array
Packit 0d464f
    ptrdiff_t       sampleCountYStride;             // y stride of the sample count array
Packit 0d464f
Packit 0d464f
    int             sampleCountXTileCoords;         // the value of xTileCoords from the
Packit 0d464f
                                                    // sample count slice
Packit 0d464f
    int             sampleCountYTileCoords;         // the value of yTileCoords from the
Packit 0d464f
                                                    // sample count slice
Packit 0d464f
Packit 0d464f
    Array<char>     sampleCountTableBuffer;         // the buffer for sample count table
Packit 0d464f
Packit 0d464f
    Compressor*     sampleCountTableComp;           // the decompressor for sample count table
Packit 0d464f
Packit 0d464f
    Int64           maxSampleCountTableSize;        // the max size in bytes for a pixel
Packit 0d464f
                                                    // sample count table
Packit 0d464f
    int             combinedSampleSize;             // total size of all channels combined to check sampletable size
Packit 0d464f
                                                    
Packit 0d464f
    InputStreamMutex *  _streamData;
Packit 0d464f
    bool                _deleteStream; // should we delete the stream
Packit 0d464f
     Data (int numThreads);
Packit 0d464f
    ~Data ();
Packit 0d464f
Packit 0d464f
    inline TileBuffer * getTileBuffer (int number);
Packit 0d464f
                                                    // hash function from tile indices
Packit 0d464f
                                                    // into our 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
Packit 0d464f
Packit 0d464f
DeepTiledInputFile::Data::Data (int numThreads):
Packit 0d464f
    numXTiles (0),
Packit 0d464f
    numYTiles (0),
Packit 0d464f
    partNumber (-1),
Packit 0d464f
    multiPartBackwardSupport(false),
Packit 0d464f
    numThreads(numThreads),
Packit 0d464f
    memoryMapped(false),
Packit 0d464f
    _streamData(NULL),
Packit 0d464f
    _deleteStream(false)
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
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
DeepTiledInputFile::Data::~Data ()
Packit 0d464f
{
Packit 0d464f
    delete [] numXTiles;
Packit 0d464f
    delete [] numYTiles;
Packit 0d464f
Packit 0d464f
    for (size_t i = 0; i < tileBuffers.size(); i++)
Packit 0d464f
        delete tileBuffers[i];
Packit 0d464f
Packit 0d464f
    if (multiPartBackwardSupport)
Packit 0d464f
        delete multiPartFile;
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
TileBuffer*
Packit 0d464f
DeepTiledInputFile::Data::getTileBuffer (int number)
Packit 0d464f
{
Packit 0d464f
    return tileBuffers[number % tileBuffers.size()];
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int&
Packit 0d464f
DeepTiledInputFile::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
namespace {
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
readTileData (InputStreamMutex *streamData,
Packit 0d464f
              DeepTiledInputFile::Data *ifd,
Packit 0d464f
              int dx, int dy,
Packit 0d464f
              int lx, int ly,
Packit 0d464f
              char *&buffer,
Packit 0d464f
              Int64 &dataSize,
Packit 0d464f
              Int64 &unpackedDataSize)
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // Read a single tile block from the file and into the array pointed
Packit 0d464f
    // to by buffer.  If the file is memory-mapped, then we change where
Packit 0d464f
    // buffer points instead of writing into the array (hence buffer needs
Packit 0d464f
    // to be a reference to a char *).
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Look up the location for this tile in the Index and
Packit 0d464f
    // seek to that position if necessary
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    Int64 tileOffset = ifd->tileOffsets (dx, dy, lx, ly);
Packit 0d464f
Packit 0d464f
    if (tileOffset == 0)
Packit 0d464f
    {
Packit 0d464f
        THROW (IEX_NAMESPACE::InputExc, "Tile (" << dx << ", " << dy << ", " <<
Packit 0d464f
                              lx << ", " << ly << ") is missing.");
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // In a multi-part file, the next chunk does not need to
Packit 0d464f
    // belong to the same part, so we have to compare the
Packit 0d464f
    // offset here.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if ( !isMultiPart(ifd->version) )
Packit 0d464f
    {
Packit 0d464f
        if (streamData->currentPosition != tileOffset)
Packit 0d464f
            streamData->is->seekg(tileOffset);
Packit 0d464f
    }
Packit 0d464f
    else
Packit 0d464f
    {
Packit 0d464f
        //
Packit 0d464f
        // In a multi-part file, the file pointer may be moved by other
Packit 0d464f
        // parts, so we have to ask tellg() where we are.
Packit 0d464f
        //
Packit 0d464f
        if (streamData->is->tellg() != tileOffset)
Packit 0d464f
            streamData->is->seekg (tileOffset);
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Read the first few bytes of the tile (the header).
Packit 0d464f
    // Verify that the tile coordinates and the level number
Packit 0d464f
    // are correct.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    int tileXCoord, tileYCoord, levelX, levelY;
Packit 0d464f
Packit 0d464f
    if (isMultiPart(ifd->version))
Packit 0d464f
    {
Packit 0d464f
        int partNumber;
Packit 0d464f
        Xdr::read <StreamIO> (*streamData->is, partNumber);
Packit 0d464f
        if (partNumber != ifd->partNumber)
Packit 0d464f
        {
Packit 0d464f
            THROW (IEX_NAMESPACE::ArgExc, "Unexpected part number " << partNumber
Packit 0d464f
                   << ", should be " << ifd->partNumber << ".");
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    Xdr::read <StreamIO> (*streamData->is, tileXCoord);
Packit 0d464f
    Xdr::read <StreamIO> (*streamData->is, tileYCoord);
Packit 0d464f
    Xdr::read <StreamIO> (*streamData->is, levelX);
Packit 0d464f
    Xdr::read <StreamIO> (*streamData->is, levelY);
Packit 0d464f
Packit 0d464f
    Int64 tableSize;
Packit 0d464f
    Xdr::read <StreamIO> (*streamData->is, tableSize);
Packit 0d464f
Packit 0d464f
    Xdr::read <StreamIO> (*streamData->is, dataSize);
Packit 0d464f
    Xdr::read <StreamIO> (*streamData->is, unpackedDataSize);
Packit 0d464f
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Skip the pixel sample count table because we have read this data.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    Xdr::skip <StreamIO> (*streamData->is, tableSize);
Packit 0d464f
Packit 0d464f
Packit 0d464f
    if (tileXCoord != dx)
Packit 0d464f
        throw IEX_NAMESPACE::InputExc ("Unexpected tile x coordinate.");
Packit 0d464f
Packit 0d464f
    if (tileYCoord != dy)
Packit 0d464f
        throw IEX_NAMESPACE::InputExc ("Unexpected tile y coordinate.");
Packit 0d464f
Packit 0d464f
    if (levelX != lx)
Packit 0d464f
        throw IEX_NAMESPACE::InputExc ("Unexpected tile x level number coordinate.");
Packit 0d464f
Packit 0d464f
    if (levelY != ly)
Packit 0d464f
        throw IEX_NAMESPACE::InputExc ("Unexpected tile y level number coordinate.");
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Read the pixel data.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (streamData->is->isMemoryMapped ())
Packit 0d464f
        buffer = streamData->is->readMemoryMapped (dataSize);
Packit 0d464f
    else
Packit 0d464f
    {
Packit 0d464f
        // (TODO) check if the packed data size is too big?
Packit 0d464f
        // (TODO) better memory management here. Don't delete buffer everytime.
Packit 0d464f
        if (buffer != 0) delete[] buffer;
Packit 0d464f
        buffer = new char[dataSize];
Packit 0d464f
        streamData->is->read (buffer, dataSize);
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Keep track of which tile is the next one in
Packit 0d464f
    // the file, so that we can avoid redundant seekg()
Packit 0d464f
    // operations (seekg() can be fairly expensive).
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    streamData->currentPosition = tileOffset + 4 * Xdr::size<int>() +
Packit 0d464f
                                  3 * Xdr::size<Int64>()            +
Packit 0d464f
                                  tableSize                         +
Packit 0d464f
                                  dataSize;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
readNextTileData (InputStreamMutex *streamData,
Packit 0d464f
                  DeepTiledInputFile::Data *ifd,
Packit 0d464f
                  int &dx, int &dy,
Packit 0d464f
                  int &lx, int &ly,
Packit 0d464f
                  char * & buffer,
Packit 0d464f
                  Int64 &dataSize,
Packit 0d464f
                  Int64 &unpackedDataSize)
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // Read the next tile block from the file
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Read the first few bytes of the tile (the header).
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    Xdr::read <StreamIO> (*streamData->is, dx);
Packit 0d464f
    Xdr::read <StreamIO> (*streamData->is, dy);
Packit 0d464f
    Xdr::read <StreamIO> (*streamData->is, lx);
Packit 0d464f
    Xdr::read <StreamIO> (*streamData->is, ly);
Packit 0d464f
Packit 0d464f
    Int64 tableSize;
Packit 0d464f
    Xdr::read <StreamIO> (*streamData->is, tableSize);
Packit 0d464f
Packit 0d464f
    Xdr::read <StreamIO> (*streamData->is, dataSize);
Packit 0d464f
    Xdr::read <StreamIO> (*streamData->is, unpackedDataSize);
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Skip the pixel sample count table because we have read this data.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    Xdr::skip <StreamIO> (*streamData->is, tableSize);
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Read the pixel data.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    streamData->is->read (buffer, dataSize);
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Keep track of which tile is the next one in
Packit 0d464f
    // the file, so that we can avoid redundant seekg()
Packit 0d464f
    // operations (seekg() can be fairly expensive).
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    streamData->currentPosition += 4 * Xdr::size<int>()   +
Packit 0d464f
                                   3 * Xdr::size<Int64>() +
Packit 0d464f
                                   tableSize              +
Packit 0d464f
                                   dataSize;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
//
Packit 0d464f
// A TileBufferTask encapsulates the task of uncompressing
Packit 0d464f
// a single tile and copying it into the frame buffer.
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
class TileBufferTask : public Task
Packit 0d464f
{
Packit 0d464f
  public:
Packit 0d464f
Packit 0d464f
    TileBufferTask (TaskGroup *group,
Packit 0d464f
                    DeepTiledInputFile::Data *ifd,
Packit 0d464f
                    TileBuffer *tileBuffer);
Packit 0d464f
Packit 0d464f
    virtual ~TileBufferTask ();
Packit 0d464f
Packit 0d464f
    virtual void                execute ();
Packit 0d464f
Packit 0d464f
  private:
Packit 0d464f
Packit 0d464f
    DeepTiledInputFile::Data *      _ifd;
Packit 0d464f
    TileBuffer *                _tileBuffer;
Packit 0d464f
};
Packit 0d464f
Packit 0d464f
Packit 0d464f
TileBufferTask::TileBufferTask
Packit 0d464f
    (TaskGroup *group,
Packit 0d464f
     DeepTiledInputFile::Data *ifd,
Packit 0d464f
     TileBuffer *tileBuffer)
Packit 0d464f
:
Packit 0d464f
    Task (group),
Packit 0d464f
    _ifd (ifd),
Packit 0d464f
    _tileBuffer (tileBuffer)
Packit 0d464f
{
Packit 0d464f
    // empty
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
        // Calculate information about the tile
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        Box2i tileRange = OPENEXR_IMF_INTERNAL_NAMESPACE::dataWindowForTile (
Packit 0d464f
                _ifd->tileDesc,
Packit 0d464f
                _ifd->minX, _ifd->maxX,
Packit 0d464f
                _ifd->minY, _ifd->maxY,
Packit 0d464f
                _tileBuffer->dx,
Packit 0d464f
                _tileBuffer->dy,
Packit 0d464f
                _tileBuffer->lx,
Packit 0d464f
                _tileBuffer->ly);
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // Get the size of the tile.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        Array<unsigned int> numPixelsPerScanLine;
Packit 0d464f
        numPixelsPerScanLine.resizeErase(tileRange.max.y - tileRange.min.y + 1);
Packit 0d464f
Packit 0d464f
        int sizeOfTile = 0;
Packit 0d464f
        int maxBytesPerTileLine = 0;
Packit 0d464f
Packit 0d464f
        for (int y = tileRange.min.y; y <= tileRange.max.y; y++)
Packit 0d464f
        {
Packit 0d464f
            numPixelsPerScanLine[y - tileRange.min.y] = 0;
Packit 0d464f
Packit 0d464f
            int bytesPerLine = 0;
Packit 0d464f
Packit 0d464f
            for (int x = tileRange.min.x; x <= tileRange.max.x; x++)
Packit 0d464f
            {
Packit 0d464f
                int xOffset = _ifd->sampleCountXTileCoords * tileRange.min.x;
Packit 0d464f
                int yOffset = _ifd->sampleCountYTileCoords * tileRange.min.y;
Packit 0d464f
Packit 0d464f
                int count = _ifd->getSampleCount(x - xOffset, y - yOffset);
Packit 0d464f
                for (unsigned int c = 0; c < _ifd->slices.size(); ++c)
Packit 0d464f
                {
Packit 0d464f
                    sizeOfTile += count * pixelTypeSize(_ifd->slices[c]->typeInFile);
Packit 0d464f
                    bytesPerLine += count * pixelTypeSize(_ifd->slices[c]->typeInFile);
Packit 0d464f
                }
Packit 0d464f
                numPixelsPerScanLine[y - tileRange.min.y] += count;
Packit 0d464f
            }
Packit 0d464f
Packit 0d464f
            if (bytesPerLine > maxBytesPerTileLine)
Packit 0d464f
                maxBytesPerTileLine = bytesPerLine;
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        // (TODO) don't do this every time.
Packit 0d464f
        if (_tileBuffer->compressor != 0)
Packit 0d464f
            delete _tileBuffer->compressor;
Packit 0d464f
        _tileBuffer->compressor = newTileCompressor
Packit 0d464f
                                  (_ifd->header.compression(),
Packit 0d464f
                                   maxBytesPerTileLine,
Packit 0d464f
                                   _ifd->tileDesc.ySize,
Packit 0d464f
                                   _ifd->header);
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // Uncompress the data, if necessary
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        if (_tileBuffer->compressor && _tileBuffer->dataSize < Int64(sizeOfTile))
Packit 0d464f
        {
Packit 0d464f
            _tileBuffer->format = _tileBuffer->compressor->format();
Packit 0d464f
Packit 0d464f
            _tileBuffer->dataSize = _tileBuffer->compressor->uncompressTile
Packit 0d464f
                (_tileBuffer->buffer, _tileBuffer->dataSize,
Packit 0d464f
                 tileRange, _tileBuffer->uncompressedData);
Packit 0d464f
        }
Packit 0d464f
        else
Packit 0d464f
        {
Packit 0d464f
            //
Packit 0d464f
            // If the line is uncompressed, it's in XDR format,
Packit 0d464f
            // regardless of the compressor's output format.
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            _tileBuffer->format = Compressor::XDR;
Packit 0d464f
            _tileBuffer->uncompressedData = _tileBuffer->buffer;
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // Convert the tile of pixel data back from the machine-independent
Packit 0d464f
        // representation, and store the result in the frame buffer.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        const char *readPtr = _tileBuffer->uncompressedData;
Packit 0d464f
                                                        // points to where we
Packit 0d464f
                                                        // read from in the
Packit 0d464f
                                                        // tile block
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // Iterate over the scan lines in the tile.
Packit 0d464f
        //
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 < _ifd->slices.size(); ++i)
Packit 0d464f
            {
Packit 0d464f
                TInSliceInfo &slice = *_ifd->slices[i];
Packit 0d464f
Packit 0d464f
                //
Packit 0d464f
                // These offsets are used to facilitate both
Packit 0d464f
                // absolute and tile-relative pixel coordinates.
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                int xOffsetForData = (slice.xTileCoords == 0) ? 0 : tileRange.min.x;
Packit 0d464f
                int yOffsetForData = (slice.yTileCoords == 0) ? 0 : tileRange.min.y;
Packit 0d464f
                int xOffsetForSampleCount =
Packit 0d464f
                        (_ifd->sampleCountXTileCoords == 0) ? 0 : tileRange.min.x;
Packit 0d464f
                int yOffsetForSampleCount =
Packit 0d464f
                        (_ifd->sampleCountYTileCoords == 0) ? 0 : tileRange.min.y;
Packit 0d464f
Packit 0d464f
                //
Packit 0d464f
                // Fill the frame buffer with pixel data.
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                if (slice.skip)
Packit 0d464f
                {
Packit 0d464f
                    //
Packit 0d464f
                    // The file contains data for this channel, but
Packit 0d464f
                    // the frame buffer contains no slice for this channel.
Packit 0d464f
                    //
Packit 0d464f
Packit 0d464f
                    skipChannel (readPtr, slice.typeInFile,
Packit 0d464f
                                 numPixelsPerScanLine[y - tileRange.min.y]);
Packit 0d464f
                }
Packit 0d464f
                else
Packit 0d464f
                {
Packit 0d464f
                    //
Packit 0d464f
                    // The frame buffer contains a slice for this channel.
Packit 0d464f
                    //
Packit 0d464f
Packit 0d464f
                    copyIntoDeepFrameBuffer (readPtr, slice.pointerArrayBase,
Packit 0d464f
                                             _ifd->sampleCountSliceBase,
Packit 0d464f
                                             _ifd->sampleCountXStride,
Packit 0d464f
                                             _ifd->sampleCountYStride,
Packit 0d464f
                                             y,
Packit 0d464f
                                             tileRange.min.x,
Packit 0d464f
                                             tileRange.max.x,
Packit 0d464f
                                             xOffsetForSampleCount, yOffsetForSampleCount,
Packit 0d464f
                                             xOffsetForData, yOffsetForData,
Packit 0d464f
                                             slice.sampleStride, 
Packit 0d464f
                                             slice.xStride,
Packit 0d464f
                                             slice.yStride,
Packit 0d464f
                                             slice.fill,
Packit 0d464f
                                             slice.fillValue, _tileBuffer->format,
Packit 0d464f
                                             slice.typeInFrameBuffer,
Packit 0d464f
                                             slice.typeInFile);
Packit 0d464f
                }
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
Packit 0d464f
TileBufferTask *
Packit 0d464f
newTileBufferTask
Packit 0d464f
    (TaskGroup *group,
Packit 0d464f
     DeepTiledInputFile::Data *ifd,
Packit 0d464f
     int number,
Packit 0d464f
     int dx, int dy,
Packit 0d464f
     int lx, int ly)
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // Wait for a tile buffer to become available,
Packit 0d464f
    // fill the buffer with raw data from the file,
Packit 0d464f
    // and create a new TileBufferTask whose execute()
Packit 0d464f
    // method will uncompress the tile and copy the
Packit 0d464f
    // tile's pixels into the frame buffer.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    TileBuffer *tileBuffer = ifd->getTileBuffer (number);
Packit 0d464f
Packit 0d464f
    try
Packit 0d464f
    {
Packit 0d464f
        tileBuffer->wait();
Packit 0d464f
Packit 0d464f
        tileBuffer->dx = dx;
Packit 0d464f
        tileBuffer->dy = dy;
Packit 0d464f
        tileBuffer->lx = lx;
Packit 0d464f
        tileBuffer->ly = ly;
Packit 0d464f
Packit 0d464f
        tileBuffer->uncompressedData = 0;
Packit 0d464f
Packit 0d464f
        readTileData (ifd->_streamData, ifd, dx, dy, lx, ly,
Packit 0d464f
                      tileBuffer->buffer,
Packit 0d464f
                      tileBuffer->dataSize,
Packit 0d464f
                      tileBuffer->uncompressedDataSize);
Packit 0d464f
    }
Packit 0d464f
    catch (...)
Packit 0d464f
    {
Packit 0d464f
        //
Packit 0d464f
        // Reading from the file caused an exception.
Packit 0d464f
        // Signal that the tile buffer is free, and
Packit 0d464f
        // re-throw the exception.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        tileBuffer->post();
Packit 0d464f
        throw;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    return new TileBufferTask (group, ifd, tileBuffer);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
} // namespace
Packit 0d464f
Packit 0d464f
Packit 0d464f
DeepTiledInputFile::DeepTiledInputFile (const char fileName[], int numThreads):
Packit 0d464f
    _data (new Data (numThreads))
Packit 0d464f
{
Packit 0d464f
    _data->_deleteStream=true;
Packit 0d464f
    //
Packit 0d464f
    // This constructor is called when a user
Packit 0d464f
    // explicitly wants to read a tiled file.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    IStream* is = 0;
Packit 0d464f
    try
Packit 0d464f
    {
Packit 0d464f
        is = new StdIFStream (fileName);
Packit 0d464f
        readMagicNumberAndVersionField(*is, _data->version);
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // Compatibility to read multpart file.
Packit 0d464f
        //
Packit 0d464f
        if (isMultiPart(_data->version))
Packit 0d464f
        {
Packit 0d464f
            compatibilityInitialize(*is);
Packit 0d464f
        }
Packit 0d464f
        else
Packit 0d464f
        {
Packit 0d464f
            _data->_streamData = new InputStreamMutex();
Packit 0d464f
            _data->_streamData->is = is;
Packit 0d464f
            _data->header.readFrom (*_data->_streamData->is, _data->version);
Packit 0d464f
            initialize();
Packit 0d464f
            _data->tileOffsets.readFrom (*(_data->_streamData->is), _data->fileIsComplete,false,true);
Packit 0d464f
            _data->_streamData->currentPosition = _data->_streamData->is->tellg();
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
    catch (IEX_NAMESPACE::BaseExc &e)
Packit 0d464f
    {
Packit 0d464f
        if (is)          delete is;
Packit 0d464f
        if (_data && !_data->multiPartBackwardSupport && _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 (is)          delete is;
Packit 0d464f
        if (_data && !_data->multiPartBackwardSupport && _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
DeepTiledInputFile::DeepTiledInputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int numThreads):
Packit 0d464f
    _data (new Data (numThreads))
Packit 0d464f
{
Packit 0d464f
    _data->_streamData=0;
Packit 0d464f
    _data->_deleteStream=false;
Packit 0d464f
    
Packit 0d464f
    //
Packit 0d464f
    // This constructor is called when a user
Packit 0d464f
    // explicitly wants to read a tiled file.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    try
Packit 0d464f
    {
Packit 0d464f
        readMagicNumberAndVersionField(is, _data->version);
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // Backward compatibility to read multpart file.
Packit 0d464f
        //
Packit 0d464f
        if (isMultiPart(_data->version))
Packit 0d464f
        {
Packit 0d464f
            compatibilityInitialize(is);
Packit 0d464f
        }
Packit 0d464f
        else
Packit 0d464f
        {
Packit 0d464f
            _data->_streamData = new InputStreamMutex();
Packit 0d464f
            _data->_streamData->is = &is;
Packit 0d464f
            _data->header.readFrom (*_data->_streamData->is, _data->version);
Packit 0d464f
            initialize();
Packit 0d464f
            // file is guaranteed not to be multipart, but is deep
Packit 0d464f
            _data->tileOffsets.readFrom (*(_data->_streamData->is), _data->fileIsComplete, false,true);
Packit 0d464f
            _data->memoryMapped = _data->_streamData->is->isMemoryMapped();
Packit 0d464f
            _data->_streamData->currentPosition = _data->_streamData->is->tellg();
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
    catch (IEX_NAMESPACE::BaseExc &e)
Packit 0d464f
    {
Packit 0d464f
        if (_data && !_data->multiPartBackwardSupport && _data->_streamData) delete _data->_streamData;
Packit 0d464f
        if (_data)       delete _data;
Packit 0d464f
Packit 0d464f
        REPLACE_EXC (e, "Cannot open image file "
Packit 0d464f
                        "\"" << is.fileName() << "\". " << e);
Packit 0d464f
        throw;
Packit 0d464f
    }
Packit 0d464f
    catch (...)
Packit 0d464f
    {
Packit 0d464f
        if (_data && !_data->multiPartBackwardSupport && _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
DeepTiledInputFile::DeepTiledInputFile (const Header &header,
Packit 0d464f
                                        OPENEXR_IMF_INTERNAL_NAMESPACE::IStream *is,
Packit 0d464f
                                        int version,
Packit 0d464f
                                        int numThreads) :
Packit 0d464f
    _data (new Data (numThreads))
Packit 0d464f
    
Packit 0d464f
{
Packit 0d464f
    _data->_streamData->is = is;
Packit 0d464f
    _data->_deleteStream=false;
Packit 0d464f
    
Packit 0d464f
    //
Packit 0d464f
    // This constructor called by class Imf::InputFile
Packit 0d464f
    // when a user wants to just read an image file, and
Packit 0d464f
    // doesn't care or know if the file is tiled.
Packit 0d464f
    // No need to have backward compatibility here, because
Packit 0d464f
    // we have the header.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    _data->header = header;
Packit 0d464f
    _data->version = version;
Packit 0d464f
    initialize();
Packit 0d464f
    _data->tileOffsets.readFrom (*(_data->_streamData->is), _data->fileIsComplete,false,true);
Packit 0d464f
    _data->memoryMapped = is->isMemoryMapped();
Packit 0d464f
    _data->_streamData->currentPosition = _data->_streamData->is->tellg();
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
DeepTiledInputFile::DeepTiledInputFile (InputPartData* part) :
Packit 0d464f
    _data (new Data (part->numThreads))
Packit 0d464f
{
Packit 0d464f
    _data->_deleteStream=false;
Packit 0d464f
    multiPartInitialize(part);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepTiledInputFile::compatibilityInitialize(OPENEXR_IMF_INTERNAL_NAMESPACE::IStream& is)
Packit 0d464f
{
Packit 0d464f
    is.seekg(0);
Packit 0d464f
    //
Packit 0d464f
    // Construct a MultiPartInputFile, initialize TiledInputFile
Packit 0d464f
    // with the part 0 data.
Packit 0d464f
    // (TODO) maybe change the third parameter of the constructor of MultiPartInputFile later.
Packit 0d464f
    //
Packit 0d464f
    _data->multiPartFile = new MultiPartInputFile(is, _data->numThreads);
Packit 0d464f
    _data->multiPartBackwardSupport = true;
Packit 0d464f
    InputPartData* part = _data->multiPartFile->getPart(0);
Packit 0d464f
Packit 0d464f
    multiPartInitialize(part);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepTiledInputFile::multiPartInitialize(InputPartData* part)
Packit 0d464f
{
Packit 0d464f
    if (isTiled(part->header.type()) == false)
Packit 0d464f
        THROW (IEX_NAMESPACE::ArgExc, "Can't build a DeepTiledInputFile from a part of type " << part->header.type());
Packit 0d464f
Packit 0d464f
    _data->_streamData = part->mutex;
Packit 0d464f
    _data->header = part->header;
Packit 0d464f
    _data->version = part->version;
Packit 0d464f
    _data->partNumber = part->partNumber;
Packit 0d464f
    _data->memoryMapped = _data->_streamData->is->isMemoryMapped();
Packit 0d464f
    initialize();
Packit 0d464f
    _data->tileOffsets.readFrom(part->chunkOffsets , _data->fileIsComplete);
Packit 0d464f
    _data->_streamData->currentPosition = _data->_streamData->is->tellg();
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepTiledInputFile::initialize ()
Packit 0d464f
{
Packit 0d464f
    if (_data->partNumber == -1)
Packit 0d464f
        if (_data->header.type() != DEEPTILE)
Packit 0d464f
            throw IEX_NAMESPACE::ArgExc ("Expected a deep tiled file but the file is not deep tiled.");
Packit 0d464f
   if(_data->header.version()!=1)
Packit 0d464f
   {
Packit 0d464f
       THROW(IEX_NAMESPACE::ArgExc, "Version " << _data->header.version() << " not supported for deeptiled images in this version of the library");
Packit 0d464f
   }
Packit 0d464f
        
Packit 0d464f
    _data->header.sanityCheck (true);
Packit 0d464f
Packit 0d464f
    _data->tileDesc = _data->header.tileDescription();
Packit 0d464f
    _data->lineOrder = _data->header.lineOrder();
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
    // Create all the TileBuffers and allocate their internal buffers
Packit 0d464f
    //
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
    for (size_t i = 0; i < _data->tileBuffers.size(); i++)
Packit 0d464f
        _data->tileBuffers[i] = new TileBuffer ();
Packit 0d464f
Packit 0d464f
    _data->maxSampleCountTableSize = _data->tileDesc.ySize *
Packit 0d464f
                                     _data->tileDesc.xSize *
Packit 0d464f
                                     sizeof(int);
Packit 0d464f
Packit 0d464f
    _data->sampleCountTableBuffer.resizeErase(_data->maxSampleCountTableSize);
Packit 0d464f
Packit 0d464f
    _data->sampleCountTableComp = newCompressor(_data->header.compression(),
Packit 0d464f
                                                _data->maxSampleCountTableSize,
Packit 0d464f
                                                _data->header);
Packit 0d464f
                                                
Packit 0d464f
                                                
Packit 0d464f
    const ChannelList & c=_data->header.channels();
Packit 0d464f
    _data->combinedSampleSize=0;
Packit 0d464f
    for(ChannelList::ConstIterator i=c.begin();i!=c.end();i++)
Packit 0d464f
    {
Packit 0d464f
        switch( i.channel().type )
Packit 0d464f
        {
Packit 0d464f
            case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF  :
Packit 0d464f
                _data->combinedSampleSize+=Xdr::size<half>();
Packit 0d464f
                break;
Packit 0d464f
            case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT :
Packit 0d464f
                _data->combinedSampleSize+=Xdr::size<float>();
Packit 0d464f
                break;
Packit 0d464f
            case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT  :
Packit 0d464f
                _data->combinedSampleSize+=Xdr::size<unsigned int>();
Packit 0d464f
                break;
Packit 0d464f
            default :
Packit 0d464f
                THROW(IEX_NAMESPACE::ArgExc, "Bad type for channel " << i.name() << " initializing deepscanline reader");
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
                                                  
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
DeepTiledInputFile::~DeepTiledInputFile ()
Packit 0d464f
{
Packit 0d464f
    if (!_data->memoryMapped)
Packit 0d464f
        for (size_t i = 0; i < _data->tileBuffers.size(); i++)
Packit 0d464f
            if (_data->tileBuffers[i]->buffer != 0)
Packit 0d464f
                delete [] _data->tileBuffers[i]->buffer;
Packit 0d464f
Packit 0d464f
    if (_data->_deleteStream)
Packit 0d464f
        delete _data->_streamData->is;
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // (TODO) we should have a way to tell if the stream data is owned by this file or
Packit 0d464f
    // by a parent multipart file.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (_data->partNumber == -1)
Packit 0d464f
        delete _data->_streamData;
Packit 0d464f
Packit 0d464f
    delete _data;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
const char *
Packit 0d464f
DeepTiledInputFile::fileName () const
Packit 0d464f
{
Packit 0d464f
    return _data->_streamData->is->fileName();
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
const Header &
Packit 0d464f
DeepTiledInputFile::header () const
Packit 0d464f
{
Packit 0d464f
    return _data->header;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
DeepTiledInputFile::version () const
Packit 0d464f
{
Packit 0d464f
    return _data->version;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepTiledInputFile::setFrameBuffer (const DeepFrameBuffer &frameBuffer)
Packit 0d464f
{
Packit 0d464f
    Lock lock (*_data->_streamData);
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Set the frame buffer
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Check if the new frame buffer descriptor is
Packit 0d464f
    // compatible with the image file header.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    const ChannelList &channels = _data->header.channels();
Packit 0d464f
Packit 0d464f
    for (DeepFrameBuffer::ConstIterator j = frameBuffer.begin();
Packit 0d464f
         j != frameBuffer.end();
Packit 0d464f
         ++j)
Packit 0d464f
    {
Packit 0d464f
        ChannelList::ConstIterator i = channels.find (j.name());
Packit 0d464f
Packit 0d464f
        if (i == channels.end())
Packit 0d464f
            continue;
Packit 0d464f
Packit 0d464f
        if (i.channel().xSampling != j.slice().xSampling ||
Packit 0d464f
            i.channel().ySampling != j.slice().ySampling)
Packit 0d464f
            THROW (IEX_NAMESPACE::ArgExc, "X and/or y subsampling factors "
Packit 0d464f
                                "of \"" << i.name() << "\" channel "
Packit 0d464f
                                "of input file \"" << fileName() << "\" are "
Packit 0d464f
                                "not compatible with the frame buffer's "
Packit 0d464f
                                "subsampling factors.");
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Store the pixel sample count table.
Packit 0d464f
    // (TODO) Support for different sampling rates?
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 the slice table for readPixels().
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    vector<TInSliceInfo*> slices;
Packit 0d464f
    ChannelList::ConstIterator i = channels.begin();
Packit 0d464f
Packit 0d464f
    for (DeepFrameBuffer::ConstIterator j = frameBuffer.begin();
Packit 0d464f
         j != frameBuffer.end();
Packit 0d464f
         ++j)
Packit 0d464f
    {
Packit 0d464f
        while (i != channels.end() && strcmp (i.name(), j.name()) < 0)
Packit 0d464f
        {
Packit 0d464f
            //
Packit 0d464f
            // Channel i is present in the file but not
Packit 0d464f
            // in the frame buffer; data for channel i
Packit 0d464f
            // will be skipped during readPixels().
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            slices.push_back (new TInSliceInfo (i.channel().type,
Packit 0d464f
                                                NULL,
Packit 0d464f
                                                i.channel().type,
Packit 0d464f
                                                0,      // xStride
Packit 0d464f
                                                0,      // yStride
Packit 0d464f
                                                0,      // sampleStride
Packit 0d464f
                                                false,  // fill
Packit 0d464f
                                                true,   // skip
Packit 0d464f
                                                0.0));  // fillValue
Packit 0d464f
            ++i;
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        bool fill = false;
Packit 0d464f
Packit 0d464f
        if (i == channels.end() || strcmp (i.name(), j.name()) > 0)
Packit 0d464f
        {
Packit 0d464f
            //
Packit 0d464f
            // Channel i is present in the frame buffer, but not in the file.
Packit 0d464f
            // In the frame buffer, slice j will be filled with a default value.
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            fill = true;
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        slices.push_back (new TInSliceInfo (j.slice().type,
Packit 0d464f
                                            j.slice().base,
Packit 0d464f
                                            fill? j.slice().type: i.channel().type,
Packit 0d464f
                                            j.slice().xStride,
Packit 0d464f
                                            j.slice().yStride,
Packit 0d464f
                                            j.slice().sampleStride,
Packit 0d464f
                                            fill,
Packit 0d464f
                                            false, // skip
Packit 0d464f
                                            j.slice().fillValue,
Packit 0d464f
                                            (j.slice().xTileCoords)? 1: 0,
Packit 0d464f
                                            (j.slice().yTileCoords)? 1: 0));
Packit 0d464f
Packit 0d464f
Packit 0d464f
        if (i != channels.end() && !fill)
Packit 0d464f
            ++i;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    // (TODO) inspect the following code. It's additional to the scanline input file.
Packit 0d464f
    // Is this needed?
Packit 0d464f
Packit 0d464f
    while (i != channels.end())
Packit 0d464f
    {
Packit 0d464f
        //
Packit 0d464f
        // Channel i is present in the file but not
Packit 0d464f
        // in the frame buffer; data for channel i
Packit 0d464f
        // will be skipped during readPixels().
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        slices.push_back (new TInSliceInfo (i.channel().type,
Packit 0d464f
                                            NULL,
Packit 0d464f
                                            i.channel().type,
Packit 0d464f
                                            0, // xStride
Packit 0d464f
                                            0, // yStride
Packit 0d464f
                                            0, // sampleStride
Packit 0d464f
                                            false,  // fill
Packit 0d464f
                                            true, // skip
Packit 0d464f
                                            0.0)); // fillValue
Packit 0d464f
        ++i;
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
DeepTiledInputFile::frameBuffer () const
Packit 0d464f
{
Packit 0d464f
    Lock lock (*_data->_streamData);
Packit 0d464f
    return _data->frameBuffer;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
bool
Packit 0d464f
DeepTiledInputFile::isComplete () const
Packit 0d464f
{
Packit 0d464f
    return _data->fileIsComplete;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepTiledInputFile::readTiles (int dx1, int dx2, int dy1, int dy2, int lx, int ly)
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // Read a range of tiles from the file into the framebuffer
Packit 0d464f
    //
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 destination.");
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
        //
Packit 0d464f
        // Determine the first and last tile coordinates in both dimensions.
Packit 0d464f
        // We always attempt to read the range of tiles in the order that
Packit 0d464f
        // they are stored in the file.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        if (dx1 > dx2)
Packit 0d464f
            std::swap (dx1, dx2);
Packit 0d464f
Packit 0d464f
        if (dy1 > dy2)
Packit 0d464f
            std::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
        //
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
            int tileNumber = 0;
Packit 0d464f
Packit 0d464f
            for (int dy = dyStart; dy != dyStop; dy += dY)
Packit 0d464f
            {
Packit 0d464f
                for (int dx = dx1; dx <= dx2; dx++)
Packit 0d464f
                {
Packit 0d464f
                    if (!isValidTile (dx, dy, lx, ly))
Packit 0d464f
                        THROW (IEX_NAMESPACE::ArgExc,
Packit 0d464f
                               "Tile (" << dx << ", " << dy << ", " <<
Packit 0d464f
                               lx << "," << ly << ") is not a valid tile.");
Packit 0d464f
Packit 0d464f
                    ThreadPool::addGlobalTask (newTileBufferTask (&taskGroup,
Packit 0d464f
                                                                  _data,
Packit 0d464f
                                                                  tileNumber++,
Packit 0d464f
                                                                  dx, dy,
Packit 0d464f
                                                                  lx, ly));
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 TiledInputFile::readTiles().
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, "Error reading pixel data from image "
Packit 0d464f
                        "file \"" << fileName() << "\". " << e);
Packit 0d464f
        throw;
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepTiledInputFile::readTiles (int dx1, int dx2, int dy1, int dy2, int l)
Packit 0d464f
{
Packit 0d464f
    readTiles (dx1, dx2, dy1, dy2, l, l);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepTiledInputFile::readTile (int dx, int dy, int lx, int ly)
Packit 0d464f
{
Packit 0d464f
    readTiles (dx, dx, dy, dy, lx, ly);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepTiledInputFile::readTile (int dx, int dy, int l)
Packit 0d464f
{
Packit 0d464f
    readTile (dx, dy, l, l);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepTiledInputFile::rawTileData (int &dx, int &dy,
Packit 0d464f
                             int &lx, int &ly,
Packit 0d464f
                             char * pixelData,
Packit 0d464f
                             Int64 &pixelDataSize) const
Packit 0d464f
{
Packit 0d464f
     if (!isValidTile (dx, dy, lx, ly))
Packit 0d464f
               throw IEX_NAMESPACE::ArgExc ("Tried to read a tile outside "
Packit 0d464f
                                   "the image file's data window.");
Packit 0d464f
    
Packit 0d464f
     Int64 tileOffset = _data->tileOffsets (dx, dy, lx, ly);
Packit 0d464f
                                   
Packit 0d464f
     if(tileOffset == 0)
Packit 0d464f
     {
Packit 0d464f
        THROW (IEX_NAMESPACE::InputExc, "Tile (" << dx << ", " << dy << ", " <<
Packit 0d464f
        lx << ", " << ly << ") is missing.");
Packit 0d464f
     }
Packit 0d464f
     
Packit 0d464f
     Lock lock(*_data->_streamData);
Packit 0d464f
                                   
Packit 0d464f
     if (_data->_streamData->is->tellg() != tileOffset)
Packit 0d464f
                                          _data->_streamData->is->seekg (tileOffset);
Packit 0d464f
                                   
Packit 0d464f
     
Packit 0d464f
     //
Packit 0d464f
     // Read the first few bytes of the tile (the header).
Packit 0d464f
     // Verify that the tile coordinates and the level number
Packit 0d464f
     // are correct.
Packit 0d464f
     //
Packit 0d464f
     
Packit 0d464f
     int tileXCoord, tileYCoord, levelX, levelY;
Packit 0d464f
     
Packit 0d464f
     if (isMultiPart(_data->version))
Packit 0d464f
     {
Packit 0d464f
         int partNumber;
Packit 0d464f
         Xdr::read <StreamIO> (*_data->_streamData->is, partNumber);
Packit 0d464f
         if (partNumber != _data->partNumber)
Packit 0d464f
         {
Packit 0d464f
             THROW (IEX_NAMESPACE::ArgExc, "Unexpected part number " << partNumber
Packit 0d464f
             << ", should be " << _data->partNumber << ".");
Packit 0d464f
         }
Packit 0d464f
     }
Packit 0d464f
     
Packit 0d464f
     Xdr::read <StreamIO> (*_data->_streamData->is, tileXCoord);
Packit 0d464f
     Xdr::read <StreamIO> (*_data->_streamData->is, tileYCoord);
Packit 0d464f
     Xdr::read <StreamIO> (*_data->_streamData->is, levelX);
Packit 0d464f
     Xdr::read <StreamIO> (*_data->_streamData->is, levelY);
Packit 0d464f
     
Packit 0d464f
     Int64 sampleCountTableSize;
Packit 0d464f
     Int64 packedDataSize;
Packit 0d464f
     Xdr::read <StreamIO> (*_data->_streamData->is, sampleCountTableSize);
Packit 0d464f
     
Packit 0d464f
     Xdr::read <StreamIO> (*_data->_streamData->is, packedDataSize);
Packit 0d464f
     
Packit 0d464f
          
Packit 0d464f
     
Packit 0d464f
     if (tileXCoord != dx)
Packit 0d464f
         throw IEX_NAMESPACE::InputExc ("Unexpected tile x coordinate.");
Packit 0d464f
     
Packit 0d464f
     if (tileYCoord != dy)
Packit 0d464f
         throw IEX_NAMESPACE::InputExc ("Unexpected tile y coordinate.");
Packit 0d464f
     
Packit 0d464f
     if (levelX != lx)
Packit 0d464f
         throw IEX_NAMESPACE::InputExc ("Unexpected tile x level number coordinate.");
Packit 0d464f
     
Packit 0d464f
     if (levelY != ly)
Packit 0d464f
         throw IEX_NAMESPACE::InputExc ("Unexpected tile y level number coordinate.");
Packit 0d464f
     
Packit 0d464f
     
Packit 0d464f
     // total requirement for reading all the data
Packit 0d464f
     
Packit 0d464f
     Int64 totalSizeRequired=40+sampleCountTableSize+packedDataSize;
Packit 0d464f
     
Packit 0d464f
     bool big_enough = totalSizeRequired<=pixelDataSize;
Packit 0d464f
     
Packit 0d464f
     pixelDataSize = totalSizeRequired;
Packit 0d464f
     
Packit 0d464f
     // was the block we were given big enough?
Packit 0d464f
     if(!big_enough || pixelData==NULL)
Packit 0d464f
     {        
Packit 0d464f
         // special case: seek stream back to start if we are at the beginning (regular reading pixels assumes it doesn't need to seek
Packit 0d464f
         // in single part files)
Packit 0d464f
         if(!isMultiPart(_data->version))
Packit 0d464f
         {
Packit 0d464f
             _data->_streamData->is->seekg(_data->_streamData->currentPosition); 
Packit 0d464f
         }
Packit 0d464f
         // leave lock here - bail before reading more data
Packit 0d464f
         return;
Packit 0d464f
     }
Packit 0d464f
     
Packit 0d464f
     // copy the values we have read into the output block
Packit 0d464f
     *(int *) (pixelData+0) = dx;
Packit 0d464f
     *(int *) (pixelData+4) = dy;
Packit 0d464f
     *(int *) (pixelData+8) = levelX;
Packit 0d464f
     *(int *) (pixelData+12) = levelY;
Packit 0d464f
     *(Int64 *) (pixelData+16) =sampleCountTableSize;
Packit 0d464f
     *(Int64 *) (pixelData+24) = packedDataSize;
Packit 0d464f
     
Packit 0d464f
     // didn't read the unpackedsize - do that now
Packit 0d464f
     Xdr::read<StreamIO> (*_data->_streamData->is, *(Int64 *) (pixelData+32));
Packit 0d464f
     
Packit 0d464f
     // read the actual data
Packit 0d464f
     _data->_streamData->is->read(pixelData+40, sampleCountTableSize+packedDataSize);
Packit 0d464f
     
Packit 0d464f
     
Packit 0d464f
     if(!isMultiPart(_data->version))
Packit 0d464f
     {
Packit 0d464f
         _data->_streamData->currentPosition+=sampleCountTableSize+packedDataSize+40;
Packit 0d464f
     }
Packit 0d464f
     
Packit 0d464f
     // leave lock here
Packit 0d464f
     
Packit 0d464f
     
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
unsigned int
Packit 0d464f
DeepTiledInputFile::tileXSize () const
Packit 0d464f
{
Packit 0d464f
    return _data->tileDesc.xSize;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
unsigned int
Packit 0d464f
DeepTiledInputFile::tileYSize () const
Packit 0d464f
{
Packit 0d464f
    return _data->tileDesc.ySize;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
LevelMode
Packit 0d464f
DeepTiledInputFile::levelMode () const
Packit 0d464f
{
Packit 0d464f
    return _data->tileDesc.mode;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
LevelRoundingMode
Packit 0d464f
DeepTiledInputFile::levelRoundingMode () const
Packit 0d464f
{
Packit 0d464f
    return _data->tileDesc.roundingMode;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
DeepTiledInputFile::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 files "
Packit 0d464f
                              "with RIPMAP level mode).");
Packit 0d464f
Packit 0d464f
    return _data->numXLevels;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
DeepTiledInputFile::numXLevels () const
Packit 0d464f
{
Packit 0d464f
    return _data->numXLevels;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
DeepTiledInputFile::numYLevels () const
Packit 0d464f
{
Packit 0d464f
    return _data->numYLevels;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
bool
Packit 0d464f
DeepTiledInputFile::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
DeepTiledInputFile::levelWidth (int lx) const
Packit 0d464f
{
Packit 0d464f
    try
Packit 0d464f
    {
Packit 0d464f
        return levelSize (_data->minX, _data->maxX, lx,
Packit 0d464f
                          _data->tileDesc.roundingMode);
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
DeepTiledInputFile::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
DeepTiledInputFile::numXTiles (int lx) const
Packit 0d464f
{
Packit 0d464f
    if (lx < 0 || lx >= _data->numXLevels)
Packit 0d464f
    {
Packit 0d464f
        THROW (IEX_NAMESPACE::ArgExc, "Error calling numXTiles() on image "
Packit 0d464f
                            "file \"" << _data->_streamData->is->fileName() << "\" "
Packit 0d464f
                            "(Argument is not in valid range).");
Packit 0d464f
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    return _data->numXTiles[lx];
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
DeepTiledInputFile::numYTiles (int ly) const
Packit 0d464f
{
Packit 0d464f
    if (ly < 0 || ly >= _data->numYLevels)
Packit 0d464f
    {
Packit 0d464f
        THROW (IEX_NAMESPACE::ArgExc, "Error calling numYTiles() on image "
Packit 0d464f
                            "file \"" << _data->_streamData->is->fileName() << "\" "
Packit 0d464f
                            "(Argument is not in valid range).");
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    return _data->numYTiles[ly];
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
Box2i
Packit 0d464f
DeepTiledInputFile::dataWindowForLevel (int l) const
Packit 0d464f
{
Packit 0d464f
    return dataWindowForLevel (l, l);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
Box2i
Packit 0d464f
DeepTiledInputFile::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
DeepTiledInputFile::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
DeepTiledInputFile::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, 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
DeepTiledInputFile::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
DeepTiledInputFile::readPixelSampleCounts (int dx1, int dx2,
Packit 0d464f
                                           int dy1, int dy2,
Packit 0d464f
                                           int lx,  int ly)
Packit 0d464f
{
Packit 0d464f
    Int64 savedFilePos = 0;
Packit 0d464f
Packit 0d464f
    try
Packit 0d464f
    {
Packit 0d464f
        Lock lock (*_data->_streamData);
Packit 0d464f
Packit 0d464f
        savedFilePos = _data->_streamData->is->tellg();
Packit 0d464f
Packit 0d464f
        
Packit 0d464f
        if (!isValidLevel (lx, ly))
Packit 0d464f
        {
Packit 0d464f
            THROW (IEX_NAMESPACE::ArgExc,
Packit 0d464f
                   "Level coordinate "
Packit 0d464f
                   "(" << lx << ", " << ly << ") "
Packit 0d464f
                   "is invalid.");
Packit 0d464f
        }
Packit 0d464f
        
Packit 0d464f
        if (dx1 > dx2)
Packit 0d464f
            std::swap (dx1, dx2);
Packit 0d464f
Packit 0d464f
        if (dy1 > dy2)
Packit 0d464f
            std::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
        // (TODO) Check if we have read the sample counts for those tiles,
Packit 0d464f
        // if we have, no need to read again.
Packit 0d464f
        for (int dy = dyStart; dy != dyStop; dy += dY)
Packit 0d464f
        {
Packit 0d464f
            for (int dx = dx1; dx <= dx2; dx++)
Packit 0d464f
            {
Packit 0d464f
                
Packit 0d464f
                if (!isValidTile (dx, dy, lx, ly))
Packit 0d464f
                {
Packit 0d464f
                    THROW (IEX_NAMESPACE::ArgExc,
Packit 0d464f
                           "Tile (" << dx << ", " << dy << ", " <<
Packit 0d464f
                           lx << "," << ly << ") is not a valid tile.");
Packit 0d464f
                }
Packit 0d464f
                
Packit 0d464f
                Box2i tileRange = 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, lx, ly);
Packit 0d464f
Packit 0d464f
                int xOffset = _data->sampleCountXTileCoords * tileRange.min.x;
Packit 0d464f
                int yOffset = _data->sampleCountYTileCoords * tileRange.min.y;
Packit 0d464f
Packit 0d464f
                //
Packit 0d464f
                // Skip and check the tile coordinates.
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                _data->_streamData->is->seekg(_data->tileOffsets(dx, dy, lx, ly));
Packit 0d464f
Packit 0d464f
                if (isMultiPart(_data->version))
Packit 0d464f
                {
Packit 0d464f
                    int partNumber;
Packit 0d464f
                    Xdr::read <StreamIO> (*_data->_streamData->is, partNumber);
Packit 0d464f
Packit 0d464f
                    if (partNumber != _data->partNumber)
Packit 0d464f
                        throw IEX_NAMESPACE::InputExc ("Unexpected part number.");
Packit 0d464f
                }
Packit 0d464f
Packit 0d464f
                int xInFile, yInFile, lxInFile, lyInFile;
Packit 0d464f
                Xdr::read <StreamIO> (*_data->_streamData->is, xInFile);
Packit 0d464f
                Xdr::read <StreamIO> (*_data->_streamData->is, yInFile);
Packit 0d464f
                Xdr::read <StreamIO> (*_data->_streamData->is, lxInFile);
Packit 0d464f
                Xdr::read <StreamIO> (*_data->_streamData->is, lyInFile);
Packit 0d464f
Packit 0d464f
                if (xInFile != dx)
Packit 0d464f
                    throw IEX_NAMESPACE::InputExc ("Unexpected tile x coordinate.");
Packit 0d464f
Packit 0d464f
                if (yInFile != dy)
Packit 0d464f
                    throw IEX_NAMESPACE::InputExc ("Unexpected tile y coordinate.");
Packit 0d464f
Packit 0d464f
                if (lxInFile != lx)
Packit 0d464f
                    throw IEX_NAMESPACE::InputExc ("Unexpected tile x level number coordinate.");
Packit 0d464f
Packit 0d464f
                if (lyInFile != ly)
Packit 0d464f
                    throw IEX_NAMESPACE::InputExc ("Unexpected tile y level number coordinate.");
Packit 0d464f
Packit 0d464f
                Int64 tableSize, dataSize, unpackedDataSize;
Packit 0d464f
                Xdr::read <StreamIO> (*_data->_streamData->is, tableSize);
Packit 0d464f
                Xdr::read <StreamIO> (*_data->_streamData->is, dataSize);
Packit 0d464f
                Xdr::read <StreamIO> (*_data->_streamData->is, unpackedDataSize);
Packit 0d464f
Packit 0d464f
                
Packit 0d464f
                if(tableSize>_data->maxSampleCountTableSize)
Packit 0d464f
                {
Packit 0d464f
                    THROW (IEX_NAMESPACE::ArgExc, "Bad sampleCountTableDataSize read from tile "<< dx << ',' << dy << ',' << lx << ',' << ly << ": expected " << _data->maxSampleCountTableSize << " or less, got "<< tableSize);
Packit 0d464f
                }
Packit 0d464f
                    
Packit 0d464f
                
Packit 0d464f
                //
Packit 0d464f
                // We make a check on the data size requirements here.
Packit 0d464f
                // Whilst we wish to store 64bit sizes on disk, not all the compressors
Packit 0d464f
                // have been made to work with such data sizes and are still limited to
Packit 0d464f
                // using signed 32 bit (int) for the data size. As such, this version
Packit 0d464f
                // insists that we validate that the data size does not exceed the data
Packit 0d464f
                // type max limit.
Packit 0d464f
                // @TODO refactor the compressor code to ensure full 64-bit support.
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                Int64 compressorMaxDataSize = Int64(std::numeric_limits<int>::max());
Packit 0d464f
                if (dataSize         > compressorMaxDataSize ||
Packit 0d464f
                    unpackedDataSize > compressorMaxDataSize ||
Packit 0d464f
                    tableSize        > compressorMaxDataSize)
Packit 0d464f
                {
Packit 0d464f
                    THROW (IEX_NAMESPACE::ArgExc, "This version of the library does not"
Packit 0d464f
                          << "support the allocation of data with size  > "
Packit 0d464f
                          << compressorMaxDataSize
Packit 0d464f
                          << " file table size    :" << tableSize
Packit 0d464f
                          << " file unpacked size :" << unpackedDataSize
Packit 0d464f
                          << " file packed size   :" << dataSize << ".\n");
Packit 0d464f
                }
Packit 0d464f
Packit 0d464f
                //
Packit 0d464f
                // Read and uncompress the pixel sample count table.
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                _data->_streamData->is->read(_data->sampleCountTableBuffer, tableSize);
Packit 0d464f
Packit 0d464f
                const char* readPtr;
Packit 0d464f
Packit 0d464f
                if (tableSize < _data->maxSampleCountTableSize)
Packit 0d464f
                {
Packit 0d464f
                    if(!_data->sampleCountTableComp)
Packit 0d464f
                    {
Packit 0d464f
                        THROW(IEX_NAMESPACE::ArgExc,"Deep scanline data corrupt at tile " << dx << ',' << dy << ',' << lx << ',' <<  ly << " (sampleCountTableDataSize error)");
Packit 0d464f
                    }
Packit 0d464f
                    _data->sampleCountTableComp->uncompress(_data->sampleCountTableBuffer,
Packit 0d464f
                                                            tableSize,
Packit 0d464f
                                                            tileRange.min.y,
Packit 0d464f
                                                            readPtr);
Packit 0d464f
                }
Packit 0d464f
                else
Packit 0d464f
                    readPtr = _data->sampleCountTableBuffer;
Packit 0d464f
Packit 0d464f
                size_t cumulative_total_samples =0;
Packit 0d464f
                int lastAccumulatedCount;
Packit 0d464f
                for (int j = tileRange.min.y; j <= tileRange.max.y; j++)
Packit 0d464f
                {
Packit 0d464f
                    lastAccumulatedCount = 0;
Packit 0d464f
                    for (int i = tileRange.min.x; i <= tileRange.max.x; i++)
Packit 0d464f
                    {
Packit 0d464f
                        int accumulatedCount;
Packit 0d464f
                        Xdr::read <CharPtrIO> (readPtr, accumulatedCount);
Packit 0d464f
                        
Packit 0d464f
                        if (accumulatedCount < lastAccumulatedCount)
Packit 0d464f
                        {
Packit 0d464f
                            THROW(IEX_NAMESPACE::ArgExc,"Deep tile sampleCount data corrupt at tile " 
Packit 0d464f
                                  << dx << ',' << dy << ',' << lx << ',' <<  ly << " (negative sample count detected)");
Packit 0d464f
                        }
Packit 0d464f
Packit 0d464f
                        int count = accumulatedCount - lastAccumulatedCount;
Packit 0d464f
                        lastAccumulatedCount = accumulatedCount;
Packit 0d464f
                        
Packit 0d464f
                        _data->getSampleCount(i - xOffset, j - yOffset) =count;
Packit 0d464f
                    }
Packit 0d464f
                    cumulative_total_samples += lastAccumulatedCount;
Packit 0d464f
                }
Packit 0d464f
                
Packit 0d464f
                if(cumulative_total_samples * _data->combinedSampleSize > unpackedDataSize)
Packit 0d464f
                {
Packit 0d464f
                    THROW(IEX_NAMESPACE::ArgExc,"Deep scanline sampleCount data corrupt at tile " 
Packit 0d464f
                                                << dx << ',' << dy << ',' << lx << ',' <<  ly 
Packit 0d464f
                                                << ": pixel data only contains " << unpackedDataSize 
Packit 0d464f
                                                << " bytes of data but table references at least " 
Packit 0d464f
                                                << cumulative_total_samples*_data->combinedSampleSize << " bytes of sample data" );            
Packit 0d464f
                }
Packit 0d464f
                    
Packit 0d464f
            }
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        _data->_streamData->is->seekg(savedFilePos);
Packit 0d464f
    }
Packit 0d464f
    catch (IEX_NAMESPACE::BaseExc &e)
Packit 0d464f
    {
Packit 0d464f
        REPLACE_EXC (e, "Error reading sample count data from image "
Packit 0d464f
                        "file \"" << fileName() << "\". " << e);
Packit 0d464f
Packit 0d464f
         _data->_streamData->is->seekg(savedFilePos);
Packit 0d464f
Packit 0d464f
        throw;
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepTiledInputFile::readPixelSampleCount (int dx, int dy, int l)
Packit 0d464f
{
Packit 0d464f
    readPixelSampleCount (dx, dy, l, l);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepTiledInputFile::readPixelSampleCount (int dx, int dy, int lx, int ly)
Packit 0d464f
{
Packit 0d464f
    readPixelSampleCounts (dx, dx, dy, dy, lx, ly);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepTiledInputFile::readPixelSampleCounts (int dx1, int dx2,
Packit 0d464f
                                           int dy1, int dy2,
Packit 0d464f
                                           int l)
Packit 0d464f
{
Packit 0d464f
    readPixelSampleCounts (dx1, dx2, dy1, dy2, l, l);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
size_t
Packit 0d464f
DeepTiledInputFile::totalTiles() const
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // Calculate the total number of tiles in the file
Packit 0d464f
    //
Packit 0d464f
    
Packit 0d464f
    int numAllTiles = 0;
Packit 0d464f
    
Packit 0d464f
    switch (levelMode ())
Packit 0d464f
    {
Packit 0d464f
        case ONE_LEVEL:
Packit 0d464f
        case MIPMAP_LEVELS:
Packit 0d464f
            
Packit 0d464f
            for (int i_l = 0; i_l < numLevels (); ++i_l)
Packit 0d464f
                numAllTiles += numXTiles (i_l) * numYTiles (i_l);
Packit 0d464f
            
Packit 0d464f
            break;
Packit 0d464f
            
Packit 0d464f
        case RIPMAP_LEVELS:
Packit 0d464f
            
Packit 0d464f
            for (int i_ly = 0; i_ly < numYLevels (); ++i_ly)
Packit 0d464f
                for (int i_lx = 0; i_lx < numXLevels (); ++i_lx)
Packit 0d464f
                    numAllTiles += numXTiles (i_lx) * numYTiles (i_ly);
Packit 0d464f
                
Packit 0d464f
                break;
Packit 0d464f
            
Packit 0d464f
        default:
Packit 0d464f
            
Packit 0d464f
            throw IEX_NAMESPACE::ArgExc ("Unknown LevelMode format.");
Packit 0d464f
    }
Packit 0d464f
    return numAllTiles;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
Packit 0d464f
Packit 0d464f
void 
Packit 0d464f
DeepTiledInputFile::getTileOrder(int dx[],int dy[],int lx[],int ly[]) const
Packit 0d464f
{
Packit 0d464f
  return _data->tileOffsets.getTileOrder(dx,dy,lx,ly);
Packit 0d464f
  
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT