RawSpeed
fast raw decoding library
Loading...
Searching...
No Matches
RawDecoder.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
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
22#include "decoders/RawDecoder.h"
23#include "MemorySanitizer.h"
24#include "adt/Array1DRef.h"
25#include "adt/Array2DRef.h"
26#include "adt/Casts.h"
27#include "adt/Point.h"
29#include "common/Common.h"
30#include "common/RawImage.h"
32#include "io/Buffer.h"
33#include "io/ByteStream.h"
34#include "io/Endianness.h"
35#include "io/FileIOException.h"
36#include "io/IOException.h"
37#include "metadata/Camera.h"
42#include "tiff/TiffEntry.h"
43#include "tiff/TiffIFD.h"
44#include "tiff/TiffTag.h"
45#include <cassert>
46#include <cstdint>
47#include <string>
48#include <vector>
49
50using std::vector;
51
52namespace rawspeed {
53
55
57 BitOrder order) const {
58 const TiffEntry* offsets = rawIFD->getEntry(TiffTag::STRIPOFFSETS);
59 const TiffEntry* counts = rawIFD->getEntry(TiffTag::STRIPBYTECOUNTS);
60 uint32_t yPerSlice = rawIFD->getEntry(TiffTag::ROWSPERSTRIP)->getU32();
61 uint32_t width = rawIFD->getEntry(TiffTag::IMAGEWIDTH)->getU32();
62 uint32_t height = rawIFD->getEntry(TiffTag::IMAGELENGTH)->getU32();
63 uint32_t bitPerPixel = rawIFD->getEntry(TiffTag::BITSPERSAMPLE)->getU32();
64
65 if (width == 0 || height == 0 || width > 5632 || height > 3720)
66 ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
67
68 mRaw->dim = iPoint2D(width, height);
69
70 if (counts->count != offsets->count) {
71 ThrowRDE("Byte count number does not match strip size: "
72 "count:%u, stips:%u ",
73 counts->count, offsets->count);
74 }
75
76 if (yPerSlice == 0 || yPerSlice > static_cast<uint32_t>(mRaw->dim.y) ||
77 roundUpDivisionSafe(mRaw->dim.y, yPerSlice) != counts->count) {
78 ThrowRDE("Invalid y per slice %u or strip count %u (height = %d)",
79 yPerSlice, counts->count, mRaw->dim.y);
80 }
81
82 switch (bitPerPixel) {
83 case 12:
84 case 14:
85 break;
86 default:
87 ThrowRDE("Unexpected bits per pixel: %u.", bitPerPixel);
88 }
89
90 vector<RawSlice> slices;
91 slices.reserve(counts->count);
92 uint32_t offY = 0;
93
94 for (uint32_t s = 0; s < counts->count; s++) {
95 RawSlice slice;
96 slice.offset = offsets->getU32(s);
97 slice.count = counts->getU32(s);
98
99 if (slice.count < 1)
100 ThrowRDE("Slice %u is empty", s);
101
102 if (offY + yPerSlice > height)
103 slice.h = height - offY;
104 else
105 slice.h = yPerSlice;
106
107 offY += yPerSlice;
108
109 if (!mFile.isValid(slice.offset, slice.count))
110 ThrowRDE("Slice offset/count invalid");
111
112 slices.push_back(slice);
113 }
114
115 if (slices.empty())
116 ThrowRDE("No valid slices found. File probably truncated.");
117
118 assert(height <= offY);
119 assert(slices.size() == counts->count);
120
121 mRaw->createData();
122
123 // Default white level is (2 ** BitsPerSample) - 1
124 mRaw->whitePoint = implicit_cast<int>((1UL << bitPerPixel) - 1UL);
125
126 offY = 0;
127 for (const RawSlice& slice : slices) {
128 iPoint2D size(width, slice.h);
129 iPoint2D pos(0, offY);
130 bitPerPixel = implicit_cast<uint32_t>(
131 (static_cast<uint64_t>(slice.count) * 8U) / (slice.h * width));
132 const auto inputPitch = width * bitPerPixel / 8;
133 if (!inputPitch)
134 ThrowRDE("Bad input pitch. Can not decode anything.");
135
137 ByteStream(DataBuffer(mFile.getSubView(slice.offset, slice.count),
139 mRaw, iRectangle2D(pos, size), inputPitch, bitPerPixel, order);
140 u.readUncompressedRaw();
142 offY += slice.h;
143 }
144}
145
147 const std::string& make,
148 const std::string& model,
149 const std::string& mode) {
151 const Camera* cam = meta->getCamera(make, model, mode);
152 if (cam)
153 supportStatus = cam->supportStatus;
154
155 // Sample beggary block.
156 switch (supportStatus) {
157 using enum Camera::SupportStatus;
158 case UnknownCamera:
159 if ("dng" != mode) {
160 noSamples = true;
162 "Unable to find camera in database: '%s' '%s' '%s'\nPlease "
163 "consider providing samples on <https://raw.pixls.us/>, thanks!",
164 make.c_str(), model.c_str(), mode.c_str());
165 }
166 break;
167 case UnknownNoSamples:
168 case SupportedNoSamples:
169 noSamples = true;
171 "Camera support status is unknown: '%s' '%s' '%s'\n"
172 "Please consider providing samples on <https://raw.pixls.us/> "
173 "if you wish for the support to not be discontinued, thanks!",
174 make.c_str(), model.c_str(), mode.c_str());
175 break; // WYSIWYG.
176 case Supported:
177 case Unknown:
178 case Unsupported:
179 break; // All these imply existence of a sample on RPU.
180 }
181
182 // Actual support handling.
183 switch (supportStatus) {
184 using enum Camera::SupportStatus;
185 case Supported:
186 case SupportedNoSamples:
187 return true; // Explicitly supported.
188 case Unsupported:
189 ThrowRDE("Camera not supported (explicit). Sorry.");
190 case UnknownCamera:
191 case UnknownNoSamples:
192 case Unknown:
193 if (failOnUnknown) {
194 ThrowRDE("Camera '%s' '%s', mode '%s' not supported, and not allowed to "
195 "guess. Sorry.",
196 make.c_str(), model.c_str(), mode.c_str());
197 }
198 return cam; // Might be implicitly supported.
199 }
200
201 return true;
202}
203
205 const std::string& make,
206 const std::string& model,
207 const std::string& mode) {
208 mRaw->metadata.make = make;
209 mRaw->metadata.model = model;
210
211 if (!handleCameraSupport(meta, make, model, mode))
212 return false;
213
214 const Camera* cam = meta->getCamera(make, model, mode);
215 assert(cam);
216
218 ThrowRDE(
219 "Camera not supported in this version. Update RawSpeed for support.");
220
221 hints = cam->hints;
222 return true;
223}
224
226 const std::string& make, const std::string& model,
227 const std::string& mode, int iso_speed) {
228 mRaw->metadata.isoSpeed = iso_speed;
229
230 if (!handleCameraSupport(meta, make, model, mode))
231 return;
232
233 const Camera* cam = meta->getCamera(make, model, mode);
234 assert(cam);
235
236 // Only final CFA with the data from cameras.xml if it actually contained
237 // the CFA.
238 if (cam->cfa.getSize().area() > 0)
239 mRaw->cfa = cam->cfa;
240
241 if (!cam->color_matrix.empty())
242 mRaw->metadata.colorMatrix = cam->color_matrix;
243
244 mRaw->metadata.canonical_make = cam->canonical_make;
245 mRaw->metadata.canonical_model = cam->canonical_model;
246 mRaw->metadata.canonical_alias = cam->canonical_alias;
247 mRaw->metadata.canonical_id = cam->canonical_id;
248 mRaw->metadata.make = make;
249 mRaw->metadata.model = model;
250 mRaw->metadata.mode = mode;
251
252 if (applyCrop) {
253 if (cam->cropAvailable) {
254 iPoint2D new_size = cam->cropSize;
255
256 // If crop size is negative, use relative cropping
257 if (new_size.x <= 0)
258 new_size.x = mRaw->dim.x - cam->cropPos.x + new_size.x;
259
260 if (new_size.y <= 0)
261 new_size.y = mRaw->dim.y - cam->cropPos.y + new_size.y;
262
263 mRaw->subFrame(iRectangle2D(cam->cropPos, new_size));
264 } else {
265 mRaw->subFrame(getDefaultCrop());
266 }
267 }
268
269 mRaw->blackAreas = cam->blackAreas;
270 if (const CameraSensorInfo* sensor = cam->getSensorInfo(iso_speed)) {
271 mRaw->blackLevel = sensor->mBlackLevel;
272 mRaw->whitePoint = sensor->mWhiteLevel;
273 if (mRaw->blackAreas.empty() && !sensor->mBlackLevelSeparate.empty()) {
274 auto cfaArea = implicit_cast<int>(mRaw->cfa.getSize().area());
275 if (mRaw->isCFA &&
276 cfaArea <= implicit_cast<int>(sensor->mBlackLevelSeparate.size())) {
277 mRaw->blackLevelSeparate =
278 Array2DRef(mRaw->blackLevelSeparateStorage.data(), 2, 2);
279 auto blackLevelSeparate1D =
280 *mRaw->blackLevelSeparate->getAsArray1DRef();
281 for (int i = 0; i < cfaArea; i++) {
282 blackLevelSeparate1D(i) = sensor->mBlackLevelSeparate[i];
283 }
284 } else if (!mRaw->isCFA &&
285 mRaw->getCpp() <= sensor->mBlackLevelSeparate.size()) {
286 mRaw->blackLevelSeparate =
287 Array2DRef(mRaw->blackLevelSeparateStorage.data(), 2, 2);
288 auto blackLevelSeparate1D =
289 *mRaw->blackLevelSeparate->getAsArray1DRef();
290 for (uint32_t i = 0; i < mRaw->getCpp(); i++) {
291 blackLevelSeparate1D(i) = sensor->mBlackLevelSeparate[i];
292 }
293 }
294 }
295 }
296
297 // Allow overriding individual blacklevels. Values are in CFA order
298 // (the same order as the in the CFA tag)
299 // A hint could be:
300 // <Hint name="final_cfa_black" value="10,20,30,20"/>
301 std::string cfa_black = hints.get("final_cfa_black", std::string());
302 if (!cfa_black.empty()) {
303 vector<std::string> v = splitString(cfa_black, ',');
304 if (v.size() != 4) {
305 mRaw->setError("Expected 4 values '10,20,30,20' as values for "
306 "final_cfa_black hint.");
307 } else {
308 auto blackLevelSeparate1D = *mRaw->blackLevelSeparate->getAsArray1DRef();
309 for (int i = 0; i < 4; i++) {
310 blackLevelSeparate1D(i) = stoi(v[i]);
311 }
312 }
313 }
314}
315
317 return {mRaw->dim.x, mRaw->dim.y};
318}
319
321 try {
324
326 hints.get("pixel_aspect_ratio", raw->metadata.pixelAspectRatio);
328 raw->fixBadPixels();
330 }
331
332 return raw;
333 } catch (const TiffParserException& e) {
334 ThrowRDE("%s", e.what());
335 } catch (const FileIOException& e) {
336 ThrowRDE("%s", e.what());
337 } catch (const IOException& e) {
338 ThrowRDE("%s", e.what());
339 }
340}
341
343 try {
345 } catch (const TiffParserException& e) {
346 ThrowRDE("%s", e.what());
347 } catch (const FileIOException& e) {
348 ThrowRDE("%s", e.what());
349 } catch (const IOException& e) {
350 ThrowRDE("%s", e.what());
351 }
352}
353
355 try {
357 } catch (const TiffParserException& e) {
358 ThrowRDE("%s", e.what());
359 } catch (const FileIOException& e) {
360 ThrowRDE("%s", e.what());
361 } catch (const IOException& e) {
362 ThrowRDE("%s", e.what());
363 }
364}
365
366} // namespace rawspeed
#define s
#define ThrowRDE(...)
assert(dim.area() >=area)
std::string canonical_id
Definition Camera.h:100
std::string canonical_alias
Definition Camera.h:99
iPoint2D cropPos
Definition Camera.h:106
std::string canonical_model
Definition Camera.h:98
iPoint2D cropSize
Definition Camera.h:105
bool cropAvailable
Definition Camera.h:117
std::string canonical_make
Definition Camera.h:97
std::vector< BlackArea > blackAreas
Definition Camera.h:107
const CameraSensorInfo * getSensorInfo(int iso) const
Definition Camera.cpp:418
SupportStatus supportStatus
Definition Camera.h:104
std::vector< NotARational< int > > color_matrix
Definition Camera.h:111
ColorFilterArray cfa
Definition Camera.h:103
const Camera * getCamera(const std::string &make, const std::string &model, const std::string &mode) const
virtual void setMetaData(const CameraMetaData *meta, const std::string &make, const std::string &model, const std::string &mode, int iso_speed=0)
void checkSupport(const CameraMetaData *meta)
RawDecoder(Buffer file)
bool checkCameraSupported(const CameraMetaData *meta, const std::string &make, const std::string &model, const std::string &mode)
virtual void decodeMetaDataInternal(const CameraMetaData *meta)=0
bool handleCameraSupport(const CameraMetaData *meta, const std::string &make, const std::string &model, const std::string &mode)
void decodeUncompressed(const TiffIFD *rawIFD, BitOrder order) const
void decodeMetaData(const CameraMetaData *meta)
virtual int getDecoderVersion() const =0
virtual RawImage decodeRawInternal()=0
virtual void checkSupportInternal(const CameraMetaData *meta)=0
virtual iRectangle2D getDefaultCrop()
void fixBadPixels() REQUIRES(!mBadPixelMutex)
Definition RawImage.cpp:232
Array2DRef< std::byte > getByteDataAsUncroppedArray2DRef() noexcept
Definition RawImage.h:330
ImageMetaData metadata
Definition RawImage.h:184
Definition TiffEntry.h:62
uint32_t getU32(uint32_t index=0) const
uint32_t count
Definition TiffEntry.h:84
TiffEntry * getEntry(TiffTag tag) const
Definition TiffIFD.cpp:313
value_type x
Definition Point.h:102
value_type y
Definition Point.h:103
area_type RAWSPEED_READONLY area() const
Definition Point.h:81
constexpr uint64_t RAWSPEED_READNONE roundUpDivisionSafe(uint64_t value, uint64_t div)
Definition Common.h:145
constexpr RAWSPEED_READNONE Ttgt implicit_cast(Tsrc value)
Definition Casts.h:32
void writeLog(DEBUG_PRIO priority, const char *format,...)
Definition Common.cpp:37
Array2DRef(Array1DRef< T > data, int width, int height, int pitch) -> Array2DRef< T >
std::vector< std::string > splitString(const std::string &input, char c=' ')
Definition Common.h:178
static void CheckMemIsInitialized(const void *addr, size_t size)