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