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