This source file includes following definitions.
- convertFromLinear
- convertToLinear
- shiftAndRound
- pack
- unpack14
- unpack3
- notEnoughData
- tooMuchData
- _channelData
- numScanLines
- format
- compress
- compressTile
- uncompress
- uncompressTile
- compress
- uncompress
#include <ImfB44Compressor.h>
#include <ImfHeader.h>
#include <ImfChannelList.h>
#include <ImfMisc.h>
#include <ImfCheckedArithmetic.h>
#include <ImathFun.h>
#include <ImathBox.h>
#include <Iex.h>
#include <ImfIO.h>
#include <ImfXdr.h>
#include <string.h>
#include <assert.h>
#include <algorithm>
namespace Imf {
using Imath::divp;
using Imath::modp;
using Imath::Box2i;
using Imath::V2i;
using std::min;
namespace {
#include "b44ExpLogTable.h"
inline void
convertFromLinear (unsigned short s[16])
{
for (int i = 0; i < 16; ++i)
s[i] = expTable[s[i]];
}
inline void
convertToLinear (unsigned short s[16])
{
for (int i = 0; i < 16; ++i)
s[i] = logTable[s[i]];
}
inline int
shiftAndRound (int x, int shift)
{
x <<= 1;
int a = (1 << shift) - 1;
shift += 1;
int b = (x >> shift) & 1;
return (x + a + b) >> shift;
}
int
pack (const unsigned short s[16],
unsigned char b[14],
bool optFlatFields,
bool exactMax)
{
unsigned short t[16];
for (int i = 0; i < 16; ++i)
{
if ((s[i] & 0x7c00) == 0x7c00)
t[i] = 0x8000;
else if (s[i] & 0x8000)
t[i] = ~s[i];
else
t[i] = s[i] | 0x8000;
}
unsigned short tMax = 0;
for (int i = 0; i < 16; ++i)
if (tMax < t[i])
tMax = t[i];
int shift = -1;
int d[16];
int r[15];
int rMin;
int rMax;
const int bias = 0x20;
do
{
shift += 1;
for (int i = 0; i < 16; ++i)
d[i] = shiftAndRound (tMax - t[i], shift);
r[ 0] = d[ 0] - d[ 4] + bias;
r[ 1] = d[ 4] - d[ 8] + bias;
r[ 2] = d[ 8] - d[12] + bias;
r[ 3] = d[ 0] - d[ 1] + bias;
r[ 4] = d[ 4] - d[ 5] + bias;
r[ 5] = d[ 8] - d[ 9] + bias;
r[ 6] = d[12] - d[13] + bias;
r[ 7] = d[ 1] - d[ 2] + bias;
r[ 8] = d[ 5] - d[ 6] + bias;
r[ 9] = d[ 9] - d[10] + bias;
r[10] = d[13] - d[14] + bias;
r[11] = d[ 2] - d[ 3] + bias;
r[12] = d[ 6] - d[ 7] + bias;
r[13] = d[10] - d[11] + bias;
r[14] = d[14] - d[15] + bias;
rMin = r[0];
rMax = r[0];
for (int i = 1; i < 15; ++i)
{
if (rMin > r[i])
rMin = r[i];
if (rMax < r[i])
rMax = r[i];
}
}
while (rMin < 0 || rMax > 0x3f);
if (rMin == bias && rMax == bias && optFlatFields)
{
b[0] = (t[0] >> 8);
b[1] = t[0];
b[2] = 0xfc;
return 3;
}
if (exactMax)
{
t[0] = tMax - (d[0] << shift);
}
b[ 0] = (t[0] >> 8);
b[ 1] = t[0];
b[ 2] = (unsigned char) ((shift << 2) | (r[ 0] >> 4));
b[ 3] = (unsigned char) ((r[ 0] << 4) | (r[ 1] >> 2));
b[ 4] = (unsigned char) ((r[ 1] << 6) | r[ 2] );
b[ 5] = (unsigned char) ((r[ 3] << 2) | (r[ 4] >> 4));
b[ 6] = (unsigned char) ((r[ 4] << 4) | (r[ 5] >> 2));
b[ 7] = (unsigned char) ((r[ 5] << 6) | r[ 6] );
b[ 8] = (unsigned char) ((r[ 7] << 2) | (r[ 8] >> 4));
b[ 9] = (unsigned char) ((r[ 8] << 4) | (r[ 9] >> 2));
b[10] = (unsigned char) ((r[ 9] << 6) | r[10] );
b[11] = (unsigned char) ((r[11] << 2) | (r[12] >> 4));
b[12] = (unsigned char) ((r[12] << 4) | (r[13] >> 2));
b[13] = (unsigned char) ((r[13] << 6) | r[14] );
return 14;
}
inline
void
unpack14 (const unsigned char b[14], unsigned short s[16])
{
#if defined (DEBUG)
assert (b[2] != 0xfc);
#endif
s[ 0] = (b[0] << 8) | b[1];
unsigned short shift = (b[ 2] >> 2);
unsigned short bias = (0x20 << shift);
s[ 4] = s[ 0] + ((((b[ 2] << 4) | (b[ 3] >> 4)) & 0x3f) << shift) - bias;
s[ 8] = s[ 4] + ((((b[ 3] << 2) | (b[ 4] >> 6)) & 0x3f) << shift) - bias;
s[12] = s[ 8] + ((b[ 4] & 0x3f) << shift) - bias;
s[ 1] = s[ 0] + ((b[ 5] >> 2) << shift) - bias;
s[ 5] = s[ 4] + ((((b[ 5] << 4) | (b[ 6] >> 4)) & 0x3f) << shift) - bias;
s[ 9] = s[ 8] + ((((b[ 6] << 2) | (b[ 7] >> 6)) & 0x3f) << shift) - bias;
s[13] = s[12] + ((b[ 7] & 0x3f) << shift) - bias;
s[ 2] = s[ 1] + ((b[ 8] >> 2) << shift) - bias;
s[ 6] = s[ 5] + ((((b[ 8] << 4) | (b[ 9] >> 4)) & 0x3f) << shift) - bias;
s[10] = s[ 9] + ((((b[ 9] << 2) | (b[10] >> 6)) & 0x3f) << shift) - bias;
s[14] = s[13] + ((b[10] & 0x3f) << shift) - bias;
s[ 3] = s[ 2] + ((b[11] >> 2) << shift) - bias;
s[ 7] = s[ 6] + ((((b[11] << 4) | (b[12] >> 4)) & 0x3f) << shift) - bias;
s[11] = s[10] + ((((b[12] << 2) | (b[13] >> 6)) & 0x3f) << shift) - bias;
s[15] = s[14] + ((b[13] & 0x3f) << shift) - bias;
for (int i = 0; i < 16; ++i)
{
if (s[i] & 0x8000)
s[i] &= 0x7fff;
else
s[i] = ~s[i];
}
}
inline
void
unpack3 (const unsigned char b[3], unsigned short s[16])
{
#if defined (DEBUG)
assert (b[2] == 0xfc);
#endif
s[0] = (b[0] << 8) | b[1];
if (s[0] & 0x8000)
s[0] &= 0x7fff;
else
s[0] = ~s[0];
for (int i = 1; i < 16; ++i)
s[i] = s[0];
}
void
notEnoughData ()
{
throw Iex::InputExc ("Error decompressing data "
"(input data are shorter than expected).");
}
void
tooMuchData ()
{
throw Iex::InputExc ("Error decompressing data "
"(input data are longer than expected).");
}
}
struct B44Compressor::ChannelData
{
unsigned short * start;
unsigned short * end;
int nx;
int ny;
int ys;
PixelType type;
bool pLinear;
int size;
};
B44Compressor::B44Compressor
(const Header &hdr,
size_t maxScanLineSize,
size_t numScanLines,
bool optFlatFields)
:
Compressor (hdr),
_maxScanLineSize (maxScanLineSize),
_optFlatFields (optFlatFields),
_format (XDR),
_numScanLines (numScanLines),
_tmpBuffer (0),
_outBuffer (0),
_numChans (0),
_channels (hdr.channels()),
_channelData (0)
{
_tmpBuffer = new unsigned short
[checkArraySize (uiMult (maxScanLineSize, numScanLines),
sizeof (unsigned short))];
const ChannelList &channels = header().channels();
int numHalfChans = 0;
for (ChannelList::ConstIterator c = channels.begin();
c != channels.end();
++c)
{
assert (pixelTypeSize (c.channel().type) % pixelTypeSize (HALF) == 0);
++_numChans;
if (c.channel().type == HALF)
++numHalfChans;
}
size_t padding = 12 * numHalfChans * (numScanLines + 3) / 4;
_outBuffer = new char
[uiAdd (uiMult (maxScanLineSize, numScanLines), padding)];
_channelData = new ChannelData[_numChans];
int i = 0;
for (ChannelList::ConstIterator c = channels.begin();
c != channels.end();
++c, ++i)
{
_channelData[i].ys = c.channel().ySampling;
_channelData[i].type = c.channel().type;
_channelData[i].pLinear = c.channel().pLinear;
_channelData[i].size =
pixelTypeSize (c.channel().type) / pixelTypeSize (HALF);
}
const Box2i &dataWindow = hdr.dataWindow();
_minX = dataWindow.min.x;
_maxX = dataWindow.max.x;
_maxY = dataWindow.max.y;
assert (sizeof (unsigned short) == pixelTypeSize (HALF));
if (_numChans == numHalfChans)
_format = NATIVE;
}
B44Compressor::~B44Compressor ()
{
delete [] _tmpBuffer;
delete [] _outBuffer;
delete [] _channelData;
}
int
B44Compressor::numScanLines () const
{
return _numScanLines;
}
Compressor::Format
B44Compressor::format () const
{
return _format;
}
int
B44Compressor::compress (const char *inPtr,
int inSize,
int minY,
const char *&outPtr)
{
return compress (inPtr,
inSize,
Box2i (V2i (_minX, minY),
V2i (_maxX, minY + numScanLines() - 1)),
outPtr);
}
int
B44Compressor::compressTile (const char *inPtr,
int inSize,
Imath::Box2i range,
const char *&outPtr)
{
return compress (inPtr, inSize, range, outPtr);
}
int
B44Compressor::uncompress (const char *inPtr,
int inSize,
int minY,
const char *&outPtr)
{
return uncompress (inPtr,
inSize,
Box2i (V2i (_minX, minY),
V2i (_maxX, minY + numScanLines() - 1)),
outPtr);
}
int
B44Compressor::uncompressTile (const char *inPtr,
int inSize,
Imath::Box2i range,
const char *&outPtr)
{
return uncompress (inPtr, inSize, range, outPtr);
}
int
B44Compressor::compress (const char *inPtr,
int inSize,
Imath::Box2i range,
const char *&outPtr)
{
outPtr = _outBuffer;
if (inSize == 0)
{
return 0;
}
int minX = range.min.x;
int maxX = min (range.max.x, _maxX);
int minY = range.min.y;
int maxY = min (range.max.y, _maxY);
unsigned short *tmpBufferEnd = _tmpBuffer;
int i = 0;
for (ChannelList::ConstIterator c = _channels.begin();
c != _channels.end();
++c, ++i)
{
ChannelData &cd = _channelData[i];
cd.start = tmpBufferEnd;
cd.end = cd.start;
cd.nx = numSamples (c.channel().xSampling, minX, maxX);
cd.ny = numSamples (c.channel().ySampling, minY, maxY);
tmpBufferEnd += cd.nx * cd.ny * cd.size;
}
if (_format == XDR)
{
for (int y = minY; y <= maxY; ++y)
{
for (int i = 0; i < _numChans; ++i)
{
ChannelData &cd = _channelData[i];
if (modp (y, cd.ys) != 0)
continue;
if (cd.type == HALF)
{
for (int x = cd.nx; x > 0; --x)
{
Xdr::read <CharPtrIO> (inPtr, *cd.end);
++cd.end;
}
}
else
{
int n = cd.nx * cd.size;
memcpy (cd.end, inPtr, n * sizeof (unsigned short));
inPtr += n * sizeof (unsigned short);
cd.end += n;
}
}
}
}
else
{
for (int y = minY; y <= maxY; ++y)
{
for (int i = 0; i < _numChans; ++i)
{
ChannelData &cd = _channelData[i];
#if defined (DEBUG)
assert (cd.type == HALF);
#endif
if (modp (y, cd.ys) != 0)
continue;
int n = cd.nx * cd.size;
memcpy (cd.end, inPtr, n * sizeof (unsigned short));
inPtr += n * sizeof (unsigned short);
cd.end += n;
}
}
}
#if defined (DEBUG)
for (int i = 1; i < _numChans; ++i)
assert (_channelData[i-1].end == _channelData[i].start);
assert (_channelData[_numChans-1].end == tmpBufferEnd);
#endif
char *outEnd = _outBuffer;
for (int i = 0; i < _numChans; ++i)
{
ChannelData &cd = _channelData[i];
if (cd.type != HALF)
{
int n = cd.nx * cd.ny * cd.size * sizeof (unsigned short);
memcpy (outEnd, cd.start, n);
outEnd += n;
continue;
}
for (int y = 0; y < cd.ny; y += 4)
{
unsigned short *row0 = cd.start + y * cd.nx;
unsigned short *row1 = row0 + cd.nx;
unsigned short *row2 = row1 + cd.nx;
unsigned short *row3 = row2 + cd.nx;
if (y + 3 >= cd.ny)
{
if (y + 1 >= cd.ny)
row1 = row0;
if (y + 2 >= cd.ny)
row2 = row1;
row3 = row2;
}
for (int x = 0; x < cd.nx; x += 4)
{
unsigned short s[16];
if (x + 3 >= cd.nx)
{
int n = cd.nx - x;
for (int i = 0; i < 4; ++i)
{
int j = min (i, n - 1);
s[i + 0] = row0[j];
s[i + 4] = row1[j];
s[i + 8] = row2[j];
s[i + 12] = row3[j];
}
}
else
{
memcpy (&s[ 0], row0, 4 * sizeof (unsigned short));
memcpy (&s[ 4], row1, 4 * sizeof (unsigned short));
memcpy (&s[ 8], row2, 4 * sizeof (unsigned short));
memcpy (&s[12], row3, 4 * sizeof (unsigned short));
}
row0 += 4;
row1 += 4;
row2 += 4;
row3 += 4;
if (cd.pLinear)
convertFromLinear (s);
outEnd += pack (s, (unsigned char *) outEnd,
_optFlatFields, !cd.pLinear);
}
}
}
return outEnd - _outBuffer;
}
int
B44Compressor::uncompress (const char *inPtr,
int inSize,
Imath::Box2i range,
const char *&outPtr)
{
outPtr = _outBuffer;
if (inSize == 0)
{
return 0;
}
int minX = range.min.x;
int maxX = min (range.max.x, _maxX);
int minY = range.min.y;
int maxY = min (range.max.y, _maxY);
unsigned short *tmpBufferEnd = _tmpBuffer;
int i = 0;
for (ChannelList::ConstIterator c = _channels.begin();
c != _channels.end();
++c, ++i)
{
ChannelData &cd = _channelData[i];
cd.start = tmpBufferEnd;
cd.end = cd.start;
cd.nx = numSamples (c.channel().xSampling, minX, maxX);
cd.ny = numSamples (c.channel().ySampling, minY, maxY);
tmpBufferEnd += cd.nx * cd.ny * cd.size;
}
for (int i = 0; i < _numChans; ++i)
{
ChannelData &cd = _channelData[i];
if (cd.type != HALF)
{
int n = cd.nx * cd.ny * cd.size * sizeof (unsigned short);
if (inSize < n)
notEnoughData();
memcpy (cd.start, inPtr, n);
inPtr += n;
inSize -= n;
continue;
}
for (int y = 0; y < cd.ny; y += 4)
{
unsigned short *row0 = cd.start + y * cd.nx;
unsigned short *row1 = row0 + cd.nx;
unsigned short *row2 = row1 + cd.nx;
unsigned short *row3 = row2 + cd.nx;
for (int x = 0; x < cd.nx; x += 4)
{
unsigned short s[16];
if (inSize < 3)
notEnoughData();
if (((const unsigned char *)inPtr)[2] == 0xfc)
{
unpack3 ((const unsigned char *)inPtr, s);
inPtr += 3;
inSize -= 3;
}
else
{
if (inSize < 14)
notEnoughData();
unpack14 ((const unsigned char *)inPtr, s);
inPtr += 14;
inSize -= 14;
}
if (cd.pLinear)
convertToLinear (s);
int n = (x + 3 < cd.nx)?
4 * sizeof (unsigned short) :
(cd.nx - x) * sizeof (unsigned short);
if (y + 3 < cd.ny)
{
memcpy (row0, &s[ 0], n);
memcpy (row1, &s[ 4], n);
memcpy (row2, &s[ 8], n);
memcpy (row3, &s[12], n);
}
else
{
memcpy (row0, &s[ 0], n);
if (y + 1 < cd.ny)
memcpy (row1, &s[ 4], n);
if (y + 2 < cd.ny)
memcpy (row2, &s[ 8], n);
}
row0 += 4;
row1 += 4;
row2 += 4;
row3 += 4;
}
}
}
char *outEnd = _outBuffer;
if (_format == XDR)
{
for (int y = minY; y <= maxY; ++y)
{
for (int i = 0; i < _numChans; ++i)
{
ChannelData &cd = _channelData[i];
if (modp (y, cd.ys) != 0)
continue;
if (cd.type == HALF)
{
for (int x = cd.nx; x > 0; --x)
{
Xdr::write <CharPtrIO> (outEnd, *cd.end);
++cd.end;
}
}
else
{
int n = cd.nx * cd.size;
memcpy (outEnd, cd.end, n * sizeof (unsigned short));
outEnd += n * sizeof (unsigned short);
cd.end += n;
}
}
}
}
else
{
for (int y = minY; y <= maxY; ++y)
{
for (int i = 0; i < _numChans; ++i)
{
ChannelData &cd = _channelData[i];
#if defined (DEBUG)
assert (cd.type == HALF);
#endif
if (modp (y, cd.ys) != 0)
continue;
int n = cd.nx * cd.size;
memcpy (outEnd, cd.end, n * sizeof (unsigned short));
outEnd += n * sizeof (unsigned short);
cd.end += n;
}
}
}
#if defined (DEBUG)
for (int i = 1; i < _numChans; ++i)
assert (_channelData[i-1].end == _channelData[i].start);
assert (_channelData[_numChans-1].end == tmpBufferEnd);
#endif
if (inSize > 0)
tooMuchData();
outPtr = _outBuffer;
return outEnd - _outBuffer;
}
}