Skip to content

Commit 299a0fd

Browse files
committed
preliminary support for multiframe DNG
1 parent 2be2bda commit 299a0fd

File tree

4 files changed

+119
-118
lines changed

4 files changed

+119
-118
lines changed

src/librawspeed/common/RawImage.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -224,13 +224,11 @@ class RawImageDataFloat final : public RawImageData {
224224
friend class RawImage;
225225
};
226226

227-
class RawImageAbstract
228-
{
229-
230-
};
231-
232227
class RawImage {
233-
using storage_t = std::vector<std::shared_ptr<RawImageData>>;
228+
public:
229+
using frame_ptr_t = std::shared_ptr<RawImageData>;
230+
using storage_t = std::vector<frame_ptr_t>;
231+
using const_iterator = storage_t::const_iterator;
234232

235233
public:
236234
[[nodiscard]] std::shared_ptr<RawImageData>
@@ -241,8 +239,11 @@ class RawImage {
241239
void clear() { data.clear(); }
242240
void appendFrame(RawImageData* frame) { data.emplace_back(frame); }
243241

242+
const_iterator begin() const { return data.begin(); }
243+
const_iterator end() const { return data.end(); }
244+
244245
private:
245-
std::vector<std::shared_ptr<RawImageData>> data;
246+
storage_t data;
246247
};
247248

248249
// setWithLookUp will set a single pixel by using the lookup table if supplied,

src/librawspeed/decoders/DngDecoder.cpp

Lines changed: 96 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ void DngDecoder::dropUnsuportedChunks(std::vector<const TiffIFD*>* data) {
145145
}
146146
}
147147

148-
void DngDecoder::parseCFA(const TiffIFD* raw) const {
148+
void DngDecoder::parseCFA(const TiffIFD* raw, RawImage::frame_ptr_t frame) {
149149

150150
// Check if layout is OK, if present
151151
if (raw->hasEntry(TiffTag::CFALAYOUT) &&
@@ -166,7 +166,7 @@ void DngDecoder::parseCFA(const TiffIFD* raw) const {
166166
cPat->count);
167167
}
168168

169-
mRaw.get(0)->cfa.setSize(cfaSize);
169+
frame->cfa.setSize(cfaSize);
170170

171171
static const map<uint32_t, CFAColor> int2enum = {
172172
{0, CFAColor::RED}, {1, CFAColor::GREEN}, {2, CFAColor::BLUE},
@@ -185,7 +185,7 @@ void DngDecoder::parseCFA(const TiffIFD* raw) const {
185185
ThrowRDE("Unsupported CFA Color: %u", c1);
186186
}
187187

188-
mRaw.get(0)->cfa.setColorAt(iPoint2D(x, y), c2);
188+
frame->cfa.setColorAt(iPoint2D(x, y), c2);
189189
}
190190
}
191191

@@ -206,8 +206,8 @@ void DngDecoder::parseCFA(const TiffIFD* raw) const {
206206
}))
207207
ThrowRDE("Error decoding active area");
208208

209-
mRaw.get(0)->cfa.shiftLeft(aa[1]);
210-
mRaw.get(0)->cfa.shiftDown(aa[0]);
209+
frame->cfa.shiftLeft(aa[1]);
210+
frame->cfa.shiftDown(aa[0]);
211211
}
212212

213213
DngTilingDescription
@@ -269,7 +269,9 @@ DngDecoder::getTilingDescription(const TiffIFD* raw) const {
269269
return {mRaw.get(0)->dim, static_cast<uint32_t>(mRaw.get(0)->dim.x), yPerSlice};
270270
}
271271

272-
void DngDecoder::decodeData(const TiffIFD* raw, uint32_t sample_format) const {
272+
void DngDecoder::decodeData(const TiffIFD* raw, uint32_t sample_format,
273+
int compression, int bps,
274+
RawImage::frame_ptr_t frame) {
273275
if (compression == 8 && sample_format != 3) {
274276
ThrowRDE("Only float format is supported for "
275277
"deflate-compressed data.");
@@ -287,11 +289,11 @@ void DngDecoder::decodeData(const TiffIFD* raw, uint32_t sample_format) const {
287289
if (raw->hasEntry(TiffTag::WHITELEVEL)) {
288290
const TiffEntry* whitelevel = raw->getEntry(TiffTag::WHITELEVEL);
289291
if (whitelevel->isInt())
290-
mRaw.get(0)->whitePoint = whitelevel->getU32();
292+
frame->whitePoint = whitelevel->getU32();
291293
}
292294

293-
AbstractDngDecompressor slices(mRaw.get(0).get(), getTilingDescription(raw), compression,
294-
mFixLjpeg, bps, predictor);
295+
AbstractDngDecompressor slices(frame.get(), getTilingDescription(raw),
296+
compression, mFixLjpeg, bps, predictor);
295297

296298
slices.slices.reserve(slices.dsc.numTiles);
297299

@@ -330,7 +332,7 @@ void DngDecoder::decodeData(const TiffIFD* raw, uint32_t sample_format) const {
330332

331333
// FIXME: should we sort the tiles, to linearize the input reading?
332334

333-
mRaw.get(0)->createData();
335+
frame->createData();
334336

335337
slices.decompress();
336338
}
@@ -346,90 +348,88 @@ void DngDecoder::decodeRawInternal() {
346348
if (data.empty())
347349
ThrowRDE("No RAW chunks found");
348350

349-
if (data.size() > 1) {
350-
writeLog(DEBUG_PRIO::EXTRA,
351-
"Multiple RAW chunks found - using first only!");
352-
}
351+
/// TODO paralelize?
352+
for (const auto* raw : data) {
353+
int bps = raw->getEntry(TiffTag::BITSPERSAMPLE)->getU32();
354+
if (bps < 1 || bps > 32)
355+
ThrowRDE("Unsupported bit per sample count: %u.", bps);
353356

354-
const TiffIFD* raw = data[0];
355-
356-
bps = raw->getEntry(TiffTag::BITSPERSAMPLE)->getU32();
357-
if (bps < 1 || bps > 32)
358-
ThrowRDE("Unsupported bit per sample count: %u.", bps);
359-
360-
uint32_t sample_format = 1;
361-
if (raw->hasEntry(TiffTag::SAMPLEFORMAT))
362-
sample_format = raw->getEntry(TiffTag::SAMPLEFORMAT)->getU32();
363-
364-
compression = raw->getEntry(TiffTag::COMPRESSION)->getU16();
365-
366-
mRaw.clear();
367-
switch (sample_format) {
368-
case 1:
369-
mRaw.appendFrame(new RawImageDataU16());
370-
break;
371-
case 3:
372-
mRaw.appendFrame(new RawImageDataFloat());
373-
break;
374-
default:
375-
ThrowRDE("Only 16 bit unsigned or float point data supported. Sample "
376-
"format %u is not supported.",
377-
sample_format);
378-
}
357+
uint32_t sample_format = 1;
358+
if (raw->hasEntry(TiffTag::SAMPLEFORMAT))
359+
sample_format = raw->getEntry(TiffTag::SAMPLEFORMAT)->getU32();
379360

380-
mRaw.get(0)->isCFA =
381-
(raw->getEntry(TiffTag::PHOTOMETRICINTERPRETATION)->getU16() == 32803);
361+
int compression = raw->getEntry(TiffTag::COMPRESSION)->getU16();
382362

383-
if (mRaw.get(0)->isCFA)
384-
writeLog(DEBUG_PRIO::EXTRA, "This is a CFA image");
385-
else {
386-
writeLog(DEBUG_PRIO::EXTRA, "This is NOT a CFA image");
387-
}
363+
mRaw.clear();
364+
switch (sample_format) {
365+
case 1:
366+
mRaw.appendFrame(new RawImageDataU16());
367+
break;
368+
case 3:
369+
mRaw.appendFrame(new RawImageDataFloat());
370+
break;
371+
default:
372+
ThrowRDE("Only 16 bit unsigned or float point data supported. Sample "
373+
"format %u is not supported.",
374+
sample_format);
375+
}
388376

389-
if (sample_format == 1 && bps > 16)
390-
ThrowRDE("Integer precision larger than 16 bits currently not supported.");
377+
mRaw.get(0)->isCFA =
378+
(raw->getEntry(TiffTag::PHOTOMETRICINTERPRETATION)->getU16() == 32803);
391379

392-
if (sample_format == 3 && bps != 16 && bps != 24 && bps != 32)
393-
ThrowRDE("Floating point must be 16/24/32 bits per sample.");
380+
if (mRaw.get(0)->isCFA)
381+
writeLog(DEBUG_PRIO::EXTRA, "This is a CFA image");
382+
else {
383+
writeLog(DEBUG_PRIO::EXTRA, "This is NOT a CFA image");
384+
}
385+
386+
if (sample_format == 1 && bps > 16)
387+
ThrowRDE(
388+
"Integer precision larger than 16 bits currently not supported.");
389+
390+
if (sample_format == 3 && bps != 16 && bps != 24 && bps != 32)
391+
ThrowRDE("Floating point must be 16/24/32 bits per sample.");
394392

395-
mRaw.get(0)->dim.x = raw->getEntry(TiffTag::IMAGEWIDTH)->getU32();
396-
mRaw.get(0)->dim.y = raw->getEntry(TiffTag::IMAGELENGTH)->getU32();
393+
mRaw.get(0)->dim.x = raw->getEntry(TiffTag::IMAGEWIDTH)->getU32();
394+
mRaw.get(0)->dim.y = raw->getEntry(TiffTag::IMAGELENGTH)->getU32();
397395

398-
if (!mRaw.get(0)->dim.hasPositiveArea())
399-
ThrowRDE("Image has zero size");
396+
if (!mRaw.get(0)->dim.hasPositiveArea())
397+
ThrowRDE("Image has zero size");
400398

401399
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
402-
// Yeah, sure, here it would be just dumb to leave this for production :)
403-
if (mRaw.get(0)->dim.x > 7424 || mRaw.get(0)->dim.y > 5552) {
404-
ThrowRDE("Unexpected image dimensions found: (%u; %u)", mRaw.get(0)->dim.x,
405-
mRaw.get(0)->dim.y);
406-
}
400+
// Yeah, sure, here it would be just dumb to leave this for production :)
401+
if (mRaw.get(0)->dim.x > 7424 || mRaw.get(0)->dim.y > 5552) {
402+
ThrowRDE("Unexpected image dimensions found: (%u; %u)",
403+
mRaw.get(0)->dim.x, mRaw.get(0)->dim.y);
404+
}
407405
#endif
408406

409-
if (mRaw.get(0)->isCFA)
410-
parseCFA(raw);
407+
if (mRaw.get(0)->isCFA)
408+
parseCFA(raw, mRaw.get(0));
411409

412-
uint32_t cpp = raw->getEntry(TiffTag::SAMPLESPERPIXEL)->getU32();
410+
uint32_t cpp = raw->getEntry(TiffTag::SAMPLESPERPIXEL)->getU32();
413411

414-
if (cpp < 1 || cpp > 4)
415-
ThrowRDE("Unsupported samples per pixel count: %u.", cpp);
412+
if (cpp < 1 || cpp > 4)
413+
ThrowRDE("Unsupported samples per pixel count: %u.", cpp);
416414

417-
mRaw.get(0)->setCpp(cpp);
415+
mRaw.get(0)->setCpp(cpp);
418416

419-
// Now load the image
420-
decodeData(raw, sample_format);
417+
// Now load the image
418+
decodeData(raw, sample_format, compression, bps, mRaw.get(0));
421419

422-
handleMetadata(raw);
420+
handleMetadata(raw, compression, bps, mRaw.get(0));
421+
}
423422
}
424423

425-
void DngDecoder::handleMetadata(const TiffIFD* raw) {
424+
void DngDecoder::handleMetadata(const TiffIFD* raw, int compression, int bps,
425+
RawImage::frame_ptr_t frame) {
426426
// Crop
427427
if (raw->hasEntry(TiffTag::ACTIVEAREA)) {
428428
const TiffEntry* active_area = raw->getEntry(TiffTag::ACTIVEAREA);
429429
if (active_area->count != 4)
430430
ThrowRDE("active area has %d values instead of 4", active_area->count);
431431

432-
const iRectangle2D fullImage(0, 0, mRaw.get(0)->dim.x, mRaw.get(0)->dim.y);
432+
const iRectangle2D fullImage(0, 0, frame->dim.x, frame->dim.y);
433433

434434
const auto corners = active_area->getU32Array(4);
435435
const iPoint2D topLeft(corners[1], corners[0]);
@@ -449,12 +449,12 @@ void DngDecoder::handleMetadata(const TiffIFD* raw) {
449449
crop.setBottomRightAbsolute(bottomRight);
450450
assert(fullImage.isThisInside(fullImage));
451451

452-
mRaw.get(0)->subFrame(crop);
452+
frame->subFrame(crop);
453453
}
454454

455455
if (raw->hasEntry(TiffTag::DEFAULTCROPORIGIN) &&
456456
raw->hasEntry(TiffTag::DEFAULTCROPSIZE)) {
457-
iRectangle2D cropped(0, 0, mRaw.get(0)->dim.x, mRaw.get(0)->dim.y);
457+
iRectangle2D cropped(0, 0, frame->dim.x, frame->dim.y);
458458
const TiffEntry* origin_entry = raw->getEntry(TiffTag::DEFAULTCROPORIGIN);
459459
const TiffEntry* size_entry = raw->getEntry(TiffTag::DEFAULTCROPSIZE);
460460

@@ -470,7 +470,7 @@ void DngDecoder::handleMetadata(const TiffIFD* raw) {
470470
cropped.isPointInsideInclusive(cropOrigin))
471471
cropped = iRectangle2D(cropOrigin, {0, 0});
472472

473-
cropped.dim = mRaw.get(0)->dim - cropped.pos;
473+
cropped.dim = frame->dim - cropped.pos;
474474

475475
/* Read size (sometimes is rational so use float) */
476476
const auto sz = size_entry->getFloatArray(2);
@@ -481,16 +481,16 @@ void DngDecoder::handleMetadata(const TiffIFD* raw) {
481481
ThrowRDE("Error decoding default crop size");
482482

483483
if (iPoint2D size(sz[0], sz[1]);
484-
size.isThisInside(mRaw.get(0)->dim) &&
485-
(size + cropped.pos).isThisInside(mRaw.get(0)->dim))
484+
size.isThisInside(frame->dim) &&
485+
(size + cropped.pos).isThisInside(frame->dim))
486486
cropped.dim = size;
487487

488488
if (!cropped.hasPositiveArea())
489489
ThrowRDE("No positive crop area");
490490

491-
mRaw.get(0)->subFrame(cropped);
491+
frame->subFrame(cropped);
492492
}
493-
if (mRaw.get(0)->dim.area() <= 0)
493+
if (frame->dim.area() <= 0)
494494
ThrowRDE("No image left after crop");
495495

496496
// Apply stage 1 opcodes
@@ -499,13 +499,13 @@ void DngDecoder::handleMetadata(const TiffIFD* raw) {
499499
const TiffEntry* opcodes = raw->getEntry(TiffTag::OPCODELIST1);
500500
// The entry might exist, but it might be empty, which means no opcodes
501501
if (opcodes->count > 0) {
502-
DngOpcodes codes(mRaw.get(0).get(), opcodes);
503-
codes.applyOpCodes(mRaw.get(0).get());
502+
DngOpcodes codes(frame.get(), opcodes);
503+
codes.applyOpCodes(frame.get());
504504
}
505505
} catch (const RawDecoderException& e) {
506506
// We push back errors from the opcode parser, since the image may still
507507
// be usable
508-
mRaw.get(0)->setError(e.what());
508+
frame->setError(e.what());
509509
}
510510
}
511511

@@ -514,23 +514,23 @@ void DngDecoder::handleMetadata(const TiffIFD* raw) {
514514
raw->getEntry(TiffTag::LINEARIZATIONTABLE)->count > 0) {
515515
const TiffEntry* lintable = raw->getEntry(TiffTag::LINEARIZATIONTABLE);
516516
auto table = lintable->getU16Array(lintable->count);
517-
RawImageCurveGuard curveHandler(mRaw.get(0).get(), table, uncorrectedRawValues);
517+
RawImageCurveGuard curveHandler(frame.get(), table, uncorrectedRawValues);
518518
if (!uncorrectedRawValues)
519-
mRaw.get(0)->sixteenBitLookup();
519+
frame->sixteenBitLookup();
520520
}
521521

522-
if (mRaw.get(0)->getDataType() == RawImageType::UINT16) {
522+
if (frame->getDataType() == RawImageType::UINT16) {
523523
// Default white level is (2 ** BitsPerSample) - 1
524-
mRaw.get(0)->whitePoint = (1UL << bps) - 1UL;
525-
} else if (mRaw.get(0)->getDataType() == RawImageType::F32) {
524+
frame->whitePoint = (1UL << bps) - 1UL;
525+
} else if (frame->getDataType() == RawImageType::F32) {
526526
// Default white level is 1.0f. But we can't represent that here.
527-
mRaw.get(0)->whitePoint = 65535;
527+
frame->whitePoint = 65535;
528528
}
529529

530530
if (raw->hasEntry(TiffTag::WHITELEVEL)) {
531531
const TiffEntry* whitelevel = raw->getEntry(TiffTag::WHITELEVEL);
532532
if (whitelevel->isInt())
533-
mRaw.get(0)->whitePoint = whitelevel->getU32();
533+
frame->whitePoint = whitelevel->getU32();
534534
}
535535
// Set black
536536
setBlack(raw);
@@ -539,22 +539,22 @@ void DngDecoder::handleMetadata(const TiffIFD* raw) {
539539
if (compression == 0x884c && !uncorrectedRawValues &&
540540
raw->hasEntry(TiffTag::OPCODELIST2)) {
541541
// We must apply black/white scaling
542-
mRaw.get(0)->scaleBlackWhite();
542+
frame->scaleBlackWhite();
543543

544544
// Apply stage 2 codes
545545
try {
546-
DngOpcodes codes(mRaw.get(0).get(), raw->getEntry(TiffTag::OPCODELIST2));
547-
codes.applyOpCodes(mRaw.get(0).get());
546+
DngOpcodes codes(frame.get(), raw->getEntry(TiffTag::OPCODELIST2));
547+
codes.applyOpCodes(frame.get());
548548
} catch (const RawDecoderException& e) {
549549
// We push back errors from the opcode parser, since the image may still
550550
// be usable
551-
mRaw.get(0)->setError(e.what());
551+
frame->setError(e.what());
552552
}
553-
mRaw.get(0)->blackAreas.clear();
554-
mRaw.get(0)->blackLevel = 0;
555-
mRaw.get(0)->blackLevelSeparate[0] = mRaw.get(0)->blackLevelSeparate[1] =
556-
mRaw.get(0)->blackLevelSeparate[2] = mRaw.get(0)->blackLevelSeparate[3] = 0;
557-
mRaw.get(0)->whitePoint = 65535;
553+
frame->blackAreas.clear();
554+
frame->blackLevel = 0;
555+
frame->blackLevelSeparate[0] = frame->blackLevelSeparate[1] =
556+
frame->blackLevelSeparate[2] = frame->blackLevelSeparate[3] = 0;
557+
frame->whitePoint = 65535;
558558
}
559559
}
560560

0 commit comments

Comments
 (0)