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 58namespace Imf { 59 60using Imath::divp; 61using Imath::modp; 62using Imath::Box2i; 63using Imath::V2i; 64using Iex::InputExc; 65 66namespace { 67 68// 69// Functions to compress the range of values in the pixel data 70// 71 72const int USHORT_RANGE = (1 << 16); 73const int BITMAP_SIZE = (USHORT_RANGE >> 3); 74 75void 76bitmapFromData (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 107unsigned short 108forwardLutFromBitmap (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 125unsigned short 126reverseLutFromBitmap (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 146void 147applyLut (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 159struct 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 170PizCompressor::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 231PizCompressor::~PizCompressor () 232{ 233 delete [] _tmpBuffer; 234 delete [] _outBuffer; 235 delete [] _channelData; 236} 237 238 239int 240PizCompressor::numScanLines () const 241{ 242 return _numScanLines; 243} 244 245 246Compressor::Format 247PizCompressor::format () const 248{ 249 return _format; 250} 251 252 253int 254PizCompressor::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 267int 268PizCompressor::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 277int 278PizCompressor::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 291int 292PizCompressor::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 301int 302PizCompressor::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 483int 484PizCompressor::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