Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/3rdparty/openexr/IlmImf/ImfB44Compressor.cpp
16337 views
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
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
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
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
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
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
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
437
notEnoughData ()
438
{
439
throw Iex::InputExc ("Error decompressing data "
440
"(input data are shorter than expected).");
441
}
442
443
444
void
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
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
551
B44Compressor::~B44Compressor ()
552
{
553
delete [] _tmpBuffer;
554
delete [] _outBuffer;
555
delete [] _channelData;
556
}
557
558
559
int
560
B44Compressor::numScanLines () const
561
{
562
return _numScanLines;
563
}
564
565
566
Compressor::Format
567
B44Compressor::format () const
568
{
569
return _format;
570
}
571
572
573
int
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
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
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
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
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
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
1071