• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 ///////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2006, Industrial Light & Magic, a division of Lucas
4 // Digital Ltd. LLC
5 //
6 // All rights reserved.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions are
10 // met:
11 // *       Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // *       Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
16 // distribution.
17 // *       Neither the name of Industrial Light & Magic nor the names of
18 // its contributors may be used to endorse or promote products derived
19 // from this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 //
33 ///////////////////////////////////////////////////////////////////////////
34 
35 
36 //-----------------------------------------------------------------------------
37 //
38 //	class B44Compressor
39 //
40 //	This compressor is lossy for HALF channels; the compression rate
41 //	is fixed at 32/14 (approximately 2.28).  FLOAT and UINT channels
42 //	are not compressed; their data are preserved exactly.
43 //
44 //	Each HALF channel is split into blocks of 4 by 4 pixels.  An
45 //	uncompressed block occupies 32 bytes, which are re-interpreted
46 //	as sixteen 16-bit unsigned integers, t[0] ... t[15].  Compression
47 //	shrinks the block to 14 bytes.  The compressed 14-byte block
48 //	contains
49 //
50 //	 - t[0]
51 //
52 //	 - a 6-bit shift value
53 //
54 //	 - 15 densely packed 6-bit values, r[0] ... r[14], which are
55 //         computed by subtracting adjacent pixel values and right-
56 //	   shifting the differences according to the stored shift value.
57 //
58 //	   Differences between adjacent pixels are computed according
59 //	   to the following diagram:
60 //
61 //		 0 -------->  1 -------->  2 -------->  3
62 //               |     3            7           11
63 //               |
64 //               | 0
65 //               |
66 //               v
67 //		 4 -------->  5 -------->  6 -------->  7
68 //               |     4            8           12
69 //               |
70 //               | 1
71 //               |
72 //               v
73 //		 8 -------->  9 --------> 10 --------> 11
74 //               |     5            9           13
75 //               |
76 //               | 2
77 //               |
78 //               v
79 //		12 --------> 13 --------> 14 --------> 15
80 //                     6           10           14
81 //
82 //	    Here
83 //
84 //               5 ---------> 6
85 //                     8
86 //
87 //	    means that r[8] is the difference between t[5] and t[6].
88 //
89 //	 - optionally, a 4-by-4 pixel block where all pixels have the
90 //	   same value can be treated as a special case, where the
91 //	   compressed block contains only 3 instead of 14 bytes:
92 //	   t[0], followed by an "impossible" 6-bit shift value and
93 //	   two padding bits.
94 //
95 //	This compressor can handle positive and negative pixel values.
96 //	NaNs and infinities are replaced with zeroes before compression.
97 //
98 //-----------------------------------------------------------------------------
99 
100 #include <ImfB44Compressor.h>
101 #include <ImfHeader.h>
102 #include <ImfChannelList.h>
103 #include <ImfMisc.h>
104 #include <ImfCheckedArithmetic.h>
105 #include <ImathFun.h>
106 #include <ImathBox.h>
107 #include <Iex.h>
108 #include <ImfIO.h>
109 #include <ImfXdr.h>
110 #include <string.h>
111 #include <assert.h>
112 #include <algorithm>
113 
114 namespace Imf {
115 
116 using Imath::divp;
117 using Imath::modp;
118 using Imath::Box2i;
119 using Imath::V2i;
120 using std::min;
121 
122 namespace {
123 
124 //
125 // Lookup tables for
126 //	y = exp (x / 8)
127 // and
128 //	x = 8 * log (y)
129 //
130 
131 #include "b44ExpLogTable.h"
132 
133 
134 inline void
convertFromLinear(unsigned short s[16])135 convertFromLinear (unsigned short s[16])
136 {
137     for (int i = 0; i < 16; ++i)
138     s[i] = expTable[s[i]];
139 }
140 
141 
142 inline void
convertToLinear(unsigned short s[16])143 convertToLinear (unsigned short s[16])
144 {
145     for (int i = 0; i < 16; ++i)
146     s[i] = logTable[s[i]];
147 }
148 
149 
150 inline int
shiftAndRound(int x,int shift)151 shiftAndRound (int x, int shift)
152 {
153     //
154     // Compute
155     //
156     //     y = x * pow (2, -shift),
157     //
158     // then round y to the nearest integer.
159     // In case of a tie, where y is exactly
160     // halfway between two integers, round
161     // to the even one.
162     //
163 
164     x <<= 1;
165     int a = (1 << shift) - 1;
166     shift += 1;
167     int b = (x >> shift) & 1;
168     return (x + a + b) >> shift;
169 }
170 
171 
172 int
pack(const unsigned short s[16],unsigned char b[14],bool optFlatFields,bool exactMax)173 pack (const unsigned short s[16],
174       unsigned char b[14],
175       bool optFlatFields,
176       bool exactMax)
177 {
178     //
179     // Pack a block of 4 by 4 16-bit pixels (32 bytes) into
180     // either 14 or 3 bytes.
181     //
182 
183     //
184     // Integers s[0] ... s[15] represent floating-point numbers
185     // in what is essentially a sign-magnitude format.  Convert
186     // s[0] .. s[15] into a new set of integers, t[0] ... t[15],
187     // such that if t[i] is greater than t[j], the floating-point
188     // number that corresponds to s[i] is always greater than
189     // the floating-point number that corresponds to s[j].
190     //
191     // Also, replace any bit patterns that represent NaNs or
192     // infinities with bit patterns that represent floating-point
193     // zeroes.
194     //
195     //	bit pattern	floating-point		bit pattern
196     //	in s[i]		value			in t[i]
197     //
198     //  0x7fff		NAN			0x8000
199     //  0x7ffe		NAN			0x8000
200     //	  ...					  ...
201     //  0x7c01		NAN			0x8000
202     //  0x7c00		+infinity		0x8000
203     //  0x7bff		+HALF_MAX		0xfbff
204     //  0x7bfe					0xfbfe
205     //  0x7bfd					0xfbfd
206     //	  ...					  ...
207     //  0x0002		+2 * HALF_MIN		0x8002
208     //  0x0001		+HALF_MIN		0x8001
209     //  0x0000		+0.0			0x8000
210     //  0x8000		-0.0			0x7fff
211     //  0x8001		-HALF_MIN		0x7ffe
212     //  0x8002		-2 * HALF_MIN		0x7ffd
213     //	  ...					  ...
214     //  0xfbfd					0x0f02
215     //  0xfbfe					0x0401
216     //  0xfbff		-HALF_MAX		0x0400
217     //  0xfc00		-infinity		0x8000
218     //  0xfc01		NAN			0x8000
219     //	  ...					  ...
220     //  0xfffe		NAN			0x8000
221     //  0xffff		NAN			0x8000
222     //
223 
224     unsigned short t[16];
225 
226     for (int i = 0; i < 16; ++i)
227     {
228     if ((s[i] & 0x7c00) == 0x7c00)
229         t[i] = 0x8000;
230     else if (s[i] & 0x8000)
231         t[i] = ~s[i];
232     else
233         t[i] = s[i] | 0x8000;
234     }
235 
236     //
237     // Find the maximum, tMax, of t[0] ... t[15].
238     //
239 
240     unsigned short tMax = 0;
241 
242     for (int i = 0; i < 16; ++i)
243     if (tMax < t[i])
244         tMax = t[i];
245 
246     //
247     // Compute a set of running differences, r[0] ... r[14]:
248     // Find a shift value such that after rounding off the
249     // rightmost bits and shifting all differenes are between
250     // -32 and +31.  Then bias the differences so that they
251     // end up between 0 and 63.
252     //
253 
254     int shift = -1;
255     int d[16];
256     int r[15];
257     int rMin;
258     int rMax;
259 
260     const int bias = 0x20;
261 
262     do
263     {
264     shift += 1;
265 
266     //
267     // Compute absolute differences, d[0] ... d[15],
268     // between tMax and t[0] ... t[15].
269     //
270     // Shift and round the absolute differences.
271     //
272 
273     for (int i = 0; i < 16; ++i)
274         d[i] = shiftAndRound (tMax - t[i], shift);
275 
276     //
277     // Convert d[0] .. d[15] into running differences
278     //
279 
280     r[ 0] = d[ 0] - d[ 4] + bias;
281     r[ 1] = d[ 4] - d[ 8] + bias;
282     r[ 2] = d[ 8] - d[12] + bias;
283 
284     r[ 3] = d[ 0] - d[ 1] + bias;
285     r[ 4] = d[ 4] - d[ 5] + bias;
286     r[ 5] = d[ 8] - d[ 9] + bias;
287     r[ 6] = d[12] - d[13] + bias;
288 
289     r[ 7] = d[ 1] - d[ 2] + bias;
290     r[ 8] = d[ 5] - d[ 6] + bias;
291     r[ 9] = d[ 9] - d[10] + bias;
292     r[10] = d[13] - d[14] + bias;
293 
294     r[11] = d[ 2] - d[ 3] + bias;
295     r[12] = d[ 6] - d[ 7] + bias;
296     r[13] = d[10] - d[11] + bias;
297     r[14] = d[14] - d[15] + bias;
298 
299     rMin = r[0];
300     rMax = r[0];
301 
302     for (int i = 1; i < 15; ++i)
303     {
304         if (rMin > r[i])
305         rMin = r[i];
306 
307         if (rMax < r[i])
308         rMax = r[i];
309     }
310     }
311     while (rMin < 0 || rMax > 0x3f);
312 
313     if (rMin == bias && rMax == bias && optFlatFields)
314     {
315     //
316     // Special case - all pixels have the same value.
317     // We encode this in 3 instead of 14 bytes by
318     // storing the value 0xfc in the third output byte,
319     // which cannot occur in the 14-byte encoding.
320     //
321 
322     b[0] = (t[0] >> 8);
323     b[1] =  t[0];
324     b[2] = 0xfc;
325 
326     return 3;
327     }
328 
329     if (exactMax)
330     {
331     //
332     // Adjust t[0] so that the pixel whose value is equal
333     // to tMax gets represented as accurately as possible.
334     //
335 
336     t[0] = tMax - (d[0] << shift);
337     }
338 
339     //
340     // Pack t[0], shift and r[0] ... r[14] into 14 bytes:
341     //
342 
343     b[ 0] = (t[0] >> 8);
344     b[ 1] =  t[0];
345 
346     b[ 2] = (unsigned char) ((shift << 2) | (r[ 0] >> 4));
347     b[ 3] = (unsigned char) ((r[ 0] << 4) | (r[ 1] >> 2));
348     b[ 4] = (unsigned char) ((r[ 1] << 6) |  r[ 2]      );
349 
350     b[ 5] = (unsigned char) ((r[ 3] << 2) | (r[ 4] >> 4));
351     b[ 6] = (unsigned char) ((r[ 4] << 4) | (r[ 5] >> 2));
352     b[ 7] = (unsigned char) ((r[ 5] << 6) |  r[ 6]      );
353 
354     b[ 8] = (unsigned char) ((r[ 7] << 2) | (r[ 8] >> 4));
355     b[ 9] = (unsigned char) ((r[ 8] << 4) | (r[ 9] >> 2));
356     b[10] = (unsigned char) ((r[ 9] << 6) |  r[10]      );
357 
358     b[11] = (unsigned char) ((r[11] << 2) | (r[12] >> 4));
359     b[12] = (unsigned char) ((r[12] << 4) | (r[13] >> 2));
360     b[13] = (unsigned char) ((r[13] << 6) |  r[14]      );
361 
362     return 14;
363 }
364 
365 
366 inline
367 void
unpack14(const unsigned char b[14],unsigned short s[16])368 unpack14 (const unsigned char b[14], unsigned short s[16])
369 {
370     //
371     // Unpack a 14-byte block into 4 by 4 16-bit pixels.
372     //
373 
374     #if defined (DEBUG)
375     assert (b[2] != 0xfc);
376     #endif
377 
378     s[ 0] = (b[0] << 8) | b[1];
379 
380     unsigned short shift = (b[ 2] >> 2);
381     unsigned short bias = (0x20 << shift);
382 
383     s[ 4] = s[ 0] + ((((b[ 2] << 4) | (b[ 3] >> 4)) & 0x3f) << shift) - bias;
384     s[ 8] = s[ 4] + ((((b[ 3] << 2) | (b[ 4] >> 6)) & 0x3f) << shift) - bias;
385     s[12] = s[ 8] +   ((b[ 4]                       & 0x3f) << shift) - bias;
386 
387     s[ 1] = s[ 0] +   ((b[ 5] >> 2)                         << shift) - bias;
388     s[ 5] = s[ 4] + ((((b[ 5] << 4) | (b[ 6] >> 4)) & 0x3f) << shift) - bias;
389     s[ 9] = s[ 8] + ((((b[ 6] << 2) | (b[ 7] >> 6)) & 0x3f) << shift) - bias;
390     s[13] = s[12] +   ((b[ 7]                       & 0x3f) << shift) - bias;
391 
392     s[ 2] = s[ 1] +   ((b[ 8] >> 2)                         << shift) - bias;
393     s[ 6] = s[ 5] + ((((b[ 8] << 4) | (b[ 9] >> 4)) & 0x3f) << shift) - bias;
394     s[10] = s[ 9] + ((((b[ 9] << 2) | (b[10] >> 6)) & 0x3f) << shift) - bias;
395     s[14] = s[13] +   ((b[10]                       & 0x3f) << shift) - bias;
396 
397     s[ 3] = s[ 2] +   ((b[11] >> 2)                         << shift) - bias;
398     s[ 7] = s[ 6] + ((((b[11] << 4) | (b[12] >> 4)) & 0x3f) << shift) - bias;
399     s[11] = s[10] + ((((b[12] << 2) | (b[13] >> 6)) & 0x3f) << shift) - bias;
400     s[15] = s[14] +   ((b[13]                       & 0x3f) << shift) - bias;
401 
402     for (int i = 0; i < 16; ++i)
403     {
404     if (s[i] & 0x8000)
405         s[i] &= 0x7fff;
406     else
407         s[i] = ~s[i];
408     }
409 }
410 
411 
412 inline
413 void
unpack3(const unsigned char b[3],unsigned short s[16])414 unpack3 (const unsigned char b[3], unsigned short s[16])
415 {
416     //
417     // Unpack a 3-byte block into 4 by 4 identical 16-bit pixels.
418     //
419 
420     #if defined (DEBUG)
421     assert (b[2] == 0xfc);
422     #endif
423 
424     s[0] = (b[0] << 8) | b[1];
425 
426     if (s[0] & 0x8000)
427     s[0] &= 0x7fff;
428     else
429     s[0] = ~s[0];
430 
431     for (int i = 1; i < 16; ++i)
432     s[i] = s[0];
433 }
434 
435 
436 void
notEnoughData()437 notEnoughData ()
438 {
439     throw Iex::InputExc ("Error decompressing data "
440              "(input data are shorter than expected).");
441 }
442 
443 
444 void
tooMuchData()445 tooMuchData ()
446 {
447     throw Iex::InputExc ("Error decompressing data "
448              "(input data are longer than expected).");
449 }
450 
451 } // namespace
452 
453 
454 struct B44Compressor::ChannelData
455 {
456     unsigned short *	start;
457     unsigned short *	end;
458     int			nx;
459     int			ny;
460     int			ys;
461     PixelType		type;
462     bool		pLinear;
463     int			size;
464 };
465 
466 
B44Compressor(const Header & hdr,size_t maxScanLineSize,size_t numScanLines,bool optFlatFields)467 B44Compressor::B44Compressor
468     (const Header &hdr,
469      size_t maxScanLineSize,
470      size_t numScanLines,
471      bool optFlatFields)
472 :
473     Compressor (hdr),
474     _maxScanLineSize (maxScanLineSize),
475     _optFlatFields (optFlatFields),
476     _format (XDR),
477     _numScanLines (numScanLines),
478     _tmpBuffer (0),
479     _outBuffer (0),
480     _numChans (0),
481     _channels (hdr.channels()),
482     _channelData (0)
483 {
484     //
485     // Allocate buffers for compressed an uncompressed pixel data,
486     // allocate a set of ChannelData structs to help speed up the
487     // compress() and uncompress() functions, below, and determine
488     // if uncompressed pixel data should be in native or Xdr format.
489     //
490 
491     _tmpBuffer = new unsigned short
492         [checkArraySize (uiMult (maxScanLineSize, numScanLines),
493                          sizeof (unsigned short))];
494 
495     const ChannelList &channels = header().channels();
496     int numHalfChans = 0;
497 
498     for (ChannelList::ConstIterator c = channels.begin();
499      c != channels.end();
500      ++c)
501     {
502     assert (pixelTypeSize (c.channel().type) % pixelTypeSize (HALF) == 0);
503     ++_numChans;
504 
505     if (c.channel().type == HALF)
506         ++numHalfChans;
507     }
508 
509     //
510     // Compressed data may be larger than the input data
511     //
512 
513     size_t padding = 12 * numHalfChans * (numScanLines + 3) / 4;
514 
515     _outBuffer = new char
516         [uiAdd (uiMult (maxScanLineSize, numScanLines), padding)];
517 
518     _channelData = new ChannelData[_numChans];
519 
520     int i = 0;
521 
522     for (ChannelList::ConstIterator c = channels.begin();
523      c != channels.end();
524      ++c, ++i)
525     {
526     _channelData[i].ys = c.channel().ySampling;
527     _channelData[i].type = c.channel().type;
528     _channelData[i].pLinear = c.channel().pLinear;
529     _channelData[i].size =
530         pixelTypeSize (c.channel().type) / pixelTypeSize (HALF);
531     }
532 
533     const Box2i &dataWindow = hdr.dataWindow();
534 
535     _minX = dataWindow.min.x;
536     _maxX = dataWindow.max.x;
537     _maxY = dataWindow.max.y;
538 
539     //
540     // We can support uncompressed data in the machine's native
541     // format only if all image channels are of type HALF.
542     //
543 
544     assert (sizeof (unsigned short) == pixelTypeSize (HALF));
545 
546     if (_numChans == numHalfChans)
547     _format = NATIVE;
548 }
549 
550 
~B44Compressor()551 B44Compressor::~B44Compressor ()
552 {
553     delete [] _tmpBuffer;
554     delete [] _outBuffer;
555     delete [] _channelData;
556 }
557 
558 
559 int
numScanLines() const560 B44Compressor::numScanLines () const
561 {
562     return _numScanLines;
563 }
564 
565 
566 Compressor::Format
format() const567 B44Compressor::format () const
568 {
569     return _format;
570 }
571 
572 
573 int
compress(const char * inPtr,int inSize,int minY,const char * & outPtr)574 B44Compressor::compress (const char *inPtr,
575              int inSize,
576              int minY,
577              const char *&outPtr)
578 {
579     return compress (inPtr,
580              inSize,
581              Box2i (V2i (_minX, minY),
582                 V2i (_maxX, minY + numScanLines() - 1)),
583              outPtr);
584 }
585 
586 
587 int
compressTile(const char * inPtr,int inSize,Imath::Box2i range,const char * & outPtr)588 B44Compressor::compressTile (const char *inPtr,
589                  int inSize,
590                  Imath::Box2i range,
591                  const char *&outPtr)
592 {
593     return compress (inPtr, inSize, range, outPtr);
594 }
595 
596 
597 int
uncompress(const char * inPtr,int inSize,int minY,const char * & outPtr)598 B44Compressor::uncompress (const char *inPtr,
599                int inSize,
600                int minY,
601                const char *&outPtr)
602 {
603     return uncompress (inPtr,
604                inSize,
605                Box2i (V2i (_minX, minY),
606                   V2i (_maxX, minY + numScanLines() - 1)),
607                outPtr);
608 }
609 
610 
611 int
uncompressTile(const char * inPtr,int inSize,Imath::Box2i range,const char * & outPtr)612 B44Compressor::uncompressTile (const char *inPtr,
613                    int inSize,
614                    Imath::Box2i range,
615                    const char *&outPtr)
616 {
617     return uncompress (inPtr, inSize, range, outPtr);
618 }
619 
620 
621 int
compress(const char * inPtr,int inSize,Imath::Box2i range,const char * & outPtr)622 B44Compressor::compress (const char *inPtr,
623              int inSize,
624              Imath::Box2i range,
625              const char *&outPtr)
626 {
627     //
628     // Compress a block of pixel data:  First copy the input pixels
629     // from the input buffer into _tmpBuffer, rearranging them such
630     // that blocks of 4x4 pixels of a single channel can be accessed
631     // conveniently.  Then compress each 4x4 block of HALF pixel data
632     // and append the result to the output buffer.  Copy UINT and
633     // FLOAT data to the output buffer without compressing them.
634     //
635 
636     outPtr = _outBuffer;
637 
638     if (inSize == 0)
639     {
640     //
641     // Special case - empty input buffer.
642     //
643 
644     return 0;
645     }
646 
647     //
648     // For each channel, detemine how many pixels are stored
649     // in the input buffer, and where those pixels will be
650     // placed in _tmpBuffer.
651     //
652 
653     int minX = range.min.x;
654     int maxX = min (range.max.x, _maxX);
655     int minY = range.min.y;
656     int maxY = min (range.max.y, _maxY);
657 
658     unsigned short *tmpBufferEnd = _tmpBuffer;
659     int i = 0;
660 
661     for (ChannelList::ConstIterator c = _channels.begin();
662      c != _channels.end();
663      ++c, ++i)
664     {
665     ChannelData &cd = _channelData[i];
666 
667     cd.start = tmpBufferEnd;
668     cd.end = cd.start;
669 
670     cd.nx = numSamples (c.channel().xSampling, minX, maxX);
671     cd.ny = numSamples (c.channel().ySampling, minY, maxY);
672 
673     tmpBufferEnd += cd.nx * cd.ny * cd.size;
674     }
675 
676     if (_format == XDR)
677     {
678     //
679     // The data in the input buffer are in the machine-independent
680     // Xdr format.  Copy the HALF channels into _tmpBuffer and
681     // convert them back into native format for compression.
682     // Copy UINT and FLOAT channels verbatim into _tmpBuffer.
683     //
684 
685     for (int y = minY; y <= maxY; ++y)
686     {
687         for (int i = 0; i < _numChans; ++i)
688         {
689         ChannelData &cd = _channelData[i];
690 
691         if (modp (y, cd.ys) != 0)
692             continue;
693 
694         if (cd.type == HALF)
695         {
696             for (int x = cd.nx; x > 0; --x)
697             {
698             Xdr::read <CharPtrIO> (inPtr, *cd.end);
699             ++cd.end;
700             }
701         }
702         else
703         {
704             int n = cd.nx * cd.size;
705             memcpy (cd.end, inPtr, n * sizeof (unsigned short));
706             inPtr += n * sizeof (unsigned short);
707             cd.end += n;
708         }
709         }
710     }
711     }
712     else
713     {
714     //
715     // The input buffer contains only HALF channels, and they
716     // are in native, machine-dependent format.  Copy the pixels
717     // into _tmpBuffer.
718     //
719 
720     for (int y = minY; y <= maxY; ++y)
721     {
722         for (int i = 0; i < _numChans; ++i)
723         {
724         ChannelData &cd = _channelData[i];
725 
726         #if defined (DEBUG)
727             assert (cd.type == HALF);
728         #endif
729 
730         if (modp (y, cd.ys) != 0)
731             continue;
732 
733         int n = cd.nx * cd.size;
734         memcpy (cd.end, inPtr, n * sizeof (unsigned short));
735         inPtr  += n * sizeof (unsigned short);
736         cd.end += n;
737         }
738     }
739     }
740 
741     //
742     // The pixels for each channel have been packed into a contiguous
743     // block in _tmpBuffer.  HALF channels are in native format; UINT
744     // and FLOAT channels are in Xdr format.
745     //
746 
747     #if defined (DEBUG)
748 
749     for (int i = 1; i < _numChans; ++i)
750         assert (_channelData[i-1].end == _channelData[i].start);
751 
752     assert (_channelData[_numChans-1].end == tmpBufferEnd);
753 
754     #endif
755 
756     //
757     // For each HALF channel, split the data in _tmpBuffer into 4x4
758     // pixel blocks.  Compress each block and append the compressed
759     // data to the output buffer.
760     //
761     // UINT and FLOAT channels are copied from _tmpBuffer into the
762     // output buffer without further processing.
763     //
764 
765     char *outEnd = _outBuffer;
766 
767     for (int i = 0; i < _numChans; ++i)
768     {
769     ChannelData &cd = _channelData[i];
770 
771     if (cd.type != HALF)
772     {
773         //
774         // UINT or FLOAT channel.
775         //
776 
777         int n = cd.nx * cd.ny * cd.size * sizeof (unsigned short);
778         memcpy (outEnd, cd.start, n);
779         outEnd += n;
780 
781         continue;
782     }
783 
784     //
785     // HALF channel
786     //
787 
788     for (int y = 0; y < cd.ny; y += 4)
789     {
790         //
791         // Copy the next 4x4 pixel block into array s.
792         // If the width, cd.nx, or the height, cd.ny, of
793         // the pixel data in _tmpBuffer is not divisible
794         // by 4, then pad the data by repeating the
795         // rightmost column and the bottom row.
796         //
797 
798         unsigned short *row0 = cd.start + y * cd.nx;
799         unsigned short *row1 = row0 + cd.nx;
800         unsigned short *row2 = row1 + cd.nx;
801         unsigned short *row3 = row2 + cd.nx;
802 
803         if (y + 3 >= cd.ny)
804         {
805         if (y + 1 >= cd.ny)
806             row1 = row0;
807 
808         if (y + 2 >= cd.ny)
809             row2 = row1;
810 
811         row3 = row2;
812         }
813 
814         for (int x = 0; x < cd.nx; x += 4)
815         {
816         unsigned short s[16];
817 
818         if (x + 3 >= cd.nx)
819         {
820             int n = cd.nx - x;
821 
822             for (int i = 0; i < 4; ++i)
823             {
824             int j = min (i, n - 1);
825 
826             s[i +  0] = row0[j];
827             s[i +  4] = row1[j];
828             s[i +  8] = row2[j];
829             s[i + 12] = row3[j];
830             }
831         }
832         else
833         {
834             memcpy (&s[ 0], row0, 4 * sizeof (unsigned short));
835             memcpy (&s[ 4], row1, 4 * sizeof (unsigned short));
836             memcpy (&s[ 8], row2, 4 * sizeof (unsigned short));
837             memcpy (&s[12], row3, 4 * sizeof (unsigned short));
838         }
839 
840         row0 += 4;
841         row1 += 4;
842         row2 += 4;
843         row3 += 4;
844 
845         //
846         // Compress the contents of array s and append the
847         // results to the output buffer.
848         //
849 
850         if (cd.pLinear)
851             convertFromLinear (s);
852 
853         outEnd += pack (s, (unsigned char *) outEnd,
854                 _optFlatFields, !cd.pLinear);
855         }
856     }
857     }
858 
859     return outEnd - _outBuffer;
860 }
861 
862 
863 int
uncompress(const char * inPtr,int inSize,Imath::Box2i range,const char * & outPtr)864 B44Compressor::uncompress (const char *inPtr,
865                int inSize,
866                Imath::Box2i range,
867                const char *&outPtr)
868 {
869     //
870     // This function is the reverse of the compress() function,
871     // above.  First all pixels are moved from the input buffer
872     // into _tmpBuffer.  UINT and FLOAT channels are copied
873     // verbatim; HALF channels are uncompressed in blocks of
874     // 4x4 pixels.  Then the pixels in _tmpBuffer are copied
875     // into the output buffer and rearranged such that the data
876     // for for each scan line form a contiguous block.
877     //
878 
879     outPtr = _outBuffer;
880 
881     if (inSize == 0)
882     {
883     return 0;
884     }
885 
886     int minX = range.min.x;
887     int maxX = min (range.max.x, _maxX);
888     int minY = range.min.y;
889     int maxY = min (range.max.y, _maxY);
890 
891     unsigned short *tmpBufferEnd = _tmpBuffer;
892     int i = 0;
893 
894     for (ChannelList::ConstIterator c = _channels.begin();
895      c != _channels.end();
896      ++c, ++i)
897     {
898     ChannelData &cd = _channelData[i];
899 
900     cd.start = tmpBufferEnd;
901     cd.end = cd.start;
902 
903     cd.nx = numSamples (c.channel().xSampling, minX, maxX);
904     cd.ny = numSamples (c.channel().ySampling, minY, maxY);
905 
906     tmpBufferEnd += cd.nx * cd.ny * cd.size;
907     }
908 
909     for (int i = 0; i < _numChans; ++i)
910     {
911     ChannelData &cd = _channelData[i];
912 
913     if (cd.type != HALF)
914     {
915         //
916         // UINT or FLOAT channel.
917         //
918 
919         int n = cd.nx * cd.ny * cd.size * sizeof (unsigned short);
920 
921         if (inSize < n)
922         notEnoughData();
923 
924         memcpy (cd.start, inPtr, n);
925         inPtr += n;
926         inSize -= n;
927 
928         continue;
929     }
930 
931     //
932     // HALF channel
933     //
934 
935     for (int y = 0; y < cd.ny; y += 4)
936     {
937         unsigned short *row0 = cd.start + y * cd.nx;
938         unsigned short *row1 = row0 + cd.nx;
939         unsigned short *row2 = row1 + cd.nx;
940         unsigned short *row3 = row2 + cd.nx;
941 
942         for (int x = 0; x < cd.nx; x += 4)
943         {
944         unsigned short s[16];
945 
946         if (inSize < 3)
947             notEnoughData();
948 
949         if (((const unsigned char *)inPtr)[2] == 0xfc)
950         {
951             unpack3 ((const unsigned char *)inPtr, s);
952             inPtr += 3;
953             inSize -= 3;
954         }
955         else
956         {
957             if (inSize < 14)
958             notEnoughData();
959 
960             unpack14 ((const unsigned char *)inPtr, s);
961             inPtr += 14;
962             inSize -= 14;
963         }
964 
965         if (cd.pLinear)
966             convertToLinear (s);
967 
968         int n = (x + 3 < cd.nx)?
969                 4 * sizeof (unsigned short) :
970                 (cd.nx - x) * sizeof (unsigned short);
971 
972         if (y + 3 < cd.ny)
973         {
974             memcpy (row0, &s[ 0], n);
975             memcpy (row1, &s[ 4], n);
976             memcpy (row2, &s[ 8], n);
977             memcpy (row3, &s[12], n);
978         }
979         else
980         {
981             memcpy (row0, &s[ 0], n);
982 
983             if (y + 1 < cd.ny)
984             memcpy (row1, &s[ 4], n);
985 
986             if (y + 2 < cd.ny)
987             memcpy (row2, &s[ 8], n);
988         }
989 
990         row0 += 4;
991         row1 += 4;
992         row2 += 4;
993         row3 += 4;
994         }
995     }
996     }
997 
998     char *outEnd = _outBuffer;
999 
1000     if (_format == XDR)
1001     {
1002     for (int y = minY; y <= maxY; ++y)
1003     {
1004         for (int i = 0; i < _numChans; ++i)
1005         {
1006         ChannelData &cd = _channelData[i];
1007 
1008         if (modp (y, cd.ys) != 0)
1009             continue;
1010 
1011         if (cd.type == HALF)
1012         {
1013             for (int x = cd.nx; x > 0; --x)
1014             {
1015             Xdr::write <CharPtrIO> (outEnd, *cd.end);
1016             ++cd.end;
1017             }
1018         }
1019         else
1020         {
1021             int n = cd.nx * cd.size;
1022             memcpy (outEnd, cd.end, n * sizeof (unsigned short));
1023             outEnd += n * sizeof (unsigned short);
1024             cd.end += n;
1025         }
1026         }
1027     }
1028     }
1029     else
1030     {
1031     for (int y = minY; y <= maxY; ++y)
1032     {
1033         for (int i = 0; i < _numChans; ++i)
1034         {
1035         ChannelData &cd = _channelData[i];
1036 
1037         #if defined (DEBUG)
1038             assert (cd.type == HALF);
1039         #endif
1040 
1041         if (modp (y, cd.ys) != 0)
1042             continue;
1043 
1044         int n = cd.nx * cd.size;
1045         memcpy (outEnd, cd.end, n * sizeof (unsigned short));
1046         outEnd += n * sizeof (unsigned short);
1047         cd.end += n;
1048         }
1049     }
1050     }
1051 
1052     #if defined (DEBUG)
1053 
1054     for (int i = 1; i < _numChans; ++i)
1055         assert (_channelData[i-1].end == _channelData[i].start);
1056 
1057     assert (_channelData[_numChans-1].end == tmpBufferEnd);
1058 
1059     #endif
1060 
1061     if (inSize > 0)
1062     tooMuchData();
1063 
1064     outPtr = _outBuffer;
1065     return outEnd - _outBuffer;
1066 }
1067 
1068 
1069 } // namespace Imf
1070