Implement DNG bad pixels constant for LibRaw

Works if the FixBadPixelsConstant is zero, as implemented for dcraw.
Other constant values may be implemented in the future.
This commit is contained in:
Lawrence Lee 2024-01-01 17:55:05 -08:00
parent d96809ecab
commit d13badbbe0
No known key found for this signature in database
GPG Key ID: 048FF2B76A63895F
7 changed files with 60 additions and 32 deletions

View File

@ -6935,28 +6935,6 @@ it under the terms of the one of two licenses as you choose:
((int *)mask)[i] = getint(type);
black = 0;
break;
case 51008: /* OpcodeList1 */
{
unsigned oldOrder = order;
order = 0x4d4d; // always big endian per definition in https://www.adobe.com/content/dam/acom/en/products/photoshop/pdfs/dng_spec_1.4.0.0.pdf chapter 7
unsigned ntags = get4(); // read the number of opcodes
if (ntags < ifp->size / 12) { // rough check for wrong value (happens for example with DNG files from DJI FC6310)
while (ntags-- && !ifp->eof) {
unsigned opcode = get4();
fseek (ifp, 8, SEEK_CUR); // skip 8 bytes as they don't interest us currently
if (opcode == 4) { // FixBadPixelsConstant
fseek (ifp, 4, SEEK_CUR); // skip 4 bytes as we know that the opcode 4 takes 4 byte
if(get4() == 0) { // if raw 0 values should be treated as bad pixels, set zero_is_bad to true (1). That's the only value currently supported by rt
zero_is_bad = 1;
}
} else {
fseek (ifp, get4(), SEEK_CUR);
}
}
}
order = oldOrder;
break;
}
case 51009: /* OpcodeList2 */
meta_offset = ftell(ifp);
break;

View File

@ -168,10 +168,15 @@ public:
}
};
std::uint32_t readFixBadPixelsConstant(TagValueReader &reader)
{
reader.seekRelative(12); // Skip DNG spec version, flags, and tag size.
return reader.readUInt();
}
GainMap readGainMap(TagValueReader &reader)
{
reader.seekRelative(4); // skip 4 bytes as we know that the opcode 4 takes 4 byte
reader.seekRelative(8); // skip 8 bytes as they don't interest us currently
reader.seekRelative(12); // Skip DNG spec version, flags, and tag size.
GainMap gainMap;
gainMap.Top = reader.readUInt();
gainMap.Left = reader.readUInt();
@ -196,7 +201,11 @@ GainMap readGainMap(TagValueReader &reader)
return gainMap;
}
void readOpcodesList(const Exiv2::Value &value, std::vector<GainMap> &gainMaps)
void readOpcodesList(
const Exiv2::Value &value,
std::uint32_t *fixBadPixelsConstant,
bool *hasFixBadPixelsConstant,
std::vector<GainMap> *gainMaps)
{
TagValueReader reader(value);
std::uint32_t ntags = reader.readUInt(); // read the number of opcodes
@ -205,8 +214,16 @@ void readOpcodesList(const Exiv2::Value &value, std::vector<GainMap> &gainMaps)
}
while (ntags-- && !reader.isEnd()) {
unsigned opcode = reader.readUInt();
if (opcode == 9 && gainMaps.size() < 4) {
gainMaps.push_back(readGainMap(reader));
if (opcode == 4 && (fixBadPixelsConstant || hasFixBadPixelsConstant)) {
const auto constant = readFixBadPixelsConstant(reader);
if (fixBadPixelsConstant) {
*fixBadPixelsConstant = constant;
}
if (hasFixBadPixelsConstant) {
*hasFixBadPixelsConstant = true;
}
} else if (opcode == 9 && gainMaps && gainMaps->size() < 4) {
gainMaps->push_back(readGainMap(reader));
} else {
reader.seekRelative(8); // skip 8 bytes as they don't interest us currently
reader.seekRelative(reader.readUInt());
@ -826,16 +843,20 @@ FramesData::FramesData(const Glib::ustring &fname, time_t ts) :
}
}
uint32_t dngVersion = 0;
std::uint32_t dngVersion = 0;
if (find_exif_tag("Exif.Image.DNGVersion") && pos->count() == 4) {
for (int i = 0; i < 4; i++) {
dngVersion = (dngVersion << 8) + static_cast<uint32_t>(to_long(pos, i));
dngVersion = (dngVersion << 8) + static_cast<std::uint32_t>(to_long(pos, i));
}
}
// Read gain maps.
// Read DNG OpcodeList1.
if (dngVersion && (find_exif_tag("Exif.SubImage1.OpcodeList1") || find_exif_tag("Exif.Image.OpcodeList1"))) {
readOpcodesList(pos->value(), &fixBadPixelsConstant, &hasFixBadPixelsConstant_, nullptr);
}
// Read DNG OpcodeList2.
if (dngVersion && (find_exif_tag("Exif.SubImage1.OpcodeList2") || find_exif_tag("Exif.Image.OpcodeList2"))) {
readOpcodesList(pos->value(), gain_maps_);
readOpcodesList(pos->value(), nullptr, nullptr, &gain_maps_);
}
} catch (const std::exception& e) {
if (settings->verbose) {
@ -1078,6 +1099,16 @@ void FramesData::fillBasicTags(Exiv2::ExifData &exif) const
set_exif(exif, "Exif.Photo.DateTimeOriginal", buf);
}
std::uint32_t FramesData::getFixBadPixelsConstant() const
{
return fixBadPixelsConstant;
}
bool FramesData::hasFixBadPixelsConstant() const
{
return hasFixBadPixelsConstant_;
}
std::vector<GainMap> FramesData::getGainMaps() const
{
return gain_maps_;

View File

@ -60,6 +60,8 @@ private:
time_t modTimeStamp;
bool isPixelShift;
bool isHDR;
std::uint32_t fixBadPixelsConstant;
bool hasFixBadPixelsConstant_{false};
std::vector<GainMap> gain_maps_;
int w_;
int h_;
@ -90,6 +92,8 @@ public:
std::string getOrientation() const override;
Glib::ustring getFileName() const override;
int getRating() const override;
std::uint32_t getFixBadPixelsConstant() const override;
bool hasFixBadPixelsConstant() const override;
std::vector<GainMap> getGainMaps() const override;
void getDimensions(int &w, int &h) const override;

View File

@ -1439,7 +1439,7 @@ void RawImageSource::preprocess(const RAWParams &raw, const LensProfParams &lens
int totBP = 0; // Hold count of bad pixels to correct
if (ri->zeroIsBad()) { // mark all pixels with value zero as bad, has to be called before FF and DF. dcraw sets this flag only for some cameras (mainly Panasonic and Leica)
if (ri->zeroIsBad() || (getMetaData()->hasFixBadPixelsConstant() && getMetaData()->getFixBadPixelsConstant() == 0)) { // mark all pixels with value zero as bad, has to be called before FF and DF. dcraw sets this flag only for some cameras (mainly Panasonic and Leica)
bitmapBads.reset(new PixelsMap(W, H));
totBP = findZeroPixels(*bitmapBads);

View File

@ -20,6 +20,7 @@
#pragma once
#include <array>
#include <cstdint>
#include <ctime>
#include <string>
#include <memory>
@ -159,6 +160,8 @@ public:
static FramesMetaData* fromFile(const Glib::ustring& fname);
virtual Glib::ustring getFileName() const = 0;
virtual std::uint32_t getFixBadPixelsConstant() const = 0;
virtual bool hasFixBadPixelsConstant() const = 0;
virtual std::vector<GainMap> getGainMaps() const = 0;
virtual void getDimensions(int &w, int &h) const = 0;
};

View File

@ -362,6 +362,16 @@ int CacheImageData::save (const Glib::ustring& fname)
}
}
std::uint32_t CacheImageData::getFixBadPixelsConstant() const
{
return 0;
}
bool CacheImageData::hasFixBadPixelsConstant() const
{
return false;
}
std::vector<GainMap> CacheImageData::getGainMaps() const
{
return std::vector<GainMap>();

View File

@ -117,6 +117,8 @@ public:
bool getHDR() const override { return isHDR; }
std::string getImageType() const override { return isPixelShift ? "PS" : isHDR ? "HDR" : "STD"; }
rtengine::IIOSampleFormat getSampleFormat() const override { return sampleFormat; }
std::uint32_t getFixBadPixelsConstant() const override;
bool hasFixBadPixelsConstant() const override;
std::vector<GainMap> getGainMaps() const override;
void getDimensions(int &w, int &h) const override
{