RawSpeed
fast raw decoding library
Loading...
Searching...
No Matches
UncompressedDecompressor.cpp
Go to the documentation of this file.
1/*
2 RawSpeed - RAW file decoder.
3
4 Copyright (C) 2009-2014 Klaus Post
5 Copyright (C) 2014 Pedro CĂ´rte-Real
6 Copyright (C) 2017-2019 Roman Lebedev
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21*/
22
24#include "adt/Array2DRef.h"
25#include "adt/Casts.h"
26#include "adt/Invariant.h"
27#include "adt/Point.h"
33#include "common/Common.h"
35#include "common/RawImage.h"
37#include "io/Buffer.h"
38#include "io/ByteStream.h"
39#include "io/Endianness.h"
40#include "io/IOException.h"
41#include <algorithm>
42#include <bit>
43#include <cinttypes>
44#include <cstddef>
45#include <cstdint>
46#include <utility>
47
48using std::min;
49
50namespace rawspeed {
51
53 int bytesPerLine) const {
54 invariant(h != nullptr);
55 invariant(*h > 0);
57 invariant(input.getSize() > 0);
58
59 // How many multiples of bpl are there in the input buffer?
60 // The remainder is ignored/discarded.
61 const auto fullRows = input.getRemainSize() / bytesPerLine;
62
63 // If more than the output height, we are all good.
64 if (fullRows >= *h)
65 return; // all good!
66
67 if (fullRows == 0)
68 ThrowIOE("Not enough data to decode a single line. Image file truncated.");
69
70 ThrowIOE("Image truncated, only %u of %u lines found", fullRows, *h);
71
72 // FIXME: need to come up with some common variable to allow proceeding here
73 // *h = min_h;
74}
75
77 int bpp) const {
78 invariant(w > 0);
79 invariant(bpp > 0);
80
81 // bytes per line
82 const auto bpl = bpp * w;
83 invariant(bpl > 0);
84
85 sanityCheck(h, bpl);
86}
87
89 invariant(w > 0);
90
91 if ((12 * w) % 8 != 0)
92 ThrowIOE("Bad image width");
93
94 // Calculate expected bytes per line.
95 auto perline = (12 * w) / 8;
96
97 if (!skips)
98 return perline;
99
100 // Add skips every 10 pixels
101 perline += ((w + 2) / 10);
102
103 return perline;
104}
105
107 ByteStream input_, RawImage img_, const iRectangle2D& crop,
108 int inputPitchBytes_, int bitPerPixel_, BitOrder order_)
109 : input(input_.getStream(crop.dim.y, inputPitchBytes_)),
110 mRaw(std::move(img_)), size(crop.dim), offset(crop.pos),
111 inputPitchBytes(inputPitchBytes_), bitPerPixel(bitPerPixel_),
112 order(order_) {
113 if (!size.hasPositiveArea())
114 ThrowRDE("Empty tile.");
115
116 if (inputPitchBytes < 1)
117 ThrowRDE("Input pitch is non-positive");
118
119 switch (order) {
120 case BitOrder::LSB:
121 case BitOrder::MSB:
122 case BitOrder::MSB16:
123 case BitOrder::MSB32:
124 break;
125 case BitOrder::JPEG:
126 ThrowRDE("JPEG bit order not supported.");
127 }
128
129 uint32_t w = size.x;
130 uint32_t h = size.y;
131 uint32_t cpp = mRaw->getCpp();
132 uint64_t ox = offset.x;
133 uint64_t oy = offset.y;
134
135 if (cpp < 1 || cpp > 3)
136 ThrowRDE("Unsupported number of components per pixel: %u", cpp);
137
139 (bitPerPixel > 16 && mRaw->getDataType() == RawImageType::UINT16))
140 ThrowRDE("Unsupported bit depth");
141
142 const auto outPixelBits = static_cast<uint64_t>(w) * cpp * bitPerPixel;
143 invariant(outPixelBits > 0);
144
145 if (outPixelBits % 8 != 0) {
146 ThrowRDE("Bad combination of cpp (%u), bps (%d) and width (%u), the "
147 "pitch is %" PRIu64 " bits, which is not a multiple of 8 (1 byte)",
148 cpp, bitPerPixel, w, outPixelBits);
149 }
150
151 const auto outPixelBytes = outPixelBits / 8;
152
153 // The input pitch might be larger than needed (i.e. have some padding),
154 // but it can *not* be smaller than needed.
155 if (static_cast<unsigned>(inputPitchBytes) < outPixelBytes)
156 ThrowRDE("Specified pitch is smaller than minimally-required pitch");
157
158 // Check the specified pitch, not the minimally-required pitch.
160
161 invariant(static_cast<unsigned>(inputPitchBytes) >= outPixelBytes);
162 skipBytes =
163 implicit_cast<uint32_t>(inputPitchBytes - outPixelBytes); // Skip per line
164
165 if (oy > static_cast<uint64_t>(mRaw->dim.y))
166 ThrowRDE("Invalid y offset");
167 if (ox + size.x > static_cast<uint64_t>(mRaw->dim.x))
168 ThrowRDE("Invalid x offset");
169}
170
171template <typename Pump, typename NarrowFpType>
172void UncompressedDecompressor::decodePackedFP(int rows, int row) const {
173 const Array2DRef<float> out(mRaw->getF32DataAsUncroppedArray2DRef());
174 Pump bits(input.peekRemainingBuffer().getAsArray1DRef());
175
176 int cols = size.x * mRaw->getCpp();
177 for (; row < rows; row++) {
178 for (int col = 0; col < cols; col++) {
179 uint32_t b = bits.getBits(NarrowFpType::StorageWidth);
180 uint32_t f =
182 out(row, offset.x + col) = std::bit_cast<float>(f);
183 }
184 bits.skipBytes(skipBytes);
185 }
186}
187
188template <typename Pump>
189void UncompressedDecompressor::decodePackedInt(int rows, int row) const {
190 const Array2DRef<uint16_t> out(mRaw->getU16DataAsUncroppedArray2DRef());
191 Pump bits(input.peekRemainingBuffer().getAsArray1DRef());
192
193 int cols = size.x * mRaw->getCpp();
194 for (; row < rows; row++) {
195 for (int x = 0; x < cols; x++) {
196 out(row, x) = implicit_cast<uint16_t>(bits.getBits(bitPerPixel));
197 }
198 bits.skipBytes(skipBytes);
199 }
200}
201
203 uint32_t outPitch = mRaw->pitch;
204 uint32_t w = size.x;
205 uint32_t h = size.y;
206 uint32_t cpp = mRaw->getCpp();
207 uint64_t oy = offset.y;
208
209 uint64_t y = oy;
210 h = implicit_cast<uint32_t>(min(h + oy, static_cast<uint64_t>(mRaw->dim.y)));
211
212 if (mRaw->getDataType() == RawImageType::F32) {
213 if (bitPerPixel == 32) {
214 const Array2DRef<float> out(mRaw->getF32DataAsUncroppedArray2DRef());
216 reinterpret_cast<std::byte*>(
217 &out(implicit_cast<int>(y), offset.x * cpp)),
218 outPitch,
219 reinterpret_cast<const std::byte*>(input.getData(
221 inputPitchBytes, w * mRaw->getBpp(), implicit_cast<int>(h - y));
222 return;
223 }
224 if (BitOrder::MSB == order && bitPerPixel == 16) {
227 return;
228 }
229 if (BitOrder::LSB == order && bitPerPixel == 16) {
232 return;
233 }
234 if (BitOrder::MSB == order && bitPerPixel == 24) {
237 return;
238 }
239 if (BitOrder::LSB == order && bitPerPixel == 24) {
242 return;
243 }
244 ThrowRDE("Unsupported floating-point input bitwidth/bit packing: %d / %u",
245 bitPerPixel, static_cast<unsigned>(order));
246 }
247
248 if (BitOrder::MSB == order) {
250 } else if (BitOrder::MSB16 == order) {
252 } else if (BitOrder::MSB32 == order) {
254 } else {
256 const Array2DRef<uint16_t> out(mRaw->getU16DataAsUncroppedArray2DRef());
258 reinterpret_cast<std::byte*>(
259 &out(implicit_cast<int>(y), offset.x * cpp)),
260 outPitch,
261 reinterpret_cast<const std::byte*>(input.getData(
263 inputPitchBytes, w * mRaw->getBpp(), implicit_cast<int>(h - y));
264 return;
265 }
267 }
268}
269
270template <bool uncorrectedRawValues>
272 uint32_t w = size.x;
273 uint32_t h = size.y;
274 sanityCheck(w, &h, 1);
275
276 const Array2DRef<uint16_t> out(mRaw->getU16DataAsUncroppedArray2DRef());
277
278 const auto in = Array2DRef(input.getData(w * h), w, h);
279 uint32_t random = 0;
280 for (uint32_t row = 0; row < h; row++) {
281 for (uint32_t col = 0; col < w; col++) {
282 if constexpr (uncorrectedRawValues)
283 out(row, col) = in(row, col);
284 else {
285 mRaw->setWithLookUp(in(row, col),
286 reinterpret_cast<std::byte*>(&out(row, col)),
287 &random);
288 }
289 }
290 }
291}
292
295
296template <Endianness e>
298 uint32_t w = size.x;
299 uint32_t h = size.y;
300 static constexpr const auto bits = 12;
301
302 static_assert(e == Endianness::little || e == Endianness::big,
303 "unknown endianness");
304
305 static constexpr const auto shift = 16 - bits;
306 static constexpr const auto pack = 8 - shift;
307 static constexpr const auto mask = (1 << pack) - 1;
308
309 static_assert(bits == 12 && pack == 4, "wrong pack");
310
311 static_assert(bits == 12 && mask == 0x0f, "wrong mask");
312
313 uint32_t perline = bytesPerLine(w, /*skips=*/true);
314
315 sanityCheck(&h, perline);
316
317 const Array2DRef<uint16_t> out(mRaw->getU16DataAsUncroppedArray2DRef());
318
319 const auto in = Array2DRef(input.getData(perline * h), perline, h);
320 for (uint32_t row = 0; row < h; row++) {
321 uint32_t col = 0;
322 for (uint32_t x = 0; x < w; x += 2) {
323 uint32_t g1 = in(row, col + 0);
324 uint32_t g2 = in(row, col + 1);
325
326 auto process = [out, row](uint32_t i, bool invert, uint32_t p1,
327 uint32_t p2) {
328 uint16_t pix;
329 if (!(invert ^ (e == Endianness::little)))
330 pix = implicit_cast<uint16_t>((p1 << pack) | (p2 >> pack));
331 else
332 pix = implicit_cast<uint16_t>(((p2 & mask) << 8) | p1);
333 out(row, i) = pix;
334 };
335
336 process(x, false, g1, g2);
337
338 g1 = in(row, col + 2);
339
340 process(x + 1, true, g1, g2);
341
342 col += 3;
343
344 if ((x % 10) == 8)
345 col++;
346 }
347 }
348 input.skipBytes(input.getRemainSize());
349}
350
351template void
353template void
355
356template <Endianness e>
358 uint32_t w = size.x;
359 uint32_t h = size.y;
360 sanityCheck(w, &h, 2);
361
362 const Array2DRef<uint16_t> out(mRaw->getU16DataAsUncroppedArray2DRef());
363 const auto in = Array2DRef(input.getData(w * h * 2), 2 * w, h);
364
365 for (int row = 0; row < static_cast<int>(h); row++) {
366 for (int col = 0; col < static_cast<int>(w); ++col) {
367 uint32_t g1 = in(row, (2 * col) + 0);
368 uint32_t g2 = in(row, (2 * col) + 1);
369
370 uint16_t pix;
371 if constexpr (e == Endianness::little)
372 pix = implicit_cast<uint16_t>((g2 << 8) | g1);
373 else
374 pix = implicit_cast<uint16_t>((g1 << 8) | g2);
375 out(row, col) = pix >> 4;
376 }
377 }
378}
379
380template void
384
385} // namespace rawspeed
#define ThrowIOE(...)
Definition IOException.h:37
#define invariant(expr)
Definition Invariant.h:27
#define ThrowRDE(...)
iPoint2D dim(rawspeed::implicit_cast< int >(ceil(sqSide *sqARatio)), rawspeed::implicit_cast< int >(ceil(sqSide/sqARatio)))
Definition Common.cpp:55
dim y
Definition Common.cpp:51
dim x
Definition Common.cpp:50
void decodePackedInt(int rows, int row) const
void decodePackedFP(int rows, int row) const
void sanityCheck(const uint32_t *h, int bytesPerLine) const
static int bytesPerLine(int w, bool skips)
UncompressedDecompressor(ByteStream input, RawImage img, const iRectangle2D &crop, int inputPitchBytes, int bitPerPixel, BitOrder order)
constexpr RAWSPEED_READNONE Ttgt implicit_cast(Tsrc value)
Definition Casts.h:32
void copyPixels(std::byte *destPtr, int dstPitch, const std::byte *srcPtr, int srcPitch, int rowSize, int height)
Definition Common.h:79
Array2DRef(Array1DRef< T > data, int width, int height, int pitch) -> Array2DRef< T >
Endianness getHostEndianness()
Definition Endianness.h:51
uint32_t extendBinaryFloatingPoint(uint32_t narrow)