This source file includes following definitions.
- floatToFloat24
- notEnoughData
- tooMuchData
- _channels
- numScanLines
- format
- compress
- compressTile
- uncompress
- uncompressTile
- compress
- uncompress
#include <ImfPxr24Compressor.h>
#include <ImfHeader.h>
#include <ImfChannelList.h>
#include <ImfMisc.h>
#include <ImfCheckedArithmetic.h>
#include <ImathFun.h>
#include <Iex.h>
#include <half.h>
#include <zlib.h>
#include <assert.h>
#include <algorithm>
using namespace std;
using namespace Imath;
namespace Imf {
namespace {
inline unsigned int
floatToFloat24 (float f)
{
union
{
float f;
unsigned int i;
} u;
u.f = f;
unsigned int s = u.i & 0x80000000;
unsigned int e = u.i & 0x7f800000;
unsigned int m = u.i & 0x007fffff;
unsigned int i;
if (e == 0x7f800000)
{
if (m)
{
m >>= 8;
i = (e >> 8) | m | (m == 0);
}
else
{
i = e >> 8;
}
}
else
{
i = ((e | m) + (m & 0x00000080)) >> 8;
if (i >= 0x7f8000)
{
i = (e | m) >> 8;
}
}
return (s >> 8) | i;
}
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).");
}
}
Pxr24Compressor::Pxr24Compressor (const Header &hdr,
size_t maxScanLineSize,
size_t numScanLines)
:
Compressor (hdr),
_maxScanLineSize (maxScanLineSize),
_numScanLines (numScanLines),
_tmpBuffer (0),
_outBuffer (0),
_channels (hdr.channels())
{
size_t maxInBytes =
uiMult (maxScanLineSize, numScanLines);
size_t maxOutBytes =
uiAdd (uiAdd (maxInBytes,
size_t (ceil (maxInBytes * 0.01))),
size_t (100));
_tmpBuffer = new unsigned char [maxInBytes];
_outBuffer = new char [maxOutBytes];
const Box2i &dataWindow = hdr.dataWindow();
_minX = dataWindow.min.x;
_maxX = dataWindow.max.x;
_maxY = dataWindow.max.y;
}
Pxr24Compressor::~Pxr24Compressor ()
{
delete [] _tmpBuffer;
delete [] _outBuffer;
}
int
Pxr24Compressor::numScanLines () const
{
return _numScanLines;
}
Compressor::Format
Pxr24Compressor::format () const
{
return NATIVE;
}
int
Pxr24Compressor::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
Pxr24Compressor::compressTile (const char *inPtr,
int inSize,
Box2i range,
const char *&outPtr)
{
return compress (inPtr, inSize, range, outPtr);
}
int
Pxr24Compressor::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
Pxr24Compressor::uncompressTile (const char *inPtr,
int inSize,
Box2i range,
const char *&outPtr)
{
return uncompress (inPtr, inSize, range, outPtr);
}
int
Pxr24Compressor::compress (const char *inPtr,
int inSize,
Box2i range,
const char *&outPtr)
{
if (inSize == 0)
{
outPtr = _outBuffer;
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 char *tmpBufferEnd = _tmpBuffer;
for (int y = minY; y <= maxY; ++y)
{
for (ChannelList::ConstIterator i = _channels.begin();
i != _channels.end();
++i)
{
const Channel &c = i.channel();
if (modp (y, c.ySampling) != 0)
continue;
int n = numSamples (c.xSampling, minX, maxX);
unsigned char *ptr[4];
unsigned int previousPixel = 0;
switch (c.type)
{
case UINT:
ptr[0] = tmpBufferEnd;
ptr[1] = ptr[0] + n;
ptr[2] = ptr[1] + n;
ptr[3] = ptr[2] + n;
tmpBufferEnd = ptr[3] + n;
for (int j = 0; j < n; ++j)
{
unsigned int pixel;
char *pPtr = (char *) &pixel;
for (int k = 0; k < sizeof (pixel); ++k)
*pPtr++ = *inPtr++;
unsigned int diff = pixel - previousPixel;
previousPixel = pixel;
*(ptr[0]++) = diff >> 24;
*(ptr[1]++) = diff >> 16;
*(ptr[2]++) = diff >> 8;
*(ptr[3]++) = diff;
}
break;
case HALF:
ptr[0] = tmpBufferEnd;
ptr[1] = ptr[0] + n;
tmpBufferEnd = ptr[1] + n;
for (int j = 0; j < n; ++j)
{
half pixel;
pixel = *(const half *) inPtr;
inPtr += sizeof (half);
unsigned int diff = pixel.bits() - previousPixel;
previousPixel = pixel.bits();
*(ptr[0]++) = diff >> 8;
*(ptr[1]++) = diff;
}
break;
case FLOAT:
ptr[0] = tmpBufferEnd;
ptr[1] = ptr[0] + n;
ptr[2] = ptr[1] + n;
tmpBufferEnd = ptr[2] + n;
for (int j = 0; j < n; ++j)
{
float pixel;
char *pPtr = (char *) &pixel;
for (int k = 0; k < sizeof (pixel); ++k)
*pPtr++ = *inPtr++;
unsigned int pixel24 = floatToFloat24 (pixel);
unsigned int diff = pixel24 - previousPixel;
previousPixel = pixel24;
*(ptr[0]++) = diff >> 16;
*(ptr[1]++) = diff >> 8;
*(ptr[2]++) = diff;
}
break;
default:
assert (false);
}
}
}
uLongf outSize = int (ceil ((tmpBufferEnd - _tmpBuffer) * 1.01)) + 100;
if (Z_OK != ::compress ((Bytef *) _outBuffer,
&outSize,
(const Bytef *) _tmpBuffer,
tmpBufferEnd - _tmpBuffer))
{
throw Iex::BaseExc ("Data compression (zlib) failed.");
}
outPtr = _outBuffer;
return outSize;
}
int
Pxr24Compressor::uncompress (const char *inPtr,
int inSize,
Box2i range,
const char *&outPtr)
{
if (inSize == 0)
{
outPtr = _outBuffer;
return 0;
}
uLongf tmpSize = _maxScanLineSize * _numScanLines;
if (Z_OK != ::uncompress ((Bytef *)_tmpBuffer,
&tmpSize,
(const Bytef *) inPtr,
inSize))
{
throw Iex::InputExc ("Data decompression (zlib) failed.");
}
int minX = range.min.x;
int maxX = min (range.max.x, _maxX);
int minY = range.min.y;
int maxY = min (range.max.y, _maxY);
const unsigned char *tmpBufferEnd = _tmpBuffer;
char *writePtr = _outBuffer;
for (int y = minY; y <= maxY; ++y)
{
for (ChannelList::ConstIterator i = _channels.begin();
i != _channels.end();
++i)
{
const Channel &c = i.channel();
if (modp (y, c.ySampling) != 0)
continue;
int n = numSamples (c.xSampling, minX, maxX);
const unsigned char *ptr[4];
unsigned int pixel = 0;
switch (c.type)
{
case UINT:
ptr[0] = tmpBufferEnd;
ptr[1] = ptr[0] + n;
ptr[2] = ptr[1] + n;
ptr[3] = ptr[2] + n;
tmpBufferEnd = ptr[3] + n;
if (tmpBufferEnd - _tmpBuffer > tmpSize)
notEnoughData();
for (int j = 0; j < n; ++j)
{
unsigned int diff = (*(ptr[0]++) << 24) |
(*(ptr[1]++) << 16) |
(*(ptr[2]++) << 8) |
*(ptr[3]++);
pixel += diff;
char *pPtr = (char *) &pixel;
for (int k = 0; k < sizeof (pixel); ++k)
*writePtr++ = *pPtr++;
}
break;
case HALF:
ptr[0] = tmpBufferEnd;
ptr[1] = ptr[0] + n;
tmpBufferEnd = ptr[1] + n;
if (tmpBufferEnd - _tmpBuffer > tmpSize)
notEnoughData();
for (int j = 0; j < n; ++j)
{
unsigned int diff = (*(ptr[0]++) << 8) |
*(ptr[1]++);
pixel += diff;
half * hPtr = (half *) writePtr;
hPtr->setBits ((unsigned short) pixel);
writePtr += sizeof (half);
}
break;
case FLOAT:
ptr[0] = tmpBufferEnd;
ptr[1] = ptr[0] + n;
ptr[2] = ptr[1] + n;
tmpBufferEnd = ptr[2] + n;
if (tmpBufferEnd - _tmpBuffer > tmpSize)
notEnoughData();
for (int j = 0; j < n; ++j)
{
unsigned int diff = (*(ptr[0]++) << 24) |
(*(ptr[1]++) << 16) |
(*(ptr[2]++) << 8);
pixel += diff;
char *pPtr = (char *) &pixel;
for (int k = 0; k < sizeof (pixel); ++k)
*writePtr++ = *pPtr++;
}
break;
default:
assert (false);
}
}
}
if (tmpBufferEnd - _tmpBuffer < tmpSize)
tooMuchData();
outPtr = _outBuffer;
return writePtr - _outBuffer;
}
}