/src/librawspeed/src/librawspeed/decompressors/PentaxDecompressor.cpp
Line | Count | Source |
1 | | /* |
2 | | RawSpeed - RAW file decoder. |
3 | | |
4 | | Copyright (C) 2009-2014 Klaus Post |
5 | | |
6 | | This library is free software; you can redistribute it and/or |
7 | | modify it under the terms of the GNU Lesser General Public |
8 | | License as published by the Free Software Foundation; either |
9 | | version 2 of the License, or (at your option) any later version. |
10 | | |
11 | | This library is distributed in the hope that it will be useful, |
12 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | Lesser General Public License for more details. |
15 | | |
16 | | You should have received a copy of the GNU Lesser General Public |
17 | | License along with this library; if not, write to the Free Software |
18 | | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | */ |
20 | | |
21 | | #include "decompressors/PentaxDecompressor.h" |
22 | | #include "adt/Array1DRef.h" |
23 | | #include "adt/Array2DRef.h" |
24 | | #include "adt/Bit.h" |
25 | | #include "adt/Casts.h" |
26 | | #include "adt/Invariant.h" |
27 | | #include "adt/Optional.h" |
28 | | #include "adt/Point.h" |
29 | | #include "bitstreams/BitStreamerMSB.h" |
30 | | #include "codes/AbstractPrefixCode.h" |
31 | | #include "codes/HuffmanCode.h" |
32 | | #include "codes/PrefixCodeDecoder.h" |
33 | | #include "common/RawImage.h" |
34 | | #include "decoders/RawDecoderException.h" |
35 | | #include "io/Buffer.h" |
36 | | #include "io/ByteStream.h" |
37 | | #include <array> |
38 | | #include <cassert> |
39 | | #include <cstdint> |
40 | | #include <utility> |
41 | | #include <vector> |
42 | | |
43 | | namespace rawspeed { |
44 | | |
45 | | // 16 entries of codes per bit length |
46 | | // 13 entries of code values |
47 | | const std::array<std::array<std::array<uint8_t, 16>, 2>, 1> |
48 | | PentaxDecompressor::pentax_tree = {{ |
49 | | {{{0, 2, 3, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0}, |
50 | | {3, 4, 2, 5, 1, 6, 0, 7, 8, 9, 10, 11, 12}}}, |
51 | | }}; |
52 | | |
53 | | PentaxDecompressor::PentaxDecompressor(RawImage img, |
54 | | Optional<ByteStream> metaData) |
55 | 1.70k | : mRaw(std::move(img)), ht(SetupPrefixCodeDecoder(metaData)) { |
56 | 1.70k | if (mRaw->getCpp() != 1 || mRaw->getDataType() != RawImageType::UINT16 || |
57 | 1.70k | mRaw->getBpp() != sizeof(uint16_t)) |
58 | 1.70k | ThrowRDE("Unexpected component count / data type"); |
59 | | |
60 | 1.69k | if (!mRaw->dim.x || !mRaw->dim.y || mRaw->dim.x % 2 != 0 || |
61 | 1.69k | mRaw->dim.x > 8384 || mRaw->dim.y > 6208) { |
62 | 93 | ThrowRDE("Unexpected image dimensions found: (%u; %u)", mRaw->dim.x, |
63 | 93 | mRaw->dim.y); |
64 | 93 | } |
65 | 1.69k | } |
66 | | |
67 | | HuffmanCode<BaselineCodeTag> |
68 | 1.18k | PentaxDecompressor::SetupPrefixCodeDecoder_Legacy() { |
69 | | // Temporary table, used during parsing LJpeg. |
70 | 1.18k | HuffmanCode<BaselineCodeTag> hc; |
71 | | |
72 | | /* Initialize with legacy data */ |
73 | 1.18k | auto nCodes = hc.setNCodesPerLength(Buffer(pentax_tree[0][0].data(), 16)); |
74 | 1.18k | invariant(nCodes == 13); // see pentax_tree definition |
75 | 1.18k | hc.setCodeValues(Array1DRef<const uint8_t>(pentax_tree[0][1].data(), nCodes)); |
76 | | |
77 | 1.18k | return hc; |
78 | 1.18k | } |
79 | | |
80 | | HuffmanCode<BaselineCodeTag> |
81 | 526 | PentaxDecompressor::SetupPrefixCodeDecoder_Modern(ByteStream stream) { |
82 | | // Temporary table, used during parsing LJpeg. |
83 | 526 | HuffmanCode<BaselineCodeTag> hc; |
84 | | |
85 | 526 | const uint32_t depth = stream.getU16() + 12; |
86 | 526 | if (depth > 15) |
87 | 526 | ThrowRDE("Depth of huffman table is too great (%u).", depth); |
88 | | |
89 | 482 | stream.skipBytes(12); |
90 | | |
91 | 482 | std::array<uint32_t, 16> v0; |
92 | 482 | std::array<uint32_t, 16> v1; |
93 | 6.18k | for (uint32_t i = 0; i < depth; i++) |
94 | 5.70k | v0[i] = stream.getU16(); |
95 | 5.29k | for (uint32_t i = 0; i < depth; i++) { |
96 | 4.86k | v1[i] = stream.getByte(); |
97 | | |
98 | 4.86k | if (v1[i] == 0 || v1[i] > 12) |
99 | 4.86k | ThrowRDE("Data corrupt: v1[%i]=%i, expected [1..12]", depth, v1[i]); |
100 | 4.86k | } |
101 | | |
102 | 426 | std::vector<uint8_t> nCodesPerLength; |
103 | 426 | nCodesPerLength.resize(17); |
104 | | |
105 | 426 | std::array<uint32_t, 16> v2; |
106 | | /* Calculate codes and store bitcounts */ |
107 | 5.00k | for (uint32_t c = 0; c < depth; c++) { |
108 | 4.57k | v2[c] = extractHighBits(v0[c], v1[c], /*effectiveBitwidth=*/12); |
109 | 4.57k | nCodesPerLength.at(v1[c])++; |
110 | 4.57k | } |
111 | | |
112 | 426 | assert(nCodesPerLength.size() == 17); |
113 | 367 | assert(nCodesPerLength[0] == 0); |
114 | 367 | auto nCodes = hc.setNCodesPerLength(Buffer(&nCodesPerLength[1], 16)); |
115 | 367 | invariant(nCodes == depth); |
116 | | |
117 | 352 | std::vector<uint8_t> codeValues; |
118 | 352 | codeValues.reserve(nCodes); |
119 | | |
120 | | /* Find smallest */ |
121 | 4.74k | for (uint32_t i = 0; i < depth; i++) { |
122 | 4.39k | uint32_t sm_val = 0xfffffff; |
123 | 4.39k | uint32_t sm_num = 0xff; |
124 | 59.4k | for (uint32_t j = 0; j < depth; j++) { |
125 | 55.0k | if (v2[j] <= sm_val) { |
126 | 12.0k | sm_num = j; |
127 | 12.0k | sm_val = v2[j]; |
128 | 12.0k | } |
129 | 55.0k | } |
130 | 4.39k | invariant(sm_num < 16); |
131 | 4.39k | codeValues.push_back(implicit_cast<uint8_t>(sm_num)); |
132 | 4.39k | v2[sm_num] = 0xffffffff; |
133 | 4.39k | } |
134 | | |
135 | 352 | assert(codeValues.size() == nCodes); |
136 | 352 | hc.setCodeValues(Array1DRef<const uint8_t>(codeValues.data(), nCodes)); |
137 | | |
138 | 352 | return hc; |
139 | 352 | } |
140 | | |
141 | | PrefixCodeDecoder<> |
142 | 1.70k | PentaxDecompressor::SetupPrefixCodeDecoder(Optional<ByteStream> metaData) { |
143 | 1.70k | Optional<HuffmanCode<BaselineCodeTag>> hc; |
144 | | |
145 | 1.70k | if (metaData) |
146 | 526 | hc = SetupPrefixCodeDecoder_Modern(*metaData); |
147 | 1.18k | else |
148 | 1.18k | hc = SetupPrefixCodeDecoder_Legacy(); |
149 | | |
150 | 1.70k | PrefixCodeDecoder<> ht(std::move(*hc)); |
151 | 1.70k | ht.setup(true, false); |
152 | | |
153 | 1.70k | return ht; |
154 | 1.70k | } |
155 | | |
156 | 1.09k | void PentaxDecompressor::decompress(ByteStream data) const { |
157 | 1.09k | const Array2DRef<uint16_t> out(mRaw->getU16DataAsUncroppedArray2DRef()); |
158 | | |
159 | 1.09k | invariant(out.height() > 0); |
160 | 1.09k | invariant(out.width() > 0); |
161 | 1.09k | invariant(out.width() % 2 == 0); |
162 | | |
163 | 1.09k | BitStreamerMSB bs(data.peekRemainingBuffer().getAsArray1DRef()); |
164 | 124k | for (int row = 0; row < out.height(); row++) { |
165 | 123k | std::array<int, 2> pred = {{}}; |
166 | 123k | if (row >= 2) |
167 | 121k | pred = {out(row - 2, 0), out(row - 2, 1)}; |
168 | | |
169 | 27.5M | for (int col = 0; col < out.width(); col++) { |
170 | 27.4M | pred[col & 1] += ht.decodeDifference(bs); |
171 | 27.4M | int value = pred[col & 1]; |
172 | 27.4M | if (!isIntN(value, 16)) |
173 | 27.4M | ThrowRDE("decoded value out of bounds at %d:%d", col, row); |
174 | 27.4M | out(row, col) = implicit_cast<uint16_t>(value); |
175 | 27.4M | } |
176 | 123k | } |
177 | 1.09k | } |
178 | | |
179 | | } // namespace rawspeed |