Coverage Report

Created: 2025-06-12 06:52

/src/opencv/3rdparty/openexr/IlmImf/ImfPxr24Compressor.cpp
Line
Count
Source (jump to first uncovered line)
1
/////////////////////////////////////////////////////////////////////////////
2
//
3
// Copyright (c) 2004, Pixar Animation Studios
4
//
5
// All rights reserved.
6
//
7
// Redistribution and use in source and binary forms, with or without
8
// modification, are permitted provided that the following conditions  are
9
// met:
10
// *       Redistributions of source code must retain the above  copyright
11
// notice, this list of conditions and the following disclaimer.
12
// *       Redistributions in binary form must reproduce the above
13
// copyright notice, this list of conditions and the following  disclaimer
14
// in the documentation and/or other materials provided with the
15
// distribution.
16
// *       Neither the name of Pixar Animation Studios nor the names of
17
// its contributors may be used to endorse or promote products derived
18
// from this software without specific prior written permission.
19
//
20
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
//
32
/////////////////////////////////////////////////////////////////////////////
33
34
//-----------------------------------------------------------------------------
35
//
36
//  class Pxr24Compressor
37
//
38
//  This compressor is based on source code that was contributed to
39
//  OpenEXR by Pixar Animation Studios.  The compression method was
40
//  developed by Loren Carpenter.
41
//
42
//  The compressor preprocesses the pixel data to reduce entropy,
43
//  and then calls zlib.
44
//
45
//  Compression of HALF and UINT channels is lossless, but compressing
46
//  FLOAT channels is lossy: 32-bit floating-point numbers are converted
47
//  to 24 bits by rounding the significand to 15 bits.
48
//
49
//  When the compressor is invoked, the caller has already arranged
50
//  the pixel data so that the values for each channel appear in a
51
//  contiguous block of memory.  The compressor converts the pixel
52
//  values to unsigned integers: For UINT, this is a no-op.  HALF
53
//  values are simply re-interpreted as 16-bit integers.  FLOAT
54
//  values are converted to 24 bits, and the resulting bit patterns
55
//  are interpreted as integers.  The compressor then replaces each
56
//  value with the difference between the value and its left neighbor.
57
//  This turns flat fields in the image into zeroes, and ramps into
58
//  strings of similar values.  Next, each difference is split into
59
//  2, 3 or 4 bytes, and the bytes are transposed so that all the
60
//  most significant bytes end up in a contiguous block, followed
61
//  by the second most significant bytes, and so on.  The resulting
62
//  string of bytes is compressed with zlib.
63
//
64
//-----------------------------------------------------------------------------
65
66
#include "ImfPxr24Compressor.h"
67
#include "ImfHeader.h"
68
#include "ImfChannelList.h"
69
#include "ImfMisc.h"
70
#include "ImfCheckedArithmetic.h"
71
#include "ImfNamespace.h"
72
73
#include <ImathFun.h>
74
#include <Iex.h>
75
76
#include <half.h>
77
#include <zlib.h>
78
#include <assert.h>
79
#include <algorithm>
80
81
using namespace std;
82
using namespace IMATH_NAMESPACE;
83
84
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
85
86
namespace {
87
88
//
89
// Conversion from 32-bit to 24-bit floating-point numbers.
90
// Conversion back to 32 bits is simply an 8-bit shift to the left.
91
//
92
93
inline unsigned int
94
floatToFloat24 (float f)
95
0
{
96
0
    union
97
0
    {
98
0
  float   f;
99
0
  unsigned int  i;
100
0
    } u;
101
102
0
    u.f = f;
103
104
    //
105
    // Disassemble the 32-bit floating point number, f,
106
    // into sign, s, exponent, e, and significand, m.
107
    //
108
109
0
    unsigned int s = u.i & 0x80000000;
110
0
    unsigned int e = u.i & 0x7f800000;
111
0
    unsigned int m = u.i & 0x007fffff;
112
0
    unsigned int i;
113
114
0
    if (e == 0x7f800000)
115
0
    {
116
0
  if (m)
117
0
  {
118
      //
119
      // F is a NAN; we preserve the sign bit and
120
      // the 15 leftmost bits of the significand,
121
      // with one exception: If the 15 leftmost
122
      // bits are all zero, the NAN would turn
123
      // into an infinity, so we have to set at
124
      // least one bit in the significand.
125
      //
126
127
0
      m >>= 8;
128
0
      i = (e >> 8) | m | (m == 0);
129
0
  }
130
0
  else
131
0
  {
132
      //
133
      // F is an infinity.
134
      //
135
136
0
      i = e >> 8;
137
0
  }
138
0
    }
139
0
    else
140
0
    {
141
  //
142
  // F is finite, round the significand to 15 bits.
143
  //
144
145
0
  i = ((e | m) + (m & 0x00000080)) >> 8;
146
147
0
  if (i >= 0x7f8000)
148
0
  {
149
      //
150
      // F was close to FLT_MAX, and the significand was
151
      // rounded up, resulting in an exponent overflow.
152
      // Avoid the overflow by truncating the significand
153
      // instead of rounding it.
154
      //
155
156
0
      i = (e | m) >> 8;
157
0
  }
158
0
    }
159
160
0
    return (s >> 8) | i;
161
0
}
162
163
164
void
165
notEnoughData ()
166
0
{
167
0
    throw IEX_NAMESPACE::InputExc ("Error decompressing data "
168
0
       "(input data are shorter than expected).");
169
0
}
170
171
172
void
173
tooMuchData ()
174
0
{
175
0
    throw IEX_NAMESPACE::InputExc ("Error decompressing data "
176
0
       "(input data are longer than expected).");
177
0
}
178
179
} // namespace
180
181
182
Pxr24Compressor::Pxr24Compressor (const Header &hdr,
183
          size_t maxScanLineSize,
184
          size_t numScanLines)
185
:
186
0
    Compressor (hdr),
187
0
    _maxScanLineSize (maxScanLineSize),
188
0
    _numScanLines (numScanLines),
189
0
    _tmpBuffer (0),
190
0
    _outBuffer (0),
191
0
    _channels (hdr.channels())
192
0
{
193
0
    size_t maxInBytes =
194
0
        uiMult (maxScanLineSize, numScanLines);
195
196
0
    size_t maxOutBytes =
197
0
        uiAdd (uiAdd (maxInBytes,
198
0
                      size_t (ceil (maxInBytes * 0.01))),
199
0
               size_t (100));
200
201
0
    _tmpBuffer = new unsigned char [maxInBytes];
202
0
    _outBuffer = new char [maxOutBytes];
203
204
0
    const Box2i &dataWindow = hdr.dataWindow();
205
206
0
    _minX = dataWindow.min.x;
207
0
    _maxX = dataWindow.max.x;
208
0
    _maxY = dataWindow.max.y;
209
0
}
210
211
212
Pxr24Compressor::~Pxr24Compressor ()
213
0
{
214
0
    delete [] _tmpBuffer;
215
0
    delete [] _outBuffer;
216
0
}
217
218
219
int
220
Pxr24Compressor::numScanLines () const
221
0
{
222
0
    return _numScanLines;
223
0
}
224
225
226
Compressor::Format
227
Pxr24Compressor::format () const
228
0
{
229
0
    return NATIVE;
230
0
}
231
232
233
int
234
Pxr24Compressor::compress (const char *inPtr,
235
         int inSize,
236
         int minY,
237
         const char *&outPtr)
238
0
{
239
0
    return compress (inPtr,
240
0
               inSize,
241
0
         Box2i (V2i (_minX, minY),
242
0
          V2i (_maxX, minY + _numScanLines - 1)),
243
0
         outPtr);
244
0
}
245
246
        
247
int
248
Pxr24Compressor::compressTile (const char *inPtr,
249
             int inSize,
250
             Box2i range,
251
             const char *&outPtr)
252
0
{
253
0
    return compress (inPtr, inSize, range, outPtr);
254
0
}
255
256
257
int
258
Pxr24Compressor::uncompress (const char *inPtr,
259
           int inSize,
260
           int minY,
261
           const char *&outPtr)
262
0
{
263
0
    return uncompress (inPtr,
264
0
                 inSize,
265
0
           Box2i (V2i (_minX, minY),
266
0
            V2i (_maxX, minY + _numScanLines - 1)),
267
0
           outPtr);
268
0
}
269
270
    
271
int
272
Pxr24Compressor::uncompressTile (const char *inPtr,
273
         int inSize,
274
         Box2i range,
275
         const char *&outPtr)
276
0
{
277
0
    return uncompress (inPtr, inSize, range, outPtr);
278
0
}
279
280
281
int
282
Pxr24Compressor::compress (const char *inPtr,
283
         int inSize,
284
         Box2i range,
285
         const char *&outPtr)
286
0
{
287
0
    if (inSize == 0)
288
0
    {
289
0
  outPtr = _outBuffer;
290
0
  return 0;
291
0
    }
292
293
0
    int minX = range.min.x;
294
0
    int maxX = min (range.max.x, _maxX);
295
0
    int minY = range.min.y;
296
0
    int maxY = min (range.max.y, _maxY);
297
298
0
    unsigned char *tmpBufferEnd = _tmpBuffer;
299
300
0
    for (int y = minY; y <= maxY; ++y)
301
0
    {
302
0
  for (ChannelList::ConstIterator i = _channels.begin();
303
0
       i != _channels.end();
304
0
       ++i)
305
0
  {
306
0
      const Channel &c = i.channel();
307
308
0
      if (modp (y, c.ySampling) != 0)
309
0
    continue;
310
311
0
      int n = numSamples (c.xSampling, minX, maxX);
312
313
0
      unsigned char *ptr[4];
314
0
      unsigned int previousPixel = 0;
315
316
0
      switch (c.type)
317
0
      {
318
0
        case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
319
320
0
    ptr[0] = tmpBufferEnd;
321
0
    ptr[1] = ptr[0] + n;
322
0
    ptr[2] = ptr[1] + n;
323
0
    ptr[3] = ptr[2] + n;
324
0
    tmpBufferEnd = ptr[3] + n;
325
326
0
    for (int j = 0; j < n; ++j)
327
0
    {
328
0
        unsigned int pixel;
329
0
        char *pPtr = (char *) &pixel;
330
331
0
        for (size_t k = 0; k < sizeof (pixel); ++k)
332
0
      *pPtr++ = *inPtr++;
333
334
0
        unsigned int diff = pixel - previousPixel;
335
0
        previousPixel = pixel;
336
337
0
        *(ptr[0]++) = diff >> 24;
338
0
        *(ptr[1]++) = diff >> 16;
339
0
        *(ptr[2]++) = diff >> 8;
340
0
        *(ptr[3]++) = diff;
341
0
    }
342
343
0
    break;
344
345
0
        case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
346
347
0
    ptr[0] = tmpBufferEnd;
348
0
    ptr[1] = ptr[0] + n;
349
0
    tmpBufferEnd = ptr[1] + n;
350
351
0
    for (int j = 0; j < n; ++j)
352
0
    {
353
0
        half pixel;
354
355
0
        pixel = *(const half *) inPtr;
356
0
        inPtr += sizeof (half);
357
358
0
        unsigned int diff = pixel.bits() - previousPixel;
359
0
        previousPixel = pixel.bits();
360
361
0
        *(ptr[0]++) = diff >> 8;
362
0
        *(ptr[1]++) = diff;
363
0
    }
364
365
0
    break;
366
367
0
        case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
368
369
0
    ptr[0] = tmpBufferEnd;
370
0
    ptr[1] = ptr[0] + n;
371
0
    ptr[2] = ptr[1] + n;
372
0
    tmpBufferEnd = ptr[2] + n;
373
374
0
    for (int j = 0; j < n; ++j)
375
0
    {
376
0
        float pixel;
377
0
        char *pPtr = (char *) &pixel;
378
379
0
        for (size_t k = 0; k < sizeof (pixel); ++k)
380
0
      *pPtr++ = *inPtr++;
381
382
0
        unsigned int pixel24 = floatToFloat24 (pixel);
383
0
        unsigned int diff = pixel24 - previousPixel;
384
0
        previousPixel = pixel24;
385
386
0
        *(ptr[0]++) = diff >> 16;
387
0
        *(ptr[1]++) = diff >> 8;
388
0
        *(ptr[2]++) = diff;
389
0
    }
390
391
0
    break;
392
393
0
        default:
394
395
0
    assert (false);
396
0
      }
397
0
  }
398
0
    }
399
400
0
    uLongf outSize = int (ceil ((tmpBufferEnd - _tmpBuffer) * 1.01)) + 100;
401
402
0
    if (Z_OK != ::compress ((Bytef *) _outBuffer,
403
0
          &outSize,
404
0
          (const Bytef *) _tmpBuffer,
405
0
          tmpBufferEnd - _tmpBuffer))
406
0
    {
407
0
  throw IEX_NAMESPACE::BaseExc ("Data compression (zlib) failed.");
408
0
    }
409
410
0
    outPtr = _outBuffer;
411
0
    return outSize;
412
0
}
413
414
 
415
int   
416
Pxr24Compressor::uncompress (const char *inPtr,
417
           int inSize,
418
           Box2i range,
419
           const char *&outPtr)
420
0
{
421
0
    if (inSize == 0)
422
0
    {
423
0
  outPtr = _outBuffer;
424
0
  return 0;
425
0
    }
426
427
0
    uLongf tmpSize = _maxScanLineSize * _numScanLines;
428
429
0
    if (Z_OK != ::uncompress ((Bytef *)_tmpBuffer,
430
0
            &tmpSize,
431
0
            (const Bytef *) inPtr,
432
0
            inSize))
433
0
    {
434
0
  throw IEX_NAMESPACE::InputExc ("Data decompression (zlib) failed.");
435
0
    }
436
437
0
    int minX = range.min.x;
438
0
    int maxX = min (range.max.x, _maxX);
439
0
    int minY = range.min.y;
440
0
    int maxY = min (range.max.y, _maxY);
441
442
0
    const unsigned char *tmpBufferEnd = _tmpBuffer;
443
0
    char *writePtr = _outBuffer;
444
445
0
    for (int y = minY; y <= maxY; ++y)
446
0
    {
447
0
  for (ChannelList::ConstIterator i = _channels.begin();
448
0
       i != _channels.end();
449
0
       ++i)
450
0
  {
451
0
      const Channel &c = i.channel();
452
453
0
      if (modp (y, c.ySampling) != 0)
454
0
    continue;
455
456
0
      int n = numSamples (c.xSampling, minX, maxX);
457
458
0
      const unsigned char *ptr[4];
459
0
      unsigned int pixel = 0;
460
461
0
      switch (c.type)
462
0
      {
463
0
        case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
464
465
0
    ptr[0] = tmpBufferEnd;
466
0
    ptr[1] = ptr[0] + n;
467
0
    ptr[2] = ptr[1] + n;
468
0
    ptr[3] = ptr[2] + n;
469
0
    tmpBufferEnd = ptr[3] + n;
470
471
0
    if ( (uLongf)(tmpBufferEnd - _tmpBuffer) > tmpSize)
472
0
        notEnoughData();
473
474
0
    for (int j = 0; j < n; ++j)
475
0
    {
476
0
        unsigned int diff = (*(ptr[0]++) << 24) |
477
0
          (*(ptr[1]++) << 16) |
478
0
          (*(ptr[2]++) <<  8) |
479
0
           *(ptr[3]++);
480
481
0
        pixel += diff;
482
483
0
        char *pPtr = (char *) &pixel;
484
485
0
        for (size_t k = 0; k < sizeof (pixel); ++k)
486
0
      *writePtr++ = *pPtr++;
487
0
    }
488
489
0
    break;
490
491
0
        case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
492
493
0
    ptr[0] = tmpBufferEnd;
494
0
    ptr[1] = ptr[0] + n;
495
0
    tmpBufferEnd = ptr[1] + n;
496
497
0
        if ( (uLongf)(tmpBufferEnd - _tmpBuffer) > tmpSize)
498
0
        notEnoughData();
499
500
0
    for (int j = 0; j < n; ++j)
501
0
    {
502
0
        unsigned int diff = (*(ptr[0]++) << 8) |
503
0
           *(ptr[1]++);
504
505
0
        pixel += diff;
506
507
0
        half * hPtr = (half *) writePtr;
508
0
        hPtr->setBits ((unsigned short) pixel);
509
0
        writePtr += sizeof (half);
510
0
    }
511
512
0
    break;
513
514
0
        case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
515
516
0
    ptr[0] = tmpBufferEnd;
517
0
    ptr[1] = ptr[0] + n;
518
0
    ptr[2] = ptr[1] + n;
519
0
    tmpBufferEnd = ptr[2] + n;
520
521
0
        if ( (uLongf) (tmpBufferEnd - _tmpBuffer) > tmpSize)
522
0
        notEnoughData();
523
524
0
    for (int j = 0; j < n; ++j)
525
0
    {
526
0
        unsigned int diff = (*(ptr[0]++) << 24) |
527
0
          (*(ptr[1]++) << 16) |
528
0
          (*(ptr[2]++) <<  8);
529
0
        pixel += diff;
530
531
0
        char *pPtr = (char *) &pixel;
532
533
0
        for (size_t k = 0; k < sizeof (pixel); ++k)
534
0
      *writePtr++ = *pPtr++;
535
0
    }
536
537
0
    break;
538
539
0
        default:
540
541
0
    assert (false);
542
0
      }
543
0
  }
544
0
    }
545
546
0
    if ((uLongf) (tmpBufferEnd - _tmpBuffer) < tmpSize)
547
0
  tooMuchData();
548
549
0
    outPtr = _outBuffer;
550
0
    return writePtr - _outBuffer;
551
0
}
552
553
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT