214 changes: 0 additions & 214 deletions data/cameras.xml

Large diffs are not rendered by default.

155 changes: 128 additions & 27 deletions src/librawspeed/decoders/Cr2Decoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "adt/Array2DRef.h"
#include "adt/Casts.h"
#include "adt/Point.h"
#include "common/Common.h"
#include "common/RawImage.h"
#include "decoders/RawDecoderException.h"
#include "decompressors/Cr2Decompressor.h"
Expand All @@ -45,6 +46,7 @@
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>

namespace rawspeed {
Expand Down Expand Up @@ -99,6 +101,7 @@
Cr2SliceWidths slicing(/*numSlices=*/1, /*sliceWidth=don't care*/ 0,
/*lastSliceWidth=*/implicit_cast<uint16_t>(width));
l.decode(slicing);
ljpegSamplePrecision = l.getSamplePrecision();

Check warning on line 104 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L104

Added line #L104 was not covered by tests

// deal with D2000 GrayResponseCurve
if (const TiffEntry* curve =
Expand Down Expand Up @@ -193,6 +196,7 @@
Cr2LJpegDecoder d(bs, mRaw);
mRaw->createData();
d.decode(slicing);
ljpegSamplePrecision = d.getSamplePrecision();

assert(getSubSampling() == mRaw->metadata.subsampling);

Expand Down Expand Up @@ -231,51 +235,51 @@
ColorData6,
ColorData7,
ColorData8,
ColorData9,
ColorData10,
};

[[nodiscard]] std::optional<ColorDataFormat>
[[nodiscard]] std::optional<std::pair<ColorDataFormat, std::optional<int>>>
deduceColorDataFormat(const TiffEntry* ccd) {
// The original ColorData, detect by it's fixed size.
if (ccd->count == 582)
return ColorDataFormat::ColorData1;
return {{ColorDataFormat::ColorData1, {}}};

Check warning on line 244 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L244

Added line #L244 was not covered by tests
// Second incarnation of ColorData, still size-only detection.
if (ccd->count == 653)
return ColorDataFormat::ColorData2;
return {{ColorDataFormat::ColorData2, {}}};

Check warning on line 247 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L247

Added line #L247 was not covered by tests
// From now onwards, Canon has finally added a `version` field, use it.
switch (int colorDataVersion = static_cast<int16_t>(ccd->getU16(0));
colorDataVersion) {
case 1:
return ColorDataFormat::ColorData3;
return {{ColorDataFormat::ColorData3, colorDataVersion}};

Check warning on line 252 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L252

Added line #L252 was not covered by tests
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 9:
return ColorDataFormat::ColorData4;
return {{ColorDataFormat::ColorData4, colorDataVersion}};
case -4:
case -3:
return ColorDataFormat::ColorData5;
case 10:
return ColorDataFormat::ColorData6;
return {{ColorDataFormat::ColorData5, colorDataVersion}};
case 10: {
ColorDataFormat f = [count = ccd->count]() {
switch (count) {
case 1273:

Check warning on line 267 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L263-L267

Added lines #L263 - L267 were not covered by tests
case 1275:
return ColorDataFormat::ColorData6;
default:
return ColorDataFormat::ColorData7;

Check warning on line 271 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L269-L271

Added lines #L269 - L271 were not covered by tests
}
}();
return {{f, colorDataVersion}};

Check warning on line 274 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L273-L274

Added lines #L273 - L274 were not covered by tests
}
case 11:
return ColorDataFormat::ColorData7;
return {{ColorDataFormat::ColorData7, colorDataVersion}};

Check warning on line 277 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L277

Added line #L277 was not covered by tests
case 12:
case 13:
case 14:
case 15:
return ColorDataFormat::ColorData8;
case 16:
case 17:
case 18:
case 19:
return ColorDataFormat::ColorData9;
case 32:
case 33:
return ColorDataFormat::ColorData10;
return {{ColorDataFormat::ColorData8, colorDataVersion}};
default:
break;
}
Expand All @@ -296,32 +300,125 @@
case ColorData8:
return 126;
case ColorData5:
case ColorData9:
return 142;
case ColorData10:
return 170;
}
__builtin_unreachable();
}

[[nodiscard]] std::optional<std::pair<int, int>>
getBlackAndWhiteLevelOffsetsInColorData(ColorDataFormat f,
int colorDataVersion) {
switch (f) {
using enum ColorDataFormat;
case ColorData1:

Check warning on line 313 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L313

Added line #L313 was not covered by tests
case ColorData2:
case ColorData3:
// These seemingly did not contain `SpecularWhiteLevel` yet.
return std::nullopt;

Check warning on line 317 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L317

Added line #L317 was not covered by tests
case ColorData4:
switch (colorDataVersion) {
case 2:
return std::nullopt; // Still no `SpecularWhiteLevel`.

Check warning on line 321 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L320-L321

Added lines #L320 - L321 were not covered by tests
case 3:
return {{231, 617}};
case 4:

Check warning on line 324 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L324

Added line #L324 was not covered by tests
case 5:
return {{692, 697}};

Check warning on line 326 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L326

Added line #L326 was not covered by tests
case 6:
case 7:
return {{715, 720}};
case 9:
return {{719, 724}};
default:
__builtin_unreachable();

Check warning on line 333 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L330-L333

Added lines #L330 - L333 were not covered by tests
}
case ColorData5:
switch (colorDataVersion) {
case -4:
return {{333, 1386}};
case -3:
return {{264, 662}};
default:
__builtin_unreachable();

Check warning on line 342 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L335-L342

Added lines #L335 - L342 were not covered by tests
}
case ColorData6:

Check warning on line 344 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L344

Added line #L344 was not covered by tests
// NOLINTNEXTLINE(hicpp-multiway-paths-covered)
switch (colorDataVersion) {
case 10:
return {{479, 484}};
default:
__builtin_unreachable();

Check warning on line 350 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L346-L350

Added lines #L346 - L350 were not covered by tests
}
case ColorData7:
switch (colorDataVersion) {
case 10:
return {{504, 509}};
case 11:
return {{728, 733}};
default:
__builtin_unreachable();

Check warning on line 359 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L352-L359

Added lines #L352 - L359 were not covered by tests
}
case ColorData8:
switch (colorDataVersion) {
case 12:
case 13:
case 15:
return {{778, 783}};
case 14:
return {{556, 561}};
default:
__builtin_unreachable();

Check warning on line 370 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L367-L370

Added lines #L367 - L370 were not covered by tests
}
}
__builtin_unreachable();

Check warning on line 373 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L373

Added line #L373 was not covered by tests
}

[[nodiscard]] bool shouldRescaleBlackLevels(ColorDataFormat f,

Check warning on line 376 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L376

Added line #L376 was not covered by tests
int colorDataVersion) {
return f != ColorDataFormat::ColorData5 || colorDataVersion != -3;

Check warning on line 378 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L378

Added line #L378 was not covered by tests
}

} // namespace

bool Cr2Decoder::decodeCanonColorData() const {
const TiffEntry* wb = mRootIFD->getEntryRecursive(TiffTag::CANONCOLORDATA);
if (!wb)
return false;

auto f = deduceColorDataFormat(wb);
if (!f)
auto dsc = deduceColorDataFormat(wb);
if (!dsc)
return false;

int offset = getWhiteBalanceOffsetInColorData(*f);
auto [f, ver] = *dsc;

int offset = getWhiteBalanceOffsetInColorData(f);

offset /= 2;
mRaw->metadata.wbCoeffs[0] = static_cast<float>(wb->getU16(offset + 0));
mRaw->metadata.wbCoeffs[1] = static_cast<float>(wb->getU16(offset + 1));
mRaw->metadata.wbCoeffs[2] = static_cast<float>(wb->getU16(offset + 3));

auto levelOffsets = getBlackAndWhiteLevelOffsetsInColorData(f, *ver);
if (!levelOffsets)
return false;

Check warning on line 403 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L403

Added line #L403 was not covered by tests

mRaw->whitePoint = wb->getU16(levelOffsets->second);
for (int c = 0; c != 4; ++c)
mRaw->blackLevelSeparate[c] = wb->getU16(c + levelOffsets->first);

// In Canon MakerNotes, the levels are always unscaled, and are 14-bit,
// and so if the LJpeg precision was lower, we need to adjust.
constexpr int makernotesPrecision = 14;
if (makernotesPrecision > ljpegSamplePrecision) {
int bitDepthDiff = makernotesPrecision - ljpegSamplePrecision;
assert(bitDepthDiff >= 1 && bitDepthDiff <= 12);

Check warning on line 414 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L413-L414

Added lines #L413 - L414 were not covered by tests
if (shouldRescaleBlackLevels(f, *ver)) {
for (int c = 0; c != 4; ++c)
mRaw->blackLevelSeparate[c] >>= bitDepthDiff;

Check warning on line 417 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L417

Added line #L417 was not covered by tests
}
mRaw->whitePoint >>= bitDepthDiff;

Check warning on line 419 in src/librawspeed/decoders/Cr2Decoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/Cr2Decoder.cpp#L419

Added line #L419 was not covered by tests
}

return true;
}

Expand Down Expand Up @@ -388,7 +485,11 @@
}
setMetaData(meta, mode, iso);
assert(mShiftUpScaleForExif == 0 || mShiftUpScaleForExif == 2);
mRaw->blackLevel <<= mShiftUpScaleForExif;
if (mShiftUpScaleForExif) {
mRaw->blackLevel = 0;
for (int c = 0; c != 4; ++c)
mRaw->blackLevelSeparate[c] = -1;
}
if (mShiftUpScaleForExif != 0 && isPowerOfTwo(1 + mRaw->whitePoint))
mRaw->whitePoint = ((1 + mRaw->whitePoint) << mShiftUpScaleForExif) - 1;
else
Expand Down
1 change: 1 addition & 0 deletions src/librawspeed/decoders/Cr2Decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class Cr2Decoder final : public AbstractTiffDecoder {
[[nodiscard]] iPoint2D getSubSampling() const;
[[nodiscard]] int getHue() const;
[[nodiscard]] bool decodeCanonColorData() const;
int ljpegSamplePrecision;
int mShiftUpScaleForExif = 0;
};

Expand Down
27 changes: 14 additions & 13 deletions src/librawspeed/decoders/RawDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,20 +250,21 @@
}
}

const CameraSensorInfo* sensor = cam->getSensorInfo(iso_speed);
mRaw->blackLevel = sensor->mBlackLevel;
mRaw->whitePoint = sensor->mWhiteLevel;
mRaw->blackAreas = cam->blackAreas;
if (mRaw->blackAreas.empty() && !sensor->mBlackLevelSeparate.empty()) {
auto cfaArea = mRaw->cfa.getSize().area();
if (mRaw->isCFA && cfaArea <= sensor->mBlackLevelSeparate.size()) {
for (auto i = 0UL; i < cfaArea; i++) {
mRaw->blackLevelSeparate[i] = sensor->mBlackLevelSeparate[i];
}
} else if (!mRaw->isCFA &&
mRaw->getCpp() <= sensor->mBlackLevelSeparate.size()) {
for (uint32_t i = 0; i < mRaw->getCpp(); i++) {
mRaw->blackLevelSeparate[i] = sensor->mBlackLevelSeparate[i];
if (const CameraSensorInfo* sensor = cam->getSensorInfo(iso_speed)) {
mRaw->blackLevel = sensor->mBlackLevel;
mRaw->whitePoint = sensor->mWhiteLevel;
if (mRaw->blackAreas.empty() && !sensor->mBlackLevelSeparate.empty()) {
auto cfaArea = mRaw->cfa.getSize().area();

Check warning on line 258 in src/librawspeed/decoders/RawDecoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/RawDecoder.cpp#L258

Added line #L258 was not covered by tests
if (mRaw->isCFA && cfaArea <= sensor->mBlackLevelSeparate.size()) {
for (auto i = 0UL; i < cfaArea; i++) {
mRaw->blackLevelSeparate[i] = sensor->mBlackLevelSeparate[i];

Check warning on line 261 in src/librawspeed/decoders/RawDecoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/RawDecoder.cpp#L261

Added line #L261 was not covered by tests
}
} else if (!mRaw->isCFA &&
mRaw->getCpp() <= sensor->mBlackLevelSeparate.size()) {

Check warning on line 264 in src/librawspeed/decoders/RawDecoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/RawDecoder.cpp#L264

Added line #L264 was not covered by tests
for (uint32_t i = 0; i < mRaw->getCpp(); i++) {
mRaw->blackLevelSeparate[i] = sensor->mBlackLevelSeparate[i];

Check warning on line 266 in src/librawspeed/decoders/RawDecoder.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/decoders/RawDecoder.cpp#L266

Added line #L266 was not covered by tests
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/librawspeed/decompressors/AbstractLJpegDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ class AbstractLJpegDecoder : public AbstractDecompressor {

public:
AbstractLJpegDecoder(ByteStream bs, RawImage img);
[[nodiscard]] int getSamplePrecision() const { return frame.prec; }

virtual ~AbstractLJpegDecoder() = default;

Expand Down
8 changes: 4 additions & 4 deletions src/librawspeed/metadata/Camera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "metadata/CameraMetadataException.h"
#include "metadata/CameraSensorInfo.h"
#include "metadata/ColorFilterArray.h"
#include <cassert>
#include <cstdint>
#include <map>
#include <string>
Expand Down Expand Up @@ -397,10 +398,8 @@
#endif

const CameraSensorInfo* Camera::getSensorInfo(int iso) const {
if (sensorInfo.empty()) {
ThrowCME("Camera '%s' '%s', mode '%s' has no <Sensor> entries.",
make.c_str(), model.c_str(), mode.c_str());
}
if (sensorInfo.empty())
return nullptr;

// If only one, just return that
if (sensorInfo.size() == 1)
Expand All @@ -411,6 +410,7 @@
if (i.isIsoWithin(iso))
candidates.push_back(&i);
}
assert(!candidates.empty());

Check warning on line 413 in src/librawspeed/metadata/Camera.cpp

View check run for this annotation

Codecov / codecov/patch

src/librawspeed/metadata/Camera.cpp#L413

Added line #L413 was not covered by tests

if (candidates.size() == 1)
return candidates.front();
Expand Down