Bigfix (see #4008) :

- CIECam now gets the shot's setting of the selected frame
- 'UserComment' metadata now correctly handled
- RT prepared to handle XTrans multiframe
- SensorType now set in the cache/data files
This commit is contained in:
Hombre57 2017-10-04 23:27:08 +02:00
parent e97c7cad2c
commit bb874bcce7
15 changed files with 161 additions and 40 deletions

View File

@ -22,6 +22,8 @@
#include "imagedata.h"
#include "iptcpairs.h"
#include "imagesource.h"
#include "rt_math.h"
#define PRINT_HDR_PS_DETECTION 0
@ -791,6 +793,39 @@ rtexif::TagDirectory* FramesData::getFrameExifData (unsigned int frame) const
return frames.empty() || frame >= frames.size() ? nullptr : frames.at(frame)->getExifData ();
}
rtexif::TagDirectory* FramesData::getBestExifData (ImageSource *imgSource, procparams::RAWParams *rawParams) const
{
rtexif::TagDirectory *td = nullptr;
if (frames.empty()) {
return nullptr;
}
if (imgSource && rawParams) {
eSensorType sensorType = imgSource->getSensorType();
unsigned int imgNum = 0;
if (sensorType == ST_BAYER) {
imgNum = rtengine::LIM<unsigned int>(rawParams->bayersensor.imageNum, 1, frames.size());
/*
// might exist someday ?
} else if (sensorType == ST_FUJI_XTRANS) {
imgNum = rtengine::LIM(rawParams->xtranssensor.imageNum, 1, frames.size());
} else if (sensorType == ST_NONE && !imgSource->isRAW()) {
// standard image multiframe support should come here (when implemented in GUI)
*/
}
frames[imgNum]->getExifData ();
td = getFrameExifData (imgNum);
rtexif::Tag* makeTag;
if (td && (makeTag = td->findTag("Make", true))) {
td = makeTag->getParent();
} else {
td = getRootExifData(0);
}
}
return td;
}
rtexif::TagDirectory* FramesData::getRootExifData (unsigned int root) const
{
return roots.empty() || root >= roots.size() ? nullptr : roots.at(root);

View File

@ -107,6 +107,7 @@ public:
IIOSampleFormat getSampleFormat (unsigned int frame = 0) const;
rtexif::TagDirectory* getFrameExifData (unsigned int frame = 0) const;
rtexif::TagDirectory* getRootExifData (unsigned int root = 0) const;
rtexif::TagDirectory* getBestExifData (ImageSource *imgSource, procparams::RAWParams *rawParams) const;
procparams::IPTCPairs getIPTCData (unsigned int frame = 0) const;
bool hasExif (unsigned int frame = 0) const;
bool hasIPTC (unsigned int frame = 0) const;

View File

@ -732,10 +732,21 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall)
CurveFactory::curveLightBrightColor (params.colorappearance.curve, params.colorappearance.curve2, params.colorappearance.curve3,
lhist16CAM, histLCAM, lhist16CCAM, histCCAM,
customColCurve1, customColCurve2, customColCurve3, 1);
float fnum = imgsrc->getMetaData()->getFNumber (); // F number
float fiso = imgsrc->getMetaData()->getISOSpeed () ; // ISO
float fspeed = imgsrc->getMetaData()->getShutterSpeed () ; // Speed
double fcomp = imgsrc->getMetaData()->getExpComp (); // Compensation +/-
const FramesMetaData* metaData = imgsrc->getMetaData();
int imgNum = 0;
if (imgsrc->isRAW()) {
if (imgsrc->getSensorType() == ST_BAYER) {
imgNum = rtengine::LIM<unsigned int>(params.raw.bayersensor.imageNum, 0, metaData->getFrameCount() - 1);
} else if (imgsrc->getSensorType() == ST_FUJI_XTRANS) {
//imgNum = rtengine::LIM<unsigned int>(params.raw.xtranssensor.imageNum, 0, metaData->getFrameCount() - 1);
}
}
float fnum = metaData->getFNumber (imgNum); // F number
float fiso = metaData->getISOSpeed (imgNum) ; // ISO
float fspeed = metaData->getShutterSpeed (imgNum) ; // Speed
double fcomp = metaData->getExpComp (imgNum); // Compensation +/-
double adap;
if (fnum < 0.3f || fiso < 5.f || fspeed < 0.00001f) { //if no exif data or wrong

View File

@ -7063,13 +7063,14 @@ double ImProcFunctions::getAutoDistor (const Glib::ustring &fname, int thumb_si
int w_raw = -1, h_raw = thumb_size;
int w_thumb = -1, h_thumb = thumb_size;
Thumbnail* thumb = rtengine::Thumbnail::loadQuickFromRaw (fname, ri, w_thumb, h_thumb, 1, FALSE);
eSensorType sensorType = rtengine::ST_NONE;
Thumbnail* thumb = rtengine::Thumbnail::loadQuickFromRaw (fname, ri, sensorType, w_thumb, h_thumb, 1, FALSE);
if (!thumb) {
return 0.0;
}
Thumbnail* raw = rtengine::Thumbnail::loadFromRaw (fname, ri, w_raw, h_raw, 1, 1.0, FALSE, 0);
Thumbnail* raw = rtengine::Thumbnail::loadFromRaw (fname, ri, sensorType, w_raw, h_raw, 1, 1.0, FALSE, 0);
if (!raw) {
delete thumb;

View File

@ -59,7 +59,8 @@ PreviewImage::PreviewImage (const Glib::ustring &fname, const Glib::ustring &ext
}
} else {
rtengine::RawMetaDataLocation ri;
tpp = rtengine::Thumbnail::loadQuickFromRaw (fname, ri, width, height, 1, true, true);
eSensorType sensorType = rtengine::ST_NONE;
tpp = rtengine::Thumbnail::loadQuickFromRaw (fname, ri, sensorType, width, height, 1, true, true);
if (tpp) {
data = tpp->getImage8Data();

View File

@ -48,7 +48,7 @@ namespace rtengine
class IImage8;
class IImage16;
class IImagefloat;
class ImageSource;
/**
* This class provides functions to obtain exif and IPTC metadata information
@ -74,6 +74,12 @@ public:
* @param frame frame number in the metadata tree
* @return The directory of exif metadata tags */
virtual rtexif::TagDirectory* getFrameExifData (unsigned int frame = 0) const = 0;
/** Returns the directory of exif metadata tags containing at least the 'Make' tag for the requested frame.
* If no usable metadata exist in the frame, send back the best TagDirectory describing the frame content.
* @param imgSource rawimage that we want the metadata from
* @param rawParams RawParams to select the frame number
* @return The directory of exif metadata tags containing at least the 'Make' tag */
virtual rtexif::TagDirectory* getBestExifData (ImageSource *imgSource, procparams::RAWParams *rawParams) const = 0;
/** Checks the availability of IPTC tags.
* @return Returns true if image contains IPTC tags */
virtual bool hasIPTC (unsigned int frame = 0) const = 0;

View File

@ -247,7 +247,7 @@ Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h,
return tpp;
}
Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, int &w, int &h, int fixwh, bool rotate, bool inspectorMode)
Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, bool rotate, bool inspectorMode)
{
RawImage *ri = new RawImage (fname);
unsigned int imageNum = 0;
@ -255,9 +255,12 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataL
if ( r ) {
delete ri;
sensorType = ST_NONE;
return nullptr;
}
sensorType = ri->getSensorType();
rml.exifBase = ri->get_exifBase();
rml.ciffBase = ri->get_ciffBase();
rml.ciffLength = ri->get_ciffLen();
@ -378,7 +381,7 @@ RawMetaDataLocation Thumbnail::loadMetaDataFromRaw (const Glib::ustring& fname)
return rml;
}
Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, int &w, int &h, int fixwh, double wbEq, bool rotate, int imageNum)
Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, double wbEq, bool rotate, int imageNum)
{
RawImage *ri = new RawImage (fname);
unsigned int tempImageNum = 0;
@ -387,9 +390,12 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocati
if ( r ) {
delete ri;
sensorType = ST_NONE;
return nullptr;
}
sensorType = ri->getSensorType();
int width = ri->get_width();
int height = ri->get_height();
rtengine::Thumbnail* tpp = new rtengine::Thumbnail;
@ -954,11 +960,15 @@ IImage8* Thumbnail::quickProcessImage (const procparams::ProcParams& params, int
}
// Full thumbnail processing, second stage if complete profile exists
IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rheight, TypeInterpolation interp, const FramesMetaData *metadata, double& myscale)
IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorType sensorType, int rheight, TypeInterpolation interp, const FramesMetaData *metadata, double& myscale)
{
int imgNum = 1;
unsigned int imgNum = 0;
if (isRaw) {
imgNum = rtengine::LIM<unsigned int>(params.raw.bayersensor.imageNum, 0, metadata->getFrameCount() - 1);
if (sensorType == ST_BAYER) {
imgNum = rtengine::LIM<unsigned int>(params.raw.bayersensor.imageNum, 0, metadata->getFrameCount() - 1);
} else if (sensorType == ST_FUJI_XTRANS) {
//imgNum = rtengine::LIM<unsigned int>(params.raw.xtranssensor.imageNum, 0, metadata->getFrameCount() - 1)
}
}
std::string camName = metadata->getCamera(imgNum);
float shutter = metadata->getShutterSpeed(imgNum);

View File

@ -71,13 +71,13 @@ public:
void init ();
IImage8* processImage (const procparams::ProcParams& pparams, int rheight, TypeInterpolation interp, const FramesMetaData *metadata, double& scale);
IImage8* processImage (const procparams::ProcParams& pparams, eSensorType sensorType, int rheight, TypeInterpolation interp, const FramesMetaData *metadata, double& scale);
IImage8* quickProcessImage (const procparams::ProcParams& pparams, int rheight, TypeInterpolation interp, double& scale);
int getImageWidth (const procparams::ProcParams& pparams, int rheight, float &ratio);
void getDimensions (int& w, int& h, double& scaleFac);
static Thumbnail* loadQuickFromRaw (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, int &w, int &h, int fixwh, bool rotate, bool inspectorMode = false);
static Thumbnail* loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, int &w, int &h, int fixwh, double wbEq, bool rotate, int imageNum);
static Thumbnail* loadQuickFromRaw (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, bool rotate, bool inspectorMode = false);
static Thumbnail* loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, double wbEq, bool rotate, int imageNum);
static Thumbnail* loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh, double wbEq, bool inspectorMode = false);
static RawMetaDataLocation loadMetaDataFromRaw (const Glib::ustring& fname);

View File

@ -1109,10 +1109,16 @@ private:
if (params.colorappearance.enabled) {
double adap;
float fnum = imgsrc->getMetaData()->getFNumber ();// F number
float fiso = imgsrc->getMetaData()->getISOSpeed () ;// ISO
float fspeed = imgsrc->getMetaData()->getShutterSpeed () ;//speed
float fcomp = imgsrc->getMetaData()->getExpComp ();//compensation + -
int imgNum = 0;
if (imgsrc->getSensorType() == ST_BAYER) {
imgNum = params.raw.bayersensor.imageNum;
} else if (imgsrc->getSensorType() == ST_FUJI_XTRANS) {
//imgNum = params.raw.xtranssensor.imageNum;
}
float fnum = imgsrc->getMetaData()->getFNumber (imgNum); // F number
float fiso = imgsrc->getMetaData()->getISOSpeed (imgNum) ; // ISO
float fspeed = imgsrc->getMetaData()->getShutterSpeed (imgNum) ; //speed
float fcomp = imgsrc->getMetaData()->getExpComp (imgNum); //compensation + -
if (fnum < 0.3f || fiso < 5.f || fspeed < 0.00001f) {
adap = 2000.;
@ -1285,9 +1291,12 @@ private:
}
if (tunnelMetaData) {
// Sending back the whole first root, which won't necessarily be the selected frame number
// and may contain subframe depending on initial raw's hierarchy
readyImg->setMetadata (ii->getMetaData()->getRootExifData ());
} else {
readyImg->setMetadata (ii->getMetaData()->getRootExifData (), params.exif, params.iptc);
// ask for the correct frame number, but may contain subframe depending on initial raw's hierarchy
readyImg->setMetadata (ii->getMetaData()->getBestExifData(imgsrc, &params.raw), params.exif, params.iptc);
}

View File

@ -28,6 +28,7 @@
#include <tiff.h>
#include <glib/gstdio.h>
#include <glib/gunicode.h>
#include "rtexif.h"
@ -707,7 +708,7 @@ int TagDirectory::write (int start, unsigned char* buffer)
return maxPos;
}
void TagDirectory::applyChange (std::string name, std::string value)
void TagDirectory::applyChange (std::string name, Glib::ustring value)
{
std::string::size_type dp = name.find_first_of ('.');
@ -741,7 +742,12 @@ void TagDirectory::applyChange (std::string name, std::string value)
if (attrib) {
Tag* nt = new Tag (this, attrib);
nt->initString (value.c_str());
if (name == "UserComment") {
// UserComment can be Unicode
nt->initUserComment (value);
} else {
nt->initString (value.c_str());
}
addTag (nt);
}
}
@ -1907,6 +1913,28 @@ void Tag::initInt (int data, TagType t, int cnt)
setInt (data, 0, t);
}
void Tag::initUserComment (const Glib::ustring &text)
{
type = UNDEFINED;
if (text.is_ascii()) {
count = 8 + strlen (text.c_str());
valuesize = count;
value = new unsigned char[valuesize];
strcpy ((char*)value, "ASCII");
value[5] = value[6] = value[7] = 0;
strcpy ((char*)value + 8, text.c_str());
} else {
wchar_t *commentStr = (wchar_t*)g_utf8_to_utf16 (text.c_str(), -1, NULL, NULL, NULL);
count = 8 + wcslen(commentStr)*2;
valuesize = count;
value = (unsigned char*)new char[valuesize];
strcpy ((char*)value, "UNICODE");
value[7] = 0;
wcscpy(((wchar_t*)value) + 4, commentStr);
g_free(commentStr);
}
}
void Tag::initString (const char* text)
{

View File

@ -171,7 +171,7 @@ public:
virtual int calculateSize ();
virtual int write (int start, unsigned char* buffer);
virtual TagDirectory* clone (TagDirectory* parent);
virtual void applyChange (std::string field, std::string value);
virtual void applyChange (std::string field, Glib::ustring value);
virtual void printAll (unsigned int level = 0) const; // reentrant debug function, keep level=0 on first call !
virtual bool CPBDump (const Glib::ustring &commFName, const Glib::ustring &imageFName, const Glib::ustring &profileFName, const Glib::ustring &defaultPParams,
@ -225,15 +225,16 @@ public:
Tag (TagDirectory* parent, const TagAttrib* attr, const char* data); // create a new tag from array (used
~Tag ();
void initType (unsigned char *data, TagType type);
void initInt (int data, TagType t, int count = 1);
void initString (const char* text);
void initSubDir ();
void initSubDir (TagDirectory* dir);
void initMakerNote (MNKind mnk, const TagAttrib* ta);
void initUndefArray (const char* data, int len);
void initLongArray (const char* data, int len);
void initRational (int num, int den);
void initType (unsigned char *data, TagType type);
void initInt (int data, TagType t, int count = 1);
void initUserComment (const Glib::ustring &text);
void initString (const char* text);
void initSubDir ();
void initSubDir (TagDirectory* dir);
void initMakerNote (MNKind mnk, const TagAttrib* ta);
void initUndefArray (const char* data, int len);
void initLongArray (const char* data, int len);
void initRational (int num, int den);
// get basic tag properties
int getID () const

View File

@ -25,8 +25,9 @@
CacheImageData::CacheImageData ()
: md5(""), supported(false), format(FT_Invalid), rankOld(-1), inTrashOld(false), recentlySaved(false),
timeValid(false), year(0), month(0), day(0), hour(0), min(0), sec(0), exifValid(false), frameCount(1),
fnumber(0.0), shutter(0.0), focalLen(0.0), focalLen35mm(0.0), focusDist(0.f), iso(0), isHDR (false), isPixelShift (false),
sampleFormat(rtengine::IIOSF_UNKNOWN), redAWBMul(-1.0), greenAWBMul(-1.0), blueAWBMul(-1.0), rotate(0), thumbImgType(0)
fnumber(0.0), shutter(0.0), focalLen(0.0), focalLen35mm(0.0), focusDist(0.f), iso(0), isHDR (false),
isPixelShift (false), sensortype(rtengine::ST_NONE), sampleFormat(rtengine::IIOSF_UNKNOWN),
redAWBMul(-1.0), greenAWBMul(-1.0), blueAWBMul(-1.0), rotate(0), thumbImgType(0)
{
}
@ -180,6 +181,9 @@ int CacheImageData::load (const Glib::ustring& fname)
if (keyFile.has_key ("ExtraRawInfo", "ThumbImageType")) {
thumbImgType = keyFile.get_integer ("ExtraRawInfo", "ThumbImageType");
}
if (keyFile.has_key ("ExtraRawInfo", "SensorType")) {
sensortype = keyFile.get_integer ("ExtraRawInfo", "SensorType");
}
} else {
rotate = 0;
thumbImgType = 0;
@ -263,6 +267,7 @@ int CacheImageData::save (const Glib::ustring& fname)
if (format == FT_Raw) {
keyFile.set_integer ("ExtraRawInfo", "ThumbImageType", thumbImgType);
keyFile.set_integer ("ExtraRawInfo", "SensorType", sensortype);
}
keyData = keyFile.to_data ();

View File

@ -56,6 +56,7 @@ public:
unsigned iso;
bool isHDR;
bool isPixelShift;
int sensortype;
rtengine::IIO_Sample_Format sampleFormat;
Glib::ustring lens;
Glib::ustring camMake;
@ -91,6 +92,7 @@ public:
bool hasExif (unsigned int frame = 0) const { return false; }
rtexif::TagDirectory* getRootExifData (unsigned int root = 0) const { return nullptr; }
rtexif::TagDirectory* getFrameExifData (unsigned int frame = 0) const { return nullptr; }
rtexif::TagDirectory* getBestExifData (rtengine::ImageSource *imgSource, rtengine::procparams::RAWParams *rawParams) const { return nullptr; }
bool hasIPTC (unsigned int frame = 0) const { return false; }
rtengine::procparams::IPTCPairs getIPTCData (unsigned int frame = 0) const { return rtengine::procparams::IPTCPairs(); }
tm getDateTime (unsigned int frame = 0) const { return tm{}; }

View File

@ -1143,7 +1143,16 @@ void EditorPanel::procParamsChanged (rtengine::procparams::ProcParams* params, r
// if (ev!=EvPhotoLoaded)
// saveLabel->set_markup (Glib::ustring("<span foreground=\"#AA0000\" weight=\"bold\">") + M("MAIN_BUTTON_SAVE") + "</span>");
selectedFrame = params->raw.bayersensor.imageNum;
rtengine::eSensorType sensorType = isrc->getImageSource()->getSensorType();
selectedFrame = 0;
if (sensorType == rtengine::ST_BAYER) {
selectedFrame = params->raw.bayersensor.imageNum;
//} else if (sensorType == rtengine::ST_FUJI_XTRANS) {
// selectedFrame = params->raw.xtranssensor.imageNum;
}
selectedFrame = rtengine::LIM<int>(selectedFrame, 0, isrc->getImageSource()->getMetaData()->getFrameCount() - 1);
info_toggled();
}

View File

@ -132,16 +132,18 @@ void Thumbnail::_generateThumbnailImage ()
bool quick = false;
rtengine::RawMetaDataLocation ri;
rtengine::eSensorType sensorType = rtengine::ST_NONE;
if ( initial_ && options.internalThumbIfUntouched) {
quick = true;
tpp = rtengine::Thumbnail::loadQuickFromRaw (fname, ri, tw, th, 1, TRUE);
tpp = rtengine::Thumbnail::loadQuickFromRaw (fname, ri, sensorType, tw, th, 1, TRUE);
}
if ( tpp == nullptr ) {
quick = false;
tpp = rtengine::Thumbnail::loadFromRaw (fname, ri, tw, th, 1, pparams.wb.equal, TRUE, pparams.raw.bayersensor.imageNum);
tpp = rtengine::Thumbnail::loadFromRaw (fname, ri, sensorType, tw, th, 1, pparams.wb.equal, TRUE, pparams.raw.bayersensor.imageNum);
}
cfs.sensortype = sensorType;
if (tpp) {
cfs.format = FT_Raw;
cfs.thumbImgType = quick ? CacheImageData::QUICK_THUMBNAIL : CacheImageData::FULL_THUMBNAIL;
@ -614,7 +616,7 @@ rtengine::IImage8* Thumbnail::processThumbImage (const rtengine::procparams::Pro
} else {
// Full thumbnail: apply profile
// image = tpp->processImage (pparams, h, rtengine::TI_Bilinear, cfs.getCamera(), cfs.focalLen, cfs.focalLen35mm, cfs.focusDist, cfs.shutter, cfs.fnumber, cfs.iso, cfs.expcomp, scale );
image = tpp->processImage (pparams, h, rtengine::TI_Bilinear, &cfs, scale );
image = tpp->processImage (pparams, static_cast<rtengine::eSensorType>(cfs.sensortype), h, rtengine::TI_Bilinear, &cfs, scale );
}
tpp->getDimensions(lastW, lastH, lastScale);
@ -640,7 +642,7 @@ rtengine::IImage8* Thumbnail::upgradeThumbImage (const rtengine::procparams::Pro
}
// rtengine::IImage8* image = tpp->processImage (pparams, h, rtengine::TI_Bilinear, cfs.getCamera(), cfs.focalLen, cfs.focalLen35mm, cfs.focusDist, cfs.shutter, cfs.fnumber, cfs.iso, cfs.expcomp, scale );
rtengine::IImage8* image = tpp->processImage (pparams, h, rtengine::TI_Bilinear, &cfs, scale );
rtengine::IImage8* image = tpp->processImage (pparams, static_cast<rtengine::eSensorType>(cfs.sensortype), h, rtengine::TI_Bilinear, &cfs, scale );
tpp->getDimensions(lastW, lastH, lastScale);
delete tpp;