1///////////////////////////////////////////////////////////////////////////// 2// 3// Copyright (c) 2004, Pixar Animation Studios 4// 5// All rights reserved. 6// 7// Redistribution and use in source and binary forms, with or without 8// modification, are permitted provided that the following conditions are 9// met: 10// * Redistributions of source code must retain the above copyright 11// notice, this list of conditions and the following disclaimer. 12// * Redistributions in binary form must reproduce the above 13// copyright notice, this list of conditions and the following disclaimer 14// in the documentation and/or other materials provided with the 15// distribution. 16// * Neither the name of Pixar Animation Studios nor the names of 17// its contributors may be used to endorse or promote products derived 18// from this software without specific prior written permission. 19// 20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31// 32///////////////////////////////////////////////////////////////////////////// 33 34//----------------------------------------------------------------------------- 35// 36// class Pxr24Compressor 37// 38// This compressor is based on source code that was contributed to 39// OpenEXR by Pixar Animation Studios. The compression method was 40// developed by Loren Carpenter. 41// 42// The compressor preprocesses the pixel data to reduce entropy, 43// and then calls zlib. 44// 45// Compression of HALF and UINT channels is lossless, but compressing 46// FLOAT channels is lossy: 32-bit floating-point numbers are converted 47// to 24 bits by rounding the significand to 15 bits. 48// 49// When the compressor is invoked, the caller has already arranged 50// the pixel data so that the values for each channel appear in a 51// contiguous block of memory. The compressor converts the pixel 52// values to unsigned integers: For UINT, this is a no-op. HALF 53// values are simply re-interpreted as 16-bit integers. FLOAT 54// values are converted to 24 bits, and the resulting bit patterns 55// are interpreted as integers. The compressor then replaces each 56// value with the difference between the value and its left neighbor. 57// This turns flat fields in the image into zeroes, and ramps into 58// strings of similar values. Next, each difference is split into 59// 2, 3 or 4 bytes, and the bytes are transposed so that all the 60// most significant bytes end up in a contiguous block, followed 61// by the second most significant bytes, and so on. The resulting 62// string of bytes is compressed with zlib. 63// 64//----------------------------------------------------------------------------- 65 66#include <ImfPxr24Compressor.h> 67#include <ImfHeader.h> 68#include <ImfChannelList.h> 69#include <ImfMisc.h> 70#include <ImathFun.h> 71#include <Iex.h> 72#include <half.h> 73#include <zlib.h> 74#include <assert.h> 75#include <algorithm> 76 77using namespace std; 78using namespace Imath; 79 80namespace Imf { 81namespace { 82 83// 84// Conversion from 32-bit to 24-bit floating-point numbers. 85// Conversion back to 32 bits is simply an 8-bit shift to the left. 86// 87 88inline unsigned int 89floatToFloat24 (float f) 90{ 91 union 92 { 93 float f; 94 unsigned int i; 95 } u; 96 97 u.f = f; 98 99 // 100 // Disassemble the 32-bit floating point number, f, 101 // into sign, s, exponent, e, and significand, m. 102 // 103 104 unsigned int s = u.i & 0x80000000; 105 unsigned int e = u.i & 0x7f800000; 106 unsigned int m = u.i & 0x007fffff; 107 unsigned int i; 108 109 if (e == 0x7f800000) 110 { 111 if (m) 112 { 113 // 114 // F is a NAN; we preserve the sign bit and 115 // the 15 leftmost bits of the significand, 116 // with one exception: If the 15 leftmost 117 // bits are all zero, the NAN would turn 118 // into an infinity, so we have to set at 119 // least one bit in the significand. 120 // 121 122 m >>= 8; 123 i = (e >> 8) | m | (m == 0); 124 } 125 else 126 { 127 // 128 // F is an infinity. 129 // 130 131 i = e >> 8; 132 } 133 } 134 else 135 { 136 // 137 // F is finite, round the significand to 15 bits. 138 // 139 140 i = ((e | m) + (m & 0x00000080)) >> 8; 141 142 if (i >= 0x7f8000) 143 { 144 // 145 // F was close to FLT_MAX, and the significand was 146 // rounded up, resulting in an exponent overflow. 147 // Avoid the overflow by truncating the significand 148 // instead of rounding it. 149 // 150 151 i = (e | m) >> 8; 152 } 153 } 154 155 return (s >> 8) | i; 156} 157 158 159void 160notEnoughData () 161{ 162 throw Iex::InputExc ("Error decompressing data " 163 "(input data are shorter than expected)."); 164} 165 166 167void 168tooMuchData () 169{ 170 throw Iex::InputExc ("Error decompressing data " 171 "(input data are longer than expected)."); 172} 173 174} // namespace 175 176 177Pxr24Compressor::Pxr24Compressor (const Header &hdr, 178 int maxScanLineSize, 179 int numScanLines) 180: 181 Compressor (hdr), 182 _maxScanLineSize (maxScanLineSize), 183 _numScanLines (numScanLines), 184 _tmpBuffer (0), 185 _outBuffer (0), 186 _channels (hdr.channels()) 187{ 188 int maxInBytes = maxScanLineSize * numScanLines; 189 190 _tmpBuffer = new unsigned char [maxInBytes]; 191 _outBuffer = new char [int (ceil (maxInBytes * 1.01)) + 100]; 192 193 const Box2i &dataWindow = hdr.dataWindow(); 194 195 _minX = dataWindow.min.x; 196 _maxX = dataWindow.max.x; 197 _maxY = dataWindow.max.y; 198} 199 200 201Pxr24Compressor::~Pxr24Compressor () 202{ 203 delete [] _tmpBuffer; 204 delete [] _outBuffer; 205} 206 207 208int 209Pxr24Compressor::numScanLines () const 210{ 211 return _numScanLines; 212} 213 214 215Compressor::Format 216Pxr24Compressor::format () const 217{ 218 return NATIVE; 219} 220 221 222int 223Pxr24Compressor::compress (const char *inPtr, 224 int inSize, 225 int minY, 226 const char *&outPtr) 227{ 228 return compress (inPtr, 229 inSize, 230 Box2i (V2i (_minX, minY), 231 V2i (_maxX, minY + _numScanLines - 1)), 232 outPtr); 233} 234 235 236int 237Pxr24Compressor::compressTile (const char *inPtr, 238 int inSize, 239 Box2i range, 240 const char *&outPtr) 241{ 242 return compress (inPtr, inSize, range, outPtr); 243} 244 245 246int 247Pxr24Compressor::uncompress (const char *inPtr, 248 int inSize, 249 int minY, 250 const char *&outPtr) 251{ 252 return uncompress (inPtr, 253 inSize, 254 Box2i (V2i (_minX, minY), 255 V2i (_maxX, minY + _numScanLines - 1)), 256 outPtr); 257} 258 259 260int 261Pxr24Compressor::uncompressTile (const char *inPtr, 262 int inSize, 263 Box2i range, 264 const char *&outPtr) 265{ 266 return uncompress (inPtr, inSize, range, outPtr); 267} 268 269 270int 271Pxr24Compressor::compress (const char *inPtr, 272 int inSize, 273 Box2i range, 274 const char *&outPtr) 275{ 276 if (inSize == 0) 277 { 278 outPtr = _outBuffer; 279 return 0; 280 } 281 282 int minX = range.min.x; 283 int maxX = min (range.max.x, _maxX); 284 int minY = range.min.y; 285 int maxY = min (range.max.y, _maxY); 286 287 unsigned char *tmpBufferEnd = _tmpBuffer; 288 289 for (int y = minY; y <= maxY; ++y) 290 { 291 for (ChannelList::ConstIterator i = _channels.begin(); 292 i != _channels.end(); 293 ++i) 294 { 295 const Channel &c = i.channel(); 296 297 if (modp (y, c.ySampling) != 0) 298 continue; 299 300 int n = numSamples (c.xSampling, minX, maxX); 301 302 unsigned char *ptr[4]; 303 unsigned int previousPixel = 0; 304 305 switch (c.type) 306 { 307 case UINT: 308 309 ptr[0] = tmpBufferEnd; 310 ptr[1] = ptr[0] + n; 311 ptr[2] = ptr[1] + n; 312 ptr[3] = ptr[2] + n; 313 tmpBufferEnd = ptr[3] + n; 314 315 for (int j = 0; j < n; ++j) 316 { 317 unsigned int pixel; 318 char *pPtr = (char *) &pixel; 319 320 for (int k = 0; k < sizeof (pixel); ++k) 321 *pPtr++ = *inPtr++; 322 323 unsigned int diff = pixel - previousPixel; 324 previousPixel = pixel; 325 326 *(ptr[0]++) = diff >> 24; 327 *(ptr[1]++) = diff >> 16; 328 *(ptr[2]++) = diff >> 8; 329 *(ptr[3]++) = diff; 330 } 331 332 break; 333 334 case HALF: 335 336 ptr[0] = tmpBufferEnd; 337 ptr[1] = ptr[0] + n; 338 tmpBufferEnd = ptr[1] + n; 339 340 for (int j = 0; j < n; ++j) 341 { 342 half pixel; 343 344 pixel = *(const half *) inPtr; 345 inPtr += sizeof (half); 346 347 unsigned int diff = pixel.bits() - previousPixel; 348 previousPixel = pixel.bits(); 349 350 *(ptr[0]++) = diff >> 8; 351 *(ptr[1]++) = diff; 352 } 353 354 break; 355 356 case FLOAT: 357 358 ptr[0] = tmpBufferEnd; 359 ptr[1] = ptr[0] + n; 360 ptr[2] = ptr[1] + n; 361 tmpBufferEnd = ptr[2] + n; 362 363 for (int j = 0; j < n; ++j) 364 { 365 float pixel; 366 char *pPtr = (char *) &pixel; 367 368 for (int k = 0; k < sizeof (pixel); ++k) 369 *pPtr++ = *inPtr++; 370 371 unsigned int pixel24 = floatToFloat24 (pixel); 372 unsigned int diff = pixel24 - previousPixel; 373 previousPixel = pixel24; 374 375 *(ptr[0]++) = diff >> 16; 376 *(ptr[1]++) = diff >> 8; 377 *(ptr[2]++) = diff; 378 } 379 380 break; 381 382 default: 383 384 assert (false); 385 } 386 } 387 } 388 389 uLongf outSize = int (ceil ((tmpBufferEnd - _tmpBuffer) * 1.01)) + 100; 390 391 if (Z_OK != ::compress ((Bytef *) _outBuffer, 392 &outSize, 393 (const Bytef *) _tmpBuffer, 394 tmpBufferEnd - _tmpBuffer)) 395 { 396 throw Iex::BaseExc ("Data compression (zlib) failed."); 397 } 398 399 outPtr = _outBuffer; 400 return outSize; 401} 402 403 404int 405Pxr24Compressor::uncompress (const char *inPtr, 406 int inSize, 407 Box2i range, 408 const char *&outPtr) 409{ 410 if (inSize == 0) 411 { 412 outPtr = _outBuffer; 413 return 0; 414 } 415 416 uLongf tmpSize = _maxScanLineSize * _numScanLines; 417 418 if (Z_OK != ::uncompress ((Bytef *)_tmpBuffer, 419 &tmpSize, 420 (const Bytef *) inPtr, 421 inSize)) 422 { 423 throw Iex::InputExc ("Data decompression (zlib) failed."); 424 } 425 426 int minX = range.min.x; 427 int maxX = min (range.max.x, _maxX); 428 int minY = range.min.y; 429 int maxY = min (range.max.y, _maxY); 430 431 const unsigned char *tmpBufferEnd = _tmpBuffer; 432 char *writePtr = _outBuffer; 433 434 for (int y = minY; y <= maxY; ++y) 435 { 436 for (ChannelList::ConstIterator i = _channels.begin(); 437 i != _channels.end(); 438 ++i) 439 { 440 const Channel &c = i.channel(); 441 442 if (modp (y, c.ySampling) != 0) 443 continue; 444 445 int n = numSamples (c.xSampling, minX, maxX); 446 447 const unsigned char *ptr[4]; 448 unsigned int pixel = 0; 449 450 switch (c.type) 451 { 452 case UINT: 453 454 ptr[0] = tmpBufferEnd; 455 ptr[1] = ptr[0] + n; 456 ptr[2] = ptr[1] + n; 457 ptr[3] = ptr[2] + n; 458 tmpBufferEnd = ptr[3] + n; 459 460 if (tmpBufferEnd - _tmpBuffer > tmpSize) 461 notEnoughData(); 462 463 for (int j = 0; j < n; ++j) 464 { 465 unsigned int diff = (*(ptr[0]++) << 24) | 466 (*(ptr[1]++) << 16) | 467 (*(ptr[2]++) << 8) | 468 *(ptr[3]++); 469 470 pixel += diff; 471 472 char *pPtr = (char *) &pixel; 473 474 for (int k = 0; k < sizeof (pixel); ++k) 475 *writePtr++ = *pPtr++; 476 } 477 478 break; 479 480 case HALF: 481 482 ptr[0] = tmpBufferEnd; 483 ptr[1] = ptr[0] + n; 484 tmpBufferEnd = ptr[1] + n; 485 486 if (tmpBufferEnd - _tmpBuffer > tmpSize) 487 notEnoughData(); 488 489 for (int j = 0; j < n; ++j) 490 { 491 unsigned int diff = (*(ptr[0]++) << 8) | 492 *(ptr[1]++); 493 494 pixel += diff; 495 496 half * hPtr = (half *) writePtr; 497 hPtr->setBits ((unsigned short) pixel); 498 writePtr += sizeof (half); 499 } 500 501 break; 502 503 case FLOAT: 504 505 ptr[0] = tmpBufferEnd; 506 ptr[1] = ptr[0] + n; 507 ptr[2] = ptr[1] + n; 508 tmpBufferEnd = ptr[2] + n; 509 510 if (tmpBufferEnd - _tmpBuffer > tmpSize) 511 notEnoughData(); 512 513 for (int j = 0; j < n; ++j) 514 { 515 unsigned int diff = (*(ptr[0]++) << 24) | 516 (*(ptr[1]++) << 16) | 517 (*(ptr[2]++) << 8); 518 pixel += diff; 519 520 char *pPtr = (char *) &pixel; 521 522 for (int k = 0; k < sizeof (pixel); ++k) 523 *writePtr++ = *pPtr++; 524 } 525 526 break; 527 528 default: 529 530 assert (false); 531 } 532 } 533 } 534 535 if (tmpBufferEnd - _tmpBuffer < tmpSize) 536 tooMuchData(); 537 538 outPtr = _outBuffer; 539 return writePtr - _outBuffer; 540} 541 542} // namespace Imf 543