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