1 // -*- c-basic-offset: 4 -*- 2 /** @file Exiv2Helper.cpp 3 * 4 * @brief helper functions to work with Exif data via the exiv2 library 5 * 6 * 7 * @author Pablo d'Angelo, T. Modes 8 * 9 */ 10 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 _getExiv2Value(Exiv2::ExifData & exifData,std::string keyName,long & value)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 value = itr->toLong(); 44 return true; 45 } 46 else 47 { 48 return false; 49 }; 50 }; 51 _getExiv2Value(Exiv2::ExifData & exifData,std::string keyName,float & value)52 bool _getExiv2Value(Exiv2::ExifData& exifData, std::string keyName, float & value) 53 { 54 Exiv2::ExifData::iterator itr = exifData.findKey(Exiv2::ExifKey(keyName)); 55 if (itr != exifData.end() && itr->count()) 56 { 57 value = itr->toFloat(); 58 return true; 59 } 60 else 61 { 62 return false; 63 }; 64 }; 65 _getExiv2Value(Exiv2::ExifData & exifData,std::string keyName,std::string & value)66 bool _getExiv2Value(Exiv2::ExifData& exifData, std::string keyName, std::string & value) 67 { 68 Exiv2::ExifData::iterator itr = exifData.findKey(Exiv2::ExifKey(keyName)); 69 if (itr != exifData.end() && itr->count()) 70 { 71 value = itr->toString(); 72 return true; 73 } 74 else 75 { 76 return false; 77 }; 78 } 79 _getExiv2Value(Exiv2::ExifData & exifData,std::string keyName,std::vector<float> & values)80 bool _getExiv2Value(Exiv2::ExifData& exifData, std::string keyName, std::vector<float> & values) 81 { 82 values.clear(); 83 Exiv2::ExifData::iterator itr = exifData.findKey(Exiv2::ExifKey(keyName)); 84 if (itr != exifData.end() && itr->count()) 85 { 86 for(long i=0; i<itr->count(); i++) 87 { 88 values.push_back(itr->toFloat(i)); 89 }; 90 return true; 91 } 92 else 93 { 94 return false; 95 } 96 } 97 _getExiv2Value(Exiv2::ExifData & exifData,uint16_t tagID,std::string groupName,std::string & value)98 bool _getExiv2Value(Exiv2::ExifData& exifData, uint16_t tagID, std::string groupName, std::string & value) 99 { 100 Exiv2::ExifData::iterator itr = exifData.findKey(Exiv2::ExifKey(tagID, groupName)); 101 if (itr != exifData.end() && itr->count()) 102 { 103 value = itr->toString(); 104 return true; 105 } 106 else 107 { 108 return false; 109 }; 110 }; 111 _getExiv2Value(Exiv2::ExifData & exifData,uint16_t tagID,std::string groupName,double & value)112 bool _getExiv2Value(Exiv2::ExifData& exifData, uint16_t tagID, std::string groupName, double & value) 113 { 114 Exiv2::ExifData::iterator itr = exifData.findKey(Exiv2::ExifKey(tagID, groupName)); 115 if (itr != exifData.end() && itr->count()) 116 { 117 value = itr->toFloat(); 118 return true; 119 } 120 else 121 { 122 return false; 123 } 124 } 125 getExiv2ValueDouble(Exiv2::ExifData & exifData,Exiv2::ExifData::const_iterator it)126 const double getExiv2ValueDouble(Exiv2::ExifData& exifData, Exiv2::ExifData::const_iterator it) 127 { 128 if(it!=exifData.end() && it->count()) 129 { 130 return it->toFloat(); 131 } 132 return 0; 133 }; 134 getExiv2ValueDouble(Exiv2::ExifData & exifData,std::string keyName)135 const double getExiv2ValueDouble(Exiv2::ExifData& exifData, std::string keyName) 136 { 137 float d; 138 if(_getExiv2Value(exifData, keyName, d)) 139 { 140 return d; 141 } 142 return 0; 143 }; 144 getExiv2ValueString(Exiv2::ExifData & exifData,Exiv2::ExifData::const_iterator it)145 const std::string getExiv2ValueString(Exiv2::ExifData& exifData,Exiv2::ExifData::const_iterator it) 146 { 147 if(it!=exifData.end() && it->count()) 148 { 149 return hugin_utils::StrTrim(it->toString()); 150 }; 151 return std::string(""); 152 }; 153 getExiv2ValueString(Exiv2::ExifData & exifData,std::string keyName)154 const std::string getExiv2ValueString(Exiv2::ExifData& exifData, std::string keyName) 155 { 156 std::string s; 157 if(_getExiv2Value(exifData, keyName, s)) 158 { 159 return hugin_utils::StrTrim(s); 160 } 161 return std::string(""); 162 }; 163 getExiv2ValueLong(Exiv2::ExifData & exifData,Exiv2::ExifData::const_iterator it)164 const long getExiv2ValueLong(Exiv2::ExifData& exifData, Exiv2::ExifData::const_iterator it) 165 { 166 if(it!=exifData.end() && it->count()) 167 { 168 return it->toLong(); 169 } 170 return 0; 171 }; 172 getExiv2ValueLong(Exiv2::ExifData & exifData,std::string keyName)173 const long getExiv2ValueLong(Exiv2::ExifData& exifData, std::string keyName) 174 { 175 long l; 176 if(_getExiv2Value(exifData, keyName, l)) 177 { 178 return l; 179 } 180 return 0; 181 }; 182 183 //for diagnostic PrintTag(Exiv2::ExifData::iterator itr)184 void PrintTag(Exiv2::ExifData::iterator itr) 185 { 186 std::cout << itr->value() << " (" << itr->typeName() << ", size: " << itr->count() << ")" << std::endl; 187 if(itr->count()>1) 188 { 189 std::cout << "["; 190 for(long i=0; i<itr->count(); i++) 191 { 192 std::cout << itr->toFloat(i) << ","; 193 } 194 std::cout << "]" << std::endl; 195 }; 196 }; 197 readRedBlueBalance(Exiv2::ExifData & exifData,double & redBalance,double & blueBalance)198 bool readRedBlueBalance(Exiv2::ExifData &exifData, double & redBalance, double & blueBalance) 199 { 200 redBalance=1.0; 201 blueBalance=1.0; 202 //Panasonic makernotes (also some Leica cams) 203 float val1=0, val2=0, val3=0; 204 std::vector<float> values; 205 if(_getExiv2Value(exifData, "Exif.Panasonic.WBRedLevel", val1) && 206 _getExiv2Value(exifData, "Exif.Panasonic.WBGreenLevel", val2) && 207 _getExiv2Value(exifData, "Exif.Panasonic.WBBlueLevel", val3)) 208 { 209 if(val1!=0 && val2!=0 && val3!=0) 210 { 211 redBalance=val1 / val2;; 212 blueBalance=val3 / val2; 213 return true; 214 } 215 else 216 { 217 return false; 218 }; 219 }; 220 // Pentax makernotes 221 if (_getExiv2Value(exifData, "Exif.Pentax.RedBalance", val1) && 222 _getExiv2Value(exifData, "Exif.Pentax.BlueBalance", val2)) 223 { 224 if(val1!=0 && val2!=0) 225 { 226 redBalance=val1 / 8192.0; 227 blueBalance=val2 / 8192.0; 228 return true; 229 } 230 else 231 { 232 return false; 233 }; 234 }; 235 #if defined EXIV2_VERSION && EXIV2_VERSION >= EXIV2_MAKE_VERSION(0,23,0) 236 if (_getExiv2Value(exifData, "Exif.PentaxDng.RedBalance", val1) && 237 _getExiv2Value(exifData, "Exif.PentaxDng.BlueBalance", val2)) 238 { 239 if(val1!=0 && val2!=0) 240 { 241 redBalance=val1 / 256.0; 242 blueBalance=val2 / 256.0; 243 return true; 244 } 245 else 246 { 247 return false; 248 }; 249 }; 250 #endif 251 //Olympus makernotes 252 if (_getExiv2Value(exifData, "Exif.Olympus.RedBalance", val1) && 253 _getExiv2Value(exifData, "Exif.Olympus.BlueBalance", val2)) 254 { 255 if(val1!=0 && val2!=0) 256 { 257 redBalance=val1 / 256.0; 258 blueBalance=val2 / 256.0; 259 return true; 260 } 261 else 262 { 263 return false; 264 }; 265 }; 266 if(_getExiv2Value(exifData, "Exif.OlympusIp.WB_RBLevels", values)) 267 { 268 if(values.size()>=2) 269 { 270 if(values[0]!=0 && values[1]!=0) 271 { 272 redBalance=values[0]/256.0; 273 blueBalance=values[1]/256.0; 274 return true; 275 } 276 else 277 { 278 return false; 279 }; 280 } 281 else 282 { 283 return false; 284 }; 285 }; 286 // Nikon makernotes 287 if(_getExiv2Value(exifData, "Exif.Nikon3.WB_RBLevels", values)) 288 { 289 if(values.size()>=2) 290 { 291 if(values[0]!=0 && values[1]!=0) 292 { 293 redBalance=values[0]; 294 blueBalance=values[1]; 295 return true; 296 } 297 else 298 { 299 return false; 300 }; 301 } 302 else 303 { 304 return false; 305 }; 306 }; 307 if(_getExiv2Value(exifData, "Exif.NikonCb1.WB_RBGGLevels", values)) 308 { 309 if(values.size()==4) 310 { 311 if(values[0]!=0 && values[1]!=0 && values[2]!=0 && values[3]!=0) 312 { 313 redBalance=values[0] / values[2]; 314 blueBalance=values[1] / values[2]; 315 return true; 316 } 317 else 318 { 319 return false; 320 }; 321 } 322 else 323 { 324 return false; 325 }; 326 }; 327 if(_getExiv2Value(exifData, "Exif.NikonCb2.WB_RGGBLevels", values)) 328 { 329 if(values.size()==4) 330 { 331 if(values[0]!=0 && values[1]!=0 && values[2]!=0 && values[3]!=0) 332 { 333 redBalance=values[0] / values[1]; 334 blueBalance=values[3] / values[1]; 335 return true; 336 } 337 else 338 { 339 return false; 340 }; 341 } 342 else 343 { 344 return false; 345 }; 346 }; 347 if(_getExiv2Value(exifData, "Exif.NikonCb2a.WB_RGGBLevels", values)) 348 { 349 if(values.size()==4) 350 { 351 if(values[0]!=0 && values[1]!=0 && values[2]!=0 && values[3]!=0) 352 { 353 redBalance=values[0] / values[1]; 354 blueBalance=values[3] / values[1]; 355 return true; 356 } 357 else 358 { 359 return false; 360 }; 361 } 362 else 363 { 364 return false; 365 }; 366 }; 367 if(_getExiv2Value(exifData, "Exif.NikonCb2b.WB_RGGBLevels", values)) 368 { 369 if(values.size()==4) 370 { 371 if(values[0]!=0 && values[1]!=0 && values[2]!=0 && values[3]!=0) 372 { 373 redBalance=values[0] / values[1]; 374 blueBalance=values[3] / values[1]; 375 return true; 376 } 377 else 378 { 379 return false; 380 }; 381 } 382 else 383 { 384 return false; 385 }; 386 }; 387 if(_getExiv2Value(exifData, "Exif.NikonCb3.WB_RGBGLevels", values)) 388 { 389 if(values.size()==4) 390 { 391 if(values[0]!=0 && values[1]!=0 && values[2]!=0 && values[3]!=0) 392 { 393 redBalance=values[0] / values[1]; 394 blueBalance=values[2] / values[3]; 395 return true; 396 } 397 else 398 { 399 return false; 400 }; 401 } 402 else 403 { 404 return false; 405 }; 406 }; 407 408 return false; 409 }; 410 getCropFactor(Exiv2::ExifData & exifData,long width,long height)411 const double getCropFactor(Exiv2::ExifData &exifData, long width, long height) 412 { 413 double cropFactor=0; 414 // some cameras do not provide Exif.Image.ImageWidth / Length 415 // notably some Olympus 416 long eWidth = 0; 417 _getExiv2Value(exifData,"Exif.Image.ImageWidth",eWidth); 418 419 long eLength = 0; 420 _getExiv2Value(exifData,"Exif.Image.ImageLength",eLength); 421 422 double sensorPixelWidth = 0; 423 double sensorPixelHeight = 0; 424 if (eWidth > 0 && eLength > 0) 425 { 426 sensorPixelHeight = (double)eLength; 427 sensorPixelWidth = (double)eWidth; 428 } 429 else 430 { 431 // No EXIF information, use number of pixels in image 432 sensorPixelWidth = width; 433 sensorPixelHeight = height; 434 } 435 436 // force landscape sensor orientation 437 if (sensorPixelWidth < sensorPixelHeight ) 438 { 439 double t = sensorPixelWidth; 440 sensorPixelWidth = sensorPixelHeight; 441 sensorPixelHeight = t; 442 } 443 444 DEBUG_DEBUG("sensorPixelWidth: " << sensorPixelWidth); 445 DEBUG_DEBUG("sensorPixelHeight: " << sensorPixelHeight); 446 447 // some cameras do not provide Exif.Photo.FocalPlaneResolutionUnit 448 // notably some Olympus 449 450 long exifResolutionUnits = 0; 451 _getExiv2Value(exifData,"Exif.Photo.FocalPlaneResolutionUnit",exifResolutionUnits); 452 453 float resolutionUnits= 0; 454 switch (exifResolutionUnits) 455 { 456 case 3: resolutionUnits = 10.0f; break; //centimeter 457 case 4: resolutionUnits = 1.0f; break; //millimeter 458 case 5: resolutionUnits = .001f; break; //micrometer 459 default: resolutionUnits = 25.4f; break; //inches 460 } 461 462 DEBUG_DEBUG("Resolution Units: " << resolutionUnits); 463 464 // some cameras do not provide Exif.Photo.FocalPlaneXResolution and 465 // Exif.Photo.FocalPlaneYResolution, notably some Olympus 466 float fplaneXresolution = 0; 467 _getExiv2Value(exifData,"Exif.Photo.FocalPlaneXResolution",fplaneXresolution); 468 469 float fplaneYresolution = 0; 470 _getExiv2Value(exifData,"Exif.Photo.FocalPlaneYResolution",fplaneYresolution); 471 472 float CCDWidth = 0; 473 if (fplaneXresolution != 0) 474 { 475 CCDWidth = (float)(sensorPixelWidth / ( fplaneXresolution / resolutionUnits)); 476 } 477 478 float CCDHeight = 0; 479 if (fplaneYresolution != 0) 480 { 481 CCDHeight = (float)(sensorPixelHeight / ( fplaneYresolution / resolutionUnits)); 482 } 483 484 DEBUG_DEBUG("CCDHeight:" << CCDHeight); 485 DEBUG_DEBUG("CCDWidth: " << CCDWidth); 486 487 // calc sensor dimensions if not set and 35mm focal length is available 488 hugin_utils::FDiff2D sensorSize; 489 if (CCDHeight > 0 && CCDWidth > 0) 490 { 491 // read sensor size directly. 492 sensorSize.x = CCDWidth; 493 sensorSize.y = CCDHeight; 494 std::string exifModel; 495 if(_getExiv2Value(exifData, "Exif.Image.Model", exifModel)) 496 { 497 if (exifModel == "Canon EOS 20D") 498 { 499 // special case for buggy 20D camera 500 sensorSize.x = 22.5; 501 sensorSize.y = 15; 502 } 503 }; 504 // check if sensor size ratio and image size fit together 505 double rsensor = (double)sensorSize.x / sensorSize.y; 506 double rimg = (double) width / height; 507 if ( (rsensor > 1 && rimg < 1) || (rsensor < 1 && rimg > 1) ) 508 { 509 // image and sensor ratio do not match 510 // swap sensor sizes 511 float t; 512 t = sensorSize.y; 513 sensorSize.y = sensorSize.x; 514 sensorSize.x = t; 515 } 516 517 DEBUG_DEBUG("sensorSize.y: " << sensorSize.y); 518 DEBUG_DEBUG("sensorSize.x: " << sensorSize.x); 519 520 cropFactor = sqrt(36.0*36.0+24.0*24.0) / 521 sqrt(sensorSize.x*sensorSize.x + sensorSize.y*sensorSize.y); 522 // FIXME: HACK guard against invalid image focal plane definition in EXIF metadata with arbitrarly chosen limits for the crop factor ( 1/100 < crop < 100) 523 if (cropFactor < 0.1 || cropFactor > 100) 524 { 525 cropFactor = 0; 526 } 527 } 528 else 529 { 530 // alternative way to calculate the crop factor for Olympus cameras 531 532 // Windows debug stuff 533 // left in as example on how to get "console output" 534 // written to a log file 535 // freopen ("oly.log","a",stdout); 536 // fprintf (stdout,"Starting Alternative crop determination\n"); 537 538 float olyFPD = 0; 539 _getExiv2Value(exifData,"Exif.Olympus.FocalPlaneDiagonal",olyFPD); 540 if (olyFPD > 0.0) 541 { 542 // Windows debug stuff 543 // fprintf(stdout,"Oly_FPD:"); 544 // fprintf(stdout,"%f",olyFPD); 545 cropFactor = sqrt(36.0*36.0+24.0*24.0) / olyFPD; 546 } 547 else 548 { 549 // for newer Olympus cameras the FocalPlaneDiagonal tag was moved into 550 // equipment (sub?)-directory, so check also there 551 _getExiv2Value(exifData,"Exif.OlympusEq.FocalPlaneDiagonal",olyFPD); 552 if (olyFPD > 0.0) 553 { 554 cropFactor = sqrt(36.0*36.0+24.0*24.0) / olyFPD; 555 }; 556 }; 557 }; 558 return cropFactor; 559 }; 560 getLensName(Exiv2::ExifData & exifData)561 const std::string getLensName(Exiv2::ExifData &exifData) 562 { 563 std::string lensName; 564 // first we are reading LensModel in Exif section, this is only available 565 // with EXIF >= 2.3 566 #if defined EXIV2_VERSION && EXIV2_VERSION >= EXIV2_MAKE_VERSION(0,22,0) 567 //the string "Exif.Photo.LensModel" is only defined in exiv2 0.22.0 and above 568 if(_getExiv2Value(exifData, "Exif.Photo.LensModel", lensName)) 569 #else 570 if(_getExiv2Value(exifData, 0xa434, "Photo", lensName)) 571 #endif 572 { 573 if(lensName.length()>0) 574 { 575 return lensName; 576 }; 577 } 578 else 579 { 580 //no lens in Exif found, now look in makernotes 581 Exiv2::ExifData::const_iterator itr2 = Exiv2::lensName(exifData); 582 if (itr2!=exifData.end() && itr2->count()) 583 { 584 //we are using prettyPrint function to get string of lens name 585 //it2->toString returns for many cameras only an ID number 586 lensName=itr2->print(&exifData); 587 //check returned lens name 588 if(lensName.length()>0) 589 { 590 //for Canon it can contain (65535) or (0) for unknown lenses 591 //for Pentax it can contain Unknown (0xHEX) 592 if(lensName.compare(0, 1, "(")!=0 && lensName.compare(0, 7, "Unknown")!=0) 593 { 594 return lensName; 595 } 596 }; 597 }; 598 }; 599 return std::string(""); 600 }; 601 602 }; //namespace Exiv2Helper 603 }; //namespace HuginBase