Add multi-frame handling.

- Exif of all frames are displayed in the Editor's Exif tab (without
separator)
- isHDR and isPixelShift is added to the data files stored in cache
- In the Editor panel, the QuickInfo frame display the HDR and
PixelShift information, as well as the number of frame and bit-depth for
HDR image
- the number of frame is provided by dcraw. If not set, it is provided
by the Exif's main IFD count
- the PixelShift information (for Pentax as of now) is provided by
looking at the Exif informations
- the HDR information is provided by the Exif information of the first
frame for Pentax raw files, or by the bitspersample, sampleformat and
compression tags for other files

TODO: add icons to the thumbnails to tag HDR and PixelShift files.
This commit is contained in:
Hombre57
2017-08-08 23:42:05 +02:00
parent b183a0b3c7
commit f23be9345c
45 changed files with 1529 additions and 265 deletions

View File

@@ -18,6 +18,7 @@
*/
#include <strings.h>
#include <glib/gstdio.h>
#include <tiff.h>
#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;
}
}