Home | History | Annotate | Download | only in IlmImf
      1 ///////////////////////////////////////////////////////////////////////////
      2 //
      3 // Copyright (c) 2006, 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 B44Compressor
     39 //
     40 //	This compressor is lossy for HALF channels; the compression rate
     41 //	is fixed at 32/14 (approximately 2.28).  FLOAT and UINT channels
     42 //	are not compressed; their data are preserved exactly.
     43 //
     44 //	Each HALF channel is split into blocks of 4 by 4 pixels.  An
     45 //	uncompressed block occupies 32 bytes, which are re-interpreted
     46 //	as sixteen 16-bit unsigned integers, t[0] ... t[15].  Compression
     47 //	shrinks the block to 14 bytes.  The compressed 14-byte block
     48 //	contains
     49 //
     50 //	 - t[0]
     51 //
     52 //	 - a 6-bit shift value
     53 //
     54 //	 - 15 densely packed 6-bit values, r[0] ... r[14], which are
     55 //         computed by subtracting adjacent pixel values and right-
     56 //	   shifting the differences according to the stored shift value.
     57 //
     58 //	   Differences between adjacent pixels are computed according
     59 //	   to the following diagram:
     60 //
     61 //		 0 -------->  1 -------->  2 -------->  3
     62 //               |     3            7           11
     63 //               |
     64 //               | 0
     65 //               |
     66 //               v
     67 //		 4 -------->  5 -------->  6 -------->  7
     68 //               |     4            8           12
     69 //               |
     70 //               | 1
     71 //               |
     72 //               v
     73 //		 8 -------->  9 --------> 10 --------> 11
     74 //               |     5            9           13
     75 //               |
     76 //               | 2
     77 //               |
     78 //               v
     79 //		12 --------> 13 --------> 14 --------> 15
     80 //                     6           10           14
     81 //
     82 //	    Here
     83 //
     84 //               5 ---------> 6
     85 //                     8
     86 //
     87 //	    means that r[8] is the difference between t[5] and t[6].
     88 //
     89 //	 - optionally, a 4-by-4 pixel block where all pixels have the
     90 //	   same value can be treated as a special case, where the
     91 //	   compressed block contains only 3 instead of 14 bytes:
     92 //	   t[0], followed by an "impossible" 6-bit shift value and
     93 //	   two padding bits.
     94 //
     95 //	This compressor can handle positive and negative pixel values.
     96 //	NaNs and infinities are replaced with zeroes before compression.
     97 //
     98 //-----------------------------------------------------------------------------
     99 
    100 #include <ImfB44Compressor.h>
    101 #include <ImfHeader.h>
    102 #include <ImfChannelList.h>
    103 #include <ImfMisc.h>
    104 #include <ImfCheckedArithmetic.h>
    105 #include <ImathFun.h>
    106 #include <ImathBox.h>
    107 #include <Iex.h>
    108 #include <ImfIO.h>
    109 #include <ImfXdr.h>
    110 #include <string.h>
    111 #include <assert.h>
    112 #include <algorithm>
    113 
    114 namespace Imf {
    115 
    116 using Imath::divp;
    117 using Imath::modp;
    118 using Imath::Box2i;
    119 using Imath::V2i;
    120 using std::min;
    121 
    122 namespace {
    123 
    124 //
    125 // Lookup tables for
    126 //	y = exp (x / 8)
    127 // and
    128 //	x = 8 * log (y)
    129 //
    130 
    131 #include "b44ExpLogTable.h"
    132 
    133 
    134 inline void
    135 convertFromLinear (unsigned short s[16])
    136 {
    137     for (int i = 0; i < 16; ++i)
    138     s[i] = expTable[s[i]];
    139 }
    140 
    141 
    142 inline void
    143 convertToLinear (unsigned short s[16])
    144 {
    145     for (int i = 0; i < 16; ++i)
    146     s[i] = logTable[s[i]];
    147 }
    148 
    149 
    150 inline int
    151 shiftAndRound (int x, int shift)
    152 {
    153     //
    154     // Compute
    155     //
    156     //     y = x * pow (2, -shift),
    157     //
    158     // then round y to the nearest integer.
    159     // In case of a tie, where y is exactly
    160     // halfway between two integers, round
    161     // to the even one.
    162     //
    163 
    164     x <<= 1;
    165     int a = (1 << shift) - 1;
    166     shift += 1;
    167     int b = (x >> shift) & 1;
    168     return (x + a + b) >> shift;
    169 }
    170 
    171 
    172 int
    173 pack (const unsigned short s[16],
    174       unsigned char b[14],
    175       bool optFlatFields,
    176       bool exactMax)
    177 {
    178     //
    179     // Pack a block of 4 by 4 16-bit pixels (32 bytes) into
    180     // either 14 or 3 bytes.
    181     //
    182 
    183     //
    184     // Integers s[0] ... s[15] represent floating-point numbers
    185     // in what is essentially a sign-magnitude format.  Convert
    186     // s[0] .. s[15] into a new set of integers, t[0] ... t[15],
    187     // such that if t[i] is greater than t[j], the floating-point
    188     // number that corresponds to s[i] is always greater than
    189     // the floating-point number that corresponds to s[j].
    190     //
    191     // Also, replace any bit patterns that represent NaNs or
    192     // infinities with bit patterns that represent floating-point
    193     // zeroes.
    194     //
    195     //	bit pattern	floating-point		bit pattern
    196     //	in s[i]		value			in t[i]
    197     //
    198     //  0x7fff		NAN			0x8000
    199     //  0x7ffe		NAN			0x8000
    200     //	  ...					  ...
    201     //  0x7c01		NAN			0x8000
    202     //  0x7c00		+infinity		0x8000
    203     //  0x7bff		+HALF_MAX		0xfbff
    204     //  0x7bfe					0xfbfe
    205     //  0x7bfd					0xfbfd
    206     //	  ...					  ...
    207     //  0x0002		+2 * HALF_MIN		0x8002
    208     //  0x0001		+HALF_MIN		0x8001
    209     //  0x0000		+0.0			0x8000
    210     //  0x8000		-0.0			0x7fff
    211     //  0x8001		-HALF_MIN		0x7ffe
    212     //  0x8002		-2 * HALF_MIN		0x7ffd
    213     //	  ...					  ...
    214     //  0xfbfd					0x0f02
    215     //  0xfbfe					0x0401
    216     //  0xfbff		-HALF_MAX		0x0400
    217     //  0xfc00		-infinity		0x8000
    218     //  0xfc01		NAN			0x8000
    219     //	  ...					  ...
    220     //  0xfffe		NAN			0x8000
    221     //  0xffff		NAN			0x8000
    222     //
    223 
    224     unsigned short t[16];
    225 
    226     for (int i = 0; i < 16; ++i)
    227     {
    228     if ((s[i] & 0x7c00) == 0x7c00)
    229         t[i] = 0x8000;
    230     else if (s[i] & 0x8000)
    231         t[i] = ~s[i];
    232     else
    233         t[i] = s[i] | 0x8000;
    234     }
    235 
    236     //
    237     // Find the maximum, tMax, of t[0] ... t[15].
    238     //
    239 
    240     unsigned short tMax = 0;
    241 
    242     for (int i = 0; i < 16; ++i)
    243     if (tMax < t[i])
    244         tMax = t[i];
    245 
    246     //
    247     // Compute a set of running differences, r[0] ... r[14]:
    248     // Find a shift value such that after rounding off the
    249     // rightmost bits and shifting all differenes are between
    250     // -32 and +31.  Then bias the differences so that they
    251     // end up between 0 and 63.
    252     //
    253 
    254     int shift = -1;
    255     int d[16];
    256     int r[15];
    257     int rMin;
    258     int rMax;
    259 
    260     const int bias = 0x20;
    261 
    262     do
    263     {
    264     shift += 1;
    265 
    266     //
    267     // Compute absolute differences, d[0] ... d[15],
    268     // between tMax and t[0] ... t[15].
    269     //
    270     // Shift and round the absolute differences.
    271     //
    272 
    273     for (int i = 0; i < 16; ++i)
    274         d[i] = shiftAndRound (tMax - t[i], shift);
    275 
    276     //
    277     // Convert d[0] .. d[15] into running differences
    278     //
    279 
    280     r[ 0] = d[ 0] - d[ 4] + bias;
    281     r[ 1] = d[ 4] - d[ 8] + bias;
    282     r[ 2] = d[ 8] - d[12] + bias;
    283 
    284     r[ 3] = d[ 0] - d[ 1] + bias;
    285     r[ 4] = d[ 4] - d[ 5] + bias;
    286     r[ 5] = d[ 8] - d[ 9] + bias;
    287     r[ 6] = d[12] - d[13] + bias;
    288 
    289     r[ 7] = d[ 1] - d[ 2] + bias;
    290     r[ 8] = d[ 5] - d[ 6] + bias;
    291     r[ 9] = d[ 9] - d[10] + bias;
    292     r[10] = d[13] - d[14] + bias;
    293 
    294     r[11] = d[ 2] - d[ 3] + bias;
    295     r[12] = d[ 6] - d[ 7] + bias;
    296     r[13] = d[10] - d[11] + bias;
    297     r[14] = d[14] - d[15] + bias;
    298 
    299     rMin = r[0];
    300     rMax = r[0];
    301 
    302     for (int i = 1; i < 15; ++i)
    303     {
    304         if (rMin > r[i])
    305         rMin = r[i];
    306 
    307         if (rMax < r[i])
    308         rMax = r[i];
    309     }
    310     }
    311     while (rMin < 0 || rMax > 0x3f);
    312 
    313     if (rMin == bias && rMax == bias && optFlatFields)
    314     {
    315     //
    316     // Special case - all pixels have the same value.
    317     // We encode this in 3 instead of 14 bytes by
    318     // storing the value 0xfc in the third output byte,
    319     // which cannot occur in the 14-byte encoding.
    320     //
    321 
    322     b[0] = (t[0] >> 8);
    323     b[1] =  t[0];
    324     b[2] = 0xfc;
    325 
    326     return 3;
    327     }
    328 
    329     if (exactMax)
    330     {
    331     //
    332     // Adjust t[0] so that the pixel whose value is equal
    333     // to tMax gets represented as accurately as possible.
    334     //
    335 
    336     t[0] = tMax - (d[0] << shift);
    337     }
    338 
    339     //
    340     // Pack t[0], shift and r[0] ... r[14] into 14 bytes:
    341     //
    342 
    343     b[ 0] = (t[0] >> 8);
    344     b[ 1] =  t[0];
    345 
    346     b[ 2] = (unsigned char) ((shift << 2) | (r[ 0] >> 4));
    347     b[ 3] = (unsigned char) ((r[ 0] << 4) | (r[ 1] >> 2));
    348     b[ 4] = (unsigned char) ((r[ 1] << 6) |  r[ 2]      );
    349 
    350     b[ 5] = (unsigned char) ((r[ 3] << 2) | (r[ 4] >> 4));
    351     b[ 6] = (unsigned char) ((r[ 4] << 4) | (r[ 5] >> 2));
    352     b[ 7] = (unsigned char) ((r[ 5] << 6) |  r[ 6]      );
    353 
    354     b[ 8] = (unsigned char) ((r[ 7] << 2) | (r[ 8] >> 4));
    355     b[ 9] = (unsigned char) ((r[ 8] << 4) | (r[ 9] >> 2));
    356     b[10] = (unsigned char) ((r[ 9] << 6) |  r[10]      );
    357 
    358     b[11] = (unsigned char) ((r[11] << 2) | (r[12] >> 4));
    359     b[12] = (unsigned char) ((r[12] << 4) | (r[13] >> 2));
    360     b[13] = (unsigned char) ((r[13] << 6) |  r[14]      );
    361 
    362     return 14;
    363 }
    364 
    365 
    366 inline
    367 void
    368 unpack14 (const unsigned char b[14], unsigned short s[16])
    369 {
    370     //
    371     // Unpack a 14-byte block into 4 by 4 16-bit pixels.
    372     //
    373 
    374     #if defined (DEBUG)
    375     assert (b[2] != 0xfc);
    376     #endif
    377 
    378     s[ 0] = (b[0] << 8) | b[1];
    379 
    380     unsigned short shift = (b[ 2] >> 2);
    381     unsigned short bias = (0x20 << shift);
    382 
    383     s[ 4] = s[ 0] + ((((b[ 2] << 4) | (b[ 3] >> 4)) & 0x3f) << shift) - bias;
    384     s[ 8] = s[ 4] + ((((b[ 3] << 2) | (b[ 4] >> 6)) & 0x3f) << shift) - bias;
    385     s[12] = s[ 8] +   ((b[ 4]                       & 0x3f) << shift) - bias;
    386 
    387     s[ 1] = s[ 0] +   ((b[ 5] >> 2)                         << shift) - bias;
    388     s[ 5] = s[ 4] + ((((b[ 5] << 4) | (b[ 6] >> 4)) & 0x3f) << shift) - bias;
    389     s[ 9] = s[ 8] + ((((b[ 6] << 2) | (b[ 7] >> 6)) & 0x3f) << shift) - bias;
    390     s[13] = s[12] +   ((b[ 7]                       & 0x3f) << shift) - bias;
    391 
    392     s[ 2] = s[ 1] +   ((b[ 8] >> 2)                         << shift) - bias;
    393     s[ 6] = s[ 5] + ((((b[ 8] << 4) | (b[ 9] >> 4)) & 0x3f) << shift) - bias;
    394     s[10] = s[ 9] + ((((b[ 9] << 2) | (b[10] >> 6)) & 0x3f) << shift) - bias;
    395     s[14] = s[13] +   ((b[10]                       & 0x3f) << shift) - bias;
    396 
    397     s[ 3] = s[ 2] +   ((b[11] >> 2)                         << shift) - bias;
    398     s[ 7] = s[ 6] + ((((b[11] << 4) | (b[12] >> 4)) & 0x3f) << shift) - bias;
    399     s[11] = s[10] + ((((b[12] << 2) | (b[13] >> 6)) & 0x3f) << shift) - bias;
    400     s[15] = s[14] +   ((b[13]                       & 0x3f) << shift) - bias;
    401 
    402     for (int i = 0; i < 16; ++i)
    403     {
    404     if (s[i] & 0x8000)
    405         s[i] &= 0x7fff;
    406     else
    407         s[i] = ~s[i];
    408     }
    409 }
    410 
    411 
    412 inline
    413 void
    414 unpack3 (const unsigned char b[3], unsigned short s[16])
    415 {
    416     //
    417     // Unpack a 3-byte block into 4 by 4 identical 16-bit pixels.
    418     //
    419 
    420     #if defined (DEBUG)
    421     assert (b[2] == 0xfc);
    422     #endif
    423 
    424     s[0] = (b[0] << 8) | b[1];
    425 
    426     if (s[0] & 0x8000)
    427     s[0] &= 0x7fff;
    428     else
    429     s[0] = ~s[0];
    430 
    431     for (int i = 1; i < 16; ++i)
    432     s[i] = s[0];
    433 }
    434 
    435 
    436 void
    437 notEnoughData ()
    438 {
    439     throw Iex::InputExc ("Error decompressing data "
    440              "(input data are shorter than expected).");
    441 }
    442 
    443 
    444 void
    445 tooMuchData ()
    446 {
    447     throw Iex::InputExc ("Error decompressing data "
    448              "(input data are longer than expected).");
    449 }
    450 
    451 } // namespace
    452 
    453 
    454 struct B44Compressor::ChannelData
    455 {
    456     unsigned short *	start;
    457     unsigned short *	end;
    458     int			nx;
    459     int			ny;
    460     int			ys;
    461     PixelType		type;
    462     bool		pLinear;
    463     int			size;
    464 };
    465 
    466 
    467 B44Compressor::B44Compressor
    468     (const Header &hdr,
    469      size_t maxScanLineSize,
    470      size_t numScanLines,
    471      bool optFlatFields)
    472 :
    473     Compressor (hdr),
    474     _maxScanLineSize (maxScanLineSize),
    475     _optFlatFields (optFlatFields),
    476     _format (XDR),
    477     _numScanLines (numScanLines),
    478     _tmpBuffer (0),
    479     _outBuffer (0),
    480     _numChans (0),
    481     _channels (hdr.channels()),
    482     _channelData (0)
    483 {
    484     //
    485     // Allocate buffers for compressed an uncompressed pixel data,
    486     // allocate a set of ChannelData structs to help speed up the
    487     // compress() and uncompress() functions, below, and determine
    488     // if uncompressed pixel data should be in native or Xdr format.
    489     //
    490 
    491     _tmpBuffer = new unsigned short
    492         [checkArraySize (uiMult (maxScanLineSize, numScanLines),
    493                          sizeof (unsigned short))];
    494 
    495     const ChannelList &channels = header().channels();
    496     int numHalfChans = 0;
    497 
    498     for (ChannelList::ConstIterator c = channels.begin();
    499      c != channels.end();
    500      ++c)
    501     {
    502     assert (pixelTypeSize (c.channel().type) % pixelTypeSize (HALF) == 0);
    503     ++_numChans;
    504 
    505     if (c.channel().type == HALF)
    506         ++numHalfChans;
    507     }
    508 
    509     //
    510     // Compressed data may be larger than the input data
    511     //
    512 
    513     size_t padding = 12 * numHalfChans * (numScanLines + 3) / 4;
    514 
    515     _outBuffer = new char
    516         [uiAdd (uiMult (maxScanLineSize, numScanLines), padding)];
    517 
    518     _channelData = new ChannelData[_numChans];
    519 
    520     int i = 0;
    521 
    522     for (ChannelList::ConstIterator c = channels.begin();
    523      c != channels.end();
    524      ++c, ++i)
    525     {
    526     _channelData[i].ys = c.channel().ySampling;
    527     _channelData[i].type = c.channel().type;
    528     _channelData[i].pLinear = c.channel().pLinear;
    529     _channelData[i].size =
    530         pixelTypeSize (c.channel().type) / pixelTypeSize (HALF);
    531     }
    532 
    533     const Box2i &dataWindow = hdr.dataWindow();
    534 
    535     _minX = dataWindow.min.x;
    536     _maxX = dataWindow.max.x;
    537     _maxY = dataWindow.max.y;
    538 
    539     //
    540     // We can support uncompressed data in the machine's native
    541     // format only if all image channels are of type HALF.
    542     //
    543 
    544     assert (sizeof (unsigned short) == pixelTypeSize (HALF));
    545 
    546     if (_numChans == numHalfChans)
    547     _format = NATIVE;
    548 }
    549 
    550 
    551 B44Compressor::~B44Compressor ()
    552 {
    553     delete [] _tmpBuffer;
    554     delete [] _outBuffer;
    555     delete [] _channelData;
    556 }
    557 
    558 
    559 int
    560 B44Compressor::numScanLines () const
    561 {
    562     return _numScanLines;
    563 }
    564 
    565 
    566 Compressor::Format
    567 B44Compressor::format () const
    568 {
    569     return _format;
    570 }
    571 
    572 
    573 int
    574 B44Compressor::compress (const char *inPtr,
    575              int inSize,
    576              int minY,
    577              const char *&outPtr)
    578 {
    579     return compress (inPtr,
    580              inSize,
    581              Box2i (V2i (_minX, minY),
    582                 V2i (_maxX, minY + numScanLines() - 1)),
    583              outPtr);
    584 }
    585 
    586 
    587 int
    588 B44Compressor::compressTile (const char *inPtr,
    589                  int inSize,
    590                  Imath::Box2i range,
    591                  const char *&outPtr)
    592 {
    593     return compress (inPtr, inSize, range, outPtr);
    594 }
    595 
    596 
    597 int
    598 B44Compressor::uncompress (const char *inPtr,
    599                int inSize,
    600                int minY,
    601                const char *&outPtr)
    602 {
    603     return uncompress (inPtr,
    604                inSize,
    605                Box2i (V2i (_minX, minY),
    606                   V2i (_maxX, minY + numScanLines() - 1)),
    607                outPtr);
    608 }
    609 
    610 
    611 int
    612 B44Compressor::uncompressTile (const char *inPtr,
    613                    int inSize,
    614                    Imath::Box2i range,
    615                    const char *&outPtr)
    616 {
    617     return uncompress (inPtr, inSize, range, outPtr);
    618 }
    619 
    620 
    621 int
    622 B44Compressor::compress (const char *inPtr,
    623              int inSize,
    624              Imath::Box2i range,
    625              const char *&outPtr)
    626 {
    627     //
    628     // Compress a block of pixel data:  First copy the input pixels
    629     // from the input buffer into _tmpBuffer, rearranging them such
    630     // that blocks of 4x4 pixels of a single channel can be accessed
    631     // conveniently.  Then compress each 4x4 block of HALF pixel data
    632     // and append the result to the output buffer.  Copy UINT and
    633     // FLOAT data to the output buffer without compressing them.
    634     //
    635 
    636     outPtr = _outBuffer;
    637 
    638     if (inSize == 0)
    639     {
    640     //
    641     // Special case - empty input buffer.
    642     //
    643 
    644     return 0;
    645     }
    646 
    647     //
    648     // For each channel, detemine how many pixels are stored
    649     // in the input buffer, and where those pixels will be
    650     // placed in _tmpBuffer.
    651     //
    652 
    653     int minX = range.min.x;
    654     int maxX = min (range.max.x, _maxX);
    655     int minY = range.min.y;
    656     int maxY = min (range.max.y, _maxY);
    657 
    658     unsigned short *tmpBufferEnd = _tmpBuffer;
    659     int i = 0;
    660 
    661     for (ChannelList::ConstIterator c = _channels.begin();
    662      c != _channels.end();
    663      ++c, ++i)
    664     {
    665     ChannelData &cd = _channelData[i];
    666 
    667     cd.start = tmpBufferEnd;
    668     cd.end = cd.start;
    669 
    670     cd.nx = numSamples (c.channel().xSampling, minX, maxX);
    671     cd.ny = numSamples (c.channel().ySampling, minY, maxY);
    672 
    673     tmpBufferEnd += cd.nx * cd.ny * cd.size;
    674     }
    675 
    676     if (_format == XDR)
    677     {
    678     //
    679     // The data in the input buffer are in the machine-independent
    680     // Xdr format.  Copy the HALF channels into _tmpBuffer and
    681     // convert them back into native format for compression.
    682     // Copy UINT and FLOAT channels verbatim into _tmpBuffer.
    683     //
    684 
    685     for (int y = minY; y <= maxY; ++y)
    686     {
    687         for (int i = 0; i < _numChans; ++i)
    688         {
    689         ChannelData &cd = _channelData[i];
    690 
    691         if (modp (y, cd.ys) != 0)
    692             continue;
    693 
    694         if (cd.type == HALF)
    695         {
    696             for (int x = cd.nx; x > 0; --x)
    697             {
    698             Xdr::read <CharPtrIO> (inPtr, *cd.end);
    699             ++cd.end;
    700             }
    701         }
    702         else
    703         {
    704             int n = cd.nx * cd.size;
    705             memcpy (cd.end, inPtr, n * sizeof (unsigned short));
    706             inPtr += n * sizeof (unsigned short);
    707             cd.end += n;
    708         }
    709         }
    710     }
    711     }
    712     else
    713     {
    714     //
    715     // The input buffer contains only HALF channels, and they
    716     // are in native, machine-dependent format.  Copy the pixels
    717     // into _tmpBuffer.
    718     //
    719 
    720     for (int y = minY; y <= maxY; ++y)
    721     {
    722         for (int i = 0; i < _numChans; ++i)
    723         {
    724         ChannelData &cd = _channelData[i];
    725 
    726         #if defined (DEBUG)
    727             assert (cd.type == HALF);
    728         #endif
    729 
    730         if (modp (y, cd.ys) != 0)
    731             continue;
    732 
    733         int n = cd.nx * cd.size;
    734         memcpy (cd.end, inPtr, n * sizeof (unsigned short));
    735         inPtr  += n * sizeof (unsigned short);
    736         cd.end += n;
    737         }
    738     }
    739     }
    740 
    741     //
    742     // The pixels for each channel have been packed into a contiguous
    743     // block in _tmpBuffer.  HALF channels are in native format; UINT
    744     // and FLOAT channels are in Xdr format.
    745     //
    746 
    747     #if defined (DEBUG)
    748 
    749     for (int i = 1; i < _numChans; ++i)
    750         assert (_channelData[i-1].end == _channelData[i].start);
    751 
    752     assert (_channelData[_numChans-1].end == tmpBufferEnd);
    753 
    754     #endif
    755 
    756     //
    757     // For each HALF channel, split the data in _tmpBuffer into 4x4
    758     // pixel blocks.  Compress each block and append the compressed
    759     // data to the output buffer.
    760     //
    761     // UINT and FLOAT channels are copied from _tmpBuffer into the
    762     // output buffer without further processing.
    763     //
    764 
    765     char *outEnd = _outBuffer;
    766 
    767     for (int i = 0; i < _numChans; ++i)
    768     {
    769     ChannelData &cd = _channelData[i];
    770 
    771     if (cd.type != HALF)
    772     {
    773         //
    774         // UINT or FLOAT channel.
    775         //
    776 
    777         int n = cd.nx * cd.ny * cd.size * sizeof (unsigned short);
    778         memcpy (outEnd, cd.start, n);
    779         outEnd += n;
    780 
    781         continue;
    782     }
    783 
    784     //
    785     // HALF channel
    786     //
    787 
    788     for (int y = 0; y < cd.ny; y += 4)
    789     {
    790         //
    791         // Copy the next 4x4 pixel block into array s.
    792         // If the width, cd.nx, or the height, cd.ny, of
    793         // the pixel data in _tmpBuffer is not divisible
    794         // by 4, then pad the data by repeating the
    795         // rightmost column and the bottom row.
    796         //
    797 
    798         unsigned short *row0 = cd.start + y * cd.nx;
    799         unsigned short *row1 = row0 + cd.nx;
    800         unsigned short *row2 = row1 + cd.nx;
    801         unsigned short *row3 = row2 + cd.nx;
    802 
    803         if (y + 3 >= cd.ny)
    804         {
    805         if (y + 1 >= cd.ny)
    806             row1 = row0;
    807 
    808         if (y + 2 >= cd.ny)
    809             row2 = row1;
    810 
    811         row3 = row2;
    812         }
    813 
    814         for (int x = 0; x < cd.nx; x += 4)
    815         {
    816         unsigned short s[16];
    817 
    818         if (x + 3 >= cd.nx)
    819         {
    820             int n = cd.nx - x;
    821 
    822             for (int i = 0; i < 4; ++i)
    823             {
    824             int j = min (i, n - 1);
    825 
    826             s[i +  0] = row0[j];
    827             s[i +  4] = row1[j];
    828             s[i +  8] = row2[j];
    829             s[i + 12] = row3[j];
    830             }
    831         }
    832         else
    833         {
    834             memcpy (&s[ 0], row0, 4 * sizeof (unsigned short));
    835             memcpy (&s[ 4], row1, 4 * sizeof (unsigned short));
    836             memcpy (&s[ 8], row2, 4 * sizeof (unsigned short));
    837             memcpy (&s[12], row3, 4 * sizeof (unsigned short));
    838         }
    839 
    840         row0 += 4;
    841         row1 += 4;
    842         row2 += 4;
    843         row3 += 4;
    844 
    845         //
    846         // Compress the contents of array s and append the
    847         // results to the output buffer.
    848         //
    849 
    850         if (cd.pLinear)
    851             convertFromLinear (s);
    852 
    853         outEnd += pack (s, (unsigned char *) outEnd,
    854                 _optFlatFields, !cd.pLinear);
    855         }
    856     }
    857     }
    858 
    859     return outEnd - _outBuffer;
    860 }
    861 
    862 
    863 int
    864 B44Compressor::uncompress (const char *inPtr,
    865                int inSize,
    866                Imath::Box2i range,
    867                const char *&outPtr)
    868 {
    869     //
    870     // This function is the reverse of the compress() function,
    871     // above.  First all pixels are moved from the input buffer
    872     // into _tmpBuffer.  UINT and FLOAT channels are copied
    873     // verbatim; HALF channels are uncompressed in blocks of
    874     // 4x4 pixels.  Then the pixels in _tmpBuffer are copied
    875     // into the output buffer and rearranged such that the data
    876     // for for each scan line form a contiguous block.
    877     //
    878 
    879     outPtr = _outBuffer;
    880 
    881     if (inSize == 0)
    882     {
    883     return 0;
    884     }
    885 
    886     int minX = range.min.x;
    887     int maxX = min (range.max.x, _maxX);
    888     int minY = range.min.y;
    889     int maxY = min (range.max.y, _maxY);
    890 
    891     unsigned short *tmpBufferEnd = _tmpBuffer;
    892     int i = 0;
    893 
    894     for (ChannelList::ConstIterator c = _channels.begin();
    895      c != _channels.end();
    896      ++c, ++i)
    897     {
    898     ChannelData &cd = _channelData[i];
    899 
    900     cd.start = tmpBufferEnd;
    901     cd.end = cd.start;
    902 
    903     cd.nx = numSamples (c.channel().xSampling, minX, maxX);
    904     cd.ny = numSamples (c.channel().ySampling, minY, maxY);
    905 
    906     tmpBufferEnd += cd.nx * cd.ny * cd.size;
    907     }
    908 
    909     for (int i = 0; i < _numChans; ++i)
    910     {
    911     ChannelData &cd = _channelData[i];
    912 
    913     if (cd.type != HALF)
    914     {
    915         //
    916         // UINT or FLOAT channel.
    917         //
    918 
    919         int n = cd.nx * cd.ny * cd.size * sizeof (unsigned short);
    920 
    921         if (inSize < n)
    922         notEnoughData();
    923 
    924         memcpy (cd.start, inPtr, n);
    925         inPtr += n;
    926         inSize -= n;
    927 
    928         continue;
    929     }
    930 
    931     //
    932     // HALF channel
    933     //
    934 
    935     for (int y = 0; y < cd.ny; y += 4)
    936     {
    937         unsigned short *row0 = cd.start + y * cd.nx;
    938         unsigned short *row1 = row0 + cd.nx;
    939         unsigned short *row2 = row1 + cd.nx;
    940         unsigned short *row3 = row2 + cd.nx;
    941 
    942         for (int x = 0; x < cd.nx; x += 4)
    943         {
    944         unsigned short s[16];
    945 
    946         if (inSize < 3)
    947             notEnoughData();
    948 
    949         if (((const unsigned char *)inPtr)[2] == 0xfc)
    950         {
    951             unpack3 ((const unsigned char *)inPtr, s);
    952             inPtr += 3;
    953             inSize -= 3;
    954         }
    955         else
    956         {
    957             if (inSize < 14)
    958             notEnoughData();
    959 
    960             unpack14 ((const unsigned char *)inPtr, s);
    961             inPtr += 14;
    962             inSize -= 14;
    963         }
    964 
    965         if (cd.pLinear)
    966             convertToLinear (s);
    967 
    968         int n = (x + 3 < cd.nx)?
    969                 4 * sizeof (unsigned short) :
    970                 (cd.nx - x) * sizeof (unsigned short);
    971 
    972         if (y + 3 < cd.ny)
    973         {
    974             memcpy (row0, &s[ 0], n);
    975             memcpy (row1, &s[ 4], n);
    976             memcpy (row2, &s[ 8], n);
    977             memcpy (row3, &s[12], n);
    978         }
    979         else
    980         {
    981             memcpy (row0, &s[ 0], n);
    982 
    983             if (y + 1 < cd.ny)
    984             memcpy (row1, &s[ 4], n);
    985 
    986             if (y + 2 < cd.ny)
    987             memcpy (row2, &s[ 8], n);
    988         }
    989 
    990         row0 += 4;
    991         row1 += 4;
    992         row2 += 4;
    993         row3 += 4;
    994         }
    995     }
    996     }
    997 
    998     char *outEnd = _outBuffer;
    999 
   1000     if (_format == XDR)
   1001     {
   1002     for (int y = minY; y <= maxY; ++y)
   1003     {
   1004         for (int i = 0; i < _numChans; ++i)
   1005         {
   1006         ChannelData &cd = _channelData[i];
   1007 
   1008         if (modp (y, cd.ys) != 0)
   1009             continue;
   1010 
   1011         if (cd.type == HALF)
   1012         {
   1013             for (int x = cd.nx; x > 0; --x)
   1014             {
   1015             Xdr::write <CharPtrIO> (outEnd, *cd.end);
   1016             ++cd.end;
   1017             }
   1018         }
   1019         else
   1020         {
   1021             int n = cd.nx * cd.size;
   1022             memcpy (outEnd, cd.end, n * sizeof (unsigned short));
   1023             outEnd += n * sizeof (unsigned short);
   1024             cd.end += n;
   1025         }
   1026         }
   1027     }
   1028     }
   1029     else
   1030     {
   1031     for (int y = minY; y <= maxY; ++y)
   1032     {
   1033         for (int i = 0; i < _numChans; ++i)
   1034         {
   1035         ChannelData &cd = _channelData[i];
   1036 
   1037         #if defined (DEBUG)
   1038             assert (cd.type == HALF);
   1039         #endif
   1040 
   1041         if (modp (y, cd.ys) != 0)
   1042             continue;
   1043 
   1044         int n = cd.nx * cd.size;
   1045         memcpy (outEnd, cd.end, n * sizeof (unsigned short));
   1046         outEnd += n * sizeof (unsigned short);
   1047         cd.end += n;
   1048         }
   1049     }
   1050     }
   1051 
   1052     #if defined (DEBUG)
   1053 
   1054     for (int i = 1; i < _numChans; ++i)
   1055         assert (_channelData[i-1].end == _channelData[i].start);
   1056 
   1057     assert (_channelData[_numChans-1].end == tmpBufferEnd);
   1058 
   1059     #endif
   1060 
   1061     if (inSize > 0)
   1062     tooMuchData();
   1063 
   1064     outPtr = _outBuffer;
   1065     return outEnd - _outBuffer;
   1066 }
   1067 
   1068 
   1069 } // namespace Imf
   1070