Home | History | Annotate | Download | only in IlmImf
      1 ///////////////////////////////////////////////////////////////////////////
      2 //
      3 // Copyright (c) 2002, 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 //
     39 //	class RleCompressor
     40 //
     41 //-----------------------------------------------------------------------------
     42 
     43 #include <ImfRleCompressor.h>
     44 #include <ImfCheckedArithmetic.h>
     45 #include "Iex.h"
     46 
     47 namespace Imf {
     48 namespace {
     49 
     50 const int MIN_RUN_LENGTH = 3;
     51 const int MAX_RUN_LENGTH = 127;
     52 
     53 
     54 //
     55 // Compress an array of bytes, using run-length encoding,
     56 // and return the length of the compressed data.
     57 //
     58 
     59 int
     60 rleCompress (int inLength, const char in[], signed char out[])
     61 {
     62     const char *inEnd = in + inLength;
     63     const char *runStart = in;
     64     const char *runEnd = in + 1;
     65     signed char *outWrite = out;
     66 
     67     while (runStart < inEnd)
     68     {
     69     while (runEnd < inEnd &&
     70            *runStart == *runEnd &&
     71            runEnd - runStart - 1 < MAX_RUN_LENGTH)
     72     {
     73         ++runEnd;
     74     }
     75 
     76     if (runEnd - runStart >= MIN_RUN_LENGTH)
     77     {
     78         //
     79         // Compressable run
     80         //
     81 
     82         *outWrite++ = (runEnd - runStart) - 1;
     83         *outWrite++ = *(signed char *) runStart;
     84         runStart = runEnd;
     85     }
     86     else
     87     {
     88         //
     89         // Uncompressable run
     90         //
     91 
     92         while (runEnd < inEnd &&
     93            ((runEnd + 1 >= inEnd ||
     94              *runEnd != *(runEnd + 1)) ||
     95             (runEnd + 2 >= inEnd ||
     96              *(runEnd + 1) != *(runEnd + 2))) &&
     97            runEnd - runStart < MAX_RUN_LENGTH)
     98         {
     99         ++runEnd;
    100         }
    101 
    102         *outWrite++ = runStart - runEnd;
    103 
    104         while (runStart < runEnd)
    105         {
    106         *outWrite++ = *(signed char *) (runStart++);
    107         }
    108     }
    109 
    110     ++runEnd;
    111     }
    112 
    113     return outWrite - out;
    114 }
    115 
    116 
    117 //
    118 // Uncompress an array of bytes compressed with rleCompress().
    119 // Returns the length of the oncompressed data, or 0 if the
    120 // length of the uncompressed data would be more than maxLength.
    121 //
    122 
    123 int
    124 rleUncompress (int inLength, int maxLength, const signed char in[], char out[])
    125 {
    126     char *outStart = out;
    127 
    128     while (inLength > 0)
    129     {
    130     if (*in < 0)
    131     {
    132         int count = -((int)*in++);
    133         inLength -= count + 1;
    134 
    135         if (0 > (maxLength -= count))
    136         return 0;
    137 
    138         while (count-- > 0)
    139         *out++ = *(char *) (in++);
    140     }
    141     else
    142     {
    143         int count = *in++;
    144         inLength -= 2;
    145 
    146         if (0 > (maxLength -= count + 1))
    147         return 0;
    148 
    149         while (count-- >= 0)
    150         *out++ = *(char *) in;
    151 
    152         in++;
    153     }
    154     }
    155 
    156     return out - outStart;
    157 }
    158 
    159 } // namespace
    160 
    161 
    162 RleCompressor::RleCompressor (const Header &hdr, size_t maxScanLineSize):
    163     Compressor (hdr),
    164     _maxScanLineSize (maxScanLineSize),
    165     _tmpBuffer (0),
    166     _outBuffer (0)
    167 {
    168     _tmpBuffer = new char [maxScanLineSize];
    169     _outBuffer = new char [uiMult (maxScanLineSize, size_t (3)) / 2];
    170 }
    171 
    172 
    173 RleCompressor::~RleCompressor ()
    174 {
    175     delete [] _tmpBuffer;
    176     delete [] _outBuffer;
    177 }
    178 
    179 
    180 int
    181 RleCompressor::numScanLines () const
    182 {
    183     //
    184     // This compressor compresses individual scan lines.
    185     //
    186 
    187     return 1;
    188 }
    189 
    190 
    191 int
    192 RleCompressor::compress (const char *inPtr,
    193              int inSize,
    194              int /*minY*/,
    195              const char *&outPtr)
    196 {
    197     //
    198     // Special case - empty input buffer
    199     //
    200 
    201     if (inSize == 0)
    202     {
    203     outPtr = _outBuffer;
    204     return 0;
    205     }
    206 
    207     //
    208     // Reorder the pixel data.
    209     //
    210 
    211     {
    212     char *t1 = _tmpBuffer;
    213     char *t2 = _tmpBuffer + (inSize + 1) / 2;
    214     const char *stop = inPtr + inSize;
    215 
    216     while (true)
    217     {
    218         if (inPtr < stop)
    219         *(t1++) = *(inPtr++);
    220         else
    221         break;
    222 
    223         if (inPtr < stop)
    224         *(t2++) = *(inPtr++);
    225         else
    226         break;
    227     }
    228     }
    229 
    230     //
    231     // Predictor.
    232     //
    233 
    234     {
    235     unsigned char *t = (unsigned char *) _tmpBuffer + 1;
    236     unsigned char *stop = (unsigned char *) _tmpBuffer + inSize;
    237     int p = t[-1];
    238 
    239     while (t < stop)
    240     {
    241         int d = int (t[0]) - p + (128 + 256);
    242         p = t[0];
    243         t[0] = d;
    244         ++t;
    245     }
    246     }
    247 
    248     //
    249     // Run-length encode the data.
    250     //
    251 
    252     outPtr = _outBuffer;
    253     return rleCompress (inSize, _tmpBuffer, (signed char *) _outBuffer);
    254 }
    255 
    256 
    257 int
    258 RleCompressor::uncompress (const char *inPtr,
    259                int inSize,
    260                int /*minY*/,
    261                const char *&outPtr)
    262 {
    263     //
    264     // Special case - empty input buffer
    265     //
    266 
    267     if (inSize == 0)
    268     {
    269     outPtr = _outBuffer;
    270     return 0;
    271     }
    272 
    273     //
    274     // Decode the run-length encoded data
    275     //
    276 
    277     int outSize;
    278 
    279     if (0 == (outSize = rleUncompress (inSize, _maxScanLineSize,
    280                        (const signed char *) inPtr,
    281                        _tmpBuffer)))
    282     {
    283     throw Iex::InputExc ("Data decoding (rle) failed.");
    284     }
    285 
    286     //
    287     // Predictor.
    288     //
    289 
    290     {
    291     unsigned char *t = (unsigned char *) _tmpBuffer + 1;
    292     unsigned char *stop = (unsigned char *) _tmpBuffer + outSize;
    293 
    294     while (t < stop)
    295     {
    296         int d = int (t[-1]) + int (t[0]) - 128;
    297         t[0] = d;
    298         ++t;
    299     }
    300     }
    301 
    302     //
    303     // Reorder the pixel data.
    304     //
    305 
    306     {
    307     const char *t1 = _tmpBuffer;
    308     const char *t2 = _tmpBuffer + (outSize + 1) / 2;
    309     char *s = _outBuffer;
    310     char *stop = s + outSize;
    311 
    312     while (true)
    313     {
    314         if (s < stop)
    315         *(s++) = *(t1++);
    316         else
    317         break;
    318 
    319         if (s < stop)
    320         *(s++) = *(t2++);
    321         else
    322         break;
    323     }
    324     }
    325 
    326     outPtr = _outBuffer;
    327     return outSize;
    328 }
    329 
    330 
    331 } // namespace Imf
    332