Blame IlmImf/ImfDwaCompressor.cpp

Packit 0d464f
///////////////////////////////////////////////////////////////////////////
Packit 0d464f
//
Packit 0d464f
// Copyright (c) 2009-2014 DreamWorks Animation 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 DreamWorks Animation 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 DwaCompressor -- Store lossy RGB data by quantizing
Packit 0d464f
//                          DCT components.
Packit 0d464f
//
Packit 0d464f
// First, we try and figure out what compression strategy to take
Packit 0d464f
// based in channel name. For RGB channels, we want a lossy method
Packit 0d464f
// described below. But, if we have alpha, we should do something
Packit 0d464f
// different (and probably using RLE). If we have depth, or velocity,
Packit 0d464f
// or something else, just fall back to ZIP. The rules for deciding 
Packit 0d464f
// which strategy to use are setup in initializeDefaultChannelRules().
Packit 0d464f
// When writing a file, the relevant rules needed to decode are written
Packit 0d464f
// into the start of the data block, making a self-contained file. 
Packit 0d464f
// If initializeDefaultChannelRules() doesn't quite suite your naming
Packit 0d464f
// conventions, you can adjust the rules without breaking decoder
Packit 0d464f
// compatability.
Packit 0d464f
//
Packit 0d464f
// If we're going to lossy compress R, G, or B channels, it's easier
Packit 0d464f
// to toss bits in a more perceptual uniform space. One could argue
Packit 0d464f
// at length as to what constitutes perceptually uniform, expecially 
Packit 0d464f
// when storing either scene/input/focal plane referred and output referred
Packit 0d464f
// data. 
Packit 0d464f
//
Packit 0d464f
// We'll compromise. For values <= 1, we use a traditional power function
Packit 0d464f
// (without any of that straight-line business at the bottom). For values > 1,
Packit 0d464f
// we want something more like a log function, since power functions blow
Packit 0d464f
// up. At 1, we want a smooth blend between the functions. So, we use a 
Packit 0d464f
// piecewise function that does just that - see dwaLookups.cpp for 
Packit 0d464f
// a little more detail.
Packit 0d464f
//
Packit 0d464f
// Also, if we find that we have R, G, and B channels from the same layer,
Packit 0d464f
// we can get a bit more compression efficiency by transforming to a Y'CbCr
Packit 0d464f
// space. We use the 709 transform, but with Cb,Cr = 0 for an input of 
Packit 0d464f
// (0, 0, 0), instead of the traditional Cb,Cr = .5. Shifting the zero point
Packit 0d464f
// makes no sense with large range data. Transforms are done to from 
Packit 0d464f
// the perceptual space data, not the linear-light space data (R'G'B' ->
Packit 0d464f
// (Y'CbCr, not RGB -> YCbCr).
Packit 0d464f
//
Packit 0d464f
// Next, we forward DCT the data. This is done with a floating
Packit 0d464f
// point DCT, as we don't really have control over the src range. The 
Packit 0d464f
// resulting values are dropped to half-float precision. 
Packit 0d464f
//
Packit 0d464f
// Now, we need to quantize. Quantization departs from the usual way 
Packit 0d464f
// of dividing and rounding. Instead, we start with some floating 
Packit 0d464f
// point "base-error" value. From this, we can derive quantization 
Packit 0d464f
// error for each DCT component. Take the standard JPEG quantization
Packit 0d464f
// tables and normalize them by the smallest value. Then, multiply
Packit 0d464f
// the normalized quant tables by our base-error value. This gives
Packit 0d464f
// a range of errors for each DCT component.
Packit 0d464f
//
Packit 0d464f
// For each DCT component, we want to find a quantized value that 
Packit 0d464f
// is within +- the per-component error. Pick the quantized value
Packit 0d464f
// that has the fewest bits set in its' binary representation. 
Packit 0d464f
// Brute-forcing the search would make for extremly inefficient 
Packit 0d464f
// compression. Fortunatly, we can precompute a table to assist 
Packit 0d464f
// with this search. 
Packit 0d464f
//
Packit 0d464f
// For each 16-bit float value, there are at most 15 other values with
Packit 0d464f
// fewer bits set. We can precompute these values in a compact form, since
Packit 0d464f
// many source values have far fewer that 15 possible quantized values. 
Packit 0d464f
// Now, instead of searching the entire range +- the component error,
Packit 0d464f
// we can just search at most 15 quantization candidates. The search can
Packit 0d464f
// be accelerated a bit more by sorting the candidates by the 
Packit 0d464f
// number of bits set, in increasing order. Then, the search can stop
Packit 0d464f
// once a candidate is found w/i the per-component quantization 
Packit 0d464f
// error range.
Packit 0d464f
//
Packit 0d464f
// The quantization strategy has the side-benefit that there is no
Packit 0d464f
// de-quantization step upon decode, so we don't bother recording
Packit 0d464f
// the quantization table.
Packit 0d464f
//
Packit 0d464f
// Ok. So we now have quantized values. Time for entropy coding. We
Packit 0d464f
// can use either static Huffman or zlib/DEFLATE. The static Huffman
Packit 0d464f
// is more efficient at compacting data, but can have a greater 
Packit 0d464f
// overhead, especially for smaller tile/strip sizes. 
Packit 0d464f
//
Packit 0d464f
// There is some additional fun, like ZIP compressing the DC components
Packit 0d464f
// instead of Huffman/zlib, which helps make things slightly smaller.
Packit 0d464f
//
Packit 0d464f
// Compression level is controlled by setting an int/float/double attribute
Packit 0d464f
// on the header named "dwaCompressionLevel". This is a thinly veiled name for 
Packit 0d464f
// the "base-error" value mentioned above. The "base-error" is just
Packit 0d464f
// dwaCompressionLevel / 100000. The default value of 45.0 is generally 
Packit 0d464f
// pretty good at generating "visually lossless" values at reasonable
Packit 0d464f
// data rates. Setting dwaCompressionLevel to 0 should result in no additional
Packit 0d464f
// quantization at the quantization stage (though there may be 
Packit 0d464f
// quantization in practice at the CSC/DCT steps). But if you really
Packit 0d464f
// want lossless compression, there are pleanty of other choices 
Packit 0d464f
// of compressors ;)
Packit 0d464f
//
Packit 0d464f
// When dealing with FLOAT source buffers, we first quantize the source
Packit 0d464f
// to HALF and continue down as we would for HALF source.
Packit 0d464f
//
Packit 0d464f
//---------------------------------------------------
Packit 0d464f
Packit 0d464f
Packit 0d464f
#include "ImfDwaCompressor.h"
Packit 0d464f
#include "ImfDwaCompressorSimd.h"
Packit 0d464f
Packit 0d464f
#include "ImfChannelList.h"
Packit 0d464f
#include "ImfStandardAttributes.h"
Packit 0d464f
#include "ImfHeader.h"
Packit 0d464f
#include "ImfHuf.h"
Packit 0d464f
#include "ImfInt64.h"
Packit 0d464f
#include "ImfIntAttribute.h"
Packit 0d464f
#include "ImfIO.h"
Packit 0d464f
#include "ImfMisc.h"
Packit 0d464f
#include "ImfNamespace.h"
Packit 0d464f
#include "ImfRle.h"
Packit 0d464f
#include "ImfSimd.h"
Packit 0d464f
#include "ImfSystemSpecific.h"
Packit 0d464f
#include "ImfXdr.h"
Packit 0d464f
#include "ImfZip.h"
Packit 0d464f
Packit 0d464f
#include "ImathFun.h"
Packit 0d464f
#include "ImathBox.h"
Packit 0d464f
#include "ImathVec.h"
Packit 0d464f
#include "half.h"
Packit 0d464f
Packit 0d464f
#include "dwaLookups.h"
Packit 0d464f
Packit 0d464f
#include <vector>
Packit 0d464f
#include <string>
Packit 0d464f
#include <cctype>
Packit 0d464f
#include <cassert>
Packit 0d464f
#include <algorithm>
Packit 0d464f
Packit 0d464f
// Windows specific addition to prevent the indirect import of the redefined min/max macros
Packit 0d464f
#if defined _WIN32 || defined _WIN64
Packit 0d464f
	#ifdef NOMINMAX
Packit 0d464f
		#undef NOMINMAX
Packit 0d464f
	#endif
Packit 0d464f
	#define NOMINMAX
Packit 0d464f
#endif
Packit 0d464f
#include <zlib.h>
Packit 0d464f
Packit 0d464f
Packit 0d464f
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
Packit 0d464f
Packit 0d464f
Packit 0d464f
namespace {
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Function pointer to dispatch to an approprate 
Packit 0d464f
    // convertFloatToHalf64_* impl, based on runtime cpu checking.
Packit 0d464f
    // Should be initialized in DwaCompressor::initializeFuncs()
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    void (*convertFloatToHalf64)(unsigned short*, float*) =
Packit 0d464f
        convertFloatToHalf64_scalar;
Packit 0d464f
Packit 0d464f
    // 
Packit 0d464f
    // Function pointer for dispatching a fromHalfZigZag_ impl
Packit 0d464f
    //
Packit 0d464f
    
Packit 0d464f
    void (*fromHalfZigZag)(unsigned short*, float*) =
Packit 0d464f
        fromHalfZigZag_scalar;
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Dispatch the inverse DCT on an 8x8 block, where the last
Packit 0d464f
    // n rows can be all zeros. The n=0 case converts the full block.
Packit 0d464f
    //
Packit 0d464f
    void (*dctInverse8x8_0)(float*) = dctInverse8x8_scalar<0>;
Packit 0d464f
    void (*dctInverse8x8_1)(float*) = dctInverse8x8_scalar<1>;
Packit 0d464f
    void (*dctInverse8x8_2)(float*) = dctInverse8x8_scalar<2>;
Packit 0d464f
    void (*dctInverse8x8_3)(float*) = dctInverse8x8_scalar<3>;
Packit 0d464f
    void (*dctInverse8x8_4)(float*) = dctInverse8x8_scalar<4>;
Packit 0d464f
    void (*dctInverse8x8_5)(float*) = dctInverse8x8_scalar<5>;
Packit 0d464f
    void (*dctInverse8x8_6)(float*) = dctInverse8x8_scalar<6>;
Packit 0d464f
    void (*dctInverse8x8_7)(float*) = dctInverse8x8_scalar<7>;
Packit 0d464f
    
Packit 0d464f
} // namespace
Packit 0d464f
Packit 0d464f
Packit 0d464f
struct DwaCompressor::ChannelData
Packit 0d464f
{
Packit 0d464f
    std::string         name;
Packit 0d464f
    CompressorScheme    compression;  
Packit 0d464f
    int                 xSampling;
Packit 0d464f
    int                 ySampling;
Packit 0d464f
    PixelType           type;
Packit 0d464f
    bool                pLinear;
Packit 0d464f
Packit 0d464f
    int                 width;
Packit 0d464f
    int                 height;
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Incoming and outgoing data is scanline interleaved, and it's much
Packit 0d464f
    // easier to operate on contiguous data.  Assuming the planare unc
Packit 0d464f
    // buffer is to hold RLE data, we need to rearrange to make bytes
Packit 0d464f
    // adjacent.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    char               *planarUncBuffer;
Packit 0d464f
    char               *planarUncBufferEnd;
Packit 0d464f
Packit 0d464f
    char               *planarUncRle[4];
Packit 0d464f
    char               *planarUncRleEnd[4];
Packit 0d464f
Packit 0d464f
    PixelType           planarUncType;
Packit 0d464f
    int                 planarUncSize;
Packit 0d464f
};
Packit 0d464f
Packit 0d464f
Packit 0d464f
struct DwaCompressor::CscChannelSet
Packit 0d464f
{
Packit 0d464f
    int idx[3];
Packit 0d464f
};
Packit 0d464f
Packit 0d464f
Packit 0d464f
struct DwaCompressor::Classifier
Packit 0d464f
{
Packit 0d464f
    Classifier (std::string suffix,
Packit 0d464f
                CompressorScheme scheme,
Packit 0d464f
                PixelType type,
Packit 0d464f
                int cscIdx,
Packit 0d464f
                bool caseInsensitive):
Packit 0d464f
        _suffix(suffix),
Packit 0d464f
        _scheme(scheme),
Packit 0d464f
        _type(type),
Packit 0d464f
        _cscIdx(cscIdx),
Packit 0d464f
        _caseInsensitive(caseInsensitive)
Packit 0d464f
    {
Packit 0d464f
        if (caseInsensitive) 
Packit 0d464f
            transform(_suffix.begin(), _suffix.end(), _suffix.begin(), tolower);
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    Classifier (const char *&ptr, int size)
Packit 0d464f
    {
Packit 0d464f
        if (size <= 0) 
Packit 0d464f
            throw Iex::InputExc("Error uncompressing DWA data"
Packit 0d464f
                                " (truncated rule).");
Packit 0d464f
            
Packit 0d464f
        {
Packit 0d464f
            char suffix[Name::SIZE];
Packit 0d464f
            memset (suffix, 0, Name::SIZE);
Packit 0d464f
            Xdr::read<CharPtrIO> (ptr, std::min(size, Name::SIZE-1), suffix);
Packit 0d464f
            _suffix = std::string(suffix);
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        if (size < _suffix.length() + 1 + 2*Xdr::size<char>()) 
Packit 0d464f
            throw Iex::InputExc("Error uncompressing DWA data"
Packit 0d464f
                                " (truncated rule).");
Packit 0d464f
Packit 0d464f
        char value;
Packit 0d464f
        Xdr::read<CharPtrIO> (ptr, value);
Packit 0d464f
Packit 0d464f
        _cscIdx = (int)(value >> 4) - 1;
Packit 0d464f
        if (_cscIdx < -1 || _cscIdx >= 3) 
Packit 0d464f
            throw Iex::InputExc("Error uncompressing DWA data"
Packit 0d464f
                                " (corrupt cscIdx rule).");
Packit 0d464f
Packit 0d464f
        _scheme = (CompressorScheme)((value >> 2) & 3);
Packit 0d464f
        if (_scheme < 0 || _scheme >= NUM_COMPRESSOR_SCHEMES) 
Packit 0d464f
            throw Iex::InputExc("Error uncompressing DWA data"
Packit 0d464f
                                " (corrupt scheme rule).");
Packit 0d464f
Packit 0d464f
        _caseInsensitive = (value & 1 ? true : false);
Packit 0d464f
Packit 0d464f
        Xdr::read<CharPtrIO> (ptr, value);
Packit 0d464f
        if (value < 0 || value >= NUM_PIXELTYPES) 
Packit 0d464f
            throw Iex::InputExc("Error uncompressing DWA data"
Packit 0d464f
                                " (corrupt rule).");
Packit 0d464f
        _type = (PixelType)value;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    bool match (const std::string &suffix, const PixelType type) const
Packit 0d464f
    {
Packit 0d464f
        if (_type != type) return false;
Packit 0d464f
Packit 0d464f
        if (_caseInsensitive) 
Packit 0d464f
        {
Packit 0d464f
            std::string tmp(suffix);
Packit 0d464f
            transform(tmp.begin(), tmp.end(), tmp.begin(), tolower);
Packit 0d464f
            return tmp == _suffix;
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        return suffix == _suffix;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    size_t size () const 
Packit 0d464f
    {
Packit 0d464f
        // string length + \0
Packit 0d464f
        size_t sizeBytes = _suffix.length() + 1;
Packit 0d464f
Packit 0d464f
        // 1 byte for scheme / cscIdx / caseInsensitive, and 1 byte for type
Packit 0d464f
        sizeBytes += 2 * Xdr::size<char>();
Packit 0d464f
Packit 0d464f
        return sizeBytes;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    void write (char *&ptr) const
Packit 0d464f
    {
Packit 0d464f
        Xdr::write<CharPtrIO> (ptr, _suffix.c_str());
Packit 0d464f
Packit 0d464f
        // Encode _cscIdx (-1-3) in the upper 4 bits,
Packit 0d464f
        //        _scheme (0-2)  in the next 2 bits
Packit 0d464f
        //        _caseInsen     in the bottom bit
Packit 0d464f
        unsigned char value = 0;
Packit 0d464f
        value |= ((unsigned char)(_cscIdx+1)      & 15) << 4;
Packit 0d464f
        value |= ((unsigned char)_scheme          &  3) << 2;
Packit 0d464f
        value |=  (unsigned char)_caseInsensitive &  1;
Packit 0d464f
Packit 0d464f
        Xdr::write<CharPtrIO> (ptr, value);
Packit 0d464f
        Xdr::write<CharPtrIO> (ptr, (unsigned char)_type);
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    std::string      _suffix;
Packit 0d464f
    CompressorScheme _scheme;
Packit 0d464f
    PixelType        _type;
Packit 0d464f
    int              _cscIdx;
Packit 0d464f
    bool             _caseInsensitive;
Packit 0d464f
};
Packit 0d464f
Packit 0d464f
Packit 0d464f
//
Packit 0d464f
// Base class for the LOSSY_DCT decoder classes
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
class DwaCompressor::LossyDctDecoderBase
Packit 0d464f
{
Packit 0d464f
  public:
Packit 0d464f
Packit 0d464f
    LossyDctDecoderBase
Packit 0d464f
        (char *packedAc,
Packit 0d464f
         char *packedDc,
Packit 0d464f
         const unsigned short *toLinear,
Packit 0d464f
         int width,
Packit 0d464f
         int height);
Packit 0d464f
Packit 0d464f
    virtual ~LossyDctDecoderBase ();
Packit 0d464f
Packit 0d464f
    void execute();
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // These return number of items, not bytes. Each item
Packit 0d464f
    // is an unsigned short
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    int numAcValuesEncoded() const { return _packedAcCount; }
Packit 0d464f
    int numDcValuesEncoded() const { return _packedDcCount; }
Packit 0d464f
Packit 0d464f
  protected:
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Un-RLE the packed AC components into 
Packit 0d464f
    // a half buffer. The half block should 
Packit 0d464f
    // be the full 8x8 block (in zig-zag order
Packit 0d464f
    // still), not the first AC component. 
Packit 0d464f
    //
Packit 0d464f
    // currAcComp is advanced as bytes are decoded.
Packit 0d464f
    //
Packit 0d464f
    // This returns the index of the last non-zero
Packit 0d464f
    // value in the buffer - with the index into zig zag
Packit 0d464f
    // order data. If we return 0, we have DC only data.
Packit 0d464f
    // 
Packit 0d464f
Packit 0d464f
    int unRleAc (unsigned short *&currAcComp,
Packit 0d464f
                 unsigned short  *halfZigBlock); 
Packit 0d464f
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // if NATIVE and XDR are really the same values, we can
Packit 0d464f
    // skip some processing and speed things along
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    bool                  _isNativeXdr;
Packit 0d464f
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Counts of how many items have been packed into the
Packit 0d464f
    // AC and DC buffers
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    int                   _packedAcCount;
Packit 0d464f
    int                   _packedDcCount;
Packit 0d464f
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // AC and DC buffers to pack
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    char                 *_packedAc;
Packit 0d464f
    char                 *_packedDc;
Packit 0d464f
Packit 0d464f
Packit 0d464f
    // 
Packit 0d464f
    // half -> half LUT to transform from nonlinear to linear
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    const unsigned short *_toLinear;
Packit 0d464f
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // image dimensions
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    int                   _width;
Packit 0d464f
    int                   _height;
Packit 0d464f
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Pointers to the start of each scanlines, to be filled on decode
Packit 0d464f
    // Generally, these will be filled by the subclasses.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    std::vector< std::vector<char *> > _rowPtrs;
Packit 0d464f
Packit 0d464f
Packit 0d464f
    // 
Packit 0d464f
    // The type of each data that _rowPtrs[i] is referring. Layout
Packit 0d464f
    // is in the same order as _rowPtrs[].
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    std::vector<PixelType>             _type;
Packit 0d464f
    std::vector<SimdAlignedBuffer64f>  _dctData;
Packit 0d464f
};
Packit 0d464f
Packit 0d464f
Packit 0d464f
//
Packit 0d464f
// Used to decode a single channel of LOSSY_DCT data.
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
class DwaCompressor::LossyDctDecoder: public LossyDctDecoderBase
Packit 0d464f
{
Packit 0d464f
  public:
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // toLinear is a half-float LUT to convert the encoded values 
Packit 0d464f
    // back to linear light. If you want to skip this step, pass
Packit 0d464f
    // in NULL here.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    LossyDctDecoder
Packit 0d464f
        (std::vector<char *> &rowPtrs,
Packit 0d464f
         char *packedAc,
Packit 0d464f
         char *packedDc,
Packit 0d464f
         const unsigned short *toLinear,
Packit 0d464f
         int width,
Packit 0d464f
         int height,
Packit 0d464f
         PixelType type)
Packit 0d464f
    :
Packit 0d464f
        LossyDctDecoderBase(packedAc, packedDc, toLinear, width, height)
Packit 0d464f
    {
Packit 0d464f
        _rowPtrs.push_back(rowPtrs);
Packit 0d464f
        _type.push_back(type);
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    virtual ~LossyDctDecoder () {}
Packit 0d464f
};
Packit 0d464f
Packit 0d464f
Packit 0d464f
//
Packit 0d464f
// Used to decode 3 channels of LOSSY_DCT data that
Packit 0d464f
// are grouped together and color space converted.
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
class DwaCompressor::LossyDctDecoderCsc: public LossyDctDecoderBase
Packit 0d464f
{
Packit 0d464f
  public:
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // toLinear is a half-float LUT to convert the encoded values 
Packit 0d464f
    // back to linear light. If you want to skip this step, pass
Packit 0d464f
    // in NULL here.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    LossyDctDecoderCsc
Packit 0d464f
        (std::vector<char *> &rowPtrsR,
Packit 0d464f
         std::vector<char *> &rowPtrsG,
Packit 0d464f
         std::vector<char *> &rowPtrsB,
Packit 0d464f
         char *packedAc,
Packit 0d464f
         char *packedDc,
Packit 0d464f
         const unsigned short *toLinear,
Packit 0d464f
         int width,
Packit 0d464f
         int height,
Packit 0d464f
         PixelType typeR,
Packit 0d464f
         PixelType typeG,
Packit 0d464f
         PixelType typeB)
Packit 0d464f
    :
Packit 0d464f
        LossyDctDecoderBase(packedAc, packedDc, toLinear, width, height)
Packit 0d464f
    {
Packit 0d464f
        _rowPtrs.push_back(rowPtrsR);
Packit 0d464f
        _rowPtrs.push_back(rowPtrsG);
Packit 0d464f
        _rowPtrs.push_back(rowPtrsB);
Packit 0d464f
        _type.push_back(typeR);
Packit 0d464f
        _type.push_back(typeG);
Packit 0d464f
        _type.push_back(typeB);
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    virtual ~LossyDctDecoderCsc () {}
Packit 0d464f
};
Packit 0d464f
Packit 0d464f
Packit 0d464f
// 
Packit 0d464f
// Base class for encoding using the lossy DCT scheme
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
class DwaCompressor::LossyDctEncoderBase
Packit 0d464f
{
Packit 0d464f
  public:
Packit 0d464f
Packit 0d464f
    LossyDctEncoderBase
Packit 0d464f
        (float quantBaseError,
Packit 0d464f
         char *packedAc,
Packit 0d464f
         char *packedDc,
Packit 0d464f
         const unsigned short *toNonlinear,
Packit 0d464f
         int width,
Packit 0d464f
         int height);
Packit 0d464f
Packit 0d464f
    virtual ~LossyDctEncoderBase ();
Packit 0d464f
Packit 0d464f
    void execute ();
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // These return number of items, not bytes. Each item
Packit 0d464f
    // is an unsigned short
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    int     numAcValuesEncoded () const {return _numAcComp;}
Packit 0d464f
    int     numDcValuesEncoded () const {return _numDcComp;}
Packit 0d464f
Packit 0d464f
  protected:
Packit 0d464f
Packit 0d464f
    void    toZigZag (half *dst, half *src);
Packit 0d464f
    int     countSetBits (unsigned short src);
Packit 0d464f
    half    quantize (half src, float errorTolerance);
Packit 0d464f
    void    rleAc (half *block, unsigned short *&acPtr);
Packit 0d464f
Packit 0d464f
    float                      _quantBaseError;
Packit 0d464f
Packit 0d464f
    int                        _width,
Packit 0d464f
                               _height;
Packit 0d464f
    const unsigned short      *_toNonlinear;
Packit 0d464f
Packit 0d464f
    int                        _numAcComp,
Packit 0d464f
                               _numDcComp;
Packit 0d464f
Packit 0d464f
    std::vector< std::vector<const char *> > _rowPtrs;
Packit 0d464f
    std::vector<PixelType>                   _type;
Packit 0d464f
    std::vector<SimdAlignedBuffer64f>        _dctData;
Packit 0d464f
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Pointers to the buffers where AC and DC
Packit 0d464f
    // DCT components should be packed for 
Packit 0d464f
    // lossless compression downstream
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    char                      *_packedAc;
Packit 0d464f
    char                      *_packedDc;
Packit 0d464f
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Our "quantization tables" - the example JPEG tables, 
Packit 0d464f
    // normalized so that the smallest value in each is 1.0.
Packit 0d464f
    // This gives us a relationship between error in DCT 
Packit 0d464f
    // components
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    float                      _quantTableY[64];
Packit 0d464f
    float                      _quantTableCbCr[64];
Packit 0d464f
};
Packit 0d464f
Packit 0d464f
Packit 0d464f
Packit 0d464f
//
Packit 0d464f
// Single channel lossy DCT encoder
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
class DwaCompressor::LossyDctEncoder: public LossyDctEncoderBase
Packit 0d464f
{
Packit 0d464f
  public:
Packit 0d464f
Packit 0d464f
    LossyDctEncoder
Packit 0d464f
        (float quantBaseError,
Packit 0d464f
         std::vector<const char *> &rowPtrs,
Packit 0d464f
         char *packedAc,
Packit 0d464f
         char *packedDc,
Packit 0d464f
         const unsigned short *toNonlinear,
Packit 0d464f
         int width,
Packit 0d464f
         int height,
Packit 0d464f
         PixelType type)
Packit 0d464f
    :
Packit 0d464f
        LossyDctEncoderBase
Packit 0d464f
            (quantBaseError, packedAc, packedDc, toNonlinear, width, height)
Packit 0d464f
    {
Packit 0d464f
        _rowPtrs.push_back(rowPtrs);
Packit 0d464f
        _type.push_back(type);
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    virtual ~LossyDctEncoder () {}
Packit 0d464f
};
Packit 0d464f
    
Packit 0d464f
Packit 0d464f
//
Packit 0d464f
// RGB channel lossy DCT encoder
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
class DwaCompressor::LossyDctEncoderCsc: public LossyDctEncoderBase
Packit 0d464f
{
Packit 0d464f
  public:
Packit 0d464f
Packit 0d464f
    LossyDctEncoderCsc
Packit 0d464f
        (float quantBaseError,
Packit 0d464f
         std::vector<const char *> &rowPtrsR,
Packit 0d464f
         std::vector<const char *> &rowPtrsG,
Packit 0d464f
         std::vector<const char *> &rowPtrsB,
Packit 0d464f
         char *packedAc,
Packit 0d464f
         char *packedDc,
Packit 0d464f
         const unsigned short *toNonlinear,
Packit 0d464f
         int width,
Packit 0d464f
         int height,
Packit 0d464f
         PixelType typeR,
Packit 0d464f
         PixelType typeG,
Packit 0d464f
         PixelType typeB)
Packit 0d464f
    :
Packit 0d464f
        LossyDctEncoderBase
Packit 0d464f
            (quantBaseError, packedAc, packedDc, toNonlinear, width, height)
Packit 0d464f
    {
Packit 0d464f
        _type.push_back(typeR);
Packit 0d464f
        _type.push_back(typeG);
Packit 0d464f
        _type.push_back(typeB);
Packit 0d464f
Packit 0d464f
        _rowPtrs.push_back(rowPtrsR);
Packit 0d464f
        _rowPtrs.push_back(rowPtrsG);
Packit 0d464f
        _rowPtrs.push_back(rowPtrsB);
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    virtual ~LossyDctEncoderCsc () {}
Packit 0d464f
};
Packit 0d464f
Packit 0d464f
Packit 0d464f
// ==============================================================
Packit 0d464f
//
Packit 0d464f
//                     LossyDctDecoderBase
Packit 0d464f
//
Packit 0d464f
// --------------------------------------------------------------
Packit 0d464f
Packit 0d464f
DwaCompressor::LossyDctDecoderBase::LossyDctDecoderBase
Packit 0d464f
    (char *packedAc,
Packit 0d464f
     char *packedDc,
Packit 0d464f
     const unsigned short *toLinear,
Packit 0d464f
     int width,
Packit 0d464f
     int height)
Packit 0d464f
:
Packit 0d464f
    _isNativeXdr(false),
Packit 0d464f
    _packedAcCount(0),
Packit 0d464f
    _packedDcCount(0),
Packit 0d464f
    _packedAc(packedAc),
Packit 0d464f
    _packedDc(packedDc),
Packit 0d464f
    _toLinear(toLinear),
Packit 0d464f
    _width(width),
Packit 0d464f
    _height(height)
Packit 0d464f
{
Packit 0d464f
    if (_toLinear == 0)
Packit 0d464f
        _toLinear = dwaCompressorNoOp;
Packit 0d464f
Packit 0d464f
    _isNativeXdr = GLOBAL_SYSTEM_LITTLE_ENDIAN;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
DwaCompressor::LossyDctDecoderBase::~LossyDctDecoderBase () {}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DwaCompressor::LossyDctDecoderBase::execute ()
Packit 0d464f
{
Packit 0d464f
    int numComp        = _rowPtrs.size();
Packit 0d464f
    int lastNonZero    = 0;
Packit 0d464f
    int numBlocksX     = (int) ceil ((float)_width  / 8.0f);
Packit 0d464f
    int numBlocksY     = (int) ceil ((float)_height / 8.0f);
Packit 0d464f
    int leftoverX      = _width  - (numBlocksX-1) * 8;
Packit 0d464f
    int leftoverY      = _height - (numBlocksY-1) * 8;
Packit 0d464f
Packit 0d464f
    int numFullBlocksX = (int)floor ((float)_width / 8.0f);
Packit 0d464f
Packit 0d464f
    unsigned short tmpShortNative = 0;
Packit 0d464f
    unsigned short tmpShortXdr    = 0;
Packit 0d464f
    const char *tmpConstCharPtr   = 0;
Packit 0d464f
Packit 0d464f
    unsigned short                    *currAcComp = (unsigned short *)_packedAc;
Packit 0d464f
    std::vector<unsigned short *>      currDcComp (_rowPtrs.size());
Packit 0d464f
    std::vector<SimdAlignedBuffer64us> halfZigBlock (_rowPtrs.size());
Packit 0d464f
Packit 0d464f
    if (_type.size() != _rowPtrs.size())
Packit 0d464f
        throw Iex::BaseExc ("Row pointers and types mismatch in count");
Packit 0d464f
Packit 0d464f
    if ((_rowPtrs.size() != 3) && (_rowPtrs.size() != 1))
Packit 0d464f
        throw Iex::NoImplExc ("Only 1 and 3 channel encoding is supported");
Packit 0d464f
Packit 0d464f
    _dctData.resize(numComp);
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Allocate a temp aligned buffer to hold a rows worth of full 
Packit 0d464f
    // 8x8 half-float blocks
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    unsigned char *rowBlockHandle = new unsigned char
Packit 0d464f
        [numComp * numBlocksX * 64 * sizeof(unsigned short) + _SSE_ALIGNMENT];
Packit 0d464f
Packit 0d464f
    unsigned short *rowBlock[3];
Packit 0d464f
Packit 0d464f
    rowBlock[0] = (unsigned short*)rowBlockHandle;
Packit 0d464f
Packit 0d464f
    for (int i = 0; i < _SSE_ALIGNMENT; ++i)
Packit 0d464f
    {
Packit 0d464f
        if (((size_t)(rowBlockHandle + i) & _SSE_ALIGNMENT_MASK) == 0)
Packit 0d464f
            rowBlock[0] = (unsigned short *)(rowBlockHandle + i);
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    for (int comp = 1; comp < numComp; ++comp)
Packit 0d464f
        rowBlock[comp] = rowBlock[comp - 1] + numBlocksX * 64;
Packit 0d464f
 
Packit 0d464f
    //
Packit 0d464f
    // Pack DC components together by common plane, so we can get 
Packit 0d464f
    // a little more out of differencing them. We'll always have 
Packit 0d464f
    // one component per block, so we can computed offsets.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    currDcComp[0] = (unsigned short *)_packedDc;
Packit 0d464f
Packit 0d464f
    for (unsigned int comp = 1; comp < numComp; ++comp)
Packit 0d464f
        currDcComp[comp] = currDcComp[comp - 1] + numBlocksX * numBlocksY;
Packit 0d464f
Packit 0d464f
    for (int blocky = 0; blocky < numBlocksY; ++blocky)
Packit 0d464f
    {
Packit 0d464f
        int maxY = 8;
Packit 0d464f
Packit 0d464f
        if (blocky == numBlocksY-1)
Packit 0d464f
            maxY = leftoverY;
Packit 0d464f
Packit 0d464f
        int maxX = 8;
Packit 0d464f
Packit 0d464f
        for (int blockx = 0; blockx < numBlocksX; ++blockx)
Packit 0d464f
        {
Packit 0d464f
            if (blockx == numBlocksX-1)
Packit 0d464f
                maxX = leftoverX;
Packit 0d464f
Packit 0d464f
            //
Packit 0d464f
            // If we can detect that the block is constant values
Packit 0d464f
            // (all components only have DC values, and all AC is 0),
Packit 0d464f
            // we can do everything only on 1 value, instead of all
Packit 0d464f
            // 64. 
Packit 0d464f
            //
Packit 0d464f
            // This won't really help for regular images, but it is
Packit 0d464f
            // meant more for layers with large swaths of black 
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            bool blockIsConstant = true;
Packit 0d464f
Packit 0d464f
            for (unsigned int comp = 0; comp < numComp; ++comp)
Packit 0d464f
            {
Packit 0d464f
Packit 0d464f
                //
Packit 0d464f
                // DC component is stored separately
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                #ifdef IMF_HAVE_SSE2
Packit 0d464f
                    {
Packit 0d464f
                        __m128i *dst = (__m128i*)halfZigBlock[comp]._buffer;
Packit 0d464f
Packit 0d464f
                        dst[7] = _mm_setzero_si128();
Packit 0d464f
                        dst[6] = _mm_setzero_si128();
Packit 0d464f
                        dst[5] = _mm_setzero_si128();
Packit 0d464f
                        dst[4] = _mm_setzero_si128();
Packit 0d464f
                        dst[3] = _mm_setzero_si128();
Packit 0d464f
                        dst[2] = _mm_setzero_si128();
Packit 0d464f
                        dst[1] = _mm_setzero_si128();
Packit 0d464f
                        dst[0] = _mm_insert_epi16
Packit 0d464f
                            (_mm_setzero_si128(), *currDcComp[comp]++, 0);
Packit 0d464f
                    }
Packit 0d464f
                #else  /* IMF_HAVE_SSE2 */
Packit 0d464f
Packit 0d464f
                    memset (halfZigBlock[comp]._buffer, 0, 64 * 2);
Packit 0d464f
                    halfZigBlock[comp]._buffer[0] = *currDcComp[comp]++;
Packit 0d464f
Packit 0d464f
                #endif /* IMF_HAVE_SSE2 */
Packit 0d464f
Packit 0d464f
                _packedDcCount++;
Packit 0d464f
                
Packit 0d464f
                //
Packit 0d464f
                // UnRLE the AC. This will modify currAcComp
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                lastNonZero = unRleAc (currAcComp, halfZigBlock[comp]._buffer);
Packit 0d464f
Packit 0d464f
                //
Packit 0d464f
                // Convert from XDR to NATIVE
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                if (!_isNativeXdr)
Packit 0d464f
                {
Packit 0d464f
                    for (int i = 0; i < 64; ++i)
Packit 0d464f
                    {
Packit 0d464f
                        tmpShortXdr      = halfZigBlock[comp]._buffer[i];
Packit 0d464f
                        tmpConstCharPtr  = (const char *)&tmpShortXdr;
Packit 0d464f
Packit 0d464f
                        Xdr::read<CharPtrIO> (tmpConstCharPtr, tmpShortNative);
Packit 0d464f
Packit 0d464f
                        halfZigBlock[comp]._buffer[i] = tmpShortNative;
Packit 0d464f
                    }
Packit 0d464f
                }
Packit 0d464f
Packit 0d464f
                if (lastNonZero == 0)
Packit 0d464f
                {
Packit 0d464f
                    //
Packit 0d464f
                    // DC only case - AC components are all 0   
Packit 0d464f
                    //
Packit 0d464f
Packit 0d464f
                    half h;
Packit 0d464f
Packit 0d464f
                    h.setBits (halfZigBlock[comp]._buffer[0]);
Packit 0d464f
                    _dctData[comp]._buffer[0] = (float)h;
Packit 0d464f
Packit 0d464f
                    dctInverse8x8DcOnly (_dctData[comp]._buffer);
Packit 0d464f
                }
Packit 0d464f
                else
Packit 0d464f
                {
Packit 0d464f
                    //
Packit 0d464f
                    // We have some AC components that are non-zero. 
Packit 0d464f
                    // Can't use the 'constant block' optimization
Packit 0d464f
                    //
Packit 0d464f
Packit 0d464f
                    blockIsConstant = false;
Packit 0d464f
Packit 0d464f
                    //
Packit 0d464f
                    // Un-Zig zag 
Packit 0d464f
                    //
Packit 0d464f
Packit 0d464f
                    (*fromHalfZigZag)
Packit 0d464f
                        (halfZigBlock[comp]._buffer, _dctData[comp]._buffer);
Packit 0d464f
Packit 0d464f
                    //
Packit 0d464f
                    // Zig-Zag indices in normal layout are as follows:
Packit 0d464f
                    //
Packit 0d464f
                    // 0   1   3   6   10  15  21  28
Packit 0d464f
                    // 2   4   7   11  16  22  29  36
Packit 0d464f
                    // 5   8   12  17  23  30  37  43
Packit 0d464f
                    // 9   13  18  24  31  38  44  49
Packit 0d464f
                    // 14  19  25  32  39  45  50  54
Packit 0d464f
                    // 20  26  33  40  46  51  55  58
Packit 0d464f
                    // 27  34  41  47  52  56  59  61
Packit 0d464f
                    // 35  42  48  53  57  60  62  63
Packit 0d464f
                    //
Packit 0d464f
                    // If lastNonZero is less than the first item on
Packit 0d464f
                    // each row, we know that the whole row is zero and 
Packit 0d464f
                    // can be skipped in the row-oriented part of the
Packit 0d464f
                    // iDCT. 
Packit 0d464f
                    //
Packit 0d464f
                    // The unrolled logic here is:
Packit 0d464f
                    //
Packit 0d464f
                    //    if lastNonZero < rowStartIdx[i],
Packit 0d464f
                    //    zeroedRows = rowsEmpty[i]
Packit 0d464f
                    //
Packit 0d464f
                    // where:
Packit 0d464f
                    //
Packit 0d464f
                    //    const int rowStartIdx[] = {2, 5, 9, 14, 20, 27, 35};
Packit 0d464f
                    //    const int rowsEmpty[]   = {7, 6, 5,  4,  3,  2,  1};
Packit 0d464f
                    //
Packit 0d464f
Packit 0d464f
                    if (lastNonZero < 2)
Packit 0d464f
                        dctInverse8x8_7(_dctData[comp]._buffer);
Packit 0d464f
                    else if (lastNonZero < 5)
Packit 0d464f
                        dctInverse8x8_6(_dctData[comp]._buffer);
Packit 0d464f
                    else if (lastNonZero < 9)
Packit 0d464f
                        dctInverse8x8_5(_dctData[comp]._buffer);
Packit 0d464f
                    else if (lastNonZero < 14)
Packit 0d464f
                        dctInverse8x8_4(_dctData[comp]._buffer);
Packit 0d464f
                    else if (lastNonZero < 20)
Packit 0d464f
                        dctInverse8x8_3(_dctData[comp]._buffer);
Packit 0d464f
                    else if (lastNonZero < 27)
Packit 0d464f
                        dctInverse8x8_2(_dctData[comp]._buffer);
Packit 0d464f
                    else if (lastNonZero < 35)
Packit 0d464f
                        dctInverse8x8_1(_dctData[comp]._buffer);
Packit 0d464f
                    else
Packit 0d464f
                        dctInverse8x8_0(_dctData[comp]._buffer);
Packit 0d464f
                }
Packit 0d464f
            }
Packit 0d464f
Packit 0d464f
            //
Packit 0d464f
            // Perform the CSC
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            if (numComp == 3)
Packit 0d464f
            {
Packit 0d464f
                if (!blockIsConstant)
Packit 0d464f
                {
Packit 0d464f
                    csc709Inverse64 (_dctData[0]._buffer, 
Packit 0d464f
                                     _dctData[1]._buffer, 
Packit 0d464f
                                     _dctData[2]._buffer);
Packit 0d464f
Packit 0d464f
                }
Packit 0d464f
                else
Packit 0d464f
                {
Packit 0d464f
                    csc709Inverse (_dctData[0]._buffer[0], 
Packit 0d464f
                                   _dctData[1]._buffer[0], 
Packit 0d464f
                                   _dctData[2]._buffer[0]);
Packit 0d464f
                }
Packit 0d464f
            }
Packit 0d464f
Packit 0d464f
            //
Packit 0d464f
            // Float -> Half conversion. 
Packit 0d464f
            //
Packit 0d464f
            // If the block has a constant value, just convert the first pixel.
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            for (unsigned int comp = 0; comp < numComp; ++comp)
Packit 0d464f
            {
Packit 0d464f
                if (!blockIsConstant)
Packit 0d464f
                {
Packit 0d464f
                    (*convertFloatToHalf64)
Packit 0d464f
                        (&rowBlock[comp][blockx*64], _dctData[comp]._buffer);
Packit 0d464f
                }
Packit 0d464f
                else
Packit 0d464f
                {
Packit 0d464f
                    #if IMF_HAVE_SSE2
Packit 0d464f
Packit 0d464f
                        __m128i *dst = (__m128i*)&rowBlock[comp][blockx*64];
Packit 0d464f
Packit 0d464f
                        dst[0] = _mm_set1_epi16
Packit 0d464f
                            (((half)_dctData[comp]._buffer[0]).bits());
Packit 0d464f
Packit 0d464f
                        dst[1] = dst[0];
Packit 0d464f
                        dst[2] = dst[0];
Packit 0d464f
                        dst[3] = dst[0];
Packit 0d464f
                        dst[4] = dst[0];
Packit 0d464f
                        dst[5] = dst[0];
Packit 0d464f
                        dst[6] = dst[0];
Packit 0d464f
                        dst[7] = dst[0];
Packit 0d464f
Packit 0d464f
                    #else  /* IMF_HAVE_SSE2 */
Packit 0d464f
Packit 0d464f
                        unsigned short *dst = &rowBlock[comp][blockx*64];
Packit 0d464f
Packit 0d464f
                        dst[0] = ((half)_dctData[comp]._buffer[0]).bits();
Packit 0d464f
Packit 0d464f
                        for (int i = 1; i < 64; ++i)
Packit 0d464f
                        {
Packit 0d464f
                            dst[i] = dst[0];
Packit 0d464f
                        }
Packit 0d464f
Packit 0d464f
                    #endif /* IMF_HAVE_SSE2 */
Packit 0d464f
                } // blockIsConstant
Packit 0d464f
            } // comp
Packit 0d464f
        } // blockx
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // At this point, we have half-float nonlinear value blocked
Packit 0d464f
        // in rowBlock[][]. We need to unblock the data, transfer
Packit 0d464f
        // back to linear, and write the results in the _rowPtrs[].
Packit 0d464f
        //
Packit 0d464f
        // There is a fast-path for aligned rows, which helps
Packit 0d464f
        // things a little. Since this fast path is only valid
Packit 0d464f
        // for full 8-element wide blocks, the partial x blocks
Packit 0d464f
        // are broken into a separate loop below.
Packit 0d464f
        //
Packit 0d464f
        // At the moment, the fast path requires:
Packit 0d464f
        //   * sse support
Packit 0d464f
        //   * aligned row pointers
Packit 0d464f
        //   * full 8-element wide blocks
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        for (int comp = 0; comp < numComp; ++comp)
Packit 0d464f
        {
Packit 0d464f
            //
Packit 0d464f
            // Test if we can use the fast path
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
        #ifdef IMF_HAVE_SSE2
Packit 0d464f
Packit 0d464f
            bool fastPath = true;
Packit 0d464f
Packit 0d464f
            for (int y = 8 * blocky; y < 8 * blocky + maxY; ++y)
Packit 0d464f
            {
Packit 0d464f
                if ((size_t)_rowPtrs[comp][y] & _SSE_ALIGNMENT_MASK)
Packit 0d464f
                    fastPath = false;
Packit 0d464f
            }
Packit 0d464f
Packit 0d464f
            if (fastPath)
Packit 0d464f
            {
Packit 0d464f
                //
Packit 0d464f
                // Handle all the full X blocks, in a fast path with sse2 and
Packit 0d464f
                // aligned row pointers
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                for (int y=8*blocky; y<8*blocky+maxY; ++y)
Packit 0d464f
                {
Packit 0d464f
                    __m128i *dst = (__m128i *)_rowPtrs[comp][y];
Packit 0d464f
                    __m128i *src = (__m128i *)&rowBlock[comp][(y & 0x7) * 8];
Packit 0d464f
Packit 0d464f
Packit 0d464f
                    for (int blockx = 0; blockx < numFullBlocksX; ++blockx)
Packit 0d464f
                    {
Packit 0d464f
                        //
Packit 0d464f
                        // These may need some twiddling.
Packit 0d464f
                        // Run with multiples of 8
Packit 0d464f
                        //
Packit 0d464f
Packit 0d464f
                        _mm_prefetch ((char *)(src + 16), _MM_HINT_NTA); 
Packit 0d464f
Packit 0d464f
                        unsigned short i0  = _mm_extract_epi16 (*src, 0);
Packit 0d464f
                        unsigned short i1  = _mm_extract_epi16 (*src, 1);
Packit 0d464f
                        unsigned short i2  = _mm_extract_epi16 (*src, 2);
Packit 0d464f
                        unsigned short i3  = _mm_extract_epi16 (*src, 3);
Packit 0d464f
Packit 0d464f
                        unsigned short i4  = _mm_extract_epi16 (*src, 4);
Packit 0d464f
                        unsigned short i5  = _mm_extract_epi16 (*src, 5);
Packit 0d464f
                        unsigned short i6  = _mm_extract_epi16 (*src, 6);
Packit 0d464f
                        unsigned short i7  = _mm_extract_epi16 (*src, 7);
Packit 0d464f
Packit 0d464f
                        i0 = _toLinear[i0];
Packit 0d464f
                        i1 = _toLinear[i1];
Packit 0d464f
                        i2 = _toLinear[i2];
Packit 0d464f
                        i3 = _toLinear[i3];
Packit 0d464f
Packit 0d464f
                        i4 = _toLinear[i4];
Packit 0d464f
                        i5 = _toLinear[i5];
Packit 0d464f
                        i6 = _toLinear[i6];
Packit 0d464f
                        i7 = _toLinear[i7];
Packit 0d464f
Packit 0d464f
                        *dst = _mm_insert_epi16 (_mm_setzero_si128(), i0, 0);
Packit 0d464f
                        *dst = _mm_insert_epi16 (*dst, i1, 1);
Packit 0d464f
                        *dst = _mm_insert_epi16 (*dst, i2, 2);
Packit 0d464f
                        *dst = _mm_insert_epi16 (*dst, i3, 3);
Packit 0d464f
Packit 0d464f
                        *dst = _mm_insert_epi16 (*dst, i4, 4);
Packit 0d464f
                        *dst = _mm_insert_epi16 (*dst, i5, 5);
Packit 0d464f
                        *dst = _mm_insert_epi16 (*dst, i6, 6);
Packit 0d464f
                        *dst = _mm_insert_epi16 (*dst, i7, 7);
Packit 0d464f
Packit 0d464f
                        src += 8;
Packit 0d464f
                        dst++;
Packit 0d464f
                    }
Packit 0d464f
                }
Packit 0d464f
            }
Packit 0d464f
            else
Packit 0d464f
            {
Packit 0d464f
Packit 0d464f
        #endif /* IMF_HAVE_SSE2 */
Packit 0d464f
Packit 0d464f
                //
Packit 0d464f
                // Basic scalar kinda slow path for handling the full X blocks
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                for (int y = 8 * blocky; y < 8 * blocky + maxY; ++y)
Packit 0d464f
                {
Packit 0d464f
                    unsigned short *dst = (unsigned short *)_rowPtrs[comp][y];
Packit 0d464f
Packit 0d464f
                    for (int blockx = 0; blockx < numFullBlocksX; ++blockx)
Packit 0d464f
                    {
Packit 0d464f
                        unsigned short *src =
Packit 0d464f
                            &rowBlock[comp][blockx * 64 + ((y & 0x7) * 8)];
Packit 0d464f
Packit 0d464f
                        dst[0] = _toLinear[src[0]];
Packit 0d464f
                        dst[1] = _toLinear[src[1]];
Packit 0d464f
                        dst[2] = _toLinear[src[2]];
Packit 0d464f
                        dst[3] = _toLinear[src[3]];
Packit 0d464f
Packit 0d464f
                        dst[4] = _toLinear[src[4]];
Packit 0d464f
                        dst[5] = _toLinear[src[5]];
Packit 0d464f
                        dst[6] = _toLinear[src[6]];
Packit 0d464f
                        dst[7] = _toLinear[src[7]];
Packit 0d464f
Packit 0d464f
                        dst += 8;
Packit 0d464f
                    }
Packit 0d464f
                }
Packit 0d464f
Packit 0d464f
        #ifdef IMF_HAVE_SSE2
Packit 0d464f
Packit 0d464f
            }
Packit 0d464f
Packit 0d464f
        #endif /* IMF_HAVE_SSE2 */
Packit 0d464f
Packit 0d464f
            //
Packit 0d464f
            // If we have partial X blocks, deal with all those now
Packit 0d464f
            // Since this should be minimal work, there currently
Packit 0d464f
            // is only one path that should work for everyone.
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            if (numFullBlocksX != numBlocksX)
Packit 0d464f
            {
Packit 0d464f
                for (int y = 8 * blocky; y < 8 * blocky + maxY; ++y)
Packit 0d464f
                {
Packit 0d464f
                    unsigned short *src = (unsigned short *)
Packit 0d464f
                        &rowBlock[comp][numFullBlocksX * 64 + ((y & 0x7) * 8)];
Packit 0d464f
Packit 0d464f
                    unsigned short *dst = (unsigned short *)_rowPtrs[comp][y];
Packit 0d464f
Packit 0d464f
                    dst += 8 * numFullBlocksX;
Packit 0d464f
Packit 0d464f
                    for (int x = 0; x < maxX; ++x)
Packit 0d464f
                    {
Packit 0d464f
                        *dst++ = _toLinear[*src++];
Packit 0d464f
                    }
Packit 0d464f
                }
Packit 0d464f
            }
Packit 0d464f
        } // comp
Packit 0d464f
    } // blocky
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Walk over all the channels that are of type FLOAT.
Packit 0d464f
    // Convert from HALF XDR back to FLOAT XDR.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    for (unsigned int chan = 0; chan < numComp; ++chan)
Packit 0d464f
    {
Packit 0d464f
Packit 0d464f
        if (_type[chan] != FLOAT)
Packit 0d464f
            continue;
Packit 0d464f
Packit 0d464f
        std::vector<unsigned short> halfXdr (_width);
Packit 0d464f
Packit 0d464f
        for (int y=0; y<_height; ++y)
Packit 0d464f
        {
Packit 0d464f
            char *floatXdrPtr = _rowPtrs[chan][y];
Packit 0d464f
Packit 0d464f
            memcpy(&halfXdr[0], floatXdrPtr, _width*sizeof(unsigned short));
Packit 0d464f
Packit 0d464f
            const char *halfXdrPtr = (const char *)(&halfXdr[0]);
Packit 0d464f
Packit 0d464f
            for (int x=0; x<_width; ++x)
Packit 0d464f
            {
Packit 0d464f
                half tmpHalf;
Packit 0d464f
Packit 0d464f
                Xdr::read<CharPtrIO> (halfXdrPtr, tmpHalf);
Packit 0d464f
                Xdr::write<CharPtrIO> (floatXdrPtr, (float)tmpHalf);
Packit 0d464f
Packit 0d464f
                // 
Packit 0d464f
                // Xdr::write and Xdr::read will advance the ptrs
Packit 0d464f
                //
Packit 0d464f
            }
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    delete[] rowBlockHandle;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
//
Packit 0d464f
// Un-RLE the packed AC components into 
Packit 0d464f
// a half buffer. The half block should 
Packit 0d464f
// be the full 8x8 block (in zig-zag order
Packit 0d464f
// still), not the first AC component. 
Packit 0d464f
//
Packit 0d464f
// currAcComp is advanced as bytes are decoded.
Packit 0d464f
//
Packit 0d464f
// This returns the index of the last non-zero
Packit 0d464f
// value in the buffer - with the index into zig zag
Packit 0d464f
// order data. If we return 0, we have DC only data.
Packit 0d464f
// 
Packit 0d464f
// This is assuminging that halfZigBlock is zero'ed
Packit 0d464f
// prior to calling
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
int 
Packit 0d464f
DwaCompressor::LossyDctDecoderBase::unRleAc
Packit 0d464f
    (unsigned short *&currAcComp,
Packit 0d464f
     unsigned short  *halfZigBlock) 
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // Un-RLE the RLE'd blocks. If we find an item whose
Packit 0d464f
    // high byte is 0xff, then insert the number of 0's
Packit 0d464f
    // as indicated by the low byte.
Packit 0d464f
    //
Packit 0d464f
    // Otherwise, just copy the number verbaitm.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    int lastNonZero          = 0;
Packit 0d464f
    int dctComp              = 1; 
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Start with a zero'ed block, so we don't have to
Packit 0d464f
    // write when we hit a run symbol
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    while (dctComp < 64)
Packit 0d464f
    {
Packit 0d464f
        if (*currAcComp == 0xff00)
Packit 0d464f
        {
Packit 0d464f
            // 
Packit 0d464f
            // End of block
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            dctComp = 64;
Packit 0d464f
Packit 0d464f
        }
Packit 0d464f
        else if ((*currAcComp) >> 8 == 0xff)
Packit 0d464f
        {
Packit 0d464f
            //
Packit 0d464f
            // Run detected! Insert 0's.
Packit 0d464f
            //
Packit 0d464f
            // Since the block has been zeroed, just advance the ptr
Packit 0d464f
            // 
Packit 0d464f
Packit 0d464f
            dctComp += (*currAcComp) & 0xff; 
Packit 0d464f
        }
Packit 0d464f
        else
Packit 0d464f
        {
Packit 0d464f
            // 
Packit 0d464f
            // Not a run, just copy over the value
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            lastNonZero = dctComp;
Packit 0d464f
            halfZigBlock[dctComp] = *currAcComp;
Packit 0d464f
Packit 0d464f
            dctComp++;
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        _packedAcCount++;
Packit 0d464f
        currAcComp++;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    return lastNonZero;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
// ==============================================================
Packit 0d464f
//
Packit 0d464f
//                     LossyDctEncoderBase
Packit 0d464f
//
Packit 0d464f
// --------------------------------------------------------------
Packit 0d464f
Packit 0d464f
DwaCompressor::LossyDctEncoderBase::LossyDctEncoderBase
Packit 0d464f
    (float quantBaseError,
Packit 0d464f
     char *packedAc,
Packit 0d464f
     char *packedDc,
Packit 0d464f
     const unsigned short *toNonlinear,
Packit 0d464f
     int width,
Packit 0d464f
     int height)
Packit 0d464f
:
Packit 0d464f
    _quantBaseError(quantBaseError),
Packit 0d464f
    _width(width),
Packit 0d464f
    _height(height),
Packit 0d464f
    _toNonlinear(toNonlinear),
Packit 0d464f
    _numAcComp(0),
Packit 0d464f
    _numDcComp(0),
Packit 0d464f
    _packedAc(packedAc),
Packit 0d464f
    _packedDc(packedDc)
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // Here, we take the generic JPEG quantization tables and
Packit 0d464f
    // normalize them by the smallest component in each table.
Packit 0d464f
    // This gives us a relationship amongst the DCT components,
Packit 0d464f
    // in terms of how sensitive each component is to
Packit 0d464f
    // error.
Packit 0d464f
    //
Packit 0d464f
    // A higher normalized value means we can quantize more,
Packit 0d464f
    // and a small normalized value means we can quantize less.
Packit 0d464f
    //
Packit 0d464f
    // Eventually, we will want an acceptable quantization
Packit 0d464f
    // error range for each component. We find this by
Packit 0d464f
    // multiplying some user-specified level (_quantBaseError)
Packit 0d464f
    // by the normalized table (_quantTableY, _quantTableCbCr) to
Packit 0d464f
    // find the acceptable quantization error range.
Packit 0d464f
    //
Packit 0d464f
    // The quantization table is not needed for decoding, and
Packit 0d464f
    // is not transmitted. So, if you want to get really fancy,
Packit 0d464f
    // you could derive some content-dependent quantization
Packit 0d464f
    // table, and the decoder would not need to be changed. But,
Packit 0d464f
    // for now, we'll just use statice quantization tables.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    int jpegQuantTableY[] =
Packit 0d464f
    {
Packit 0d464f
        16,  11,  10,  16,   24,   40,   51,   61,
Packit 0d464f
        12,  12,  14,  19,   26,   58,   60,   55,
Packit 0d464f
        14,  13,  16,  24,   40,   57,   69,   56,
Packit 0d464f
        14,  17,  22,  29,   51,   87,   80,   62,
Packit 0d464f
        18,  22,  37,  56,   68,  109,  103,   77,
Packit 0d464f
        24,  35,  55,  64,   81,  104,  113,   92,
Packit 0d464f
        49,  64,  78,  87,  103,  121,  120,  101,
Packit 0d464f
        72,  92,  95,  98,  112,  100,  103,   99
Packit 0d464f
    };
Packit 0d464f
Packit 0d464f
    int jpegQuantTableYMin = 10;
Packit 0d464f
Packit 0d464f
    int jpegQuantTableCbCr[] =
Packit 0d464f
    {
Packit 0d464f
        17,  18,  24,  47,  99,  99,  99,  99,
Packit 0d464f
        18,  21,  26,  66,  99,  99,  99,  99,
Packit 0d464f
        24,  26,  56,  99,  99,  99,  99,  99,
Packit 0d464f
        47,  66,  99,  99,  99,  99,  99,  99,
Packit 0d464f
        99,  99,  99,  99,  99,  99,  99,  99,
Packit 0d464f
        99,  99,  99,  99,  99,  99,  99,  99,
Packit 0d464f
        99,  99,  99,  99,  99,  99,  99,  99,
Packit 0d464f
        99,  99,  99,  99,  99,  99,  99,  99
Packit 0d464f
    };
Packit 0d464f
Packit 0d464f
    int jpegQuantTableCbCrMin = 17;
Packit 0d464f
Packit 0d464f
    for (int idx = 0; idx < 64; ++idx)
Packit 0d464f
    {
Packit 0d464f
        _quantTableY[idx] = static_cast<float> (jpegQuantTableY[idx]) /
Packit 0d464f
                            static_cast<float> (jpegQuantTableYMin);
Packit 0d464f
Packit 0d464f
        _quantTableCbCr[idx] = static_cast<float> (jpegQuantTableCbCr[idx]) /
Packit 0d464f
                               static_cast<float> (jpegQuantTableCbCrMin);
Packit 0d464f
    }
Packit 0d464f
    
Packit 0d464f
    if (_quantBaseError < 0)
Packit 0d464f
        quantBaseError = 0;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
DwaCompressor::LossyDctEncoderBase::~LossyDctEncoderBase () 
Packit 0d464f
{
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
//
Packit 0d464f
// Given three channels of source data, encoding by first applying
Packit 0d464f
// a color space conversion to a YCbCr space.  Otherwise, if we only
Packit 0d464f
// have one channel, just encode it as is. 
Packit 0d464f
//
Packit 0d464f
// Other numbers of channels are somewhat unexpected at this point,
Packit 0d464f
// and will throw an exception.
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DwaCompressor::LossyDctEncoderBase::execute ()
Packit 0d464f
{
Packit 0d464f
    int  numBlocksX   = (int)ceil ((float)_width / 8.0f);
Packit 0d464f
    int  numBlocksY   = (int)ceil ((float)_height/ 8.0f);
Packit 0d464f
Packit 0d464f
    half halfZigCoef[64]; 
Packit 0d464f
    half halfCoef[64];
Packit 0d464f
Packit 0d464f
    std::vector<unsigned short *> currDcComp (_rowPtrs.size());
Packit 0d464f
    unsigned short               *currAcComp = (unsigned short *)_packedAc;
Packit 0d464f
Packit 0d464f
    _dctData.resize (_rowPtrs.size());
Packit 0d464f
    _numAcComp = 0;
Packit 0d464f
    _numDcComp = 0;
Packit 0d464f
 
Packit 0d464f
    assert (_type.size() == _rowPtrs.size());
Packit 0d464f
    assert ((_rowPtrs.size() == 3) || (_rowPtrs.size() == 1));
Packit 0d464f
Packit 0d464f
    // 
Packit 0d464f
    // Allocate a temp half buffer to quantize into for
Packit 0d464f
    // any FLOAT source channels.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    int tmpHalfBufferElements = 0;
Packit 0d464f
Packit 0d464f
    for (unsigned int chan = 0; chan < _rowPtrs.size(); ++chan)
Packit 0d464f
        if (_type[chan] == FLOAT)
Packit 0d464f
            tmpHalfBufferElements += _width * _height;
Packit 0d464f
Packit 0d464f
    std::vector<unsigned short> tmpHalfBuffer (tmpHalfBufferElements);
Packit 0d464f
Packit 0d464f
    char *tmpHalfBufferPtr = 0;
Packit 0d464f
Packit 0d464f
    if (tmpHalfBufferElements)
Packit 0d464f
        tmpHalfBufferPtr = (char *)&tmpHalfBuffer[0];
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Run over all the float scanlines, quantizing, 
Packit 0d464f
    // and re-assigning _rowPtr[y]. We need to translate
Packit 0d464f
    // FLOAT XDR to HALF XDR.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    for (unsigned int chan = 0; chan < _rowPtrs.size(); ++chan)
Packit 0d464f
    {
Packit 0d464f
        if (_type[chan] != FLOAT)
Packit 0d464f
            continue;
Packit 0d464f
    
Packit 0d464f
        for (int y = 0; y < _height; ++y)
Packit 0d464f
        {
Packit 0d464f
            float       src = 0;
Packit 0d464f
            const char *srcXdr = _rowPtrs[chan][y];
Packit 0d464f
            char       *dstXdr = tmpHalfBufferPtr;
Packit 0d464f
           
Packit 0d464f
            for (int x = 0; x < _width; ++x)
Packit 0d464f
            {
Packit 0d464f
Packit 0d464f
                Xdr::read<CharPtrIO> (srcXdr, src);
Packit 0d464f
                Xdr::write<CharPtrIO> (dstXdr, ((half)src).bits());
Packit 0d464f
Packit 0d464f
                //
Packit 0d464f
                // Xdr::read and Xdr::write will advance the ptr
Packit 0d464f
                //
Packit 0d464f
            }
Packit 0d464f
Packit 0d464f
            _rowPtrs[chan][y] = (const char *)tmpHalfBufferPtr;
Packit 0d464f
            tmpHalfBufferPtr += _width * sizeof (unsigned short);
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Pack DC components together by common plane, so we can get 
Packit 0d464f
    // a little more out of differencing them. We'll always have 
Packit 0d464f
    // one component per block, so we can computed offsets.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    currDcComp[0] = (unsigned short *)_packedDc;
Packit 0d464f
Packit 0d464f
    for (unsigned int chan = 1; chan < _rowPtrs.size(); ++chan)
Packit 0d464f
        currDcComp[chan] = currDcComp[chan-1] + numBlocksX * numBlocksY;
Packit 0d464f
Packit 0d464f
    for (int blocky = 0; blocky < numBlocksY; ++blocky)
Packit 0d464f
    {
Packit 0d464f
        for (int blockx = 0; blockx < numBlocksX; ++blockx)
Packit 0d464f
        {
Packit 0d464f
            half           h;
Packit 0d464f
            unsigned short tmpShortXdr, tmpShortNative;
Packit 0d464f
            char          *tmpCharPtr;
Packit 0d464f
Packit 0d464f
            for (unsigned int chan = 0; chan < _rowPtrs.size(); ++chan)
Packit 0d464f
            {
Packit 0d464f
                //
Packit 0d464f
                // Break the source into 8x8 blocks. If we don't
Packit 0d464f
                // fit at the edges, mirror.
Packit 0d464f
                //
Packit 0d464f
                // Also, convert from linear to nonlinear representation.
Packit 0d464f
                // Our source is assumed to be XDR, and we need to convert
Packit 0d464f
                // to NATIVE prior to converting to float.
Packit 0d464f
                //
Packit 0d464f
                // If we're converting linear -> nonlinear, assume that the
Packit 0d464f
                // XDR -> NATIVE conversion is built into the lookup. Otherwise,
Packit 0d464f
                // we'll need to explicitly do it.
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                for (int y = 0; y < 8; ++y)
Packit 0d464f
                {
Packit 0d464f
                    for (int x = 0; x < 8; ++x)
Packit 0d464f
                    {
Packit 0d464f
                        int vx = 8 * blockx + x;
Packit 0d464f
                        int vy = 8 * blocky + y;
Packit 0d464f
Packit 0d464f
                        if (vx >= _width)
Packit 0d464f
                            vx = _width - (vx - (_width - 1));
Packit 0d464f
                        
Packit 0d464f
                        if (vx < 0) vx = _width-1;
Packit 0d464f
Packit 0d464f
                        if (vy >=_height)
Packit 0d464f
                            vy = _height - (vy - (_height - 1));
Packit 0d464f
Packit 0d464f
                        if (vy < 0) vy = _height-1;
Packit 0d464f
                    
Packit 0d464f
                        tmpShortXdr =
Packit 0d464f
                            ((const unsigned short *)(_rowPtrs[chan])[vy])[vx];
Packit 0d464f
Packit 0d464f
                        if (_toNonlinear)
Packit 0d464f
                        {
Packit 0d464f
                            h.setBits (_toNonlinear[tmpShortXdr]);
Packit 0d464f
                        }
Packit 0d464f
                        else
Packit 0d464f
                        {
Packit 0d464f
                            const char *tmpConstCharPtr =
Packit 0d464f
                                (const char *)(&tmpShortXdr);
Packit 0d464f
Packit 0d464f
                            Xdr::read<CharPtrIO>
Packit 0d464f
                                (tmpConstCharPtr, tmpShortNative);
Packit 0d464f
Packit 0d464f
                            h.setBits(tmpShortNative);
Packit 0d464f
                        }
Packit 0d464f
Packit 0d464f
                        _dctData[chan]._buffer[y * 8 + x] = (float)h;
Packit 0d464f
                    } // x
Packit 0d464f
                } // y
Packit 0d464f
            } // chan
Packit 0d464f
Packit 0d464f
            //
Packit 0d464f
            // Color space conversion
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            if (_rowPtrs.size() == 3)
Packit 0d464f
            {
Packit 0d464f
                csc709Forward64 (_dctData[0]._buffer, 
Packit 0d464f
                                 _dctData[1]._buffer, 
Packit 0d464f
                                 _dctData[2]._buffer);
Packit 0d464f
            }
Packit 0d464f
Packit 0d464f
            for (unsigned int chan = 0; chan < _rowPtrs.size(); ++chan)
Packit 0d464f
            {
Packit 0d464f
                //
Packit 0d464f
                // Forward DCT
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                dctForward8x8(_dctData[chan]._buffer);
Packit 0d464f
Packit 0d464f
                //
Packit 0d464f
                // Quantize to half, and zigzag
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                if (chan == 0)
Packit 0d464f
                {
Packit 0d464f
                    for (int i = 0; i < 64; ++i)
Packit 0d464f
                    {
Packit 0d464f
                        halfCoef[i] =
Packit 0d464f
                            quantize ((half)_dctData[chan]._buffer[i],
Packit 0d464f
                                      _quantBaseError*_quantTableY[i]);
Packit 0d464f
                    }
Packit 0d464f
                }
Packit 0d464f
                else
Packit 0d464f
                {
Packit 0d464f
                    for (int i = 0; i < 64; ++i)
Packit 0d464f
                    {
Packit 0d464f
                        halfCoef[i] =
Packit 0d464f
                            quantize ((half)_dctData[chan]._buffer[i],
Packit 0d464f
                                      _quantBaseError*_quantTableCbCr[i]);
Packit 0d464f
                    }
Packit 0d464f
                }
Packit 0d464f
Packit 0d464f
                toZigZag (halfZigCoef, halfCoef);
Packit 0d464f
                
Packit 0d464f
                //
Packit 0d464f
                // Convert from NATIVE back to XDR, before we write out
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                for (int i = 0; i < 64; ++i)
Packit 0d464f
                {
Packit 0d464f
                    tmpCharPtr = (char *)&tmpShortXdr;
Packit 0d464f
                    Xdr::write<CharPtrIO>(tmpCharPtr, halfZigCoef[i].bits());
Packit 0d464f
                    halfZigCoef[i].setBits(tmpShortXdr);
Packit 0d464f
                }
Packit 0d464f
Packit 0d464f
                //
Packit 0d464f
                // Save the DC component separately, to be compressed on
Packit 0d464f
                // its own.
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                *currDcComp[chan]++ = halfZigCoef[0].bits();
Packit 0d464f
                _numDcComp++;
Packit 0d464f
                
Packit 0d464f
                //
Packit 0d464f
                // Then RLE the AC components (which will record the count
Packit 0d464f
                // of the resulting number of items)
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                rleAc (halfZigCoef, currAcComp);
Packit 0d464f
            } // chan
Packit 0d464f
        } // blockx
Packit 0d464f
    } // blocky              
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
// 
Packit 0d464f
// Reorder from zig-zag order to normal ordering
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
void 
Packit 0d464f
DwaCompressor::LossyDctEncoderBase::toZigZag (half *dst, half *src) 
Packit 0d464f
{
Packit 0d464f
    const int remap[] =
Packit 0d464f
    {
Packit 0d464f
         0, 
Packit 0d464f
         1,  8,
Packit 0d464f
        16,  9,  2,
Packit 0d464f
         3, 10, 17, 24,
Packit 0d464f
        32, 25, 18, 11, 4,
Packit 0d464f
         5, 12, 19, 26, 33, 40,
Packit 0d464f
        48, 41, 34, 27, 20, 13, 6,
Packit 0d464f
         7, 14, 21, 28, 35, 42, 49, 56,
Packit 0d464f
            57, 50, 43, 36, 29, 22, 15,
Packit 0d464f
                23, 30, 37, 44, 51, 58,
Packit 0d464f
                    59, 52, 45, 38, 31,
Packit 0d464f
                        39, 46, 53, 60,
Packit 0d464f
                            61, 54, 47,
Packit 0d464f
                                55, 62,
Packit 0d464f
                                    63
Packit 0d464f
    };
Packit 0d464f
Packit 0d464f
    for (int i=0; i<64; ++i)
Packit 0d464f
        dst[i] = src[remap[i]];
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
//
Packit 0d464f
// Precomputing the bit count runs faster than using
Packit 0d464f
// the builtin instruction, at least in one case..
Packit 0d464f
//
Packit 0d464f
// Precomputing 8-bits is no slower than 16-bits,
Packit 0d464f
// and saves a fair bit of overhead..
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
DwaCompressor::LossyDctEncoderBase::countSetBits (unsigned short src)
Packit 0d464f
{
Packit 0d464f
    static const unsigned short numBitsSet[256] =
Packit 0d464f
    {
Packit 0d464f
        0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
Packit 0d464f
        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
Packit 0d464f
        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
Packit 0d464f
        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
Packit 0d464f
        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
Packit 0d464f
        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
Packit 0d464f
        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
Packit 0d464f
        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
Packit 0d464f
        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
Packit 0d464f
        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
Packit 0d464f
        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
Packit 0d464f
        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
Packit 0d464f
        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
Packit 0d464f
        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
Packit 0d464f
        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
Packit 0d464f
        4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
Packit 0d464f
    };
Packit 0d464f
Packit 0d464f
    return numBitsSet[src & 0xff] + numBitsSet[src >> 8];
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
//
Packit 0d464f
// Take a DCT coefficient, as well as an acceptable error. Search
Packit 0d464f
// nearby values within the error tolerance, that have fewer 
Packit 0d464f
// bits set.
Packit 0d464f
//
Packit 0d464f
// The list of candidates has been pre-computed and sorted 
Packit 0d464f
// in order of increasing numbers of bits set. This way, we
Packit 0d464f
// can stop searching as soon as we find a candidate that
Packit 0d464f
// is within the error tolerance.
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
half
Packit 0d464f
DwaCompressor::LossyDctEncoderBase::quantize (half src, float errorTolerance)
Packit 0d464f
{
Packit 0d464f
    half            tmp;
Packit 0d464f
    float           srcFloat      = (float)src;
Packit 0d464f
    int             numSetBits    = countSetBits(src.bits());
Packit 0d464f
    const unsigned short *closest = closestData + closestDataOffset[src.bits()];
Packit 0d464f
Packit 0d464f
    for (int targetNumSetBits = numSetBits - 1;
Packit 0d464f
         targetNumSetBits >= 0;
Packit 0d464f
         --targetNumSetBits)
Packit 0d464f
    {
Packit 0d464f
        tmp.setBits (*closest);
Packit 0d464f
Packit 0d464f
        if (fabs ((float)tmp - srcFloat) < errorTolerance)
Packit 0d464f
            return tmp;
Packit 0d464f
Packit 0d464f
        closest++;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    return src;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
//
Packit 0d464f
// RLE the zig-zag of the AC components + copy over 
Packit 0d464f
// into another tmp buffer
Packit 0d464f
//
Packit 0d464f
// Try to do a simple RLE scheme to reduce run's of 0's. This
Packit 0d464f
// differs from the jpeg EOB case, since EOB just indicates that
Packit 0d464f
// the rest of the block is zero. In our case, we have lots of
Packit 0d464f
// NaN symbols, which shouldn't be allowed to occur in DCT 
Packit 0d464f
// coefficents - so we'll use them for encoding runs.
Packit 0d464f
//
Packit 0d464f
// If the high byte is 0xff, then we have a run of 0's, of length
Packit 0d464f
// given by the low byte. For example, 0xff03 would be a run
Packit 0d464f
// of 3 0's, starting at the current location.
Packit 0d464f
//
Packit 0d464f
// block is our block of 64 coefficients
Packit 0d464f
// acPtr a pointer to back the RLE'd values into.
Packit 0d464f
//
Packit 0d464f
// This will advance the counter, _numAcComp.
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DwaCompressor::LossyDctEncoderBase::rleAc
Packit 0d464f
    (half *block,
Packit 0d464f
     unsigned short *&acPtr)
Packit 0d464f
{
Packit 0d464f
    int dctComp              = 1; 
Packit 0d464f
    unsigned short rleSymbol = 0x0;
Packit 0d464f
Packit 0d464f
    while (dctComp < 64)
Packit 0d464f
    {
Packit 0d464f
        int runLen = 1;
Packit 0d464f
    
Packit 0d464f
        //
Packit 0d464f
        // If we don't have a 0, output verbatim
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        if (block[dctComp].bits() != rleSymbol)
Packit 0d464f
        {
Packit 0d464f
            *acPtr++ =  block[dctComp].bits();
Packit 0d464f
            _numAcComp++;
Packit 0d464f
Packit 0d464f
            dctComp += runLen;
Packit 0d464f
            continue;
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // We're sitting on a 0, so see how big the run is.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        while ((dctComp+runLen < 64) && 
Packit 0d464f
               (block[dctComp+runLen].bits() == rleSymbol))
Packit 0d464f
        {
Packit 0d464f
            runLen++;
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // If the run len is too small, just output verbatim
Packit 0d464f
        // otherwise output our run token
Packit 0d464f
        //
Packit 0d464f
        // Originally, we wouldn't have a separate symbol for
Packit 0d464f
        // "end of block". But in some experimentation, it looks
Packit 0d464f
        // like using 0xff00 for "end of block" can save a bit
Packit 0d464f
        // of space. 
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        if (runLen == 1)
Packit 0d464f
        {
Packit 0d464f
            runLen           = 1;
Packit 0d464f
            *acPtr++ = block[dctComp].bits();
Packit 0d464f
            _numAcComp++;
Packit 0d464f
Packit 0d464f
            //
Packit 0d464f
            // Using 0xff00 for "end of block"
Packit 0d464f
            //
Packit 0d464f
        }
Packit 0d464f
        else if (runLen + dctComp == 64)
Packit 0d464f
        {
Packit 0d464f
            //
Packit 0d464f
            // Signal EOB
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            *acPtr++ = 0xff00;
Packit 0d464f
            _numAcComp++;
Packit 0d464f
        }
Packit 0d464f
        else
Packit 0d464f
        {
Packit 0d464f
            // 
Packit 0d464f
            // Signal normal run
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            *acPtr++   = 0xff00 | runLen;
Packit 0d464f
            _numAcComp++;
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // Advance by runLen
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        dctComp += runLen;
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
// ==============================================================
Packit 0d464f
//
Packit 0d464f
//                     DwaCompressor
Packit 0d464f
//
Packit 0d464f
// --------------------------------------------------------------
Packit 0d464f
Packit 0d464f
// 
Packit 0d464f
// DwaCompressor()
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
DwaCompressor::DwaCompressor
Packit 0d464f
    (const Header &hdr,
Packit 0d464f
     int maxScanLineSize,
Packit 0d464f
     int numScanLines,
Packit 0d464f
     AcCompression acCompression)
Packit 0d464f
:
Packit 0d464f
    Compressor(hdr),
Packit 0d464f
    _acCompression(acCompression),
Packit 0d464f
    _maxScanLineSize(maxScanLineSize),
Packit 0d464f
    _numScanLines(numScanLines),
Packit 0d464f
    _channels(hdr.channels()),
Packit 0d464f
    _packedAcBuffer(0),
Packit 0d464f
    _packedAcBufferSize(0),
Packit 0d464f
    _packedDcBuffer(0),
Packit 0d464f
    _packedDcBufferSize(0),
Packit 0d464f
    _rleBuffer(0),
Packit 0d464f
    _rleBufferSize(0),
Packit 0d464f
    _outBuffer(0),
Packit 0d464f
    _outBufferSize(0),
Packit 0d464f
    _zip(0),
Packit 0d464f
    _dwaCompressionLevel(45.0)
Packit 0d464f
{
Packit 0d464f
    _min[0] = hdr.dataWindow().min.x;
Packit 0d464f
    _min[1] = hdr.dataWindow().min.y;
Packit 0d464f
    _max[0] = hdr.dataWindow().max.x;
Packit 0d464f
    _max[1] = hdr.dataWindow().max.y;
Packit 0d464f
Packit 0d464f
    for (int i=0; i < NUM_COMPRESSOR_SCHEMES; ++i) 
Packit 0d464f
    {
Packit 0d464f
        _planarUncBuffer[i] = 0;
Packit 0d464f
        _planarUncBufferSize[i] = 0;
Packit 0d464f
    }
Packit 0d464f
    
Packit 0d464f
    //
Packit 0d464f
    // Check the header for a quality attribute
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (hasDwaCompressionLevel (hdr))
Packit 0d464f
        _dwaCompressionLevel = dwaCompressionLevel (hdr);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
DwaCompressor::~DwaCompressor()
Packit 0d464f
{
Packit 0d464f
    delete[] _packedAcBuffer;
Packit 0d464f
    delete[] _packedDcBuffer;
Packit 0d464f
    delete[] _rleBuffer;
Packit 0d464f
    delete[] _outBuffer;
Packit 0d464f
    delete _zip;
Packit 0d464f
Packit 0d464f
    for (int i=0; i
Packit 0d464f
        delete[] _planarUncBuffer[i];
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
DwaCompressor::numScanLines() const
Packit 0d464f
{
Packit 0d464f
    return _numScanLines;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
Imf::Compressor::Format 
Packit 0d464f
DwaCompressor::format() const
Packit 0d464f
{
Packit 0d464f
    if (GLOBAL_SYSTEM_LITTLE_ENDIAN)
Packit 0d464f
        return NATIVE;
Packit 0d464f
    else
Packit 0d464f
        return XDR;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
DwaCompressor::compress
Packit 0d464f
    (const char *inPtr,
Packit 0d464f
     int inSize,
Packit 0d464f
     int minY,
Packit 0d464f
     const char *&outPtr)
Packit 0d464f
{
Packit 0d464f
    return compress
Packit 0d464f
        (inPtr,
Packit 0d464f
         inSize, 
Packit 0d464f
         Imath::Box2i (Imath::V2i (_min[0], minY),
Packit 0d464f
                       Imath::V2i (_max[0], minY + numScanLines() - 1)),
Packit 0d464f
         outPtr);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
DwaCompressor::compressTile
Packit 0d464f
    (const char *inPtr,
Packit 0d464f
     int inSize,
Packit 0d464f
     Imath::Box2i range,
Packit 0d464f
     const char *&outPtr)
Packit 0d464f
{
Packit 0d464f
    return compress (inPtr, inSize, range, outPtr);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int 
Packit 0d464f
DwaCompressor::compress
Packit 0d464f
    (const char *inPtr,
Packit 0d464f
     int inSize,
Packit 0d464f
     Imath::Box2i range,
Packit 0d464f
     const char  *&outPtr)
Packit 0d464f
{
Packit 0d464f
    const char *inDataPtr   = inPtr;
Packit 0d464f
    char       *packedAcEnd = 0;
Packit 0d464f
    char       *packedDcEnd = 0; 
Packit 0d464f
    int         fileVersion = 2;   // Starting with 2, we write the channel
Packit 0d464f
                                   // classification rules into the file
Packit 0d464f
Packit 0d464f
    if (fileVersion < 2) 
Packit 0d464f
        initializeLegacyChannelRules();
Packit 0d464f
    else 
Packit 0d464f
        initializeDefaultChannelRules();
Packit 0d464f
Packit 0d464f
    size_t outBufferSize = 0;
Packit 0d464f
    initializeBuffers(outBufferSize);
Packit 0d464f
Packit 0d464f
    unsigned short          channelRuleSize = 0;
Packit 0d464f
    std::vector<Classifier> channelRules;
Packit 0d464f
    if (fileVersion >= 2) 
Packit 0d464f
    {
Packit 0d464f
        relevantChannelRules(channelRules);
Packit 0d464f
Packit 0d464f
        channelRuleSize = Xdr::size<unsigned short>();
Packit 0d464f
        for (size_t i = 0; i < channelRules.size(); ++i) 
Packit 0d464f
            channelRuleSize += channelRules[i].size();
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Remember to allocate _outBuffer, if we haven't done so already.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    outBufferSize += channelRuleSize;
Packit 0d464f
    if (outBufferSize > _outBufferSize) 
Packit 0d464f
    {
Packit 0d464f
        _outBufferSize = outBufferSize;
Packit 0d464f
        if (_outBuffer == 0)
Packit 0d464f
            delete[] _outBuffer;       
Packit 0d464f
        _outBuffer = new char[outBufferSize];
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    char *outDataPtr = &_outBuffer[NUM_SIZES_SINGLE * sizeof(Imf::Int64) +
Packit 0d464f
                                   channelRuleSize];
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // We might not be dealing with any color data, in which
Packit 0d464f
    // case the AC buffer size will be 0, and deferencing
Packit 0d464f
    // a vector will not be a good thing to do.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (_packedAcBuffer)
Packit 0d464f
        packedAcEnd = _packedAcBuffer;
Packit 0d464f
Packit 0d464f
    if (_packedDcBuffer)
Packit 0d464f
        packedDcEnd = _packedDcBuffer;
Packit 0d464f
Packit 0d464f
    #define OBIDX(x) (Int64 *)&_outBuffer[x * sizeof (Int64)]
Packit 0d464f
Packit 0d464f
    Int64 *version                 = OBIDX (VERSION);
Packit 0d464f
    Int64 *unknownUncompressedSize = OBIDX (UNKNOWN_UNCOMPRESSED_SIZE);
Packit 0d464f
    Int64 *unknownCompressedSize   = OBIDX (UNKNOWN_COMPRESSED_SIZE);
Packit 0d464f
    Int64 *acCompressedSize        = OBIDX (AC_COMPRESSED_SIZE);
Packit 0d464f
    Int64 *dcCompressedSize        = OBIDX (DC_COMPRESSED_SIZE);
Packit 0d464f
    Int64 *rleCompressedSize       = OBIDX (RLE_COMPRESSED_SIZE);
Packit 0d464f
    Int64 *rleUncompressedSize     = OBIDX (RLE_UNCOMPRESSED_SIZE);
Packit 0d464f
    Int64 *rleRawSize              = OBIDX (RLE_RAW_SIZE);
Packit 0d464f
Packit 0d464f
    Int64 *totalAcUncompressedCount = OBIDX (AC_UNCOMPRESSED_COUNT);
Packit 0d464f
    Int64 *totalDcUncompressedCount = OBIDX (DC_UNCOMPRESSED_COUNT);
Packit 0d464f
Packit 0d464f
    Int64 *acCompression            = OBIDX (AC_COMPRESSION);
Packit 0d464f
Packit 0d464f
    int minX   = range.min.x;
Packit 0d464f
    int maxX   = std::min(range.max.x, _max[0]);
Packit 0d464f
    int minY   = range.min.y;
Packit 0d464f
    int maxY   = std::min(range.max.y, _max[1]);
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Zero all the numbers in the chunk header
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    memset (_outBuffer, 0, NUM_SIZES_SINGLE * sizeof (Int64));
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Setup the AC compression strategy and the version in the data block,
Packit 0d464f
    // then write the relevant channel classification rules if needed
Packit 0d464f
    //
Packit 0d464f
    *version       = fileVersion;  
Packit 0d464f
    *acCompression = _acCompression;
Packit 0d464f
Packit 0d464f
    setupChannelData (minX, minY, maxX, maxY);
Packit 0d464f
Packit 0d464f
    if (fileVersion >= 2) 
Packit 0d464f
    {
Packit 0d464f
        char *writePtr = &_outBuffer[NUM_SIZES_SINGLE * sizeof(Imf::Int64)];
Packit 0d464f
        Xdr::write<CharPtrIO> (writePtr, channelRuleSize);
Packit 0d464f
        
Packit 0d464f
        for (size_t i = 0; i < channelRules.size(); ++i) 
Packit 0d464f
            channelRules[i].write(writePtr);
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Determine the start of each row in the input buffer
Packit 0d464f
    // Channels are interleaved by scanline
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    std::vector<bool> encodedChannels (_channelData.size());
Packit 0d464f
    std::vector< std::vector<const char *> > rowPtrs (_channelData.size());
Packit 0d464f
Packit 0d464f
    for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
Packit 0d464f
        encodedChannels[chan] = false;
Packit 0d464f
Packit 0d464f
    inDataPtr =  inPtr;
Packit 0d464f
Packit 0d464f
    for (int y = minY; y <= maxY; ++y)
Packit 0d464f
    {
Packit 0d464f
        for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
Packit 0d464f
        {
Packit 0d464f
Packit 0d464f
            ChannelData *cd = &_channelData[chan];
Packit 0d464f
Packit 0d464f
            if (Imath::modp(y, cd->ySampling) != 0)
Packit 0d464f
                continue;
Packit 0d464f
Packit 0d464f
            rowPtrs[chan].push_back(inDataPtr);
Packit 0d464f
            inDataPtr += cd->width * Imf::pixelTypeSize(cd->type);
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    inDataPtr = inPtr;
Packit 0d464f
Packit 0d464f
    // 
Packit 0d464f
    // Make a pass over all our CSC sets and try to encode them first
Packit 0d464f
    // 
Packit 0d464f
Packit 0d464f
    for (unsigned int csc = 0; csc < _cscSets.size(); ++csc)
Packit 0d464f
    {
Packit 0d464f
Packit 0d464f
        LossyDctEncoderCsc encoder
Packit 0d464f
            (_dwaCompressionLevel / 100000.f,
Packit 0d464f
             rowPtrs[_cscSets[csc].idx[0]],
Packit 0d464f
             rowPtrs[_cscSets[csc].idx[1]],
Packit 0d464f
             rowPtrs[_cscSets[csc].idx[2]],
Packit 0d464f
             packedAcEnd,
Packit 0d464f
             packedDcEnd,
Packit 0d464f
             dwaCompressorToNonlinear,
Packit 0d464f
             _channelData[_cscSets[csc].idx[0]].width,
Packit 0d464f
             _channelData[_cscSets[csc].idx[0]].height,
Packit 0d464f
             _channelData[_cscSets[csc].idx[0]].type,
Packit 0d464f
             _channelData[_cscSets[csc].idx[1]].type,
Packit 0d464f
             _channelData[_cscSets[csc].idx[2]].type);
Packit 0d464f
Packit 0d464f
        encoder.execute();
Packit 0d464f
Packit 0d464f
        *totalAcUncompressedCount  += encoder.numAcValuesEncoded();
Packit 0d464f
        *totalDcUncompressedCount  += encoder.numDcValuesEncoded();
Packit 0d464f
Packit 0d464f
        packedAcEnd += encoder.numAcValuesEncoded() * sizeof(unsigned short);
Packit 0d464f
        packedDcEnd += encoder.numDcValuesEncoded() * sizeof(unsigned short);
Packit 0d464f
Packit 0d464f
        encodedChannels[_cscSets[csc].idx[0]] = true;
Packit 0d464f
        encodedChannels[_cscSets[csc].idx[1]] = true;
Packit 0d464f
        encodedChannels[_cscSets[csc].idx[2]] = true;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
Packit 0d464f
    {
Packit 0d464f
        ChannelData *cd = &_channelData[chan];
Packit 0d464f
Packit 0d464f
        if (encodedChannels[chan])
Packit 0d464f
            continue;
Packit 0d464f
Packit 0d464f
        switch (cd->compression)
Packit 0d464f
        {
Packit 0d464f
          case LOSSY_DCT:
Packit 0d464f
Packit 0d464f
            //
Packit 0d464f
            // For LOSSY_DCT, treat this just like the CSC'd case,
Packit 0d464f
            // but only operate on one channel
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            {
Packit 0d464f
                const unsigned short *nonlinearLut = 0;
Packit 0d464f
Packit 0d464f
                if (!cd->pLinear)
Packit 0d464f
                    nonlinearLut = dwaCompressorToNonlinear; 
Packit 0d464f
Packit 0d464f
                LossyDctEncoder encoder
Packit 0d464f
                    (_dwaCompressionLevel / 100000.f,
Packit 0d464f
                     rowPtrs[chan],
Packit 0d464f
                     packedAcEnd,
Packit 0d464f
                     packedDcEnd,
Packit 0d464f
                     nonlinearLut,
Packit 0d464f
                     cd->width,
Packit 0d464f
                     cd->height,
Packit 0d464f
                     cd->type);
Packit 0d464f
Packit 0d464f
                encoder.execute();
Packit 0d464f
Packit 0d464f
                *totalAcUncompressedCount  += encoder.numAcValuesEncoded();
Packit 0d464f
                *totalDcUncompressedCount  += encoder.numDcValuesEncoded();
Packit 0d464f
Packit 0d464f
                packedAcEnd +=
Packit 0d464f
                    encoder.numAcValuesEncoded() * sizeof (unsigned short);
Packit 0d464f
Packit 0d464f
                packedDcEnd +=
Packit 0d464f
                    encoder.numDcValuesEncoded() * sizeof (unsigned short);
Packit 0d464f
            }
Packit 0d464f
Packit 0d464f
            break;
Packit 0d464f
Packit 0d464f
          case RLE:
Packit 0d464f
Packit 0d464f
            //
Packit 0d464f
            // For RLE, bash the bytes up so that the first bytes of each
Packit 0d464f
            // pixel are contingous, as are the second bytes, and so on.
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            for (unsigned int y = 0; y < rowPtrs[chan].size(); ++y)
Packit 0d464f
            {
Packit 0d464f
                const char *row = rowPtrs[chan][y];
Packit 0d464f
Packit 0d464f
                for (int x = 0; x < cd->width; ++x)
Packit 0d464f
                {
Packit 0d464f
                    for (int byte = 0;
Packit 0d464f
                         byte < Imf::pixelTypeSize (cd->type);
Packit 0d464f
                         ++byte)
Packit 0d464f
                    {
Packit 0d464f
                            
Packit 0d464f
                        *cd->planarUncRleEnd[byte]++ = *row++;
Packit 0d464f
                    }
Packit 0d464f
                }
Packit 0d464f
Packit 0d464f
                *rleRawSize += cd->width * Imf::pixelTypeSize(cd->type);
Packit 0d464f
            }
Packit 0d464f
Packit 0d464f
            break;
Packit 0d464f
Packit 0d464f
          case UNKNOWN:
Packit 0d464f
           
Packit 0d464f
            //
Packit 0d464f
            // Otherwise, just copy data over verbatim
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            {
Packit 0d464f
                int scanlineSize = cd->width * Imf::pixelTypeSize(cd->type);
Packit 0d464f
Packit 0d464f
                for (unsigned int y = 0; y < rowPtrs[chan].size(); ++y)
Packit 0d464f
                {
Packit 0d464f
                    memcpy (cd->planarUncBufferEnd,
Packit 0d464f
                            rowPtrs[chan][y],
Packit 0d464f
                            scanlineSize);
Packit 0d464f
    
Packit 0d464f
                    cd->planarUncBufferEnd += scanlineSize;
Packit 0d464f
                }
Packit 0d464f
Packit 0d464f
                *unknownUncompressedSize += cd->planarUncSize;
Packit 0d464f
            }
Packit 0d464f
Packit 0d464f
            break;
Packit 0d464f
Packit 0d464f
          default:
Packit 0d464f
Packit 0d464f
            assert (false);
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        encodedChannels[chan] = true;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Pack the Unknown data into the output buffer first. Instead of
Packit 0d464f
    // just copying it uncompressed, try zlib compression at least.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (*unknownUncompressedSize > 0)
Packit 0d464f
    {
Packit 0d464f
        uLongf inSize  = (uLongf)(*unknownUncompressedSize);
Packit 0d464f
        uLongf outSize = (uLongf)(ceil ((float)inSize * 1.01f) + 100);
Packit 0d464f
Packit 0d464f
        if (Z_OK != ::compress2 ((Bytef *)outDataPtr,
Packit 0d464f
                                 &outSize,
Packit 0d464f
                                 (const Bytef *)_planarUncBuffer[UNKNOWN],
Packit 0d464f
                                 inSize,
Packit 0d464f
                                 9))
Packit 0d464f
        {
Packit 0d464f
            throw Iex::BaseExc ("Data compression (zlib) failed.");
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        outDataPtr += outSize;
Packit 0d464f
        *unknownCompressedSize = outSize;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Now, pack all the Lossy DCT coefficients into our output
Packit 0d464f
    // buffer, with Huffman encoding.
Packit 0d464f
    //
Packit 0d464f
    // Also, record the compressed size and the number of 
Packit 0d464f
    // uncompressed componentns we have.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (*totalAcUncompressedCount > 0)
Packit 0d464f
    { 
Packit 0d464f
        switch (_acCompression)
Packit 0d464f
        {
Packit 0d464f
          case STATIC_HUFFMAN:
Packit 0d464f
Packit 0d464f
            *acCompressedSize = (int)
Packit 0d464f
                hufCompress((unsigned short *)_packedAcBuffer,
Packit 0d464f
                            (int)*totalAcUncompressedCount,
Packit 0d464f
                            outDataPtr);                
Packit 0d464f
            break;
Packit 0d464f
Packit 0d464f
          case DEFLATE:
Packit 0d464f
Packit 0d464f
            {
Packit 0d464f
                uLongf destLen = (uLongf)
Packit 0d464f
                    (2 * (*totalAcUncompressedCount) * sizeof (unsigned short));
Packit 0d464f
Packit 0d464f
                if (Z_OK != ::compress2
Packit 0d464f
                                ((Bytef *)outDataPtr,
Packit 0d464f
                                 &destLen,
Packit 0d464f
                                 (Bytef *)_packedAcBuffer, 
Packit 0d464f
                                 (uLong)(*totalAcUncompressedCount
Packit 0d464f
                                                * sizeof (unsigned short)),
Packit 0d464f
                                 9))
Packit 0d464f
                {
Packit 0d464f
                    throw Iex::InputExc ("Data compression (zlib) failed.");
Packit 0d464f
                }
Packit 0d464f
Packit 0d464f
                *acCompressedSize = destLen;        
Packit 0d464f
            }
Packit 0d464f
Packit 0d464f
            break;
Packit 0d464f
Packit 0d464f
          default:
Packit 0d464f
            
Packit 0d464f
            assert (false);
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        outDataPtr += *acCompressedSize;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    // 
Packit 0d464f
    // Handle the DC components separately
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (*totalDcUncompressedCount > 0)
Packit 0d464f
    {
Packit 0d464f
        *dcCompressedSize = _zip->compress
Packit 0d464f
            (_packedDcBuffer,
Packit 0d464f
             (int)(*totalDcUncompressedCount) * sizeof (unsigned short),
Packit 0d464f
             outDataPtr);
Packit 0d464f
Packit 0d464f
        outDataPtr += *dcCompressedSize;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    // 
Packit 0d464f
    // If we have RLE data, first RLE encode it and set the uncompressed
Packit 0d464f
    // size. Then, deflate the results and set the compressed size.
Packit 0d464f
    //    
Packit 0d464f
Packit 0d464f
    if (*rleRawSize > 0)
Packit 0d464f
    {
Packit 0d464f
        *rleUncompressedSize = rleCompress
Packit 0d464f
            ((int)(*rleRawSize),
Packit 0d464f
             _planarUncBuffer[RLE],
Packit 0d464f
             (signed char *)_rleBuffer);
Packit 0d464f
Packit 0d464f
        uLongf dstLen =
Packit 0d464f
            (uLongf)ceil (1.01f * (float) * rleUncompressedSize) + 24;
Packit 0d464f
Packit 0d464f
        if (Z_OK != ::compress2
Packit 0d464f
                        ((Bytef *)outDataPtr, 
Packit 0d464f
                         &dstLen, 
Packit 0d464f
                         (Bytef *)_rleBuffer, 
Packit 0d464f
                         (uLong)(*rleUncompressedSize),
Packit 0d464f
                         9))
Packit 0d464f
        {
Packit 0d464f
            throw Iex::BaseExc ("Error compressing RLE'd data.");
Packit 0d464f
        }
Packit 0d464f
        
Packit 0d464f
       *rleCompressedSize = dstLen;
Packit 0d464f
        outDataPtr       += *rleCompressedSize;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    // 
Packit 0d464f
    // Flip the counters to XDR format
Packit 0d464f
    //         
Packit 0d464f
Packit 0d464f
    for (int i = 0; i < NUM_SIZES_SINGLE; ++i)
Packit 0d464f
    {
Packit 0d464f
        Int64  src = *(((Int64 *)_outBuffer) + i);
Packit 0d464f
        char  *dst = (char *)(((Int64 *)_outBuffer) + i);
Packit 0d464f
Packit 0d464f
        Xdr::write<CharPtrIO> (dst, src);
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // We're done - compute the number of bytes we packed
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    outPtr = _outBuffer;
Packit 0d464f
Packit 0d464f
    return static_cast<int>(outDataPtr - _outBuffer + 1);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
DwaCompressor::uncompress
Packit 0d464f
    (const char *inPtr,
Packit 0d464f
     int inSize,
Packit 0d464f
     int minY,
Packit 0d464f
     const char *&outPtr)
Packit 0d464f
{
Packit 0d464f
    return uncompress (inPtr,
Packit 0d464f
                       inSize,
Packit 0d464f
                       Imath::Box2i (Imath::V2i (_min[0], minY),
Packit 0d464f
                       Imath::V2i (_max[0], minY + numScanLines() - 1)),
Packit 0d464f
                       outPtr);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int 
Packit 0d464f
DwaCompressor::uncompressTile
Packit 0d464f
    (const char *inPtr,
Packit 0d464f
     int inSize,
Packit 0d464f
     Imath::Box2i range,
Packit 0d464f
     const char *&outPtr)
Packit 0d464f
{
Packit 0d464f
    return uncompress (inPtr, inSize, range, outPtr);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int 
Packit 0d464f
DwaCompressor::uncompress
Packit 0d464f
    (const char *inPtr,
Packit 0d464f
     int inSize,
Packit 0d464f
     Imath::Box2i range,
Packit 0d464f
     const char *&outPtr)
Packit 0d464f
{
Packit 0d464f
    int minX = range.min.x;
Packit 0d464f
    int maxX = std::min (range.max.x, _max[0]);
Packit 0d464f
    int minY = range.min.y;
Packit 0d464f
    int maxY = std::min (range.max.y, _max[1]);
Packit 0d464f
Packit 0d464f
    int headerSize = NUM_SIZES_SINGLE*sizeof(Int64);
Packit 0d464f
    if (inSize < headerSize) 
Packit 0d464f
    {
Packit 0d464f
        throw Iex::InputExc("Error uncompressing DWA data"
Packit 0d464f
                            "(truncated header).");
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    // 
Packit 0d464f
    // Flip the counters from XDR to NATIVE
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    for (int i = 0; i < NUM_SIZES_SINGLE; ++i)
Packit 0d464f
    {
Packit 0d464f
        Int64      *dst =  (((Int64 *)inPtr) + i);
Packit 0d464f
        const char *src = (char *)(((Int64 *)inPtr) + i);
Packit 0d464f
Packit 0d464f
        Xdr::read<CharPtrIO> (src, *dst);
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Unwind all the counter info
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    const Int64 *inPtr64 = (const Int64*) inPtr;
Packit 0d464f
Packit 0d464f
    Int64 version                  = *(inPtr64 + VERSION);
Packit 0d464f
    Int64 unknownUncompressedSize  = *(inPtr64 + UNKNOWN_UNCOMPRESSED_SIZE);
Packit 0d464f
    Int64 unknownCompressedSize    = *(inPtr64 + UNKNOWN_COMPRESSED_SIZE);
Packit 0d464f
    Int64 acCompressedSize         = *(inPtr64 + AC_COMPRESSED_SIZE);
Packit 0d464f
    Int64 dcCompressedSize         = *(inPtr64 + DC_COMPRESSED_SIZE);
Packit 0d464f
    Int64 rleCompressedSize        = *(inPtr64 + RLE_COMPRESSED_SIZE);
Packit 0d464f
    Int64 rleUncompressedSize      = *(inPtr64 + RLE_UNCOMPRESSED_SIZE);
Packit 0d464f
    Int64 rleRawSize               = *(inPtr64 + RLE_RAW_SIZE);
Packit 0d464f
 
Packit 0d464f
    Int64 totalAcUncompressedCount = *(inPtr64 + AC_UNCOMPRESSED_COUNT); 
Packit 0d464f
    Int64 totalDcUncompressedCount = *(inPtr64 + DC_UNCOMPRESSED_COUNT); 
Packit 0d464f
Packit 0d464f
    Int64 acCompression            = *(inPtr64 + AC_COMPRESSION); 
Packit 0d464f
Packit 0d464f
    Int64 compressedSize           = unknownCompressedSize + 
Packit 0d464f
                                     acCompressedSize +
Packit 0d464f
                                     dcCompressedSize +
Packit 0d464f
                                     rleCompressedSize;
Packit 0d464f
Packit 0d464f
    const char *dataPtr            = inPtr + NUM_SIZES_SINGLE * sizeof(Int64);
Packit 0d464f
Packit 0d464f
    if (inSize < headerSize + compressedSize) 
Packit 0d464f
    {
Packit 0d464f
        throw Iex::InputExc("Error uncompressing DWA data"
Packit 0d464f
                            "(truncated file).");
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    if (unknownUncompressedSize < 0  || 
Packit 0d464f
        unknownCompressedSize < 0    ||
Packit 0d464f
        acCompressedSize < 0         || 
Packit 0d464f
        dcCompressedSize < 0         ||
Packit 0d464f
        rleCompressedSize < 0        || 
Packit 0d464f
        rleUncompressedSize < 0      ||
Packit 0d464f
        rleRawSize < 0               ||  
Packit 0d464f
        totalAcUncompressedCount < 0 || 
Packit 0d464f
        totalDcUncompressedCount < 0) 
Packit 0d464f
    {
Packit 0d464f
        throw Iex::InputExc("Error uncompressing DWA data"
Packit 0d464f
                            " (corrupt header).");
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    if (version < 2) 
Packit 0d464f
        initializeLegacyChannelRules();
Packit 0d464f
    else
Packit 0d464f
    {
Packit 0d464f
        unsigned short ruleSize = 0;
Packit 0d464f
        Xdr::read<CharPtrIO>(dataPtr, ruleSize);
Packit 0d464f
Packit 0d464f
        if (ruleSize < 0) 
Packit 0d464f
            throw Iex::InputExc("Error uncompressing DWA data"
Packit 0d464f
                                " (corrupt header file).");
Packit 0d464f
Packit 0d464f
        headerSize += ruleSize;
Packit 0d464f
        if (inSize < headerSize + compressedSize)
Packit 0d464f
            throw Iex::InputExc("Error uncompressing DWA data"
Packit 0d464f
                                " (truncated file).");
Packit 0d464f
Packit 0d464f
        _channelRules.clear();
Packit 0d464f
        ruleSize -= Xdr::size<unsigned short> ();
Packit 0d464f
        while (ruleSize > 0) 
Packit 0d464f
        {
Packit 0d464f
            Classifier rule(dataPtr, ruleSize);
Packit 0d464f
            
Packit 0d464f
            _channelRules.push_back(rule);
Packit 0d464f
            ruleSize -= rule.size();
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
Packit 0d464f
    size_t outBufferSize = 0;
Packit 0d464f
    initializeBuffers(outBufferSize);
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Allocate _outBuffer, if we haven't done so already
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (_maxScanLineSize * numScanLines() > _outBufferSize) 
Packit 0d464f
    {
Packit 0d464f
        _outBufferSize = _maxScanLineSize * numScanLines();
Packit 0d464f
        if (_outBuffer != 0)
Packit 0d464f
            delete[] _outBuffer;
Packit 0d464f
        _outBuffer = new char[_maxScanLineSize * numScanLines()];
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
Packit 0d464f
    char *outBufferEnd = _outBuffer;
Packit 0d464f
Packit 0d464f
       
Packit 0d464f
    //
Packit 0d464f
    // Find the start of the RLE packed AC components and
Packit 0d464f
    // the DC components for each channel. This will be handy   
Packit 0d464f
    // if you want to decode the channels in parallel later on.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    char *packedAcBufferEnd = 0; 
Packit 0d464f
Packit 0d464f
    if (_packedAcBuffer)
Packit 0d464f
        packedAcBufferEnd = _packedAcBuffer;
Packit 0d464f
Packit 0d464f
    char *packedDcBufferEnd = 0;
Packit 0d464f
Packit 0d464f
    if (_packedDcBuffer)
Packit 0d464f
        packedDcBufferEnd = _packedDcBuffer;
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // UNKNOWN data is packed first, followed by the 
Packit 0d464f
    // Huffman-compressed AC, then the DC values, 
Packit 0d464f
    // and then the zlib compressed RLE data.
Packit 0d464f
    //
Packit 0d464f
    
Packit 0d464f
    const char *compressedUnknownBuf = dataPtr;
Packit 0d464f
Packit 0d464f
    const char *compressedAcBuf      = compressedUnknownBuf + 
Packit 0d464f
                                  static_cast<ptrdiff_t>(unknownCompressedSize);
Packit 0d464f
    const char *compressedDcBuf      = compressedAcBuf +
Packit 0d464f
                                  static_cast<ptrdiff_t>(acCompressedSize);
Packit 0d464f
    const char *compressedRleBuf     = compressedDcBuf + 
Packit 0d464f
                                  static_cast<ptrdiff_t>(dcCompressedSize);
Packit 0d464f
Packit 0d464f
    // 
Packit 0d464f
    // Sanity check that the version is something we expect. Right now, 
Packit 0d464f
    // we can decode version 0, 1, and 2. v1 adds 'end of block' symbols
Packit 0d464f
    // to the AC RLE. v2 adds channel classification rules at the 
Packit 0d464f
    // start of the data block.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if ((version < 0) || (version > 2))
Packit 0d464f
        throw Iex::InputExc ("Invalid version of compressed data block");    
Packit 0d464f
Packit 0d464f
    setupChannelData(minX, minY, maxX, maxY);
Packit 0d464f
Packit 0d464f
    // 
Packit 0d464f
    // Uncompress the UNKNOWN data into _planarUncBuffer[UNKNOWN]
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (unknownCompressedSize > 0)
Packit 0d464f
    {
Packit 0d464f
        uLongf outSize = static_cast<uLongf>(
Packit 0d464f
                ceil( (float)unknownUncompressedSize * 1.01) + 100);
Packit 0d464f
Packit 0d464f
        if (unknownUncompressedSize < 0 || 
Packit 0d464f
            outSize > _planarUncBufferSize[UNKNOWN]) 
Packit 0d464f
        {
Packit 0d464f
            throw Iex::InputExc("Error uncompressing DWA data"
Packit 0d464f
                                "(corrupt header).");
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        if (Z_OK != ::uncompress
Packit 0d464f
                        ((Bytef *)_planarUncBuffer[UNKNOWN],
Packit 0d464f
                         &outSize,
Packit 0d464f
                         (Bytef *)compressedUnknownBuf,
Packit 0d464f
                         (uLong)unknownCompressedSize))
Packit 0d464f
        {
Packit 0d464f
            throw Iex::BaseExc("Error uncompressing UNKNOWN data.");
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    // 
Packit 0d464f
    // Uncompress the AC data into _packedAcBuffer
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (acCompressedSize > 0)
Packit 0d464f
    {
Packit 0d464f
        if (totalAcUncompressedCount*sizeof(unsigned short) > _packedAcBufferSize)
Packit 0d464f
        {
Packit 0d464f
            throw Iex::InputExc("Error uncompressing DWA data"
Packit 0d464f
                                "(corrupt header).");
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // Don't trust the user to get it right, look in the file.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        switch (acCompression)
Packit 0d464f
        {
Packit 0d464f
          case STATIC_HUFFMAN:
Packit 0d464f
Packit 0d464f
            hufUncompress
Packit 0d464f
                (compressedAcBuf, 
Packit 0d464f
                 (int)acCompressedSize, 
Packit 0d464f
                 (unsigned short *)_packedAcBuffer, 
Packit 0d464f
                 (int)totalAcUncompressedCount); 
Packit 0d464f
Packit 0d464f
            break;
Packit 0d464f
Packit 0d464f
          case DEFLATE:
Packit 0d464f
            {
Packit 0d464f
                uLongf destLen =
Packit 0d464f
                    (int)(totalAcUncompressedCount) * sizeof (unsigned short);
Packit 0d464f
Packit 0d464f
                if (Z_OK != ::uncompress
Packit 0d464f
                                ((Bytef *)_packedAcBuffer,
Packit 0d464f
                                 &destLen,
Packit 0d464f
                                 (Bytef *)compressedAcBuf,
Packit 0d464f
                                 (uLong)acCompressedSize))
Packit 0d464f
                {
Packit 0d464f
                    throw Iex::InputExc ("Data decompression (zlib) failed.");
Packit 0d464f
                }
Packit 0d464f
Packit 0d464f
                if (totalAcUncompressedCount * sizeof (unsigned short) !=
Packit 0d464f
                                destLen)
Packit 0d464f
                {
Packit 0d464f
                    throw Iex::InputExc ("AC data corrupt.");     
Packit 0d464f
                }
Packit 0d464f
            }
Packit 0d464f
            break;
Packit 0d464f
Packit 0d464f
          default:
Packit 0d464f
Packit 0d464f
            throw Iex::NoImplExc ("Unknown AC Compression");
Packit 0d464f
            break;
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Uncompress the DC data into _packedDcBuffer
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (dcCompressedSize > 0)
Packit 0d464f
    {
Packit 0d464f
        if (totalDcUncompressedCount*sizeof(unsigned short) > _packedDcBufferSize)
Packit 0d464f
        {
Packit 0d464f
            throw Iex::InputExc("Error uncompressing DWA data"
Packit 0d464f
                                "(corrupt header).");
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        if (_zip->uncompress
Packit 0d464f
                    (compressedDcBuf, (int)dcCompressedSize, _packedDcBuffer)
Packit 0d464f
            != (int)totalDcUncompressedCount * sizeof (unsigned short))
Packit 0d464f
        {
Packit 0d464f
            throw Iex::BaseExc("DC data corrupt.");
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Uncompress the RLE data into _rleBuffer, then unRLE the results
Packit 0d464f
    // into _planarUncBuffer[RLE]
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (rleRawSize > 0)
Packit 0d464f
    {
Packit 0d464f
        if (rleUncompressedSize > _rleBufferSize ||
Packit 0d464f
            rleRawSize > _planarUncBufferSize[RLE])
Packit 0d464f
        {
Packit 0d464f
            throw Iex::InputExc("Error uncompressing DWA data"
Packit 0d464f
                                "(corrupt header).");
Packit 0d464f
        }
Packit 0d464f
 
Packit 0d464f
        uLongf dstLen = (uLongf)rleUncompressedSize;
Packit 0d464f
Packit 0d464f
        if (Z_OK != ::uncompress
Packit 0d464f
                        ((Bytef *)_rleBuffer,
Packit 0d464f
                         &dstLen,
Packit 0d464f
                         (Bytef *)compressedRleBuf,
Packit 0d464f
                         (uLong)rleCompressedSize))
Packit 0d464f
        {
Packit 0d464f
            throw Iex::BaseExc("Error uncompressing RLE data.");
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        if (dstLen != rleUncompressedSize)
Packit 0d464f
            throw Iex::BaseExc("RLE data corrupted");
Packit 0d464f
Packit 0d464f
        if (rleUncompress
Packit 0d464f
                ((int)rleUncompressedSize, 
Packit 0d464f
                 (int)rleRawSize,
Packit 0d464f
                 (signed char *)_rleBuffer,
Packit 0d464f
                 _planarUncBuffer[RLE]) != rleRawSize)
Packit 0d464f
        {        
Packit 0d464f
            throw Iex::BaseExc("RLE data corrupted");
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Determine the start of each row in the output buffer
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    std::vector<bool> decodedChannels (_channelData.size());
Packit 0d464f
    std::vector< std::vector<char *> > rowPtrs (_channelData.size());
Packit 0d464f
Packit 0d464f
    for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
Packit 0d464f
        decodedChannels[chan] = false;
Packit 0d464f
Packit 0d464f
    outBufferEnd = _outBuffer;
Packit 0d464f
Packit 0d464f
    for (int y = minY; y <= maxY; ++y)
Packit 0d464f
    {
Packit 0d464f
        for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
Packit 0d464f
        {
Packit 0d464f
            ChannelData *cd = &_channelData[chan];
Packit 0d464f
Packit 0d464f
            if (Imath::modp (y, cd->ySampling) != 0)
Packit 0d464f
                continue;
Packit 0d464f
Packit 0d464f
            rowPtrs[chan].push_back (outBufferEnd);
Packit 0d464f
            outBufferEnd += cd->width * Imf::pixelTypeSize (cd->type);
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Setup to decode each block of 3 channels that need to
Packit 0d464f
    // be handled together
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    for (unsigned int csc = 0; csc < _cscSets.size(); ++csc)
Packit 0d464f
    {
Packit 0d464f
        int rChan = _cscSets[csc].idx[0];    
Packit 0d464f
        int gChan = _cscSets[csc].idx[1];    
Packit 0d464f
        int bChan = _cscSets[csc].idx[2];    
Packit 0d464f
Packit 0d464f
Packit 0d464f
        LossyDctDecoderCsc decoder
Packit 0d464f
            (rowPtrs[rChan],
Packit 0d464f
             rowPtrs[gChan],
Packit 0d464f
             rowPtrs[bChan],
Packit 0d464f
             packedAcBufferEnd,
Packit 0d464f
             packedDcBufferEnd,
Packit 0d464f
             dwaCompressorToLinear,
Packit 0d464f
             _channelData[rChan].width,
Packit 0d464f
             _channelData[rChan].height,
Packit 0d464f
             _channelData[rChan].type,
Packit 0d464f
             _channelData[gChan].type,
Packit 0d464f
             _channelData[bChan].type);
Packit 0d464f
Packit 0d464f
        decoder.execute();
Packit 0d464f
Packit 0d464f
        packedAcBufferEnd +=
Packit 0d464f
            decoder.numAcValuesEncoded() * sizeof (unsigned short);
Packit 0d464f
Packit 0d464f
        packedDcBufferEnd +=
Packit 0d464f
            decoder.numDcValuesEncoded() * sizeof (unsigned short);
Packit 0d464f
Packit 0d464f
        decodedChannels[rChan] = true;
Packit 0d464f
        decodedChannels[gChan] = true;
Packit 0d464f
        decodedChannels[bChan] = true;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Setup to handle the remaining channels by themselves
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
Packit 0d464f
    {
Packit 0d464f
        if (decodedChannels[chan])
Packit 0d464f
            continue;
Packit 0d464f
Packit 0d464f
        ChannelData *cd = &_channelData[chan];
Packit 0d464f
        int pixelSize = Imf::pixelTypeSize (cd->type);
Packit 0d464f
Packit 0d464f
        switch (cd->compression)
Packit 0d464f
        {
Packit 0d464f
          case LOSSY_DCT:
Packit 0d464f
Packit 0d464f
            //
Packit 0d464f
            // Setup a single-channel lossy DCT decoder pointing
Packit 0d464f
            // at the output buffer
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            {
Packit 0d464f
                const unsigned short *linearLut = 0;
Packit 0d464f
Packit 0d464f
                if (!cd->pLinear)
Packit 0d464f
                    linearLut = dwaCompressorToLinear;
Packit 0d464f
Packit 0d464f
                LossyDctDecoder decoder
Packit 0d464f
                    (rowPtrs[chan],
Packit 0d464f
                     packedAcBufferEnd,
Packit 0d464f
                     packedDcBufferEnd,
Packit 0d464f
                     linearLut,
Packit 0d464f
                     cd->width,
Packit 0d464f
                     cd->height,
Packit 0d464f
                     cd->type);
Packit 0d464f
Packit 0d464f
                decoder.execute();   
Packit 0d464f
Packit 0d464f
                packedAcBufferEnd += 
Packit 0d464f
                    decoder.numAcValuesEncoded() * sizeof (unsigned short);
Packit 0d464f
Packit 0d464f
                packedDcBufferEnd += 
Packit 0d464f
                    decoder.numDcValuesEncoded() * sizeof (unsigned short);
Packit 0d464f
            }
Packit 0d464f
Packit 0d464f
            break;
Packit 0d464f
Packit 0d464f
          case RLE:
Packit 0d464f
Packit 0d464f
            //
Packit 0d464f
            // For the RLE case, the data has been un-RLE'd into
Packit 0d464f
            // planarUncRleEnd[], but is still split out by bytes.
Packit 0d464f
            // We need to rearrange the bytes back into the correct
Packit 0d464f
            // order in the output buffer;
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            {
Packit 0d464f
                int row = 0;
Packit 0d464f
Packit 0d464f
                for (int y = minY; y <= maxY; ++y)
Packit 0d464f
                {
Packit 0d464f
                    if (Imath::modp (y, cd->ySampling) != 0)
Packit 0d464f
                        continue;
Packit 0d464f
Packit 0d464f
                    char *dst = rowPtrs[chan][row];
Packit 0d464f
Packit 0d464f
                    if (pixelSize == 2)
Packit 0d464f
                    {
Packit 0d464f
                        interleaveByte2 (dst, 
Packit 0d464f
                                         cd->planarUncRleEnd[0],
Packit 0d464f
                                         cd->planarUncRleEnd[1],
Packit 0d464f
                                         cd->width);
Packit 0d464f
                                            
Packit 0d464f
                        cd->planarUncRleEnd[0] += cd->width;
Packit 0d464f
                        cd->planarUncRleEnd[1] += cd->width;
Packit 0d464f
                    }
Packit 0d464f
                    else
Packit 0d464f
                    {
Packit 0d464f
                        for (int x = 0; x < cd->width; ++x)
Packit 0d464f
                        {
Packit 0d464f
                            for (int byte = 0; byte < pixelSize; ++byte)
Packit 0d464f
                            {
Packit 0d464f
                               *dst++ = *cd->planarUncRleEnd[byte]++;
Packit 0d464f
                            }
Packit 0d464f
                        }
Packit 0d464f
                    }
Packit 0d464f
Packit 0d464f
                    row++;
Packit 0d464f
                }
Packit 0d464f
            }
Packit 0d464f
Packit 0d464f
            break;
Packit 0d464f
Packit 0d464f
          case UNKNOWN:
Packit 0d464f
Packit 0d464f
            //
Packit 0d464f
            // In the UNKNOWN case, data is already in planarUncBufferEnd
Packit 0d464f
            // and just needs to copied over to the output buffer
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            {
Packit 0d464f
                int row             = 0;
Packit 0d464f
                int dstScanlineSize = cd->width * Imf::pixelTypeSize (cd->type);
Packit 0d464f
Packit 0d464f
                for (int y = minY; y <= maxY; ++y)
Packit 0d464f
                {
Packit 0d464f
                    if (Imath::modp (y, cd->ySampling) != 0)
Packit 0d464f
                        continue;
Packit 0d464f
Packit 0d464f
                    memcpy (rowPtrs[chan][row],
Packit 0d464f
                            cd->planarUncBufferEnd,
Packit 0d464f
                            dstScanlineSize);
Packit 0d464f
Packit 0d464f
                    cd->planarUncBufferEnd += dstScanlineSize;
Packit 0d464f
                    row++;
Packit 0d464f
                }
Packit 0d464f
            }
Packit 0d464f
Packit 0d464f
            break;
Packit 0d464f
Packit 0d464f
          default:
Packit 0d464f
Packit 0d464f
            throw Iex::NoImplExc ("Unhandled compression scheme case");
Packit 0d464f
            break;
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        decodedChannels[chan] = true;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Return a ptr to _outBuffer
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    outPtr = _outBuffer;
Packit 0d464f
    return (int)(outBufferEnd - _outBuffer);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
// static
Packit 0d464f
void
Packit 0d464f
DwaCompressor::initializeFuncs()
Packit 0d464f
{
Packit 0d464f
    convertFloatToHalf64 = convertFloatToHalf64_scalar;
Packit 0d464f
    fromHalfZigZag       = fromHalfZigZag_scalar;
Packit 0d464f
Packit 0d464f
    CpuId cpuId;
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Setup HALF <-> FLOAT conversion implementations
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (cpuId.avx && cpuId.f16c)
Packit 0d464f
    {
Packit 0d464f
        convertFloatToHalf64 = convertFloatToHalf64_f16c;
Packit 0d464f
        fromHalfZigZag       = fromHalfZigZag_f16c;
Packit 0d464f
    } 
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Setup inverse DCT implementations
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    dctInverse8x8_0 = dctInverse8x8_scalar<0>;
Packit 0d464f
    dctInverse8x8_1 = dctInverse8x8_scalar<1>;
Packit 0d464f
    dctInverse8x8_2 = dctInverse8x8_scalar<2>;
Packit 0d464f
    dctInverse8x8_3 = dctInverse8x8_scalar<3>;
Packit 0d464f
    dctInverse8x8_4 = dctInverse8x8_scalar<4>;
Packit 0d464f
    dctInverse8x8_5 = dctInverse8x8_scalar<5>;
Packit 0d464f
    dctInverse8x8_6 = dctInverse8x8_scalar<6>;
Packit 0d464f
    dctInverse8x8_7 = dctInverse8x8_scalar<7>;
Packit 0d464f
Packit 0d464f
    if (cpuId.avx) 
Packit 0d464f
    {
Packit 0d464f
        dctInverse8x8_0 = dctInverse8x8_avx<0>;
Packit 0d464f
        dctInverse8x8_1 = dctInverse8x8_avx<1>;
Packit 0d464f
        dctInverse8x8_2 = dctInverse8x8_avx<2>;
Packit 0d464f
        dctInverse8x8_3 = dctInverse8x8_avx<3>;
Packit 0d464f
        dctInverse8x8_4 = dctInverse8x8_avx<4>;
Packit 0d464f
        dctInverse8x8_5 = dctInverse8x8_avx<5>;
Packit 0d464f
        dctInverse8x8_6 = dctInverse8x8_avx<6>;
Packit 0d464f
        dctInverse8x8_7 = dctInverse8x8_avx<7>;
Packit 0d464f
    } 
Packit 0d464f
    else if (cpuId.sse2) 
Packit 0d464f
    {
Packit 0d464f
        dctInverse8x8_0 = dctInverse8x8_sse2<0>;
Packit 0d464f
        dctInverse8x8_1 = dctInverse8x8_sse2<1>;
Packit 0d464f
        dctInverse8x8_2 = dctInverse8x8_sse2<2>;
Packit 0d464f
        dctInverse8x8_3 = dctInverse8x8_sse2<3>;
Packit 0d464f
        dctInverse8x8_4 = dctInverse8x8_sse2<4>;
Packit 0d464f
        dctInverse8x8_5 = dctInverse8x8_sse2<5>;
Packit 0d464f
        dctInverse8x8_6 = dctInverse8x8_sse2<6>;
Packit 0d464f
        dctInverse8x8_7 = dctInverse8x8_sse2<7>;
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
//
Packit 0d464f
// Handle channel classification and buffer allocation once we know
Packit 0d464f
// how to classify channels
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DwaCompressor::initializeBuffers (size_t &outBufferSize)
Packit 0d464f
{
Packit 0d464f
    classifyChannels (_channels, _channelData, _cscSets);
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // _outBuffer needs to be big enough to hold all our 
Packit 0d464f
    // compressed data - which could vary depending on what sort
Packit 0d464f
    // of channels we have. 
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    int maxOutBufferSize  = 0;
Packit 0d464f
    int numLossyDctChans  = 0;
Packit 0d464f
    int unknownBufferSize = 0;
Packit 0d464f
    int rleBufferSize     = 0;
Packit 0d464f
Packit 0d464f
    int maxLossyDctAcSize = (int)ceil ((float)numScanLines() / 8.0f) * 
Packit 0d464f
                            (int)ceil ((float)(_max[0] - _min[0] + 1) / 8.0f) *
Packit 0d464f
                            63 * sizeof (unsigned short);
Packit 0d464f
Packit 0d464f
    int maxLossyDctDcSize = (int)ceil ((float)numScanLines() / 8.0f) * 
Packit 0d464f
                            (int)ceil ((float)(_max[0] - _min[0] + 1) / 8.0f) *
Packit 0d464f
                            sizeof (unsigned short);
Packit 0d464f
Packit 0d464f
    for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
Packit 0d464f
    {
Packit 0d464f
        switch (_channelData[chan].compression)
Packit 0d464f
        {
Packit 0d464f
          case LOSSY_DCT:
Packit 0d464f
Packit 0d464f
            //
Packit 0d464f
            // This is the size of the number of packed
Packit 0d464f
            // components, plus the requirements for
Packit 0d464f
            // maximum Huffman encoding size.
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            maxOutBufferSize += 2 * maxLossyDctAcSize + 65536;
Packit 0d464f
            numLossyDctChans++;
Packit 0d464f
            break;
Packit 0d464f
Packit 0d464f
          case RLE:
Packit 0d464f
            {
Packit 0d464f
                //
Packit 0d464f
                // RLE, if gone horribly wrong, could double the size
Packit 0d464f
                // of the source data.
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                int rleAmount = 2 * numScanLines() * (_max[0] - _min[0] + 1) *
Packit 0d464f
                                Imf::pixelTypeSize (_channelData[chan].type);
Packit 0d464f
Packit 0d464f
                rleBufferSize += rleAmount;
Packit 0d464f
            }
Packit 0d464f
            break;
Packit 0d464f
Packit 0d464f
Packit 0d464f
          case UNKNOWN:
Packit 0d464f
Packit 0d464f
            unknownBufferSize += numScanLines() * (_max[0] - _min[0] + 1) *
Packit 0d464f
                                 Imf::pixelTypeSize (_channelData[chan].type);
Packit 0d464f
            break;
Packit 0d464f
Packit 0d464f
          default:
Packit 0d464f
Packit 0d464f
            throw Iex::NoImplExc ("Unhandled compression scheme case");
Packit 0d464f
            break;
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Also, since the results of the RLE are packed into 
Packit 0d464f
    // the output buffer, we need the extra room there. But
Packit 0d464f
    // we're going to zlib compress() the data we pack, 
Packit 0d464f
    // which could take slightly more space
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    maxOutBufferSize += (int)(ceil (1.01f * (float)rleBufferSize) + 100);
Packit 0d464f
    
Packit 0d464f
    //
Packit 0d464f
    // And the same goes for the UNKNOWN data
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    maxOutBufferSize += (int)(ceil (1.01f * (float)unknownBufferSize) + 100);
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Allocate a zip/deflate compressor big enought to hold the DC data
Packit 0d464f
    // and include it's compressed results in the size requirements
Packit 0d464f
    // for our output buffer
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (_zip == 0) 
Packit 0d464f
        _zip = new Zip (maxLossyDctDcSize * numLossyDctChans);
Packit 0d464f
    else if (_zip->maxRawSize() < maxLossyDctDcSize * numLossyDctChans)
Packit 0d464f
    {
Packit 0d464f
        delete _zip;
Packit 0d464f
        _zip = new Zip (maxLossyDctDcSize * numLossyDctChans);
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
Packit 0d464f
    maxOutBufferSize += _zip->maxCompressedSize();
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // We also need to reserve space at the head of the buffer to 
Packit 0d464f
    // write out the size of our various packed and compressed data.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    maxOutBufferSize += NUM_SIZES_SINGLE * sizeof (Int64); 
Packit 0d464f
                    
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Later, we're going to hijack outBuffer for the result of
Packit 0d464f
    // both encoding and decoding. So it needs to be big enough
Packit 0d464f
    // to hold either a buffers' worth of uncompressed or
Packit 0d464f
    // compressed data
Packit 0d464f
    //
Packit 0d464f
    // For encoding, we'll need _outBuffer to hold maxOutBufferSize bytes,
Packit 0d464f
    // but for decoding, we only need it to be maxScanLineSize*numScanLines.
Packit 0d464f
    // Cache the max size for now, and alloc the buffer when we either
Packit 0d464f
    // encode or decode.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    outBufferSize = maxOutBufferSize;
Packit 0d464f
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // _packedAcBuffer holds the quantized DCT coefficients prior
Packit 0d464f
    // to Huffman encoding
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (maxLossyDctAcSize * numLossyDctChans > _packedAcBufferSize)
Packit 0d464f
    {
Packit 0d464f
        _packedAcBufferSize = maxLossyDctAcSize * numLossyDctChans;
Packit 0d464f
        if (_packedAcBuffer != 0) 
Packit 0d464f
            delete[] _packedAcBuffer;
Packit 0d464f
        _packedAcBuffer = new char[_packedAcBufferSize];
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // _packedDcBuffer holds one quantized DCT coef per 8x8 block
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (maxLossyDctDcSize * numLossyDctChans > _packedDcBufferSize)
Packit 0d464f
    {
Packit 0d464f
        _packedDcBufferSize = maxLossyDctDcSize * numLossyDctChans;
Packit 0d464f
        if (_packedDcBuffer != 0) 
Packit 0d464f
            delete[] _packedDcBuffer;
Packit 0d464f
        _packedDcBuffer     = new char[_packedDcBufferSize];
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    if (rleBufferSize > _rleBufferSize) 
Packit 0d464f
    {
Packit 0d464f
        _rleBufferSize = rleBufferSize;
Packit 0d464f
        if (_rleBuffer != 0) 
Packit 0d464f
            delete[] _rleBuffer;
Packit 0d464f
        _rleBuffer = new char[rleBufferSize];
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    // 
Packit 0d464f
    // The planar uncompressed buffer will hold float data for LOSSY_DCT
Packit 0d464f
    // compressed values, and whatever the native type is for other
Packit 0d464f
    // channels. We're going to use this to hold data in a planar
Packit 0d464f
    // format, as opposed to the native interleaved format we take
Packit 0d464f
    // into compress() and give back from uncompress().
Packit 0d464f
    //
Packit 0d464f
    // This also makes it easier to compress the UNKNOWN and RLE data
Packit 0d464f
    // all in one swoop (for each compression scheme).
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    int planarUncBufferSize[NUM_COMPRESSOR_SCHEMES];
Packit 0d464f
    for (int i=0; i
Packit 0d464f
        planarUncBufferSize[i] = 0;
Packit 0d464f
Packit 0d464f
    for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
Packit 0d464f
    {
Packit 0d464f
        switch (_channelData[chan].compression)
Packit 0d464f
        {
Packit 0d464f
          case LOSSY_DCT:
Packit 0d464f
            break;
Packit 0d464f
Packit 0d464f
          case RLE:
Packit 0d464f
            planarUncBufferSize[RLE] +=
Packit 0d464f
                     numScanLines() * (_max[0] - _min[0] + 1) *
Packit 0d464f
                     Imf::pixelTypeSize (_channelData[chan].type);
Packit 0d464f
            break;
Packit 0d464f
Packit 0d464f
          case UNKNOWN: 
Packit 0d464f
            planarUncBufferSize[UNKNOWN] +=
Packit 0d464f
                     numScanLines() * (_max[0] - _min[0] + 1) *
Packit 0d464f
                     Imf::pixelTypeSize (_channelData[chan].type);
Packit 0d464f
            break;
Packit 0d464f
Packit 0d464f
          default:
Packit 0d464f
            throw Iex::NoImplExc ("Unhandled compression scheme case");
Packit 0d464f
            break;
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // UNKNOWN data is going to be zlib compressed, which needs 
Packit 0d464f
    // a little extra headroom
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (planarUncBufferSize[UNKNOWN] > 0)
Packit 0d464f
    {
Packit 0d464f
        planarUncBufferSize[UNKNOWN] =
Packit 0d464f
            (int) ceil (1.01f * (float)planarUncBufferSize[UNKNOWN]) + 100;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    for (int i = 0; i < NUM_COMPRESSOR_SCHEMES; ++i)
Packit 0d464f
    {
Packit 0d464f
        if (planarUncBufferSize[i] > _planarUncBufferSize[i]) 
Packit 0d464f
        {
Packit 0d464f
            _planarUncBufferSize[i] = planarUncBufferSize[i];
Packit 0d464f
            if (_planarUncBuffer[i] != 0) 
Packit 0d464f
                delete[] _planarUncBuffer[i];
Packit 0d464f
            _planarUncBuffer[i] = new char[planarUncBufferSize[i]];
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
//
Packit 0d464f
// Setup channel classification rules to use when writing files
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DwaCompressor::initializeDefaultChannelRules ()
Packit 0d464f
{
Packit 0d464f
    _channelRules.clear();
Packit 0d464f
Packit 0d464f
    _channelRules.push_back (Classifier ("R",     LOSSY_DCT, HALF,   0, false));
Packit 0d464f
    _channelRules.push_back (Classifier ("R",     LOSSY_DCT, FLOAT,  0, false));
Packit 0d464f
    _channelRules.push_back (Classifier ("G",     LOSSY_DCT, HALF,   1, false));
Packit 0d464f
    _channelRules.push_back (Classifier ("G",     LOSSY_DCT, FLOAT,  1, false));
Packit 0d464f
    _channelRules.push_back (Classifier ("B",     LOSSY_DCT, HALF,   2, false));
Packit 0d464f
    _channelRules.push_back (Classifier ("B",     LOSSY_DCT, FLOAT,  2, false));
Packit 0d464f
Packit 0d464f
    _channelRules.push_back (Classifier ("Y",     LOSSY_DCT, HALF,  -1, false));
Packit 0d464f
    _channelRules.push_back (Classifier ("Y",     LOSSY_DCT, FLOAT, -1, false));
Packit 0d464f
    _channelRules.push_back (Classifier ("BY",    LOSSY_DCT, HALF,  -1, false));
Packit 0d464f
    _channelRules.push_back (Classifier ("BY",    LOSSY_DCT, FLOAT, -1, false));
Packit 0d464f
    _channelRules.push_back (Classifier ("RY",    LOSSY_DCT, HALF,  -1, false));
Packit 0d464f
    _channelRules.push_back (Classifier ("RY",    LOSSY_DCT, FLOAT, -1, false));
Packit 0d464f
Packit 0d464f
    _channelRules.push_back (Classifier ("A",     RLE,       UINT,  -1, false));
Packit 0d464f
    _channelRules.push_back (Classifier ("A",     RLE,       HALF,  -1, false));
Packit 0d464f
    _channelRules.push_back (Classifier ("A",     RLE,       FLOAT, -1, false));
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
//
Packit 0d464f
// Setup channel classification rules when reading files with VERSION < 2
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DwaCompressor::initializeLegacyChannelRules ()
Packit 0d464f
{
Packit 0d464f
    _channelRules.clear();
Packit 0d464f
Packit 0d464f
    _channelRules.push_back (Classifier ("r",     LOSSY_DCT, HALF,   0, true));
Packit 0d464f
    _channelRules.push_back (Classifier ("r",     LOSSY_DCT, FLOAT,  0, true));
Packit 0d464f
    _channelRules.push_back (Classifier ("red",   LOSSY_DCT, HALF,   0, true));
Packit 0d464f
    _channelRules.push_back (Classifier ("red",   LOSSY_DCT, FLOAT,  0, true));
Packit 0d464f
    _channelRules.push_back (Classifier ("g",     LOSSY_DCT, HALF,   1, true));
Packit 0d464f
    _channelRules.push_back (Classifier ("g",     LOSSY_DCT, FLOAT,  1, true));
Packit 0d464f
    _channelRules.push_back (Classifier ("grn",   LOSSY_DCT, HALF,   1, true));
Packit 0d464f
    _channelRules.push_back (Classifier ("grn",   LOSSY_DCT, FLOAT,  1, true));
Packit 0d464f
    _channelRules.push_back (Classifier ("green", LOSSY_DCT, HALF,   1, true));
Packit 0d464f
    _channelRules.push_back (Classifier ("green", LOSSY_DCT, FLOAT,  1, true));
Packit 0d464f
    _channelRules.push_back (Classifier ("b",     LOSSY_DCT, HALF,   2, true));
Packit 0d464f
    _channelRules.push_back (Classifier ("b",     LOSSY_DCT, FLOAT,  2, true));
Packit 0d464f
    _channelRules.push_back (Classifier ("blu",   LOSSY_DCT, HALF,   2, true));
Packit 0d464f
    _channelRules.push_back (Classifier ("blu",   LOSSY_DCT, FLOAT,  2, true));
Packit 0d464f
    _channelRules.push_back (Classifier ("blue",  LOSSY_DCT, HALF,   2, true));
Packit 0d464f
    _channelRules.push_back (Classifier ("blue",  LOSSY_DCT, FLOAT,  2, true));
Packit 0d464f
Packit 0d464f
    _channelRules.push_back (Classifier ("y",     LOSSY_DCT, HALF,  -1, true));
Packit 0d464f
    _channelRules.push_back (Classifier ("y",     LOSSY_DCT, FLOAT, -1, true));
Packit 0d464f
    _channelRules.push_back (Classifier ("by",    LOSSY_DCT, HALF,  -1, true));
Packit 0d464f
    _channelRules.push_back (Classifier ("by",    LOSSY_DCT, FLOAT, -1, true));
Packit 0d464f
    _channelRules.push_back (Classifier ("ry",    LOSSY_DCT, HALF,  -1, true));
Packit 0d464f
    _channelRules.push_back (Classifier ("ry",    LOSSY_DCT, FLOAT, -1, true));
Packit 0d464f
    _channelRules.push_back (Classifier ("a",     RLE,       UINT,  -1, true));
Packit 0d464f
    _channelRules.push_back (Classifier ("a",     RLE,       HALF,  -1, true));
Packit 0d464f
    _channelRules.push_back (Classifier ("a",     RLE,       FLOAT, -1, true));
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
// 
Packit 0d464f
// Given a set of rules and ChannelData, figure out which rules apply
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DwaCompressor::relevantChannelRules (std::vector<Classifier> &rules) const 
Packit 0d464f
{
Packit 0d464f
    rules.clear();
Packit 0d464f
Packit 0d464f
    std::vector<std::string> suffixes;
Packit 0d464f
    
Packit 0d464f
    for (size_t cd = 0; cd < _channelData.size(); ++cd) 
Packit 0d464f
    {
Packit 0d464f
        std::string suffix  = _channelData[cd].name;
Packit 0d464f
        size_t      lastDot = suffix.find_last_of ('.');
Packit 0d464f
Packit 0d464f
        if (lastDot != std::string::npos)
Packit 0d464f
            suffix = suffix.substr (lastDot+1, std::string::npos);
Packit 0d464f
Packit 0d464f
        suffixes.push_back(suffix);
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    
Packit 0d464f
    for (size_t i = 0; i < _channelRules.size(); ++i) 
Packit 0d464f
    {
Packit 0d464f
        for (size_t cd = 0; cd < _channelData.size(); ++cd) 
Packit 0d464f
        {
Packit 0d464f
            if (_channelRules[i].match (suffixes[cd], _channelData[cd].type ))
Packit 0d464f
            {
Packit 0d464f
                rules.push_back (_channelRules[i]);
Packit 0d464f
                break;
Packit 0d464f
            }
Packit 0d464f
        }       
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
//
Packit 0d464f
// Take our initial list of channels, and cache the contents.
Packit 0d464f
//
Packit 0d464f
// Determine approprate compression schemes for each channel,
Packit 0d464f
// and figure out which sets should potentially be CSC'ed 
Packit 0d464f
// prior to lossy compression.
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DwaCompressor::classifyChannels
Packit 0d464f
    (ChannelList channels,
Packit 0d464f
     std::vector<ChannelData> &chanData,
Packit 0d464f
     std::vector<CscChannelSet> &cscData)
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // prefixMap used to map channel name prefixes to 
Packit 0d464f
    // potential CSC-able sets of channels.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    std::map<std::string, DwaCompressor::CscChannelSet> prefixMap;
Packit 0d464f
    std::vector<DwaCompressor::CscChannelSet>           tmpCscSet;
Packit 0d464f
Packit 0d464f
    unsigned int numChan = 0;
Packit 0d464f
Packit 0d464f
    for (ChannelList::Iterator c = channels.begin(); c != channels.end(); ++c)
Packit 0d464f
        numChan++;
Packit 0d464f
    
Packit 0d464f
    if (numChan)
Packit 0d464f
        chanData.resize (numChan);
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Cache the relevant data from the channel structs.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    unsigned int offset = 0;
Packit 0d464f
Packit 0d464f
    for (ChannelList::Iterator c = channels.begin(); c != channels.end(); ++c)
Packit 0d464f
    {
Packit 0d464f
        chanData[offset].name        = std::string (c.name());
Packit 0d464f
        chanData[offset].compression = UNKNOWN;
Packit 0d464f
        chanData[offset].xSampling   = c.channel().xSampling;
Packit 0d464f
        chanData[offset].ySampling   = c.channel().ySampling;
Packit 0d464f
        chanData[offset].type        = c.channel().type;
Packit 0d464f
        chanData[offset].pLinear     = c.channel().pLinear;
Packit 0d464f
Packit 0d464f
        offset++;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Try and figure out which channels should be
Packit 0d464f
    // compressed by which means.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    for (offset = 0; offset
Packit 0d464f
    {
Packit 0d464f
        std::string prefix  = "";
Packit 0d464f
        std::string suffix  = chanData[offset].name;
Packit 0d464f
        size_t      lastDot = suffix.find_last_of ('.');
Packit 0d464f
Packit 0d464f
        if (lastDot != std::string::npos)
Packit 0d464f
        {
Packit 0d464f
            prefix = suffix.substr (0,         lastDot);
Packit 0d464f
            suffix = suffix.substr (lastDot+1, std::string::npos);
Packit 0d464f
        } 
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // Make sure we have an entry in our CSC set map 
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        std::map<std::string, DwaCompressor::CscChannelSet>::iterator 
Packit 0d464f
            theSet = prefixMap.find (prefix);
Packit 0d464f
Packit 0d464f
        if (theSet == prefixMap.end())
Packit 0d464f
        {
Packit 0d464f
            DwaCompressor::CscChannelSet tmpSet;
Packit 0d464f
Packit 0d464f
            tmpSet.idx[0] = 
Packit 0d464f
            tmpSet.idx[1] = 
Packit 0d464f
            tmpSet.idx[2] = -1;
Packit 0d464f
Packit 0d464f
            prefixMap[prefix] = tmpSet;
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        // 
Packit 0d464f
        // Check the suffix against the list of classifications
Packit 0d464f
        // we defined previously. If the _cscIdx is not negative,
Packit 0d464f
        // it indicates that we should be part of a CSC group.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        for (std::vector<Classifier>::iterator i = _channelRules.begin();
Packit 0d464f
             i != _channelRules.end();
Packit 0d464f
             ++i)
Packit 0d464f
        {
Packit 0d464f
            if ( i->match(suffix, chanData[offset].type) )
Packit 0d464f
            {
Packit 0d464f
                chanData[offset].compression = i->_scheme;
Packit 0d464f
Packit 0d464f
                if ( i->_cscIdx >= 0)
Packit 0d464f
                    prefixMap[prefix].idx[i->_cscIdx] = offset;
Packit 0d464f
            }
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Finally, try and find RGB sets of channels which 
Packit 0d464f
    // can be CSC'ed to a Y'CbCr space prior to loss, for
Packit 0d464f
    // better compression.
Packit 0d464f
    //
Packit 0d464f
    // Walk over our set of candidates, and see who has
Packit 0d464f
    // all three channels defined (and has common sampling
Packit 0d464f
    // patterns, etc).
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    for (std::map<std::string, DwaCompressor::CscChannelSet>::iterator 
Packit 0d464f
         theItem = prefixMap.begin(); theItem != prefixMap.end();
Packit 0d464f
         ++theItem)
Packit 0d464f
    {
Packit 0d464f
        int red = (*theItem).second.idx[0];
Packit 0d464f
        int grn = (*theItem).second.idx[1];
Packit 0d464f
        int blu = (*theItem).second.idx[2];
Packit 0d464f
Packit 0d464f
        if ((red < 0) || (grn < 0) || (blu < 0))
Packit 0d464f
            continue;
Packit 0d464f
Packit 0d464f
        if ((chanData[red].xSampling != chanData[grn].xSampling) ||
Packit 0d464f
            (chanData[red].xSampling != chanData[blu].xSampling) ||
Packit 0d464f
            (chanData[grn].xSampling != chanData[blu].xSampling) ||
Packit 0d464f
            (chanData[red].ySampling != chanData[grn].ySampling) ||
Packit 0d464f
            (chanData[red].ySampling != chanData[blu].ySampling) ||
Packit 0d464f
            (chanData[grn].ySampling != chanData[blu].ySampling))
Packit 0d464f
        {
Packit 0d464f
            continue;
Packit 0d464f
        }
Packit 0d464f
        
Packit 0d464f
        tmpCscSet.push_back ((*theItem).second);
Packit 0d464f
    }
Packit 0d464f
    
Packit 0d464f
    size_t numCsc = tmpCscSet.size();
Packit 0d464f
Packit 0d464f
    if (numCsc)
Packit 0d464f
        cscData.resize(numCsc);
Packit 0d464f
Packit 0d464f
    for (offset = 0; offset < numCsc; ++offset)
Packit 0d464f
        cscData[offset] = tmpCscSet[offset];
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
Packit 0d464f
//
Packit 0d464f
// Setup some buffer pointers, determine channel sizes, things
Packit 0d464f
// like that.
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DwaCompressor::setupChannelData (int minX, int minY, int maxX, int maxY)
Packit 0d464f
{
Packit 0d464f
    char *planarUncBuffer[NUM_COMPRESSOR_SCHEMES];
Packit 0d464f
Packit 0d464f
    for (int i=0; i
Packit 0d464f
    {
Packit 0d464f
        planarUncBuffer[i] = 0;
Packit 0d464f
Packit 0d464f
        if (_planarUncBuffer[i])
Packit 0d464f
            planarUncBuffer[i] =  _planarUncBuffer[i];
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
Packit 0d464f
    {
Packit 0d464f
        ChannelData *cd = &_channelData[chan];
Packit 0d464f
Packit 0d464f
        cd->width  = Imf::numSamples (cd->xSampling, minX, maxX);
Packit 0d464f
        cd->height = Imf::numSamples (cd->ySampling, minY, maxY);
Packit 0d464f
                                
Packit 0d464f
        cd->planarUncSize =
Packit 0d464f
            cd->width * cd->height * Imf::pixelTypeSize (cd->type);
Packit 0d464f
                                  
Packit 0d464f
        cd->planarUncBuffer    = planarUncBuffer[cd->compression];
Packit 0d464f
        cd->planarUncBufferEnd = cd->planarUncBuffer;
Packit 0d464f
Packit 0d464f
        cd->planarUncRle[0]    = cd->planarUncBuffer;
Packit 0d464f
        cd->planarUncRleEnd[0] = cd->planarUncRle[0];
Packit 0d464f
Packit 0d464f
        for (int byte = 1; byte < Imf::pixelTypeSize(cd->type); ++byte)
Packit 0d464f
        {
Packit 0d464f
            cd->planarUncRle[byte] = 
Packit 0d464f
                         cd->planarUncRle[byte-1] + cd->width * cd->height;
Packit 0d464f
Packit 0d464f
            cd->planarUncRleEnd[byte] =
Packit 0d464f
                         cd->planarUncRle[byte];
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        cd->planarUncType = cd->type;
Packit 0d464f
Packit 0d464f
        if (cd->compression == LOSSY_DCT)
Packit 0d464f
        {
Packit 0d464f
            cd->planarUncType = FLOAT;
Packit 0d464f
        }
Packit 0d464f
        else
Packit 0d464f
        {
Packit 0d464f
            planarUncBuffer[cd->compression] +=
Packit 0d464f
                cd->width * cd->height * Imf::pixelTypeSize (cd->planarUncType);
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT