Coverage Report

Created: 2026-08-14 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opencv/3rdparty/openexr/IlmImf/ImfDwaCompressor.cpp
Line
Count
Source
1
///////////////////////////////////////////////////////////////////////////
2
//
3
// Copyright (c) 2009-2014 DreamWorks Animation LLC. 
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 DreamWorks Animation 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 DwaCompressor -- Store lossy RGB data by quantizing
37
//                          DCT components.
38
//
39
// First, we try and figure out what compression strategy to take
40
// based in channel name. For RGB channels, we want a lossy method
41
// described below. But, if we have alpha, we should do something
42
// different (and probably using RLE). If we have depth, or velocity,
43
// or something else, just fall back to ZIP. The rules for deciding 
44
// which strategy to use are setup in initializeDefaultChannelRules().
45
// When writing a file, the relevant rules needed to decode are written
46
// into the start of the data block, making a self-contained file. 
47
// If initializeDefaultChannelRules() doesn't quite suite your naming
48
// conventions, you can adjust the rules without breaking decoder
49
// compatability.
50
//
51
// If we're going to lossy compress R, G, or B channels, it's easier
52
// to toss bits in a more perceptual uniform space. One could argue
53
// at length as to what constitutes perceptually uniform, expecially 
54
// when storing either scene/input/focal plane referred and output referred
55
// data. 
56
//
57
// We'll compromise. For values <= 1, we use a traditional power function
58
// (without any of that straight-line business at the bottom). For values > 1,
59
// we want something more like a log function, since power functions blow
60
// up. At 1, we want a smooth blend between the functions. So, we use a 
61
// piecewise function that does just that - see dwaLookups.cpp for 
62
// a little more detail.
63
//
64
// Also, if we find that we have R, G, and B channels from the same layer,
65
// we can get a bit more compression efficiency by transforming to a Y'CbCr
66
// space. We use the 709 transform, but with Cb,Cr = 0 for an input of 
67
// (0, 0, 0), instead of the traditional Cb,Cr = .5. Shifting the zero point
68
// makes no sense with large range data. Transforms are done to from 
69
// the perceptual space data, not the linear-light space data (R'G'B' ->
70
// (Y'CbCr, not RGB -> YCbCr).
71
//
72
// Next, we forward DCT the data. This is done with a floating
73
// point DCT, as we don't really have control over the src range. The 
74
// resulting values are dropped to half-float precision. 
75
//
76
// Now, we need to quantize. Quantization departs from the usual way 
77
// of dividing and rounding. Instead, we start with some floating 
78
// point "base-error" value. From this, we can derive quantization 
79
// error for each DCT component. Take the standard JPEG quantization
80
// tables and normalize them by the smallest value. Then, multiply
81
// the normalized quant tables by our base-error value. This gives
82
// a range of errors for each DCT component.
83
//
84
// For each DCT component, we want to find a quantized value that 
85
// is within +- the per-component error. Pick the quantized value
86
// that has the fewest bits set in its' binary representation. 
87
// Brute-forcing the search would make for extremly inefficient 
88
// compression. Fortunatly, we can precompute a table to assist 
89
// with this search. 
90
//
91
// For each 16-bit float value, there are at most 15 other values with
92
// fewer bits set. We can precompute these values in a compact form, since
93
// many source values have far fewer that 15 possible quantized values. 
94
// Now, instead of searching the entire range +- the component error,
95
// we can just search at most 15 quantization candidates. The search can
96
// be accelerated a bit more by sorting the candidates by the 
97
// number of bits set, in increasing order. Then, the search can stop
98
// once a candidate is found w/i the per-component quantization 
99
// error range.
100
//
101
// The quantization strategy has the side-benefit that there is no
102
// de-quantization step upon decode, so we don't bother recording
103
// the quantization table.
104
//
105
// Ok. So we now have quantized values. Time for entropy coding. We
106
// can use either static Huffman or zlib/DEFLATE. The static Huffman
107
// is more efficient at compacting data, but can have a greater 
108
// overhead, especially for smaller tile/strip sizes. 
109
//
110
// There is some additional fun, like ZIP compressing the DC components
111
// instead of Huffman/zlib, which helps make things slightly smaller.
112
//
113
// Compression level is controlled by setting an int/float/double attribute
114
// on the header named "dwaCompressionLevel". This is a thinly veiled name for 
115
// the "base-error" value mentioned above. The "base-error" is just
116
// dwaCompressionLevel / 100000. The default value of 45.0 is generally 
117
// pretty good at generating "visually lossless" values at reasonable
118
// data rates. Setting dwaCompressionLevel to 0 should result in no additional
119
// quantization at the quantization stage (though there may be 
120
// quantization in practice at the CSC/DCT steps). But if you really
121
// want lossless compression, there are pleanty of other choices 
122
// of compressors ;)
123
//
124
// When dealing with FLOAT source buffers, we first quantize the source
125
// to HALF and continue down as we would for HALF source.
126
//
127
//---------------------------------------------------
128
129
130
#include "ImfDwaCompressor.h"
131
#include "ImfDwaCompressorSimd.h"
132
133
#include "ImfChannelList.h"
134
#include "ImfStandardAttributes.h"
135
#include "ImfHeader.h"
136
#include "ImfHuf.h"
137
#include "ImfInt64.h"
138
#include "ImfIntAttribute.h"
139
#include "ImfIO.h"
140
#include "ImfMisc.h"
141
#include "ImfNamespace.h"
142
#include "ImfRle.h"
143
#include "ImfSimd.h"
144
#include "ImfSystemSpecific.h"
145
#include "ImfXdr.h"
146
#include "ImfZip.h"
147
148
#include "ImathFun.h"
149
#include "ImathBox.h"
150
#include "ImathVec.h"
151
#include "half.h"
152
#include "halfLimits.h"
153
154
#include "dwaLookups.h"
155
156
#include <vector>
157
#include <string>
158
#include <cctype>
159
#include <cassert>
160
#include <algorithm>
161
162
// Windows specific addition to prevent the indirect import of the redefined min/max macros
163
#if defined _WIN32 || defined _WIN64
164
  #ifdef NOMINMAX
165
    #undef NOMINMAX
166
  #endif
167
  #define NOMINMAX
168
#endif
169
#include <zlib.h>
170
171
172
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
173
174
175
namespace {
176
177
    //
178
    // Function pointer to dispatch to an approprate 
179
    // convertFloatToHalf64_* impl, based on runtime cpu checking.
180
    // Should be initialized in DwaCompressor::initializeFuncs()
181
    //
182
183
    void (*convertFloatToHalf64)(unsigned short*, float*) =
184
        convertFloatToHalf64_scalar;
185
186
    // 
187
    // Function pointer for dispatching a fromHalfZigZag_ impl
188
    //
189
    
190
    void (*fromHalfZigZag)(unsigned short*, float*) =
191
        fromHalfZigZag_scalar;
192
193
    //
194
    // Dispatch the inverse DCT on an 8x8 block, where the last
195
    // n rows can be all zeros. The n=0 case converts the full block.
196
    //
197
    void (*dctInverse8x8_0)(float*) = dctInverse8x8_scalar<0>;
198
    void (*dctInverse8x8_1)(float*) = dctInverse8x8_scalar<1>;
199
    void (*dctInverse8x8_2)(float*) = dctInverse8x8_scalar<2>;
200
    void (*dctInverse8x8_3)(float*) = dctInverse8x8_scalar<3>;
201
    void (*dctInverse8x8_4)(float*) = dctInverse8x8_scalar<4>;
202
    void (*dctInverse8x8_5)(float*) = dctInverse8x8_scalar<5>;
203
    void (*dctInverse8x8_6)(float*) = dctInverse8x8_scalar<6>;
204
    void (*dctInverse8x8_7)(float*) = dctInverse8x8_scalar<7>;
205
    
206
} // namespace
207
208
209
struct DwaCompressor::ChannelData
210
{
211
    std::string         name;
212
    CompressorScheme    compression;  
213
    int                 xSampling;
214
    int                 ySampling;
215
    PixelType           type;
216
    bool                pLinear;
217
218
    int                 width;
219
    int                 height;
220
221
    //
222
    // Incoming and outgoing data is scanline interleaved, and it's much
223
    // easier to operate on contiguous data.  Assuming the planare unc
224
    // buffer is to hold RLE data, we need to rearrange to make bytes
225
    // adjacent.
226
    //
227
228
    char               *planarUncBuffer;
229
    char               *planarUncBufferEnd;
230
231
    char               *planarUncRle[4];
232
    char               *planarUncRleEnd[4];
233
234
    PixelType           planarUncType;
235
    int                 planarUncSize;
236
};
237
238
239
struct DwaCompressor::CscChannelSet
240
{
241
    int idx[3];
242
};
243
244
245
struct DwaCompressor::Classifier
246
{
247
    Classifier (std::string suffix,
248
                CompressorScheme scheme,
249
                PixelType type,
250
                int cscIdx,
251
                bool caseInsensitive):
252
0
        _suffix(suffix),
253
0
        _scheme(scheme),
254
0
        _type(type),
255
0
        _cscIdx(cscIdx),
256
0
        _caseInsensitive(caseInsensitive)
257
0
    {
258
0
        if (caseInsensitive) 
259
0
            std::transform(_suffix.begin(), _suffix.end(), _suffix.begin(), tolower);
260
0
    }
261
262
    Classifier (const char *&ptr, int size)
263
0
    {
264
0
        if (size <= 0) 
265
0
            throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
266
0
                                " (truncated rule).");
267
            
268
0
        {
269
0
            char suffix[Name::SIZE];
270
0
            memset (suffix, 0, Name::SIZE);
271
0
            Xdr::read<CharPtrIO> (ptr, std::min(size, Name::SIZE-1), suffix);
272
0
            _suffix = std::string(suffix);
273
0
        }
274
275
0
        if (size < _suffix.length() + 1 + 2*Xdr::size<char>()) 
276
0
            throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
277
0
                                " (truncated rule).");
278
279
0
        char value;
280
0
        Xdr::read<CharPtrIO> (ptr, value);
281
282
0
        _cscIdx = (int)(value >> 4) - 1;
283
0
        if (_cscIdx < -1 || _cscIdx >= 3) 
284
0
            throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
285
0
                                " (corrupt cscIdx rule).");
286
287
0
        _scheme = (CompressorScheme)((value >> 2) & 3);
288
0
        if (_scheme < 0 || _scheme >= NUM_COMPRESSOR_SCHEMES) 
289
0
            throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
290
0
                                " (corrupt scheme rule).");
291
292
0
        _caseInsensitive = (value & 1 ? true : false);
293
294
0
        Xdr::read<CharPtrIO> (ptr, value);
295
0
        if (value < 0 || value >= NUM_PIXELTYPES) 
296
0
            throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
297
0
                                " (corrupt rule).");
298
0
        _type = (PixelType)value;
299
0
    }
300
301
    bool match (const std::string &suffix, const PixelType type) const
302
0
    {
303
0
        if (_type != type) return false;
304
305
0
        if (_caseInsensitive) 
306
0
        {
307
0
            std::string tmp(suffix);
308
0
            std::transform(tmp.begin(), tmp.end(), tmp.begin(), tolower);
309
0
            return tmp == _suffix;
310
0
        }
311
312
0
        return suffix == _suffix;
313
0
    }
314
315
    size_t size () const 
316
0
    {
317
        // string length + \0
318
0
        size_t sizeBytes = _suffix.length() + 1;
319
320
        // 1 byte for scheme / cscIdx / caseInsensitive, and 1 byte for type
321
0
        sizeBytes += 2 * Xdr::size<char>();
322
323
0
        return sizeBytes;
324
0
    }
325
326
    void write (char *&ptr) const
327
0
    {
328
0
        Xdr::write<CharPtrIO> (ptr, _suffix.c_str());
329
330
        // Encode _cscIdx (-1-3) in the upper 4 bits,
331
        //        _scheme (0-2)  in the next 2 bits
332
        //        _caseInsen     in the bottom bit
333
0
        unsigned char value = 0;
334
0
        value |= ((unsigned char)(_cscIdx+1)      & 15) << 4;
335
0
        value |= ((unsigned char)_scheme          &  3) << 2;
336
0
        value |=  (unsigned char)_caseInsensitive &  1;
337
338
0
        Xdr::write<CharPtrIO> (ptr, value);
339
0
        Xdr::write<CharPtrIO> (ptr, (unsigned char)_type);
340
0
    }
341
342
    std::string      _suffix;
343
    CompressorScheme _scheme;
344
    PixelType        _type;
345
    int              _cscIdx;
346
    bool             _caseInsensitive;
347
};
348
349
350
//
351
// Base class for the LOSSY_DCT decoder classes
352
//
353
354
class DwaCompressor::LossyDctDecoderBase
355
{
356
  public:
357
358
    LossyDctDecoderBase
359
        (char *packedAc,
360
         char *packedDc,
361
         const unsigned short *toLinear,
362
         int width,
363
         int height);
364
365
    virtual ~LossyDctDecoderBase ();
366
367
    void execute();
368
369
    //
370
    // These return number of items, not bytes. Each item
371
    // is an unsigned short
372
    //
373
374
0
    int numAcValuesEncoded() const { return _packedAcCount; }
375
0
    int numDcValuesEncoded() const { return _packedDcCount; }
376
377
  protected:
378
379
    //
380
    // Un-RLE the packed AC components into 
381
    // a half buffer. The half block should 
382
    // be the full 8x8 block (in zig-zag order
383
    // still), not the first AC component. 
384
    //
385
    // currAcComp is advanced as bytes are decoded.
386
    //
387
    // This returns the index of the last non-zero
388
    // value in the buffer - with the index into zig zag
389
    // order data. If we return 0, we have DC only data.
390
    // 
391
392
    int unRleAc (unsigned short *&currAcComp,
393
                 unsigned short  *halfZigBlock); 
394
395
396
    //
397
    // if NATIVE and XDR are really the same values, we can
398
    // skip some processing and speed things along
399
    //
400
401
    bool                  _isNativeXdr;
402
403
404
    //
405
    // Counts of how many items have been packed into the
406
    // AC and DC buffers
407
    //
408
409
    int                   _packedAcCount;
410
    int                   _packedDcCount;
411
412
413
    //
414
    // AC and DC buffers to pack
415
    //
416
417
    char                 *_packedAc;
418
    char                 *_packedDc;
419
420
421
    // 
422
    // half -> half LUT to transform from nonlinear to linear
423
    //
424
425
    const unsigned short *_toLinear;
426
427
428
    //
429
    // image dimensions
430
    //
431
432
    int                   _width;
433
    int                   _height;
434
435
436
    //
437
    // Pointers to the start of each scanlines, to be filled on decode
438
    // Generally, these will be filled by the subclasses.
439
    //
440
441
    std::vector< std::vector<char *> > _rowPtrs;
442
443
444
    // 
445
    // The type of each data that _rowPtrs[i] is referring. Layout
446
    // is in the same order as _rowPtrs[].
447
    //
448
449
    std::vector<PixelType>             _type;
450
    std::vector<SimdAlignedBuffer64f>  _dctData;
451
};
452
453
454
//
455
// Used to decode a single channel of LOSSY_DCT data.
456
//
457
458
class DwaCompressor::LossyDctDecoder: public LossyDctDecoderBase
459
{
460
  public:
461
462
    //
463
    // toLinear is a half-float LUT to convert the encoded values 
464
    // back to linear light. If you want to skip this step, pass
465
    // in NULL here.
466
    //
467
468
    LossyDctDecoder
469
        (std::vector<char *> &rowPtrs,
470
         char *packedAc,
471
         char *packedDc,
472
         const unsigned short *toLinear,
473
         int width,
474
         int height,
475
         PixelType type)
476
    :
477
0
        LossyDctDecoderBase(packedAc, packedDc, toLinear, width, height)
478
0
    {
479
0
        _rowPtrs.push_back(rowPtrs);
480
0
        _type.push_back(type);
481
0
    }
482
483
0
    virtual ~LossyDctDecoder () {}
484
};
485
486
487
//
488
// Used to decode 3 channels of LOSSY_DCT data that
489
// are grouped together and color space converted.
490
//
491
492
class DwaCompressor::LossyDctDecoderCsc: public LossyDctDecoderBase
493
{
494
  public:
495
496
    //
497
    // toLinear is a half-float LUT to convert the encoded values 
498
    // back to linear light. If you want to skip this step, pass
499
    // in NULL here.
500
    //
501
502
    LossyDctDecoderCsc
503
        (std::vector<char *> &rowPtrsR,
504
         std::vector<char *> &rowPtrsG,
505
         std::vector<char *> &rowPtrsB,
506
         char *packedAc,
507
         char *packedDc,
508
         const unsigned short *toLinear,
509
         int width,
510
         int height,
511
         PixelType typeR,
512
         PixelType typeG,
513
         PixelType typeB)
514
    :
515
0
        LossyDctDecoderBase(packedAc, packedDc, toLinear, width, height)
516
0
    {
517
0
        _rowPtrs.push_back(rowPtrsR);
518
0
        _rowPtrs.push_back(rowPtrsG);
519
0
        _rowPtrs.push_back(rowPtrsB);
520
0
        _type.push_back(typeR);
521
0
        _type.push_back(typeG);
522
0
        _type.push_back(typeB);
523
0
    }
524
525
0
    virtual ~LossyDctDecoderCsc () {}
526
};
527
528
529
// 
530
// Base class for encoding using the lossy DCT scheme
531
//
532
533
class DwaCompressor::LossyDctEncoderBase
534
{
535
  public:
536
537
    LossyDctEncoderBase
538
        (float quantBaseError,
539
         char *packedAc,
540
         char *packedDc,
541
         const unsigned short *toNonlinear,
542
         int width,
543
         int height);
544
545
    virtual ~LossyDctEncoderBase ();
546
547
    void execute ();
548
549
    //
550
    // These return number of items, not bytes. Each item
551
    // is an unsigned short
552
    //
553
554
0
    int     numAcValuesEncoded () const {return _numAcComp;}
555
0
    int     numDcValuesEncoded () const {return _numDcComp;}
556
557
  protected:
558
559
    void    toZigZag (half *dst, half *src);
560
    int     countSetBits (unsigned short src);
561
    half    quantize (half src, float errorTolerance);
562
    void    rleAc (half *block, unsigned short *&acPtr);
563
564
    float                      _quantBaseError;
565
566
    int                        _width,
567
                               _height;
568
    const unsigned short      *_toNonlinear;
569
570
    int                        _numAcComp,
571
                               _numDcComp;
572
573
    std::vector< std::vector<const char *> > _rowPtrs;
574
    std::vector<PixelType>                   _type;
575
    std::vector<SimdAlignedBuffer64f>        _dctData;
576
577
578
    //
579
    // Pointers to the buffers where AC and DC
580
    // DCT components should be packed for 
581
    // lossless compression downstream
582
    //
583
584
    char                      *_packedAc;
585
    char                      *_packedDc;
586
587
588
    //
589
    // Our "quantization tables" - the example JPEG tables, 
590
    // normalized so that the smallest value in each is 1.0.
591
    // This gives us a relationship between error in DCT 
592
    // components
593
    //
594
595
    float                      _quantTableY[64];
596
    float                      _quantTableCbCr[64];
597
};
598
599
600
601
//
602
// Single channel lossy DCT encoder
603
//
604
605
class DwaCompressor::LossyDctEncoder: public LossyDctEncoderBase
606
{
607
  public:
608
609
    LossyDctEncoder
610
        (float quantBaseError,
611
         std::vector<const char *> &rowPtrs,
612
         char *packedAc,
613
         char *packedDc,
614
         const unsigned short *toNonlinear,
615
         int width,
616
         int height,
617
         PixelType type)
618
    :
619
0
        LossyDctEncoderBase
620
0
            (quantBaseError, packedAc, packedDc, toNonlinear, width, height)
621
0
    {
622
0
        _rowPtrs.push_back(rowPtrs);
623
0
        _type.push_back(type);
624
0
    }
625
626
0
    virtual ~LossyDctEncoder () {}
627
};
628
    
629
630
//
631
// RGB channel lossy DCT encoder
632
//
633
634
class DwaCompressor::LossyDctEncoderCsc: public LossyDctEncoderBase
635
{
636
  public:
637
638
    LossyDctEncoderCsc
639
        (float quantBaseError,
640
         std::vector<const char *> &rowPtrsR,
641
         std::vector<const char *> &rowPtrsG,
642
         std::vector<const char *> &rowPtrsB,
643
         char *packedAc,
644
         char *packedDc,
645
         const unsigned short *toNonlinear,
646
         int width,
647
         int height,
648
         PixelType typeR,
649
         PixelType typeG,
650
         PixelType typeB)
651
    :
652
0
        LossyDctEncoderBase
653
0
            (quantBaseError, packedAc, packedDc, toNonlinear, width, height)
654
0
    {
655
0
        _type.push_back(typeR);
656
0
        _type.push_back(typeG);
657
0
        _type.push_back(typeB);
658
659
0
        _rowPtrs.push_back(rowPtrsR);
660
0
        _rowPtrs.push_back(rowPtrsG);
661
0
        _rowPtrs.push_back(rowPtrsB);
662
0
    }
663
664
0
    virtual ~LossyDctEncoderCsc () {}
665
};
666
667
668
// ==============================================================
669
//
670
//                     LossyDctDecoderBase
671
//
672
// --------------------------------------------------------------
673
674
DwaCompressor::LossyDctDecoderBase::LossyDctDecoderBase
675
    (char *packedAc,
676
     char *packedDc,
677
     const unsigned short *toLinear,
678
     int width,
679
     int height)
680
:
681
0
    _isNativeXdr(false),
682
0
    _packedAcCount(0),
683
0
    _packedDcCount(0),
684
0
    _packedAc(packedAc),
685
0
    _packedDc(packedDc),
686
0
    _toLinear(toLinear),
687
0
    _width(width),
688
0
    _height(height)
689
0
{
690
0
    if (_toLinear == 0)
691
0
        _toLinear = get_dwaCompressorNoOp();
692
693
0
    _isNativeXdr = GLOBAL_SYSTEM_LITTLE_ENDIAN;
694
0
}
695
696
697
0
DwaCompressor::LossyDctDecoderBase::~LossyDctDecoderBase () {}
698
699
700
void
701
DwaCompressor::LossyDctDecoderBase::execute ()
702
0
{
703
0
    int numComp        = _rowPtrs.size();
704
0
    int lastNonZero    = 0;
705
0
    int numBlocksX     = (int) ceil ((float)_width  / 8.0f);
706
0
    int numBlocksY     = (int) ceil ((float)_height / 8.0f);
707
0
    int leftoverX      = _width  - (numBlocksX-1) * 8;
708
0
    int leftoverY      = _height - (numBlocksY-1) * 8;
709
710
0
    int numFullBlocksX = (int)floor ((float)_width / 8.0f);
711
712
0
    unsigned short tmpShortNative = 0;
713
0
    unsigned short tmpShortXdr    = 0;
714
0
    const char *tmpConstCharPtr   = 0;
715
716
0
    unsigned short                    *currAcComp = (unsigned short *)_packedAc;
717
0
    std::vector<unsigned short *>      currDcComp (_rowPtrs.size());
718
0
    std::vector<SimdAlignedBuffer64us> halfZigBlock (_rowPtrs.size());
719
720
0
    if (_type.size() != _rowPtrs.size())
721
0
        throw IEX_NAMESPACE::BaseExc ("Row pointers and types mismatch in count");
722
723
0
    if ((_rowPtrs.size() != 3) && (_rowPtrs.size() != 1))
724
0
        throw IEX_NAMESPACE::NoImplExc ("Only 1 and 3 channel encoding is supported");
725
726
0
    _dctData.resize(numComp);
727
728
    //
729
    // Allocate a temp aligned buffer to hold a rows worth of full 
730
    // 8x8 half-float blocks
731
    //
732
733
0
    unsigned char *rowBlockHandle = new unsigned char
734
0
        [numComp * numBlocksX * 64 * sizeof(unsigned short) + _SSE_ALIGNMENT];
735
736
0
    unsigned short *rowBlock[3];
737
738
0
    rowBlock[0] = (unsigned short*)rowBlockHandle;
739
740
0
    for (int i = 0; i < _SSE_ALIGNMENT; ++i)
741
0
    {
742
0
        if (((size_t)(rowBlockHandle + i) & _SSE_ALIGNMENT_MASK) == 0)
743
0
            rowBlock[0] = (unsigned short *)(rowBlockHandle + i);
744
0
    }
745
746
0
    for (int comp = 1; comp < numComp; ++comp)
747
0
        rowBlock[comp] = rowBlock[comp - 1] + numBlocksX * 64;
748
 
749
    //
750
    // Pack DC components together by common plane, so we can get 
751
    // a little more out of differencing them. We'll always have 
752
    // one component per block, so we can computed offsets.
753
    //
754
755
0
    currDcComp[0] = (unsigned short *)_packedDc;
756
757
0
    for (unsigned int comp = 1; comp < numComp; ++comp)
758
0
        currDcComp[comp] = currDcComp[comp - 1] + numBlocksX * numBlocksY;
759
760
0
    for (int blocky = 0; blocky < numBlocksY; ++blocky)
761
0
    {
762
0
        int maxY = 8;
763
764
0
        if (blocky == numBlocksY-1)
765
0
            maxY = leftoverY;
766
767
0
        int maxX = 8;
768
769
0
        for (int blockx = 0; blockx < numBlocksX; ++blockx)
770
0
        {
771
0
            if (blockx == numBlocksX-1)
772
0
                maxX = leftoverX;
773
774
            //
775
            // If we can detect that the block is constant values
776
            // (all components only have DC values, and all AC is 0),
777
            // we can do everything only on 1 value, instead of all
778
            // 64. 
779
            //
780
            // This won't really help for regular images, but it is
781
            // meant more for layers with large swaths of black 
782
            //
783
784
0
            bool blockIsConstant = true;
785
786
0
            for (unsigned int comp = 0; comp < numComp; ++comp)
787
0
            {
788
789
                //
790
                // DC component is stored separately
791
                //
792
793
0
                #ifdef IMF_HAVE_SSE2
794
0
                    {
795
0
                        __m128i *dst = (__m128i*)halfZigBlock[comp]._buffer;
796
797
0
                        dst[7] = _mm_setzero_si128();
798
0
                        dst[6] = _mm_setzero_si128();
799
0
                        dst[5] = _mm_setzero_si128();
800
0
                        dst[4] = _mm_setzero_si128();
801
0
                        dst[3] = _mm_setzero_si128();
802
0
                        dst[2] = _mm_setzero_si128();
803
0
                        dst[1] = _mm_setzero_si128();
804
0
                        dst[0] = _mm_insert_epi16
805
0
                            (_mm_setzero_si128(), *currDcComp[comp]++, 0);
806
0
                    }
807
                #else  /* IMF_HAVE_SSE2 */
808
809
                    memset (halfZigBlock[comp]._buffer, 0, 64 * 2);
810
                    halfZigBlock[comp]._buffer[0] = *currDcComp[comp]++;
811
812
                #endif /* IMF_HAVE_SSE2 */
813
814
0
                _packedDcCount++;
815
                
816
                //
817
                // UnRLE the AC. This will modify currAcComp
818
                //
819
820
0
                lastNonZero = unRleAc (currAcComp, halfZigBlock[comp]._buffer);
821
822
                //
823
                // Convert from XDR to NATIVE
824
                //
825
826
0
                if (!_isNativeXdr)
827
0
                {
828
0
                    for (int i = 0; i < 64; ++i)
829
0
                    {
830
0
                        tmpShortXdr      = halfZigBlock[comp]._buffer[i];
831
0
                        tmpConstCharPtr  = (const char *)&tmpShortXdr;
832
833
0
                        Xdr::read<CharPtrIO> (tmpConstCharPtr, tmpShortNative);
834
835
0
                        halfZigBlock[comp]._buffer[i] = tmpShortNative;
836
0
                    }
837
0
                }
838
839
0
                if (lastNonZero == 0)
840
0
                {
841
                    //
842
                    // DC only case - AC components are all 0   
843
                    //
844
845
0
                    half h;
846
847
0
                    h.setBits (halfZigBlock[comp]._buffer[0]);
848
0
                    _dctData[comp]._buffer[0] = (float)h;
849
850
0
                    dctInverse8x8DcOnly (_dctData[comp]._buffer);
851
0
                }
852
0
                else
853
0
                {
854
                    //
855
                    // We have some AC components that are non-zero. 
856
                    // Can't use the 'constant block' optimization
857
                    //
858
859
0
                    blockIsConstant = false;
860
861
                    //
862
                    // Un-Zig zag 
863
                    //
864
865
0
                    (*fromHalfZigZag)
866
0
                        (halfZigBlock[comp]._buffer, _dctData[comp]._buffer);
867
868
                    //
869
                    // Zig-Zag indices in normal layout are as follows:
870
                    //
871
                    // 0   1   5   6   14  15  27  28
872
                    // 2   4   7   13  16  26  29  42
873
                    // 3   8   12  17  25  30  41  43
874
                    // 9   11  18  24  31  40  44  53
875
                    // 10  19  23  32  39  45  52  54
876
                    // 20  22  33  38  46  51  55  60
877
                    // 21  34  37  47  50  56  59  61
878
                    // 35  36  48  49  57  58  62  63
879
                    //
880
                    // If lastNonZero is less than the first item on
881
                    // each row, we know that the whole row is zero and 
882
                    // can be skipped in the row-oriented part of the
883
                    // iDCT. 
884
                    //
885
                    // The unrolled logic here is:
886
                    //
887
                    //    if lastNonZero < rowStartIdx[i],
888
                    //    zeroedRows = rowsEmpty[i]
889
                    //
890
                    // where:
891
                    //
892
                    //    const int rowStartIdx[] = {2, 3, 9, 10, 20, 21, 35};
893
                    //    const int rowsEmpty[]   = {7, 6, 5,  4,  3,  2,  1};
894
                    //
895
896
0
                    if (lastNonZero < 2)
897
0
                        dctInverse8x8_7(_dctData[comp]._buffer);
898
0
                    else if (lastNonZero < 3)
899
0
                        dctInverse8x8_6(_dctData[comp]._buffer);
900
0
                    else if (lastNonZero < 9)
901
0
                        dctInverse8x8_5(_dctData[comp]._buffer);
902
0
                    else if (lastNonZero < 10)
903
0
                        dctInverse8x8_4(_dctData[comp]._buffer);
904
0
                    else if (lastNonZero < 20)
905
0
                        dctInverse8x8_3(_dctData[comp]._buffer);
906
0
                    else if (lastNonZero < 21)
907
0
                        dctInverse8x8_2(_dctData[comp]._buffer);
908
0
                    else if (lastNonZero < 35)
909
0
                        dctInverse8x8_1(_dctData[comp]._buffer);
910
0
                    else
911
0
                        dctInverse8x8_0(_dctData[comp]._buffer);
912
0
                }
913
0
            }
914
915
            //
916
            // Perform the CSC
917
            //
918
919
0
            if (numComp == 3)
920
0
            {
921
0
                if (!blockIsConstant)
922
0
                {
923
0
                    csc709Inverse64 (_dctData[0]._buffer, 
924
0
                                     _dctData[1]._buffer, 
925
0
                                     _dctData[2]._buffer);
926
927
0
                }
928
0
                else
929
0
                {
930
0
                    csc709Inverse (_dctData[0]._buffer[0], 
931
0
                                   _dctData[1]._buffer[0], 
932
0
                                   _dctData[2]._buffer[0]);
933
0
                }
934
0
            }
935
936
            //
937
            // Float -> Half conversion. 
938
            //
939
            // If the block has a constant value, just convert the first pixel.
940
            //
941
942
0
            for (unsigned int comp = 0; comp < numComp; ++comp)
943
0
            {
944
0
                if (!blockIsConstant)
945
0
                {
946
0
                    (*convertFloatToHalf64)
947
0
                        (&rowBlock[comp][blockx*64], _dctData[comp]._buffer);
948
0
                }
949
0
                else
950
0
                {
951
0
                    #ifdef IMF_HAVE_SSE2
952
953
0
                        __m128i *dst = (__m128i*)&rowBlock[comp][blockx*64];
954
955
0
                        dst[0] = _mm_set1_epi16
956
0
                            (((half)_dctData[comp]._buffer[0]).bits());
957
958
0
                        dst[1] = dst[0];
959
0
                        dst[2] = dst[0];
960
0
                        dst[3] = dst[0];
961
0
                        dst[4] = dst[0];
962
0
                        dst[5] = dst[0];
963
0
                        dst[6] = dst[0];
964
0
                        dst[7] = dst[0];
965
966
                    #else  /* IMF_HAVE_SSE2 */
967
968
                        unsigned short *dst = &rowBlock[comp][blockx*64];
969
970
                        dst[0] = ((half)_dctData[comp]._buffer[0]).bits();
971
972
                        for (int i = 1; i < 64; ++i)
973
                        {
974
                            dst[i] = dst[0];
975
                        }
976
977
                    #endif /* IMF_HAVE_SSE2 */
978
0
                } // blockIsConstant
979
0
            } // comp
980
0
        } // blockx
981
982
        //
983
        // At this point, we have half-float nonlinear value blocked
984
        // in rowBlock[][]. We need to unblock the data, transfer
985
        // back to linear, and write the results in the _rowPtrs[].
986
        //
987
        // There is a fast-path for aligned rows, which helps
988
        // things a little. Since this fast path is only valid
989
        // for full 8-element wide blocks, the partial x blocks
990
        // are broken into a separate loop below.
991
        //
992
        // At the moment, the fast path requires:
993
        //   * sse support
994
        //   * aligned row pointers
995
        //   * full 8-element wide blocks
996
        //
997
998
0
        for (int comp = 0; comp < numComp; ++comp)
999
0
        {
1000
            //
1001
            // Test if we can use the fast path
1002
            //
1003
1004
0
        #ifdef IMF_HAVE_SSE2
1005
1006
0
            bool fastPath = true;
1007
1008
0
            for (int y = 8 * blocky; y < 8 * blocky + maxY; ++y)
1009
0
            {
1010
0
                if ((size_t)_rowPtrs[comp][y] & _SSE_ALIGNMENT_MASK)
1011
0
                    fastPath = false;
1012
0
            }
1013
1014
0
            if (fastPath)
1015
0
            {
1016
                //
1017
                // Handle all the full X blocks, in a fast path with sse2 and
1018
                // aligned row pointers
1019
                //
1020
1021
0
                for (int y=8*blocky; y<8*blocky+maxY; ++y)
1022
0
                {
1023
0
                    __m128i *dst = (__m128i *)_rowPtrs[comp][y];
1024
0
                    __m128i *src = (__m128i *)&rowBlock[comp][(y & 0x7) * 8];
1025
1026
1027
0
                    for (int blockx = 0; blockx < numFullBlocksX; ++blockx)
1028
0
                    {
1029
                        //
1030
                        // These may need some twiddling.
1031
                        // Run with multiples of 8
1032
                        //
1033
1034
0
                        _mm_prefetch ((char *)(src + 16), _MM_HINT_NTA); 
1035
1036
0
                        unsigned short i0  = _mm_extract_epi16 (*src, 0);
1037
0
                        unsigned short i1  = _mm_extract_epi16 (*src, 1);
1038
0
                        unsigned short i2  = _mm_extract_epi16 (*src, 2);
1039
0
                        unsigned short i3  = _mm_extract_epi16 (*src, 3);
1040
1041
0
                        unsigned short i4  = _mm_extract_epi16 (*src, 4);
1042
0
                        unsigned short i5  = _mm_extract_epi16 (*src, 5);
1043
0
                        unsigned short i6  = _mm_extract_epi16 (*src, 6);
1044
0
                        unsigned short i7  = _mm_extract_epi16 (*src, 7);
1045
1046
0
                        i0 = _toLinear[i0];
1047
0
                        i1 = _toLinear[i1];
1048
0
                        i2 = _toLinear[i2];
1049
0
                        i3 = _toLinear[i3];
1050
1051
0
                        i4 = _toLinear[i4];
1052
0
                        i5 = _toLinear[i5];
1053
0
                        i6 = _toLinear[i6];
1054
0
                        i7 = _toLinear[i7];
1055
1056
0
                        *dst = _mm_insert_epi16 (_mm_setzero_si128(), i0, 0);
1057
0
                        *dst = _mm_insert_epi16 (*dst, i1, 1);
1058
0
                        *dst = _mm_insert_epi16 (*dst, i2, 2);
1059
0
                        *dst = _mm_insert_epi16 (*dst, i3, 3);
1060
1061
0
                        *dst = _mm_insert_epi16 (*dst, i4, 4);
1062
0
                        *dst = _mm_insert_epi16 (*dst, i5, 5);
1063
0
                        *dst = _mm_insert_epi16 (*dst, i6, 6);
1064
0
                        *dst = _mm_insert_epi16 (*dst, i7, 7);
1065
1066
0
                        src += 8;
1067
0
                        dst++;
1068
0
                    }
1069
0
                }
1070
0
            }
1071
0
            else
1072
0
            {
1073
1074
0
        #endif /* IMF_HAVE_SSE2 */
1075
1076
                //
1077
                // Basic scalar kinda slow path for handling the full X blocks
1078
                //
1079
1080
0
                for (int y = 8 * blocky; y < 8 * blocky + maxY; ++y)
1081
0
                {
1082
0
                    unsigned short *dst = (unsigned short *)_rowPtrs[comp][y];
1083
1084
0
                    for (int blockx = 0; blockx < numFullBlocksX; ++blockx)
1085
0
                    {
1086
0
                        unsigned short *src =
1087
0
                            &rowBlock[comp][blockx * 64 + ((y & 0x7) * 8)];
1088
1089
0
                        dst[0] = _toLinear[src[0]];
1090
0
                        dst[1] = _toLinear[src[1]];
1091
0
                        dst[2] = _toLinear[src[2]];
1092
0
                        dst[3] = _toLinear[src[3]];
1093
1094
0
                        dst[4] = _toLinear[src[4]];
1095
0
                        dst[5] = _toLinear[src[5]];
1096
0
                        dst[6] = _toLinear[src[6]];
1097
0
                        dst[7] = _toLinear[src[7]];
1098
1099
0
                        dst += 8;
1100
0
                    }
1101
0
                }
1102
1103
0
        #ifdef IMF_HAVE_SSE2
1104
1105
0
            }
1106
1107
0
        #endif /* IMF_HAVE_SSE2 */
1108
1109
            //
1110
            // If we have partial X blocks, deal with all those now
1111
            // Since this should be minimal work, there currently
1112
            // is only one path that should work for everyone.
1113
            //
1114
1115
0
            if (numFullBlocksX != numBlocksX)
1116
0
            {
1117
0
                for (int y = 8 * blocky; y < 8 * blocky + maxY; ++y)
1118
0
                {
1119
0
                    unsigned short *src = (unsigned short *)
1120
0
                        &rowBlock[comp][numFullBlocksX * 64 + ((y & 0x7) * 8)];
1121
1122
0
                    unsigned short *dst = (unsigned short *)_rowPtrs[comp][y];
1123
1124
0
                    dst += 8 * numFullBlocksX;
1125
1126
0
                    for (int x = 0; x < maxX; ++x)
1127
0
                    {
1128
0
                        *dst++ = _toLinear[*src++];
1129
0
                    }
1130
0
                }
1131
0
            }
1132
0
        } // comp
1133
0
    } // blocky
1134
1135
    //
1136
    // Walk over all the channels that are of type FLOAT.
1137
    // Convert from HALF XDR back to FLOAT XDR.
1138
    //
1139
1140
0
    for (unsigned int chan = 0; chan < numComp; ++chan)
1141
0
    {
1142
1143
0
        if (_type[chan] != FLOAT)
1144
0
            continue;
1145
1146
0
        std::vector<unsigned short> halfXdr (_width);
1147
1148
0
        for (int y=0; y<_height; ++y)
1149
0
        {
1150
0
            char *floatXdrPtr = _rowPtrs[chan][y];
1151
1152
0
            memcpy(&halfXdr[0], floatXdrPtr, _width*sizeof(unsigned short));
1153
1154
0
            const char *halfXdrPtr = (const char *)(&halfXdr[0]);
1155
1156
0
            for (int x=0; x<_width; ++x)
1157
0
            {
1158
0
                half tmpHalf;
1159
1160
0
                Xdr::read<CharPtrIO> (halfXdrPtr, tmpHalf);
1161
0
                Xdr::write<CharPtrIO> (floatXdrPtr, (float)tmpHalf);
1162
1163
                // 
1164
                // Xdr::write and Xdr::read will advance the ptrs
1165
                //
1166
0
            }
1167
0
        }
1168
0
    }
1169
1170
0
    delete[] rowBlockHandle;
1171
0
}
1172
1173
1174
//
1175
// Un-RLE the packed AC components into 
1176
// a half buffer. The half block should 
1177
// be the full 8x8 block (in zig-zag order
1178
// still), not the first AC component. 
1179
//
1180
// currAcComp is advanced as bytes are decoded.
1181
//
1182
// This returns the index of the last non-zero
1183
// value in the buffer - with the index into zig zag
1184
// order data. If we return 0, we have DC only data.
1185
// 
1186
// This is assuminging that halfZigBlock is zero'ed
1187
// prior to calling
1188
//
1189
1190
int 
1191
DwaCompressor::LossyDctDecoderBase::unRleAc
1192
    (unsigned short *&currAcComp,
1193
     unsigned short  *halfZigBlock) 
1194
0
{
1195
    //
1196
    // Un-RLE the RLE'd blocks. If we find an item whose
1197
    // high byte is 0xff, then insert the number of 0's
1198
    // as indicated by the low byte.
1199
    //
1200
    // Otherwise, just copy the number verbaitm.
1201
    //
1202
1203
0
    int lastNonZero          = 0;
1204
0
    int dctComp              = 1; 
1205
1206
    //
1207
    // Start with a zero'ed block, so we don't have to
1208
    // write when we hit a run symbol
1209
    //
1210
1211
0
    while (dctComp < 64)
1212
0
    {
1213
0
        if (*currAcComp == 0xff00)
1214
0
        {
1215
            // 
1216
            // End of block
1217
            //
1218
1219
0
            dctComp = 64;
1220
1221
0
        }
1222
0
        else if ((*currAcComp) >> 8 == 0xff)
1223
0
        {
1224
            //
1225
            // Run detected! Insert 0's.
1226
            //
1227
            // Since the block has been zeroed, just advance the ptr
1228
            // 
1229
1230
0
            dctComp += (*currAcComp) & 0xff; 
1231
0
        }
1232
0
        else
1233
0
        {
1234
            // 
1235
            // Not a run, just copy over the value
1236
            //
1237
1238
0
            lastNonZero = dctComp;
1239
0
            halfZigBlock[dctComp] = *currAcComp;
1240
1241
0
            dctComp++;
1242
0
        }
1243
1244
0
        _packedAcCount++;
1245
0
        currAcComp++;
1246
0
    }
1247
1248
0
    return lastNonZero;
1249
0
}
1250
1251
1252
// ==============================================================
1253
//
1254
//                     LossyDctEncoderBase
1255
//
1256
// --------------------------------------------------------------
1257
1258
DwaCompressor::LossyDctEncoderBase::LossyDctEncoderBase
1259
    (float quantBaseError,
1260
     char *packedAc,
1261
     char *packedDc,
1262
     const unsigned short *toNonlinear,
1263
     int width,
1264
     int height)
1265
:
1266
0
    _quantBaseError(quantBaseError),
1267
0
    _width(width),
1268
0
    _height(height),
1269
0
    _toNonlinear(toNonlinear),
1270
0
    _numAcComp(0),
1271
0
    _numDcComp(0),
1272
0
    _packedAc(packedAc),
1273
0
    _packedDc(packedDc)
1274
0
{
1275
    //
1276
    // Here, we take the generic JPEG quantization tables and
1277
    // normalize them by the smallest component in each table.
1278
    // This gives us a relationship amongst the DCT components,
1279
    // in terms of how sensitive each component is to
1280
    // error.
1281
    //
1282
    // A higher normalized value means we can quantize more,
1283
    // and a small normalized value means we can quantize less.
1284
    //
1285
    // Eventually, we will want an acceptable quantization
1286
    // error range for each component. We find this by
1287
    // multiplying some user-specified level (_quantBaseError)
1288
    // by the normalized table (_quantTableY, _quantTableCbCr) to
1289
    // find the acceptable quantization error range.
1290
    //
1291
    // The quantization table is not needed for decoding, and
1292
    // is not transmitted. So, if you want to get really fancy,
1293
    // you could derive some content-dependent quantization
1294
    // table, and the decoder would not need to be changed. But,
1295
    // for now, we'll just use statice quantization tables.
1296
    //
1297
1298
0
    int jpegQuantTableY[] =
1299
0
    {
1300
0
        16,  11,  10,  16,   24,   40,   51,   61,
1301
0
        12,  12,  14,  19,   26,   58,   60,   55,
1302
0
        14,  13,  16,  24,   40,   57,   69,   56,
1303
0
        14,  17,  22,  29,   51,   87,   80,   62,
1304
0
        18,  22,  37,  56,   68,  109,  103,   77,
1305
0
        24,  35,  55,  64,   81,  104,  113,   92,
1306
0
        49,  64,  78,  87,  103,  121,  120,  101,
1307
0
        72,  92,  95,  98,  112,  100,  103,   99
1308
0
    };
1309
1310
0
    int jpegQuantTableYMin = 10;
1311
1312
0
    int jpegQuantTableCbCr[] =
1313
0
    {
1314
0
        17,  18,  24,  47,  99,  99,  99,  99,
1315
0
        18,  21,  26,  66,  99,  99,  99,  99,
1316
0
        24,  26,  56,  99,  99,  99,  99,  99,
1317
0
        47,  66,  99,  99,  99,  99,  99,  99,
1318
0
        99,  99,  99,  99,  99,  99,  99,  99,
1319
0
        99,  99,  99,  99,  99,  99,  99,  99,
1320
0
        99,  99,  99,  99,  99,  99,  99,  99,
1321
0
        99,  99,  99,  99,  99,  99,  99,  99
1322
0
    };
1323
1324
0
    int jpegQuantTableCbCrMin = 17;
1325
1326
0
    for (int idx = 0; idx < 64; ++idx)
1327
0
    {
1328
0
        _quantTableY[idx] = static_cast<float> (jpegQuantTableY[idx]) /
1329
0
                            static_cast<float> (jpegQuantTableYMin);
1330
1331
0
        _quantTableCbCr[idx] = static_cast<float> (jpegQuantTableCbCr[idx]) /
1332
0
                               static_cast<float> (jpegQuantTableCbCrMin);
1333
0
    }
1334
    
1335
0
    if (_quantBaseError < 0)
1336
0
        quantBaseError = 0;
1337
0
}
1338
1339
1340
DwaCompressor::LossyDctEncoderBase::~LossyDctEncoderBase () 
1341
0
{
1342
0
}
1343
1344
1345
//
1346
// Given three channels of source data, encoding by first applying
1347
// a color space conversion to a YCbCr space.  Otherwise, if we only
1348
// have one channel, just encode it as is. 
1349
//
1350
// Other numbers of channels are somewhat unexpected at this point,
1351
// and will throw an exception.
1352
//
1353
1354
void
1355
DwaCompressor::LossyDctEncoderBase::execute ()
1356
0
{
1357
0
    int  numBlocksX   = (int)ceil ((float)_width / 8.0f);
1358
0
    int  numBlocksY   = (int)ceil ((float)_height/ 8.0f);
1359
1360
0
    half halfZigCoef[64]; 
1361
0
    half halfCoef[64];
1362
1363
0
    std::vector<unsigned short *> currDcComp (_rowPtrs.size());
1364
0
    unsigned short               *currAcComp = (unsigned short *)_packedAc;
1365
1366
0
    _dctData.resize (_rowPtrs.size());
1367
0
    _numAcComp = 0;
1368
0
    _numDcComp = 0;
1369
 
1370
0
    assert (_type.size() == _rowPtrs.size());
1371
0
    assert ((_rowPtrs.size() == 3) || (_rowPtrs.size() == 1));
1372
1373
    // 
1374
    // Allocate a temp half buffer to quantize into for
1375
    // any FLOAT source channels.
1376
    //
1377
1378
0
    int tmpHalfBufferElements = 0;
1379
1380
0
    for (unsigned int chan = 0; chan < _rowPtrs.size(); ++chan)
1381
0
        if (_type[chan] == FLOAT)
1382
0
            tmpHalfBufferElements += _width * _height;
1383
1384
0
    std::vector<unsigned short> tmpHalfBuffer (tmpHalfBufferElements);
1385
1386
0
    char *tmpHalfBufferPtr = 0;
1387
1388
0
    if (tmpHalfBufferElements)
1389
0
        tmpHalfBufferPtr = (char *)&tmpHalfBuffer[0];
1390
1391
    //
1392
    // Run over all the float scanlines, quantizing, 
1393
    // and re-assigning _rowPtr[y]. We need to translate
1394
    // FLOAT XDR to HALF XDR.
1395
    //
1396
1397
0
    for (unsigned int chan = 0; chan < _rowPtrs.size(); ++chan)
1398
0
    {
1399
0
        if (_type[chan] != FLOAT)
1400
0
            continue;
1401
    
1402
0
        for (int y = 0; y < _height; ++y)
1403
0
        {
1404
0
            float       src = 0;
1405
0
            const char *srcXdr = _rowPtrs[chan][y];
1406
0
            char       *dstXdr = tmpHalfBufferPtr;
1407
           
1408
0
            for (int x = 0; x < _width; ++x)
1409
0
            {
1410
1411
0
                Xdr::read<CharPtrIO> (srcXdr, src);
1412
1413
                //
1414
                // Clamp to half ranges, instead of just casting. This
1415
                // avoids introducing Infs which end up getting zeroed later
1416
                //
1417
0
                src = std::max (
1418
0
                    std::min ((float) std::numeric_limits<half>::max(), src),
1419
0
                              (float)-std::numeric_limits<half>::max());
1420
1421
0
                Xdr::write<CharPtrIO> (dstXdr, ((half)src).bits());
1422
1423
                //
1424
                // Xdr::read and Xdr::write will advance the ptr
1425
                //
1426
0
            }
1427
1428
0
            _rowPtrs[chan][y] = (const char *)tmpHalfBufferPtr;
1429
0
            tmpHalfBufferPtr += _width * sizeof (unsigned short);
1430
0
        }
1431
0
    }
1432
1433
    //
1434
    // Pack DC components together by common plane, so we can get 
1435
    // a little more out of differencing them. We'll always have 
1436
    // one component per block, so we can computed offsets.
1437
    //
1438
1439
0
    currDcComp[0] = (unsigned short *)_packedDc;
1440
1441
0
    for (unsigned int chan = 1; chan < _rowPtrs.size(); ++chan)
1442
0
        currDcComp[chan] = currDcComp[chan-1] + numBlocksX * numBlocksY;
1443
1444
0
    for (int blocky = 0; blocky < numBlocksY; ++blocky)
1445
0
    {
1446
0
        for (int blockx = 0; blockx < numBlocksX; ++blockx)
1447
0
        {
1448
0
            half           h;
1449
0
            unsigned short tmpShortXdr, tmpShortNative;
1450
0
            char          *tmpCharPtr;
1451
1452
0
            for (unsigned int chan = 0; chan < _rowPtrs.size(); ++chan)
1453
0
            {
1454
                //
1455
                // Break the source into 8x8 blocks. If we don't
1456
                // fit at the edges, mirror.
1457
                //
1458
                // Also, convert from linear to nonlinear representation.
1459
                // Our source is assumed to be XDR, and we need to convert
1460
                // to NATIVE prior to converting to float.
1461
                //
1462
                // If we're converting linear -> nonlinear, assume that the
1463
                // XDR -> NATIVE conversion is built into the lookup. Otherwise,
1464
                // we'll need to explicitly do it.
1465
                //
1466
1467
0
                for (int y = 0; y < 8; ++y)
1468
0
                {
1469
0
                    for (int x = 0; x < 8; ++x)
1470
0
                    {
1471
0
                        int vx = 8 * blockx + x;
1472
0
                        int vy = 8 * blocky + y;
1473
1474
0
                        if (vx >= _width)
1475
0
                            vx = _width - (vx - (_width - 1));
1476
                        
1477
0
                        if (vx < 0) vx = _width-1;
1478
1479
0
                        if (vy >=_height)
1480
0
                            vy = _height - (vy - (_height - 1));
1481
1482
0
                        if (vy < 0) vy = _height-1;
1483
                    
1484
0
                        tmpShortXdr =
1485
0
                            ((const unsigned short *)(_rowPtrs[chan])[vy])[vx];
1486
1487
0
                        if (_toNonlinear)
1488
0
                        {
1489
0
                            h.setBits (_toNonlinear[tmpShortXdr]);
1490
0
                        }
1491
0
                        else
1492
0
                        {
1493
0
                            const char *tmpConstCharPtr =
1494
0
                                (const char *)(&tmpShortXdr);
1495
1496
0
                            Xdr::read<CharPtrIO>
1497
0
                                (tmpConstCharPtr, tmpShortNative);
1498
1499
0
                            h.setBits(tmpShortNative);
1500
0
                        }
1501
1502
0
                        _dctData[chan]._buffer[y * 8 + x] = (float)h;
1503
0
                    } // x
1504
0
                } // y
1505
0
            } // chan
1506
1507
            //
1508
            // Color space conversion
1509
            //
1510
1511
0
            if (_rowPtrs.size() == 3)
1512
0
            {
1513
0
                csc709Forward64 (_dctData[0]._buffer, 
1514
0
                                 _dctData[1]._buffer, 
1515
0
                                 _dctData[2]._buffer);
1516
0
            }
1517
1518
0
            for (unsigned int chan = 0; chan < _rowPtrs.size(); ++chan)
1519
0
            {
1520
                //
1521
                // Forward DCT
1522
                //
1523
1524
0
                dctForward8x8(_dctData[chan]._buffer);
1525
1526
                //
1527
                // Quantize to half, and zigzag
1528
                //
1529
1530
0
                if (chan == 0)
1531
0
                {
1532
0
                    for (int i = 0; i < 64; ++i)
1533
0
                    {
1534
0
                        halfCoef[i] =
1535
0
                            quantize ((half)_dctData[chan]._buffer[i],
1536
0
                                      _quantBaseError*_quantTableY[i]);
1537
0
                    }
1538
0
                }
1539
0
                else
1540
0
                {
1541
0
                    for (int i = 0; i < 64; ++i)
1542
0
                    {
1543
0
                        halfCoef[i] =
1544
0
                            quantize ((half)_dctData[chan]._buffer[i],
1545
0
                                      _quantBaseError*_quantTableCbCr[i]);
1546
0
                    }
1547
0
                }
1548
1549
0
                toZigZag (halfZigCoef, halfCoef);
1550
                
1551
                //
1552
                // Convert from NATIVE back to XDR, before we write out
1553
                //
1554
1555
0
                for (int i = 0; i < 64; ++i)
1556
0
                {
1557
0
                    tmpCharPtr = (char *)&tmpShortXdr;
1558
0
                    Xdr::write<CharPtrIO>(tmpCharPtr, halfZigCoef[i].bits());
1559
0
                    halfZigCoef[i].setBits(tmpShortXdr);
1560
0
                }
1561
1562
                //
1563
                // Save the DC component separately, to be compressed on
1564
                // its own.
1565
                //
1566
1567
0
                *currDcComp[chan]++ = halfZigCoef[0].bits();
1568
0
                _numDcComp++;
1569
                
1570
                //
1571
                // Then RLE the AC components (which will record the count
1572
                // of the resulting number of items)
1573
                //
1574
1575
0
                rleAc (halfZigCoef, currAcComp);
1576
0
            } // chan
1577
0
        } // blockx
1578
0
    } // blocky              
1579
0
}
1580
1581
1582
// 
1583
// Reorder from zig-zag order to normal ordering
1584
//
1585
1586
void 
1587
DwaCompressor::LossyDctEncoderBase::toZigZag (half *dst, half *src) 
1588
0
{
1589
0
    const int remap[] =
1590
0
    {
1591
0
         0, 
1592
0
         1,  8,
1593
0
        16,  9,  2,
1594
0
         3, 10, 17, 24,
1595
0
        32, 25, 18, 11, 4,
1596
0
         5, 12, 19, 26, 33, 40,
1597
0
        48, 41, 34, 27, 20, 13, 6,
1598
0
         7, 14, 21, 28, 35, 42, 49, 56,
1599
0
            57, 50, 43, 36, 29, 22, 15,
1600
0
                23, 30, 37, 44, 51, 58,
1601
0
                    59, 52, 45, 38, 31,
1602
0
                        39, 46, 53, 60,
1603
0
                            61, 54, 47,
1604
0
                                55, 62,
1605
0
                                    63
1606
0
    };
1607
1608
0
    for (int i=0; i<64; ++i)
1609
0
        dst[i] = src[remap[i]];
1610
0
}
1611
1612
1613
//
1614
// Precomputing the bit count runs faster than using
1615
// the builtin instruction, at least in one case..
1616
//
1617
// Precomputing 8-bits is no slower than 16-bits,
1618
// and saves a fair bit of overhead..
1619
//
1620
1621
int
1622
DwaCompressor::LossyDctEncoderBase::countSetBits (unsigned short src)
1623
0
{
1624
0
    static const unsigned short numBitsSet[256] =
1625
0
    {
1626
0
        0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1627
0
        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1628
0
        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1629
0
        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1630
0
        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1631
0
        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1632
0
        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1633
0
        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1634
0
        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1635
0
        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1636
0
        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1637
0
        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1638
0
        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1639
0
        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1640
0
        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1641
0
        4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
1642
0
    };
1643
1644
0
    return numBitsSet[src & 0xff] + numBitsSet[src >> 8];
1645
0
}
1646
1647
1648
//
1649
// Take a DCT coefficient, as well as an acceptable error. Search
1650
// nearby values within the error tolerance, that have fewer 
1651
// bits set.
1652
//
1653
// The list of candidates has been pre-computed and sorted 
1654
// in order of increasing numbers of bits set. This way, we
1655
// can stop searching as soon as we find a candidate that
1656
// is within the error tolerance.
1657
//
1658
1659
half
1660
DwaCompressor::LossyDctEncoderBase::quantize (half src, float errorTolerance)
1661
0
{
1662
0
    half            tmp;
1663
0
    float           srcFloat      = (float)src;
1664
0
    int             numSetBits    = countSetBits(src.bits());
1665
0
    const unsigned short *closest = get_dwaClosest(src.bits());
1666
1667
0
    for (int targetNumSetBits = numSetBits - 1;
1668
0
         targetNumSetBits >= 0;
1669
0
         --targetNumSetBits)
1670
0
    {
1671
0
        tmp.setBits (*closest);
1672
1673
0
        if (fabs ((float)tmp - srcFloat) < errorTolerance)
1674
0
            return tmp;
1675
1676
0
        closest++;
1677
0
    }
1678
1679
0
    return src;
1680
0
}
1681
1682
1683
//
1684
// RLE the zig-zag of the AC components + copy over 
1685
// into another tmp buffer
1686
//
1687
// Try to do a simple RLE scheme to reduce run's of 0's. This
1688
// differs from the jpeg EOB case, since EOB just indicates that
1689
// the rest of the block is zero. In our case, we have lots of
1690
// NaN symbols, which shouldn't be allowed to occur in DCT 
1691
// coefficents - so we'll use them for encoding runs.
1692
//
1693
// If the high byte is 0xff, then we have a run of 0's, of length
1694
// given by the low byte. For example, 0xff03 would be a run
1695
// of 3 0's, starting at the current location.
1696
//
1697
// block is our block of 64 coefficients
1698
// acPtr a pointer to back the RLE'd values into.
1699
//
1700
// This will advance the counter, _numAcComp.
1701
//
1702
1703
void
1704
DwaCompressor::LossyDctEncoderBase::rleAc
1705
    (half *block,
1706
     unsigned short *&acPtr)
1707
0
{
1708
0
    int dctComp              = 1; 
1709
0
    unsigned short rleSymbol = 0x0;
1710
1711
0
    while (dctComp < 64)
1712
0
    {
1713
0
        int runLen = 1;
1714
    
1715
        //
1716
        // If we don't have a 0, output verbatim
1717
        //
1718
1719
0
        if (block[dctComp].bits() != rleSymbol)
1720
0
        {
1721
0
            *acPtr++ =  block[dctComp].bits();
1722
0
            _numAcComp++;
1723
1724
0
            dctComp += runLen;
1725
0
            continue;
1726
0
        }
1727
1728
        //
1729
        // We're sitting on a 0, so see how big the run is.
1730
        //
1731
1732
0
        while ((dctComp+runLen < 64) && 
1733
0
               (block[dctComp+runLen].bits() == rleSymbol))
1734
0
        {
1735
0
            runLen++;
1736
0
        }
1737
1738
        //
1739
        // If the run len is too small, just output verbatim
1740
        // otherwise output our run token
1741
        //
1742
        // Originally, we wouldn't have a separate symbol for
1743
        // "end of block". But in some experimentation, it looks
1744
        // like using 0xff00 for "end of block" can save a bit
1745
        // of space. 
1746
        //
1747
1748
0
        if (runLen == 1)
1749
0
        {
1750
0
            runLen           = 1;
1751
0
            *acPtr++ = block[dctComp].bits();
1752
0
            _numAcComp++;
1753
1754
            //
1755
            // Using 0xff00 for "end of block"
1756
            //
1757
0
        }
1758
0
        else if (runLen + dctComp == 64)
1759
0
        {
1760
            //
1761
            // Signal EOB
1762
            //
1763
1764
0
            *acPtr++ = 0xff00;
1765
0
            _numAcComp++;
1766
0
        }
1767
0
        else
1768
0
        {
1769
            // 
1770
            // Signal normal run
1771
            //
1772
1773
0
            *acPtr++   = 0xff00 | runLen;
1774
0
            _numAcComp++;
1775
0
        }
1776
1777
        //
1778
        // Advance by runLen
1779
        //
1780
1781
0
        dctComp += runLen;
1782
0
    }
1783
0
}
1784
1785
1786
// ==============================================================
1787
//
1788
//                     DwaCompressor
1789
//
1790
// --------------------------------------------------------------
1791
1792
// 
1793
// DwaCompressor()
1794
//
1795
1796
DwaCompressor::DwaCompressor
1797
    (const Header &hdr,
1798
     int maxScanLineSize,
1799
     int numScanLines,
1800
     AcCompression acCompression)
1801
:
1802
0
    Compressor(hdr),
1803
0
    _acCompression(acCompression),
1804
0
    _maxScanLineSize(maxScanLineSize),
1805
0
    _numScanLines(numScanLines),
1806
0
    _channels(hdr.channels()),
1807
0
    _packedAcBuffer(0),
1808
0
    _packedAcBufferSize(0),
1809
0
    _packedDcBuffer(0),
1810
0
    _packedDcBufferSize(0),
1811
0
    _rleBuffer(0),
1812
0
    _rleBufferSize(0),
1813
0
    _outBuffer(0),
1814
0
    _outBufferSize(0),
1815
0
    _zip(0),
1816
0
    _dwaCompressionLevel(45.0)
1817
0
{
1818
0
    _min[0] = hdr.dataWindow().min.x;
1819
0
    _min[1] = hdr.dataWindow().min.y;
1820
0
    _max[0] = hdr.dataWindow().max.x;
1821
0
    _max[1] = hdr.dataWindow().max.y;
1822
1823
0
    for (int i=0; i < NUM_COMPRESSOR_SCHEMES; ++i) 
1824
0
    {
1825
0
        _planarUncBuffer[i] = 0;
1826
0
        _planarUncBufferSize[i] = 0;
1827
0
    }
1828
    
1829
    //
1830
    // Check the header for a quality attribute
1831
    //
1832
1833
0
    if (hasDwaCompressionLevel (hdr))
1834
0
        _dwaCompressionLevel = dwaCompressionLevel (hdr);
1835
0
}
1836
1837
1838
DwaCompressor::~DwaCompressor()
1839
0
{
1840
0
    delete[] _packedAcBuffer;
1841
0
    delete[] _packedDcBuffer;
1842
0
    delete[] _rleBuffer;
1843
0
    delete[] _outBuffer;
1844
0
    delete _zip;
1845
1846
0
    for (int i=0; i<NUM_COMPRESSOR_SCHEMES; ++i)
1847
0
        delete[] _planarUncBuffer[i];
1848
0
}
1849
1850
1851
int
1852
DwaCompressor::numScanLines() const
1853
0
{
1854
0
    return _numScanLines;
1855
0
}
1856
1857
1858
OPENEXR_IMF_NAMESPACE::Compressor::Format 
1859
DwaCompressor::format() const
1860
0
{
1861
0
    if (GLOBAL_SYSTEM_LITTLE_ENDIAN)
1862
0
        return NATIVE;
1863
0
    else
1864
0
        return XDR;
1865
0
}
1866
1867
1868
int
1869
DwaCompressor::compress
1870
    (const char *inPtr,
1871
     int inSize,
1872
     int minY,
1873
     const char *&outPtr)
1874
0
{
1875
0
    return compress
1876
0
        (inPtr,
1877
0
         inSize, 
1878
0
         IMATH_NAMESPACE::Box2i (IMATH_NAMESPACE::V2i (_min[0], minY),
1879
0
                                 IMATH_NAMESPACE::V2i (_max[0], minY + numScanLines() - 1)),
1880
0
         outPtr);
1881
0
}
1882
1883
1884
int
1885
DwaCompressor::compressTile
1886
    (const char             *inPtr,
1887
     int                    inSize,
1888
     IMATH_NAMESPACE::Box2i range,
1889
     const char             *&outPtr)
1890
0
{
1891
0
    return compress (inPtr, inSize, range, outPtr);
1892
0
}
1893
1894
1895
int 
1896
DwaCompressor::compress
1897
    (const char             *inPtr,
1898
     int                    inSize,
1899
     IMATH_NAMESPACE::Box2i range,
1900
     const char             *&outPtr)
1901
0
{
1902
0
    const char *inDataPtr   = inPtr;
1903
0
    char       *packedAcEnd = 0;
1904
0
    char       *packedDcEnd = 0; 
1905
0
    int         fileVersion = 2;   // Starting with 2, we write the channel
1906
                                   // classification rules into the file
1907
1908
0
    if (fileVersion < 2) 
1909
0
        initializeLegacyChannelRules();
1910
0
    else 
1911
0
        initializeDefaultChannelRules();
1912
1913
0
    size_t outBufferSize = 0;
1914
0
    initializeBuffers(outBufferSize);
1915
1916
0
    unsigned short          channelRuleSize = 0;
1917
0
    std::vector<Classifier> channelRules;
1918
0
    if (fileVersion >= 2) 
1919
0
    {
1920
0
        relevantChannelRules(channelRules);
1921
1922
0
        channelRuleSize = Xdr::size<unsigned short>();
1923
0
        for (size_t i = 0; i < channelRules.size(); ++i) 
1924
0
            channelRuleSize += channelRules[i].size();
1925
0
    }
1926
1927
    //
1928
    // Remember to allocate _outBuffer, if we haven't done so already.
1929
    //
1930
1931
0
    outBufferSize += channelRuleSize;
1932
0
    if (outBufferSize > _outBufferSize) 
1933
0
    {
1934
0
        _outBufferSize = outBufferSize;
1935
0
        if (_outBuffer != 0)
1936
0
            delete[] _outBuffer;       
1937
0
        _outBuffer = new char[outBufferSize];
1938
0
    }
1939
1940
0
    char *outDataPtr = &_outBuffer[NUM_SIZES_SINGLE * sizeof(OPENEXR_IMF_NAMESPACE::Int64) +
1941
0
                                   channelRuleSize];
1942
1943
    //
1944
    // We might not be dealing with any color data, in which
1945
    // case the AC buffer size will be 0, and deferencing
1946
    // a vector will not be a good thing to do.
1947
    //
1948
1949
0
    if (_packedAcBuffer)
1950
0
        packedAcEnd = _packedAcBuffer;
1951
1952
0
    if (_packedDcBuffer)
1953
0
        packedDcEnd = _packedDcBuffer;
1954
1955
0
    #define OBIDX(x) (Int64 *)&_outBuffer[x * sizeof (Int64)]
1956
1957
0
    Int64 *version                 = OBIDX (VERSION);
1958
0
    Int64 *unknownUncompressedSize = OBIDX (UNKNOWN_UNCOMPRESSED_SIZE);
1959
0
    Int64 *unknownCompressedSize   = OBIDX (UNKNOWN_COMPRESSED_SIZE);
1960
0
    Int64 *acCompressedSize        = OBIDX (AC_COMPRESSED_SIZE);
1961
0
    Int64 *dcCompressedSize        = OBIDX (DC_COMPRESSED_SIZE);
1962
0
    Int64 *rleCompressedSize       = OBIDX (RLE_COMPRESSED_SIZE);
1963
0
    Int64 *rleUncompressedSize     = OBIDX (RLE_UNCOMPRESSED_SIZE);
1964
0
    Int64 *rleRawSize              = OBIDX (RLE_RAW_SIZE);
1965
1966
0
    Int64 *totalAcUncompressedCount = OBIDX (AC_UNCOMPRESSED_COUNT);
1967
0
    Int64 *totalDcUncompressedCount = OBIDX (DC_UNCOMPRESSED_COUNT);
1968
1969
0
    Int64 *acCompression            = OBIDX (AC_COMPRESSION);
1970
1971
0
    int minX   = range.min.x;
1972
0
    int maxX   = std::min(range.max.x, _max[0]);
1973
0
    int minY   = range.min.y;
1974
0
    int maxY   = std::min(range.max.y, _max[1]);
1975
1976
    //
1977
    // Zero all the numbers in the chunk header
1978
    //
1979
1980
0
    memset (_outBuffer, 0, NUM_SIZES_SINGLE * sizeof (Int64));
1981
1982
    //
1983
    // Setup the AC compression strategy and the version in the data block,
1984
    // then write the relevant channel classification rules if needed
1985
    //
1986
0
    *version       = fileVersion;  
1987
0
    *acCompression = _acCompression;
1988
1989
0
    setupChannelData (minX, minY, maxX, maxY);
1990
1991
0
    if (fileVersion >= 2) 
1992
0
    {
1993
0
        char *writePtr = &_outBuffer[NUM_SIZES_SINGLE * sizeof(OPENEXR_IMF_NAMESPACE::Int64)];
1994
0
        Xdr::write<CharPtrIO> (writePtr, channelRuleSize);
1995
        
1996
0
        for (size_t i = 0; i < channelRules.size(); ++i) 
1997
0
            channelRules[i].write(writePtr);
1998
0
    }
1999
2000
    //
2001
    // Determine the start of each row in the input buffer
2002
    // Channels are interleaved by scanline
2003
    //
2004
2005
0
    std::vector<bool> encodedChannels (_channelData.size());
2006
0
    std::vector< std::vector<const char *> > rowPtrs (_channelData.size());
2007
2008
0
    for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
2009
0
        encodedChannels[chan] = false;
2010
2011
0
    inDataPtr =  inPtr;
2012
2013
0
    for (int y = minY; y <= maxY; ++y)
2014
0
    {
2015
0
        for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
2016
0
        {
2017
2018
0
            ChannelData *cd = &_channelData[chan];
2019
2020
0
            if (IMATH_NAMESPACE::modp(y, cd->ySampling) != 0)
2021
0
                continue;
2022
2023
0
            rowPtrs[chan].push_back(inDataPtr);
2024
0
            inDataPtr += cd->width * OPENEXR_IMF_NAMESPACE::pixelTypeSize(cd->type);
2025
0
        }
2026
0
    }
2027
2028
0
    inDataPtr = inPtr;
2029
2030
    // 
2031
    // Make a pass over all our CSC sets and try to encode them first
2032
    // 
2033
2034
0
    for (unsigned int csc = 0; csc < _cscSets.size(); ++csc)
2035
0
    {
2036
2037
0
        LossyDctEncoderCsc encoder
2038
0
            (_dwaCompressionLevel / 100000.f,
2039
0
             rowPtrs[_cscSets[csc].idx[0]],
2040
0
             rowPtrs[_cscSets[csc].idx[1]],
2041
0
             rowPtrs[_cscSets[csc].idx[2]],
2042
0
             packedAcEnd,
2043
0
             packedDcEnd,
2044
0
             get_dwaCompressorToNonlinear(),
2045
0
             _channelData[_cscSets[csc].idx[0]].width,
2046
0
             _channelData[_cscSets[csc].idx[0]].height,
2047
0
             _channelData[_cscSets[csc].idx[0]].type,
2048
0
             _channelData[_cscSets[csc].idx[1]].type,
2049
0
             _channelData[_cscSets[csc].idx[2]].type);
2050
2051
0
        encoder.execute();
2052
2053
0
        *totalAcUncompressedCount  += encoder.numAcValuesEncoded();
2054
0
        *totalDcUncompressedCount  += encoder.numDcValuesEncoded();
2055
2056
0
        packedAcEnd += encoder.numAcValuesEncoded() * sizeof(unsigned short);
2057
0
        packedDcEnd += encoder.numDcValuesEncoded() * sizeof(unsigned short);
2058
2059
0
        encodedChannels[_cscSets[csc].idx[0]] = true;
2060
0
        encodedChannels[_cscSets[csc].idx[1]] = true;
2061
0
        encodedChannels[_cscSets[csc].idx[2]] = true;
2062
0
    }
2063
2064
0
    for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
2065
0
    {
2066
0
        ChannelData *cd = &_channelData[chan];
2067
2068
0
        if (encodedChannels[chan])
2069
0
            continue;
2070
2071
0
        switch (cd->compression)
2072
0
        {
2073
0
          case LOSSY_DCT:
2074
2075
            //
2076
            // For LOSSY_DCT, treat this just like the CSC'd case,
2077
            // but only operate on one channel
2078
            //
2079
2080
0
            {
2081
0
                const unsigned short *nonlinearLut = 0;
2082
2083
0
                if (!cd->pLinear)
2084
0
                    nonlinearLut = get_dwaCompressorToNonlinear(); 
2085
2086
0
                LossyDctEncoder encoder
2087
0
                    (_dwaCompressionLevel / 100000.f,
2088
0
                     rowPtrs[chan],
2089
0
                     packedAcEnd,
2090
0
                     packedDcEnd,
2091
0
                     nonlinearLut,
2092
0
                     cd->width,
2093
0
                     cd->height,
2094
0
                     cd->type);
2095
2096
0
                encoder.execute();
2097
2098
0
                *totalAcUncompressedCount  += encoder.numAcValuesEncoded();
2099
0
                *totalDcUncompressedCount  += encoder.numDcValuesEncoded();
2100
2101
0
                packedAcEnd +=
2102
0
                    encoder.numAcValuesEncoded() * sizeof (unsigned short);
2103
2104
0
                packedDcEnd +=
2105
0
                    encoder.numDcValuesEncoded() * sizeof (unsigned short);
2106
0
            }
2107
2108
0
            break;
2109
2110
0
          case RLE:
2111
2112
            //
2113
            // For RLE, bash the bytes up so that the first bytes of each
2114
            // pixel are contingous, as are the second bytes, and so on.
2115
            //
2116
2117
0
            for (unsigned int y = 0; y < rowPtrs[chan].size(); ++y)
2118
0
            {
2119
0
                const char *row = rowPtrs[chan][y];
2120
2121
0
                for (int x = 0; x < cd->width; ++x)
2122
0
                {
2123
0
                    for (int byte = 0;
2124
0
                         byte < OPENEXR_IMF_NAMESPACE::pixelTypeSize (cd->type);
2125
0
                         ++byte)
2126
0
                    {
2127
                            
2128
0
                        *cd->planarUncRleEnd[byte]++ = *row++;
2129
0
                    }
2130
0
                }
2131
2132
0
                *rleRawSize += cd->width * OPENEXR_IMF_NAMESPACE::pixelTypeSize(cd->type);
2133
0
            }
2134
2135
0
            break;
2136
2137
0
          case UNKNOWN:
2138
           
2139
            //
2140
            // Otherwise, just copy data over verbatim
2141
            //
2142
2143
0
            {
2144
0
                int scanlineSize = cd->width * OPENEXR_IMF_NAMESPACE::pixelTypeSize(cd->type);
2145
2146
0
                for (unsigned int y = 0; y < rowPtrs[chan].size(); ++y)
2147
0
                {
2148
0
                    memcpy (cd->planarUncBufferEnd,
2149
0
                            rowPtrs[chan][y],
2150
0
                            scanlineSize);
2151
    
2152
0
                    cd->planarUncBufferEnd += scanlineSize;
2153
0
                }
2154
2155
0
                *unknownUncompressedSize += cd->planarUncSize;
2156
0
            }
2157
2158
0
            break;
2159
2160
0
          default:
2161
2162
0
            assert (false);
2163
0
        }
2164
2165
0
        encodedChannels[chan] = true;
2166
0
    }
2167
2168
    //
2169
    // Pack the Unknown data into the output buffer first. Instead of
2170
    // just copying it uncompressed, try zlib compression at least.
2171
    //
2172
2173
0
    if (*unknownUncompressedSize > 0)
2174
0
    {
2175
0
        uLongf inSize  = (uLongf)(*unknownUncompressedSize);
2176
0
        uLongf outSize = compressBound (inSize);
2177
2178
0
        if (Z_OK != ::compress2 ((Bytef *)outDataPtr,
2179
0
                                 &outSize,
2180
0
                                 (const Bytef *)_planarUncBuffer[UNKNOWN],
2181
0
                                 inSize,
2182
0
                                 9))
2183
0
        {
2184
0
            throw IEX_NAMESPACE::BaseExc ("Data compression (zlib) failed.");
2185
0
        }
2186
2187
0
        outDataPtr += outSize;
2188
0
        *unknownCompressedSize = outSize;
2189
0
    }
2190
2191
    //
2192
    // Now, pack all the Lossy DCT coefficients into our output
2193
    // buffer, with Huffman encoding.
2194
    //
2195
    // Also, record the compressed size and the number of 
2196
    // uncompressed componentns we have.
2197
    //
2198
2199
0
    if (*totalAcUncompressedCount > 0)
2200
0
    { 
2201
0
        switch (_acCompression)
2202
0
        {
2203
0
          case STATIC_HUFFMAN:
2204
2205
0
            *acCompressedSize = (int)
2206
0
                hufCompress((unsigned short *)_packedAcBuffer,
2207
0
                            (int)*totalAcUncompressedCount,
2208
0
                            outDataPtr);                
2209
0
            break;
2210
2211
0
          case DEFLATE:
2212
2213
0
            {
2214
0
                uLongf destLen = compressBound (
2215
0
                    (*totalAcUncompressedCount) * sizeof (unsigned short));
2216
2217
0
                if (Z_OK != ::compress2
2218
0
                                ((Bytef *)outDataPtr,
2219
0
                                 &destLen,
2220
0
                                 (Bytef *)_packedAcBuffer, 
2221
0
                                 (uLong)(*totalAcUncompressedCount
2222
0
                                                * sizeof (unsigned short)),
2223
0
                                 9))
2224
0
                {
2225
0
                    throw IEX_NAMESPACE::InputExc ("Data compression (zlib) failed.");
2226
0
                }
2227
2228
0
                *acCompressedSize = destLen;        
2229
0
            }
2230
2231
0
            break;
2232
2233
0
          default:
2234
            
2235
0
            assert (false);
2236
0
        }
2237
2238
0
        outDataPtr += *acCompressedSize;
2239
0
    }
2240
2241
    // 
2242
    // Handle the DC components separately
2243
    //
2244
2245
0
    if (*totalDcUncompressedCount > 0)
2246
0
    {
2247
0
        *dcCompressedSize = _zip->compress
2248
0
            (_packedDcBuffer,
2249
0
             (int)(*totalDcUncompressedCount) * sizeof (unsigned short),
2250
0
             outDataPtr);
2251
2252
0
        outDataPtr += *dcCompressedSize;
2253
0
    }
2254
2255
    // 
2256
    // If we have RLE data, first RLE encode it and set the uncompressed
2257
    // size. Then, deflate the results and set the compressed size.
2258
    //    
2259
2260
0
    if (*rleRawSize > 0)
2261
0
    {
2262
0
        *rleUncompressedSize = rleCompress
2263
0
            ((int)(*rleRawSize),
2264
0
             _planarUncBuffer[RLE],
2265
0
             (signed char *)_rleBuffer);
2266
2267
0
        uLongf dstLen = compressBound ((uLongf)*rleUncompressedSize);
2268
2269
0
        if (Z_OK != ::compress2
2270
0
                        ((Bytef *)outDataPtr, 
2271
0
                         &dstLen, 
2272
0
                         (Bytef *)_rleBuffer, 
2273
0
                         (uLong)(*rleUncompressedSize),
2274
0
                         9))
2275
0
        {
2276
0
            throw IEX_NAMESPACE::BaseExc ("Error compressing RLE'd data.");
2277
0
        }
2278
        
2279
0
       *rleCompressedSize = dstLen;
2280
0
        outDataPtr       += *rleCompressedSize;
2281
0
    }
2282
2283
    // 
2284
    // Flip the counters to XDR format
2285
    //         
2286
2287
0
    for (int i = 0; i < NUM_SIZES_SINGLE; ++i)
2288
0
    {
2289
0
        Int64  src = *(((Int64 *)_outBuffer) + i);
2290
0
        char  *dst = (char *)(((Int64 *)_outBuffer) + i);
2291
2292
0
        Xdr::write<CharPtrIO> (dst, src);
2293
0
    }
2294
2295
    //
2296
    // We're done - compute the number of bytes we packed
2297
    //
2298
2299
0
    outPtr = _outBuffer;
2300
2301
0
    return static_cast<int>(outDataPtr - _outBuffer + 1);
2302
0
}
2303
2304
2305
int
2306
DwaCompressor::uncompress
2307
    (const char *inPtr,
2308
     int inSize,
2309
     int minY,
2310
     const char *&outPtr)
2311
0
{
2312
0
    return uncompress (inPtr,
2313
0
                       inSize,
2314
0
                       IMATH_NAMESPACE::Box2i (IMATH_NAMESPACE::V2i (_min[0], minY),
2315
0
                       IMATH_NAMESPACE::V2i (_max[0], minY + numScanLines() - 1)),
2316
0
                       outPtr);
2317
0
}
2318
2319
2320
int 
2321
DwaCompressor::uncompressTile
2322
    (const char *inPtr,
2323
     int inSize,
2324
     IMATH_NAMESPACE::Box2i range,
2325
     const char *&outPtr)
2326
0
{
2327
0
    return uncompress (inPtr, inSize, range, outPtr);
2328
0
}
2329
2330
2331
int 
2332
DwaCompressor::uncompress
2333
    (const char *inPtr,
2334
     int inSize,
2335
     IMATH_NAMESPACE::Box2i range,
2336
     const char *&outPtr)
2337
0
{
2338
0
    int minX = range.min.x;
2339
0
    int maxX = std::min (range.max.x, _max[0]);
2340
0
    int minY = range.min.y;
2341
0
    int maxY = std::min (range.max.y, _max[1]);
2342
2343
0
    int headerSize = NUM_SIZES_SINGLE*sizeof(Int64);
2344
0
    if (inSize < headerSize) 
2345
0
    {
2346
0
        throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
2347
0
                            "(truncated header).");
2348
0
    }
2349
2350
    // 
2351
    // Flip the counters from XDR to NATIVE
2352
    //
2353
2354
0
    for (int i = 0; i < NUM_SIZES_SINGLE; ++i)
2355
0
    {
2356
0
        Int64      *dst =  (((Int64 *)inPtr) + i);
2357
0
        const char *src = (char *)(((Int64 *)inPtr) + i);
2358
2359
0
        Xdr::read<CharPtrIO> (src, *dst);
2360
0
    }
2361
2362
    //
2363
    // Unwind all the counter info
2364
    //
2365
2366
0
    const Int64 *inPtr64 = (const Int64*) inPtr;
2367
2368
0
    Int64 version                  = *(inPtr64 + VERSION);
2369
0
    Int64 unknownUncompressedSize  = *(inPtr64 + UNKNOWN_UNCOMPRESSED_SIZE);
2370
0
    Int64 unknownCompressedSize    = *(inPtr64 + UNKNOWN_COMPRESSED_SIZE);
2371
0
    Int64 acCompressedSize         = *(inPtr64 + AC_COMPRESSED_SIZE);
2372
0
    Int64 dcCompressedSize         = *(inPtr64 + DC_COMPRESSED_SIZE);
2373
0
    Int64 rleCompressedSize        = *(inPtr64 + RLE_COMPRESSED_SIZE);
2374
0
    Int64 rleUncompressedSize      = *(inPtr64 + RLE_UNCOMPRESSED_SIZE);
2375
0
    Int64 rleRawSize               = *(inPtr64 + RLE_RAW_SIZE);
2376
 
2377
0
    Int64 totalAcUncompressedCount = *(inPtr64 + AC_UNCOMPRESSED_COUNT); 
2378
0
    Int64 totalDcUncompressedCount = *(inPtr64 + DC_UNCOMPRESSED_COUNT); 
2379
2380
0
    Int64 acCompression            = *(inPtr64 + AC_COMPRESSION); 
2381
2382
0
    Int64 compressedSize           = unknownCompressedSize + 
2383
0
                                     acCompressedSize +
2384
0
                                     dcCompressedSize +
2385
0
                                     rleCompressedSize;
2386
2387
0
    const char *dataPtr            = inPtr + NUM_SIZES_SINGLE * sizeof(Int64);
2388
2389
    /* Both the sum and individual sizes are checked in case of overflow. */
2390
0
    if (inSize < (headerSize + compressedSize) ||
2391
0
        inSize < unknownCompressedSize ||
2392
0
        inSize < acCompressedSize ||
2393
0
        inSize < dcCompressedSize ||
2394
0
        inSize < rleCompressedSize)
2395
0
    {
2396
0
        throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
2397
0
                            "(truncated file).");
2398
0
    }
2399
2400
0
    if ((SInt64)unknownUncompressedSize < 0  ||
2401
0
        (SInt64)unknownCompressedSize < 0    ||
2402
0
        (SInt64)acCompressedSize < 0         ||
2403
0
        (SInt64)dcCompressedSize < 0         ||
2404
0
        (SInt64)rleCompressedSize < 0        ||
2405
0
        (SInt64)rleUncompressedSize < 0      ||
2406
0
        (SInt64)rleRawSize < 0               ||
2407
0
        (SInt64)totalAcUncompressedCount < 0 ||
2408
0
        (SInt64)totalDcUncompressedCount < 0)
2409
0
    {
2410
0
        throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
2411
0
                            " (corrupt header).");
2412
0
    }
2413
2414
0
    if (version < 2) 
2415
0
        initializeLegacyChannelRules();
2416
0
    else
2417
0
    {
2418
0
        unsigned short ruleSize = 0;
2419
0
        Xdr::read<CharPtrIO>(dataPtr, ruleSize);
2420
2421
0
        if (ruleSize < 0) 
2422
0
            throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
2423
0
                                " (corrupt header file).");
2424
2425
0
        headerSize += ruleSize;
2426
0
        if (inSize < headerSize + compressedSize)
2427
0
            throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
2428
0
                                " (truncated file).");
2429
2430
0
        _channelRules.clear();
2431
0
        ruleSize -= Xdr::size<unsigned short> ();
2432
0
        while (ruleSize > 0) 
2433
0
        {
2434
0
            Classifier rule(dataPtr, ruleSize);
2435
            
2436
0
            _channelRules.push_back(rule);
2437
0
            ruleSize -= rule.size();
2438
0
        }
2439
0
    }
2440
2441
2442
0
    size_t outBufferSize = 0;
2443
0
    initializeBuffers(outBufferSize);
2444
2445
    //
2446
    // Allocate _outBuffer, if we haven't done so already
2447
    //
2448
2449
0
    if (_maxScanLineSize * numScanLines() > _outBufferSize) 
2450
0
    {
2451
0
        _outBufferSize = _maxScanLineSize * numScanLines();
2452
0
        if (_outBuffer != 0)
2453
0
            delete[] _outBuffer;
2454
0
        _outBuffer = new char[_maxScanLineSize * numScanLines()];
2455
0
    }
2456
2457
2458
0
    char *outBufferEnd = _outBuffer;
2459
2460
       
2461
    //
2462
    // Find the start of the RLE packed AC components and
2463
    // the DC components for each channel. This will be handy   
2464
    // if you want to decode the channels in parallel later on.
2465
    //
2466
2467
0
    char *packedAcBufferEnd = 0; 
2468
2469
0
    if (_packedAcBuffer)
2470
0
        packedAcBufferEnd = _packedAcBuffer;
2471
2472
0
    char *packedDcBufferEnd = 0;
2473
2474
0
    if (_packedDcBuffer)
2475
0
        packedDcBufferEnd = _packedDcBuffer;
2476
2477
    //
2478
    // UNKNOWN data is packed first, followed by the 
2479
    // Huffman-compressed AC, then the DC values, 
2480
    // and then the zlib compressed RLE data.
2481
    //
2482
    
2483
0
    const char *compressedUnknownBuf = dataPtr;
2484
2485
0
    const char *compressedAcBuf      = compressedUnknownBuf + 
2486
0
                                  static_cast<ptrdiff_t>(unknownCompressedSize);
2487
0
    const char *compressedDcBuf      = compressedAcBuf +
2488
0
                                  static_cast<ptrdiff_t>(acCompressedSize);
2489
0
    const char *compressedRleBuf     = compressedDcBuf + 
2490
0
                                  static_cast<ptrdiff_t>(dcCompressedSize);
2491
2492
    // 
2493
    // Sanity check that the version is something we expect. Right now, 
2494
    // we can decode version 0, 1, and 2. v1 adds 'end of block' symbols
2495
    // to the AC RLE. v2 adds channel classification rules at the 
2496
    // start of the data block.
2497
    //
2498
2499
0
    if (version > 2)
2500
0
        throw IEX_NAMESPACE::InputExc ("Invalid version of compressed data block");    
2501
2502
0
    setupChannelData(minX, minY, maxX, maxY);
2503
2504
    // 
2505
    // Uncompress the UNKNOWN data into _planarUncBuffer[UNKNOWN]
2506
    //
2507
2508
0
    if (unknownCompressedSize > 0)
2509
0
    {
2510
0
        if (unknownUncompressedSize > _planarUncBufferSize[UNKNOWN]) 
2511
0
        {
2512
0
            throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
2513
0
                                "(corrupt header).");
2514
0
        }
2515
2516
0
        uLongf outSize = (uLongf)unknownUncompressedSize;
2517
2518
0
        if (Z_OK != ::uncompress
2519
0
                        ((Bytef *)_planarUncBuffer[UNKNOWN],
2520
0
                         &outSize,
2521
0
                         (Bytef *)compressedUnknownBuf,
2522
0
                         (uLong)unknownCompressedSize))
2523
0
        {
2524
0
            throw IEX_NAMESPACE::BaseExc("Error uncompressing UNKNOWN data.");
2525
0
        }
2526
0
    }
2527
2528
    // 
2529
    // Uncompress the AC data into _packedAcBuffer
2530
    //
2531
2532
0
    if (acCompressedSize > 0)
2533
0
    {
2534
0
        if (totalAcUncompressedCount*sizeof(unsigned short) > _packedAcBufferSize)
2535
0
        {
2536
0
            throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
2537
0
                                "(corrupt header).");
2538
0
        }
2539
2540
        //
2541
        // Don't trust the user to get it right, look in the file.
2542
        //
2543
2544
0
        switch (acCompression)
2545
0
        {
2546
0
          case STATIC_HUFFMAN:
2547
2548
0
            hufUncompress
2549
0
                (compressedAcBuf, 
2550
0
                 (int)acCompressedSize, 
2551
0
                 (unsigned short *)_packedAcBuffer, 
2552
0
                 (int)totalAcUncompressedCount); 
2553
2554
0
            break;
2555
2556
0
          case DEFLATE:
2557
0
            {
2558
0
                uLongf destLen =
2559
0
                    (int)(totalAcUncompressedCount) * sizeof (unsigned short);
2560
2561
0
                if (Z_OK != ::uncompress
2562
0
                                ((Bytef *)_packedAcBuffer,
2563
0
                                 &destLen,
2564
0
                                 (Bytef *)compressedAcBuf,
2565
0
                                 (uLong)acCompressedSize))
2566
0
                {
2567
0
                    throw IEX_NAMESPACE::InputExc ("Data decompression (zlib) failed.");
2568
0
                }
2569
2570
0
                if (totalAcUncompressedCount * sizeof (unsigned short) !=
2571
0
                                destLen)
2572
0
                {
2573
0
                    throw IEX_NAMESPACE::InputExc ("AC data corrupt.");     
2574
0
                }
2575
0
            }
2576
0
            break;
2577
2578
0
          default:
2579
2580
0
            throw IEX_NAMESPACE::NoImplExc ("Unknown AC Compression");
2581
0
            break;
2582
0
        }
2583
0
    }
2584
2585
    //
2586
    // Uncompress the DC data into _packedDcBuffer
2587
    //
2588
2589
0
    if (dcCompressedSize > 0)
2590
0
    {
2591
0
        if (totalDcUncompressedCount*sizeof(unsigned short) > _packedDcBufferSize)
2592
0
        {
2593
0
            throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
2594
0
                                "(corrupt header).");
2595
0
        }
2596
2597
0
        if (_zip->uncompress
2598
0
                    (compressedDcBuf, (int)dcCompressedSize, _packedDcBuffer)
2599
0
            != (int)totalDcUncompressedCount * sizeof (unsigned short))
2600
0
        {
2601
0
            throw IEX_NAMESPACE::BaseExc("DC data corrupt.");
2602
0
        }
2603
0
    }
2604
2605
    //
2606
    // Uncompress the RLE data into _rleBuffer, then unRLE the results
2607
    // into _planarUncBuffer[RLE]
2608
    //
2609
2610
0
    if (rleRawSize > 0)
2611
0
    {
2612
0
        if (rleUncompressedSize > _rleBufferSize ||
2613
0
            rleRawSize > _planarUncBufferSize[RLE])
2614
0
        {
2615
0
            throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
2616
0
                                "(corrupt header).");
2617
0
        }
2618
 
2619
0
        uLongf dstLen = (uLongf)rleUncompressedSize;
2620
2621
0
        if (Z_OK != ::uncompress
2622
0
                        ((Bytef *)_rleBuffer,
2623
0
                         &dstLen,
2624
0
                         (Bytef *)compressedRleBuf,
2625
0
                         (uLong)rleCompressedSize))
2626
0
        {
2627
0
            throw IEX_NAMESPACE::BaseExc("Error uncompressing RLE data.");
2628
0
        }
2629
2630
0
        if (dstLen != rleUncompressedSize)
2631
0
            throw IEX_NAMESPACE::BaseExc("RLE data corrupted");
2632
2633
0
        if (rleUncompress
2634
0
                ((int)rleUncompressedSize, 
2635
0
                 (int)rleRawSize,
2636
0
                 (signed char *)_rleBuffer,
2637
0
                 _planarUncBuffer[RLE]) != rleRawSize)
2638
0
        {        
2639
0
            throw IEX_NAMESPACE::BaseExc("RLE data corrupted");
2640
0
        }
2641
0
    }
2642
2643
    //
2644
    // Determine the start of each row in the output buffer
2645
    //
2646
2647
0
    std::vector<bool> decodedChannels (_channelData.size());
2648
0
    std::vector< std::vector<char *> > rowPtrs (_channelData.size());
2649
2650
0
    for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
2651
0
        decodedChannels[chan] = false;
2652
2653
0
    outBufferEnd = _outBuffer;
2654
2655
0
    for (int y = minY; y <= maxY; ++y)
2656
0
    {
2657
0
        for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
2658
0
        {
2659
0
            ChannelData *cd = &_channelData[chan];
2660
2661
0
            if (IMATH_NAMESPACE::modp (y, cd->ySampling) != 0)
2662
0
                continue;
2663
2664
0
            rowPtrs[chan].push_back (outBufferEnd);
2665
0
            outBufferEnd += cd->width * OPENEXR_IMF_NAMESPACE::pixelTypeSize (cd->type);
2666
0
        }
2667
0
    }
2668
2669
    //
2670
    // Setup to decode each block of 3 channels that need to
2671
    // be handled together
2672
    //
2673
2674
0
    for (unsigned int csc = 0; csc < _cscSets.size(); ++csc)
2675
0
    {
2676
0
        int rChan = _cscSets[csc].idx[0];    
2677
0
        int gChan = _cscSets[csc].idx[1];    
2678
0
        int bChan = _cscSets[csc].idx[2];    
2679
2680
2681
0
        LossyDctDecoderCsc decoder
2682
0
            (rowPtrs[rChan],
2683
0
             rowPtrs[gChan],
2684
0
             rowPtrs[bChan],
2685
0
             packedAcBufferEnd,
2686
0
             packedDcBufferEnd,
2687
0
             get_dwaCompressorToLinear(),
2688
0
             _channelData[rChan].width,
2689
0
             _channelData[rChan].height,
2690
0
             _channelData[rChan].type,
2691
0
             _channelData[gChan].type,
2692
0
             _channelData[bChan].type);
2693
2694
0
        decoder.execute();
2695
2696
0
        packedAcBufferEnd +=
2697
0
            decoder.numAcValuesEncoded() * sizeof (unsigned short);
2698
2699
0
        packedDcBufferEnd +=
2700
0
            decoder.numDcValuesEncoded() * sizeof (unsigned short);
2701
2702
0
        decodedChannels[rChan] = true;
2703
0
        decodedChannels[gChan] = true;
2704
0
        decodedChannels[bChan] = true;
2705
0
    }
2706
2707
    //
2708
    // Setup to handle the remaining channels by themselves
2709
    //
2710
2711
0
    for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
2712
0
    {
2713
0
        if (decodedChannels[chan])
2714
0
            continue;
2715
2716
0
        ChannelData *cd = &_channelData[chan];
2717
0
        int pixelSize = OPENEXR_IMF_NAMESPACE::pixelTypeSize (cd->type);
2718
2719
0
        switch (cd->compression)
2720
0
        {
2721
0
          case LOSSY_DCT:
2722
2723
            //
2724
            // Setup a single-channel lossy DCT decoder pointing
2725
            // at the output buffer
2726
            //
2727
2728
0
            {
2729
0
                const unsigned short *linearLut = 0;
2730
2731
0
                if (!cd->pLinear)
2732
0
                    linearLut = get_dwaCompressorToLinear();
2733
2734
0
                LossyDctDecoder decoder
2735
0
                    (rowPtrs[chan],
2736
0
                     packedAcBufferEnd,
2737
0
                     packedDcBufferEnd,
2738
0
                     linearLut,
2739
0
                     cd->width,
2740
0
                     cd->height,
2741
0
                     cd->type);
2742
2743
0
                decoder.execute();   
2744
2745
0
                packedAcBufferEnd += 
2746
0
                    decoder.numAcValuesEncoded() * sizeof (unsigned short);
2747
2748
0
                packedDcBufferEnd += 
2749
0
                    decoder.numDcValuesEncoded() * sizeof (unsigned short);
2750
0
            }
2751
2752
0
            break;
2753
2754
0
          case RLE:
2755
2756
            //
2757
            // For the RLE case, the data has been un-RLE'd into
2758
            // planarUncRleEnd[], but is still split out by bytes.
2759
            // We need to rearrange the bytes back into the correct
2760
            // order in the output buffer;
2761
            //
2762
2763
0
            {
2764
0
                int row = 0;
2765
2766
0
                for (int y = minY; y <= maxY; ++y)
2767
0
                {
2768
0
                    if (IMATH_NAMESPACE::modp (y, cd->ySampling) != 0)
2769
0
                        continue;
2770
2771
0
                    char *dst = rowPtrs[chan][row];
2772
2773
0
                    if (pixelSize == 2)
2774
0
                    {
2775
0
                        interleaveByte2 (dst, 
2776
0
                                         cd->planarUncRleEnd[0],
2777
0
                                         cd->planarUncRleEnd[1],
2778
0
                                         cd->width);
2779
                                            
2780
0
                        cd->planarUncRleEnd[0] += cd->width;
2781
0
                        cd->planarUncRleEnd[1] += cd->width;
2782
0
                    }
2783
0
                    else
2784
0
                    {
2785
0
                        for (int x = 0; x < cd->width; ++x)
2786
0
                        {
2787
0
                            for (int byte = 0; byte < pixelSize; ++byte)
2788
0
                            {
2789
0
                               *dst++ = *cd->planarUncRleEnd[byte]++;
2790
0
                            }
2791
0
                        }
2792
0
                    }
2793
2794
0
                    row++;
2795
0
                }
2796
0
            }
2797
2798
0
            break;
2799
2800
0
          case UNKNOWN:
2801
2802
            //
2803
            // In the UNKNOWN case, data is already in planarUncBufferEnd
2804
            // and just needs to copied over to the output buffer
2805
            //
2806
2807
0
            {
2808
0
                int row             = 0;
2809
0
                int dstScanlineSize = cd->width * OPENEXR_IMF_NAMESPACE::pixelTypeSize (cd->type);
2810
2811
0
                for (int y = minY; y <= maxY; ++y)
2812
0
                {
2813
0
                    if (IMATH_NAMESPACE::modp (y, cd->ySampling) != 0)
2814
0
                        continue;
2815
2816
0
                    memcpy (rowPtrs[chan][row],
2817
0
                            cd->planarUncBufferEnd,
2818
0
                            dstScanlineSize);
2819
2820
0
                    cd->planarUncBufferEnd += dstScanlineSize;
2821
0
                    row++;
2822
0
                }
2823
0
            }
2824
2825
0
            break;
2826
2827
0
          default:
2828
2829
0
            throw IEX_NAMESPACE::NoImplExc ("Unhandled compression scheme case");
2830
0
            break;
2831
0
        }
2832
2833
0
        decodedChannels[chan] = true;
2834
0
    }
2835
2836
    //
2837
    // Return a ptr to _outBuffer
2838
    //
2839
2840
0
    outPtr = _outBuffer;
2841
0
    return (int)(outBufferEnd - _outBuffer);
2842
0
}
2843
2844
2845
// static
2846
void
2847
DwaCompressor::initializeFuncs()
2848
0
{
2849
0
    convertFloatToHalf64 = convertFloatToHalf64_scalar;
2850
0
    fromHalfZigZag       = fromHalfZigZag_scalar;
2851
2852
0
    CpuId cpuId;
2853
2854
    //
2855
    // Setup HALF <-> FLOAT conversion implementations
2856
    //
2857
2858
0
    if (cpuId.avx && cpuId.f16c)
2859
0
    {
2860
0
        convertFloatToHalf64 = convertFloatToHalf64_f16c;
2861
0
        fromHalfZigZag       = fromHalfZigZag_f16c;
2862
0
    } 
2863
2864
    //
2865
    // Setup inverse DCT implementations
2866
    //
2867
2868
0
    dctInverse8x8_0 = dctInverse8x8_scalar<0>;
2869
0
    dctInverse8x8_1 = dctInverse8x8_scalar<1>;
2870
0
    dctInverse8x8_2 = dctInverse8x8_scalar<2>;
2871
0
    dctInverse8x8_3 = dctInverse8x8_scalar<3>;
2872
0
    dctInverse8x8_4 = dctInverse8x8_scalar<4>;
2873
0
    dctInverse8x8_5 = dctInverse8x8_scalar<5>;
2874
0
    dctInverse8x8_6 = dctInverse8x8_scalar<6>;
2875
0
    dctInverse8x8_7 = dctInverse8x8_scalar<7>;
2876
2877
0
    if (cpuId.avx) 
2878
0
    {
2879
0
        dctInverse8x8_0 = dctInverse8x8_avx<0>;
2880
0
        dctInverse8x8_1 = dctInverse8x8_avx<1>;
2881
0
        dctInverse8x8_2 = dctInverse8x8_avx<2>;
2882
0
        dctInverse8x8_3 = dctInverse8x8_avx<3>;
2883
0
        dctInverse8x8_4 = dctInverse8x8_avx<4>;
2884
0
        dctInverse8x8_5 = dctInverse8x8_avx<5>;
2885
0
        dctInverse8x8_6 = dctInverse8x8_avx<6>;
2886
0
        dctInverse8x8_7 = dctInverse8x8_avx<7>;
2887
0
    } 
2888
0
    else if (cpuId.sse2) 
2889
0
    {
2890
0
        dctInverse8x8_0 = dctInverse8x8_sse2<0>;
2891
0
        dctInverse8x8_1 = dctInverse8x8_sse2<1>;
2892
0
        dctInverse8x8_2 = dctInverse8x8_sse2<2>;
2893
0
        dctInverse8x8_3 = dctInverse8x8_sse2<3>;
2894
0
        dctInverse8x8_4 = dctInverse8x8_sse2<4>;
2895
0
        dctInverse8x8_5 = dctInverse8x8_sse2<5>;
2896
0
        dctInverse8x8_6 = dctInverse8x8_sse2<6>;
2897
0
        dctInverse8x8_7 = dctInverse8x8_sse2<7>;
2898
0
    }
2899
0
}
2900
2901
2902
//
2903
// Handle channel classification and buffer allocation once we know
2904
// how to classify channels
2905
//
2906
2907
void
2908
DwaCompressor::initializeBuffers (size_t &outBufferSize)
2909
0
{
2910
0
    classifyChannels (_channels, _channelData, _cscSets);
2911
2912
    //
2913
    // _outBuffer needs to be big enough to hold all our 
2914
    // compressed data - which could vary depending on what sort
2915
    // of channels we have. 
2916
    //
2917
2918
0
    int maxOutBufferSize  = 0;
2919
0
    int numLossyDctChans  = 0;
2920
0
    int unknownBufferSize = 0;
2921
0
    int rleBufferSize     = 0;
2922
2923
0
    int maxLossyDctAcSize = (int)ceil ((float)numScanLines() / 8.0f) * 
2924
0
                            (int)ceil ((float)(_max[0] - _min[0] + 1) / 8.0f) *
2925
0
                            63 * sizeof (unsigned short);
2926
2927
0
    int maxLossyDctDcSize = (int)ceil ((float)numScanLines() / 8.0f) * 
2928
0
                            (int)ceil ((float)(_max[0] - _min[0] + 1) / 8.0f) *
2929
0
                            sizeof (unsigned short);
2930
2931
0
    for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
2932
0
    {
2933
0
        switch (_channelData[chan].compression)
2934
0
        {
2935
0
          case LOSSY_DCT:
2936
2937
            //
2938
            // This is the size of the number of packed
2939
            // components, plus the requirements for
2940
            // maximum Huffman encoding size (for STATIC_HUFFMAN)
2941
            // or for zlib compression (for DEFLATE)
2942
            //
2943
2944
0
            maxOutBufferSize += std::max(
2945
0
                            (int)(2 * maxLossyDctAcSize + 65536),
2946
0
                            (int)compressBound (maxLossyDctAcSize) );
2947
0
            numLossyDctChans++;
2948
0
            break;
2949
2950
0
          case RLE:
2951
0
            {
2952
                //
2953
                // RLE, if gone horribly wrong, could double the size
2954
                // of the source data.
2955
                //
2956
2957
0
                int rleAmount = 2 * numScanLines() * (_max[0] - _min[0] + 1) *
2958
0
                                OPENEXR_IMF_NAMESPACE::pixelTypeSize (_channelData[chan].type);
2959
2960
0
                rleBufferSize += rleAmount;
2961
0
            }
2962
0
            break;
2963
2964
2965
0
          case UNKNOWN:
2966
2967
0
            unknownBufferSize += numScanLines() * (_max[0] - _min[0] + 1) *
2968
0
                                 OPENEXR_IMF_NAMESPACE::pixelTypeSize (_channelData[chan].type);
2969
0
            break;
2970
2971
0
          default:
2972
2973
0
            throw IEX_NAMESPACE::NoImplExc ("Unhandled compression scheme case");
2974
0
            break;
2975
0
        }
2976
0
    }
2977
2978
    //
2979
    // Also, since the results of the RLE are packed into 
2980
    // the output buffer, we need the extra room there. But
2981
    // we're going to zlib compress() the data we pack, 
2982
    // which could take slightly more space
2983
    //
2984
2985
0
    maxOutBufferSize += (int)compressBound ((uLongf)rleBufferSize);
2986
    
2987
    //
2988
    // And the same goes for the UNKNOWN data
2989
    //
2990
2991
0
    maxOutBufferSize += (int)compressBound ((uLongf)unknownBufferSize);
2992
2993
    //
2994
    // Allocate a zip/deflate compressor big enought to hold the DC data
2995
    // and include it's compressed results in the size requirements
2996
    // for our output buffer
2997
    //
2998
2999
0
    if (_zip == 0) 
3000
0
        _zip = new Zip (maxLossyDctDcSize * numLossyDctChans);
3001
0
    else if (_zip->maxRawSize() < maxLossyDctDcSize * numLossyDctChans)
3002
0
    {
3003
0
        delete _zip;
3004
0
        _zip = new Zip (maxLossyDctDcSize * numLossyDctChans);
3005
0
    }
3006
3007
3008
0
    maxOutBufferSize += _zip->maxCompressedSize();
3009
3010
    //
3011
    // We also need to reserve space at the head of the buffer to 
3012
    // write out the size of our various packed and compressed data.
3013
    //
3014
3015
0
    maxOutBufferSize += NUM_SIZES_SINGLE * sizeof (Int64); 
3016
                    
3017
3018
    //
3019
    // Later, we're going to hijack outBuffer for the result of
3020
    // both encoding and decoding. So it needs to be big enough
3021
    // to hold either a buffers' worth of uncompressed or
3022
    // compressed data
3023
    //
3024
    // For encoding, we'll need _outBuffer to hold maxOutBufferSize bytes,
3025
    // but for decoding, we only need it to be maxScanLineSize*numScanLines.
3026
    // Cache the max size for now, and alloc the buffer when we either
3027
    // encode or decode.
3028
    //
3029
3030
0
    outBufferSize = maxOutBufferSize;
3031
3032
3033
    //
3034
    // _packedAcBuffer holds the quantized DCT coefficients prior
3035
    // to Huffman encoding
3036
    //
3037
3038
0
    if (maxLossyDctAcSize * numLossyDctChans > _packedAcBufferSize)
3039
0
    {
3040
0
        _packedAcBufferSize = maxLossyDctAcSize * numLossyDctChans;
3041
0
        if (_packedAcBuffer != 0) 
3042
0
            delete[] _packedAcBuffer;
3043
0
        _packedAcBuffer = new char[_packedAcBufferSize];
3044
0
    }
3045
3046
    //
3047
    // _packedDcBuffer holds one quantized DCT coef per 8x8 block
3048
    //
3049
3050
0
    if (maxLossyDctDcSize * numLossyDctChans > _packedDcBufferSize)
3051
0
    {
3052
0
        _packedDcBufferSize = maxLossyDctDcSize * numLossyDctChans;
3053
0
        if (_packedDcBuffer != 0) 
3054
0
            delete[] _packedDcBuffer;
3055
0
        _packedDcBuffer     = new char[_packedDcBufferSize];
3056
0
    }
3057
3058
0
    if (rleBufferSize > _rleBufferSize) 
3059
0
    {
3060
0
        _rleBufferSize = rleBufferSize;
3061
0
        if (_rleBuffer != 0) 
3062
0
            delete[] _rleBuffer;
3063
0
        _rleBuffer = new char[rleBufferSize];
3064
0
    }
3065
3066
    // 
3067
    // The planar uncompressed buffer will hold float data for LOSSY_DCT
3068
    // compressed values, and whatever the native type is for other
3069
    // channels. We're going to use this to hold data in a planar
3070
    // format, as opposed to the native interleaved format we take
3071
    // into compress() and give back from uncompress().
3072
    //
3073
    // This also makes it easier to compress the UNKNOWN and RLE data
3074
    // all in one swoop (for each compression scheme).
3075
    //
3076
3077
0
    int planarUncBufferSize[NUM_COMPRESSOR_SCHEMES];
3078
0
    for (int i=0; i<NUM_COMPRESSOR_SCHEMES; ++i)
3079
0
        planarUncBufferSize[i] = 0;
3080
3081
0
    for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
3082
0
    {
3083
0
        switch (_channelData[chan].compression)
3084
0
        {
3085
0
          case LOSSY_DCT:
3086
0
            break;
3087
3088
0
          case RLE:
3089
0
            planarUncBufferSize[RLE] +=
3090
0
                     numScanLines() * (_max[0] - _min[0] + 1) *
3091
0
                     OPENEXR_IMF_NAMESPACE::pixelTypeSize (_channelData[chan].type);
3092
0
            break;
3093
3094
0
          case UNKNOWN: 
3095
0
            planarUncBufferSize[UNKNOWN] +=
3096
0
                     numScanLines() * (_max[0] - _min[0] + 1) *
3097
0
                     OPENEXR_IMF_NAMESPACE::pixelTypeSize (_channelData[chan].type);
3098
0
            break;
3099
3100
0
          default:
3101
0
            throw IEX_NAMESPACE::NoImplExc ("Unhandled compression scheme case");
3102
0
            break;
3103
0
        }
3104
0
    }
3105
3106
    //
3107
    // UNKNOWN data is going to be zlib compressed, which needs 
3108
    // a little extra headroom
3109
    //
3110
3111
0
    if (planarUncBufferSize[UNKNOWN] > 0)
3112
0
    {
3113
0
        planarUncBufferSize[UNKNOWN] = 
3114
0
            compressBound ((uLongf)planarUncBufferSize[UNKNOWN]);
3115
0
    }
3116
3117
0
    for (int i = 0; i < NUM_COMPRESSOR_SCHEMES; ++i)
3118
0
    {
3119
0
        if (planarUncBufferSize[i] > _planarUncBufferSize[i]) 
3120
0
        {
3121
0
            _planarUncBufferSize[i] = planarUncBufferSize[i];
3122
0
            if (_planarUncBuffer[i] != 0) 
3123
0
                delete[] _planarUncBuffer[i];
3124
0
            _planarUncBuffer[i] = new char[planarUncBufferSize[i]];
3125
0
        }
3126
0
    }
3127
0
}
3128
3129
3130
//
3131
// Setup channel classification rules to use when writing files
3132
//
3133
3134
void
3135
DwaCompressor::initializeDefaultChannelRules ()
3136
0
{
3137
0
    _channelRules.clear();
3138
3139
0
    _channelRules.push_back (Classifier ("R",     LOSSY_DCT, HALF,   0, false));
3140
0
    _channelRules.push_back (Classifier ("R",     LOSSY_DCT, FLOAT,  0, false));
3141
0
    _channelRules.push_back (Classifier ("G",     LOSSY_DCT, HALF,   1, false));
3142
0
    _channelRules.push_back (Classifier ("G",     LOSSY_DCT, FLOAT,  1, false));
3143
0
    _channelRules.push_back (Classifier ("B",     LOSSY_DCT, HALF,   2, false));
3144
0
    _channelRules.push_back (Classifier ("B",     LOSSY_DCT, FLOAT,  2, false));
3145
3146
0
    _channelRules.push_back (Classifier ("Y",     LOSSY_DCT, HALF,  -1, false));
3147
0
    _channelRules.push_back (Classifier ("Y",     LOSSY_DCT, FLOAT, -1, false));
3148
0
    _channelRules.push_back (Classifier ("BY",    LOSSY_DCT, HALF,  -1, false));
3149
0
    _channelRules.push_back (Classifier ("BY",    LOSSY_DCT, FLOAT, -1, false));
3150
0
    _channelRules.push_back (Classifier ("RY",    LOSSY_DCT, HALF,  -1, false));
3151
0
    _channelRules.push_back (Classifier ("RY",    LOSSY_DCT, FLOAT, -1, false));
3152
3153
0
    _channelRules.push_back (Classifier ("A",     RLE,       UINT,  -1, false));
3154
0
    _channelRules.push_back (Classifier ("A",     RLE,       HALF,  -1, false));
3155
0
    _channelRules.push_back (Classifier ("A",     RLE,       FLOAT, -1, false));
3156
0
}
3157
3158
3159
//
3160
// Setup channel classification rules when reading files with VERSION < 2
3161
//
3162
3163
void
3164
DwaCompressor::initializeLegacyChannelRules ()
3165
0
{
3166
0
    _channelRules.clear();
3167
3168
0
    _channelRules.push_back (Classifier ("r",     LOSSY_DCT, HALF,   0, true));
3169
0
    _channelRules.push_back (Classifier ("r",     LOSSY_DCT, FLOAT,  0, true));
3170
0
    _channelRules.push_back (Classifier ("red",   LOSSY_DCT, HALF,   0, true));
3171
0
    _channelRules.push_back (Classifier ("red",   LOSSY_DCT, FLOAT,  0, true));
3172
0
    _channelRules.push_back (Classifier ("g",     LOSSY_DCT, HALF,   1, true));
3173
0
    _channelRules.push_back (Classifier ("g",     LOSSY_DCT, FLOAT,  1, true));
3174
0
    _channelRules.push_back (Classifier ("grn",   LOSSY_DCT, HALF,   1, true));
3175
0
    _channelRules.push_back (Classifier ("grn",   LOSSY_DCT, FLOAT,  1, true));
3176
0
    _channelRules.push_back (Classifier ("green", LOSSY_DCT, HALF,   1, true));
3177
0
    _channelRules.push_back (Classifier ("green", LOSSY_DCT, FLOAT,  1, true));
3178
0
    _channelRules.push_back (Classifier ("b",     LOSSY_DCT, HALF,   2, true));
3179
0
    _channelRules.push_back (Classifier ("b",     LOSSY_DCT, FLOAT,  2, true));
3180
0
    _channelRules.push_back (Classifier ("blu",   LOSSY_DCT, HALF,   2, true));
3181
0
    _channelRules.push_back (Classifier ("blu",   LOSSY_DCT, FLOAT,  2, true));
3182
0
    _channelRules.push_back (Classifier ("blue",  LOSSY_DCT, HALF,   2, true));
3183
0
    _channelRules.push_back (Classifier ("blue",  LOSSY_DCT, FLOAT,  2, true));
3184
3185
0
    _channelRules.push_back (Classifier ("y",     LOSSY_DCT, HALF,  -1, true));
3186
0
    _channelRules.push_back (Classifier ("y",     LOSSY_DCT, FLOAT, -1, true));
3187
0
    _channelRules.push_back (Classifier ("by",    LOSSY_DCT, HALF,  -1, true));
3188
0
    _channelRules.push_back (Classifier ("by",    LOSSY_DCT, FLOAT, -1, true));
3189
0
    _channelRules.push_back (Classifier ("ry",    LOSSY_DCT, HALF,  -1, true));
3190
0
    _channelRules.push_back (Classifier ("ry",    LOSSY_DCT, FLOAT, -1, true));
3191
0
    _channelRules.push_back (Classifier ("a",     RLE,       UINT,  -1, true));
3192
0
    _channelRules.push_back (Classifier ("a",     RLE,       HALF,  -1, true));
3193
0
    _channelRules.push_back (Classifier ("a",     RLE,       FLOAT, -1, true));
3194
0
}
3195
3196
3197
// 
3198
// Given a set of rules and ChannelData, figure out which rules apply
3199
//
3200
3201
void
3202
DwaCompressor::relevantChannelRules (std::vector<Classifier> &rules) const 
3203
0
{
3204
0
    rules.clear();
3205
3206
0
    std::vector<std::string> suffixes;
3207
    
3208
0
    for (size_t cd = 0; cd < _channelData.size(); ++cd) 
3209
0
    {
3210
0
        std::string suffix  = _channelData[cd].name;
3211
0
        size_t      lastDot = suffix.find_last_of ('.');
3212
3213
0
        if (lastDot != std::string::npos)
3214
0
            suffix = suffix.substr (lastDot+1, std::string::npos);
3215
3216
0
        suffixes.push_back(suffix);
3217
0
    }
3218
3219
    
3220
0
    for (size_t i = 0; i < _channelRules.size(); ++i) 
3221
0
    {
3222
0
        for (size_t cd = 0; cd < _channelData.size(); ++cd) 
3223
0
        {
3224
0
            if (_channelRules[i].match (suffixes[cd], _channelData[cd].type ))
3225
0
            {
3226
0
                rules.push_back (_channelRules[i]);
3227
0
                break;
3228
0
            }
3229
0
        }       
3230
0
    }
3231
0
}
3232
3233
3234
//
3235
// Take our initial list of channels, and cache the contents.
3236
//
3237
// Determine approprate compression schemes for each channel,
3238
// and figure out which sets should potentially be CSC'ed 
3239
// prior to lossy compression.
3240
//
3241
3242
void
3243
DwaCompressor::classifyChannels
3244
    (ChannelList channels,
3245
     std::vector<ChannelData> &chanData,
3246
     std::vector<CscChannelSet> &cscData)
3247
0
{
3248
    //
3249
    // prefixMap used to map channel name prefixes to 
3250
    // potential CSC-able sets of channels.
3251
    //
3252
3253
0
    std::map<std::string, DwaCompressor::CscChannelSet> prefixMap;
3254
0
    std::vector<DwaCompressor::CscChannelSet>           tmpCscSet;
3255
3256
0
    unsigned int numChan = 0;
3257
3258
0
    for (ChannelList::Iterator c = channels.begin(); c != channels.end(); ++c)
3259
0
        numChan++;
3260
    
3261
0
    if (numChan)
3262
0
        chanData.resize (numChan);
3263
3264
    //
3265
    // Cache the relevant data from the channel structs.
3266
    //
3267
3268
0
    unsigned int offset = 0;
3269
3270
0
    for (ChannelList::Iterator c = channels.begin(); c != channels.end(); ++c)
3271
0
    {
3272
0
        chanData[offset].name        = std::string (c.name());
3273
0
        chanData[offset].compression = UNKNOWN;
3274
0
        chanData[offset].xSampling   = c.channel().xSampling;
3275
0
        chanData[offset].ySampling   = c.channel().ySampling;
3276
0
        chanData[offset].type        = c.channel().type;
3277
0
        chanData[offset].pLinear     = c.channel().pLinear;
3278
3279
0
        offset++;
3280
0
    }
3281
3282
    //
3283
    // Try and figure out which channels should be
3284
    // compressed by which means.
3285
    //
3286
3287
0
    for (offset = 0; offset<numChan; ++offset)
3288
0
    {
3289
0
        std::string prefix  = "";
3290
0
        std::string suffix  = chanData[offset].name;
3291
0
        size_t      lastDot = suffix.find_last_of ('.');
3292
3293
0
        if (lastDot != std::string::npos)
3294
0
        {
3295
0
            prefix = suffix.substr (0,         lastDot);
3296
0
            suffix = suffix.substr (lastDot+1, std::string::npos);
3297
0
        } 
3298
3299
        //
3300
        // Make sure we have an entry in our CSC set map 
3301
        //
3302
3303
0
        std::map<std::string, DwaCompressor::CscChannelSet>::iterator 
3304
0
            theSet = prefixMap.find (prefix);
3305
3306
0
        if (theSet == prefixMap.end())
3307
0
        {
3308
0
            DwaCompressor::CscChannelSet tmpSet;
3309
3310
0
            tmpSet.idx[0] = 
3311
0
            tmpSet.idx[1] = 
3312
0
            tmpSet.idx[2] = -1;
3313
3314
0
            prefixMap[prefix] = tmpSet;
3315
0
        }
3316
3317
        // 
3318
        // Check the suffix against the list of classifications
3319
        // we defined previously. If the _cscIdx is not negative,
3320
        // it indicates that we should be part of a CSC group.
3321
        //
3322
3323
0
        for (std::vector<Classifier>::iterator i = _channelRules.begin();
3324
0
             i != _channelRules.end();
3325
0
             ++i)
3326
0
        {
3327
0
            if ( i->match(suffix, chanData[offset].type) )
3328
0
            {
3329
0
                chanData[offset].compression = i->_scheme;
3330
3331
0
                if ( i->_cscIdx >= 0)
3332
0
                    prefixMap[prefix].idx[i->_cscIdx] = offset;
3333
0
            }
3334
0
        }
3335
0
    }
3336
3337
    //
3338
    // Finally, try and find RGB sets of channels which 
3339
    // can be CSC'ed to a Y'CbCr space prior to loss, for
3340
    // better compression.
3341
    //
3342
    // Walk over our set of candidates, and see who has
3343
    // all three channels defined (and has common sampling
3344
    // patterns, etc).
3345
    //
3346
3347
0
    for (std::map<std::string, DwaCompressor::CscChannelSet>::iterator 
3348
0
         theItem = prefixMap.begin(); theItem != prefixMap.end();
3349
0
         ++theItem)
3350
0
    {
3351
0
        int red = (*theItem).second.idx[0];
3352
0
        int grn = (*theItem).second.idx[1];
3353
0
        int blu = (*theItem).second.idx[2];
3354
3355
0
        if ((red < 0) || (grn < 0) || (blu < 0))
3356
0
            continue;
3357
3358
0
        if ((chanData[red].xSampling != chanData[grn].xSampling) ||
3359
0
            (chanData[red].xSampling != chanData[blu].xSampling) ||
3360
0
            (chanData[grn].xSampling != chanData[blu].xSampling) ||
3361
0
            (chanData[red].ySampling != chanData[grn].ySampling) ||
3362
0
            (chanData[red].ySampling != chanData[blu].ySampling) ||
3363
0
            (chanData[grn].ySampling != chanData[blu].ySampling))
3364
0
        {
3365
0
            continue;
3366
0
        }
3367
        
3368
0
        tmpCscSet.push_back ((*theItem).second);
3369
0
    }
3370
    
3371
0
    size_t numCsc = tmpCscSet.size();
3372
3373
0
    if (numCsc)
3374
0
        cscData.resize(numCsc);
3375
3376
0
    for (offset = 0; offset < numCsc; ++offset)
3377
0
        cscData[offset] = tmpCscSet[offset];
3378
0
}
3379
3380
3381
3382
//
3383
// Setup some buffer pointers, determine channel sizes, things
3384
// like that.
3385
//
3386
3387
void
3388
DwaCompressor::setupChannelData (int minX, int minY, int maxX, int maxY)
3389
0
{
3390
0
    char *planarUncBuffer[NUM_COMPRESSOR_SCHEMES];
3391
3392
0
    for (int i=0; i<NUM_COMPRESSOR_SCHEMES; ++i)
3393
0
    {
3394
0
        planarUncBuffer[i] = 0;
3395
3396
0
        if (_planarUncBuffer[i])
3397
0
            planarUncBuffer[i] =  _planarUncBuffer[i];
3398
0
    }
3399
3400
0
    for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
3401
0
    {
3402
0
        ChannelData *cd = &_channelData[chan];
3403
3404
0
        cd->width  = OPENEXR_IMF_NAMESPACE::numSamples (cd->xSampling, minX, maxX);
3405
0
        cd->height = OPENEXR_IMF_NAMESPACE::numSamples (cd->ySampling, minY, maxY);
3406
                                
3407
0
        cd->planarUncSize =
3408
0
            cd->width * cd->height * OPENEXR_IMF_NAMESPACE::pixelTypeSize (cd->type);
3409
                                  
3410
0
        cd->planarUncBuffer    = planarUncBuffer[cd->compression];
3411
0
        cd->planarUncBufferEnd = cd->planarUncBuffer;
3412
3413
0
        cd->planarUncRle[0]    = cd->planarUncBuffer;
3414
0
        cd->planarUncRleEnd[0] = cd->planarUncRle[0];
3415
3416
0
        for (int byte = 1; byte < OPENEXR_IMF_NAMESPACE::pixelTypeSize(cd->type); ++byte)
3417
0
        {
3418
0
            cd->planarUncRle[byte] = 
3419
0
                         cd->planarUncRle[byte-1] + cd->width * cd->height;
3420
3421
0
            cd->planarUncRleEnd[byte] =
3422
0
                         cd->planarUncRle[byte];
3423
0
        }
3424
3425
0
        cd->planarUncType = cd->type;
3426
3427
0
        if (cd->compression == LOSSY_DCT)
3428
0
        {
3429
0
            cd->planarUncType = FLOAT;
3430
0
        }
3431
0
        else
3432
0
        {
3433
0
            planarUncBuffer[cd->compression] +=
3434
0
                cd->width * cd->height * OPENEXR_IMF_NAMESPACE::pixelTypeSize (cd->planarUncType);
3435
0
        }
3436
0
    }
3437
0
}
3438
3439
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT