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 "ImfCheckedArithmetic.h"
71 #include "ImfNamespace.h"
72 
73 #include <ImathFun.h>
74 #include <Iex.h>
75 
76 #include <half.h>
77 #include <zlib.h>
78 #include <assert.h>
79 #include <algorithm>
80 
81 using namespace std;
82 using namespace IMATH_NAMESPACE;
83 
84 OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
85 
86 namespace {
87 
88 //
89 // Conversion from 32-bit to 24-bit floating-point numbers.
90 // Conversion back to 32 bits is simply an 8-bit shift to the left.
91 //
92 
93 inline unsigned int
floatToFloat24(float f)94 floatToFloat24 (float f)
95 {
96     union
97     {
98 	float		f;
99 	unsigned int	i;
100     } u;
101 
102     u.f = f;
103 
104     //
105     // Disassemble the 32-bit floating point number, f,
106     // into sign, s, exponent, e, and significand, m.
107     //
108 
109     unsigned int s = u.i & 0x80000000;
110     unsigned int e = u.i & 0x7f800000;
111     unsigned int m = u.i & 0x007fffff;
112     unsigned int i;
113 
114     if (e == 0x7f800000)
115     {
116 	if (m)
117 	{
118 	    //
119 	    // F is a NAN; we preserve the sign bit and
120 	    // the 15 leftmost bits of the significand,
121 	    // with one exception: If the 15 leftmost
122 	    // bits are all zero, the NAN would turn
123 	    // into an infinity, so we have to set at
124 	    // least one bit in the significand.
125 	    //
126 
127 	    m >>= 8;
128 	    i = (e >> 8) | m | (m == 0);
129 	}
130 	else
131 	{
132 	    //
133 	    // F is an infinity.
134 	    //
135 
136 	    i = e >> 8;
137 	}
138     }
139     else
140     {
141 	//
142 	// F is finite, round the significand to 15 bits.
143 	//
144 
145 	i = ((e | m) + (m & 0x00000080)) >> 8;
146 
147 	if (i >= 0x7f8000)
148 	{
149 	    //
150 	    // F was close to FLT_MAX, and the significand was
151 	    // rounded up, resulting in an exponent overflow.
152 	    // Avoid the overflow by truncating the significand
153 	    // instead of rounding it.
154 	    //
155 
156 	    i = (e | m) >> 8;
157 	}
158     }
159 
160     return (s >> 8) | i;
161 }
162 
163 
164 void
notEnoughData()165 notEnoughData ()
166 {
167     throw IEX_NAMESPACE::InputExc ("Error decompressing data "
168 			 "(input data are shorter than expected).");
169 }
170 
171 
172 void
tooMuchData()173 tooMuchData ()
174 {
175     throw IEX_NAMESPACE::InputExc ("Error decompressing data "
176 			 "(input data are longer than expected).");
177 }
178 
179 } // namespace
180 
181 
Pxr24Compressor(const Header & hdr,size_t maxScanLineSize,size_t numScanLines)182 Pxr24Compressor::Pxr24Compressor (const Header &hdr,
183 				  size_t maxScanLineSize,
184 				  size_t numScanLines)
185 :
186     Compressor (hdr),
187     _maxScanLineSize (maxScanLineSize),
188     _numScanLines (numScanLines),
189     _tmpBuffer (0),
190     _outBuffer (0),
191     _channels (hdr.channels())
192 {
193     size_t maxInBytes =
194         uiMult (maxScanLineSize, numScanLines);
195 
196     size_t maxOutBytes =
197         uiAdd (uiAdd (maxInBytes,
198                       size_t (ceil (maxInBytes * 0.01))),
199                size_t (100));
200 
201     _tmpBuffer = new unsigned char [maxInBytes];
202     _outBuffer = new char [maxOutBytes];
203 
204     const Box2i &dataWindow = hdr.dataWindow();
205 
206     _minX = dataWindow.min.x;
207     _maxX = dataWindow.max.x;
208     _maxY = dataWindow.max.y;
209 }
210 
211 
~Pxr24Compressor()212 Pxr24Compressor::~Pxr24Compressor ()
213 {
214     delete [] _tmpBuffer;
215     delete [] _outBuffer;
216 }
217 
218 
219 int
numScanLines() const220 Pxr24Compressor::numScanLines () const
221 {
222     return _numScanLines;
223 }
224 
225 
226 Compressor::Format
format() const227 Pxr24Compressor::format () const
228 {
229     return NATIVE;
230 }
231 
232 
233 int
compress(const char * inPtr,int inSize,int minY,const char * & outPtr)234 Pxr24Compressor::compress (const char *inPtr,
235 			   int inSize,
236 			   int minY,
237 			   const char *&outPtr)
238 {
239     return compress (inPtr,
240 	             inSize,
241 		     Box2i (V2i (_minX, minY),
242 			    V2i (_maxX, minY + _numScanLines - 1)),
243 		     outPtr);
244 }
245 
246 
247 int
compressTile(const char * inPtr,int inSize,Box2i range,const char * & outPtr)248 Pxr24Compressor::compressTile (const char *inPtr,
249 			       int inSize,
250 			       Box2i range,
251 			       const char *&outPtr)
252 {
253     return compress (inPtr, inSize, range, outPtr);
254 }
255 
256 
257 int
uncompress(const char * inPtr,int inSize,int minY,const char * & outPtr)258 Pxr24Compressor::uncompress (const char *inPtr,
259 			     int inSize,
260 			     int minY,
261 			     const char *&outPtr)
262 {
263     return uncompress (inPtr,
264 	               inSize,
265 		       Box2i (V2i (_minX, minY),
266 			      V2i (_maxX, minY + _numScanLines - 1)),
267 		       outPtr);
268 }
269 
270 
271 int
uncompressTile(const char * inPtr,int inSize,Box2i range,const char * & outPtr)272 Pxr24Compressor::uncompressTile (const char *inPtr,
273 				 int inSize,
274 				 Box2i range,
275 				 const char *&outPtr)
276 {
277     return uncompress (inPtr, inSize, range, outPtr);
278 }
279 
280 
281 int
compress(const char * inPtr,int inSize,Box2i range,const char * & outPtr)282 Pxr24Compressor::compress (const char *inPtr,
283 			   int inSize,
284 			   Box2i range,
285 			   const char *&outPtr)
286 {
287     if (inSize == 0)
288     {
289 	outPtr = _outBuffer;
290 	return 0;
291     }
292 
293     int minX = range.min.x;
294     int maxX = min (range.max.x, _maxX);
295     int minY = range.min.y;
296     int maxY = min (range.max.y, _maxY);
297 
298     unsigned char *tmpBufferEnd = _tmpBuffer;
299 
300     for (int y = minY; y <= maxY; ++y)
301     {
302 	for (ChannelList::ConstIterator i = _channels.begin();
303 	     i != _channels.end();
304 	     ++i)
305 	{
306 	    const Channel &c = i.channel();
307 
308 	    if (modp (y, c.ySampling) != 0)
309 		continue;
310 
311 	    int n = numSamples (c.xSampling, minX, maxX);
312 
313 	    unsigned char *ptr[4];
314 	    unsigned int previousPixel = 0;
315 
316 	    switch (c.type)
317 	    {
318 	      case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
319 
320 		ptr[0] = tmpBufferEnd;
321 		ptr[1] = ptr[0] + n;
322 		ptr[2] = ptr[1] + n;
323 		ptr[3] = ptr[2] + n;
324 		tmpBufferEnd = ptr[3] + n;
325 
326 		for (int j = 0; j < n; ++j)
327 		{
328 		    unsigned int pixel;
329 		    char *pPtr = (char *) &pixel;
330 
331 		    for (size_t k = 0; k < sizeof (pixel); ++k)
332 			*pPtr++ = *inPtr++;
333 
334 		    unsigned int diff = pixel - previousPixel;
335 		    previousPixel = pixel;
336 
337 		    *(ptr[0]++) = diff >> 24;
338 		    *(ptr[1]++) = diff >> 16;
339 		    *(ptr[2]++) = diff >> 8;
340 		    *(ptr[3]++) = diff;
341 		}
342 
343 		break;
344 
345 	      case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
346 
347 		ptr[0] = tmpBufferEnd;
348 		ptr[1] = ptr[0] + n;
349 		tmpBufferEnd = ptr[1] + n;
350 
351 		for (int j = 0; j < n; ++j)
352 		{
353 		    half pixel;
354 
355 		    pixel = *(const half *) inPtr;
356 		    inPtr += sizeof (half);
357 
358 		    unsigned int diff = pixel.bits() - previousPixel;
359 		    previousPixel = pixel.bits();
360 
361 		    *(ptr[0]++) = diff >> 8;
362 		    *(ptr[1]++) = diff;
363 		}
364 
365 		break;
366 
367 	      case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
368 
369 		ptr[0] = tmpBufferEnd;
370 		ptr[1] = ptr[0] + n;
371 		ptr[2] = ptr[1] + n;
372 		tmpBufferEnd = ptr[2] + n;
373 
374 		for (int j = 0; j < n; ++j)
375 		{
376 		    float pixel;
377 		    char *pPtr = (char *) &pixel;
378 
379 		    for (size_t k = 0; k < sizeof (pixel); ++k)
380 			*pPtr++ = *inPtr++;
381 
382 		    unsigned int pixel24 = floatToFloat24 (pixel);
383 		    unsigned int diff = pixel24 - previousPixel;
384 		    previousPixel = pixel24;
385 
386 		    *(ptr[0]++) = diff >> 16;
387 		    *(ptr[1]++) = diff >> 8;
388 		    *(ptr[2]++) = diff;
389 		}
390 
391 		break;
392 
393 	      default:
394 
395 		assert (false);
396 	    }
397 	}
398     }
399 
400     uLongf outSize = int (ceil ((tmpBufferEnd - _tmpBuffer) * 1.01)) + 100;
401 
402     if (Z_OK != ::compress ((Bytef *) _outBuffer,
403 			    &outSize,
404 			    (const Bytef *) _tmpBuffer,
405 			    tmpBufferEnd - _tmpBuffer))
406     {
407 	throw IEX_NAMESPACE::BaseExc ("Data compression (zlib) failed.");
408     }
409 
410     outPtr = _outBuffer;
411     return outSize;
412 }
413 
414 
415 int
uncompress(const char * inPtr,int inSize,Box2i range,const char * & outPtr)416 Pxr24Compressor::uncompress (const char *inPtr,
417 			     int inSize,
418 			     Box2i range,
419 			     const char *&outPtr)
420 {
421     if (inSize == 0)
422     {
423 	outPtr = _outBuffer;
424 	return 0;
425     }
426 
427     uLongf tmpSize = _maxScanLineSize * _numScanLines;
428 
429     if (Z_OK != ::uncompress ((Bytef *)_tmpBuffer,
430 			      &tmpSize,
431 			      (const Bytef *) inPtr,
432 			      inSize))
433     {
434 	throw IEX_NAMESPACE::InputExc ("Data decompression (zlib) failed.");
435     }
436 
437     int minX = range.min.x;
438     int maxX = min (range.max.x, _maxX);
439     int minY = range.min.y;
440     int maxY = min (range.max.y, _maxY);
441 
442     const unsigned char *tmpBufferEnd = _tmpBuffer;
443     char *writePtr = _outBuffer;
444 
445     for (int y = minY; y <= maxY; ++y)
446     {
447 	for (ChannelList::ConstIterator i = _channels.begin();
448 	     i != _channels.end();
449 	     ++i)
450 	{
451 	    const Channel &c = i.channel();
452 
453 	    if (modp (y, c.ySampling) != 0)
454 		continue;
455 
456 	    int n = numSamples (c.xSampling, minX, maxX);
457 
458 	    const unsigned char *ptr[4];
459 	    unsigned int pixel = 0;
460 
461 	    switch (c.type)
462 	    {
463 	      case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
464 
465 		ptr[0] = tmpBufferEnd;
466 		ptr[1] = ptr[0] + n;
467 		ptr[2] = ptr[1] + n;
468 		ptr[3] = ptr[2] + n;
469 		tmpBufferEnd = ptr[3] + n;
470 
471 		if ( (uLongf)(tmpBufferEnd - _tmpBuffer) > tmpSize)
472 		    notEnoughData();
473 
474 		for (int j = 0; j < n; ++j)
475 		{
476 		    unsigned int diff = (*(ptr[0]++) << 24) |
477 					(*(ptr[1]++) << 16) |
478 					(*(ptr[2]++) <<  8) |
479 					 *(ptr[3]++);
480 
481 		    pixel += diff;
482 
483 		    char *pPtr = (char *) &pixel;
484 
485 		    for (size_t k = 0; k < sizeof (pixel); ++k)
486 			*writePtr++ = *pPtr++;
487 		}
488 
489 		break;
490 
491 	      case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
492 
493 		ptr[0] = tmpBufferEnd;
494 		ptr[1] = ptr[0] + n;
495 		tmpBufferEnd = ptr[1] + n;
496 
497         if ( (uLongf)(tmpBufferEnd - _tmpBuffer) > tmpSize)
498 		    notEnoughData();
499 
500 		for (int j = 0; j < n; ++j)
501 		{
502 		    unsigned int diff = (*(ptr[0]++) << 8) |
503 					 *(ptr[1]++);
504 
505 		    pixel += diff;
506 
507 		    half * hPtr = (half *) writePtr;
508 		    hPtr->setBits ((unsigned short) pixel);
509 		    writePtr += sizeof (half);
510 		}
511 
512 		break;
513 
514 	      case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
515 
516 		ptr[0] = tmpBufferEnd;
517 		ptr[1] = ptr[0] + n;
518 		ptr[2] = ptr[1] + n;
519 		tmpBufferEnd = ptr[2] + n;
520 
521         if ( (uLongf) (tmpBufferEnd - _tmpBuffer) > tmpSize)
522 		    notEnoughData();
523 
524 		for (int j = 0; j < n; ++j)
525 		{
526 		    unsigned int diff = (*(ptr[0]++) << 24) |
527 					(*(ptr[1]++) << 16) |
528 					(*(ptr[2]++) <<  8);
529 		    pixel += diff;
530 
531 		    char *pPtr = (char *) &pixel;
532 
533 		    for (size_t k = 0; k < sizeof (pixel); ++k)
534 			*writePtr++ = *pPtr++;
535 		}
536 
537 		break;
538 
539 	      default:
540 
541 		assert (false);
542 	    }
543 	}
544     }
545 
546     if ((uLongf) (tmpBufferEnd - _tmpBuffer) < tmpSize)
547 	tooMuchData();
548 
549     outPtr = _outBuffer;
550     return writePtr - _outBuffer;
551 }
552 
553 OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
554