Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Exiv2Helper.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
11 /*
12  * This is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public
14  * License as published by the Free Software Foundation; either
15  * version 2 of the License, or (at your option) any later version.
16  *
17  * This software is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public
23  * License along with this software. If not, see
24  * <http://www.gnu.org/licenses/>.
25  *
26  */
27 
28 #include "Exiv2Helper.h"
29 #include "hugin_math/hugin_math.h"
30 #include "hugin_utils/utils.h"
31 #include <exiv2/exiv2.hpp>
32 
33 namespace HuginBase
34 {
35  namespace Exiv2Helper
36  {
37 
38  bool _getExiv2Value(Exiv2::ExifData& exifData, std::string keyName, long & value)
39  {
40  Exiv2::ExifData::iterator itr = exifData.findKey(Exiv2::ExifKey(keyName));
41  if (itr != exifData.end() && itr->count())
42  {
43 #if defined EXIV2_VERSION && EXIV2_TEST_VERSION(0,28,0)
44  value = itr->toInt64();
45 #else
46  value = itr->toLong();
47 #endif
48  return true;
49  }
50  else
51  {
52  return false;
53  };
54  };
55 
56  bool _getExiv2Value(Exiv2::ExifData& exifData, std::string keyName, float & value)
57  {
58  Exiv2::ExifData::iterator itr = exifData.findKey(Exiv2::ExifKey(keyName));
59  if (itr != exifData.end() && itr->count())
60  {
61  value = itr->toFloat();
62  return true;
63  }
64  else
65  {
66  return false;
67  };
68  };
69 
70  bool _getExiv2Value(Exiv2::ExifData& exifData, std::string keyName, std::string & value)
71  {
72  Exiv2::ExifData::iterator itr = exifData.findKey(Exiv2::ExifKey(keyName));
73  if (itr != exifData.end() && itr->count())
74  {
75  value = itr->toString();
76  return true;
77  }
78  else
79  {
80  return false;
81  };
82  }
83 
84  bool _getExiv2Value(Exiv2::ExifData& exifData, std::string keyName, std::vector<float> & values)
85  {
86  values.clear();
87  Exiv2::ExifData::iterator itr = exifData.findKey(Exiv2::ExifKey(keyName));
88  if (itr != exifData.end() && itr->count())
89  {
90  for(long i=0; i<itr->count(); i++)
91  {
92  values.push_back(itr->toFloat(i));
93  };
94  return true;
95  }
96  else
97  {
98  return false;
99  }
100  }
101 
102  bool _getExiv2Value(Exiv2::ExifData& exifData, uint16_t tagID, std::string groupName, std::string & value)
103  {
104  Exiv2::ExifData::iterator itr = exifData.findKey(Exiv2::ExifKey(tagID, groupName));
105  if (itr != exifData.end() && itr->count())
106  {
107  value = itr->toString();
108  return true;
109  }
110  else
111  {
112  return false;
113  };
114  };
115 
116  bool _getExiv2Value(Exiv2::ExifData& exifData, uint16_t tagID, std::string groupName, double & value)
117  {
118  Exiv2::ExifData::iterator itr = exifData.findKey(Exiv2::ExifKey(tagID, groupName));
119  if (itr != exifData.end() && itr->count())
120  {
121  value = itr->toFloat();
122  return true;
123  }
124  else
125  {
126  return false;
127  }
128  }
129 
130  const double getExiv2ValueDouble(Exiv2::ExifData& exifData, Exiv2::ExifData::const_iterator it)
131  {
132  if(it!=exifData.end() && it->count())
133  {
134  return it->toFloat();
135  }
136  return 0;
137  };
138 
139  const double getExiv2ValueDouble(Exiv2::ExifData& exifData, std::string keyName)
140  {
141  float d;
142  if(_getExiv2Value(exifData, keyName, d))
143  {
144  return d;
145  }
146  return 0;
147  };
148 
149  const std::string getExiv2ValueString(Exiv2::ExifData& exifData,Exiv2::ExifData::const_iterator it)
150  {
151  if(it!=exifData.end() && it->count())
152  {
153  return hugin_utils::StrTrim(it->toString());
154  };
155  return std::string("");
156  };
157 
158  const std::string getExiv2ValueString(Exiv2::ExifData& exifData, std::string keyName)
159  {
160  std::string s;
161  if(_getExiv2Value(exifData, keyName, s))
162  {
163  return hugin_utils::StrTrim(s);
164  }
165  return std::string("");
166  };
167 
168  const long getExiv2ValueLong(Exiv2::ExifData& exifData, Exiv2::ExifData::const_iterator it)
169  {
170  if(it!=exifData.end() && it->count())
171  {
172 #if defined EXIV2_VERSION && EXIV2_TEST_VERSION(0,28,0)
173  return it->toInt64();
174 #else
175  return it->toLong();
176 #endif
177  }
178  return 0;
179  };
180 
181  const long getExiv2ValueLong(Exiv2::ExifData& exifData, std::string keyName)
182  {
183  long l;
184  if(_getExiv2Value(exifData, keyName, l))
185  {
186  return l;
187  }
188  return 0;
189  }
190 
191  bool getExiv2GPSLatitude(Exiv2::ExifData& exifData, double& latitude)
192  {
193  Exiv2::ExifData::iterator lat = exifData.findKey(Exiv2::ExifKey("Exif.GPSInfo.GPSLatitude"));
194  Exiv2::ExifData::iterator latRef = exifData.findKey(Exiv2::ExifKey("Exif.GPSInfo.GPSLatitudeRef"));
195  // check that both tags exists
196  if (lat != exifData.end() && latRef != exifData.end())
197  {
198  // check type
199  if (lat->value().typeId() == Exiv2::unsignedRational)
200  {
201  double denom = 1;
202  double value = 0;
203  for (int i = 0; i < lat->value().count(); i++)
204  {
205  value += lat->value().toFloat(i) / denom;
206  denom *= 60;
207  };
208  if (latRef->toString() == "S")
209  {
210  value *= -1;
211  };
212  latitude = value;
213  return true;
214  };
215  };
216  return false;
217  }
218 
219  bool getExiv2GPSLongitude(Exiv2::ExifData& exifData, double& longitude)
220  {
221  Exiv2::ExifData::iterator longitudeTag = exifData.findKey(Exiv2::ExifKey("Exif.GPSInfo.GPSLongitude"));
222  Exiv2::ExifData::iterator longitudeRef = exifData.findKey(Exiv2::ExifKey("Exif.GPSInfo.GPSLongitudeRef"));
223  // check that both tags exists
224  if (longitudeTag != exifData.end() && longitudeRef != exifData.end())
225  {
226  // check type
227  if (longitudeTag->value().typeId() == Exiv2::unsignedRational)
228  {
229  double denom = 1;
230  double value = 0;
231  for (int i = 0; i < longitudeTag->value().count(); i++)
232  {
233  value += longitudeTag->value().toFloat(i) / denom;
234  denom *= 60;
235  };
236  if (longitudeRef->toString() == "W")
237  {
238  value *= -1;
239  };
240  longitude = value;
241  return true;
242  };
243  };
244  return false;
245  }
246 
247  //for diagnostic
248  void PrintTag(Exiv2::ExifData::iterator itr)
249  {
250  std::cout << itr->value() << " (" << itr->typeName() << ", size: " << itr->count() << ")" << std::endl;
251  if(itr->count()>1)
252  {
253  std::cout << "[";
254  for(long i=0; i<itr->count(); i++)
255  {
256  std::cout << itr->toFloat(i) << ",";
257  }
258  std::cout << "]" << std::endl;
259  };
260  };
261 
262  bool readRedBlueBalance(Exiv2::ExifData &exifData, double & redBalance, double & blueBalance)
263  {
264  redBalance=1.0;
265  blueBalance=1.0;
266  //Panasonic makernotes (also some Leica cams)
267  float val1=0, val2=0, val3=0;
268  std::vector<float> values;
269  if(_getExiv2Value(exifData, "Exif.Panasonic.WBRedLevel", val1) &&
270  _getExiv2Value(exifData, "Exif.Panasonic.WBGreenLevel", val2) &&
271  _getExiv2Value(exifData, "Exif.Panasonic.WBBlueLevel", val3))
272  {
273  if(val1!=0 && val2!=0 && val3!=0)
274  {
275  redBalance=val1 / val2;;
276  blueBalance=val3 / val2;
277  return true;
278  }
279  else
280  {
281  return false;
282  };
283  };
284  // Pentax makernotes
285  if (_getExiv2Value(exifData, "Exif.Pentax.RedBalance", val1) &&
286  _getExiv2Value(exifData, "Exif.Pentax.BlueBalance", val2))
287  {
288  if(val1!=0 && val2!=0)
289  {
290  redBalance=val1 / 8192.0;
291  blueBalance=val2 / 8192.0;
292  return true;
293  }
294  else
295  {
296  return false;
297  };
298  };
299 #if defined EXIV2_VERSION && EXIV2_VERSION >= EXIV2_MAKE_VERSION(0,23,0)
300  if (_getExiv2Value(exifData, "Exif.PentaxDng.RedBalance", val1) &&
301  _getExiv2Value(exifData, "Exif.PentaxDng.BlueBalance", val2))
302  {
303  if(val1!=0 && val2!=0)
304  {
305  redBalance=val1 / 256.0;
306  blueBalance=val2 / 256.0;
307  return true;
308  }
309  else
310  {
311  return false;
312  };
313  };
314 #endif
315  //Olympus makernotes
316  if (_getExiv2Value(exifData, "Exif.Olympus.RedBalance", val1) &&
317  _getExiv2Value(exifData, "Exif.Olympus.BlueBalance", val2))
318  {
319  if(val1!=0 && val2!=0)
320  {
321  redBalance=val1 / 256.0;
322  blueBalance=val2 / 256.0;
323  return true;
324  }
325  else
326  {
327  return false;
328  };
329  };
330  if(_getExiv2Value(exifData, "Exif.OlympusIp.WB_RBLevels", values))
331  {
332  if(values.size()>=2)
333  {
334  if(values[0]!=0 && values[1]!=0)
335  {
336  redBalance=values[0]/256.0;
337  blueBalance=values[1]/256.0;
338  return true;
339  }
340  else
341  {
342  return false;
343  };
344  }
345  else
346  {
347  return false;
348  };
349  };
350  // Nikon makernotes
351  if(_getExiv2Value(exifData, "Exif.Nikon3.WB_RBLevels", values))
352  {
353  if(values.size()>=2)
354  {
355  if(values[0]!=0 && values[1]!=0)
356  {
357  redBalance=values[0];
358  blueBalance=values[1];
359  return true;
360  }
361  else
362  {
363  return false;
364  };
365  }
366  else
367  {
368  return false;
369  };
370  };
371  if(_getExiv2Value(exifData, "Exif.NikonCb1.WB_RBGGLevels", values))
372  {
373  if(values.size()==4)
374  {
375  if(values[0]!=0 && values[1]!=0 && values[2]!=0 && values[3]!=0)
376  {
377  redBalance=values[0] / values[2];
378  blueBalance=values[1] / values[2];
379  return true;
380  }
381  else
382  {
383  return false;
384  };
385  }
386  else
387  {
388  return false;
389  };
390  };
391  if(_getExiv2Value(exifData, "Exif.NikonCb2.WB_RGGBLevels", values))
392  {
393  if(values.size()==4)
394  {
395  if(values[0]!=0 && values[1]!=0 && values[2]!=0 && values[3]!=0)
396  {
397  redBalance=values[0] / values[1];
398  blueBalance=values[3] / values[1];
399  return true;
400  }
401  else
402  {
403  return false;
404  };
405  }
406  else
407  {
408  return false;
409  };
410  };
411  if(_getExiv2Value(exifData, "Exif.NikonCb2a.WB_RGGBLevels", values))
412  {
413  if(values.size()==4)
414  {
415  if(values[0]!=0 && values[1]!=0 && values[2]!=0 && values[3]!=0)
416  {
417  redBalance=values[0] / values[1];
418  blueBalance=values[3] / values[1];
419  return true;
420  }
421  else
422  {
423  return false;
424  };
425  }
426  else
427  {
428  return false;
429  };
430  };
431  if(_getExiv2Value(exifData, "Exif.NikonCb2b.WB_RGGBLevels", values))
432  {
433  if(values.size()==4)
434  {
435  if(values[0]!=0 && values[1]!=0 && values[2]!=0 && values[3]!=0)
436  {
437  redBalance=values[0] / values[1];
438  blueBalance=values[3] / values[1];
439  return true;
440  }
441  else
442  {
443  return false;
444  };
445  }
446  else
447  {
448  return false;
449  };
450  };
451  if(_getExiv2Value(exifData, "Exif.NikonCb3.WB_RGBGLevels", values))
452  {
453  if(values.size()==4)
454  {
455  if(values[0]!=0 && values[1]!=0 && values[2]!=0 && values[3]!=0)
456  {
457  redBalance=values[0] / values[1];
458  blueBalance=values[2] / values[3];
459  return true;
460  }
461  else
462  {
463  return false;
464  };
465  }
466  else
467  {
468  return false;
469  };
470  };
471 
472  return false;
473  };
474 
475  const double getCropFactor(Exiv2::ExifData &exifData, long width, long height)
476  {
477  double cropFactor=0;
478  // some cameras do not provide Exif.Image.ImageWidth / Length
479  // notably some Olympus
480  long eWidth = 0;
481  _getExiv2Value(exifData,"Exif.Image.ImageWidth",eWidth);
482 
483  long eLength = 0;
484  _getExiv2Value(exifData,"Exif.Image.ImageLength",eLength);
485 
486  double sensorPixelWidth = 0;
487  double sensorPixelHeight = 0;
488  if (eWidth > 0 && eLength > 0)
489  {
490  sensorPixelHeight = (double)eLength;
491  sensorPixelWidth = (double)eWidth;
492  }
493  else
494  {
495  // No EXIF information, use number of pixels in image
496  sensorPixelWidth = width;
497  sensorPixelHeight = height;
498  }
499 
500  // force landscape sensor orientation
501  if (sensorPixelWidth < sensorPixelHeight )
502  {
503  double t = sensorPixelWidth;
504  sensorPixelWidth = sensorPixelHeight;
505  sensorPixelHeight = t;
506  }
507 
508  DEBUG_DEBUG("sensorPixelWidth: " << sensorPixelWidth);
509  DEBUG_DEBUG("sensorPixelHeight: " << sensorPixelHeight);
510 
511  // some cameras do not provide Exif.Photo.FocalPlaneResolutionUnit
512  // notably some Olympus
513 
514  long exifResolutionUnits = 0;
515  _getExiv2Value(exifData,"Exif.Photo.FocalPlaneResolutionUnit",exifResolutionUnits);
516 
517  float resolutionUnits= 0;
518  switch (exifResolutionUnits)
519  {
520  case 3: resolutionUnits = 10.0f; break; //centimeter
521  case 4: resolutionUnits = 1.0f; break; //millimeter
522  case 5: resolutionUnits = .001f; break; //micrometer
523  default: resolutionUnits = 25.4f; break; //inches
524  }
525 
526  DEBUG_DEBUG("Resolution Units: " << resolutionUnits);
527 
528  // some cameras do not provide Exif.Photo.FocalPlaneXResolution and
529  // Exif.Photo.FocalPlaneYResolution, notably some Olympus
530  float fplaneXresolution = 0;
531  _getExiv2Value(exifData,"Exif.Photo.FocalPlaneXResolution",fplaneXresolution);
532 
533  float fplaneYresolution = 0;
534  _getExiv2Value(exifData,"Exif.Photo.FocalPlaneYResolution",fplaneYresolution);
535 
536  float CCDWidth = 0;
537  if (fplaneXresolution != 0)
538  {
539  CCDWidth = (float)(sensorPixelWidth / ( fplaneXresolution / resolutionUnits));
540  }
541 
542  float CCDHeight = 0;
543  if (fplaneYresolution != 0)
544  {
545  CCDHeight = (float)(sensorPixelHeight / ( fplaneYresolution / resolutionUnits));
546  }
547 
548  DEBUG_DEBUG("CCDHeight:" << CCDHeight);
549  DEBUG_DEBUG("CCDWidth: " << CCDWidth);
550 
551  // calc sensor dimensions if not set and 35mm focal length is available
552  hugin_utils::FDiff2D sensorSize;
553  if (CCDHeight > 0 && CCDWidth > 0)
554  {
555  // read sensor size directly.
556  sensorSize.x = CCDWidth;
557  sensorSize.y = CCDHeight;
558  std::string exifModel;
559  if(_getExiv2Value(exifData, "Exif.Image.Model", exifModel))
560  {
561  if (exifModel == "Canon EOS 20D")
562  {
563  // special case for buggy 20D camera
564  sensorSize.x = 22.5;
565  sensorSize.y = 15;
566  }
567  };
568  // check if sensor size ratio and image size fit together
569  double rsensor = (double)sensorSize.x / sensorSize.y;
570  double rimg = (double) width / height;
571  if ( (rsensor > 1 && rimg < 1) || (rsensor < 1 && rimg > 1) )
572  {
573  // image and sensor ratio do not match
574  // swap sensor sizes
575  float t;
576  t = sensorSize.y;
577  sensorSize.y = sensorSize.x;
578  sensorSize.x = t;
579  }
580 
581  DEBUG_DEBUG("sensorSize.y: " << sensorSize.y);
582  DEBUG_DEBUG("sensorSize.x: " << sensorSize.x);
583 
584  cropFactor = sqrt(36.0*36.0+24.0*24.0) /
585  sqrt(sensorSize.x*sensorSize.x + sensorSize.y*sensorSize.y);
586  // FIXME: HACK guard against invalid image focal plane definition in EXIF metadata with arbitrarly chosen limits for the crop factor ( 1/100 < crop < 100)
587  if (cropFactor < 0.1 || cropFactor > 100)
588  {
589  cropFactor = 0;
590  }
591  }
592  else
593  {
594  // alternative way to calculate the crop factor for Olympus cameras
595 
596  // Windows debug stuff
597  // left in as example on how to get "console output"
598  // written to a log file
599  // freopen ("oly.log","a",stdout);
600  // fprintf (stdout,"Starting Alternative crop determination\n");
601 
602  float olyFPD = 0;
603  _getExiv2Value(exifData,"Exif.Olympus.FocalPlaneDiagonal",olyFPD);
604  if (olyFPD > 0.0)
605  {
606  // Windows debug stuff
607  // fprintf(stdout,"Oly_FPD:");
608  // fprintf(stdout,"%f",olyFPD);
609  cropFactor = sqrt(36.0*36.0+24.0*24.0) / olyFPD;
610  }
611  else
612  {
613  // for newer Olympus cameras the FocalPlaneDiagonal tag was moved into
614  // equipment (sub?)-directory, so check also there
615  _getExiv2Value(exifData,"Exif.OlympusEq.FocalPlaneDiagonal",olyFPD);
616  if (olyFPD > 0.0)
617  {
618  cropFactor = sqrt(36.0*36.0+24.0*24.0) / olyFPD;
619  };
620  };
621  };
622  return cropFactor;
623  };
624 
625  const std::string getLensName(Exiv2::ExifData &exifData)
626  {
627  std::string lensName;
628  // first we are reading LensModel in Exif section, this is only available
629  // with EXIF >= 2.3
630 #if defined EXIV2_VERSION && EXIV2_VERSION >= EXIV2_MAKE_VERSION(0,22,0)
631  //the string "Exif.Photo.LensModel" is only defined in exiv2 0.22.0 and above
632  if(_getExiv2Value(exifData, "Exif.Photo.LensModel", lensName))
633 #else
634  if(_getExiv2Value(exifData, 0xa434, "Photo", lensName))
635 #endif
636  {
637  if(lensName.length()>0)
638  {
639  return lensName;
640  };
641  }
642  else
643  {
644  //no lens in Exif found, now look in makernotes
645  Exiv2::ExifData::const_iterator itr2 = Exiv2::lensName(exifData);
646  if (itr2!=exifData.end() && itr2->count())
647  {
648  //we are using prettyPrint function to get string of lens name
649  //it2->toString returns for many cameras only an ID number
650  lensName=itr2->print(&exifData);
651  //check returned lens name
652  if(lensName.length()>0)
653  {
654  //for Canon it can contain (65535) or (0) for unknown lenses
655  //for Pentax it can contain Unknown (0xHEX)
656  if(lensName.compare(0, 1, "(")!=0 && lensName.compare(0, 7, "Unknown")!=0)
657  {
658  return lensName;
659  }
660  };
661  };
662  };
663  return std::string("");
664  };
665 
666  }; //namespace Exiv2Helper
667 }; //namespace HuginBase
const std::string getLensName(Exiv2::ExifData &exifData)
std::string StrTrim(const std::string &str)
remove trailing and leading white spaces and tabs
Definition: utils.cpp:208
bool _getExiv2Value(Exiv2::ExifData &exifData, std::string keyName, long &value)
Definition: Exiv2Helper.cpp:38
misc math function &amp; classes used by other parts of the program
const double getExiv2ValueDouble(Exiv2::ExifData &exifData, Exiv2::ExifData::const_iterator it)
const long getExiv2ValueLong(Exiv2::ExifData &exifData, Exiv2::ExifData::const_iterator it)
const std::string getExiv2ValueString(Exiv2::ExifData &exifData, Exiv2::ExifData::const_iterator it)
bool getExiv2GPSLongitude(Exiv2::ExifData &exifData, double &longitude)
const double getCropFactor(Exiv2::ExifData &exifData, long width, long height)
bool getExiv2GPSLatitude(Exiv2::ExifData &exifData, double &latitude)
#define DEBUG_DEBUG(msg)
Definition: utils.h:68
helper functions to work with Exif data via the exiv2 library
void PrintTag(Exiv2::ExifData::iterator itr)
bool readRedBlueBalance(Exiv2::ExifData &exifData, double &redBalance, double &blueBalance)