Pentax and Sony EXIF Tags decoding
New class TagDirectoryTable to support array of tags class Tag has a property allocOwnMemory to reference external memory (saved by parent directory) Pentax LensID support deconding of compatible lens with same number, by guessing. Exifpanel add array of tags as SYSTEM. Reordered stdattribs by tagID.
This commit is contained in:
310
rtexif/rtexif.cc
310
rtexif/rtexif.cc
@@ -99,6 +99,11 @@ void TagDirectory::sort () {
|
||||
for (int j=0; tags[i]->getDirectory(j); j++)
|
||||
tags[i]->getDirectory(j)->sort ();
|
||||
}
|
||||
TagDirectory* TagDirectory::getRoot()
|
||||
{
|
||||
if(parent) return parent->getRoot();
|
||||
else return this;
|
||||
}
|
||||
|
||||
const TagAttrib* TagDirectory::getAttrib (int id) {
|
||||
|
||||
@@ -185,6 +190,24 @@ Tag* TagDirectory::getTag (const char* name) const {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Tag* TagDirectory::findTag (const char* name) const {
|
||||
if (attribs) {
|
||||
for (int i=0; attribs[i].ignore!=-1; i++)
|
||||
if (!strcmp (attribs[i].name, name)){
|
||||
Tag* t= getTag (attribs[i].ID);
|
||||
if(t) return t;
|
||||
else break;
|
||||
}
|
||||
}
|
||||
for (int i=0; i<tags.size(); i++)
|
||||
if(tags[i]->isDirectory()){
|
||||
TagDirectory *dir = tags[i]->getDirectory();
|
||||
Tag* t=dir->findTag(name);
|
||||
if(t) return t;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int TagDirectory::calculateSize () {
|
||||
|
||||
int size = 2; // space to store the number of tags
|
||||
@@ -310,12 +333,63 @@ void TagDirectory::applyChange (std::string name, std::string value) {
|
||||
}
|
||||
}
|
||||
|
||||
TagDirectoryTable::TagDirectoryTable ()
|
||||
:valuesSize(0),zeroOffset(0)
|
||||
{
|
||||
}
|
||||
|
||||
TagDirectoryTable::TagDirectoryTable (TagDirectory* p, unsigned char *v,int memsize,int offs, TagType type, const TagAttrib* ta, ByteOrder border)
|
||||
:TagDirectory(p,ta,border),valuesSize(memsize),zeroOffset(offs),defaultType( type )
|
||||
{
|
||||
values = new unsigned char[valuesSize];
|
||||
memcpy(values,v,valuesSize);
|
||||
for( const TagAttrib* tattr = ta; tattr->ignore != -1; tattr++){
|
||||
Tag* newTag = new Tag (this, tattr, (values + zeroOffset+ tattr->ID*getTypeSize(type)),type);
|
||||
tags.push_back(newTag); // Here we can insert more tag in the same offset because of bitfield meaning
|
||||
}
|
||||
}
|
||||
|
||||
TagDirectoryTable::TagDirectoryTable (TagDirectory* p, FILE* f, int memsize,int offs, TagType type, const TagAttrib* ta, ByteOrder border)
|
||||
:TagDirectory(p,ta,border),valuesSize(memsize),zeroOffset(offs),defaultType( type )
|
||||
{
|
||||
values = new unsigned char[valuesSize];
|
||||
fread (values, 1, valuesSize, f);
|
||||
|
||||
for( const TagAttrib* tattr = ta; tattr->ignore != -1; tattr++){
|
||||
Tag* newTag = new Tag (this, tattr, (values + zeroOffset+ tattr->ID*getTypeSize(type)),type);
|
||||
tags.push_back(newTag); // Here we can insert more tag in the same offset because of bitfield meaning
|
||||
}
|
||||
}
|
||||
TagDirectory* TagDirectoryTable::clone (TagDirectory* parent) {
|
||||
|
||||
TagDirectory* td = new TagDirectoryTable (parent,values,valuesSize,zeroOffset,defaultType, attribs, order);
|
||||
return td;
|
||||
}
|
||||
|
||||
TagDirectoryTable::~TagDirectoryTable()
|
||||
{
|
||||
if(values)
|
||||
delete [] values;
|
||||
}
|
||||
int TagDirectoryTable::calculateSize ()
|
||||
{
|
||||
return valuesSize;
|
||||
}
|
||||
|
||||
int TagDirectoryTable::write (int start, unsigned char* buffer) {
|
||||
if( values && valuesSize){
|
||||
memcpy(buffer+start,values,valuesSize);
|
||||
return start+valuesSize;
|
||||
}else
|
||||
return start;
|
||||
}
|
||||
|
||||
//--------------- class Tag ---------------------------------------------------
|
||||
// this class represents a tag stored in the directory
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
Tag::Tag (TagDirectory* p, FILE* f, int base)
|
||||
: parent(p), value(NULL), directory(NULL), count(0), attrib(NULL), type(INVALID) {
|
||||
: parent(p), value(NULL), directory(NULL), count(0), attrib(NULL), type(INVALID),allocOwnMemory(true) {
|
||||
|
||||
tag = get2 (f, getOrder());
|
||||
type = (TagType)get2 (f, getOrder());
|
||||
@@ -334,7 +408,7 @@ Tag::Tag (TagDirectory* p, FILE* f, int base)
|
||||
int save = ftell(f) + 4;
|
||||
|
||||
// load value field (possibly seek before)
|
||||
valuesize = count * ("11124811248484"[type<14?type:0]-'0');
|
||||
valuesize = count * getTypeSize(type);
|
||||
|
||||
if (valuesize > 4)
|
||||
fseek (f, get4(f, getOrder()) + base, SEEK_SET);
|
||||
@@ -453,44 +527,103 @@ Tag::Tag (TagDirectory* p, FILE* f, int base)
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (type==UNDEFINED && attrib && attrib->subdirAttribs) {
|
||||
count = 1;
|
||||
type = LONG;
|
||||
directory = new TagDirectory*[2];
|
||||
directory[0] = new TagDirectory (parent, f, base, attrib->subdirAttribs, getOrder());
|
||||
directory[1] = NULL;
|
||||
else if (attrib && attrib->subdirAttribs) {
|
||||
// Some subdirs are specific of maker and model
|
||||
char make[128], model[128];
|
||||
Tag* tmake = parent->getRoot()->getTag ("Make");
|
||||
if (tmake) tmake->toString (make);
|
||||
else make[0] = 0;
|
||||
Tag* tmodel = parent->getRoot()->getTag ("Model");
|
||||
if (tmodel) tmodel->toString (model);
|
||||
else model[0] = 0;
|
||||
|
||||
|
||||
if (!strncmp(make, "SONY", 4)) {
|
||||
switch( tag ){
|
||||
case 0x0114:
|
||||
{
|
||||
directory = new TagDirectory*[2];
|
||||
directory[1] = NULL;
|
||||
if( strstr(model, "A330") || strstr(model, "A380") )
|
||||
directory[0] = new TagDirectoryTable (parent, f, valuesize*2,0,SHORT , sonyCameraSettingsAttribs2, MOTOROLA);
|
||||
else
|
||||
directory[0] = new TagDirectoryTable (parent, f, valuesize*2,0,SHORT , sonyCameraSettingsAttribs, MOTOROLA);
|
||||
makerNoteKind = TABLESUBDIR;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto defsubdirs;
|
||||
}
|
||||
}else if (!strncmp(make, "PENTAX", 6)) {
|
||||
switch( tag ){
|
||||
case 0x005c:
|
||||
case 0x0205:
|
||||
case 0x0206:
|
||||
case 0x0208:
|
||||
case 0x0216:
|
||||
directory = new TagDirectory*[2];
|
||||
directory[1] = NULL;
|
||||
directory[0] = new TagDirectoryTable (parent, f, valuesize,0,BYTE , attrib->subdirAttribs, getOrder());
|
||||
makerNoteKind = TABLESUBDIR;
|
||||
break;
|
||||
case 0x0207:
|
||||
{ // There are 2 format pentaxLensDataAttribs
|
||||
int offsetFirst = 4;
|
||||
if( strstr(model, "*ist") || strstr(model, "GX-1") || strstr(model, "K100D") || strstr(model, "K110D") )
|
||||
offsetFirst = 3;
|
||||
directory = new TagDirectory*[2];
|
||||
directory[1] = NULL;
|
||||
directory[0] = new TagDirectoryTable (parent, f, valuesize,offsetFirst,BYTE , attrib->subdirAttribs, getOrder());
|
||||
makerNoteKind = TABLESUBDIR;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto defsubdirs;
|
||||
}
|
||||
}else if(type==UNDEFINED){
|
||||
count = 1;
|
||||
type = LONG;
|
||||
directory[0] = new TagDirectory (parent, f, base, attrib->subdirAttribs, getOrder());
|
||||
}else
|
||||
goto defsubdirs;
|
||||
}
|
||||
else {
|
||||
// read value
|
||||
value = new unsigned char [valuesize];
|
||||
fread (value, 1, valuesize, f);
|
||||
|
||||
// if it is a subdirectory, load it (there may be several directories if count>1)
|
||||
if (attrib && attrib->subdirAttribs) {
|
||||
int pos = ftell (f);
|
||||
// count the number of valid subdirs
|
||||
int sdcount = count;
|
||||
if (sdcount>0) {
|
||||
if (parent->getAttribTable()==olympusAttribs)
|
||||
sdcount = 1;
|
||||
// allocate space
|
||||
directory = new TagDirectory*[sdcount+1];
|
||||
// load directories
|
||||
for (int j=0,i=0; j<count; j++,i++) {
|
||||
int newpos = base + toInt(j*4, LONG);
|
||||
fseek (f, newpos, SEEK_SET);
|
||||
directory[i] = new TagDirectory (parent, f, base, attrib->subdirAttribs, getOrder());
|
||||
fseek (f, pos, SEEK_SET);
|
||||
}
|
||||
// set the terminating NULL
|
||||
directory[sdcount] = NULL;
|
||||
}
|
||||
else
|
||||
type = INVALID;
|
||||
}
|
||||
}
|
||||
// seek back to the saved position
|
||||
fseek (f, save, SEEK_SET);
|
||||
return;
|
||||
defsubdirs:
|
||||
// read value
|
||||
value = new unsigned char [valuesize];
|
||||
fread (value, 1, valuesize, f);
|
||||
int pos = ftell (f);
|
||||
// count the number of valid subdirs
|
||||
int sdcount = count;
|
||||
if (sdcount>0) {
|
||||
if (parent->getAttribTable()==olympusAttribs)
|
||||
sdcount = 1;
|
||||
// allocate space
|
||||
directory = new TagDirectory*[sdcount+1];
|
||||
// load directories
|
||||
for (int j=0,i=0; j<count; j++,i++) {
|
||||
int newpos = base + toInt(j*4, LONG);
|
||||
fseek (f, newpos, SEEK_SET);
|
||||
directory[i] = new TagDirectory (parent, f, base, attrib->subdirAttribs, getOrder());
|
||||
fseek (f, pos, SEEK_SET);
|
||||
}
|
||||
// set the terminating NULL
|
||||
directory[sdcount] = NULL;
|
||||
}
|
||||
else
|
||||
type = INVALID;
|
||||
|
||||
// seek back to the saved position
|
||||
fseek (f, save, SEEK_SET);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
Tag* Tag::clone (TagDirectory* parent) {
|
||||
@@ -525,7 +658,7 @@ Tag* Tag::clone (TagDirectory* parent) {
|
||||
Tag::~Tag () {
|
||||
|
||||
// delete value
|
||||
if (value)
|
||||
if (value && allocOwnMemory)
|
||||
delete [] value;
|
||||
|
||||
// if there are directories behind the tag, delete them
|
||||
@@ -559,13 +692,15 @@ void Tag::fromInt (int v) {
|
||||
|
||||
void Tag::fromString (const char* v, int size) {
|
||||
|
||||
delete value;
|
||||
if( value && allocOwnMemory)
|
||||
delete [] value;
|
||||
if (size<0)
|
||||
valuesize = strlen (v) + 1;
|
||||
else
|
||||
valuesize = size;
|
||||
count = valuesize;
|
||||
value = new unsigned char [valuesize];
|
||||
if( allocOwnMemory )
|
||||
value = new unsigned char [valuesize];
|
||||
memcpy ((char*)value, v, valuesize);
|
||||
}
|
||||
|
||||
@@ -720,7 +855,6 @@ int Tag::calculateSize () {
|
||||
size += valuesize;
|
||||
else if (makerNoteKind==HEADERIFD)
|
||||
size += valuesize;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
@@ -770,6 +904,11 @@ int Tag::write (int offs, int dataOffs, unsigned char* buffer) {
|
||||
dataOffs += directory[0]->write (dataOffs, buffer);
|
||||
return dataOffs;
|
||||
}
|
||||
else if( makerNoteKind==TABLESUBDIR){
|
||||
sset4 (dataOffs, buffer+offs, parent->getOrder());
|
||||
dataOffs = directory[0]->write (dataOffs, buffer);
|
||||
return dataOffs;
|
||||
}
|
||||
else if (!directory[1]) {
|
||||
sset4 (dataOffs, buffer+offs, parent->getOrder());
|
||||
return directory[0]->write (dataOffs, buffer);
|
||||
@@ -790,21 +929,37 @@ int Tag::write (int offs, int dataOffs, unsigned char* buffer) {
|
||||
}
|
||||
|
||||
Tag::Tag (TagDirectory* p, const TagAttrib* attr)
|
||||
: parent(p), attrib(attr), makerNoteKind (NOMK), directory(NULL), keep(true), tag(attr ? attr->ID : -1), count(0), valuesize(0), value(NULL), type(INVALID) {
|
||||
: parent(p), attrib(attr), makerNoteKind (NOMK), directory(NULL), keep(true), tag(attr ? attr->ID : -1), count(0), valuesize(0), value(NULL), type(INVALID),allocOwnMemory(true) {
|
||||
}
|
||||
|
||||
Tag::Tag (TagDirectory* p, const TagAttrib* attr, int data, TagType t)
|
||||
: parent(p), attrib(attr), makerNoteKind (NOMK), directory(NULL), keep(true), tag(attr ? attr->ID : -1), count(1), valuesize(0), value(NULL), type(t) {
|
||||
: parent(p), attrib(attr), makerNoteKind (NOMK), directory(NULL), keep(true), tag(attr ? attr->ID : -1), count(1), valuesize(0), value(NULL), type(t),allocOwnMemory(true) {
|
||||
|
||||
initInt (data, t);
|
||||
}
|
||||
|
||||
Tag::Tag (TagDirectory* p, const TagAttrib* attr, unsigned char *data, TagType t)
|
||||
: parent(p), attrib(attr), makerNoteKind (NOMK), directory(NULL), keep(true), tag(attr ? attr->ID : -1), count(1), valuesize(0), value(NULL), type(t),allocOwnMemory(false) {
|
||||
|
||||
initType (data, t);
|
||||
}
|
||||
|
||||
Tag::Tag (TagDirectory* p, const TagAttrib* attr, const char* text)
|
||||
: parent(p), attrib(attr), makerNoteKind (NOMK), directory(NULL), keep(true), tag(attr ? attr->ID : -1), count(1), valuesize(0), value(NULL), type(ASCII) {
|
||||
: parent(p), attrib(attr), makerNoteKind (NOMK), directory(NULL), keep(true), tag(attr ? attr->ID : -1), count(1), valuesize(0), value(NULL), type(ASCII),allocOwnMemory(true) {
|
||||
|
||||
initString (text);
|
||||
}
|
||||
|
||||
void Tag::initType (unsigned char *data, TagType type)
|
||||
{
|
||||
valuesize = getTypeSize(type);
|
||||
if( allocOwnMemory ){
|
||||
value = new unsigned char[valuesize];
|
||||
memcpy ((char*)value, data, valuesize);
|
||||
}else
|
||||
value = data;
|
||||
}
|
||||
|
||||
void Tag::initInt (int data, TagType t, int cnt) {
|
||||
|
||||
type = t;
|
||||
@@ -1382,6 +1537,13 @@ short int int2_to_signed (short unsigned int i) {
|
||||
return u.s;
|
||||
}
|
||||
|
||||
int getTypeSize( TagType type ){
|
||||
return ("11124811248484"[type<14?type:0]-'0');
|
||||
}
|
||||
|
||||
#undef ABS
|
||||
#define ABS(a) (((a) < 0) ? -(a) : (a))
|
||||
|
||||
/* Function to parse and extract focal length and aperture information from description
|
||||
* @fullname must conform to the following formats
|
||||
* <focal>mm f/<aperture>
|
||||
@@ -1430,5 +1592,75 @@ bool extractLensInfo(std::string &fullname,double &minFocal, double &maxFocal, d
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
std::string IntLensInterpreter< T >::guess( const T lensID, double focalLength, double maxApertureAtFocal )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
double deltaMin = 1000.;
|
||||
|
||||
/* 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( !extractLensInfo( r->second ,f1,f2,a1,a2) )
|
||||
continue;
|
||||
if( f1 == 0. || a1 == 0.)
|
||||
continue;
|
||||
|
||||
if( focalLength < f1 - .5 || focalLength > f2 + 0.5 )
|
||||
continue;
|
||||
if( maxApertureAtFocal > 0.1){
|
||||
if( maxApertureAtFocal < a1 - 0.15 || maxApertureAtFocal > a2 +0.15)
|
||||
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)) );
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user