1 /*
2 RawSpeed - RAW file decoder.
3
4 Copyright (C) 2009-2014 Klaus Post
5 Copyright (C) 2017 Axel Waggershauser
6 Copyright (C) 2017-2018 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
23 #include "decompressors/Cr2Decompressor.h"
24 #include "common/Array2DRef.h" // for Array2DRef
25 #include "common/Point.h" // for iPoint2D, iPoint2D::area_type
26 #include "common/RawImage.h" // for RawImage, RawImageData
27 #include "decoders/RawDecoderException.h" // for ThrowRDE
28 #include "io/BitPumpJPEG.h" // for BitPumpJPEG, BitStream<>::...
29 #include <algorithm> // for copy_n, min
30 #include <array> // for array
31 #include <cassert> // for assert
32 #include <initializer_list> // for initializer_list
33
34 namespace rawspeed {
35
36 class ByteStream;
37
Cr2Decompressor(const ByteStream & bs,const RawImage & img)38 Cr2Decompressor::Cr2Decompressor(const ByteStream& bs, const RawImage& img)
39 : AbstractLJpegDecompressor(bs, img) {
40 if (mRaw->getDataType() != TYPE_USHORT16)
41 ThrowRDE("Unexpected data type");
42
43 if (!((mRaw->getCpp() == 1 && mRaw->getBpp() == sizeof(uint16_t))))
44 ThrowRDE("Unexpected cpp: %u", mRaw->getCpp());
45
46 if (!mRaw->dim.x || !mRaw->dim.y || mRaw->dim.x > 19440 ||
47 mRaw->dim.y > 5920) {
48 ThrowRDE("Unexpected image dimensions found: (%u; %u)", mRaw->dim.x,
49 mRaw->dim.y);
50 }
51 }
52
decodeScan()53 void Cr2Decompressor::decodeScan()
54 {
55 if (predictorMode != 1)
56 ThrowRDE("Unsupported predictor mode.");
57
58 if (slicing.empty()) {
59 const int slicesWidth = frame.w * frame.cps;
60 if (slicesWidth > mRaw->dim.x)
61 ThrowRDE("Don't know slicing pattern, and failed to guess it.");
62
63 slicing = Cr2Slicing(/*numSlices=*/1, /*sliceWidth=don't care*/ 0,
64 /*lastSliceWidth=*/slicesWidth);
65 }
66
67 bool isSubSampled = false;
68 for (uint32_t i = 0; i < frame.cps; i++)
69 isSubSampled = isSubSampled || frame.compInfo[i].superH != 1 ||
70 frame.compInfo[i].superV != 1;
71
72 if (isSubSampled) {
73 if (mRaw->isCFA)
74 ThrowRDE("Cannot decode subsampled image to CFA data");
75
76 if (frame.cps != 3)
77 ThrowRDE("Unsupported number of subsampled components: %u", frame.cps);
78
79 // see http://lclevy.free.fr/cr2/#sraw for overview table
80 bool isSupported = frame.compInfo[0].superH == 2;
81
82 isSupported = isSupported && (frame.compInfo[0].superV == 1 ||
83 frame.compInfo[0].superV == 2);
84
85 for (uint32_t i = 1; i < frame.cps; i++)
86 isSupported = isSupported && frame.compInfo[i].superH == 1 &&
87 frame.compInfo[i].superV == 1;
88
89 if (!isSupported) {
90 ThrowRDE("Unsupported subsampling ([[%u, %u], [%u, %u], [%u, %u]])",
91 frame.compInfo[0].superH, frame.compInfo[0].superV,
92 frame.compInfo[1].superH, frame.compInfo[1].superV,
93 frame.compInfo[2].superH, frame.compInfo[2].superV);
94 }
95
96 if (frame.compInfo[0].superV == 2)
97 decodeN_X_Y<3, 2, 2>(); // Cr2 sRaw1/mRaw
98 else {
99 assert(frame.compInfo[0].superV == 1);
100 decodeN_X_Y<3, 2, 1>(); // Cr2 sRaw2/sRaw
101 }
102 } else {
103 switch (frame.cps) {
104 case 2:
105 decodeN_X_Y<2, 1, 1>();
106 break;
107 case 4:
108 decodeN_X_Y<4, 1, 1>();
109 break;
110 default:
111 ThrowRDE("Unsupported number of components: %u", frame.cps);
112 }
113 }
114 }
115
decode(const Cr2Slicing & slicing_)116 void Cr2Decompressor::decode(const Cr2Slicing& slicing_) {
117 slicing = slicing_;
118 for (auto sliceId = 0; sliceId < slicing.numSlices; sliceId++) {
119 const auto sliceWidth = slicing.widthOfSlice(sliceId);
120 if (sliceWidth <= 0)
121 ThrowRDE("Bad slice width: %i", sliceWidth);
122 }
123
124 AbstractLJpegDecompressor::decode();
125 }
126
127 // N_COMP == number of components (2, 3 or 4)
128 // X_S_F == x/horizontal sampling factor (1 or 2)
129 // Y_S_F == y/vertical sampling factor (1 or 2)
130
131 template <int N_COMP, int X_S_F, int Y_S_F>
decodeN_X_Y()132 void Cr2Decompressor::decodeN_X_Y()
133 {
134 const Array2DRef<uint16_t> out(mRaw->getU16DataAsUncroppedArray2DRef());
135
136 // To understand the CR2 slice handling and sampling factor behavior, see
137 // https://github.com/lclevy/libcraw2/blob/master/docs/cr2_lossless.pdf?raw=true
138
139 constexpr bool subSampled = X_S_F != 1 || Y_S_F != 1;
140
141 // inner loop decodes one group of pixels at a time
142 // * for <N,1,1>: N = N*1*1 (full raw)
143 // * for <3,2,1>: 6 = 3*2*1
144 // * for <3,2,2>: 12 = 3*2*2
145 // and advances x by N_COMP*X_S_F and y by Y_S_F
146 constexpr int sliceColStep = N_COMP * X_S_F;
147 constexpr int frameRowStep = Y_S_F;
148 constexpr int pixelsPerGroup = X_S_F * Y_S_F;
149 constexpr int groupSize = !subSampled ? N_COMP : 2 + pixelsPerGroup;
150 const int cpp = !subSampled ? 1 : 3;
151 const int colsPerGroup = !subSampled ? cpp : groupSize;
152
153 iPoint2D realDim = mRaw->dim;
154 if (subSampled) {
155 assert(realDim.x % groupSize == 0);
156 realDim.x /= groupSize;
157 }
158 realDim.x *= X_S_F;
159 realDim.y *= Y_S_F;
160
161 auto ht = getHuffmanTables<N_COMP>();
162 auto pred = getInitialPredictors<N_COMP>();
163 auto* predNext = &out(0, 0);
164
165 BitPumpJPEG bs(input);
166
167 if (frame.cps != 3 && frame.w * frame.cps > 2 * frame.h) {
168 // Fix Canon double height issue where Canon doubled the width and halfed
169 // the height (e.g. with 5Ds), ask Canon. frame.w needs to stay as is here
170 // because the number of pixels after which the predictor gets updated is
171 // still the doubled width.
172 // see: FIX_CANON_HALF_HEIGHT_DOUBLE_WIDTH
173 frame.h *= 2;
174 }
175
176 if (X_S_F == 2 && Y_S_F == 1)
177 {
178 // fix the inconsistent slice width in sRaw mode, ask Canon.
179 for (auto* width : {&slicing.sliceWidth, &slicing.lastSliceWidth})
180 *width = (*width) * 3 / 2;
181 }
182
183 for (const auto& width : {slicing.sliceWidth, slicing.lastSliceWidth}) {
184 if (width > realDim.x)
185 ThrowRDE("Slice is longer than image's height, which is unsupported.");
186 if (width % sliceColStep != 0) {
187 ThrowRDE("Slice width (%u) should be multiple of pixel group size (%u)",
188 width, sliceColStep);
189 }
190 if (width % cpp != 0) {
191 ThrowRDE("Slice width (%u) should be multiple of image cpp (%u)", width,
192 cpp);
193 }
194 }
195
196 if (iPoint2D::area_type(frame.h) * slicing.totalWidth() <
197 cpp * realDim.area())
198 ThrowRDE("Incorrrect slice height / slice widths! Less than image size.");
199
200 unsigned globalFrameCol = 0;
201 unsigned globalFrameRow = 0;
202 for (auto sliceId = 0; sliceId < slicing.numSlices; sliceId++) {
203 const unsigned sliceWidth = slicing.widthOfSlice(sliceId);
204
205 assert(frame.h % frameRowStep == 0);
206 for (unsigned sliceFrameRow = 0; sliceFrameRow < frame.h;
207 sliceFrameRow += frameRowStep, globalFrameRow += frameRowStep) {
208 unsigned row = globalFrameRow % realDim.y;
209 unsigned col = globalFrameRow / realDim.y * slicing.widthOfSlice(0) / cpp;
210 if (col >= static_cast<unsigned>(realDim.x))
211 break;
212
213 assert(sliceWidth % cpp == 0);
214 unsigned pixelsPerSliceRow = sliceWidth / cpp;
215 if (col + pixelsPerSliceRow > static_cast<unsigned>(realDim.x))
216 ThrowRDE("Bad slice width / frame size / image size combination.");
217 if (((sliceId + 1) == slicing.numSlices) &&
218 (col + pixelsPerSliceRow != static_cast<unsigned>(realDim.x)))
219 ThrowRDE("Insufficient slices - do not fill the entire image");
220
221 row /= Y_S_F;
222
223 assert(col % X_S_F == 0);
224 col /= X_S_F;
225 col *= colsPerGroup;
226 assert(sliceWidth % sliceColStep == 0);
227 for (unsigned sliceCol = 0; sliceCol < sliceWidth;) {
228 // check if we processed one full raw row worth of pixels
229 if (globalFrameCol == frame.w) {
230 // if yes -> update predictor by going back exactly one row,
231 // no matter where we are right now.
232 // makes no sense from an image compression point of view, ask Canon.
233 for (int c = 0; c < N_COMP; ++c)
234 pred[c] = predNext[c == 0 ? c : groupSize - (N_COMP - c)];
235 predNext = &out(row, col);
236 globalFrameCol = 0;
237 }
238
239 // How many pixel can we decode until we finish the row of either
240 // the frame (i.e. predictor change time), or of the current slice?
241 assert(frame.w % X_S_F == 0);
242 unsigned sliceColsRemainingInThisFrameRow =
243 sliceColStep * ((frame.w - globalFrameCol) / X_S_F);
244 unsigned sliceColsRemainingInThisSliceRow = sliceWidth - sliceCol;
245 unsigned sliceColsRemaining = std::min(
246 sliceColsRemainingInThisSliceRow, sliceColsRemainingInThisFrameRow);
247 assert(sliceColsRemaining >= sliceColStep &&
248 (sliceColsRemaining % sliceColStep) == 0);
249 for (unsigned sliceColEnd = sliceCol + sliceColsRemaining;
250 sliceCol < sliceColEnd; sliceCol += sliceColStep,
251 globalFrameCol += X_S_F, col += groupSize) {
252 for (int p = 0; p < groupSize; ++p) {
253 int c = p < pixelsPerGroup ? 0 : p - pixelsPerGroup + 1;
254 out(row, col + p) = pred[c] += ht[c]->decodeDifference(bs);
255 }
256 }
257 }
258 }
259 }
260 }
261
262 } // namespace rawspeed
263