Coverage Report

Created: 2026-10-27 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openexr/src/lib/OpenEXR/ImfDwaCompressor.cpp
Line
Count
Source
1
//
2
// SPDX-License-Identifier: BSD-3-Clause
3
// Copyright (c) DreamWorks Animation LLC and Contributors of the OpenEXR Project
4
//
5
6
//---------------------------------------------------
7
//
8
// class DwaCompressor -- Store lossy RGB data by quantizing
9
//                          DCT components.
10
//
11
// First, we try and figure out what compression strategy to take
12
// based in channel name. For RGB channels, we want a lossy method
13
// described below. But, if we have alpha, we should do something
14
// different (and probably using RLE). If we have depth, or velocity,
15
// or something else, just fall back to ZIP. The rules for deciding
16
// which strategy to use are setup in initializeDefaultChannelRules().
17
// When writing a file, the relevant rules needed to decode are written
18
// into the start of the data block, making a self-contained file.
19
// If initializeDefaultChannelRules() doesn't quite suite your naming
20
// conventions, you can adjust the rules without breaking decoder
21
// compatibility.
22
//
23
// If we're going to lossy compress R, G, or B channels, it's easier
24
// to toss bits in a more perceptual uniform space. One could argue
25
// at length as to what constitutes perceptually uniform, especially
26
// when storing either scene/input/focal plane referred and output referred
27
// data.
28
//
29
// We'll compromise. For values <= 1, we use a traditional power function
30
// (without any of that straight-line business at the bottom). For values > 1,
31
// we want something more like a log function, since power functions blow
32
// up. At 1, we want a smooth blend between the functions. So, we use a
33
// piecewise function that does just that - see dwaLookups.cpp for
34
// a little more detail.
35
//
36
// Also, if we find that we have R, G, and B channels from the same layer,
37
// we can get a bit more compression efficiency by transforming to a Y'CbCr
38
// space. We use the 709 transform, but with Cb,Cr = 0 for an input of
39
// (0, 0, 0), instead of the traditional Cb,Cr = .5. Shifting the zero point
40
// makes no sense with large range data. Transforms are done to from
41
// the perceptual space data, not the linear-light space data (R'G'B' ->
42
// (Y'CbCr, not RGB -> YCbCr).
43
//
44
// Next, we forward DCT the data. This is done with a floating
45
// point DCT, as we don't really have control over the src range. The
46
// resulting values are dropped to half-float precision.
47
//
48
// Now, we need to quantize. Quantization departs from the usual way
49
// of dividing and rounding. Instead, we start with some floating
50
// point "base-error" value. From this, we can derive quantization
51
// error for each DCT component. Take the standard JPEG quantization
52
// tables and normalize them by the smallest value. Then, multiply
53
// the normalized quant tables by our base-error value. This gives
54
// a range of errors for each DCT component.
55
//
56
// For each DCT component, we want to find a quantized value that
57
// is within +- the per-component error. Pick the quantized value
58
// that has the fewest bits set in its' binary representation.
59
// Brute-forcing the search would make for extremely inefficient
60
// compression. Fortunately, we can precompute a table to assist
61
// with this search.
62
//
63
// For each 16-bit float value, there are at most 15 other values with
64
// fewer bits set. We can precompute these values in a compact form, since
65
// many source values have far fewer that 15 possible quantized values.
66
// Now, instead of searching the entire range +- the component error,
67
// we can just search at most 15 quantization candidates. The search can
68
// be accelerated a bit more by sorting the candidates by the
69
// number of bits set, in increasing order. Then, the search can stop
70
// once a candidate is found w/i the per-component quantization
71
// error range.
72
//
73
// The quantization strategy has the side-benefit that there is no
74
// de-quantization step upon decode, so we don't bother recording
75
// the quantization table.
76
//
77
// Ok. So we now have quantized values. Time for entropy coding. We
78
// can use either static Huffman or zlib/DEFLATE. The static Huffman
79
// is more efficient at compacting data, but can have a greater
80
// overhead, especially for smaller tile/strip sizes.
81
//
82
// There is some additional fun, like ZIP compressing the DC components
83
// instead of Huffman/zlib, which helps make things slightly smaller.
84
//
85
// Compression level is controlled by setting an int/float/double attribute
86
// on the header named "dwaCompressionLevel". This is a thinly veiled name for
87
// the "base-error" value mentioned above. The "base-error" is just
88
// dwaCompressionLevel / 100000. The default value of 45.0 is generally
89
// pretty good at generating "visually lossless" values at reasonable
90
// data rates. Setting dwaCompressionLevel to 0 should result in no additional
91
// quantization at the quantization stage (though there may be
92
// quantization in practice at the CSC/DCT steps). But if you really
93
// want lossless compression, there are pleanty of other choices
94
// of compressors ;)
95
//
96
// When dealing with FLOAT source buffers, we first quantize the source
97
// to HALF and continue down as we would for HALF source.
98
//
99
//---------------------------------------------------
100
101
#include "ImfDwaCompressor.h"
102
103
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
104
105
// ==============================================================
106
//
107
//                     DwaCompressor
108
//
109
// --------------------------------------------------------------
110
111
//
112
// DwaCompressor()
113
//
114
115
DwaCompressor::DwaCompressor (
116
    const Header& hdr,
117
    size_t        maxScanLineSize,
118
    int           numScanLines,
119
    AcCompression acCompression)
120
0
    : Compressor (hdr,
121
0
                  EXR_COMPRESSION_LAST_TYPE, /* use the header */
122
0
                  maxScanLineSize,
123
0
                  numScanLines)
124
0
{
125
0
}
126
127
DwaCompressor::~DwaCompressor ()
128
0
{
129
0
}
130
131
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT