Blame IlmImf/ImfB44Compressor.cpp

Packit 0d464f
///////////////////////////////////////////////////////////////////////////
Packit 0d464f
//
Packit 0d464f
// Copyright (c) 2006, Industrial Light & Magic, a division of Lucas
Packit 0d464f
// Digital Ltd. LLC
Packit 0d464f
// 
Packit 0d464f
// All rights reserved.
Packit 0d464f
// 
Packit 0d464f
// Redistribution and use in source and binary forms, with or without
Packit 0d464f
// modification, are permitted provided that the following conditions are
Packit 0d464f
// met:
Packit 0d464f
// *       Redistributions of source code must retain the above copyright
Packit 0d464f
// notice, this list of conditions and the following disclaimer.
Packit 0d464f
// *       Redistributions in binary form must reproduce the above
Packit 0d464f
// copyright notice, this list of conditions and the following disclaimer
Packit 0d464f
// in the documentation and/or other materials provided with the
Packit 0d464f
// distribution.
Packit 0d464f
// *       Neither the name of Industrial Light & Magic nor the names of
Packit 0d464f
// its contributors may be used to endorse or promote products derived
Packit 0d464f
// from this software without specific prior written permission. 
Packit 0d464f
// 
Packit 0d464f
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit 0d464f
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit 0d464f
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
Packit 0d464f
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
Packit 0d464f
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
Packit 0d464f
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
Packit 0d464f
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit 0d464f
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit 0d464f
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit 0d464f
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
Packit 0d464f
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 0d464f
//
Packit 0d464f
///////////////////////////////////////////////////////////////////////////
Packit 0d464f
Packit 0d464f
Packit 0d464f
//-----------------------------------------------------------------------------
Packit 0d464f
//
Packit 0d464f
//	class B44Compressor
Packit 0d464f
//
Packit 0d464f
//	This compressor is lossy for HALF channels; the compression rate
Packit 0d464f
//	is fixed at 32/14 (approximately 2.28).  FLOAT and UINT channels
Packit 0d464f
//	are not compressed; their data are preserved exactly.
Packit 0d464f
//
Packit 0d464f
//	Each HALF channel is split into blocks of 4 by 4 pixels.  An
Packit 0d464f
//	uncompressed block occupies 32 bytes, which are re-interpreted
Packit 0d464f
//	as sixteen 16-bit unsigned integers, t[0] ... t[15].  Compression
Packit 0d464f
//	shrinks the block to 14 bytes.  The compressed 14-byte block
Packit 0d464f
//	contains
Packit 0d464f
//
Packit 0d464f
//	 - t[0]
Packit 0d464f
//
Packit 0d464f
//	 - a 6-bit shift value
Packit 0d464f
//
Packit 0d464f
//	 - 15 densely packed 6-bit values, r[0] ... r[14], which are
Packit 0d464f
//         computed by subtracting adjacent pixel values and right-
Packit 0d464f
//	   shifting the differences according to the stored shift value.
Packit 0d464f
//
Packit 0d464f
//	   Differences between adjacent pixels are computed according
Packit 0d464f
//	   to the following diagram:
Packit 0d464f
//
Packit 0d464f
//		 0 -------->  1 -------->  2 -------->  3
Packit 0d464f
//               |     3            7           11
Packit 0d464f
//               |
Packit 0d464f
//               | 0
Packit 0d464f
//               |
Packit 0d464f
//               v 
Packit 0d464f
//		 4 -------->  5 -------->  6 -------->  7
Packit 0d464f
//               |     4            8           12
Packit 0d464f
//               |
Packit 0d464f
//               | 1
Packit 0d464f
//               |
Packit 0d464f
//               v
Packit 0d464f
//		 8 -------->  9 --------> 10 --------> 11
Packit 0d464f
//               |     5            9           13
Packit 0d464f
//               |
Packit 0d464f
//               | 2
Packit 0d464f
//               |
Packit 0d464f
//               v
Packit 0d464f
//		12 --------> 13 --------> 14 --------> 15
Packit 0d464f
//                     6           10           14
Packit 0d464f
//
Packit 0d464f
//	    Here
Packit 0d464f
//
Packit 0d464f
//               5 ---------> 6
Packit 0d464f
//                     8
Packit 0d464f
//
Packit 0d464f
//	    means that r[8] is the difference between t[5] and t[6].
Packit 0d464f
//
Packit 0d464f
//	 - optionally, a 4-by-4 pixel block where all pixels have the
Packit 0d464f
//	   same value can be treated as a special case, where the
Packit 0d464f
//	   compressed block contains only 3 instead of 14 bytes:
Packit 0d464f
//	   t[0], followed by an "impossible" 6-bit shift value and
Packit 0d464f
//	   two padding bits.
Packit 0d464f
//
Packit 0d464f
//	This compressor can handle positive and negative pixel values.
Packit 0d464f
//	NaNs and infinities are replaced with zeroes before compression.
Packit 0d464f
//
Packit 0d464f
//-----------------------------------------------------------------------------
Packit 0d464f
Packit 0d464f
#include "ImfB44Compressor.h"
Packit 0d464f
#include "ImfHeader.h"
Packit 0d464f
#include "ImfChannelList.h"
Packit 0d464f
#include "ImfMisc.h"
Packit 0d464f
#include "ImfCheckedArithmetic.h"
Packit 0d464f
#include <ImathFun.h>
Packit 0d464f
#include <ImathBox.h>
Packit 0d464f
#include <Iex.h>
Packit 0d464f
#include <ImfIO.h>
Packit 0d464f
#include <ImfXdr.h>
Packit 0d464f
#include <string.h>
Packit 0d464f
#include <assert.h>
Packit 0d464f
#include <algorithm>
Packit 0d464f
#include "ImfNamespace.h"
Packit 0d464f
Packit 0d464f
Packit 0d464f
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
Packit 0d464f
Packit 0d464f
Packit 0d464f
using IMATH_NAMESPACE::divp;
Packit 0d464f
using IMATH_NAMESPACE::modp;
Packit 0d464f
using IMATH_NAMESPACE::Box2i;
Packit 0d464f
using IMATH_NAMESPACE::V2i;
Packit 0d464f
using std::min;
Packit 0d464f
Packit 0d464f
namespace {
Packit 0d464f
Packit 0d464f
//
Packit 0d464f
// Lookup tables for
Packit 0d464f
//	y = exp (x / 8)
Packit 0d464f
// and 
Packit 0d464f
//	x = 8 * log (y)
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
#include "b44ExpLogTable.h"
Packit 0d464f
Packit 0d464f
Packit 0d464f
inline void
Packit 0d464f
convertFromLinear (unsigned short s[16])
Packit 0d464f
{
Packit 0d464f
    for (int i = 0; i < 16; ++i)
Packit 0d464f
	s[i] = expTable[s[i]];
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
inline void
Packit 0d464f
convertToLinear (unsigned short s[16])
Packit 0d464f
{
Packit 0d464f
    for (int i = 0; i < 16; ++i)
Packit 0d464f
	s[i] = logTable[s[i]];
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
inline int
Packit 0d464f
shiftAndRound (int x, int shift)
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // Compute
Packit 0d464f
    //
Packit 0d464f
    //     y = x * pow (2, -shift),
Packit 0d464f
    //
Packit 0d464f
    // then round y to the nearest integer.
Packit 0d464f
    // In case of a tie, where y is exactly
Packit 0d464f
    // halfway between two integers, round
Packit 0d464f
    // to the even one.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    x <<= 1;
Packit 0d464f
    int a = (1 << shift) - 1;
Packit 0d464f
    shift += 1;
Packit 0d464f
    int b = (x >> shift) & 1;
Packit 0d464f
    return (x + a + b) >> shift;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
pack (const unsigned short s[16],
Packit 0d464f
      unsigned char b[14],
Packit 0d464f
      bool optFlatFields,
Packit 0d464f
      bool exactMax)
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // Pack a block of 4 by 4 16-bit pixels (32 bytes) into
Packit 0d464f
    // either 14 or 3 bytes.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Integers s[0] ... s[15] represent floating-point numbers
Packit 0d464f
    // in what is essentially a sign-magnitude format.  Convert
Packit 0d464f
    // s[0] .. s[15] into a new set of integers, t[0] ... t[15],
Packit 0d464f
    // such that if t[i] is greater than t[j], the floating-point
Packit 0d464f
    // number that corresponds to s[i] is always greater than
Packit 0d464f
    // the floating-point number that corresponds to s[j].
Packit 0d464f
    //
Packit 0d464f
    // Also, replace any bit patterns that represent NaNs or
Packit 0d464f
    // infinities with bit patterns that represent floating-point
Packit 0d464f
    // zeroes.
Packit 0d464f
    //
Packit 0d464f
    //	bit pattern	floating-point		bit pattern
Packit 0d464f
    //	in s[i]		value			in t[i]
Packit 0d464f
    //
Packit 0d464f
    //  0x7fff		NAN			0x8000
Packit 0d464f
    //  0x7ffe		NAN			0x8000
Packit 0d464f
    //	  ...					  ...
Packit 0d464f
    //  0x7c01		NAN			0x8000
Packit 0d464f
    //  0x7c00		+infinity		0x8000
Packit 0d464f
    //  0x7bff		+HALF_MAX		0xfbff
Packit 0d464f
    //  0x7bfe					0xfbfe
Packit 0d464f
    //  0x7bfd					0xfbfd
Packit 0d464f
    //	  ...					  ...
Packit 0d464f
    //  0x0002		+2 * HALF_MIN		0x8002
Packit 0d464f
    //  0x0001		+HALF_MIN		0x8001
Packit 0d464f
    //  0x0000		+0.0			0x8000
Packit 0d464f
    //  0x8000		-0.0			0x7fff
Packit 0d464f
    //  0x8001		-HALF_MIN		0x7ffe
Packit 0d464f
    //  0x8002		-2 * HALF_MIN		0x7ffd
Packit 0d464f
    //	  ...					  ...
Packit 0d464f
    //  0xfbfd					0x0f02
Packit 0d464f
    //  0xfbfe					0x0401
Packit 0d464f
    //  0xfbff		-HALF_MAX		0x0400
Packit 0d464f
    //  0xfc00		-infinity		0x8000
Packit 0d464f
    //  0xfc01		NAN			0x8000
Packit 0d464f
    //	  ...					  ...
Packit 0d464f
    //  0xfffe		NAN			0x8000
Packit 0d464f
    //  0xffff		NAN			0x8000
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    unsigned short t[16];
Packit 0d464f
Packit 0d464f
    for (int i = 0; i < 16; ++i)
Packit 0d464f
    {
Packit 0d464f
	if ((s[i] & 0x7c00) == 0x7c00)
Packit 0d464f
	    t[i] = 0x8000;
Packit 0d464f
	else if (s[i] & 0x8000)
Packit 0d464f
	    t[i] = ~s[i];
Packit 0d464f
	else
Packit 0d464f
	    t[i] = s[i] | 0x8000;
Packit 0d464f
    }
Packit 0d464f
    
Packit 0d464f
    //
Packit 0d464f
    // Find the maximum, tMax, of t[0] ... t[15].
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    unsigned short tMax = 0;
Packit 0d464f
Packit 0d464f
    for (int i = 0; i < 16; ++i)
Packit 0d464f
	if (tMax < t[i])
Packit 0d464f
	    tMax = t[i];
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Compute a set of running differences, r[0] ... r[14]:
Packit 0d464f
    // Find a shift value such that after rounding off the
Packit 0d464f
    // rightmost bits and shifting all differenes are between
Packit 0d464f
    // -32 and +31.  Then bias the differences so that they
Packit 0d464f
    // end up between 0 and 63.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    int shift = -1;
Packit 0d464f
    int d[16];
Packit 0d464f
    int r[15];
Packit 0d464f
    int rMin;
Packit 0d464f
    int rMax;
Packit 0d464f
Packit 0d464f
    const int bias = 0x20;
Packit 0d464f
Packit 0d464f
    do
Packit 0d464f
    {
Packit 0d464f
        shift += 1;
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // Compute absolute differences, d[0] ... d[15],
Packit 0d464f
        // between tMax and t[0] ... t[15].
Packit 0d464f
        //
Packit 0d464f
        // Shift and round the absolute differences.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        for (int i = 0; i < 16; ++i)
Packit 0d464f
            d[i] = shiftAndRound (tMax - t[i], shift);
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // Convert d[0] .. d[15] into running differences
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        r[ 0] = d[ 0] - d[ 4] + bias;
Packit 0d464f
        r[ 1] = d[ 4] - d[ 8] + bias;
Packit 0d464f
        r[ 2] = d[ 8] - d[12] + bias;
Packit 0d464f
Packit 0d464f
        r[ 3] = d[ 0] - d[ 1] + bias;
Packit 0d464f
        r[ 4] = d[ 4] - d[ 5] + bias;
Packit 0d464f
        r[ 5] = d[ 8] - d[ 9] + bias;
Packit 0d464f
        r[ 6] = d[12] - d[13] + bias;
Packit 0d464f
Packit 0d464f
        r[ 7] = d[ 1] - d[ 2] + bias;
Packit 0d464f
        r[ 8] = d[ 5] - d[ 6] + bias;
Packit 0d464f
        r[ 9] = d[ 9] - d[10] + bias;
Packit 0d464f
        r[10] = d[13] - d[14] + bias;
Packit 0d464f
Packit 0d464f
        r[11] = d[ 2] - d[ 3] + bias;
Packit 0d464f
        r[12] = d[ 6] - d[ 7] + bias;
Packit 0d464f
        r[13] = d[10] - d[11] + bias;
Packit 0d464f
        r[14] = d[14] - d[15] + bias;
Packit 0d464f
Packit 0d464f
        rMin = r[0];
Packit 0d464f
        rMax = r[0];
Packit 0d464f
Packit 0d464f
        for (int i = 1; i < 15; ++i)
Packit 0d464f
        {
Packit 0d464f
            if (rMin > r[i])
Packit 0d464f
                rMin = r[i];
Packit 0d464f
Packit 0d464f
            if (rMax < r[i])
Packit 0d464f
                rMax = r[i];
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
    while (rMin < 0 || rMax > 0x3f);
Packit 0d464f
Packit 0d464f
    if (rMin == bias && rMax == bias && optFlatFields)
Packit 0d464f
    {
Packit 0d464f
        //
Packit 0d464f
        // Special case - all pixels have the same value.
Packit 0d464f
        // We encode this in 3 instead of 14 bytes by
Packit 0d464f
        // storing the value 0xfc in the third output byte,
Packit 0d464f
        // which cannot occur in the 14-byte encoding.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        b[0] = (t[0] >> 8);
Packit 0d464f
        b[1] = (unsigned char) t[0];
Packit 0d464f
        b[2] = 0xfc;
Packit 0d464f
Packit 0d464f
        return 3;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    if (exactMax)
Packit 0d464f
    {
Packit 0d464f
        //
Packit 0d464f
        // Adjust t[0] so that the pixel whose value is equal
Packit 0d464f
        // to tMax gets represented as accurately as possible.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        t[0] = tMax - (d[0] << shift);
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Pack t[0], shift and r[0] ... r[14] into 14 bytes:
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    b[ 0] = (t[0] >> 8);
Packit 0d464f
    b[ 1] = (unsigned char) t[0];
Packit 0d464f
Packit 0d464f
    b[ 2] = (unsigned char) ((shift << 2) | (r[ 0] >> 4));
Packit 0d464f
    b[ 3] = (unsigned char) ((r[ 0] << 4) | (r[ 1] >> 2));
Packit 0d464f
    b[ 4] = (unsigned char) ((r[ 1] << 6) |  r[ 2]      );
Packit 0d464f
Packit 0d464f
    b[ 5] = (unsigned char) ((r[ 3] << 2) | (r[ 4] >> 4));
Packit 0d464f
    b[ 6] = (unsigned char) ((r[ 4] << 4) | (r[ 5] >> 2));
Packit 0d464f
    b[ 7] = (unsigned char) ((r[ 5] << 6) |  r[ 6]      );
Packit 0d464f
Packit 0d464f
    b[ 8] = (unsigned char) ((r[ 7] << 2) | (r[ 8] >> 4));
Packit 0d464f
    b[ 9] = (unsigned char) ((r[ 8] << 4) | (r[ 9] >> 2));
Packit 0d464f
    b[10] = (unsigned char) ((r[ 9] << 6) |  r[10]      );
Packit 0d464f
Packit 0d464f
    b[11] = (unsigned char) ((r[11] << 2) | (r[12] >> 4));
Packit 0d464f
    b[12] = (unsigned char) ((r[12] << 4) | (r[13] >> 2));
Packit 0d464f
    b[13] = (unsigned char) ((r[13] << 6) |  r[14]      );
Packit 0d464f
Packit 0d464f
    return 14;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
inline
Packit 0d464f
void
Packit 0d464f
unpack14 (const unsigned char b[14], unsigned short s[16])
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // Unpack a 14-byte block into 4 by 4 16-bit pixels.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    #if defined (DEBUG)
Packit 0d464f
	assert (b[2] != 0xfc);
Packit 0d464f
    #endif
Packit 0d464f
Packit 0d464f
    s[ 0] = (b[0] << 8) | b[1];
Packit 0d464f
Packit 0d464f
    unsigned short shift = (b[ 2] >> 2);
Packit 0d464f
    unsigned short bias = (0x20 << shift);
Packit 0d464f
Packit 0d464f
    s[ 4] = s[ 0] + ((((b[ 2] << 4) | (b[ 3] >> 4)) & 0x3f) << shift) - bias;
Packit 0d464f
    s[ 8] = s[ 4] + ((((b[ 3] << 2) | (b[ 4] >> 6)) & 0x3f) << shift) - bias;
Packit 0d464f
    s[12] = s[ 8] +   ((b[ 4]                       & 0x3f) << shift) - bias;
Packit 0d464f
    
Packit 0d464f
    s[ 1] = s[ 0] +   ((b[ 5] >> 2)                         << shift) - bias;
Packit 0d464f
    s[ 5] = s[ 4] + ((((b[ 5] << 4) | (b[ 6] >> 4)) & 0x3f) << shift) - bias;
Packit 0d464f
    s[ 9] = s[ 8] + ((((b[ 6] << 2) | (b[ 7] >> 6)) & 0x3f) << shift) - bias;
Packit 0d464f
    s[13] = s[12] +   ((b[ 7]                       & 0x3f) << shift) - bias;
Packit 0d464f
    
Packit 0d464f
    s[ 2] = s[ 1] +   ((b[ 8] >> 2)                         << shift) - bias;
Packit 0d464f
    s[ 6] = s[ 5] + ((((b[ 8] << 4) | (b[ 9] >> 4)) & 0x3f) << shift) - bias;
Packit 0d464f
    s[10] = s[ 9] + ((((b[ 9] << 2) | (b[10] >> 6)) & 0x3f) << shift) - bias;
Packit 0d464f
    s[14] = s[13] +   ((b[10]                       & 0x3f) << shift) - bias;
Packit 0d464f
    
Packit 0d464f
    s[ 3] = s[ 2] +   ((b[11] >> 2)                         << shift) - bias;
Packit 0d464f
    s[ 7] = s[ 6] + ((((b[11] << 4) | (b[12] >> 4)) & 0x3f) << shift) - bias;
Packit 0d464f
    s[11] = s[10] + ((((b[12] << 2) | (b[13] >> 6)) & 0x3f) << shift) - bias;
Packit 0d464f
    s[15] = s[14] +   ((b[13]                       & 0x3f) << shift) - bias;
Packit 0d464f
Packit 0d464f
    for (int i = 0; i < 16; ++i)
Packit 0d464f
    {
Packit 0d464f
	if (s[i] & 0x8000)
Packit 0d464f
	    s[i] &= 0x7fff;
Packit 0d464f
	else
Packit 0d464f
	    s[i] = ~s[i];
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
inline
Packit 0d464f
void
Packit 0d464f
unpack3 (const unsigned char b[3], unsigned short s[16])
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // Unpack a 3-byte block into 4 by 4 identical 16-bit pixels.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    #if defined (DEBUG)
Packit 0d464f
	assert (b[2] == 0xfc);
Packit 0d464f
    #endif
Packit 0d464f
Packit 0d464f
    s[0] = (b[0] << 8) | b[1];
Packit 0d464f
Packit 0d464f
    if (s[0] & 0x8000)
Packit 0d464f
	s[0] &= 0x7fff;
Packit 0d464f
    else
Packit 0d464f
	s[0] = ~s[0];
Packit 0d464f
Packit 0d464f
    for (int i = 1; i < 16; ++i)
Packit 0d464f
	s[i] = s[0];
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
notEnoughData ()
Packit 0d464f
{
Packit 0d464f
    throw IEX_NAMESPACE::InputExc ("Error decompressing data "
Packit 0d464f
			 "(input data are shorter than expected).");
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
tooMuchData ()
Packit 0d464f
{
Packit 0d464f
    throw IEX_NAMESPACE::InputExc ("Error decompressing data "
Packit 0d464f
			 "(input data are longer than expected).");
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
} // namespace
Packit 0d464f
Packit 0d464f
Packit 0d464f
struct B44Compressor::ChannelData
Packit 0d464f
{
Packit 0d464f
    unsigned short *	start;
Packit 0d464f
    unsigned short *	end;
Packit 0d464f
    int			nx;
Packit 0d464f
    int			ny;
Packit 0d464f
    int			ys;
Packit 0d464f
    PixelType		type;
Packit 0d464f
    bool		pLinear;
Packit 0d464f
    int			size;
Packit 0d464f
};
Packit 0d464f
Packit 0d464f
Packit 0d464f
B44Compressor::B44Compressor
Packit 0d464f
    (const Header &hdr,
Packit 0d464f
     size_t maxScanLineSize,
Packit 0d464f
     size_t numScanLines,
Packit 0d464f
     bool optFlatFields)
Packit 0d464f
:
Packit 0d464f
    Compressor (hdr),
Packit 0d464f
    _maxScanLineSize (maxScanLineSize),
Packit 0d464f
    _optFlatFields (optFlatFields),
Packit 0d464f
    _format (XDR),
Packit 0d464f
    _numScanLines (numScanLines),
Packit 0d464f
    _tmpBuffer (0),
Packit 0d464f
    _outBuffer (0),
Packit 0d464f
    _numChans (0),
Packit 0d464f
    _channels (hdr.channels()),
Packit 0d464f
    _channelData (0)
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // Allocate buffers for compressed an uncompressed pixel data,
Packit 0d464f
    // allocate a set of ChannelData structs to help speed up the
Packit 0d464f
    // compress() and uncompress() functions, below, and determine
Packit 0d464f
    // if uncompressed pixel data should be in native or Xdr format.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    _tmpBuffer = new unsigned short
Packit 0d464f
        [checkArraySize (uiMult (maxScanLineSize, numScanLines),
Packit 0d464f
                         sizeof (unsigned short))];
Packit 0d464f
Packit 0d464f
    const ChannelList &channels = header().channels();
Packit 0d464f
    int numHalfChans = 0;
Packit 0d464f
Packit 0d464f
    for (ChannelList::ConstIterator c = channels.begin();
Packit 0d464f
	 c != channels.end();
Packit 0d464f
	 ++c)
Packit 0d464f
    {
Packit 0d464f
	assert (pixelTypeSize (c.channel().type) % pixelTypeSize (HALF) == 0);
Packit 0d464f
	++_numChans;
Packit 0d464f
Packit 0d464f
	if (c.channel().type == HALF)
Packit 0d464f
	    ++numHalfChans;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Compressed data may be larger than the input data
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    size_t padding = 12 * numHalfChans * (numScanLines + 3) / 4;
Packit 0d464f
Packit 0d464f
    _outBuffer = new char
Packit 0d464f
        [uiAdd (uiMult (maxScanLineSize, numScanLines), padding)];
Packit 0d464f
Packit 0d464f
    _channelData = new ChannelData[_numChans];
Packit 0d464f
Packit 0d464f
    int i = 0;
Packit 0d464f
Packit 0d464f
    for (ChannelList::ConstIterator c = channels.begin();
Packit 0d464f
	 c != channels.end();
Packit 0d464f
	 ++c, ++i)
Packit 0d464f
    {
Packit 0d464f
	_channelData[i].ys = c.channel().ySampling;
Packit 0d464f
	_channelData[i].type = c.channel().type;
Packit 0d464f
	_channelData[i].pLinear = c.channel().pLinear;
Packit 0d464f
	_channelData[i].size =
Packit 0d464f
	    pixelTypeSize (c.channel().type) / pixelTypeSize (HALF);
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    const Box2i &dataWindow = hdr.dataWindow();
Packit 0d464f
Packit 0d464f
    _minX = dataWindow.min.x;
Packit 0d464f
    _maxX = dataWindow.max.x;
Packit 0d464f
    _maxY = dataWindow.max.y;
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // We can support uncompressed data in the machine's native
Packit 0d464f
    // format only if all image channels are of type HALF.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    assert (sizeof (unsigned short) == pixelTypeSize (HALF));
Packit 0d464f
Packit 0d464f
    if (_numChans == numHalfChans)
Packit 0d464f
	_format = NATIVE;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
B44Compressor::~B44Compressor ()
Packit 0d464f
{
Packit 0d464f
    delete [] _tmpBuffer;
Packit 0d464f
    delete [] _outBuffer;
Packit 0d464f
    delete [] _channelData;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
B44Compressor::numScanLines () const
Packit 0d464f
{
Packit 0d464f
    return _numScanLines;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
Compressor::Format
Packit 0d464f
B44Compressor::format () const
Packit 0d464f
{
Packit 0d464f
    return _format;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
B44Compressor::compress (const char *inPtr,
Packit 0d464f
			 int inSize,
Packit 0d464f
			 int minY,
Packit 0d464f
			 const char *&outPtr)
Packit 0d464f
{
Packit 0d464f
    return compress (inPtr,
Packit 0d464f
		     inSize,
Packit 0d464f
		     Box2i (V2i (_minX, minY),
Packit 0d464f
			    V2i (_maxX, minY + numScanLines() - 1)),
Packit 0d464f
		     outPtr);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
B44Compressor::compressTile (const char *inPtr,
Packit 0d464f
			     int inSize,
Packit 0d464f
			     IMATH_NAMESPACE::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
B44Compressor::uncompress (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
		       Box2i (V2i (_minX, minY),
Packit 0d464f
			      V2i (_maxX, minY + numScanLines() - 1)),
Packit 0d464f
		       outPtr);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
B44Compressor::uncompressTile (const char *inPtr,
Packit 0d464f
			       int inSize,
Packit 0d464f
			       IMATH_NAMESPACE::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
B44Compressor::compress (const char *inPtr,
Packit 0d464f
			 int inSize,
Packit 0d464f
			 IMATH_NAMESPACE::Box2i range,
Packit 0d464f
			 const char *&outPtr)
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // Compress a block of pixel data:  First copy the input pixels
Packit 0d464f
    // from the input buffer into _tmpBuffer, rearranging them such
Packit 0d464f
    // that blocks of 4x4 pixels of a single channel can be accessed
Packit 0d464f
    // conveniently.  Then compress each 4x4 block of HALF pixel data
Packit 0d464f
    // and append the result to the output buffer.  Copy UINT and
Packit 0d464f
    // FLOAT data to the output buffer without compressing them.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    outPtr = _outBuffer;
Packit 0d464f
Packit 0d464f
    if (inSize == 0)
Packit 0d464f
    {
Packit 0d464f
	//
Packit 0d464f
	// Special case - empty input buffer.
Packit 0d464f
	//
Packit 0d464f
Packit 0d464f
	return 0;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // For each channel, detemine how many pixels are stored
Packit 0d464f
    // in the input buffer, and where those pixels will be
Packit 0d464f
    // placed in _tmpBuffer.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    int minX = range.min.x;
Packit 0d464f
    int maxX = min (range.max.x, _maxX);
Packit 0d464f
    int minY = range.min.y;
Packit 0d464f
    int maxY = min (range.max.y, _maxY);
Packit 0d464f
    
Packit 0d464f
    unsigned short *tmpBufferEnd = _tmpBuffer;
Packit 0d464f
    int i = 0;
Packit 0d464f
Packit 0d464f
    for (ChannelList::ConstIterator c = _channels.begin();
Packit 0d464f
	 c != _channels.end();
Packit 0d464f
	 ++c, ++i)
Packit 0d464f
    {
Packit 0d464f
	ChannelData &cd = _channelData[i];
Packit 0d464f
Packit 0d464f
	cd.start = tmpBufferEnd;
Packit 0d464f
	cd.end = cd.start;
Packit 0d464f
Packit 0d464f
	cd.nx = numSamples (c.channel().xSampling, minX, maxX);
Packit 0d464f
	cd.ny = numSamples (c.channel().ySampling, minY, maxY);
Packit 0d464f
Packit 0d464f
	tmpBufferEnd += cd.nx * cd.ny * cd.size;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    if (_format == XDR)
Packit 0d464f
    {
Packit 0d464f
	//
Packit 0d464f
	// The data in the input buffer are in the machine-independent
Packit 0d464f
	// Xdr format.  Copy the HALF channels into _tmpBuffer and
Packit 0d464f
	// convert them back into native format for compression.
Packit 0d464f
	// Copy UINT and FLOAT channels verbatim into _tmpBuffer.
Packit 0d464f
	//
Packit 0d464f
Packit 0d464f
	for (int y = minY; y <= maxY; ++y)
Packit 0d464f
	{
Packit 0d464f
	    for (int i = 0; i < _numChans; ++i)
Packit 0d464f
	    {
Packit 0d464f
		ChannelData &cd = _channelData[i];
Packit 0d464f
Packit 0d464f
		if (modp (y, cd.ys) != 0)
Packit 0d464f
		    continue;
Packit 0d464f
Packit 0d464f
		if (cd.type == HALF)
Packit 0d464f
		{
Packit 0d464f
		    for (int x = cd.nx; x > 0; --x)
Packit 0d464f
		    {
Packit 0d464f
			Xdr::read <CharPtrIO> (inPtr, *cd.end);
Packit 0d464f
			++cd.end;
Packit 0d464f
		    }
Packit 0d464f
		}
Packit 0d464f
		else
Packit 0d464f
		{
Packit 0d464f
		    int n = cd.nx * cd.size;
Packit 0d464f
		    memcpy (cd.end, inPtr, n * sizeof (unsigned short));
Packit 0d464f
		    inPtr += n * sizeof (unsigned short);
Packit 0d464f
		    cd.end += n;
Packit 0d464f
		}
Packit 0d464f
	    }
Packit 0d464f
	}
Packit 0d464f
    }
Packit 0d464f
    else
Packit 0d464f
    {
Packit 0d464f
	//
Packit 0d464f
	// The input buffer contains only HALF channels, and they
Packit 0d464f
	// are in native, machine-dependent format.  Copy the pixels
Packit 0d464f
	// into _tmpBuffer.
Packit 0d464f
	//
Packit 0d464f
Packit 0d464f
	for (int y = minY; y <= maxY; ++y)
Packit 0d464f
	{
Packit 0d464f
	    for (int i = 0; i < _numChans; ++i)
Packit 0d464f
	    {
Packit 0d464f
		ChannelData &cd = _channelData[i];
Packit 0d464f
Packit 0d464f
		#if defined (DEBUG)
Packit 0d464f
		    assert (cd.type == HALF);
Packit 0d464f
		#endif
Packit 0d464f
Packit 0d464f
		if (modp (y, cd.ys) != 0)
Packit 0d464f
		    continue;
Packit 0d464f
Packit 0d464f
		int n = cd.nx * cd.size;
Packit 0d464f
		memcpy (cd.end, inPtr, n * sizeof (unsigned short));
Packit 0d464f
		inPtr  += n * sizeof (unsigned short);
Packit 0d464f
		cd.end += n;
Packit 0d464f
	    }
Packit 0d464f
	}
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // The pixels for each channel have been packed into a contiguous
Packit 0d464f
    // block in _tmpBuffer.  HALF channels are in native format; UINT
Packit 0d464f
    // and FLOAT channels are in Xdr format.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    #if defined (DEBUG)
Packit 0d464f
Packit 0d464f
	for (int i = 1; i < _numChans; ++i)
Packit 0d464f
	    assert (_channelData[i-1].end == _channelData[i].start);
Packit 0d464f
Packit 0d464f
	assert (_channelData[_numChans-1].end == tmpBufferEnd);
Packit 0d464f
Packit 0d464f
    #endif
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // For each HALF channel, split the data in _tmpBuffer into 4x4
Packit 0d464f
    // pixel blocks.  Compress each block and append the compressed
Packit 0d464f
    // data to the output buffer.
Packit 0d464f
    //
Packit 0d464f
    // UINT and FLOAT channels are copied from _tmpBuffer into the
Packit 0d464f
    // output buffer without further processing.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    char *outEnd = _outBuffer;
Packit 0d464f
Packit 0d464f
    for (int i = 0; i < _numChans; ++i)
Packit 0d464f
    {
Packit 0d464f
	ChannelData &cd = _channelData[i];
Packit 0d464f
	
Packit 0d464f
	if (cd.type != HALF)
Packit 0d464f
	{
Packit 0d464f
	    //
Packit 0d464f
	    // UINT or FLOAT channel.
Packit 0d464f
	    //
Packit 0d464f
Packit 0d464f
	    int n = cd.nx * cd.ny * cd.size * sizeof (unsigned short);
Packit 0d464f
	    memcpy (outEnd, cd.start, n);
Packit 0d464f
	    outEnd += n;
Packit 0d464f
Packit 0d464f
	    continue;
Packit 0d464f
	}
Packit 0d464f
	
Packit 0d464f
	//
Packit 0d464f
	// HALF channel
Packit 0d464f
	//
Packit 0d464f
Packit 0d464f
	for (int y = 0; y < cd.ny; y += 4)
Packit 0d464f
	{
Packit 0d464f
	    //
Packit 0d464f
	    // Copy the next 4x4 pixel block into array s.
Packit 0d464f
	    // If the width, cd.nx, or the height, cd.ny, of
Packit 0d464f
	    // the pixel data in _tmpBuffer is not divisible
Packit 0d464f
	    // by 4, then pad the data by repeating the
Packit 0d464f
	    // rightmost column and the bottom row.
Packit 0d464f
	    // 
Packit 0d464f
Packit 0d464f
	    unsigned short *row0 = cd.start + y * cd.nx;
Packit 0d464f
	    unsigned short *row1 = row0 + cd.nx;
Packit 0d464f
	    unsigned short *row2 = row1 + cd.nx;
Packit 0d464f
	    unsigned short *row3 = row2 + cd.nx;
Packit 0d464f
Packit 0d464f
	    if (y + 3 >= cd.ny)
Packit 0d464f
	    {
Packit 0d464f
		if (y + 1 >= cd.ny)
Packit 0d464f
		    row1 = row0;
Packit 0d464f
Packit 0d464f
		if (y + 2 >= cd.ny)
Packit 0d464f
		    row2 = row1;
Packit 0d464f
Packit 0d464f
		row3 = row2;
Packit 0d464f
	    }
Packit 0d464f
Packit 0d464f
	    for (int x = 0; x < cd.nx; x += 4)
Packit 0d464f
	    {
Packit 0d464f
		unsigned short s[16];
Packit 0d464f
Packit 0d464f
		if (x + 3 >= cd.nx)
Packit 0d464f
		{
Packit 0d464f
		    int n = cd.nx - x;
Packit 0d464f
Packit 0d464f
		    for (int i = 0; i < 4; ++i)
Packit 0d464f
		    {
Packit 0d464f
			int j = min (i, n - 1);
Packit 0d464f
Packit 0d464f
			s[i +  0] = row0[j];
Packit 0d464f
			s[i +  4] = row1[j];
Packit 0d464f
			s[i +  8] = row2[j];
Packit 0d464f
			s[i + 12] = row3[j];
Packit 0d464f
		    }
Packit 0d464f
		}
Packit 0d464f
		else
Packit 0d464f
		{
Packit 0d464f
		    memcpy (&s[ 0], row0, 4 * sizeof (unsigned short));
Packit 0d464f
		    memcpy (&s[ 4], row1, 4 * sizeof (unsigned short));
Packit 0d464f
		    memcpy (&s[ 8], row2, 4 * sizeof (unsigned short));
Packit 0d464f
		    memcpy (&s[12], row3, 4 * sizeof (unsigned short));
Packit 0d464f
		}
Packit 0d464f
Packit 0d464f
		row0 += 4;
Packit 0d464f
		row1 += 4;
Packit 0d464f
		row2 += 4;
Packit 0d464f
		row3 += 4;
Packit 0d464f
Packit 0d464f
		//
Packit 0d464f
		// Compress the contents of array s and append the
Packit 0d464f
		// results to the output buffer.
Packit 0d464f
		//
Packit 0d464f
Packit 0d464f
		if (cd.pLinear)
Packit 0d464f
		    convertFromLinear (s);
Packit 0d464f
Packit 0d464f
		outEnd += pack (s, (unsigned char *) outEnd,
Packit 0d464f
				_optFlatFields, !cd.pLinear);
Packit 0d464f
	    }
Packit 0d464f
	}
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    return outEnd - _outBuffer;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
B44Compressor::uncompress (const char *inPtr,
Packit 0d464f
			   int inSize,
Packit 0d464f
			   IMATH_NAMESPACE::Box2i range,
Packit 0d464f
			   const char *&outPtr)
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // This function is the reverse of the compress() function,
Packit 0d464f
    // above.  First all pixels are moved from the input buffer
Packit 0d464f
    // into _tmpBuffer.  UINT and FLOAT channels are copied
Packit 0d464f
    // verbatim; HALF channels are uncompressed in blocks of
Packit 0d464f
    // 4x4 pixels.  Then the pixels in _tmpBuffer are copied
Packit 0d464f
    // into the output buffer and rearranged such that the data
Packit 0d464f
    // for for each scan line form a contiguous block.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    outPtr = _outBuffer;
Packit 0d464f
Packit 0d464f
    if (inSize == 0)
Packit 0d464f
    {
Packit 0d464f
	return 0;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    int minX = range.min.x;
Packit 0d464f
    int maxX = min (range.max.x, _maxX);
Packit 0d464f
    int minY = range.min.y;
Packit 0d464f
    int maxY = min (range.max.y, _maxY);
Packit 0d464f
    
Packit 0d464f
    unsigned short *tmpBufferEnd = _tmpBuffer;
Packit 0d464f
    int i = 0;
Packit 0d464f
Packit 0d464f
    for (ChannelList::ConstIterator c = _channels.begin();
Packit 0d464f
	 c != _channels.end();
Packit 0d464f
	 ++c, ++i)
Packit 0d464f
    {
Packit 0d464f
	ChannelData &cd = _channelData[i];
Packit 0d464f
Packit 0d464f
	cd.start = tmpBufferEnd;
Packit 0d464f
	cd.end = cd.start;
Packit 0d464f
Packit 0d464f
	cd.nx = numSamples (c.channel().xSampling, minX, maxX);
Packit 0d464f
	cd.ny = numSamples (c.channel().ySampling, minY, maxY);
Packit 0d464f
Packit 0d464f
	tmpBufferEnd += cd.nx * cd.ny * cd.size;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    for (int i = 0; i < _numChans; ++i)
Packit 0d464f
    {
Packit 0d464f
	ChannelData &cd = _channelData[i];
Packit 0d464f
Packit 0d464f
	if (cd.type != HALF)
Packit 0d464f
	{
Packit 0d464f
	    //
Packit 0d464f
	    // UINT or FLOAT channel.
Packit 0d464f
	    //
Packit 0d464f
Packit 0d464f
	    int n = cd.nx * cd.ny * cd.size * sizeof (unsigned short);
Packit 0d464f
Packit 0d464f
	    if (inSize < n)
Packit 0d464f
		notEnoughData();
Packit 0d464f
Packit 0d464f
	    memcpy (cd.start, inPtr, n);
Packit 0d464f
	    inPtr += n;
Packit 0d464f
	    inSize -= n;
Packit 0d464f
Packit 0d464f
	    continue;
Packit 0d464f
	}
Packit 0d464f
Packit 0d464f
	//
Packit 0d464f
	// HALF channel
Packit 0d464f
	//
Packit 0d464f
Packit 0d464f
	for (int y = 0; y < cd.ny; y += 4)
Packit 0d464f
	{
Packit 0d464f
	    unsigned short *row0 = cd.start + y * cd.nx;
Packit 0d464f
	    unsigned short *row1 = row0 + cd.nx;
Packit 0d464f
	    unsigned short *row2 = row1 + cd.nx;
Packit 0d464f
	    unsigned short *row3 = row2 + cd.nx;
Packit 0d464f
Packit 0d464f
	    for (int x = 0; x < cd.nx; x += 4)
Packit 0d464f
	    {
Packit 0d464f
		unsigned short s[16]; 
Packit 0d464f
Packit 0d464f
		if (inSize < 3)
Packit 0d464f
		    notEnoughData();
Packit 0d464f
Packit 0d464f
		if (((const unsigned char *)inPtr)[2] == 0xfc)
Packit 0d464f
		{
Packit 0d464f
		    unpack3 ((const unsigned char *)inPtr, s);
Packit 0d464f
		    inPtr += 3;
Packit 0d464f
		    inSize -= 3;
Packit 0d464f
		}
Packit 0d464f
		else
Packit 0d464f
		{
Packit 0d464f
		    if (inSize < 14)
Packit 0d464f
			notEnoughData();
Packit 0d464f
Packit 0d464f
		    unpack14 ((const unsigned char *)inPtr, s);
Packit 0d464f
		    inPtr += 14;
Packit 0d464f
		    inSize -= 14;
Packit 0d464f
		}
Packit 0d464f
Packit 0d464f
		if (cd.pLinear)
Packit 0d464f
		    convertToLinear (s);
Packit 0d464f
Packit 0d464f
		int n = (x + 3 < cd.nx)?
Packit 0d464f
			    4 * sizeof (unsigned short) :
Packit 0d464f
			    (cd.nx - x) * sizeof (unsigned short);
Packit 0d464f
Packit 0d464f
		if (y + 3 < cd.ny)
Packit 0d464f
		{
Packit 0d464f
		    memcpy (row0, &s[ 0], n);
Packit 0d464f
		    memcpy (row1, &s[ 4], n);
Packit 0d464f
		    memcpy (row2, &s[ 8], n);
Packit 0d464f
		    memcpy (row3, &s[12], n);
Packit 0d464f
		}
Packit 0d464f
		else
Packit 0d464f
		{
Packit 0d464f
		    memcpy (row0, &s[ 0], n);
Packit 0d464f
Packit 0d464f
		    if (y + 1 < cd.ny)
Packit 0d464f
			memcpy (row1, &s[ 4], n);
Packit 0d464f
Packit 0d464f
		    if (y + 2 < cd.ny)
Packit 0d464f
			memcpy (row2, &s[ 8], n);
Packit 0d464f
		}
Packit 0d464f
Packit 0d464f
		row0 += 4;
Packit 0d464f
		row1 += 4;
Packit 0d464f
		row2 += 4;
Packit 0d464f
		row3 += 4;
Packit 0d464f
	    }
Packit 0d464f
	}
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    char *outEnd = _outBuffer;
Packit 0d464f
Packit 0d464f
    if (_format == XDR)
Packit 0d464f
    {
Packit 0d464f
	for (int y = minY; y <= maxY; ++y)
Packit 0d464f
	{
Packit 0d464f
	    for (int i = 0; i < _numChans; ++i)
Packit 0d464f
	    {
Packit 0d464f
		ChannelData &cd = _channelData[i];
Packit 0d464f
Packit 0d464f
		if (modp (y, cd.ys) != 0)
Packit 0d464f
		    continue;
Packit 0d464f
Packit 0d464f
		if (cd.type == HALF)
Packit 0d464f
		{
Packit 0d464f
		    for (int x = cd.nx; x > 0; --x)
Packit 0d464f
		    {
Packit 0d464f
			Xdr::write <CharPtrIO> (outEnd, *cd.end);
Packit 0d464f
			++cd.end;
Packit 0d464f
		    }
Packit 0d464f
		}
Packit 0d464f
		else
Packit 0d464f
		{
Packit 0d464f
		    int n = cd.nx * cd.size;
Packit 0d464f
		    memcpy (outEnd, cd.end, n * sizeof (unsigned short));
Packit 0d464f
		    outEnd += n * sizeof (unsigned short);
Packit 0d464f
		    cd.end += n;
Packit 0d464f
		}
Packit 0d464f
	    }
Packit 0d464f
	}
Packit 0d464f
    }
Packit 0d464f
    else
Packit 0d464f
    {
Packit 0d464f
	for (int y = minY; y <= maxY; ++y)
Packit 0d464f
	{
Packit 0d464f
	    for (int i = 0; i < _numChans; ++i)
Packit 0d464f
	    {
Packit 0d464f
		ChannelData &cd = _channelData[i];
Packit 0d464f
Packit 0d464f
		#if defined (DEBUG)
Packit 0d464f
		    assert (cd.type == HALF);
Packit 0d464f
		#endif
Packit 0d464f
Packit 0d464f
		if (modp (y, cd.ys) != 0)
Packit 0d464f
		    continue;
Packit 0d464f
Packit 0d464f
		int n = cd.nx * cd.size;
Packit 0d464f
		memcpy (outEnd, cd.end, n * sizeof (unsigned short));
Packit 0d464f
		outEnd += n * sizeof (unsigned short);
Packit 0d464f
		cd.end += n;
Packit 0d464f
	    }
Packit 0d464f
	}
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    #if defined (DEBUG)
Packit 0d464f
Packit 0d464f
	for (int i = 1; i < _numChans; ++i)
Packit 0d464f
	    assert (_channelData[i-1].end == _channelData[i].start);
Packit 0d464f
Packit 0d464f
	assert (_channelData[_numChans-1].end == tmpBufferEnd);
Packit 0d464f
Packit 0d464f
    #endif
Packit 0d464f
Packit 0d464f
    if (inSize > 0)
Packit 0d464f
	tooMuchData();
Packit 0d464f
Packit 0d464f
    outPtr = _outBuffer;
Packit 0d464f
    return outEnd - _outBuffer;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT