RawSpeed
fast raw decoding library
Loading...
Searching...
No Matches
DngDecoder.cpp
Go to the documentation of this file.
1/*
2 RawSpeed - RAW file decoder.
3
4 Copyright (C) 2009-2014 Klaus Post
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19*/
20
21#include "rawspeedconfig.h"
22#include "decoders/DngDecoder.h"
23#include "adt/Array1DRef.h"
24#include "adt/Array2DRef.h"
25#include "adt/Casts.h"
26#include "adt/NORangesSet.h"
27#include "adt/NotARational.h"
28#include "adt/Optional.h"
29#include "adt/Point.h"
30#include "common/Common.h"
31#include "common/DngOpcodes.h"
32#include "common/RawImage.h"
36#include "io/Buffer.h"
37#include "io/ByteStream.h"
38#include "metadata/Camera.h"
42#include "tiff/TiffEntry.h"
43#include "tiff/TiffIFD.h"
44#include "tiff/TiffTag.h"
45#include <algorithm>
46#include <array>
47#include <cassert>
48#include <cstdint>
49#include <limits>
50#include <map>
51#include <memory>
52#include <string>
53#include <utility>
54#include <vector>
55
56using std::map;
57using std::vector;
58
59namespace rawspeed {
60
61bool RAWSPEED_READONLY DngDecoder::isAppropriateDecoder(
62 const TiffRootIFD* rootIFD, [[maybe_unused]] Buffer file) {
64}
65
67 : AbstractTiffDecoder(std::move(rootIFD), file) {
68 if (!mRootIFD->hasEntryRecursive(TiffTag::DNGVERSION))
69 ThrowRDE("DNG, but version tag is missing. Will not guess.");
70
71 const auto v =
72 mRootIFD->getEntryRecursive(TiffTag::DNGVERSION)->getData().getBuffer(4);
73
74 if (v[0] != 1) {
75 ThrowRDE("Not a supported DNG image format: v%i.%i.%i.%i",
76 static_cast<int>(v[0]), static_cast<int>(v[1]),
77 static_cast<int>(v[2]), static_cast<int>(v[3]));
78 }
79 // if (v[1] > 4)
80 // ThrowRDE("Not a supported DNG image format: v%u.%u.%u.%u", (int)v[0],
81 // (int)v[1], (int)v[2], (int)v[3]);
82
83 // Prior to v1.1.xxx fix LJPEG encoding bug
84 mFixLjpeg = (v[0] <= 1) && (v[1] < 1);
85}
86
87void DngDecoder::dropUnsuportedChunks(std::vector<const TiffIFD*>* data) {
88 for (auto i = data->begin(); i != data->end();) {
89 const auto& ifd = *i;
90
91 int comp = ifd->getEntry(TiffTag::COMPRESSION)->getU16();
92 bool isSubsampled = false;
93 bool isAlpha = false;
94
95 if (ifd->hasEntry(TiffTag::NEWSUBFILETYPE) &&
96 ifd->getEntry(TiffTag::NEWSUBFILETYPE)->isInt()) {
97 const uint32_t NewSubFileType =
98 (*i)->getEntry(TiffTag::NEWSUBFILETYPE)->getU32();
99
100 // bit 0 is on if image is subsampled.
101 // the value itself can be either 1, or 0x10001.
102 // or 5 for "Transparency information for subsampled raw images"
103 isSubsampled = NewSubFileType & (1 << 0);
104
105 // bit 2 is on if image contains transparency information.
106 // the value itself can be either 4 or 5
107 isAlpha = NewSubFileType & (1 << 2);
108 }
109
110 // normal raw?
111 bool supported = !isSubsampled && !isAlpha;
112
113 switch (comp) {
114 case 1: // uncompressed
115 case 7: // lossless JPEG
116#ifdef HAVE_ZLIB
117 case 8: // deflate
118#endif
119 case 9: // VC-5 as used by GoPro
120#ifdef HAVE_JPEG
121 case 0x884c: // lossy JPEG
122#endif
123 // no change, if supported, then is still supported.
124 break;
125
126#ifndef HAVE_ZLIB
127 case 8: // deflate
128#pragma message \
129 "ZLIB is not present! Deflate compression will not be supported!"
130 writeLog(DEBUG_PRIO::WARNING, "DNG Decoder: found Deflate-encoded chunk, "
131 "but the deflate support was disabled at "
132 "build!");
133 [[clang::fallthrough]];
134#endif
135#ifndef HAVE_JPEG
136 case 0x884c: // lossy JPEG
137#pragma message \
138 "JPEG is not present! Lossy JPEG compression will not be supported!"
139 writeLog(DEBUG_PRIO::WARNING, "DNG Decoder: found lossy JPEG-encoded "
140 "chunk, but the jpeg support was "
141 "disabled at build!");
142 [[clang::fallthrough]];
143#endif
144 default:
145 supported = false;
146 break;
147 }
148
149 if (supported)
150 ++i;
151 else
152 i = data->erase(i);
153 }
154}
155
157 if (!raw->hasEntry(TiffTag::ACTIVEAREA))
158 return {};
159
160 const TiffEntry* active_area = raw->getEntry(TiffTag::ACTIVEAREA);
161 if (active_area->count != 4)
162 ThrowRDE("active area has %u values instead of 4", active_area->count);
163
164 const iRectangle2D fullImage(0, 0, mRaw->dim.x, mRaw->dim.y);
165
166 const auto corners = active_area->getU32Array(4);
167 const iPoint2D topLeft(static_cast<int>(corners[1]),
168 static_cast<int>(corners[0]));
169 const iPoint2D bottomRight(static_cast<int>(corners[3]),
170 static_cast<int>(corners[2]));
171
172 if (!(fullImage.isPointInsideInclusive(topLeft) &&
173 fullImage.isPointInsideInclusive(bottomRight) &&
174 bottomRight >= topLeft)) {
175 ThrowRDE("Rectangle (%i, %i, %i, %i) not inside image (%i, %i, %i, %i).",
176 topLeft.x, topLeft.y, bottomRight.x, bottomRight.y,
177 fullImage.getTopLeft().x, fullImage.getTopLeft().y,
178 fullImage.getBottomRight().x, fullImage.getBottomRight().y);
179 }
180
181 iRectangle2D crop;
182 crop.setTopLeft(topLeft);
183 crop.setBottomRightAbsolute(bottomRight);
184 assert(fullImage.isThisInside(fullImage));
185
186 return crop;
187}
188
189namespace {
191 switch (c) {
192 using enum CFAColor;
193 case 0:
194 return RED;
195 case 1:
196 return GREEN;
197 case 2:
198 return BLUE;
199 case 3:
200 return CYAN;
201 case 4:
202 return MAGENTA;
203 case 5:
204 return YELLOW;
205 case 6:
206 return WHITE;
207 default:
208 return std::nullopt;
209 }
210}
211} // namespace
212
213void DngDecoder::parseCFA(const TiffIFD* raw) const {
214
215 // Check if layout is OK, if present
216 if (raw->hasEntry(TiffTag::CFALAYOUT) &&
217 raw->getEntry(TiffTag::CFALAYOUT)->getU16() != 1)
218 ThrowRDE("Unsupported CFA Layout.");
219
220 const TiffEntry* cfadim = raw->getEntry(TiffTag::CFAREPEATPATTERNDIM);
221 if (cfadim->count != 2)
222 ThrowRDE("Couldn't read CFA pattern dimension");
223
224 // Does NOT contain dimensions as some documents state
225 const TiffEntry* cPat = raw->getEntry(TiffTag::CFAPATTERN);
226 if (!cPat->count)
227 ThrowRDE("CFA pattern is empty!");
228
229 iPoint2D cfaSize(cfadim->getU32(1), cfadim->getU32(0));
230 if (!cfaSize.hasPositiveArea() || cfaSize.area() != cPat->count) {
231 ThrowRDE("CFA pattern dimension and pattern count does not "
232 "match: %u.",
233 cPat->count);
234 }
235
236 mRaw->cfa.setSize(cfaSize);
237
238 for (int y = 0; y < cfaSize.y; y++) {
239 for (int x = 0; x < cfaSize.x; x++) {
240 uint32_t c1 = cPat->getByte(x + (y * cfaSize.x));
241
242 auto c2 = getDNGCFAPatternAsCFAColor(c1);
243 if (!c2)
244 ThrowRDE("Unsupported CFA Color: %u", c1);
245
246 mRaw->cfa.setColorAt(iPoint2D(x, y), *c2);
247 }
248 }
249
250 // the cfa is specified relative to the ActiveArea. we want it relative (0,0)
251 // Since in handleMetadata(), in subFrame() we unconditionally shift CFA by
252 // activearea+DefaultCropOrigin; here we need to undo the 'ACTIVEAREA' part.
254 if (!aa)
255 return;
256
257 // To reverse the ActiveArea modifictions done earlier, we need to
258 // use the negated ActiveArea x/y values.
259 mRaw->cfa.shiftRight(-int(aa->pos.x));
260 mRaw->cfa.shiftDown(-int(aa->pos.y));
261}
262
264 // Look for D65 calibrated color matrix
265
266 auto impl = [this](TiffTag I, TiffTag M) -> TiffEntry* {
267 if (!mRootIFD->hasEntryRecursive(I))
268 return nullptr;
269 if (const TiffEntry* illuminant = mRootIFD->getEntryRecursive(I);
270 illuminant->getU16() != 21 || // D65
271 !mRootIFD->hasEntryRecursive(M))
272 return nullptr;
273 return mRootIFD->getEntryRecursive(M);
274 };
275
276 const TiffEntry* mat;
278 if (!mat)
280 if (!mat)
281 return;
282
283 // Color matrix size *MUST* be a multiple of 3 (number of channels in XYZ).
284 if (mat->count % 3 != 0)
285 return;
286
287 const auto srat_vals = mat->getSRationalArray(mat->count);
288 bool Success = true;
289 mRaw->metadata.colorMatrix.reserve(mat->count);
290 for (const auto& val : srat_vals) {
291 Success &= val.den != 0;
292 if (!Success)
293 break;
294 mRaw->metadata.colorMatrix.emplace_back(val);
295 }
296 if (!Success)
297 mRaw->metadata.colorMatrix.clear();
298}
299
302 if (raw->hasEntry(TiffTag::TILEOFFSETS)) {
303 const uint32_t tilew = raw->getEntry(TiffTag::TILEWIDTH)->getU32();
304 const uint32_t tileh = raw->getEntry(TiffTag::TILELENGTH)->getU32();
305
306 if (tilew <= 0 || tileh <= 0)
307 ThrowRDE("Invalid tile size: (%u, %u)", tilew, tileh);
308
309 assert(tilew > 0);
310 const auto tilesX =
312 if (!tilesX)
313 ThrowRDE("Zero tiles horizontally");
314
315 assert(tileh > 0);
316 const auto tilesY =
318 if (!tilesY)
319 ThrowRDE("Zero tiles vertically");
320
321 const TiffEntry* offsets = raw->getEntry(TiffTag::TILEOFFSETS);
322 if (const TiffEntry* counts = raw->getEntry(TiffTag::TILEBYTECOUNTS);
323 offsets->count != counts->count) {
324 ThrowRDE("Tile count mismatch: offsets:%u count:%u", offsets->count,
325 counts->count);
326 }
327
328 // tilesX * tilesY may overflow, but division is fine, so let's do that.
329 if ((offsets->count / tilesX != tilesY || (offsets->count % tilesX != 0)) ||
330 (offsets->count / tilesY != tilesX || (offsets->count % tilesY != 0))) {
331 ThrowRDE("Tile X/Y count mismatch: total:%u X:%u, Y:%u", offsets->count,
332 tilesX, tilesY);
333 }
334
335 return {mRaw->dim, tilew, tileh};
336 }
337
338 // Strips
339 const TiffEntry* offsets = raw->getEntry(TiffTag::STRIPOFFSETS);
340 const TiffEntry* counts = raw->getEntry(TiffTag::STRIPBYTECOUNTS);
341
342 if (counts->count != offsets->count) {
343 ThrowRDE("Byte count number does not match strip size: "
344 "count:%u, stips:%u ",
345 counts->count, offsets->count);
346 }
347
348 uint32_t yPerSlice = raw->hasEntry(TiffTag::ROWSPERSTRIP)
350 : mRaw->dim.y;
351
352 if (yPerSlice == 0 ||
353 roundUpDivisionSafe(mRaw->dim.y, yPerSlice) != counts->count) {
354 ThrowRDE("Invalid y per slice %u or strip count %u (height = %i)",
355 yPerSlice, counts->count, mRaw->dim.y);
356 }
357
358 return {mRaw->dim, static_cast<uint32_t>(mRaw->dim.x), yPerSlice};
359}
360
361void DngDecoder::decodeData(const TiffIFD* raw, uint32_t sample_format) const {
362 if (compression == 8 && sample_format != 3) {
363 ThrowRDE("Only float format is supported for "
364 "deflate-compressed data.");
365 } else if ((compression == 7 || compression == 0x884c) &&
366 sample_format != 1) {
367 ThrowRDE("Only 16 bit unsigned data supported for "
368 "JPEG-compressed data.");
369 }
370
371 uint32_t predictor = ~0U;
373 predictor = raw->getEntry(TiffTag::PREDICTOR)->getU32();
374
375 if (mRaw->getDataType() == RawImageType::UINT16) {
376 // Default white level is (2 ** BitsPerSample) - 1
377 mRaw->whitePoint = implicit_cast<int>((1UL << *bps) - 1UL);
378 } else if (mRaw->getDataType() == RawImageType::F32) {
379 // 1. We divide by white level to normalize the image,
380 // s.t. the 1.0 becomes the white level.
381 // 2. In DNG spec, white level is always an integer,
382 // there can not be a non-integral white level.
383 // 3. Additionally, no white level for FP DNG's means that
384 // it is pre-normalized (default is 1.0).
385 //
386 // Therefore, we can surmise that:
387 // a) FP DNG's never have white level of <1.0
388 // b) FP DNG's always have integral white level
389 // c) if FP DNG has a white level of `w`, it is always correct
390 // to divide by `float(w)` to normalize the image
391 // ... therefore, we can, as an optimization,
392 // store FP DNG white level as an integer.
393 mRaw->whitePoint = 1;
394 }
395
396 // Some decompressors (such as VC5) may depend on the white point
397 if (raw->hasEntry(TiffTag::WHITELEVEL)) {
398 const TiffEntry* whitelevel = raw->getEntry(TiffTag::WHITELEVEL);
399 if (whitelevel->isInt())
400 mRaw->whitePoint = whitelevel->getU32();
401 }
402
404 mFixLjpeg, *bps, predictor);
405
406 slices.slices.reserve(slices.dsc.numTiles);
407
408 const TiffEntry* offsets = nullptr;
409 const TiffEntry* counts = nullptr;
410 if (raw->hasEntry(TiffTag::TILEOFFSETS)) {
411 offsets = raw->getEntry(TiffTag::TILEOFFSETS);
412 counts = raw->getEntry(TiffTag::TILEBYTECOUNTS);
413 } else { // Strips
414 offsets = raw->getEntry(TiffTag::STRIPOFFSETS);
415 counts = raw->getEntry(TiffTag::STRIPBYTECOUNTS);
416 }
417 assert(slices.dsc.numTiles == offsets->count);
418 assert(slices.dsc.numTiles == counts->count);
419
420 NORangesSet<Buffer> tilesLegality;
421 for (auto n = 0U; n < slices.dsc.numTiles; n++) {
422 const auto offset = offsets->getU32(n);
423 const auto count = counts->getU32(n);
424
425 if (count < 1)
426 ThrowRDE("Tile %u is empty", n);
427
428 ByteStream bs(DataBuffer(mFile.getSubView(offset, count),
429 mRootIFD->rootBuffer.getByteOrder()));
430
431 if (!tilesLegality.insert(bs))
432 ThrowTPE("Two tiles overlap. Raw corrupt!");
433
434 slices.slices.emplace_back(slices.dsc, n, bs);
435 }
436
437 assert(slices.slices.size() == slices.dsc.numTiles);
438 if (slices.slices.empty())
439 ThrowRDE("No valid slices found.");
440
441 // FIXME: should we sort the tiles, to linearize the input reading?
442
443 mRaw->createData();
444
445 slices.decompress();
446}
447
449 vector<const TiffIFD*> data = mRootIFD->getIFDsWithTag(TiffTag::COMPRESSION);
450
451 if (data.empty())
452 ThrowRDE("No image data found");
453
455
456 if (data.empty())
457 ThrowRDE("No RAW chunks found");
458
459 if (data.size() > 1) {
461 "Multiple RAW chunks found - using first only!");
462 }
463
464 const TiffIFD* raw = data[0];
465
467 if (*bps < 1 || *bps > 32)
468 ThrowRDE("Unsupported bit per sample count: %i.", *bps);
469
470 uint32_t sample_format = 1;
472 sample_format = raw->getEntry(TiffTag::SAMPLEFORMAT)->getU32();
473
475
476 switch (sample_format) {
477 case 1:
479 break;
480 case 3:
482 break;
483 default:
484 ThrowRDE("Only 16 bit unsigned or float point data supported. Sample "
485 "format %u is not supported.",
486 sample_format);
487 }
488
489 mRaw->isCFA =
490 (raw->getEntry(TiffTag::PHOTOMETRICINTERPRETATION)->getU16() == 32803);
491
492 if (mRaw->isCFA)
493 writeLog(DEBUG_PRIO::EXTRA, "This is a CFA image");
494 else {
495 writeLog(DEBUG_PRIO::EXTRA, "This is NOT a CFA image");
496 }
497
498 if (sample_format == 1 && *bps > 16)
499 ThrowRDE("Integer precision larger than 16 bits currently not supported.");
500
501 if (sample_format == 3 && *bps != 16 && *bps != 24 && *bps != 32)
502 ThrowRDE("Floating point must be 16/24/32 bits per sample.");
503
504 mRaw->dim.x = raw->getEntry(TiffTag::IMAGEWIDTH)->getU32();
505 mRaw->dim.y = raw->getEntry(TiffTag::IMAGELENGTH)->getU32();
506
507 if (!mRaw->dim.hasPositiveArea())
508 ThrowRDE("Image has zero size");
509
510#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
511 // Yeah, sure, here it would be just dumb to leave this for production :)
512 if (mRaw->dim.x > 9536 || mRaw->dim.y > 7680) {
513 ThrowRDE("Unexpected image dimensions found: (%i; %i)", mRaw->dim.x,
514 mRaw->dim.y);
515 }
516#endif
517
518 if (mRaw->isCFA)
519 parseCFA(raw);
520
522
523 if (cpp < 1 || cpp > 4)
524 ThrowRDE("Unsupported samples per pixel count: %u.", cpp);
525
526 mRaw->setCpp(cpp);
527
528 // Now load the image
529 decodeData(raw, sample_format);
530
531 handleMetadata(raw);
532
533 return mRaw;
534}
535
537 // Crop
538 if (const Optional<iRectangle2D> aa = parseACTIVEAREA(raw))
539 mRaw->subFrame(*aa);
540
543 iRectangle2D cropped(0, 0, mRaw->dim.x, mRaw->dim.y);
544 const TiffEntry* origin_entry = raw->getEntry(TiffTag::DEFAULTCROPORIGIN);
545 const TiffEntry* size_entry = raw->getEntry(TiffTag::DEFAULTCROPSIZE);
546
547 const auto tl_r = origin_entry->getRationalArray(2);
548 std::array<unsigned, 2> tl;
549 std::transform(tl_r.begin(), tl_r.end(), tl.begin(),
550 [](const NotARational<unsigned>& r) {
551 if (r.den == 0 || r.num % r.den != 0)
552 ThrowRDE("Error decoding default crop origin");
553 return r.num / r.den;
554 });
555
556 if (iPoint2D cropOrigin(tl[0], tl[1]);
557 cropped.isPointInsideInclusive(cropOrigin))
558 cropped = iRectangle2D(cropOrigin, {0, 0});
559
560 cropped.dim = mRaw->dim - cropped.pos;
561
562 const auto sz_r = size_entry->getRationalArray(2);
563 std::array<unsigned, 2> sz;
564 std::transform(sz_r.begin(), sz_r.end(), sz.begin(),
565 [](const NotARational<unsigned>& r) {
566 if (r.den == 0 || r.num % r.den != 0)
567 ThrowRDE("Error decoding default crop size");
568 return r.num / r.den;
569 });
570
571 if (iPoint2D size(sz[0], sz[1]);
572 size.isThisInside(mRaw->dim) &&
573 (size + cropped.pos).isThisInside(mRaw->dim))
574 cropped.dim = size;
575
576 mRaw->subFrame(cropped);
577 }
578
579 // Adapt DNG DefaultScale to aspect-ratio
581 const TiffEntry* default_scale = raw->getEntry(TiffTag::DEFAULTSCALE);
582 const auto scales = default_scale->getRationalArray(2);
583 for (const auto& scale : scales) {
584 if (scale.num == 0 || scale.den == 0)
585 ThrowRDE("Error decoding default pixel scale");
586 }
587 mRaw->metadata.pixelAspectRatio =
588 static_cast<double>(scales[0]) / static_cast<double>(scales[1]);
589 }
590
591 // Apply stage 1 opcodes
593 try {
594 const TiffEntry* opcodes = raw->getEntry(TiffTag::OPCODELIST1);
595 // The entry might exist, but it might be empty, which means no opcodes
596 if (opcodes->count > 0) {
597 DngOpcodes codes(mRaw, opcodes->getData());
598 codes.applyOpCodes(mRaw);
599 }
600 } catch (const RawDecoderException& e) {
601 // We push back errors from the opcode parser, since the image may still
602 // be usable
603 mRaw->setError(e.what());
604 }
605 }
606
607 // Linearization
610 const TiffEntry* lintable = raw->getEntry(TiffTag::LINEARIZATIONTABLE);
611 auto table = lintable->getU16Array(lintable->count);
612 RawImageCurveGuard curveHandler(&mRaw, table, uncorrectedRawValues);
614 mRaw->sixteenBitLookup();
615 }
616
617 // Set black
618 setBlack(raw);
619
620 // Apply opcodes to lossy DNG
621 if (compression == 0x884c && !uncorrectedRawValues &&
623 // We must apply black/white scaling
624 mRaw->scaleBlackWhite();
625
626 // Apply stage 2 codes
627 try {
629 codes.applyOpCodes(mRaw);
630 } catch (const RawDecoderException& e) {
631 // We push back errors from the opcode parser, since the image may still
632 // be usable
633 mRaw->setError(e.what());
634 }
635 mRaw->blackAreas.clear();
636 mRaw->blackLevel = 0;
637 mRaw->blackLevelSeparate =
638 Array2DRef(mRaw->blackLevelSeparateStorage.data(), 2, 2);
639 auto blackLevelSeparate1D = *mRaw->blackLevelSeparate->getAsArray1DRef();
640 std::fill(blackLevelSeparate1D.begin(), blackLevelSeparate1D.end(), 0);
641 // FIXME: why do we provide both the `blackLevel` and `blackLevelSeparate`?
642 mRaw->whitePoint = 65535;
643 }
644}
645
647 // Fetch the white balance
648 if (mRootIFD->hasEntryRecursive(TiffTag::ASSHOTNEUTRAL)) {
649 const TiffEntry* as_shot_neutral =
650 mRootIFD->getEntryRecursive(TiffTag::ASSHOTNEUTRAL);
651 if (as_shot_neutral->count == 3) {
652 std::array<float, 4> wbCoeffs = {};
653 for (uint32_t i = 0; i < 3; i++) {
654 float c = as_shot_neutral->getFloat(i);
655 wbCoeffs[i] = (c > 0.0F) ? (1.0F / c) : 0.0F;
656 }
657 mRaw->metadata.wbCoeffs = wbCoeffs;
658 }
659 return;
660 }
661
662 if (!mRaw->metadata.colorMatrix.empty() &&
663 mRootIFD->hasEntryRecursive(TiffTag::ASSHOTWHITEXY)) {
664 const TiffEntry* as_shot_white_xy =
665 mRootIFD->getEntryRecursive(TiffTag::ASSHOTWHITEXY);
666 assert(mRaw->metadata.colorMatrix.size() % 3 == 0);
667 const auto numColorPlanes = mRaw->metadata.colorMatrix.size() / 3;
668 if (numColorPlanes == 3 && as_shot_white_xy->count == 2) {
669 // See http://www.brucelindbloom.com/index.html?Eqn_xyY_to_XYZ.html
670 const float x = as_shot_white_xy->getFloat(0);
671 const float y = as_shot_white_xy->getFloat(1);
672 if (y > 0.0F) {
673 constexpr float Y = 1.0F;
674 const std::array<float, 3> as_shot_white = {
675 {x * Y / y, Y, (1 - x - y) * Y / y}};
676
677 // Convert from XYZ to camera reference values first
678 std::array<float, 4> wbCoeffs = {};
679
680 for (uint32_t i = 0; i < 3; i++) {
681 float c = (float(mRaw->metadata.colorMatrix[(i * 3) + 0]) *
682 as_shot_white[0]) +
683 (float(mRaw->metadata.colorMatrix[(i * 3) + 1]) *
684 as_shot_white[1]) +
685 (float(mRaw->metadata.colorMatrix[(i * 3) + 2]) *
686 as_shot_white[2]);
687 wbCoeffs[i] = (c > 0.0F) ? (1.0F / c) : 0.0F;
688 }
689 mRaw->metadata.wbCoeffs = wbCoeffs;
690 }
691 }
692 }
693}
694
696 if (mRootIFD->hasEntryRecursive(TiffTag::ISOSPEEDRATINGS))
697 mRaw->metadata.isoSpeed =
698 mRootIFD->getEntryRecursive(TiffTag::ISOSPEEDRATINGS)->getU32();
699
700 TiffID id;
701
702 try {
703 id = mRootIFD->getID();
704 } catch (const RawspeedException& e) {
705 mRaw->setError(e.what());
706 // not all dngs have MAKE/MODEL entries,
707 // will be dealt with by using UNIQUECAMERAMODEL below
708 }
709
710 // Set the make and model
711 mRaw->metadata.make = id.make;
712 mRaw->metadata.model = id.model;
713
714 const Camera* cam = meta->getCamera(id.make, id.model, "dng");
715 if (!cam) // Also look for non-DNG cameras in case it's a converted file
716 cam = meta->getCamera(id.make, id.model, "");
717 if (!cam) // Worst case scenario, look for any such camera.
718 cam = meta->getCamera(id.make, id.model);
719 if (cam) {
720 mRaw->metadata.canonical_make = cam->canonical_make;
721 mRaw->metadata.canonical_model = cam->canonical_model;
722 mRaw->metadata.canonical_alias = cam->canonical_alias;
723 mRaw->metadata.canonical_id = cam->canonical_id;
724 } else {
725 mRaw->metadata.canonical_make = id.make;
726 mRaw->metadata.canonical_model = mRaw->metadata.canonical_alias = id.model;
727 if (mRootIFD->hasEntryRecursive(TiffTag::UNIQUECAMERAMODEL)) {
728 mRaw->metadata.canonical_id =
729 mRootIFD->getEntryRecursive(TiffTag::UNIQUECAMERAMODEL)->getString();
730 } else {
731 mRaw->metadata.canonical_id = id.make + " " + id.model;
732 }
733 }
734
736
738}
739
740/* DNG Images are assumed to be decodable unless explicitly set so */
742 // We set this, since DNG's are not explicitly added.
743 failOnUnknown = false;
744
745 if (!(mRootIFD->hasEntryRecursive(TiffTag::MAKE) &&
746 mRootIFD->hasEntryRecursive(TiffTag::MODEL))) {
747 // Check "Unique Camera Model" instead, uses this for both make + model.
748 if (mRootIFD->hasEntryRecursive(TiffTag::UNIQUECAMERAMODEL)) {
749 std::string unique =
750 mRootIFD->getEntryRecursive(TiffTag::UNIQUECAMERAMODEL)->getString();
751 checkCameraSupported(meta, {unique, unique}, "dng");
752 return;
753 }
754 // If we don't have make/model we cannot tell, but still assume yes.
755 return;
756 }
757
758 checkCameraSupported(meta, mRootIFD->getID(), "dng");
759}
760
761/* Decodes DNG masked areas into blackareas in the image */
763 const TiffEntry* masked = raw->getEntry(TiffTag::MASKEDAREAS);
764
765 if (masked->type != TiffDataType::SHORT && masked->type != TiffDataType::LONG)
766 return false;
767
768 uint32_t nrects = masked->count / 4;
769 if (0 == nrects)
770 return false;
771
772 /* Since we may both have short or int, copy it to int array. */
773 auto rects = masked->getU32Array(nrects * 4);
774
775 const iRectangle2D fullImage(0, 0, mRaw->getUncroppedDim().x,
776 mRaw->getUncroppedDim().y);
777 const iPoint2D top = mRaw->getCropOffset();
778
779 for (uint32_t i = 0; i < nrects; i++) {
780 iPoint2D topleft(rects[(i * 4UL) + 1UL], rects[i * 4UL]);
781 iPoint2D bottomright(rects[(i * 4UL) + 3UL], rects[(i * 4UL) + 2UL]);
782
783 if (!(fullImage.isPointInsideInclusive(topleft) &&
784 fullImage.isPointInsideInclusive(bottomright) &&
785 (topleft < bottomright)))
786 ThrowRDE("Bad masked area.");
787
788 // Is this a horizontal box, only add it if it covers the active width of
789 // the image
790 if (topleft.x <= top.x && bottomright.x >= (mRaw->dim.x + top.x)) {
791 mRaw->blackAreas.emplace_back(topleft.y, bottomright.y - topleft.y,
792 false);
793 }
794 // Is it a vertical box, only add it if it covers the active height of the
795 // image
796 else if (topleft.y <= top.y && bottomright.y >= (mRaw->dim.y + top.y)) {
797 mRaw->blackAreas.emplace_back(topleft.x, bottomright.x - topleft.x, true);
798 }
799 }
800 return !mRaw->blackAreas.empty();
801}
802
804 iPoint2D blackdim(1, 1);
806 const TiffEntry* bleveldim = raw->getEntry(TiffTag::BLACKLEVELREPEATDIM);
807 if (bleveldim->count == 2)
808 blackdim = iPoint2D(bleveldim->getU32(0), bleveldim->getU32(1));
809 else if (bleveldim->count == 1) {
810 // Non-spec-compliant quirk. Assuming NxN repeat dimensions.
811 blackdim = iPoint2D(bleveldim->getU32(0), bleveldim->getU32(0));
812 // Let's only allow somewhat unambiguous case of 1x1 repeat dimensions.
813 if (blackdim != iPoint2D(1, 1))
814 return false;
815 } else {
816 return false;
817 }
818 }
819
820 if (!blackdim.hasPositiveArea())
821 return false;
822
823 if (!raw->hasEntry(TiffTag::BLACKLEVEL))
824 return true;
825
826 if (mRaw->getCpp() != 1)
827 return false;
828
829 const TiffEntry* black_entry = raw->getEntry(TiffTag::BLACKLEVEL);
830 if (black_entry->count < blackdim.area())
831 ThrowRDE("BLACKLEVEL entry is too small");
832
833 using BlackType = decltype(mRaw->blackLevelSeparateStorage)::value_type;
834
835 if (blackdim.x < 2 || blackdim.y < 2) {
836 // We so not have enough to fill all individually, read a single and copy it
837 float value = black_entry->getFloat();
838
839 if (static_cast<double>(value) < std::numeric_limits<BlackType>::min() ||
840 static_cast<double>(value) > std::numeric_limits<BlackType>::max())
841 ThrowRDE("Error decoding black level");
842
843 mRaw->blackLevelSeparate =
844 Array2DRef(mRaw->blackLevelSeparateStorage.data(), 2, 2);
845 auto blackLevelSeparate1D = *mRaw->blackLevelSeparate->getAsArray1DRef();
846 for (int y = 0; y < 2; y++) {
847 for (int x = 0; x < 2; x++)
848 blackLevelSeparate1D((y * 2) + x) = implicit_cast<int>(value);
849 }
850 } else {
851 mRaw->blackLevelSeparate =
852 Array2DRef(mRaw->blackLevelSeparateStorage.data(), 2, 2);
853 auto blackLevelSeparate1D = *mRaw->blackLevelSeparate->getAsArray1DRef();
854 for (int y = 0; y < 2; y++) {
855 for (int x = 0; x < 2; x++) {
856 float value = black_entry->getFloat((y * blackdim.x) + x);
857
858 if (static_cast<double>(value) <
859 std::numeric_limits<BlackType>::min() ||
860 static_cast<double>(value) > std::numeric_limits<BlackType>::max())
861 ThrowRDE("Error decoding black level");
862
863 blackLevelSeparate1D((y * 2) + x) = implicit_cast<int>(value);
864 }
865 }
866 }
867
868 // DNG Spec says we must add black in deltav and deltah
870 const TiffEntry* blackleveldeltav =
872 if (static_cast<int>(blackleveldeltav->count) < mRaw->dim.y)
873 ThrowRDE("BLACKLEVELDELTAV array is too small");
874 std::array<float, 2> black_sum = {{}};
875 for (int i = 0; i < mRaw->dim.y; i++)
876 black_sum[i & 1] += blackleveldeltav->getFloat(i);
877
878 auto blackLevelSeparate1D = *mRaw->blackLevelSeparate->getAsArray1DRef();
879 for (int i = 0; i < 4; i++) {
880 const float value =
881 black_sum[i >> 1] / static_cast<float>(mRaw->dim.y) * 2.0F;
882 if (static_cast<double>(value) < std::numeric_limits<BlackType>::min() ||
883 static_cast<double>(value) > std::numeric_limits<BlackType>::max())
884 ThrowRDE("Error decoding black level");
885
886 if (__builtin_sadd_overflow(blackLevelSeparate1D(i),
887 implicit_cast<int>(value),
888 &blackLevelSeparate1D(i)))
889 ThrowRDE("Integer overflow when calculating black level");
890 }
891 }
892
894 const TiffEntry* blackleveldeltah =
896 if (static_cast<int>(blackleveldeltah->count) < mRaw->dim.x)
897 ThrowRDE("BLACKLEVELDELTAH array is too small");
898 std::array<float, 2> black_sum = {{}};
899 for (int i = 0; i < mRaw->dim.x; i++)
900 black_sum[i & 1] += blackleveldeltah->getFloat(i);
901
902 auto blackLevelSeparate1D = *mRaw->blackLevelSeparate->getAsArray1DRef();
903 for (int i = 0; i < 4; i++) {
904 const float value =
905 black_sum[i & 1] / static_cast<float>(mRaw->dim.x) * 2.0F;
906 if (static_cast<double>(value) < std::numeric_limits<BlackType>::min() ||
907 static_cast<double>(value) > std::numeric_limits<BlackType>::max())
908 ThrowRDE("Error decoding black level");
909
910 if (__builtin_sadd_overflow(blackLevelSeparate1D(i),
911 implicit_cast<int>(value),
912 &blackLevelSeparate1D(i)))
913 ThrowRDE("Integer overflow when calculating black level");
914 }
915 }
916 return true;
917}
918
919void DngDecoder::setBlack(const TiffIFD* raw) const {
920
922 return;
923
924 // Black defaults to 0
925 // FIXME: is this the right thing to do?
926 mRaw->blackLevelSeparate =
927 Array2DRef(mRaw->blackLevelSeparateStorage.data(), 2, 2);
928 auto blackLevelSeparate1D = *mRaw->blackLevelSeparate->getAsArray1DRef();
929 std::fill(blackLevelSeparate1D.begin(), blackLevelSeparate1D.end(), 0);
930
933}
934} // namespace rawspeed
#define ThrowRDE(...)
#define ThrowTPE(...)
assert(dim.area() >=area)
dim y
Definition Common.cpp:51
dim x
Definition Common.cpp:50
std::vector< DngSliceElement > slices
bool checkCameraSupported(const CameraMetaData *meta, const TiffID &id, const std::string &mode)
AbstractTiffDecoder(TiffRootIFDOwner &&root, Buffer file)
std::string canonical_id
Definition Camera.h:100
std::string canonical_alias
Definition Camera.h:99
std::string canonical_model
Definition Camera.h:98
std::string canonical_make
Definition Camera.h:97
const Camera * getCamera(const std::string &make, const std::string &model, const std::string &mode) const
DngDecoder(TiffRootIFDOwner &&rootIFD, Buffer file)
void decodeMetaDataInternal(const CameraMetaData *meta) override
void setBlack(const TiffIFD *raw) const
bool decodeMaskedAreas(const TiffIFD *raw) const
bool decodeBlackLevels(const TiffIFD *raw) const
void parseCFA(const TiffIFD *raw) const
Optional< int > bps
Definition DngDecoder.h:61
void decodeData(const TiffIFD *raw, uint32_t sample_format) const
RawImage decodeRawInternal() override
static bool isAppropriateDecoder(const TiffRootIFD *rootIFD, Buffer file)
static void dropUnsuportedChunks(std::vector< const TiffIFD * > *data)
void handleMetadata(const TiffIFD *raw)
DngTilingDescription getTilingDescription(const TiffIFD *raw) const
void checkSupportInternal(const CameraMetaData *meta) override
void parseWhiteBalance() const
Optional< iRectangle2D > parseACTIVEAREA(const TiffIFD *raw) const
void parseColorMatrix() const
void applyOpCodes(const RawImage &ri) const
bool insert(const T &newElt)
Definition NORangesSet.h:61
static RawImage create(RawImageType type=RawImageType::UINT16)
Definition RawImage.h:265
Definition TiffEntry.h:62
std::vector< uint32_t > getU32Array(uint32_t count_) const
Definition TiffEntry.h:111
std::vector< NotARational< int32_t > > getSRationalArray(uint32_t count_) const
Definition TiffEntry.h:125
std::vector< uint16_t > getU16Array(uint32_t count_) const
Definition TiffEntry.h:107
float getFloat(uint32_t index=0) const
uint32_t getU32(uint32_t index=0) const
bool RAWSPEED_READONLY isInt() const
std::vector< NotARational< uint32_t > > getRationalArray(uint32_t count_) const
Definition TiffEntry.h:120
ByteStream getData() const
Definition TiffEntry.h:129
uint32_t count
Definition TiffEntry.h:84
uint16_t getU16(uint32_t index=0) const
TiffDataType type
Definition TiffEntry.h:83
uint8_t getByte(uint32_t index=0) const
bool RAWSPEED_READONLY hasEntry(TiffTag tag) const
Definition TiffIFD.h:119
TiffEntry * getEntry(TiffTag tag) const
Definition TiffIFD.cpp:313
bool hasEntryRecursive(TiffTag tag) const
Definition TiffIFD.h:122
value_type x
Definition Point.h:102
value_type y
Definition Point.h:103
area_type RAWSPEED_READONLY area() const
Definition Point.h:81
bool RAWSPEED_READONLY hasPositiveArea() const
Definition Point.h:77
constexpr bool RAWSPEED_READONLY isPointInsideInclusive(const iPoint2D &subPoint) const
Definition Point.h:141
void setTopLeft(const iPoint2D &top_left)
Definition Point.h:158
constexpr bool RAWSPEED_READONLY isThisInside(const iRectangle2D &superRect) const
Definition Point.h:146
void setBottomRightAbsolute(const iPoint2D &bottom_right)
Definition Point.h:161
constexpr iPoint2D getTopLeft() const
Definition Point.h:123
constexpr iPoint2D getBottomRight() const
Definition Point.h:124
Optional< CFAColor > getDNGCFAPatternAsCFAColor(uint32_t c)
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
std::unique_ptr< TiffRootIFD > TiffRootIFDOwner
Definition TiffIFD.h:46
void writeLog(DEBUG_PRIO priority, const char *format,...)
Definition Common.cpp:37
Array2DRef(Array1DRef< T > data, int width, int height, int pitch) -> Array2DRef< T >
@ PHOTOMETRICINTERPRETATION
Definition TiffTag.h:46