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