RawSpeed
fast raw decoding library
Loading...
Searching...
No Matches
LJpegDecoder.cpp
Go to the documentation of this file.
1/*
2 RawSpeed - RAW file decoder.
3
4 Copyright (C) 2017 Axel Waggershauser
5 Copyright (C) 2017 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
23#include "adt/Casts.h"
24#include "adt/Invariant.h"
25#include "adt/Point.h"
26#include "common/RawImage.h"
30#include "io/Buffer.h"
31#include "io/ByteStream.h"
32#include <algorithm>
33#include <array>
34#include <cstdint>
35#include <iterator>
36#include <limits>
37#include <vector>
38
39using std::copy_n;
40
41namespace rawspeed {
42
44 : AbstractLJpegDecoder(bs, img) {
45 if (mRaw->getDataType() != RawImageType::UINT16)
46 ThrowRDE("Unexpected data type (%u)",
47 static_cast<unsigned>(mRaw->getDataType()));
48
49 if ((mRaw->getCpp() != 1 || mRaw->getBpp() != sizeof(uint16_t)) &&
50 (mRaw->getCpp() != 2 || mRaw->getBpp() != 2 * sizeof(uint16_t)) &&
51 (mRaw->getCpp() != 3 || mRaw->getBpp() != 3 * sizeof(uint16_t)))
52 ThrowRDE("Unexpected component count (%u)", mRaw->getCpp());
53
54 if (!mRaw->dim.hasPositiveArea())
55 ThrowRDE("Image has zero size");
56
57#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
58 // Yeah, sure, here it would be just dumb to leave this for production :)
59 if (mRaw->dim.x > 9728 || mRaw->dim.y > 6656) {
60 ThrowRDE("Unexpected image dimensions found: (%i; %i)", mRaw->dim.x,
61 mRaw->dim.y);
62 }
63#endif
64}
65
66void LJpegDecoder::decode(uint32_t offsetX, uint32_t offsetY, uint32_t width,
67 uint32_t height, iPoint2D maxDim_,
68 bool fixDng16Bug_) {
69 if (offsetX >= static_cast<unsigned>(mRaw->dim.x))
70 ThrowRDE("X offset outside of image");
71 if (offsetY >= static_cast<unsigned>(mRaw->dim.y))
72 ThrowRDE("Y offset outside of image");
73
74 if (width > static_cast<unsigned>(mRaw->dim.x))
75 ThrowRDE("Tile wider than image");
76 if (height > static_cast<unsigned>(mRaw->dim.y))
77 ThrowRDE("Tile taller than image");
78
79 if (offsetX + width > static_cast<unsigned>(mRaw->dim.x))
80 ThrowRDE("Tile overflows image horizontally");
81 if (offsetY + height > static_cast<unsigned>(mRaw->dim.y))
82 ThrowRDE("Tile overflows image vertically");
83
84 if (width == 0 || height == 0)
85 return; // We do not need anything from this tile.
86
87 if (!maxDim_.hasPositiveArea() ||
88 implicit_cast<unsigned>(maxDim_.x) < width ||
89 implicit_cast<unsigned>(maxDim_.y) < height)
90 ThrowRDE("Requested tile is larger than tile's maximal dimensions");
91
92 offX = offsetX;
93 offY = offsetY;
94 w = width;
95 h = height;
96
97 maxDim = maxDim_;
98
99 fixDng16Bug = fixDng16Bug_;
100
102}
103
105 invariant(frame.cps > 0);
106
107 if (predictorMode != 1)
108 ThrowRDE("Unsupported predictor mode: %u", predictorMode);
109
110 for (uint32_t i = 0; i < frame.cps; i++)
111 if (frame.compInfo[i].superH != 1 || frame.compInfo[i].superV != 1)
112 ThrowRDE("Unsupported subsampling");
113
114 int N_COMP = frame.cps;
115
116 std::vector<LJpegDecompressor::PerComponentRecipe> rec;
117 rec.reserve(N_COMP);
118 std::generate_n(std::back_inserter(rec), N_COMP,
119 [&rec, hts = getPrefixCodeDecoders(N_COMP),
120 initPred = getInitialPredictors(
122 const auto i = implicit_cast<int>(rec.size());
123 return {*hts[i], initPred[i]};
124 });
125
126 const iRectangle2D imgFrame = {
127 {static_cast<int>(offX), static_cast<int>(offY)},
128 {static_cast<int>(w), static_cast<int>(h)}};
129 const auto jpegFrameDim = iPoint2D(frame.w, frame.h);
130
132 std::numeric_limits<int>::max())
133 ThrowRDE("Maximal output tile is too large");
134
135 auto maxRes =
136 iPoint2D(implicit_cast<int>(mRaw->getCpp()) * maxDim.x, maxDim.y);
137 if (maxRes.area() != N_COMP * jpegFrameDim.area())
138 ThrowRDE("LJpeg frame area does not match maximal tile area");
139
140 if (maxRes.x % jpegFrameDim.x != 0 || maxRes.y % jpegFrameDim.y != 0)
141 ThrowRDE("Maximal output tile size is not a multiple of LJpeg frame size");
142
143 auto MCUSize = iPoint2D{maxRes.x / jpegFrameDim.x, maxRes.y / jpegFrameDim.y};
144 if (MCUSize.area() != implicit_cast<uint64_t>(N_COMP))
145 ThrowRDE("Unexpected MCU size, does not match LJpeg component count");
146
147 const LJpegDecompressor::Frame jpegFrame = {MCUSize, jpegFrameDim};
148
149 int numLJpegRowsPerRestartInterval;
150 if (numMCUsPerRestartInterval == 0) {
151 // Restart interval not enabled, so all of the rows
152 // are contained in the first (implicit) restart interval.
153 numLJpegRowsPerRestartInterval = jpegFrameDim.y;
154 } else {
155 const int numMCUsPerRow = jpegFrameDim.x;
156 if (numMCUsPerRestartInterval % numMCUsPerRow != 0)
157 ThrowRDE("Restart interval is not a multiple of frame row size");
158 numLJpegRowsPerRestartInterval = numMCUsPerRestartInterval / numMCUsPerRow;
159 }
160
161 LJpegDecompressor d(mRaw, imgFrame, jpegFrame, rec,
162 numLJpegRowsPerRestartInterval,
163 input.peekRemainingBuffer().getAsArray1DRef());
164 return d.decode();
165}
166
167} // namespace rawspeed
#define invariant(expr)
Definition Invariant.h:27
#define ThrowRDE(...)
AbstractLJpegDecoder(ByteStream bs, RawImage img)
std::vector< uint16_t > getInitialPredictors(int N_COMP) const
std::vector< const PrefixCodeDecoder<> * > getPrefixCodeDecoders(int N_COMP) const
uint32_t size_type
Definition Buffer.h:49
LJpegDecoder(ByteStream bs, const RawImage &img)
ByteStream::size_type decodeScan() override
void decode(uint32_t offsetX, uint32_t offsetY, uint32_t width, uint32_t height, iPoint2D maxDim, bool fixDng16Bug_)
ByteStream::size_type decode() const
value_type x
Definition Point.h:102
value_type y
Definition Point.h:103
bool RAWSPEED_READONLY hasPositiveArea() const
Definition Point.h:77
constexpr RAWSPEED_READNONE Ttgt implicit_cast(Tsrc value)
Definition Casts.h:32