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