diff --git a/rtdata/languages/Francais b/rtdata/languages/Francais index 65cf503eb..34a9a75a2 100644 --- a/rtdata/languages/Francais +++ b/rtdata/languages/Francais @@ -1155,8 +1155,16 @@ PROGRESSBAR_SAVEPNG;Enregistrement du fichier PNG... PROGRESSBAR_SAVETIFF;Enregistrement du fichier TIFF... PROGRESSBAR_SNAPSHOT_ADDED;Signet ajouté PROGRESSDLG_PROFILECHANGEDINBROWSER;Profil modifié dans le navigateur +QINFO_HDR;HDR / %1 image(s) QINFO_ISO;ISO QINFO_NOEXIF;Données EXIF non disponibles. +QINFO_PIXELSHIFT;PixelShift / %1 images +SAMPLEFORMAT_0;Format de donnée inconnu +SAMPLEFORMAT_1;8 bits non signé +SAMPLEFORMAT_2;16 bits non signé +SAMPLEFORMAT_4;LogLuv 24 bits +SAMPLEFORMAT_8;LogLuv 32 bits +SAMPLEFORMAT_16;32 bits à virgule flottante SAVEDLG_AUTOSUFFIX;Ajouter automatiquement un suffixe si le fichier existe déjà SAVEDLG_FILEFORMAT;Format de fichier SAVEDLG_FORCEFORMATOPTS;Forcer les options d'enregistrement diff --git a/rtdata/languages/default b/rtdata/languages/default index 5f1b4666c..f8d54154c 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1157,8 +1157,16 @@ PROGRESSBAR_SAVEPNG;Saving PNG file... PROGRESSBAR_SAVETIFF;Saving TIFF file... PROGRESSBAR_SNAPSHOT_ADDED;Snapshot added PROGRESSDLG_PROFILECHANGEDINBROWSER;Processing profile changed in browser +QINFO_HDR;HDR / %1 frame(s) QINFO_ISO;ISO QINFO_NOEXIF;Exif data not available. +QINFO_PIXELSHIFT;PixelShift / %1 frame(s) +SAMPLEFORMAT_0;Unknown data format +SAMPLEFORMAT_1;Unsigned 8 bits +SAMPLEFORMAT_2;Unsigned 16 bits +SAMPLEFORMAT_4;LogLuv 24 bits +SAMPLEFORMAT_8;LogLuv 32 bits +SAMPLEFORMAT_16;32 bits floating point SAVEDLG_AUTOSUFFIX;Automatically add a suffix if the file already exists SAVEDLG_FILEFORMAT;File format SAVEDLG_FORCEFORMATOPTS;Force saving options diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index 43aa98480..ee0cf3462 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -696,7 +696,8 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : return; } - std::unique_ptr tagDir(ExifManager::parseTIFF(file, false)); + ExifManager exifManager(file, nullptr, true); + std::unique_ptr tagDir(exifManager.parseTIFF(false)); Tag* tag = tagDir->getTag(toUnderlying(TagKey::CALIBRATION_ILLUMINANT_1)); light_source_1 = diff --git a/rtengine/dfmanager.cc b/rtengine/dfmanager.cc index bc35b3c71..68123d9b4 100644 --- a/rtengine/dfmanager.cc +++ b/rtengine/dfmanager.cc @@ -382,11 +382,8 @@ dfInfo* DFManager::addFileInfo (const Glib::ustring& filename, bool pool) return &(iter->second); } - RawMetaDataLocation rml; - rml.exifBase = ri.get_exifBase(); - rml.ciffBase = ri.get_ciffBase(); - rml.ciffLength = ri.get_ciffLen(); - ImageData idata(filename, &rml); + RawMetaDataLocation rml(ri.get_exifBase(), ri.get_ciffBase(), ri.get_ciffLen()); + FramesData idata(filename, &rml, true); /* Files are added in the map, divided by same maker/model,ISO and shutter*/ std::string key( dfInfo::key(((Glib::ustring)idata.getMake()).uppercase(), ((Glib::ustring)idata.getModel()).uppercase(), idata.getISOSpeed(), idata.getShutterSpeed()) ); iter = dfList.find( key ); diff --git a/rtengine/dynamicprofile.cc b/rtengine/dynamicprofile.cc index 5ac408da5..1afc04446 100644 --- a/rtengine/dynamicprofile.cc +++ b/rtengine/dynamicprofile.cc @@ -72,7 +72,7 @@ bool DynamicProfileRule::operator< (const DynamicProfileRule &other) const } -bool DynamicProfileRule::matches (const rtengine::ImageMetaData *im) const +bool DynamicProfileRule::matches (const rtengine::FramesMetaData *im) const { return (iso (im->getISOSpeed()) && fnumber (im->getFNumber()) diff --git a/rtengine/dynamicprofile.h b/rtengine/dynamicprofile.h index cfe46d9ba..4e6bbbba9 100644 --- a/rtengine/dynamicprofile.h +++ b/rtengine/dynamicprofile.h @@ -48,7 +48,7 @@ public: }; DynamicProfileRule(); - bool matches (const rtengine::ImageMetaData *im) const; + bool matches (const rtengine::FramesMetaData *im) const; bool operator< (const DynamicProfileRule &other) const; int serial_number; diff --git a/rtengine/ffmanager.cc b/rtengine/ffmanager.cc index 87ae98905..6acdc1b0a 100644 --- a/rtengine/ffmanager.cc +++ b/rtengine/ffmanager.cc @@ -338,11 +338,8 @@ ffInfo* FFManager::addFileInfo (const Glib::ustring& filename, bool pool) return &(iter->second); } - RawMetaDataLocation rml; - rml.exifBase = ri.get_exifBase(); - rml.ciffBase = ri.get_ciffBase(); - rml.ciffLength = ri.get_ciffLen(); - ImageData idata(filename, &rml); + RawMetaDataLocation rml(ri.get_exifBase(), ri.get_ciffBase(), ri.get_ciffLen()); + FramesData idata(filename, &rml, true); /* Files are added in the map, divided by same maker/model,lens and aperture*/ std::string key( ffInfo::key(idata.getMake(), idata.getModel(), idata.getLens(), idata.getFocalLen(), idata.getFNumber()) ); iter = ffList.find( key ); diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 5faa6175e..289fc4a25 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -18,6 +18,7 @@ */ #include #include +#include #include "imagedata.h" #include "iptcpairs.h" @@ -40,57 +41,25 @@ Glib::ustring to_utf8 (const std::string& str) } -ImageMetaData* ImageMetaData::fromFile (const Glib::ustring& fname, RawMetaDataLocation* rml) +FramesMetaData* FramesMetaData::fromFile (const Glib::ustring& fname, RawMetaDataLocation* rml, bool firstFrameOnly) { - - return new ImageData (fname, rml); + return new FramesData (fname, rml, firstFrameOnly); } -ImageData::ImageData (Glib::ustring fname, RawMetaDataLocation* ri) : iso_speed(0), aperture(0.), shutter(0.) +FrameData::FrameData () + : root(nullptr), iptc(nullptr), time(), timeStamp(), iso_speed(0), aperture(0.), focal_len(0.), focal_len35mm(0.), focus_dist(0.f), + shutter(0.), expcomp(0.), make("Unknown"), model("Unknown"), orientation("Unknown"), lens("Unknown"), + sampleFormat(IIOSF_UNKNOWN), isPixelShift(false), isHDR(false) { memset (&time, 0, sizeof(time)); - root = nullptr; - iptc = nullptr; +} - if (ri && (ri->exifBase >= 0 || ri->ciffBase >= 0)) { - FILE* f = g_fopen (fname.c_str (), "rb"); - - if (f) { - if (ri->exifBase >= 0) { - root = rtexif::ExifManager::parse (f, ri->exifBase); - - if (root) { - rtexif::Tag* t = root->getTag (0x83BB); - - if (t) { - iptc = iptc_data_new_from_data ((unsigned char*)t->getValue (), (unsigned)t->getValueSize ()); - } - } - } else if (ri->ciffBase >= 0) { - root = rtexif::ExifManager::parseCIFF (f, ri->ciffBase, ri->ciffLength); - } - - fclose (f); - extractInfo (); - } - } else if (hasJpegExtension(fname)) { - FILE* f = g_fopen (fname.c_str (), "rb"); - - if (f) { - root = rtexif::ExifManager::parseJPEG (f); - extractInfo (); - fclose (f); - FILE* ff = g_fopen (fname.c_str (), "rb"); - iptc = iptc_data_new_from_jpeg_file (ff); - fclose (ff); - } - } else if (hasTiffExtension(fname)) { - FILE* f = g_fopen (fname.c_str (), "rb"); - - if (f) { - root = rtexif::ExifManager::parseTIFF (f); - fclose (f); - extractInfo (); +RawFrameData::RawFrameData (rtexif::ExifManager &exifManager) +{ + bool rootCreated = false; + if (exifManager.f && exifManager.rml) { + if (exifManager.rml->exifBase >= 0) { + root = exifManager.parse (); if (root) { rtexif::Tag* t = root->getTag (0x83BB); @@ -98,23 +67,59 @@ ImageData::ImageData (Glib::ustring fname, RawMetaDataLocation* ri) : iso_speed( if (t) { iptc = iptc_data_new_from_data ((unsigned char*)t->getValue (), (unsigned)t->getValueSize ()); } + extractInfo (); + rootCreated = true; } + } else if (exifManager.rml->ciffBase >= 0) { + root = exifManager.parseCIFF (); + extractInfo (); + rootCreated = true; } - } else { + } + if (!rootCreated) { root = new rtexif::TagDirectory (); - shutter = 0; - aperture = 0; - iso_speed = 0; - lens = "Unknown"; - make = "Unknown"; - model = "Unknown"; - orientation = "Unknown"; - expcomp = 0; - focal_len = 0; } } -void ImageData::extractInfo () +JpegFrameData::JpegFrameData (rtexif::ExifManager &exifManager) +{ + bool rootCreated = false; + if (exifManager.f) { + root = exifManager.parseJPEG (); + if (root) { + extractInfo (); + rootCreated = true; + } + rewind (exifManager.f); // Not sure this is necessary + iptc = iptc_data_new_from_jpeg_file (exifManager.f); + } + if (!rootCreated) { + root = new rtexif::TagDirectory (); + } +} + +TiffFrameData::TiffFrameData (rtexif::ExifManager &exifManager) +{ + bool rootCreated = false; + if (exifManager.f) { + root = exifManager.parseTIFF (); + extractInfo (); + + if (root) { + rtexif::Tag* t = root->getTag (0x83BB); + + if (t) { + iptc = iptc_data_new_from_data ((unsigned char*)t->getValue (), (unsigned)t->getValueSize ()); + } + rootCreated = true; + } + } + if (!rootCreated) { + root = new rtexif::TagDirectory (); + } +} + +void FrameData::extractInfo () { if (!root) { @@ -206,8 +211,13 @@ void ImageData::extractInfo () orientation = root->getTag ("Orientation")->valueToString (); } - rtexif::TagDirectory* exif = nullptr; + rtexif::Tag* mnoteTag = root->findTag("MakerNote"); + rtexif::TagDirectory* mnote = nullptr; + if (mnoteTag) { + mnote = mnoteTag->getDirectory(); + } + rtexif::TagDirectory* exif = nullptr; if (root->getTag ("Exif")) { exif = root->getTag ("Exif")->getDirectory (); } @@ -313,12 +323,10 @@ void ImageData::extractInfo () } if (lens == "Unknown") { - rtexif::Tag* mnoteTag = root->findTag("MakerNote"); - if (mnoteTag) { - rtexif::TagDirectory* mnote = mnoteTag->getDirectory(); + if (mnote) { - if (mnote && !make.compare (0, 5, "NIKON")) { + if (!make.compare (0, 5, "NIKON")) { // ISO at max value supported, check manufacturer specific if (iso_speed == 65535 || iso_speed == 0) { rtexif::Tag* isoTag = mnote->getTagP("ISOInfo/ISO"); @@ -406,7 +414,7 @@ void ImageData::extractInfo () } } } - } else if (mnote && !make.compare (0, 5, "Canon")) { + } else if (!make.compare (0, 5, "Canon")) { // ISO at max value supported, check manufacturer specific if (iso_speed == 65535 || iso_speed == 0) { rtexif::Tag* baseIsoTag = mnote->getTagP("CanonShotInfo/BaseISO"); @@ -440,7 +448,7 @@ void ImageData::extractInfo () } } } - } else if (mnote && (!make.compare (0, 6, "PENTAX") || (!make.compare (0, 5, "RICOH") && !model.compare (0, 6, "PENTAX")))) { + } else if (!make.compare (0, 6, "PENTAX") || (!make.compare (0, 5, "RICOH") && !model.compare (0, 6, "PENTAX"))) { // ISO at max value supported, check manufacturer specific if (iso_speed == 65535 || iso_speed == 0) { rtexif::Tag* baseIsoTag = mnote->getTag("ISO"); @@ -475,7 +483,7 @@ void ImageData::extractInfo () if (mnote->getTag ("LensID")) { lens = mnote->getTag ("LensID")->valueToString (); } - } else if (mnote && !make.compare (0, 7, "OLYMPUS")) { + } else if (!make.compare (0, 7, "OLYMPUS")) { if (mnote->getTag ("Equipment")) { rtexif::TagDirectory* eq = mnote->getTag ("Equipment")->getDirectory (); @@ -504,9 +512,111 @@ void ImageData::extractInfo () } } } + + + // ----------------------- Special file type detection (HDR, PixelShift) ------------------------ + + + uint16 bitspersample = 0, samplesperpixel = 0, sampleformat = 0, photometric = 0, compression = 0; + rtexif::Tag* bps = root->findTag("BitsPerSample"); + rtexif::Tag* spp = root->findTag("SamplesPerPixel"); + rtexif::Tag* sf = root->findTag("SampleFormat"); + rtexif::Tag* pi = root->findTag("PhotometricInterpretation"); + rtexif::Tag* c = root->findTag("Compression"); + + if (mnote && (!make.compare (0, 6, "PENTAX") || (!make.compare (0, 5, "RICOH") && !model.compare (0, 6, "PENTAX")))) { + rtexif::Tag* hdr = mnote->findTag("HDR"); + if (hdr) { + if (hdr->toInt() > 0 && hdr->toInt(2) > 0) { + isHDR = true; + } + } else { + rtexif::Tag* dm = mnote->findTag("DriveMode"); + if (dm) { + char buffer[60]; + dm->toString(buffer, 3); + buffer[3] = 0; + if (!strcmp(buffer, "HDR")) { + isHDR = true; + } + } + } + + if (!isHDR) { + rtexif::Tag* q = mnote->findTag("Quality"); + if (q && q->toInt() == 7) { + isPixelShift = true; + } + } + } + + sampleFormat = IIOSF_UNKNOWN; + + if (!sf) + /* + * WARNING: This is a dirty hack! + * We assume that files which doesn't contain the TIFFTAG_SAMPLEFORMAT tag + * (which is the case with uncompressed TIFFs produced by RT!) are RGB files, + * but that may be not true. --- Hombre + */ + { + sampleformat = SAMPLEFORMAT_UINT; + } else { + sampleformat = sf->toInt(); + } + + if ((!bps & !spp) || !pi) { + return; + } + + samplesperpixel = spp->toInt(); + bitspersample = bps->toInt(); + + photometric = pi->toInt(); + if (photometric == PHOTOMETRIC_LOGLUV) { + if (!c) { + compression = COMPRESSION_NONE; + } else { + compression = c->toInt(); + } + } + + if (photometric == PHOTOMETRIC_RGB || photometric == PHOTOMETRIC_MINISBLACK) { + if ((samplesperpixel == 1 || samplesperpixel == 3 || samplesperpixel == 4) && sampleformat == SAMPLEFORMAT_UINT) { + if (bitspersample == 8) { + sampleFormat = IIOSF_UNSIGNED_CHAR; + } + + if (bitspersample == 16) { + sampleFormat = IIOSF_UNSIGNED_SHORT; + } + } else if (samplesperpixel == 3 && sampleformat == SAMPLEFORMAT_IEEEFP) { + /* + * Not yet supported + * + if (bitspersample==16) { + sampleFormat = IIOSF_HALF; + }*/ + if ((samplesperpixel == 3 || samplesperpixel == 4) && bitspersample == 32) { + sampleFormat = IIOSF_FLOAT; + isHDR = true; + } + } + } else if (photometric == PHOTOMETRIC_CFA) { + // Assuming Bayer or X-Trans raw file deliver 10, 12 14 or 16 bits uint, which is the case as of now + sampleFormat = IIOSF_UNSIGNED_SHORT; + } else if (samplesperpixel == 3 && photometric == PHOTOMETRIC_LOGLUV) { + if (compression == COMPRESSION_SGILOG24) { + sampleFormat = IIOSF_LOGLUV24; + isHDR = true; + } else if (compression == COMPRESSION_SGILOG) { + sampleFormat = IIOSF_LOGLUV32; + isHDR = true; + } + } } -ImageData::~ImageData () +FrameData::~FrameData () { delete root; @@ -516,7 +626,7 @@ ImageData::~ImageData () } } -const procparams::IPTCPairs ImageData::getIPTCData () const +const procparams::IPTCPairs FrameData::getIPTCData () const { procparams::IPTCPairs iptcc; @@ -565,7 +675,7 @@ const procparams::IPTCPairs ImageData::getIPTCData () const //------inherited functions--------------// -std::string ImageMetaData::apertureToString (double aperture) +std::string FramesMetaData::apertureToString (double aperture) { char buffer[256]; @@ -573,7 +683,7 @@ std::string ImageMetaData::apertureToString (double aperture) return buffer; } -std::string ImageMetaData::shutterToString (double shutter) +std::string FramesMetaData::shutterToString (double shutter) { char buffer[256]; @@ -587,7 +697,7 @@ std::string ImageMetaData::shutterToString (double shutter) return buffer; } -std::string ImageMetaData::expcompToString (double expcomp, bool maskZeroexpcomp) +std::string FramesMetaData::expcompToString (double expcomp, bool maskZeroexpcomp) { char buffer[256]; @@ -605,7 +715,7 @@ std::string ImageMetaData::expcompToString (double expcomp, bool maskZeroexpcomp } } -double ImageMetaData::shutterFromString (std::string s) +double FramesMetaData::shutterFromString (std::string s) { size_t i = s.find_first_of ('/'); @@ -617,7 +727,7 @@ double ImageMetaData::shutterFromString (std::string s) } } -double ImageMetaData::apertureFromString (std::string s) +double FramesMetaData::apertureFromString (std::string s) { return atof (s.c_str()); @@ -685,3 +795,60 @@ failure: } } + +FramesData::FramesData (Glib::ustring fname, RawMetaDataLocation* rml, bool firstFrameOnly, bool loadAll) : dcrawFrameCount (0) +{ + if (rml && (rml->exifBase >= 0 || rml->ciffBase >= 0)) { + FILE* f = g_fopen (fname.c_str (), "rb"); + + if (f) { + rtexif::ExifManager exifManager (f, rml, firstFrameOnly); + + if (rml->exifBase >= 0) { + FrameData *idata = new RawFrameData (exifManager); + frames.push_back(idata); + if (rml && !firstFrameOnly) { + while (exifManager.getNextIFDOffset ()) { + int nextIFD = exifManager.getNextIFDOffset (); + exifManager.setIFDOffset (nextIFD); + idata = new RawFrameData (exifManager); + frames.push_back(idata); + } + } + } + fclose (f); + } + } else if (hasJpegExtension(fname)) { + FILE* f = g_fopen (fname.c_str (), "rb"); + + if (f) { + rtexif::ExifManager exifManager (f, rml, true); + FrameData *idata = new JpegFrameData (exifManager); + frames.push_back(idata); + fclose (f); + } + } else if (hasTiffExtension(fname)) { + FILE* f = g_fopen (fname.c_str (), "rb"); + + if (f) { + rtexif::ExifManager exifManager (f, rml, firstFrameOnly); + FrameData *idata = new TiffFrameData (exifManager); + frames.push_back(idata); + if (rml && !firstFrameOnly) { + while (exifManager.getNextIFDOffset ()) { + exifManager.setIFDOffset (exifManager.getNextIFDOffset ()); + idata = new TiffFrameData (exifManager); + frames.push_back(idata); + } + } + fclose (f); + } + } +} + +FramesData::~FramesData () +{ + for (auto currFrame : frames) { + delete currFrame; + } +} diff --git a/rtengine/imagedata.h b/rtengine/imagedata.h index f28a49a2f..da5b337cb 100644 --- a/rtengine/imagedata.h +++ b/rtengine/imagedata.h @@ -31,7 +31,7 @@ namespace rtengine { -class ImageData : public ImageMetaData +class FrameData { protected: @@ -49,13 +49,34 @@ protected: std::string make, model, serial; std::string orientation; std::string lens; + IIOSampleFormat sampleFormat; + + // each frame has the knowledge of "being an" + // or "being part of an" HDR or PS image + bool isPixelShift; + int isHDR; // Number of frame void extractInfo (); public: - ImageData (Glib::ustring fname, RawMetaDataLocation* rml = nullptr); - virtual ~ImageData (); + FrameData (); + FrameData (rtexif::ExifManager &exifManager); + virtual ~FrameData (); + + bool getPixelShift () const + { + return isPixelShift; + } + int getHDR () const + { + return isHDR; + } + + IIOSampleFormat getSampleFormat () const + { + return sampleFormat; + } const rtexif::TagDirectory* getExifData () const { @@ -128,5 +149,154 @@ public: return orientation; } }; + +class RawFrameData : public FrameData +{ +public: + RawFrameData (rtexif::ExifManager &exifManager); +}; + +class JpegFrameData : public FrameData +{ +public: + JpegFrameData (rtexif::ExifManager &exifManager); +}; + +class TiffFrameData : public FrameData +{ +public: + TiffFrameData (rtexif::ExifManager &exifManager); +}; + +class FramesData : public FramesMetaData { +private: + std::vector frames; + int dcrawFrameCount; + +public: + FramesData (Glib::ustring fname, RawMetaDataLocation* rml = nullptr, bool firstFrameOnly = false, bool loadAll = false); + ~FramesData (); + + void setDCRawFrameCount (int frameCount) + { + dcrawFrameCount = frameCount; + } + + int getFrameCount () const + { + return dcrawFrameCount ? dcrawFrameCount : frames.size(); + } + FrameData *getFrameData (int frame) const + { + return frames.at(frame); + } + + bool getPixelShift (int frame = 0) const + { + // So far only Pentax provide multi-frame HDR file. + // Only the first frame contains the HDR tag + // If more brand have to be supported, this rule may need + // to evolve + + //return frames.at(frame)->getPixelShift (); + return frames.at(0)->getPixelShift (); + } + int getHDR (int frame = 0) const + { + // So far only Pentax provide multi-frame HDR file. + // Only the first frame contains the HDR tag + // If more brand have to be supported, this rule may need + // to evolve + + //return frames.at(frame)->getPixelShift (); + if (frames.size()) { + return frames.at(frame)->getHDR (); + } else { + return 0; + } + } + + IIOSampleFormat getSampleFormat (int frame = 0) const + { + return frames.at(frame)->getSampleFormat (); + } + + const rtexif::TagDirectory* getExifData (int frame = 0) const + { + return frames.at(frame)->getExifData (); + } + const procparams::IPTCPairs getIPTCData (int frame = 0) const + { + return frames.at(frame)->getIPTCData (); + } + + bool hasExif (int frame = 0) const + { + return frames.at(frame)->hasExif (); + } + bool hasIPTC (int frame = 0) const + { + return frames.at(frame)->hasIPTC (); + } + + struct tm getDateTime (int frame = 0) const { + return frames.at(frame)->getDateTime (); + } + time_t getDateTimeAsTS(int frame = 0) const + { + return frames.at(frame)->getDateTimeAsTS (); + } + int getISOSpeed (int frame = 0) const + { + return frames.at(frame)->getISOSpeed (); + } + double getFNumber (int frame = 0) const + { + return frames.at(frame)->getFNumber (); + } + double getFocalLen (int frame = 0) const + { + return frames.at(frame)->getFocalLen (); + } + double getFocalLen35mm (int frame = 0) const + { + return frames.at(frame)->getFocalLen35mm (); + } + float getFocusDist (int frame = 0) const + { + return frames.at(frame)->getFocusDist (); + } + double getShutterSpeed (int frame = 0) const + { + return frames.at(frame)->getShutterSpeed (); + } + double getExpComp (int frame = 0) const + { + return frames.at(frame)->getExpComp (); + } + std::string getMake (int frame = 0) const + { + return frames.at(frame)->getMake (); + } + std::string getModel (int frame = 0) const + { + return frames.at(frame)->getModel (); + } + std::string getLens (int frame = 0) const + { + return frames.at(frame)->getLens (); + } + std::string getSerialNumber (int frame = 0) const + { + return frames.at(frame)->getSerialNumber (); + } + std::string getOrientation (int frame = 0) const + { + return frames.at(frame)->getOrientation (); + } + +}; + + } #endif diff --git a/rtengine/imageformat.h b/rtengine/imageformat.h new file mode 100644 index 000000000..b34f701b7 --- /dev/null +++ b/rtengine/imageformat.h @@ -0,0 +1,54 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 20017 Jean-Christophe Frisch + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _IMAGEFORMAT_ +#define _IMAGEFORMAT_ + +namespace rtengine +{ + +//NB: Update the associated strings in languages files when updating the following enum +// Look for "SAMPLEFORMAT_" +typedef enum IIO_Sample_Format { + IIOSF_UNKNOWN = 0, // Unknown or Unsupported file type; Has to remain 0 + //IIOSF_SIGNED_INT , // Not yet supported + IIOSF_UNSIGNED_CHAR = 1 << 0, + IIOSF_UNSIGNED_SHORT = 1 << 1, + //IIOSF_HALF , // OpenEXR & NVidia's Half Float, not yet supported + IIOSF_LOGLUV24 = 1 << 2, + IIOSF_LOGLUV32 = 1 << 3, + IIOSF_FLOAT = 1 << 4 +} IIOSampleFormat; + +typedef enum IIO_Sample_Arrangement { + IIOSA_UNKNOWN, // Unknown or Unsupported file type + IIOSA_CHUNKY, + IIOSA_PLANAR +} IIOSampleArrangement; + +typedef enum SensorType { + ST_NONE, // use this value if the image is already demosaiced (i.e. not a raw file) + ST_BAYER, + ST_FUJI_XTRANS, + ST_FOVEON, + //ST_FUJI_EXR +} eSensorType; + +} + +#endif diff --git a/rtengine/imageio.h b/rtengine/imageio.h index 1fbeb6e2d..372f42380 100644 --- a/rtengine/imageio.h +++ b/rtengine/imageio.h @@ -29,6 +29,7 @@ #define IMIO_CANNOTWRITEFILE 7 #include "rtengine.h" +#include "imageformat.h" #include #include "procparams.h" #include @@ -43,31 +44,6 @@ namespace rtengine class ProgressListener; class Imagefloat; -typedef enum IIO_Sample_Format { - IIOSF_UNKNOWN = 0, // Unknown or Unsupported file type; Has to remain 0 - //IIOSF_SIGNED_INT , // Not yet supported - IIOSF_UNSIGNED_CHAR = 1 << 0, - IIOSF_UNSIGNED_SHORT = 1 << 1, - //IIOSF_HALF , // OpenEXR & NVidia's Half Float, not yet supported - IIOSF_LOGLUV24 = 1 << 2, - IIOSF_LOGLUV32 = 1 << 3, - IIOSF_FLOAT = 1 << 4 -} IIOSampleFormat; - -typedef enum IIO_Sample_Arrangement { - IIOSA_UNKNOWN, // Unknown or Unsupported file type - IIOSA_CHUNKY, - IIOSA_PLANAR -} IIOSampleArrangement; - -typedef enum SensorType { - ST_NONE, // use this value if the image is already demosaiced (i.e. not a raw file) - ST_BAYER, - ST_FUJI_XTRANS, - ST_FOVEON, - //ST_FUJI_EXR -} eSensorType; - class ImageIO : virtual public ImageDatas { diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 0eec1325a..02f0ec550 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -57,7 +57,7 @@ protected: double redAWBMul, greenAWBMul, blueAWBMul; // local copy of the multipliers, to avoid recomputing the values cmsHPROFILE embProfile; Glib::ustring fileName; - ImageData* idata; + FramesData* idata; ImageMatrices imatrices; double dirpyrdenoiseExpComp; @@ -76,12 +76,12 @@ public: virtual void flushRGB () {}; virtual void HLRecovery_Global (ToneCurveParams hrp) {}; virtual void HLRecovery_inpaint (float** red, float** green, float** blue) {}; - virtual void MSR(LabImage* lab, LUTf & mapcurve, bool &mapcontlutili, int width, int height, int skip, RetinexParams deh, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax) {}; + virtual void MSR (LabImage* lab, LUTf & mapcurve, bool &mapcontlutili, int width, int height, int skip, RetinexParams deh, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax) {}; - virtual bool IsrgbSourceModified() const = 0; // tracks whether cached rgb output of demosaic has been modified + virtual bool IsrgbSourceModified () const = 0; // tracks whether cached rgb output of demosaic has been modified - virtual void setCurrentFrame(unsigned int frameNum) = 0; - virtual int getFrameCount() = 0; + virtual void setCurrentFrame (unsigned int frameNum) = 0; + virtual int getFrameCount () = 0; // use right after demosaicing image, add coarse transformation and put the result in the provided Imagefloat* @@ -107,10 +107,10 @@ public: return 0; } - virtual ImageData* getImageData () = 0; + virtual FrameData* getImageData (int frameNum) = 0; virtual ImageMatrices* getImageMatrices () = 0; - virtual bool isRAW() const = 0; - virtual DCPProfile* getDCP(const ColorManagementParams &cmp, ColorTemp &wb, DCPProfile::ApplyState &as) + virtual bool isRAW () const = 0; + virtual DCPProfile* getDCP (const ColorManagementParams &cmp, ColorTemp &wb, DCPProfile::ApplyState &as) { return nullptr; }; @@ -150,7 +150,7 @@ public: { return embProfile; } - virtual const ImageMetaData* getMetaData () + virtual const FramesMetaData* getMetaData () { return idata; } diff --git a/rtengine/profilestore.cc b/rtengine/profilestore.cc index c713d6b5c..4d06b6f6b 100644 --- a/rtengine/profilestore.cc +++ b/rtengine/profilestore.cc @@ -498,7 +498,7 @@ void ProfileStore::dumpFolderList() printf ("\n"); } -PartialProfile *ProfileStore::loadDynamicProfile (const ImageMetaData *im) +PartialProfile *ProfileStore::loadDynamicProfile (const FramesMetaData *im) { if (storeState == STORESTATE_NOTINITIALIZED) { parseProfilesOnce(); diff --git a/rtengine/profilestore.h b/rtengine/profilestore.h index 372dbfc3b..4949517da 100644 --- a/rtengine/profilestore.h +++ b/rtengine/profilestore.h @@ -195,7 +195,7 @@ public: void addListener (ProfileStoreListener *listener); void removeListener (ProfileStoreListener *listener); - rtengine::procparams::PartialProfile* loadDynamicProfile (const rtengine::ImageMetaData *im); + rtengine::procparams::PartialProfile* loadDynamicProfile (const rtengine::FramesMetaData *im); void dumpFolderList(); }; diff --git a/rtengine/rawimage.h b/rtengine/rawimage.h index 62752b59c..33580c6de 100644 --- a/rtengine/rawimage.h +++ b/rtengine/rawimage.h @@ -22,7 +22,7 @@ #include #include "dcraw.h" -#include "imageio.h" +#include "imageformat.h" #include "noncopyable.h" namespace rtengine diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 148d17ee9..6641cf51e 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -913,7 +913,7 @@ DCPProfile *RawImageSource::getDCP(const ColorManagementParams &cmp, ColorTemp & { DCPProfile *dcpProf = nullptr; cmsHPROFILE dummy; - findInputProfile(cmp.input, nullptr, (static_cast(getMetaData()))->getCamera(), &dcpProf, dummy); + findInputProfile(cmp.input, nullptr, (static_cast(getMetaData()))->getCamera(), &dcpProf, dummy); if (dcpProf == nullptr) { if (settings->verbose) { @@ -929,7 +929,7 @@ DCPProfile *RawImageSource::getDCP(const ColorManagementParams &cmp, ColorTemp & void RawImageSource::convertColorSpace(Imagefloat* image, const ColorManagementParams &cmp, const ColorTemp &wb) { double pre_mul[3] = { ri->get_pre_mul(0), ri->get_pre_mul(1), ri->get_pre_mul(2) }; - colorSpaceConversion (image, cmp, wb, pre_mul, embProfile, camProfile, imatrices.xyz_cam, (static_cast(getMetaData()))->getCamera()); + colorSpaceConversion (image, cmp, wb, pre_mul, embProfile, camProfile, imatrices.xyz_cam, (static_cast(getMetaData()))->getCamera()); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1703,7 +1703,8 @@ int RawImageSource::load (const Glib::ustring &fname, int imageNum, bool batch) rml.exifBase = ri->get_exifBase(); rml.ciffBase = ri->get_ciffBase(); rml.ciffLength = ri->get_ciffLen(); - idata = new ImageData (fname, &rml); + idata = new FramesData (fname, &rml); + idata->setDCRawFrameCount (numFrames); green(W, H); red(W, H); diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index bc2589408..21db71a72 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -166,9 +166,9 @@ public: return ri->get_rotateDegree(); } - ImageData* getImageData () + FrameData* getImageData (int frameNum) { - return idata; + return idata->getFrameData (frameNum); } ImageMatrices* getImageMatrices () { diff --git a/rtengine/rawmetadatalocation.h b/rtengine/rawmetadatalocation.h index d029d2a13..40ac6cc3e 100644 --- a/rtengine/rawmetadatalocation.h +++ b/rtengine/rawmetadatalocation.h @@ -22,11 +22,19 @@ namespace rtengine { -struct RawMetaDataLocation { +class RawMetaDataLocation { + +public: int exifBase; int ciffBase; int ciffLength; + + RawMetaDataLocation () : exifBase(-1), ciffBase(-1), ciffLength(-1) {} + RawMetaDataLocation (int exifBase) : exifBase(exifBase), ciffBase(-1), ciffLength(-1) {} + RawMetaDataLocation (int ciffBase, int ciffLength) : exifBase(-1), ciffBase(ciffBase), ciffLength(ciffLength) {} + RawMetaDataLocation (int exifBase, int ciffBase, int ciffLength) : exifBase(exifBase), ciffBase(ciffBase), ciffLength(ciffLength) {} }; + } #endif diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 6ab12c026..e72f6fbfd 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -19,6 +19,7 @@ #ifndef _RTENGINE_ #define _RTENGINE_ +#include "imageformat.h" #include "rt_math.h" #include "procparams.h" #include "procevents.h" @@ -49,57 +50,68 @@ class IImage16; class IImagefloat; /** - * This class represents provides functions to obtain exif and IPTC metadata information - * from the image file + * This class provides functions to obtain exif and IPTC metadata information + * from any of the sub-frame of an image file */ -class ImageMetaData +class FramesMetaData { public: + /** @return Returns the number of frame contained in the file based on Metadata */ + virtual int getFrameCount () const = 0; + /** Checks the availability of exif metadata tags. * @return Returns true if image contains exif metadata tags */ - virtual bool hasExif () const = 0; + virtual bool hasExif (int frame = 0) const = 0; /** Returns the directory of exif metadata tags. * @return The directory of exif metadata tags */ - virtual const rtexif::TagDirectory* getExifData () const = 0; + virtual const rtexif::TagDirectory* getExifData (int frame = 0) const = 0; /** Checks the availability of IPTC tags. * @return Returns true if image contains IPTC tags */ - virtual bool hasIPTC () const = 0; + virtual bool hasIPTC (int frame = 0) const = 0; /** Returns the directory of IPTC tags. * @return The directory of IPTC tags */ - virtual const procparams::IPTCPairs getIPTCData () const = 0; + virtual const procparams::IPTCPairs getIPTCData (int frame = 0) const = 0; /** @return a struct containing the date and time of the image */ - virtual struct tm getDateTime () const = 0; + virtual struct tm getDateTime (int frame = 0) const = 0; /** @return a timestamp containing the date and time of the image */ - virtual time_t getDateTimeAsTS() const = 0; + virtual time_t getDateTimeAsTS(int frame = 0) const = 0; /** @return the ISO of the image */ - virtual int getISOSpeed () const = 0; + virtual int getISOSpeed (int frame = 0) const = 0; /** @return the F number of the image */ - virtual double getFNumber () const = 0; + virtual double getFNumber (int frame = 0) const = 0; /** @return the focal length used at the exposure */ - virtual double getFocalLen () const = 0; + virtual double getFocalLen (int frame = 0) const = 0; /** @return the focal length in 35mm used at the exposure */ - virtual double getFocalLen35mm () const = 0; + virtual double getFocalLen35mm (int frame = 0) const = 0; /** @return the focus distance in meters, 0=unknown, 10000=infinity */ - virtual float getFocusDist () const = 0; + virtual float getFocusDist (int frame = 0) const = 0; /** @return the shutter speed */ - virtual double getShutterSpeed () const = 0; + virtual double getShutterSpeed (int frame = 0) const = 0; /** @return the exposure compensation */ - virtual double getExpComp () const = 0; + virtual double getExpComp (int frame = 0) const = 0; /** @return the maker of the camera */ - virtual std::string getMake () const = 0; + virtual std::string getMake (int frame = 0) const = 0; /** @return the model of the camera */ - virtual std::string getModel () const = 0; + virtual std::string getModel (int frame = 0) const = 0; - std::string getCamera () const + std::string getCamera (int frame = 0) const { - return getMake() + " " + getModel(); + return getMake(frame) + " " + getModel(frame); } /** @return the lens on the camera */ - virtual std::string getLens () const = 0; + virtual std::string getLens (int frame = 0) const = 0; /** @return the orientation of the image */ - virtual std::string getOrientation () const = 0; + virtual std::string getOrientation (int frame = 0) const = 0; + + /** @return true if the file is a PixelShift shot (Pentax bodies) */ + virtual bool getPixelShift (int frame = 0) const = 0; + /** @return 0: not ah HDR file ; 1: single shot HDR (e.g. 32 bit float DNG file or Log compressed) ; >1: multi-frame HDR file */ + virtual int getHDR (int frame = 0) const = 0; + /** @return the sample format based on MetaData */ + virtual IIOSampleFormat getSampleFormat (int frame = 0) const = 0; + /** Functions to convert between floating point and string representation of shutter and aperture */ static std::string apertureToString (double aperture); /** Functions to convert between floating point and string representation of shutter and aperture */ @@ -111,14 +123,15 @@ public: /** Functions to convert between floating point and string representation of exposure compensation */ static std::string expcompToString (double expcomp, bool maskZeroexpcomp); - virtual ~ImageMetaData () {} + virtual ~FramesMetaData () {} /** Reads metadata from file. * @param fname is the name of the file - * @param rml is a struct containing information about metadata location. Use it only for raw files. In case - * of jpgs and tiffs pass a NULL pointer. + * @param rml is a struct containing information about metadata location of the first frame. + * Use it only for raw files. In caseof jpgs and tiffs pass a NULL pointer. + * @param firstFrameOnly must be true to get the MetaData of the first frame only, e.g. for a PixelShift file. * @return The metadata */ - static ImageMetaData* fromFile (const Glib::ustring& fname, RawMetaDataLocation* rml); + static FramesMetaData* fromFile (const Glib::ustring& fname, RawMetaDataLocation* rml, bool firstFrameOnly = false); }; /** This listener interface is used to indicate the progress of time consuming operations */ @@ -157,9 +170,9 @@ public: /** Returns the embedded icc profile of the image. * @return The handle of the embedded profile */ virtual cmsHPROFILE getEmbeddedProfile () = 0; - /** Returns a class providing access to the exif and iptc metadata tags of the image. - * @return An instance of the ImageMetaData class */ - virtual const ImageMetaData* getMetaData () = 0; + /** Returns a class providing access to the exif and iptc metadata tags of all frames of the image. + * @return An instance of the FramesMetaData class */ + virtual const FramesMetaData* getMetaData () = 0; /** This is a function used for internal purposes only. */ virtual ImageSource* getImageSource () = 0; /** This class has manual reference counting. You have to call this function each time to make a new reference to an instance. */ diff --git a/rtengine/stdimagesource.cc b/rtengine/stdimagesource.cc index 87f25a497..d4e6a62f1 100644 --- a/rtengine/stdimagesource.cc +++ b/rtengine/stdimagesource.cc @@ -158,7 +158,7 @@ int StdImageSource::load (const Glib::ustring &fname, int imageNum, bool batch) embProfile = img->getEmbeddedProfile (); - idata = new ImageData (fname); + idata = new FramesData (fname); if (idata->hasExif()) { int deg = 0; diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index 330c08244..2e845e3f3 100644 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -68,9 +68,9 @@ public: void getFullSize (int& w, int& h, int tr = TR_NONE); void getSize (const PreviewProps &pp, int& w, int& h); - ImageData* getImageData () + FrameData* getImageData (int frameNum) { - return idata; + return idata->getFrameData (frameNum); } ImageIO* getImageIO () { diff --git a/rtexif/pentaxattribs.cc b/rtexif/pentaxattribs.cc index 2c52a0c88..e9a7a3544 100644 --- a/rtexif/pentaxattribs.cc +++ b/rtexif/pentaxattribs.cc @@ -1228,6 +1228,7 @@ public: choices[2] = "HDR 1"; choices[3] = "HDR 2"; choices[4] = "HDR 3"; + choices[5] = "Advanced"; choices1[0] = "Auto-align Off"; choices1[1] = "Auto-align On"; diff --git a/rtexif/rtexif.cc b/rtexif/rtexif.cc index c12f5f782..7c508892a 100644 --- a/rtexif/rtexif.cc +++ b/rtexif/rtexif.cc @@ -19,6 +19,7 @@ * along with RawTherapee. If not, see . */ #include +#include #include #include #include @@ -289,6 +290,8 @@ bool TagDirectory::CPBDump (const Glib::ustring &commFName, const Glib::ustring kf->set_double ("Common Data", "Shutter", cfs->shutter); kf->set_double ("Common Data", "FocalLength", cfs->focalLen); kf->set_integer ("Common Data", "ISO", cfs->iso); + kf->set_integer ("Common Data", "IsHDR", cfs->isHDR); + kf->set_boolean ("Common Data", "IsPixelShift", cfs->isPixelShift); kf->set_string ("Common Data", "Lens", cfs->lens); kf->set_string ("Common Data", "Make", cfs->camMake); kf->set_string ("Common Data", "Model", cfs->camModel); @@ -849,7 +852,11 @@ Tag::Tag (TagDirectory* p, FILE* f, int base) } if (tag == 0x002e) { // location of the embedded preview image in raw files of Panasonic cameras - TagDirectory* previewdir = ExifManager::parseJPEG (f, ftell (f)); // try to parse the exif data from the preview image + TagDirectory* previewdir; + { + ExifManager exifManager(f, 0, true); + previewdir = exifManager.parseJPEG (ftell (f)); // try to parse the exif data from the preview image + } if (previewdir) { if (previewdir->getTag ("Exif")) { @@ -1894,7 +1901,7 @@ const TagAttrib* lookupAttrib (const TagAttrib* dir, const char* field) } -TagDirectory* ExifManager::parseCIFF (FILE* f, int base, int length) +TagDirectory* ExifManager::parseCIFF () { TagDirectory* root = new TagDirectory (nullptr, ifdAttribs, INTEL); @@ -1904,12 +1911,12 @@ TagDirectory* ExifManager::parseCIFF (FILE* f, int base, int length) mn->initMakerNote (IFD, canonAttribs); root->addTag (exif); exif->getDirectory()->addTag (mn); - parseCIFF (f, base, length, root); + parseCIFF (rml->ciffLength, root); root->sort (); return root; } -Tag* ExifManager::saveCIFFMNTag (FILE* f, TagDirectory* root, int len, const char* name) +Tag* ExifManager::saveCIFFMNTag (TagDirectory* root, int len, const char* name) { int s = ftell (f); if(s >= 0) { @@ -1927,15 +1934,22 @@ Tag* ExifManager::saveCIFFMNTag (FILE* f, TagDirectory* root, int len, const cha } } -void ExifManager::parseCIFF (FILE* f, int base, int length, TagDirectory* root) +void ExifManager::parseCIFF (int length, TagDirectory* root) { + if (!f) { + #ifndef NDEBUG + std::cerr << "ERROR : no file opened !" << std::endl; + #endif + return; + } + char buffer[1024]; Tag* t; - fseek (f, base + length - 4, SEEK_SET); + fseek (f, rml->ciffBase + length - 4, SEEK_SET); - int dirStart = get4 (f, INTEL) + base; + int dirStart = get4 (f, INTEL) + rml->ciffBase; fseek (f, dirStart, SEEK_SET); int numOfTags = get2 (f, INTEL); @@ -1960,10 +1974,12 @@ void ExifManager::parseCIFF (FILE* f, int base, int length, TagDirectory* root) int nextPos = ftell (f) + 4; // seek to the location of the value - fseek (f, base + get4 (f, INTEL), SEEK_SET); + fseek (f, rml->ciffBase + get4 (f, INTEL), SEEK_SET); if ((((type >> 8) + 8) | 8) == 0x38) { - parseCIFF (f, ftell (f), len, root); // Parse a sub-table + rtengine::RawMetaDataLocation rml2(ftell (f), len); + ExifManager exifManager(f, &rml2, true); + exifManager.parseCIFF (len, root); // Parse a sub-table } if (type == 0x0810) { @@ -1994,8 +2010,9 @@ void ExifManager::parseCIFF (FILE* f, int base, int length, TagDirectory* root) } + ExifManager exifManager(f, 0, true); if (type == 0x102d) { - Tag* t = saveCIFFMNTag (f, root, len, "CanonCameraSettings"); + Tag* t = exifManager.saveCIFFMNTag (root, len, "CanonCameraSettings"); int mm = t->toInt (34, SHORT); Tag* nt = new Tag (exif, lookupAttrib (exifAttribs, "MeteringMode")); @@ -2074,31 +2091,31 @@ void ExifManager::parseCIFF (FILE* f, int base, int length, TagDirectory* root) } if (type == 0x1029) { - saveCIFFMNTag (f, root, len, "CanonFocalLength"); + exifManager.saveCIFFMNTag (root, len, "CanonFocalLength"); } if (type == 0x1031) { - saveCIFFMNTag (f, root, len, "SensorInfo"); + exifManager.saveCIFFMNTag (root, len, "SensorInfo"); } if (type == 0x1033) { - saveCIFFMNTag (f, root, len, "CustomFunctions"); + exifManager.saveCIFFMNTag (root, len, "CustomFunctions"); } if (type == 0x1038) { - saveCIFFMNTag (f, root, len, "CanonAFInfo"); + exifManager.saveCIFFMNTag (root, len, "CanonAFInfo"); } if (type == 0x1093) { - saveCIFFMNTag (f, root, len, "CanonFileInfo"); + exifManager.saveCIFFMNTag (root, len, "CanonFileInfo"); } if (type == 0x10a9) { - saveCIFFMNTag (f, root, len, "ColorBalance"); + exifManager.saveCIFFMNTag (root, len, "ColorBalance"); } if (type == 0x102a) { - saveCIFFMNTag (f, root, len, "CanonShotInfo"); + exifManager.saveCIFFMNTag (root, len, "CanonShotInfo"); iso = pow (2, (get4 (f, INTEL), get2 (f, INTEL)) / 32.0 - 4) * 50; aperture = (get2 (f, INTEL), (short)get2 (f, INTEL)) / 32.0f; @@ -2530,22 +2547,47 @@ parse_leafdata (TagDirectory* root, ByteOrder order) } } -TagDirectory* ExifManager::parse (FILE* f, int base, bool skipIgnored) +TagDirectory* ExifManager::parse (bool skipIgnored) { + int ifd = IFDOffset; + + if (!f) { + #ifndef NDEBUG + std::cerr << "ERROR : no file opened !" << std::endl; + #endif + return nullptr; + } setlocale (LC_NUMERIC, "C"); // to set decimal point in sscanf - // read tiff header - fseek (f, base, SEEK_SET); - unsigned short bo; - fread (&bo, 1, 2, f); - ByteOrder order = (ByteOrder) ((int)bo); - get2 (f, order); - int firstifd = get4 (f, order); + + if (order == ByteOrder::UNKNOWN) { + // read tiff header + fseek (f, rml->exifBase, SEEK_SET); + unsigned short bo; + fread (&bo, 1, 2, f); + order = (ByteOrder) ((int)bo); + get2 (f, order); + if (!ifd) { + ifd = get4 (f, order); + } + } + + return parseIFD (ifd, skipIgnored); +} + +TagDirectory* ExifManager::parseIFD (int ifdOffset, bool skipIgnored) +{ + if (!f) { + #ifndef NDEBUG + std::cerr << "ERROR : no file opened !" << std::endl; + #endif + return nullptr; + } // seek to IFD0 - fseek (f, base + firstifd, SEEK_SET); + fseek (f, rml->exifBase + ifdOffset, SEEK_SET); // first read the IFD directory - TagDirectory* root = new TagDirectory (nullptr, f, base, ifdAttribs, order, skipIgnored); + TagDirectory* root = new TagDirectory (nullptr, f, rml->exifBase, ifdAttribs, order, skipIgnored); // fix ISO issue with nikon and panasonic cameras Tag* make = root->getTag ("Make"); @@ -2580,8 +2622,8 @@ TagDirectory* ExifManager::parse (FILE* f, int base, bool skipIgnored) if (make && !strncmp ((char*)make->getValue(), "Kodak", 5)) { if (!exif) { // old Kodak cameras may have exif tags in IFD0, reparse and create an exif subdir - fseek (f, base + firstifd, SEEK_SET); - TagDirectory* exifdir = new TagDirectory (nullptr, f, base, exifAttribs, order, true); + fseek (f, rml->exifBase + ifdOffset, SEEK_SET); + TagDirectory* exifdir = new TagDirectory (nullptr, f, rml->exifBase, exifAttribs, order, true); exif = new Tag (root, root->getAttrib ("Exif")); exif->initSubDir (exifdir); @@ -2777,13 +2819,20 @@ TagDirectory* ExifManager::parse (FILE* f, int base, bool skipIgnored) } } -// root->printAll (); + nextIFDOffset = get4 (f, order); + //root->printAll (); return root; } -TagDirectory* ExifManager::parseJPEG (FILE* f, int offset) +TagDirectory* ExifManager::parseJPEG (int offset) { + if (!f) { + #ifndef NDEBUG + std::cerr << "ERROR : no file opened !" << std::endl; + #endif + return nullptr; + } if(!fseek (f, offset, SEEK_SET)) { unsigned char c; @@ -2805,7 +2854,20 @@ TagDirectory* ExifManager::parseJPEG (FILE* f, int offset) if (!memcmp (idbuff + 2, exifid, 6)) { // Exif info found tiffbase = ftell (f); - return parse (f, tiffbase); + + // We need a RawMetaDataLocation to put the 'tiffbase' value + bool rmlCreated = false; + if (!rml) { + rml = new rtengine::RawMetaDataLocation (0); + rmlCreated = true; + } + rml->exifBase = tiffbase; + TagDirectory* tagDir = parse (); + if (rmlCreated) { + delete rml; + rml = nullptr; + } + return tagDir; } } } @@ -2815,10 +2877,17 @@ TagDirectory* ExifManager::parseJPEG (FILE* f, int offset) return nullptr; } -TagDirectory* ExifManager::parseTIFF (FILE* f, bool skipIgnored) +TagDirectory* ExifManager::parseTIFF (bool skipIgnored) { - return parse (f, 0, skipIgnored); + if (!rml) { + rml = new rtengine::RawMetaDataLocation(0); + TagDirectory* tagDir = parse (skipIgnored); + delete rml; + return tagDir; + } else { + return parse (skipIgnored); + } } std::vector ExifManager::getDefaultTIFFTags (TagDirectory* forthis) diff --git a/rtexif/rtexif.h b/rtexif/rtexif.h index 0167ef445..c476e3dc9 100644 --- a/rtexif/rtexif.h +++ b/rtexif/rtexif.h @@ -31,6 +31,7 @@ #include "../rtengine/procparams.h" #include "../rtengine/noncopyable.h" +#include "../rtengine/rawmetadatalocation.h" class CacheImageData; @@ -46,7 +47,7 @@ enum ActionCode { AC_INVALID = 100, // invalid state }; -enum ByteOrder {INTEL = 0x4949, MOTOROLA = 0x4D4D}; +enum ByteOrder {UNKNOWN = 0, INTEL = 0x4949, MOTOROLA = 0x4D4D}; #if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ const enum ByteOrder HOSTORDER = INTEL; #else @@ -99,10 +100,10 @@ class TagDirectory { protected: - std::vector tags; // tags in the directory - const TagAttrib* attribs; // descriptor table to decode the tags - ByteOrder order; // byte order - TagDirectory* parent; // parent directory (NULL if root) + std::vector tags; // tags in the directory + const TagAttrib* attribs; // descriptor table to decode the tags + ByteOrder order; // byte order + TagDirectory* parent; // parent directory (NULL if root) static Glib::ustring getDumpKey (int tagID, const Glib::ustring &tagName); public: @@ -309,13 +310,37 @@ public: class ExifManager { - static Tag* saveCIFFMNTag (FILE* f, TagDirectory* root, int len, const char* name); + Tag* saveCIFFMNTag (TagDirectory* root, int len, const char* name); + TagDirectory* parseIFD (int ifdOffset, bool skipIgnored); + public: - static TagDirectory* parse (FILE*f, int base, bool skipIgnored = true); - static TagDirectory* parseJPEG (FILE*f, int offset = 0); // offset: to extract exif data from a embedded preview/thumbnail - static TagDirectory* parseTIFF (FILE*f, bool skipIgnored = true); - static TagDirectory* parseCIFF (FILE* f, int base, int length); - static void parseCIFF (FILE* f, int base, int length, TagDirectory* root); + FILE* f; + rtengine::RawMetaDataLocation *rml; + ByteOrder order; + bool onlyFirst; // Only first IFD + unsigned int IFDOffset; + unsigned int nextIFDOffset; + + ExifManager (FILE* fHandle, rtengine::RawMetaDataLocation *rml, bool onlyFirstIFD) + : f(fHandle), rml(rml), order(UNKNOWN), onlyFirst(onlyFirstIFD), + IFDOffset(0), nextIFDOffset(0) {} + + void setIFDOffset(unsigned int offset) + { + IFDOffset = offset; + } + + unsigned int getNextIFDOffset() + { + return nextIFDOffset; + } + + // The following functions parse only one IFD at a time and store the "next IFD offset" + TagDirectory* parse (bool skipIgnored = true); + TagDirectory* parseJPEG (int offset = 0); // offset: to extract exif data from a embedded preview/thumbnail + TagDirectory* parseTIFF (bool skipIgnored = true); + TagDirectory* parseCIFF (); + void parseCIFF (int length, TagDirectory* root); /// @brief Get default tag for TIFF /// @param forthis The byte order will be taken from the given directory. diff --git a/rtexif/stdattribs.cc b/rtexif/stdattribs.cc index 514dd5215..f59fa9b36 100644 --- a/rtexif/stdattribs.cc +++ b/rtexif/stdattribs.cc @@ -539,6 +539,7 @@ const TagAttrib exifAttribs[] = { {0, AC_SYSTEM, 0, nullptr, 0x0101, AUTO, "ImageHeight", &stdInterpreter}, {0, AC_SYSTEM, 0, nullptr, 0x0102, AUTO, "BitsPerSample", &stdInterpreter}, {0, AC_SYSTEM, 0, nullptr, 0x0103, AUTO, "Compression", &compressionInterpreter}, + {0, AC_SYSTEM, 0, nullptr, 0x0153, AUTO, "SampleFormat", &stdInterpreter}, {0, AC_WRITE, 0, nullptr, 0x828d, AUTO, "CFAPatternDim", &stdInterpreter}, {0, AC_WRITE, 0, nullptr, 0x828e, AUTO, "CFAPattern", &cfaInterpreter}, {0, AC_WRITE, 0, nullptr, 0x829A, AUTO, "ExposureTime", &exposureTimeInterpreter}, @@ -777,6 +778,7 @@ const TagAttrib ifdAttribs[] = { {0, AC_SYSTEM, 0, nullptr, 0x013E, AUTO, "WhitePoint", &stdInterpreter}, {0, AC_SYSTEM, 0, nullptr, 0x013F, AUTO, "PriomaryChromaticities", &stdInterpreter}, {0, AC_WRITE, 0, ifdAttribs, 0x014A, AUTO, "SubIFD", &stdInterpreter}, + {0, AC_SYSTEM, 0, nullptr, 0x0153, AUTO, "SampleFormat", &stdInterpreter}, {0, AC_SYSTEM, 0, nullptr, 0x0201, AUTO, "JPEGInterchangeFormat", &stdInterpreter}, {0, AC_SYSTEM, 0, nullptr, 0x0202, AUTO, "JPEGInterchangeFormatLength", &stdInterpreter}, {0, AC_SYSTEM, 0, nullptr, 0x0211, AUTO, "YCbCrCoefficients", &stdInterpreter}, diff --git a/rtgui/cacheimagedata.cc b/rtgui/cacheimagedata.cc index 34983d46a..e1a3eaba3 100644 --- a/rtgui/cacheimagedata.cc +++ b/rtgui/cacheimagedata.cc @@ -24,9 +24,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), - fnumber(0.0), shutter(0.0), focalLen(0.0), focalLen35mm(0.0), focusDist(0.f), iso(0), - redAWBMul(-1.0), greenAWBMul(-1.0), blueAWBMul(-1.0), rotate(0), thumbImgType(0) + timeValid(false), year(0), month(0), day(0), hour(0), min(0), sec(0), exifValid(false), + fnumber(0.0), shutter(0.0), focalLen(0.0), focalLen35mm(0.0), focusDist(0.f), iso(0), isHDR (0), isPixelShift (false), + sampleFormat(rtengine::IIOSF_UNKNOWN), redAWBMul(-1.0), greenAWBMul(-1.0), blueAWBMul(-1.0), rotate(0), thumbImgType(0) { } @@ -138,6 +138,14 @@ int CacheImageData::load (const Glib::ustring& fname) iso = keyFile.get_integer ("ExifInfo", "ISO"); } + if (keyFile.has_key ("ExifInfo", "IsHDR")) { + isHDR = keyFile.get_integer ("ExifInfo", "IsHDR"); + } + + if (keyFile.has_key ("ExifInfo", "IsPixelShift")) { + isPixelShift = keyFile.get_boolean ("ExifInfo", "IsPixelShift"); + } + if (keyFile.has_key ("ExifInfo", "ExpComp")) { expcomp = keyFile.get_string ("ExifInfo", "ExpComp"); } @@ -160,6 +168,9 @@ int CacheImageData::load (const Glib::ustring& fname) if (keyFile.has_key ("FileInfo", "Filetype")) { filetype = keyFile.get_string ("FileInfo", "Filetype"); } + if (keyFile.has_key ("FileInfo", "SampleFormat")) { + sampleFormat = (rtengine::IIO_Sample_Format)keyFile.get_integer ("FileInfo", "SampleFormat"); + } } if (format == FT_Raw && keyFile.has_group ("ExtraRawInfo")) { @@ -235,6 +246,8 @@ int CacheImageData::save (const Glib::ustring& fname) keyFile.set_double ("ExifInfo", "FocalLen35mm", focalLen35mm); keyFile.set_double ("ExifInfo", "FocusDist", focusDist); keyFile.set_integer ("ExifInfo", "ISO", iso); + keyFile.set_integer ("ExifInfo", "IsHDR", isHDR); + keyFile.set_boolean ("ExifInfo", "IsPixelShift", isPixelShift); keyFile.set_string ("ExifInfo", "ExpComp", expcomp); } @@ -242,6 +255,7 @@ int CacheImageData::save (const Glib::ustring& fname) keyFile.set_string ("ExifInfo", "CameraMake", camMake); keyFile.set_string ("ExifInfo", "CameraModel", camModel); keyFile.set_string ("FileInfo", "Filetype", filetype); + keyFile.set_integer ("FileInfo", "SampleFormat", sampleFormat); if (format == FT_Raw) { keyFile.set_integer ("ExtraRawInfo", "ThumbImageType", thumbImgType); diff --git a/rtgui/cacheimagedata.h b/rtgui/cacheimagedata.h index f655bd88b..548633168 100644 --- a/rtgui/cacheimagedata.h +++ b/rtgui/cacheimagedata.h @@ -21,6 +21,7 @@ #include #include "options.h" +#include "../rtengine/imageformat.h" class CacheImageData { @@ -51,6 +52,9 @@ public: double focalLen, focalLen35mm; float focusDist; unsigned iso; + int isHDR; // null if no HDR, otherwise provide the number of frame for this HDR file + bool isPixelShift; + rtengine::IIO_Sample_Format sampleFormat; Glib::ustring lens; Glib::ustring camMake; Glib::ustring camModel; diff --git a/rtgui/dynamicprofilepanel.cc b/rtgui/dynamicprofilepanel.cc index db3a19ed0..c8a8a1644 100644 --- a/rtgui/dynamicprofilepanel.cc +++ b/rtgui/dynamicprofilepanel.cc @@ -405,7 +405,7 @@ void DynamicProfilePanel::render_fnumber ( RENDER_RANGE_ (double, fnumber, [] (double f) { return std::string ("f/") + - rtengine::ImageMetaData::apertureToString (f); + rtengine::FramesMetaData::apertureToString (f); }); } @@ -421,7 +421,7 @@ void DynamicProfilePanel::render_shutterspeed ( Gtk::CellRenderer *cell, const Gtk::TreeModel::iterator &iter) { RENDER_RANGE_ (double, shutterspeed, - rtengine::ImageMetaData::shutterToString); + rtengine::FramesMetaData::shutterToString); } diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 389c16a4e..1566f3c07 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -1268,13 +1268,14 @@ void EditorPanel::info_toggled () Glib::ustring infoString2; //2-nd line Glib::ustring infoString3; //3-rd line Glib::ustring infoString4; //4-th line + Glib::ustring infoString5; //5-th line Glib::ustring expcomp; if (!ipc || !openThm) { return; } - const rtengine::ImageMetaData* idata = ipc->getInitialImage()->getMetaData(); + const rtengine::FramesMetaData* idata = ipc->getInitialImage()->getMetaData(); if (idata && idata->hasExif()) { infoString1 = Glib::ustring::compose ("%1 + %2", @@ -1305,6 +1306,24 @@ void EditorPanel::info_toggled () infoString4 = Glib::ustring::compose ("%1 MP (%2x%3)", Glib::ustring::format (std::setw (4), std::fixed, std::setprecision (1), (float)ww * hh / 1000000), ww, hh); infoString = Glib::ustring::compose ("%1\n%2\n%3\n%4", infoString1, infoString2, infoString3, infoString4); + + //adding special characteristics + bool isHDR = idata->getHDR(); + bool isPixelShift = idata->getPixelShift(); + int numFrames = idata->getFrameCount(); + if (isHDR) { + infoString5 = Glib::ustring::compose (M("QINFO_HDR"), numFrames); + if (numFrames == 1) { + int sampleFormat = idata->getSampleFormat(); + infoString5 = Glib::ustring::compose ("%1 / %2", infoString5, M(Glib::ustring::compose("SAMPLEFORMAT_%1", sampleFormat))); + } + } else if (isPixelShift) { + infoString5 = Glib::ustring::compose (M("QINFO_PIXELSHIFT"), numFrames); + } + if (!infoString5.empty()) { + infoString = Glib::ustring::compose ("%1\n%2", infoString, infoString5); + } + } else { infoString = M ("QINFO_NOEXIF"); } diff --git a/rtgui/exifpanel.cc b/rtgui/exifpanel.cc index 34cb2c064..370a29c77 100644 --- a/rtgui/exifpanel.cc +++ b/rtgui/exifpanel.cc @@ -177,15 +177,28 @@ void ExifPanel::setDefaults (const ProcParams* defParams, const ParamsEdited* pe defChangeList = defParams->exif; } -void ExifPanel::setImageData (const ImageMetaData* id) +void ExifPanel::setImageData (const FramesMetaData* id) { idata = id; exifTreeModel->clear (); - if (id && id->getExifData ()) { -// id->getExifData ()->printAll (); - addDirectory (id->getExifData (), exifTreeModel->children()); + if (id) { + //bool first = true; + // HOMBRE: Should we only display the current frame's Exifs ? + for (int frameNum = 0; frameNum < id->getFrameCount (); ++frameNum) { + if ( id->getExifData (frameNum)) { + /* + if (!first) { + Gtk::Separator *sep = Gtk::manage (new Gtk::Separator); + sep->set_orientation(Gtk::ORIENTATION_HORIZONTAL); + first = false; + } + */ + //id->getExifData ()->printAll (); + addDirectory (id->getExifData (frameNum), exifTreeModel->children()); + } + } } } diff --git a/rtgui/exifpanel.h b/rtgui/exifpanel.h index 6244c1a4f..db1fc8649 100644 --- a/rtgui/exifpanel.h +++ b/rtgui/exifpanel.h @@ -26,7 +26,7 @@ class ExifPanel : public Gtk::VBox, public ToolPanel { private: - const rtengine::ImageMetaData* idata; + const rtengine::FramesMetaData* idata; rtengine::procparams::ExifPairs changeList; rtengine::procparams::ExifPairs defChangeList; bool recursiveOp; @@ -91,7 +91,7 @@ public: void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr); void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr); - void setImageData (const rtengine::ImageMetaData* id); + void setImageData (const rtengine::FramesMetaData* id); void exifSelectionChanged (); void removePressed (); diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index 10d4809ed..ff49b5ce3 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -1539,8 +1539,8 @@ bool FileBrowser::checkFilter (ThumbBrowserEntryBase* entryb) // true -> entry && (!filter.exifFilter.filterExpComp || filter.exifFilter.expcomp.count(cfs->expcomp) > 0); return - (!filter.exifFilter.filterShutter || (rtengine::ImageMetaData::shutterFromString(rtengine::ImageMetaData::shutterToString(cfs->shutter)) >= filter.exifFilter.shutterFrom - tol2 && rtengine::ImageMetaData::shutterFromString(rtengine::ImageMetaData::shutterToString(cfs->shutter)) <= filter.exifFilter.shutterTo + tol2)) - && (!filter.exifFilter.filterFNumber || (rtengine::ImageMetaData::apertureFromString(rtengine::ImageMetaData::apertureToString(cfs->fnumber)) >= filter.exifFilter.fnumberFrom - tol2 && rtengine::ImageMetaData::apertureFromString(rtengine::ImageMetaData::apertureToString(cfs->fnumber)) <= filter.exifFilter.fnumberTo + tol2)) + (!filter.exifFilter.filterShutter || (rtengine::FramesMetaData::shutterFromString(rtengine::FramesMetaData::shutterToString(cfs->shutter)) >= filter.exifFilter.shutterFrom - tol2 && rtengine::FramesMetaData::shutterFromString(rtengine::FramesMetaData::shutterToString(cfs->shutter)) <= filter.exifFilter.shutterTo + tol2)) + && (!filter.exifFilter.filterFNumber || (rtengine::FramesMetaData::apertureFromString(rtengine::FramesMetaData::apertureToString(cfs->fnumber)) >= filter.exifFilter.fnumberFrom - tol2 && rtengine::FramesMetaData::apertureFromString(rtengine::FramesMetaData::apertureToString(cfs->fnumber)) <= filter.exifFilter.fnumberTo + tol2)) && (!filter.exifFilter.filterFocalLen || (cfs->focalLen >= filter.exifFilter.focalFrom - tol && cfs->focalLen <= filter.exifFilter.focalTo + tol)) && (!filter.exifFilter.filterISO || (cfs->iso >= filter.exifFilter.isoFrom && cfs->iso <= filter.exifFilter.isoTo)) && (!filter.exifFilter.filterExpComp || filter.exifFilter.expcomp.count(cfs->expcomp) > 0) diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index eafe32fcd..a2088b9e2 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -770,6 +770,8 @@ void FileCatalog::previewReady (int dir_id, FileBrowserEntry* fdn) if (cfs->focalLen > dirEFS.focalTo) { dirEFS.focalTo = cfs->focalLen; } + + //TODO: ass filters for HDR and PixelShift files } dirEFS.filetypes.insert (cfs->filetype); diff --git a/rtgui/filterpanel.cc b/rtgui/filterpanel.cc index a8691c1b3..5f8fa2781 100644 --- a/rtgui/filterpanel.cc +++ b/rtgui/filterpanel.cc @@ -171,15 +171,15 @@ void FilterPanel::setFilter (ExifFilterSettings& defefs, bool updateLists) } // enaFNumber->set_active (curefs.filterFNumber); - fnumberFrom->set_text (ImageMetaData::apertureToString (defefs.fnumberFrom)); + fnumberFrom->set_text (FramesMetaData::apertureToString (defefs.fnumberFrom)); curefs.fnumberFrom = defefs.fnumberFrom; - fnumberTo->set_text (ImageMetaData::apertureToString (defefs.fnumberTo)); + fnumberTo->set_text (FramesMetaData::apertureToString (defefs.fnumberTo)); curefs.fnumberTo = defefs.fnumberTo; // enaShutter->set_active (curefs.filterShutter); - shutterFrom->set_text (ImageMetaData::shutterToString (defefs.shutterFrom)); + shutterFrom->set_text (FramesMetaData::shutterToString (defefs.shutterFrom)); curefs.shutterFrom = defefs.shutterFrom; - shutterTo->set_text (ImageMetaData::shutterToString (defefs.shutterTo)); + shutterTo->set_text (FramesMetaData::shutterToString (defefs.shutterTo)); curefs.shutterTo = defefs.shutterTo; // enaISO->set_active (curefs.filterISO); @@ -315,8 +315,8 @@ ExifFilterSettings FilterPanel::getFilter () efs.focalTo = atof (focalTo->get_text().c_str()); efs.isoFrom = atoi (isoFrom->get_text().c_str()); efs.isoTo = atoi (isoTo->get_text().c_str()); - efs.shutterFrom = ImageMetaData::shutterFromString (shutterFrom->get_text()); - efs.shutterTo = ImageMetaData::shutterFromString (shutterTo->get_text()); + efs.shutterFrom = FramesMetaData::shutterFromString (shutterFrom->get_text()); + efs.shutterTo = FramesMetaData::shutterFromString (shutterTo->get_text()); efs.filterFNumber = enaFNumber->get_active (); efs.filterShutter = enaShutter->get_active (); diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index 1bb1c23a3..e026243be 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -958,7 +958,7 @@ void ICMPanel::oBPCChanged () } } -void ICMPanel::setRawMeta (bool raw, const rtengine::ImageData* pMeta) +void ICMPanel::setRawMeta (bool raw, const rtengine::FramesData* pMeta) { disableListener (); diff --git a/rtgui/icmpanel.h b/rtgui/icmpanel.h index 35017bed4..f8c762b0e 100644 --- a/rtgui/icmpanel.h +++ b/rtgui/icmpanel.h @@ -122,7 +122,7 @@ public: void applyBaselineExposureOffsetChanged(); void applyHueSatMapChanged(); - void setRawMeta (bool raw, const rtengine::ImageData* pMeta); + void setRawMeta (bool raw, const rtengine::FramesData* pMeta); void saveReferencePressed (); void setICMPanelListener (ICMPanelListener* ipl) diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index 8af99b2ab..4084e300f 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -59,7 +59,7 @@ InspectorBuffer::~InspectorBuffer() { //int InspectorBuffer::infoFromImage (const Glib::ustring& fname) //{ // -// rtengine::ImageMetaData* idata = rtengine::ImageMetaData::fromFile (fname, nullptr); +// rtengine::FramesMetaData* idata = rtengine::FramesMetaData::fromFile (fname, nullptr, true); // // if (!idata) { // return 0; diff --git a/rtgui/iptcpanel.cc b/rtgui/iptcpanel.cc index 5ee533e2c..cd0fe4050 100644 --- a/rtgui/iptcpanel.cc +++ b/rtgui/iptcpanel.cc @@ -434,7 +434,7 @@ void IPTCPanel::setDefaults (const ProcParams* defParams, const ParamsEdited* pe defChangeList = defParams->iptc; } -void IPTCPanel::setImageData (const ImageMetaData* id) +void IPTCPanel::setImageData (const FramesMetaData* id) { if (id) { diff --git a/rtgui/iptcpanel.h b/rtgui/iptcpanel.h index 63309cc27..b216cf638 100644 --- a/rtgui/iptcpanel.h +++ b/rtgui/iptcpanel.h @@ -75,7 +75,7 @@ public: void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr); void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr); - void setImageData (const rtengine::ImageMetaData* id); + void setImageData (const rtengine::FramesMetaData* id); void notifyListener (); diff --git a/rtgui/lensprofile.cc b/rtgui/lensprofile.cc index 0855ef03f..991ad0416 100644 --- a/rtgui/lensprofile.cc +++ b/rtgui/lensprofile.cc @@ -110,7 +110,7 @@ void LensProfilePanel::read(const rtengine::procparams::ProcParams* pp, const Pa conUseDist.block(false); } -void LensProfilePanel::setRawMeta(bool raw, const rtengine::ImageMetaData* pMeta) +void LensProfilePanel::setRawMeta(bool raw, const rtengine::FramesMetaData* pMeta) { if (!raw || pMeta->getFocusDist() <= 0) { disableListener(); diff --git a/rtgui/lensprofile.h b/rtgui/lensprofile.h index 9543721a0..4ccc4acf7 100644 --- a/rtgui/lensprofile.h +++ b/rtgui/lensprofile.h @@ -47,7 +47,7 @@ public: void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr); void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr); - void setRawMeta (bool raw, const rtengine::ImageMetaData* pMeta); + void setRawMeta (bool raw, const rtengine::FramesMetaData* pMeta); void onLCPFileChanged (); void onLCPFileReset (); diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index 9db7c69b6..320424bf1 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -227,14 +227,17 @@ rtengine::procparams::ProcParams* Thumbnail::createProcParamsForUpdate(bool retu if (!run_cpb) { if (defProf == DEFPROFILE_DYNAMIC && create && cfs && cfs->exifValid) { - rtengine::ImageMetaData* imageMetaData; + rtengine::FramesMetaData* imageMetaData; if (getType() == FT_Raw) { rtengine::RawMetaDataLocation metaData = rtengine::Thumbnail::loadMetaDataFromRaw(fname); - imageMetaData = rtengine::ImageMetaData::fromFile (fname, &metaData); + // Should we ask all frame's MetaData ? + imageMetaData = rtengine::FramesMetaData::fromFile (fname, &metaData, true); } else { - imageMetaData = rtengine::ImageMetaData::fromFile (fname, nullptr); + // Should we ask all frame's MetaData ? + imageMetaData = rtengine::FramesMetaData::fromFile (fname, nullptr, true); } PartialProfile *pp = ProfileStore::getInstance()->loadDynamicProfile(imageMetaData); + delete imageMetaData; int err = pp->pparams->save(outFName); pp->deleteInstance(); delete pp; @@ -249,13 +252,15 @@ rtengine::procparams::ProcParams* Thumbnail::createProcParamsForUpdate(bool retu } } else { // First generate the communication file, with general values and EXIF metadata - rtengine::ImageMetaData* imageMetaData; + rtengine::FramesMetaData* imageMetaData; if (getType() == FT_Raw) { rtengine::RawMetaDataLocation metaData = rtengine::Thumbnail::loadMetaDataFromRaw(fname); - imageMetaData = rtengine::ImageMetaData::fromFile (fname, &metaData); + // Should we ask all frame's MetaData ? + imageMetaData = rtengine::FramesMetaData::fromFile (fname, &metaData, true); } else { - imageMetaData = rtengine::ImageMetaData::fromFile (fname, nullptr); + // Should we ask all frame's MetaData ? + imageMetaData = rtengine::FramesMetaData::fromFile (fname, nullptr, true); } Glib::ustring tmpFileName( Glib::build_filename(options.cacheBaseDir, Glib::ustring::compose("CPB_temp_%1.txt", index++)) ); @@ -268,6 +273,7 @@ rtengine::procparams::ProcParams* Thumbnail::createProcParamsForUpdate(bool retu cfs, flaggingMode); } + delete imageMetaData; // For the filename etc. do NOT use streams, since they are not UTF8 safe Glib::ustring cmdLine = options.CPBPath + Glib::ustring(" \"") + tmpFileName + Glib::ustring("\""); @@ -284,8 +290,6 @@ rtengine::procparams::ProcParams* Thumbnail::createProcParamsForUpdate(bool retu } g_remove (tmpFileName.c_str ()); - - delete imageMetaData; } if (returnParams && hasProcParams()) { @@ -645,7 +649,7 @@ void Thumbnail::generateExifDateTimeStrings () return; } - exifString = Glib::ustring::compose ("f/%1 %2s %3%4 %5mm", Glib::ustring(rtengine::ImageData::apertureToString(cfs.fnumber)), Glib::ustring(rtengine::ImageData::shutterToString(cfs.shutter)), M("QINFO_ISO"), cfs.iso, Glib::ustring::format(std::setw(3), std::fixed, std::setprecision(2), cfs.focalLen)); + exifString = Glib::ustring::compose ("f/%1 %2s %3%4 %5mm", Glib::ustring(rtengine::FramesData::apertureToString(cfs.fnumber)), Glib::ustring(rtengine::FramesData::shutterToString(cfs.shutter)), M("QINFO_ISO"), cfs.iso, Glib::ustring::format(std::setw(3), std::fixed, std::setprecision(2), cfs.focalLen)); if (options.fbShowExpComp && cfs.expcomp != "0.00" && cfs.expcomp != "") { // don't show exposure compensation if it is 0.00EV;old cache iles do not have ExpComp, so value will not be displayed. exifString = Glib::ustring::compose ("%1 %2EV", exifString, cfs.expcomp); // append exposure compensation to exifString @@ -712,7 +716,7 @@ ThFileType Thumbnail::getType () int Thumbnail::infoFromImage (const Glib::ustring& fname, rtengine::RawMetaDataLocation* rml) { - rtengine::ImageMetaData* idata = rtengine::ImageMetaData::fromFile (fname, rml); + rtengine::FramesMetaData* idata = rtengine::FramesMetaData::fromFile (fname, rml); if (!idata) { return 0; @@ -723,24 +727,27 @@ int Thumbnail::infoFromImage (const Glib::ustring& fname, rtengine::RawMetaDataL cfs.exifValid = false; if (idata->hasExif()) { - cfs.shutter = idata->getShutterSpeed (); - cfs.fnumber = idata->getFNumber (); - cfs.focalLen = idata->getFocalLen (); + cfs.shutter = idata->getShutterSpeed (); + cfs.fnumber = idata->getFNumber (); + cfs.focalLen = idata->getFocalLen (); cfs.focalLen35mm = idata->getFocalLen35mm (); - cfs.focusDist = idata->getFocusDist (); - cfs.iso = idata->getISOSpeed (); - cfs.expcomp = idata->expcompToString (idata->getExpComp(), false); // do not mask Zero expcomp - cfs.year = 1900 + idata->getDateTime().tm_year; - cfs.month = idata->getDateTime().tm_mon + 1; - cfs.day = idata->getDateTime().tm_mday; - cfs.hour = idata->getDateTime().tm_hour; - cfs.min = idata->getDateTime().tm_min; - cfs.sec = idata->getDateTime().tm_sec; - cfs.timeValid = true; - cfs.exifValid = true; - cfs.lens = idata->getLens(); - cfs.camMake = idata->getMake(); - cfs.camModel = idata->getModel(); + cfs.focusDist = idata->getFocusDist (); + cfs.iso = idata->getISOSpeed (); + cfs.expcomp = idata->expcompToString (idata->getExpComp(), false); // do not mask Zero expcomp + cfs.isHDR = idata->getHDR (); + cfs.isPixelShift = idata->getPixelShift (); + cfs.sampleFormat = idata->getSampleFormat (); + cfs.year = 1900 + idata->getDateTime().tm_year; + cfs.month = idata->getDateTime().tm_mon + 1; + cfs.day = idata->getDateTime().tm_mday; + cfs.hour = idata->getDateTime().tm_hour; + cfs.min = idata->getDateTime().tm_min; + cfs.sec = idata->getDateTime().tm_sec; + cfs.timeValid = true; + cfs.exifValid = true; + cfs.lens = idata->getLens(); + cfs.camMake = idata->getMake(); + cfs.camModel = idata->getModel(); if (idata->getOrientation() == "Rotate 90 CW") { deg = 90; diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index b06463eff..8fde5a1de 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -510,7 +510,7 @@ void ToolPanelCoordinator::initImage (rtengine::StagedImageProcessor* ipc_, bool toneCurve->enableListener (); if (ipc) { - const rtengine::ImageMetaData* pMetaData = ipc->getInitialImage()->getMetaData(); + const rtengine::FramesMetaData* pMetaData = ipc->getInitialImage()->getMetaData(); exifpanel->setImageData (pMetaData); iptcpanel->setImageData (pMetaData); @@ -528,7 +528,7 @@ void ToolPanelCoordinator::initImage (rtengine::StagedImageProcessor* ipc_, bool ipc->setImageTypeListener (this); flatfield->setShortcutPath(Glib::path_get_dirname(ipc->getInitialImage()->getFileName())); - icm->setRawMeta (raw, (const rtengine::ImageData*)pMetaData); + icm->setRawMeta (raw, (const rtengine::FramesData*)pMetaData); lensProf->setRawMeta (raw, pMetaData); } @@ -677,7 +677,7 @@ rtengine::RawImage* ToolPanelCoordinator::getDF() return nullptr; } - const rtengine::ImageMetaData *imd = ipc->getInitialImage()->getMetaData(); + const rtengine::FramesMetaData *imd = ipc->getInitialImage()->getMetaData(); if(imd) { int iso = imd->getISOSpeed(); @@ -698,7 +698,7 @@ rtengine::RawImage* ToolPanelCoordinator::getFF() return nullptr; } - const rtengine::ImageMetaData *imd = ipc->getInitialImage()->getMetaData(); + const rtengine::FramesMetaData *imd = ipc->getInitialImage()->getMetaData(); if(imd) { // int iso = imd->getISOSpeed(); temporarilly removed because unused diff --git a/tools/source_icons/scalable/HDR-thumbnail.svg b/tools/source_icons/scalable/HDR-thumbnail.svg new file mode 100644 index 000000000..2b6d1a4bc --- /dev/null +++ b/tools/source_icons/scalable/HDR-thumbnail.svg @@ -0,0 +1,355 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/tools/source_icons/scalable/PixeShift-thumbnail.svg b/tools/source_icons/scalable/PixeShift-thumbnail.svg new file mode 100644 index 000000000..9e50ba9c1 --- /dev/null +++ b/tools/source_icons/scalable/PixeShift-thumbnail.svg @@ -0,0 +1,353 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + +