Home | History | Annotate | Download | only in IlmImf
      1 ///////////////////////////////////////////////////////////////////////////
      2 //
      3 // Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
      4 // Digital Ltd. LLC
      5 //
      6 // All rights reserved.
      7 //
      8 // Redistribution and use in source and binary forms, with or without
      9 // modification, are permitted provided that the following conditions are
     10 // met:
     11 // *       Redistributions of source code must retain the above copyright
     12 // notice, this list of conditions and the following disclaimer.
     13 // *       Redistributions in binary form must reproduce the above
     14 // copyright notice, this list of conditions and the following disclaimer
     15 // in the documentation and/or other materials provided with the
     16 // distribution.
     17 // *       Neither the name of Industrial Light & Magic nor the names of
     18 // its contributors may be used to endorse or promote products derived
     19 // from this software without specific prior written permission.
     20 //
     21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32 //
     33 ///////////////////////////////////////////////////////////////////////////
     34 
     35 
     36 //-----------------------------------------------------------------------------
     37 //
     38 //	class PizCompressor
     39 //
     40 //-----------------------------------------------------------------------------
     41 
     42 #include <ImfPizCompressor.h>
     43 #include <ImfHeader.h>
     44 #include <ImfChannelList.h>
     45 #include <ImfHuf.h>
     46 #include <ImfWav.h>
     47 #include <ImfMisc.h>
     48 #include <ImfCheckedArithmetic.h>
     49 #include <ImathFun.h>
     50 #include <ImathBox.h>
     51 #include <Iex.h>
     52 #include <ImfIO.h>
     53 #include <ImfXdr.h>
     54 #include <ImfAutoArray.h>
     55 #include <string.h>
     56 #include <assert.h>
     57 
     58 namespace Imf {
     59 
     60 using Imath::divp;
     61 using Imath::modp;
     62 using Imath::Box2i;
     63 using Imath::V2i;
     64 using Iex::InputExc;
     65 
     66 namespace {
     67 
     68 //
     69 // Functions to compress the range of values in the pixel data
     70 //
     71 
     72 const int USHORT_RANGE = (1 << 16);
     73 const int BITMAP_SIZE  = (USHORT_RANGE >> 3);
     74 
     75 void
     76 bitmapFromData (const unsigned short data[/*nData*/],
     77         int nData,
     78         unsigned char bitmap[BITMAP_SIZE],
     79         unsigned short &minNonZero,
     80         unsigned short &maxNonZero)
     81 {
     82     for (int i = 0; i < BITMAP_SIZE; ++i)
     83     bitmap[i] = 0;
     84 
     85     for (int i = 0; i < nData; ++i)
     86     bitmap[data[i] >> 3] |= (1 << (data[i] & 7));
     87 
     88     bitmap[0] &= ~1;			// zero is not explicitly stored in
     89                     // the bitmap; we assume that the
     90                     // data always contain zeroes
     91     minNonZero = BITMAP_SIZE - 1;
     92     maxNonZero = 0;
     93 
     94     for (int i = 0; i < BITMAP_SIZE; ++i)
     95     {
     96     if (bitmap[i])
     97     {
     98         if (minNonZero > i)
     99         minNonZero = i;
    100         if (maxNonZero < i)
    101         maxNonZero = i;
    102     }
    103     }
    104 }
    105 
    106 
    107 unsigned short
    108 forwardLutFromBitmap (const unsigned char bitmap[BITMAP_SIZE],
    109               unsigned short lut[USHORT_RANGE])
    110 {
    111     int k = 0;
    112 
    113     for (int i = 0; i < USHORT_RANGE; ++i)
    114     {
    115     if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7))))
    116         lut[i] = k++;
    117     else
    118         lut[i] = 0;
    119     }
    120 
    121     return k - 1;	// maximum value stored in lut[],
    122 }			// i.e. number of ones in bitmap minus 1
    123 
    124 
    125 unsigned short
    126 reverseLutFromBitmap (const unsigned char bitmap[BITMAP_SIZE],
    127               unsigned short lut[USHORT_RANGE])
    128 {
    129     int k = 0;
    130 
    131     for (int i = 0; i < USHORT_RANGE; ++i)
    132     {
    133     if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7))))
    134         lut[k++] = i;
    135     }
    136 
    137     int n = k - 1;
    138 
    139     while (k < USHORT_RANGE)
    140     lut[k++] = 0;
    141 
    142     return n;		// maximum k where lut[k] is non-zero,
    143 }			// i.e. number of ones in bitmap minus 1
    144 
    145 
    146 void
    147 applyLut (const unsigned short lut[USHORT_RANGE],
    148       unsigned short data[/*nData*/],
    149       int nData)
    150 {
    151     for (int i = 0; i < nData; ++i)
    152     data[i] = lut[data[i]];
    153 }
    154 
    155 
    156 } // namespace
    157 
    158 
    159 struct PizCompressor::ChannelData
    160 {
    161     unsigned short *	start;
    162     unsigned short *	end;
    163     int			nx;
    164     int			ny;
    165     int			ys;
    166     int			size;
    167 };
    168 
    169 
    170 PizCompressor::PizCompressor
    171     (const Header &hdr,
    172      size_t maxScanLineSize,
    173      size_t numScanLines)
    174 :
    175     Compressor (hdr),
    176     _maxScanLineSize (maxScanLineSize),
    177     _format (XDR),
    178     _numScanLines (numScanLines),
    179     _tmpBuffer (0),
    180     _outBuffer (0),
    181     _numChans (0),
    182     _channels (hdr.channels()),
    183     _channelData (0)
    184 {
    185     size_t tmpBufferSize =
    186                 uiMult (maxScanLineSize, numScanLines) / 2;
    187 
    188     size_t outBufferSize =
    189                 uiAdd (uiMult (maxScanLineSize, numScanLines),
    190                        size_t (65536 + 8192));
    191 
    192     _tmpBuffer = new unsigned short
    193             [checkArraySize (tmpBufferSize, sizeof (unsigned short))];
    194 
    195     _outBuffer = new char [outBufferSize];
    196 
    197     const ChannelList &channels = header().channels();
    198     bool onlyHalfChannels = true;
    199 
    200     for (ChannelList::ConstIterator c = channels.begin();
    201      c != channels.end();
    202      ++c)
    203     {
    204     _numChans++;
    205 
    206     assert (pixelTypeSize (c.channel().type) % pixelTypeSize (HALF) == 0);
    207 
    208     if (c.channel().type != HALF)
    209         onlyHalfChannels = false;
    210     }
    211 
    212     _channelData = new ChannelData[_numChans];
    213 
    214     const Box2i &dataWindow = hdr.dataWindow();
    215 
    216     _minX = dataWindow.min.x;
    217     _maxX = dataWindow.max.x;
    218     _maxY = dataWindow.max.y;
    219 
    220     //
    221     // We can support uncompressed data in the machine's native format
    222     // if all image channels are of type HALF, and if the Xdr and the
    223     // native represenations of a half have the same size.
    224     //
    225 
    226     if (onlyHalfChannels && (sizeof (half) == pixelTypeSize (HALF)))
    227     _format = NATIVE;
    228 }
    229 
    230 
    231 PizCompressor::~PizCompressor ()
    232 {
    233     delete [] _tmpBuffer;
    234     delete [] _outBuffer;
    235     delete [] _channelData;
    236 }
    237 
    238 
    239 int
    240 PizCompressor::numScanLines () const
    241 {
    242     return _numScanLines;
    243 }
    244 
    245 
    246 Compressor::Format
    247 PizCompressor::format () const
    248 {
    249     return _format;
    250 }
    251 
    252 
    253 int
    254 PizCompressor::compress (const char *inPtr,
    255              int inSize,
    256              int minY,
    257              const char *&outPtr)
    258 {
    259     return compress (inPtr,
    260              inSize,
    261              Box2i (V2i (_minX, minY),
    262                 V2i (_maxX, minY + numScanLines() - 1)),
    263              outPtr);
    264 }
    265 
    266 
    267 int
    268 PizCompressor::compressTile (const char *inPtr,
    269                  int inSize,
    270                  Imath::Box2i range,
    271                  const char *&outPtr)
    272 {
    273     return compress (inPtr, inSize, range, outPtr);
    274 }
    275 
    276 
    277 int
    278 PizCompressor::uncompress (const char *inPtr,
    279                int inSize,
    280                int minY,
    281                const char *&outPtr)
    282 {
    283     return uncompress (inPtr,
    284                inSize,
    285                Box2i (V2i (_minX, minY),
    286                   V2i (_maxX, minY + numScanLines() - 1)),
    287                outPtr);
    288 }
    289 
    290 
    291 int
    292 PizCompressor::uncompressTile (const char *inPtr,
    293                    int inSize,
    294                    Imath::Box2i range,
    295                    const char *&outPtr)
    296 {
    297     return uncompress (inPtr, inSize, range, outPtr);
    298 }
    299 
    300 
    301 int
    302 PizCompressor::compress (const char *inPtr,
    303              int inSize,
    304              Imath::Box2i range,
    305              const char *&outPtr)
    306 {
    307     //
    308     // This is the compress function which is used by both the tiled and
    309     // scanline compression routines.
    310     //
    311 
    312     //
    313     // Special case - empty input buffer
    314     //
    315 
    316     if (inSize == 0)
    317     {
    318     outPtr = _outBuffer;
    319     return 0;
    320     }
    321 
    322     //
    323     // Rearrange the pixel data so that the wavelet
    324     // and Huffman encoders can process them easily.
    325     //
    326     // The wavelet and Huffman encoders both handle only
    327     // 16-bit data, so 32-bit data must be split into smaller
    328     // pieces.  We treat each 32-bit channel (UINT, FLOAT) as
    329     // two interleaved 16-bit channels.
    330     //
    331 
    332     int minX = range.min.x;
    333     int maxX = range.max.x;
    334     int minY = range.min.y;
    335     int maxY = range.max.y;
    336 
    337     if (maxY > _maxY)
    338         maxY = _maxY;
    339 
    340     if (maxX > _maxX)
    341         maxX = _maxX;
    342 
    343     unsigned short *tmpBufferEnd = _tmpBuffer;
    344     int i = 0;
    345 
    346     for (ChannelList::ConstIterator c = _channels.begin();
    347      c != _channels.end();
    348      ++c, ++i)
    349     {
    350     ChannelData &cd = _channelData[i];
    351 
    352     cd.start = tmpBufferEnd;
    353     cd.end = cd.start;
    354 
    355     cd.nx = numSamples (c.channel().xSampling, minX, maxX);
    356     cd.ny = numSamples (c.channel().ySampling, minY, maxY);
    357     cd.ys = c.channel().ySampling;
    358 
    359     cd.size = pixelTypeSize (c.channel().type) / pixelTypeSize (HALF);
    360 
    361     tmpBufferEnd += cd.nx * cd.ny * cd.size;
    362     }
    363 
    364     if (_format == XDR)
    365     {
    366     //
    367     // Machine-independent (Xdr) data format
    368     //
    369 
    370     for (int y = minY; y <= maxY; ++y)
    371     {
    372         for (int i = 0; i < _numChans; ++i)
    373         {
    374         ChannelData &cd = _channelData[i];
    375 
    376         if (modp (y, cd.ys) != 0)
    377             continue;
    378 
    379         for (int x = cd.nx * cd.size; x > 0; --x)
    380         {
    381             Xdr::read <CharPtrIO> (inPtr, *cd.end);
    382             ++cd.end;
    383         }
    384         }
    385     }
    386     }
    387     else
    388     {
    389     //
    390     // Native, machine-dependent data format
    391     //
    392 
    393     for (int y = minY; y <= maxY; ++y)
    394     {
    395         for (int i = 0; i < _numChans; ++i)
    396         {
    397         ChannelData &cd = _channelData[i];
    398 
    399         if (modp (y, cd.ys) != 0)
    400             continue;
    401 
    402         int n = cd.nx * cd.size;
    403         memcpy (cd.end, inPtr, n * sizeof (unsigned short));
    404         inPtr  += n * sizeof (unsigned short);
    405         cd.end += n;
    406         }
    407     }
    408     }
    409 
    410     #if defined (DEBUG)
    411 
    412     for (int i = 1; i < _numChans; ++i)
    413         assert (_channelData[i-1].end == _channelData[i].start);
    414 
    415     assert (_channelData[_numChans-1].end == tmpBufferEnd);
    416 
    417     #endif
    418 
    419     //
    420     // Compress the range of the pixel data
    421     //
    422 
    423     AutoArray <unsigned char, BITMAP_SIZE> bitmap;
    424     unsigned short minNonZero;
    425     unsigned short maxNonZero;
    426 
    427     bitmapFromData (_tmpBuffer,
    428             tmpBufferEnd - _tmpBuffer,
    429             bitmap,
    430             minNonZero, maxNonZero);
    431 
    432     AutoArray <unsigned short, USHORT_RANGE> lut;
    433     unsigned short maxValue = forwardLutFromBitmap (bitmap, lut);
    434     applyLut (lut, _tmpBuffer, tmpBufferEnd - _tmpBuffer);
    435 
    436     //
    437     // Store range compression info in _outBuffer
    438     //
    439 
    440     char *buf = _outBuffer;
    441 
    442     Xdr::write <CharPtrIO> (buf, minNonZero);
    443     Xdr::write <CharPtrIO> (buf, maxNonZero);
    444 
    445     if (minNonZero <= maxNonZero)
    446     {
    447     Xdr::write <CharPtrIO> (buf, (char *) &bitmap[0] + minNonZero,
    448                 maxNonZero - minNonZero + 1);
    449     }
    450 
    451     //
    452     // Apply wavelet encoding
    453     //
    454 
    455     for (int i = 0; i < _numChans; ++i)
    456     {
    457     ChannelData &cd = _channelData[i];
    458 
    459     for (int j = 0; j < cd.size; ++j)
    460     {
    461         wav2Encode (cd.start + j,
    462             cd.nx, cd.size,
    463             cd.ny, cd.nx * cd.size,
    464             maxValue);
    465     }
    466     }
    467 
    468     //
    469     // Apply Huffman encoding; append the result to _outBuffer
    470     //
    471 
    472     char *lengthPtr = buf;
    473     Xdr::write <CharPtrIO> (buf, int(0));
    474 
    475     int length = hufCompress (_tmpBuffer, tmpBufferEnd - _tmpBuffer, buf);
    476     Xdr::write <CharPtrIO> (lengthPtr, length);
    477 
    478     outPtr = _outBuffer;
    479     return buf - _outBuffer + length;
    480 }
    481 
    482 
    483 int
    484 PizCompressor::uncompress (const char *inPtr,
    485                int inSize,
    486                Imath::Box2i range,
    487                const char *&outPtr)
    488 {
    489     //
    490     // This is the cunompress function which is used by both the tiled and
    491     // scanline decompression routines.
    492     //
    493 
    494     //
    495     // Special case - empty input buffer
    496     //
    497 
    498     if (inSize == 0)
    499     {
    500     outPtr = _outBuffer;
    501     return 0;
    502     }
    503 
    504     //
    505     // Determine the layout of the compressed pixel data
    506     //
    507 
    508     int minX = range.min.x;
    509     int maxX = range.max.x;
    510     int minY = range.min.y;
    511     int maxY = range.max.y;
    512 
    513     if (maxY > _maxY)
    514         maxY = _maxY;
    515 
    516     if (maxX > _maxX)
    517         maxX = _maxX;
    518 
    519     unsigned short *tmpBufferEnd = _tmpBuffer;
    520     int i = 0;
    521 
    522     for (ChannelList::ConstIterator c = _channels.begin();
    523      c != _channels.end();
    524      ++c, ++i)
    525     {
    526     ChannelData &cd = _channelData[i];
    527 
    528     cd.start = tmpBufferEnd;
    529     cd.end = cd.start;
    530 
    531     cd.nx = numSamples (c.channel().xSampling, minX, maxX);
    532     cd.ny = numSamples (c.channel().ySampling, minY, maxY);
    533     cd.ys = c.channel().ySampling;
    534 
    535     cd.size = pixelTypeSize (c.channel().type) / pixelTypeSize (HALF);
    536 
    537     tmpBufferEnd += cd.nx * cd.ny * cd.size;
    538     }
    539 
    540     //
    541     // Read range compression data
    542     //
    543 
    544     unsigned short minNonZero;
    545     unsigned short maxNonZero;
    546 
    547     AutoArray <unsigned char, BITMAP_SIZE> bitmap;
    548     memset (bitmap, 0, sizeof (unsigned char) * BITMAP_SIZE);
    549 
    550     Xdr::read <CharPtrIO> (inPtr, minNonZero);
    551     Xdr::read <CharPtrIO> (inPtr, maxNonZero);
    552 
    553     if (maxNonZero >= BITMAP_SIZE)
    554     {
    555     throw InputExc ("Error in header for PIZ-compressed data "
    556             "(invalid bitmap size).");
    557     }
    558 
    559     if (minNonZero <= maxNonZero)
    560     {
    561     Xdr::read <CharPtrIO> (inPtr, (char *) &bitmap[0] + minNonZero,
    562                    maxNonZero - minNonZero + 1);
    563     }
    564 
    565     AutoArray <unsigned short, USHORT_RANGE> lut;
    566     unsigned short maxValue = reverseLutFromBitmap (bitmap, lut);
    567 
    568     //
    569     // Huffman decoding
    570     //
    571 
    572     int length;
    573     Xdr::read <CharPtrIO> (inPtr, length);
    574 
    575     hufUncompress (inPtr, length, _tmpBuffer, tmpBufferEnd - _tmpBuffer);
    576 
    577     //
    578     // Wavelet decoding
    579     //
    580 
    581     for (int i = 0; i < _numChans; ++i)
    582     {
    583     ChannelData &cd = _channelData[i];
    584 
    585     for (int j = 0; j < cd.size; ++j)
    586     {
    587         wav2Decode (cd.start + j,
    588             cd.nx, cd.size,
    589             cd.ny, cd.nx * cd.size,
    590             maxValue);
    591     }
    592     }
    593 
    594     //
    595     // Expand the pixel data to their original range
    596     //
    597 
    598     applyLut (lut, _tmpBuffer, tmpBufferEnd - _tmpBuffer);
    599 
    600     //
    601     // Rearrange the pixel data into the format expected by the caller.
    602     //
    603 
    604     char *outEnd = _outBuffer;
    605 
    606     if (_format == XDR)
    607     {
    608     //
    609     // Machine-independent (Xdr) data format
    610     //
    611 
    612     for (int y = minY; y <= maxY; ++y)
    613     {
    614         for (int i = 0; i < _numChans; ++i)
    615         {
    616         ChannelData &cd = _channelData[i];
    617 
    618         if (modp (y, cd.ys) != 0)
    619             continue;
    620 
    621         for (int x = cd.nx * cd.size; x > 0; --x)
    622         {
    623             Xdr::write <CharPtrIO> (outEnd, *cd.end);
    624             ++cd.end;
    625         }
    626         }
    627     }
    628     }
    629     else
    630     {
    631     //
    632     // Native, machine-dependent data format
    633     //
    634 
    635     for (int y = minY; y <= maxY; ++y)
    636     {
    637         for (int i = 0; i < _numChans; ++i)
    638         {
    639         ChannelData &cd = _channelData[i];
    640 
    641         if (modp (y, cd.ys) != 0)
    642             continue;
    643 
    644         int n = cd.nx * cd.size;
    645         memcpy (outEnd, cd.end, n * sizeof (unsigned short));
    646         outEnd += n * sizeof (unsigned short);
    647         cd.end += n;
    648         }
    649     }
    650     }
    651 
    652     #if defined (DEBUG)
    653 
    654     for (int i = 1; i < _numChans; ++i)
    655         assert (_channelData[i-1].end == _channelData[i].start);
    656 
    657     assert (_channelData[_numChans-1].end == tmpBufferEnd);
    658 
    659     #endif
    660 
    661     outPtr = _outBuffer;
    662     return outEnd - _outBuffer;
    663 }
    664 
    665 
    666 } // namespace Imf
    667