Solving issue 466: "DNG makerNote"
This commit is contained in:
299
rtexif/rtexif.h
299
rtexif/rtexif.h
@@ -24,19 +24,37 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include "../rtengine/procparams.h"
|
||||
|
||||
namespace rtexif {
|
||||
|
||||
enum TagType {INVALID=0, BYTE=1, ASCII=2, SHORT=3, LONG=4, RATIONAL=5, UNDEFINED=7, SSHORT=8, SLONG=9, SRATIONAL=10, FLOAT=11, DOUBLE=12, OLYUNDEF=13, SUBDIR=99};
|
||||
enum ActionCode {DONTWRITE=0, WRITE=1, SYSTEM=2};
|
||||
enum TagType {INVALID=0, BYTE=1, ASCII=2, SHORT=3, LONG=4, RATIONAL=5, UNDEFINED=7, SSHORT=8, SLONG=9, SRATIONAL=10, FLOAT=11, DOUBLE=12, OLYUNDEF=13, AUTO=98, SUBDIR=99};
|
||||
enum ActionCode {
|
||||
AC_DONTWRITE, // don't write it to the output
|
||||
AC_WRITE, // write it to the output
|
||||
AC_SYSTEM, // changed by RT (not editable/deletable) - don't write, don't show
|
||||
AC_NEW, // new addition - write, don't show
|
||||
|
||||
AC_INVALID=100, // invalid state
|
||||
};
|
||||
enum ByteOrder {INTEL=0x4949, MOTOROLA=0x4D4D};
|
||||
enum MNKind {NOMK, IFD, HEADERIFD, NIKON3, OLYMPUS2, FUJI,TABLESUBDIR};
|
||||
|
||||
bool extractLensInfo(std::string &fullname,double &minFocal, double &maxFocal, double &maxApertureAtMinFocal, double &maxApertureAtMaxFocal);
|
||||
|
||||
unsigned short sget2 (unsigned char *s, ByteOrder order);
|
||||
int sget4 (unsigned char *s, ByteOrder order);
|
||||
inline unsigned short get2 (FILE* f, ByteOrder order);
|
||||
inline int get4 (FILE* f, ByteOrder order);
|
||||
inline void sset2 (unsigned short v, unsigned char *s, ByteOrder order);
|
||||
inline void sset4 (int v, unsigned char *s, ByteOrder order);
|
||||
inline float int_to_float (int i);
|
||||
short int int2_to_signed (short unsigned int i);
|
||||
|
||||
|
||||
struct TIFFHeader {
|
||||
|
||||
unsigned short byteOrder;
|
||||
@@ -47,18 +65,24 @@ struct TIFFHeader {
|
||||
class Tag;
|
||||
class Interpreter;
|
||||
|
||||
// structure of informations describing an exif tag
|
||||
/// Structure of informations describing an Exif tag
|
||||
struct TagAttrib {
|
||||
int ignore; // =0: never ignore, =1: always ignore, =2: ignore if the subdir type is reduced image, =-1: end of table
|
||||
int action; //=0: dont write it to the output, =1: write it to the output, =2: dont write, dont show, =3: write, dont show
|
||||
ActionCode action;
|
||||
int editable;
|
||||
const TagAttrib* subdirAttribs; // =0 ->not subdir
|
||||
unsigned short ID; // Numeric identifier of tag (or index inside DirectoryTable)
|
||||
const TagAttrib* subdirAttribs; // !NULL if this tag points to a subdir
|
||||
/** Numeric identifier of tag (or index inside DirectoryTable)
|
||||
To avoid rewriting all the tables, and to address the problem of TagDirectoryTable with heterogeneous tag's type,
|
||||
this parameter is now an unsigned int, where the leftmost 2 bytes represent the tag's type, which by default will be aqual
|
||||
to 0 (INVALID). Only non null tag type will be used. See nikon attrib for an example
|
||||
*/
|
||||
unsigned short ID;
|
||||
TagType type;
|
||||
const char* name;
|
||||
Interpreter* interpreter;
|
||||
Interpreter* interpreter; // Call back hook
|
||||
};
|
||||
|
||||
// a directory of tags
|
||||
/// A directory of tags
|
||||
class TagDirectory {
|
||||
|
||||
protected:
|
||||
@@ -66,7 +90,7 @@ class TagDirectory {
|
||||
const TagAttrib* attribs; // descriptor table to decode the tags
|
||||
ByteOrder order; // byte order
|
||||
TagDirectory* parent; // parent directory (NULL if root)
|
||||
|
||||
|
||||
public:
|
||||
TagDirectory ();
|
||||
TagDirectory (TagDirectory* p, FILE* f, int base, const TagAttrib* ta, ByteOrder border, bool skipIgnored=true);
|
||||
@@ -78,10 +102,12 @@ class TagDirectory {
|
||||
TagDirectory* getRoot ();
|
||||
inline int getCount () const { return tags.size (); }
|
||||
const TagAttrib* getAttrib (int id);
|
||||
const TagAttrib* getAttrib (const char* name);
|
||||
const TagAttrib* getAttrib (const char* name); // Find a Tag by scanning the whole tag tree and stopping at the first occurrence
|
||||
const TagAttrib* getAttribP (const char* name); // Try to get the Tag at a given location. 'name' is a path relative to this directory (e.g. "LensInfo/FocalLength")
|
||||
const TagAttrib* getAttribTable() { return attribs; }
|
||||
virtual Tag* getTag (const char* name) const;
|
||||
virtual Tag* getTag (int ID) const;
|
||||
Tag* getTag (const char* name) const; // Find a Tag by scanning the whole tag tree and stopping at the first occurrence
|
||||
Tag* getTagP (const char* name) const; // Try to get the Tag at a given location. 'name' is a path relative to this directory (e.g. "LensInfo/FocalLength")
|
||||
Tag* getTag (int ID) const;
|
||||
virtual Tag* findTag (const char* name) const;
|
||||
bool getXMPTagValue(const char* name, char* value) const;
|
||||
|
||||
@@ -97,7 +123,7 @@ class TagDirectory {
|
||||
virtual TagDirectory* clone (TagDirectory* parent);
|
||||
virtual void applyChange (std::string field, std::string value);
|
||||
|
||||
virtual void printAll () const;
|
||||
virtual void printAll (unsigned int level=0) const; // reentrant debug function, keep level=0 on first call !
|
||||
virtual void sort ();
|
||||
};
|
||||
|
||||
@@ -134,7 +160,8 @@ class Tag {
|
||||
TagDirectory* parent;
|
||||
TagDirectory** directory;
|
||||
MNKind makerNoteKind;
|
||||
|
||||
bool parseMakerNote(FILE* f, int base, ByteOrder bom );
|
||||
|
||||
public:
|
||||
Tag (TagDirectory* parent, FILE* f, int base); // parse next tag from the file
|
||||
Tag (TagDirectory* parent, const TagAttrib* attr);
|
||||
@@ -154,7 +181,7 @@ class Tag {
|
||||
// get basic tag properties
|
||||
int getID () const { return tag; }
|
||||
int getCount () const { return count; }
|
||||
TagType getType () const { return type; }
|
||||
TagType getType () const { return (attrib && attrib->type > INVALID && attrib->type < AUTO) ? attrib->type : type; }
|
||||
unsigned char* getValue () const { return value; }
|
||||
const TagAttrib* getAttrib () const { return attrib; }
|
||||
inline ByteOrder getOrder () const { return parent ? parent->getOrder() : INTEL; }
|
||||
@@ -163,15 +190,17 @@ class Tag {
|
||||
bool getOwnMemory() const { return allocOwnMemory; }
|
||||
|
||||
// read/write value
|
||||
int toInt (int ofs=0, TagType astype=INVALID);
|
||||
void fromInt (int v);
|
||||
double toDouble (int ofs=0);
|
||||
void toRational (int& num, int& denom, int ofs=0);
|
||||
void toString (char* buffer, int ofs=0);
|
||||
void fromString (const char* v, int size=-1);
|
||||
void setInt (int v, int ofs=0, TagType astype=LONG);
|
||||
int toInt (int ofs=0, TagType astype=INVALID);
|
||||
void fromInt (int v);
|
||||
double toDouble (int ofs=0);
|
||||
double *toDoubleArray (int ofs=0);
|
||||
void toRational (int& num, int& denom, int ofs=0);
|
||||
void toString (char* buffer, int ofs=0);
|
||||
void fromString (const char* v, int size=-1);
|
||||
void setInt (int v, int ofs=0, TagType astype=LONG);
|
||||
|
||||
// additional getter/setter for more confortable use
|
||||
|
||||
// additional getter/setter for more comfortable use
|
||||
std::string valueToString ();
|
||||
std::string nameToString (int i=0);
|
||||
void valueFromString (const std::string& value);
|
||||
@@ -213,22 +242,15 @@ class Interpreter {
|
||||
public:
|
||||
Interpreter () {}
|
||||
virtual ~Interpreter() {};
|
||||
virtual std::string toString (Tag* t) { return ""; }
|
||||
virtual void fromString (Tag* t, const std::string& value) {}
|
||||
};
|
||||
|
||||
class StdInterpreter : public Interpreter {
|
||||
public:
|
||||
StdInterpreter () {}
|
||||
virtual std::string toString (Tag* t) {
|
||||
char buffer[1024];
|
||||
char buffer[1024];
|
||||
t->toString (buffer);
|
||||
std::string s(buffer);
|
||||
std::string::size_type p1 = s.find_first_not_of(' ');
|
||||
if( p1 == std::string::npos )
|
||||
return s;
|
||||
return s;
|
||||
else
|
||||
return s.substr(p1, s.find_last_not_of(' ')-p1+1);
|
||||
return s.substr(p1, s.find_last_not_of(' ')-p1+1);
|
||||
}
|
||||
virtual void fromString (Tag* t, const std::string& value) {
|
||||
if (t->getType()==SHORT || t->getType()==LONG)
|
||||
@@ -236,8 +258,46 @@ class StdInterpreter : public Interpreter {
|
||||
else
|
||||
t->fromString (value.c_str());
|
||||
}
|
||||
// Get the value as a double
|
||||
virtual double toDouble(Tag* t, int ofs=0) {
|
||||
double ud, dd;
|
||||
switch (t->getType()) {
|
||||
case BYTE: return (double)((int)t->getValue()[ofs]);
|
||||
case ASCII: return 0.0;
|
||||
case SSHORT:return (double)int2_to_signed(sget2 (t->getValue()+ofs, t->getOrder()));
|
||||
case SHORT: return (double)((int)sget2 (t->getValue()+ofs, t->getOrder()));
|
||||
case SLONG:
|
||||
case LONG: return (double)((int)sget4 (t->getValue()+ofs, t->getOrder()));
|
||||
case SRATIONAL:
|
||||
case RATIONAL: ud = (int)sget4 (t->getValue()+ofs, t->getOrder()); dd = (int)sget4 (t->getValue()+ofs+4, t->getOrder()); return dd==0. ? 0. : (double)ud / (double)dd;
|
||||
case FLOAT: return double(sget4 (t->getValue()+ofs, t->getOrder()));
|
||||
case UNDEFINED: return 0.;
|
||||
default: return 0.; // Quick fix for missing cases (INVALID, DOUBLE, OLYUNDEF, SUBDIR)
|
||||
}
|
||||
}
|
||||
// Get the value as an int
|
||||
virtual int toInt (Tag* t, int ofs=0, TagType astype=INVALID) {
|
||||
int a;
|
||||
if (astype == INVALID || astype==AUTO)
|
||||
astype = t->getType();
|
||||
switch (astype) {
|
||||
case BYTE: return t->getValue()[ofs];
|
||||
case ASCII: return 0;
|
||||
case SSHORT:return (int)int2_to_signed(sget2 (t->getValue()+ofs, t->getOrder()));
|
||||
case SHORT: return (int)sget2 (t->getValue()+ofs, t->getOrder());
|
||||
case SLONG:
|
||||
case LONG: return (int)sget4 (t->getValue()+ofs, t->getOrder());
|
||||
case SRATIONAL:
|
||||
case RATIONAL: a = (int)sget4 (t->getValue()+ofs+4, t->getOrder()); return a==0 ? 0 : (int)sget4 (t->getValue()+ofs, t->getOrder()) / a;
|
||||
case FLOAT: return (int)toDouble(t, ofs);
|
||||
case UNDEFINED: return 0;
|
||||
default: return 0; // Quick fix for missing cases (INVALID, DOUBLE, OLYUNDEF, SUBDIR)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
extern StdInterpreter stdInterpreter;
|
||||
|
||||
extern Interpreter stdInterpreter;
|
||||
class ChoiceInterpreter : public Interpreter {
|
||||
protected:
|
||||
std::map<int,std::string> choices;
|
||||
@@ -248,7 +308,7 @@ class ChoiceInterpreter : public Interpreter {
|
||||
if (r!=choices.end())
|
||||
return r->second;
|
||||
else {
|
||||
char buffer[1024];
|
||||
char buffer[1024];
|
||||
t->toString (buffer);
|
||||
return std::string (buffer);
|
||||
}
|
||||
@@ -258,92 +318,109 @@ class ChoiceInterpreter : public Interpreter {
|
||||
template< class T >
|
||||
class IntLensInterpreter : public Interpreter {
|
||||
protected:
|
||||
typedef std::multimap< T, std::string> container_t;
|
||||
typedef typename std::multimap< T, std::string>::iterator it_t;
|
||||
typedef std::pair< T, std::string> p_t;
|
||||
container_t choices;
|
||||
typedef std::multimap< T, std::string> container_t;
|
||||
typedef typename std::multimap< T, std::string>::iterator it_t;
|
||||
typedef std::pair< T, std::string> p_t;
|
||||
container_t choices;
|
||||
|
||||
virtual std::string guess(const T lensID, double focalLength, double maxApertureAtFocal )
|
||||
{
|
||||
it_t r;
|
||||
size_t nFound = choices.count( lensID );
|
||||
virtual std::string guess(const T lensID, double focalLength, double maxApertureAtFocal, double *lensInfoArray) {
|
||||
it_t r;
|
||||
size_t nFound = choices.count( lensID );
|
||||
|
||||
switch( nFound )
|
||||
{
|
||||
case 0: // lens Unknown
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << lensID;
|
||||
return s.str();
|
||||
}
|
||||
case 1: // lens found
|
||||
r = choices.find ( lensID );
|
||||
return r->second;
|
||||
default:
|
||||
// More than one hit: we must guess
|
||||
break;
|
||||
}
|
||||
switch( nFound ) {
|
||||
case 0: // lens Unknown
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << lensID;
|
||||
return s.str();
|
||||
}
|
||||
case 1: // lens found
|
||||
r = choices.find ( lensID );
|
||||
return r->second;
|
||||
default:
|
||||
// More than one hit: we must guess
|
||||
break;
|
||||
}
|
||||
|
||||
std::string bestMatch("Unknown");
|
||||
double a1,a2,f1,f2;
|
||||
|
||||
double deltaMin = 1000.;
|
||||
/* FIRST TRY
|
||||
*
|
||||
* Get the lens info (min/man focal, min/max aperture) and compare them to the possible choice
|
||||
*/
|
||||
if (lensInfoArray) {
|
||||
for ( r = choices.lower_bound( lensID ); r != choices.upper_bound(lensID); r++ ){
|
||||
if( !extractLensInfo( r->second ,f1,f2,a1,a2) )
|
||||
continue;
|
||||
if (f1==lensInfoArray[0] && f2==lensInfoArray[1] && a1==lensInfoArray[2] && a2==lensInfoArray[3])
|
||||
// can't match better! we take this entry as being the one
|
||||
return r->second;
|
||||
}
|
||||
// No lens found, we update the "unknown" string with the lens info values
|
||||
if (lensInfoArray[0]==lensInfoArray[1])
|
||||
bestMatch += Glib::ustring::compose(" (%1mm", int(lensInfoArray[0]));
|
||||
else
|
||||
bestMatch += Glib::ustring::compose(" (%1-%2mm", int(lensInfoArray[0]), int(lensInfoArray[1]));
|
||||
|
||||
/* Choose the best match: thanks to exiftool by Phil Harvey
|
||||
* first throws for "out of focal range" and lower or upper aperture of the lens compared to MaxApertureAtFocal
|
||||
* if the lens is not constant aperture, calculate aprox. aperture of the lens at focalLength
|
||||
* and compare with actual aperture.
|
||||
*/
|
||||
std::string bestMatch("Unknown");
|
||||
std::ostringstream candidates;
|
||||
for ( r = choices.lower_bound( lensID ); r != choices.upper_bound(lensID); r++ ){
|
||||
double a1,a2,f1,f2,lensAperture,dif;
|
||||
if (lensInfoArray[2]==lensInfoArray[3])
|
||||
bestMatch += Glib::ustring::compose(" f/%1)", Glib::ustring::format(std::fixed, std::setprecision(1), lensInfoArray[2]));
|
||||
else
|
||||
bestMatch += Glib::ustring::compose(" f/%1-%2)",
|
||||
Glib::ustring::format(std::fixed, std::setprecision(1), lensInfoArray[2]),
|
||||
Glib::ustring::format(std::fixed, std::setprecision(1), lensInfoArray[3]));
|
||||
}
|
||||
|
||||
if( !extractLensInfo( r->second ,f1,f2,a1,a2) )
|
||||
continue;
|
||||
if( f1 == 0. || a1 == 0.)
|
||||
continue;
|
||||
/* SECOND TRY
|
||||
*
|
||||
* Choose the best match: thanks to exiftool by Phil Harvey
|
||||
* first throws for "out of focal range" and lower or upper aperture of the lens compared to MaxApertureAtFocal
|
||||
* if the lens is not constant aperture, calculate aprox. aperture of the lens at focalLength
|
||||
* and compare with actual aperture.
|
||||
*/
|
||||
std::ostringstream candidates;
|
||||
double deltaMin = 1000.;
|
||||
for ( r = choices.lower_bound( lensID ); r != choices.upper_bound(lensID); r++ ){
|
||||
double lensAperture,dif;
|
||||
|
||||
if( focalLength < f1 - .5 || focalLength > f2 + 0.5 )
|
||||
continue;
|
||||
if( maxApertureAtFocal > 0.1){
|
||||
if( maxApertureAtFocal < a1 - 0.15 || maxApertureAtFocal > a2 +0.15)
|
||||
continue;
|
||||
if( !extractLensInfo( r->second ,f1,f2,a1,a2) )
|
||||
continue;
|
||||
if( f1 == 0. || a1 == 0.)
|
||||
continue;
|
||||
|
||||
if( a1 == a2 || f1 == f2)
|
||||
lensAperture = a1;
|
||||
else
|
||||
lensAperture = exp( log(a1)+(log(a2)-log(a1))/(log(f2)-log(f1))*(log(focalLength)-log(f1)) );
|
||||
if( focalLength < f1 - .5 || focalLength > f2 + 0.5 )
|
||||
continue;
|
||||
if( maxApertureAtFocal > 0.1){
|
||||
if( maxApertureAtFocal < a1 - 0.15 || maxApertureAtFocal > a2 +0.15)
|
||||
continue;
|
||||
|
||||
dif = abs(lensAperture - maxApertureAtFocal);
|
||||
}else
|
||||
dif = 0;
|
||||
if( dif < deltaMin ){
|
||||
deltaMin = dif;
|
||||
bestMatch = r->second;
|
||||
}
|
||||
if( dif < 0.15){
|
||||
if( candidates.tellp() )
|
||||
candidates << "\n or " << r->second;
|
||||
else
|
||||
candidates << r->second;
|
||||
}
|
||||
if( a1 == a2 || f1 == f2)
|
||||
lensAperture = a1;
|
||||
else
|
||||
lensAperture = exp( log(a1)+(log(a2)-log(a1))/(log(f2)-log(f1))*(log(focalLength)-log(f1)) );
|
||||
|
||||
}
|
||||
if( !candidates.tellp() )
|
||||
return bestMatch;
|
||||
else
|
||||
return candidates.str();
|
||||
}
|
||||
dif = abs(lensAperture - maxApertureAtFocal);
|
||||
}else
|
||||
dif = 0;
|
||||
if( dif < deltaMin ){
|
||||
deltaMin = dif;
|
||||
bestMatch = r->second;
|
||||
}
|
||||
if( dif < 0.15){
|
||||
if( candidates.tellp() )
|
||||
candidates << "\n or " << r->second;
|
||||
else
|
||||
candidates << r->second;
|
||||
}
|
||||
}
|
||||
if( !candidates.tellp() )
|
||||
return bestMatch;
|
||||
else
|
||||
return candidates.str();
|
||||
}
|
||||
};
|
||||
|
||||
inline int getTypeSize( TagType type );
|
||||
inline unsigned short sget2 (unsigned char *s, ByteOrder order);
|
||||
inline int sget4 (unsigned char *s, ByteOrder order);
|
||||
inline unsigned short get2 (FILE* f, ByteOrder order);
|
||||
inline int get4 (FILE* f, ByteOrder order);
|
||||
inline void sset2 (unsigned short v, unsigned char *s, ByteOrder order);
|
||||
inline void sset4 (int v, unsigned char *s, ByteOrder order);
|
||||
inline float int_to_float (int i);
|
||||
inline short int int2_to_signed (short unsigned int i);
|
||||
|
||||
extern const TagAttrib exifAttribs[];
|
||||
extern const TagAttrib gpsAttribs[];
|
||||
@@ -354,6 +431,7 @@ extern const TagAttrib nikon3Attribs[];
|
||||
extern const TagAttrib canonAttribs[];
|
||||
extern const TagAttrib pentaxAttribs[];
|
||||
extern const TagAttrib pentaxLensDataAttribs[];
|
||||
extern const TagAttrib pentaxLensInfoQAttribs[];
|
||||
extern const TagAttrib pentaxAEInfoAttribs[];
|
||||
extern const TagAttrib pentaxCameraSettingsAttribs[];
|
||||
extern const TagAttrib pentaxFlashInfoAttribs[];
|
||||
@@ -363,8 +441,13 @@ extern const TagAttrib pentaxCameraInfoAttribs[];
|
||||
extern const TagAttrib fujiAttribs[];
|
||||
extern const TagAttrib minoltaAttribs[];
|
||||
extern const TagAttrib sonyAttribs[];
|
||||
extern const TagAttrib sonyTag9405Attribs[];
|
||||
extern const TagAttrib sonyCameraInfoAttribs[];
|
||||
extern const TagAttrib sonyCameraInfo2Attribs[];
|
||||
extern const TagAttrib sonyCameraSettingsAttribs[];
|
||||
extern const TagAttrib sonyCameraSettingsAttribs2[];
|
||||
extern const TagAttrib sonyCameraSettingsAttribs3[];
|
||||
//extern const TagAttrib sonyDNGMakerNote[];
|
||||
extern const TagAttrib olympusAttribs[];
|
||||
}
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user