Hugin trunk 0.1
Loading...
Searching...
No Matches
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"
30#include "hugin_utils/utils.h"
31#include <exiv2/exiv2.hpp>
32
33namespace 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;
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;
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;
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 {
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 {
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
502 {
503 double t = sensorPixelWidth;
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 {
540 }
541
542 float CCDHeight = 0;
543 if (fplaneYresolution != 0)
544 {
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
553 if (CCDHeight > 0 && CCDWidth > 0)
554 {
555 // read sensor size directly.
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;
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) /
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)
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 {
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
helper functions to work with Exif data via the exiv2 library
misc math function & classes used by other parts of the program
#define DEBUG_DEBUG(msg)
Definition utils.h:68
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)
const double getExiv2ValueDouble(Exiv2::ExifData &exifData, Exiv2::ExifData::const_iterator it)
const long getExiv2ValueLong(Exiv2::ExifData &exifData, Exiv2::ExifData::const_iterator it)
bool _getExiv2Value(Exiv2::ExifData &exifData, std::string keyName, long &value)
const std::string getLensName(Exiv2::ExifData &exifData)
void PrintTag(Exiv2::ExifData::iterator itr)
bool readRedBlueBalance(Exiv2::ExifData &exifData, double &redBalance, double &blueBalance)
mainly consists of wrapper around the pano tools library, to assist in ressource management and to pr...
Definition wxcms.cpp:39
std::string StrTrim(const std::string &str)
remove trailing and leading white spaces and tabs
Definition utils.cpp:208
std::vector< deghosting::BImagePtr > threshold(const std::vector< deghosting::FImagePtr > &inputImages, const double threshold, const uint16_t flags)
Threshold function used for creating alpha masks for images.
Definition threshold.h:41