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