Coverage Report

Created: 2026-02-14 07:18

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