RawSpeed
fast raw decoding library
Loading...
Searching...
No Matches
HuffmanCode.h
Go to the documentation of this file.
1/*
2 RawSpeed - RAW file decoder.
3
4 Copyright (C) 2017 Axel Waggershauser
5 Copyright (C) 2017-2018 Roman Lebedev
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20*/
21
22#pragma once
23
24#include "rawspeedconfig.h"
25#include "adt/Array1DRef.h"
26#include "adt/Invariant.h"
28#include "codes/PrefixCode.h"
30#include "io/Buffer.h"
31#include <algorithm>
32#include <cassert>
33#include <cstddef>
34#include <cstdint>
35#include <iterator>
36#include <numeric>
37#include <vector>
38
39namespace rawspeed {
40
41template <typename CodeTag>
42class HuffmanCode final : public AbstractPrefixCode<CodeTag> {
43public:
47
48 HuffmanCode() = default;
49
50protected:
51 [[nodiscard]] size_t RAWSPEED_READONLY maxCodeLength() const {
52 return nCodesPerLength.size() - 1;
53 }
54
55 // These two fields directly represent the contents of a JPEG DHT field
56
57 // 1. The number of codes there are per bit length, this is index 1 based.
58 // (there are always 0 codes of length 0)
59 std::vector<unsigned int> nCodesPerLength; // index is length of code
60
61 [[nodiscard]] unsigned int RAWSPEED_READONLY maxCodesCount() const {
62 return std::accumulate(nCodesPerLength.begin(), nCodesPerLength.end(), 0U);
63 }
64
65public:
66 [[nodiscard]] std::vector<CodeSymbol> generateCodeSymbols() const {
67 std::vector<CodeSymbol> symbols;
68
69 assert(!nCodesPerLength.empty());
70 assert(maxCodesCount() > 0);
71
72 assert(this->codeValues.size() == maxCodesCount());
73
74 // reserve all the memory. avoids lots of small allocs
75 symbols.reserve(maxCodesCount());
76
77 // Figure C.1: make table of Huffman code length for each symbol
78 // Figure C.2: generate the codes themselves
79 uint32_t code = 0;
80 for (unsigned int l = 1; l <= maxCodeLength(); ++l) {
81 for (unsigned int i = 0; i < nCodesPerLength[l]; ++i) {
82 symbols.emplace_back(code, l);
83 code++;
84 }
85
86 code <<= 1;
87 }
88
89 assert(symbols.size() == maxCodesCount());
90
91 return symbols;
92 }
93
94 bool operator==(const HuffmanCode& other) const {
95 return nCodesPerLength == other.nCodesPerLength &&
96 this->codeValues == other.codeValues;
97 }
98
100 invariant(data.getSize() == Traits::MaxCodeLenghtBits);
101
102 nCodesPerLength.resize((1 + Traits::MaxCodeLenghtBits), 0);
103 std::copy(data.begin(), data.end(), &nCodesPerLength[1]);
104 assert(nCodesPerLength[0] == 0);
105
106 // trim empty entries from the codes per length table on the right
107 while (!nCodesPerLength.empty() && nCodesPerLength.back() == 0)
108 nCodesPerLength.pop_back();
109
110 if (nCodesPerLength.empty())
111 ThrowRDE("Codes-per-length table is empty");
112
113 assert(nCodesPerLength.back() > 0);
114
115 const auto count = maxCodesCount();
116 invariant(count > 0);
117
118 if (count > Traits::MaxNumCodeValues)
119 ThrowRDE("Too big code-values table");
120
121 // We are at the Root node, len is 1, there are two possible child Nodes
122 unsigned maxCodes = 2;
123
124 for (auto codeLen = 1UL; codeLen < nCodesPerLength.size(); codeLen++) {
125 // we have codeLen bits. make sure that that code count can actually fit
126 // E.g. for len 1 we could have two codes: 0b0 and 0b1
127 // (but in that case there can be no other codes (with higher lengths))
128 const auto maxCodesInCurrLen = (1U << codeLen);
129 const auto nCodes = nCodesPerLength[codeLen];
130 if (nCodes > maxCodesInCurrLen) {
131 ThrowRDE("Corrupt Huffman. Can never have %u codes in %lu-bit len",
132 nCodes, codeLen);
133 }
134
135 // Also, check that we actually can have this much leafs for this length
136 if (nCodes > maxCodes) {
137 ThrowRDE(
138 "Corrupt Huffman. Can only fit %u out of %u codes in %lu-bit len",
139 maxCodes, nCodes, codeLen);
140 }
141
142 // There are nCodes leafs on this level, and those can not be branches
143 maxCodes -= nCodes;
144 // On the next level, rest can be branches, and can have two child Nodes
145 maxCodes *= 2;
146 }
147
148 return count;
149 }
150
152 invariant(data.size() <= Traits::MaxNumCodeValues);
153 invariant(static_cast<unsigned>(data.size()) == maxCodesCount());
154
155 this->codeValues.clear();
156 this->codeValues.reserve(maxCodesCount());
157 std::copy(data.begin(), data.end(), std::back_inserter(this->codeValues));
158 assert(this->codeValues.size() == maxCodesCount());
159
160 for (const auto& cValue : this->codeValues) {
161 if (cValue <= Traits::MaxCodeValue)
162 continue;
163 ThrowRDE("Corrupt Huffman code: code value %u is larger than maximum %u",
164 cValue, Traits::MaxCodeValue);
165 }
166 }
167
168 explicit operator PrefixCode<CodeTag>() {
169 std::vector<CodeSymbol> symbols = generateCodeSymbols();
170 return {std::move(symbols), std::move(Parent::codeValues)};
171 }
172};
173
174} // namespace rawspeed
#define invariant(expr)
Definition Invariant.h:27
#define ThrowRDE(...)
assert(dim.area() >=area)
HuffmanCode()=default
std::vector< CodeValueTy > codeValues
int RAWSPEED_READONLY size() const
const uint8_t * begin() const
Definition Buffer.h:99
const uint8_t * end() const
Definition Buffer.h:102
size_type RAWSPEED_READONLY getSize() const
Definition Buffer.h:115
typename AbstractPrefixCode< CodeTag >::Traits Traits
Definition HuffmanCode.h:46
size_t RAWSPEED_READONLY maxCodeLength() const
Definition HuffmanCode.h:51
uint32_t setNCodesPerLength(Buffer data)
Definition HuffmanCode.h:99
std::vector< unsigned int > nCodesPerLength
Definition HuffmanCode.h:59
AbstractPrefixCode< CodeTag > Parent
Definition HuffmanCode.h:44
bool operator==(const HuffmanCode &other) const
Definition HuffmanCode.h:94
std::vector< CodeSymbol > generateCodeSymbols() const
Definition HuffmanCode.h:66
typename AbstractPrefixCode< CodeTag >::CodeSymbol CodeSymbol
Definition HuffmanCode.h:45
void setCodeValues(Array1DRef< const typename Traits::CodeValueTy > data)
unsigned int RAWSPEED_READONLY maxCodesCount() const
Definition HuffmanCode.h:61