PageRenderTime 99ms CodeModel.GetById 13ms app.highlight 79ms RepoModel.GetById 1ms app.codeStats 0ms

/src/FreeImage/Source/OpenEXR/IlmImf/ImfB44Compressor.cpp

https://bitbucket.org/cabalistic/ogredeps/
C++ | 1069 lines | 598 code | 192 blank | 279 comment | 105 complexity | 4afc4f15da69d57a2cb9dfb201c3681e MD5 | raw file
   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
 114namespace Imf {
 115
 116using Imath::divp;
 117using Imath::modp;
 118using Imath::Box2i;
 119using Imath::V2i;
 120using std::min;
 121
 122namespace {
 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
 134inline void
 135convertFromLinear (unsigned short s[16])
 136{
 137    for (int i = 0; i < 16; ++i)
 138	s[i] = expTable[s[i]];
 139}
 140
 141
 142inline void
 143convertToLinear (unsigned short s[16])
 144{
 145    for (int i = 0; i < 16; ++i)
 146	s[i] = logTable[s[i]];
 147}
 148
 149
 150inline int
 151shiftAndRound (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
 172int
 173pack (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
 366inline
 367void
 368unpack14 (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
 412inline
 413void
 414unpack3 (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
 436void
 437notEnoughData ()
 438{
 439    throw Iex::InputExc ("Error decompressing data "
 440			 "(input data are shorter than expected).");
 441}
 442
 443
 444void
 445tooMuchData ()
 446{
 447    throw Iex::InputExc ("Error decompressing data "
 448			 "(input data are longer than expected).");
 449}
 450
 451} // namespace
 452
 453
 454struct 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
 467B44Compressor::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
 551B44Compressor::~B44Compressor ()
 552{
 553    delete [] _tmpBuffer;
 554    delete [] _outBuffer;
 555    delete [] _channelData;
 556}
 557
 558
 559int
 560B44Compressor::numScanLines () const
 561{
 562    return _numScanLines;
 563}
 564
 565
 566Compressor::Format
 567B44Compressor::format () const
 568{
 569    return _format;
 570}
 571
 572
 573int
 574B44Compressor::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
 587int
 588B44Compressor::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
 597int
 598B44Compressor::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
 611int
 612B44Compressor::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
 621int
 622B44Compressor::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
 863int
 864B44Compressor::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