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