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