int JpegContent::dotsPerMeter(const QString& keyName) const { Exiv2::ExifKey keyResUnit("Exif.Image.ResolutionUnit"); Exiv2::ExifData::iterator it = d->mExifData.findKey(keyResUnit); if (it == d->mExifData.end()) { return 0; } int res = it->toLong(); QString keyVal = "Exif.Image." + keyName; Exiv2::ExifKey keyResolution(keyVal.toAscii().data()); it = d->mExifData.findKey(keyResolution); if (it == d->mExifData.end()) { return 0; } // The unit for measuring XResolution and YResolution. The same unit is used for both XResolution and YResolution. // If the image resolution in unknown, 2 (inches) is designated. // Default = 2 // 2 = inches // 3 = centimeters // Other = reserved const float INCHESPERMETER = (100. / 2.54); switch (res) { case 3: // dots per cm return int(it->toLong() * 100); default: // dots per inch return int(it->toLong() * INCHESPERMETER); } return 0; }
bool getExifDateTime(Exiv2::ExifData &exifData, QDateTime &dateTime) { bool anyFound = false; try { Exiv2::ExifKey key(EXIF_PHOTO_DATETIMEORIGINAL); Exiv2::ExifData::iterator it = exifData.findKey(key); if (it != exifData.end()) { dateTime = QDateTime::fromString(QString::fromLatin1(it->toString().c_str()), Qt::ISODate); anyFound = dateTime.isValid(); } if (!anyFound) { Exiv2::ExifKey imageKey(EXIF_IMAGE_DATETIMEORIGINAL); Exiv2::ExifData::iterator imageIt = exifData.findKey(imageKey); if (imageIt != exifData.end()) { dateTime = QDateTime::fromString(QString::fromLatin1(imageIt->toString().c_str()), Qt::ISODate); anyFound = dateTime.isValid(); } } } catch (Exiv2::Error &e) { LOG_WARNING << "Exiv2 error:" << e.what(); anyFound = false; } catch (...) { LOG_WARNING << "Exception"; anyFound = false; #ifdef QT_DEBUG throw; #endif } return anyFound; }
Orientation JpegContent::orientation() const { Exiv2::ExifKey key("Exif.Image.Orientation"); Exiv2::ExifData::iterator it = d->mExifData.findKey(key); // We do the same checks as in libexiv2's src/crwimage.cpp: // http://dev.exiv2.org/projects/exiv2/repository/entry/trunk/src/crwimage.cpp?rev=2681#L1336 if (it == d->mExifData.end() || it->count() == 0 || it->typeId() != Exiv2::unsignedShort) { return NOT_AVAILABLE; } return Orientation(it->toLong()); }
bool _getExiv2Value(Exiv2::ExifData& exifData, std::string keyName, float & value) { Exiv2::ExifData::iterator itr = exifData.findKey(Exiv2::ExifKey(keyName)); if (itr != exifData.end() && itr->count()) { value = itr->toFloat(); return true; } else { return false; }; };
bool _getExiv2Value(Exiv2::ExifData& exifData, uint16_t tagID, std::string groupName, std::string & value) { Exiv2::ExifData::iterator itr = exifData.findKey(Exiv2::ExifKey(tagID, groupName)); if (itr != exifData.end() && itr->count()) { value = itr->toString(); return true; } else { return false; }; };
static void EraseGpsTags(Exiv2::ExifData &ExifInfo) { // Search through, find the keys that we want, and wipe them // Code below submitted by Marc Horowitz Exiv2::ExifData::iterator Iter; for (Exiv2::ExifData::iterator Iter = ExifInfo.begin(); Iter != ExifInfo.end(); ) { if (Iter->key().find("Exif.GPSInfo") == 0) Iter = ExifInfo.erase(Iter); else Iter++; } }
QString Previewimage::getExifKey(QString key, Exiv2::ExifData *exifData){ // returns string represented by exif key if(exifData == 0) return QString(); QString ret; try { Exiv2::ExifData::iterator pos = exifData->findKey( Exiv2::ExifKey(qPrintable(key))); if (pos == exifData->end()) return QString(); else ret = QString().fromStdString(pos->value().toString()); } catch (Exiv2::Error& e) { qCritical("[Rename] %s", e.what()); } return ret; }
bool _getExiv2Value(Exiv2::ExifData& exifData, std::string keyName, std::vector<float> & values) { values.clear(); Exiv2::ExifData::iterator itr = exifData.findKey(Exiv2::ExifKey(keyName)); if (itr != exifData.end() && itr->count()) { for(long i=0; i<itr->count(); i++) { values.push_back(itr->toFloat(i)); }; return true; } else { return false; } }
// ***************************************************************************** void testCase(const std::string& file1, const std::string& file2, const std::string& thumb, const std::string& key, const std::string& value) { Key1 ek(key); //Open first image Image::AutoPtr image1 = ImageFactory::open(file1); assert(image1.get() != 0); // Load existing metadata std::cerr << "---> Reading file " << file1 << "\n"; image1->readMetadata(); Exiv2::ExifData &ed1 = image1->exifData(); std::cerr << "---> Modifying Exif data\n"; Exiv2::ExifData::iterator pos = ed1.findKey(ek); if (pos == ed1.end()) { throw Error(1, "Metadatum with key = " + ek.key() + " not found"); } pos->setValue(value); // Open second image Image::AutoPtr image2 = ImageFactory::open(file2); assert(image2.get() != 0); image2->setExifData(image1->exifData()); std::cerr << "---> Writing Exif data to file " << file2 << "\n"; image2->writeMetadata(); std::cerr << "---> Reading file " << file2 << "\n"; image2->readMetadata(); Exiv2::ExifData &ed2 = image2->exifData(); exifPrint(ed2); std::cerr << "---> Writing Exif thumbnail to file " << thumb << ".*\n"; ExifThumbC et2(ed2); et2.writeFile(thumb); }
//for diagnostic void PrintTag(Exiv2::ExifData::iterator itr) { std::cout << itr->value() << " (" << itr->typeName() << ", size: " << itr->count() << ")" << std::endl; if(itr->count()>1) { std::cout << "["; for(long i=0; i<itr->count(); i++) { std::cout << itr->toFloat(i) << ","; } std::cout << "]" << std::endl; }; };
int main(int argc,const char* argv[]) { int result=0; const char* program = argv[0]; const char* types[typeMax]; types[typeUnknown ] = "unknown"; types[typeDirectory] = "directory"; types[typeImage ] = "image"; types[typeXML ] = "xml"; types[typeDoc ] = "doc"; types[typeCode ] = "code"; types[typeFile ] = "file"; char const* keywords[kwMAX]; memset(keywords,0,sizeof(keywords)); keywords[kwHELP ] = "help"; keywords[kwVERSION ] = "version"; keywords[kwVERBOSE ] = "verbose"; keywords[kwDRYRUN ] = "dryrun"; keywords[kwDST ] = "dst"; keywords[kwADJUST ] = "adjust"; keywords[kwTZ ] = "tz"; keywords[kwDELTA ] = "delta"; map<std::string,string> shorts; shorts["-?"] = "-help"; shorts["-h"] = "-help"; shorts["-v"] = "-verbose"; shorts["-V"] = "-version"; shorts["-d"] = "-dst"; shorts["-a"] = "-adjust"; shorts["-t"] = "-tz"; shorts["-D"] = "-delta"; shorts["-s"] = "-delta"; shorts["-X"] = "-dryrun"; Options options ; options.help = sina(keywords[kwHELP ],argv) || argc < 2; options.verbose = sina(keywords[kwVERBOSE],argv); options.dryrun = sina(keywords[kwDRYRUN ],argv); options.version = sina(keywords[kwVERSION],argv); options.dst = sina(keywords[kwDST ],argv); options.dryrun = sina(keywords[kwDRYRUN ],argv); for ( int i = 1 ; !result && i < argc ; i++ ) { const char* arg = argv[i++]; if ( shorts.count(arg) ) arg = shorts[arg].c_str(); const char* value = argv[i ]; int ivalue = ::atoi(value?value:"0"); int key = ::find(arg,keywords,kwMAX); int needv = key < kwMAX && key > (-kwNOVALUE); if (!needv ) i--; if ( needv && !value) key = kwNEEDVALUE; switch ( key ) { case kwDST : options.dst = true ; break; case kwHELP : options.help = true ; break; case kwVERSION : options.version = true ; break; case kwDRYRUN : options.dryrun = true ; break; case kwVERBOSE : options.verbose = true ; break; case kwTZ : Position::tz_ = parseTZ(value);break; case kwADJUST : Position::adjust_ = ivalue;break; case kwDELTA : Position::deltaMax_= ivalue;break; case kwNEEDVALUE: fprintf(stderr,"error: %s requires a value\n",arg); result = resultSyntaxError ; break ; case kwSYNTAX : default: { int type = getFileType(arg,options) ; if ( options.verbose ) printf("%s %s ",arg,types[type]) ; if ( type == typeImage ) { time_t t = readImageTime(std::string(arg)) ; char* path = realpath(arg,NULL); if ( t && path ) { if ( options.verbose) printf("%s %ld %s",path,(long int)t,asctime(localtime(&t))); gFiles.push_back(path); } if ( path ) :: free((void*) path); } if ( type == typeUnknown ) { fprintf(stderr,"error: illegal syntax %s\n",arg); result = resultSyntaxError ; } if ( options.verbose ) printf("\n") ; }break; } } if ( options.help ) ::help(program,keywords,kwMAX,options.verbose); if ( options.version ) ::version(program); if ( !result ) { sort(gFiles.begin(),gFiles.end(),mySort); if ( options.dst ) Position::dst_ = 3600; if ( options.verbose ) { int t = Position::tz(); int d = Position::dst(); int a = Position::adjust(); int A = Position::Adjust(); int s = A ; int h = s/3600; s-= h*3600; s = abs(s); int m = s/60 ; s-= m*60 ; printf("tz,dsl,adjust = %d,%d,%d total = %dsecs (= %d:%d:%d)\n",t,d,a,A,h,m,s); } for ( size_t p = 0 ; !options.dryrun && p < gFiles.size() ; p++ ) { std::string arg = gFiles[p] ; std::string stamp ; try { time_t t = readImageTime(arg,&stamp) ; Position* pPos = searchTimeDict(gTimeDict,t,Position::deltaMax_); Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(gFiles[p]); if ( image.get() ) { image->readMetadata(); Exiv2::ExifData& exifData = image->exifData(); #if 0 /* char* keys[]={ "Exif.Image.GPSTag" , "Exif.GPSInfo.GPSProcessingMethod" , "Exif.GPSInfo.GPSAltitudeRef" , "Exif.GPSInfo.GPSVersionID" , "Exif.GPSInfo.GPSProcessingMethod" , "Exif.GPSInfo.GPSVersionID" , "Exif.GPSInfo.GPSMapDatum" , "Exif.GPSInfo.GPSLatitude" , "Exif.GPSInfo.GPSLongitude" , "Exif.GPSInfo.GPSAltitude" , "Exif.GPSInfo.GPSAltitudeRef" , "Exif.GPSInfo.GPSLatitudeRef" , "Exif.GPSInfo.GPSLongitudeRef" , "Exif.GPSInfo.GPSDateStamp" , "Exif.GPSInfo.GPSTimeStamp" }; static int bPrint = true ; for ( int k = 0 ; k < 15 ; k++ ) { try { if ( bPrint ) printf("erasing %s\n",keys[k]); Exiv2::ExifKey key = Exiv2::ExifKey(keys[k]); Exiv2::ExifData::iterator kk = exifData.findKey(key); if ( kk != exifData.end() ) exifData.erase(kk); } catch (...) {}; } bPrint = false; */ #endif #if 0 Exiv2::ExifData::const_iterator end = exifData.end(); for (Exiv2::ExifData::iterator i = exifData.begin(); i != end; ++i) { char name[100]; strcpy(name,i->key().c_str()); // std::cout << "sniff " << i->key() << std::endl; if ( strstr(name,"GPS") ) { Exiv2::ExifData::iterator pos; Exiv2::ExifKey exifKey = Exiv2::ExifKey(name); pos = exifData.findKey(exifKey); while( pos != exifData.end()) { exifData.erase(pos); } } } #endif if ( pPos ) { /* struct _stat buf; int result; char timebuf[26]; char* filename = "crt_stat.c"; errno_t err; // Get data associated with "crt_stat.c": result = _stat( filename, &buf ); int _utime( const char *filename, struct _utimbuf *times ); */ exifData["Exif.GPSInfo.GPSProcessingMethod" ] = "65 83 67 73 73 0 0 0 72 89 66 82 73 68 45 70 73 88"; // ASCII HYBRID-FIX exifData["Exif.GPSInfo.GPSVersionID" ] = "2 2 0 0"; exifData["Exif.GPSInfo.GPSMapDatum" ] = "WGS-84"; exifData["Exif.GPSInfo.GPSLatitude" ] = Position::toExifString(pPos->lat(),true,true); exifData["Exif.GPSInfo.GPSLongitude" ] = Position::toExifString(pPos->lon(),true,false); exifData["Exif.GPSInfo.GPSAltitude" ] = Position::toExifString(pPos->ele()); exifData["Exif.GPSInfo.GPSAltitudeRef" ] = pPos->ele()<0.0?"1":"0"; exifData["Exif.GPSInfo.GPSLatitudeRef" ] = pPos->lat()>0?"N":"S"; exifData["Exif.GPSInfo.GPSLongitudeRef" ] = pPos->lon()>0?"E":"W"; exifData["Exif.GPSInfo.GPSDateStamp" ] = stamp; exifData["Exif.GPSInfo.GPSTimeStamp" ] = Position::toExifTimeStamp(stamp); exifData["Exif.Image.GPSTag" ] = 4908; printf("%s %s % 2d\n",arg.c_str(),pPos->toString().c_str(),pPos->delta()); } else { printf("%s *** not in time dict ***\n",arg.c_str()); } image->writeMetadata(); } } catch ( ... ) {}; } } return result ; }
// ***************************************************************************** // Main int main(int argc, char* const argv[]) try { if (argc != 2) { std::cout << "Usage: " << argv[0] << " file\n"; return 1; } Exiv2::ExifData exifData; int rc = exifData.read(argv[1]); if (rc) { std::string error = Exiv2::ExifData::strError(rc, argv[1]); throw Exiv2::Error(error); } /* There are two pitfalls that we need to consider when setting the Exif user comment (Exif.Photo.UserComment) of an image: First, the type of the Exif user comment tag is "undefined" (and not ASCII) according to the Exif standard. This means that in Exiv2, we have to deal with a DataValue (and not an AsciiValue). DataValue has the usual two read methods, however, the one taking a const std::string& buf expects the string to contain a series of integers (e.g., "0 1 2") and not a text string. Thus, we need to use the read function that reads the value from a character buffer of a given length. Second, the Exif comment field starts with an eight character area that identifies the used character set. For ASCII, these eight characters are "ASCII\0\0\0". The actual comment follows after this code. Note: There is a more simple Exif tag for the title of an image. It is a 20 byte string (type ASCII) and does not store two-byte characters. (Image.OtherTags.ImageDescription) */ // Initialise a data value with the character set and comment std::string charset("ASCII\0\0\0", 8); std::string comment("A comment added to the Exif metadata through Exiv2"); Exiv2::DataValue value; value.read(reinterpret_cast<const Exiv2::byte*>((charset + comment).data()), 8 + static_cast<long>(comment.size())); // Set the Exif comment Exiv2::ExifKey key("Exif.Photo.UserComment"); Exiv2::ExifData::iterator pos = exifData.findKey(key); if (pos != exifData.end()) { // Use the existing Exif UserComment metadatum if there is one pos->setValue(&value); } else { // Otherwise add a new UserComment metadatum exifData.add(key, &value); pos = exifData.findKey(key); } // Now we should have a valid iterator in any case. We use the metadatum // output operator to print the formatted value std::cout << "Writing user comment '" << *pos << "' back to the image\n"; rc = exifData.write(argv[1]); if (rc) { std::string error = Exiv2::ExifData::strError(rc, argv[1]); throw Exiv2::Error(error); } return rc; } catch (Exiv2::Error& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; return -1; }
bool KExiv2::Private::saveOperations(const QFileInfo& finfo, Exiv2::Image::AutoPtr image) const { try { Exiv2::AccessMode mode; bool wroteComment = false, wroteEXIF = false, wroteIPTC = false, wroteXMP = false; // We need to load target file metadata to merge with new one. It's mandatory with TIFF format: // like all tiff file structure is based on Exif. image->readMetadata(); // Image Comments --------------------------------- mode = image->checkMode(Exiv2::mdComment); if ((mode == Exiv2::amWrite) || (mode == Exiv2::amReadWrite)) { image->setComment(imageComments()); wroteComment = true; } // Exif metadata ---------------------------------- mode = image->checkMode(Exiv2::mdExif); if ((mode == Exiv2::amWrite) || (mode == Exiv2::amReadWrite)) { if (image->mimeType() == "image/tiff") { Exiv2::ExifData orgExif = image->exifData(); Exiv2::ExifData newExif; QStringList untouchedTags; // With tiff image we cannot overwrite whole Exif data as well, because // image data are stored in Exif container. We need to take a care about // to not lost image data. untouchedTags << "Exif.Image.ImageWidth"; untouchedTags << "Exif.Image.ImageLength"; untouchedTags << "Exif.Image.BitsPerSample"; untouchedTags << "Exif.Image.Compression"; untouchedTags << "Exif.Image.PhotometricInterpretation"; untouchedTags << "Exif.Image.FillOrder"; untouchedTags << "Exif.Image.SamplesPerPixel"; untouchedTags << "Exif.Image.StripOffsets"; untouchedTags << "Exif.Image.RowsPerStrip"; untouchedTags << "Exif.Image.StripByteCounts"; untouchedTags << "Exif.Image.XResolution"; untouchedTags << "Exif.Image.YResolution"; untouchedTags << "Exif.Image.PlanarConfiguration"; untouchedTags << "Exif.Image.ResolutionUnit"; for (Exiv2::ExifData::iterator it = orgExif.begin(); it != orgExif.end(); ++it) { if (untouchedTags.contains(it->key().c_str())) { newExif[it->key().c_str()] = orgExif[it->key().c_str()]; } } Exiv2::ExifData readedExif = exifMetadata(); for (Exiv2::ExifData::iterator it = readedExif.begin(); it != readedExif.end(); ++it) { if (!untouchedTags.contains(it->key().c_str())) { newExif[it->key().c_str()] = readedExif[it->key().c_str()]; } } image->setExifData(newExif); } else { image->setExifData(exifMetadata()); } wroteEXIF = true; } // Iptc metadata ---------------------------------- mode = image->checkMode(Exiv2::mdIptc); if ((mode == Exiv2::amWrite) || (mode == Exiv2::amReadWrite)) { image->setIptcData(iptcMetadata()); wroteIPTC = true; } // Xmp metadata ----------------------------------- mode = image->checkMode(Exiv2::mdXmp); if ((mode == Exiv2::amWrite) || (mode == Exiv2::amReadWrite)) { #ifdef _XMP_SUPPORT_ image->setXmpData(xmpMetadata()); wroteXMP = true; #endif } if (!wroteComment && !wroteEXIF && !wroteIPTC && !wroteXMP) { kDebug() << "Writing metadata is not supported for file" << finfo.fileName(); return false; } else if (!wroteEXIF || !wroteIPTC || !wroteXMP) { kDebug() << "Support for writing metadata is limited for file" << finfo.fileName() << "EXIF" << wroteEXIF << "IPTC" << wroteIPTC << "XMP" << wroteXMP; } if (!updateFileTimeStamp) { // Don't touch access and modification timestamp of file. struct stat st; ::stat(QFile::encodeName(filePath), &st); struct utimbuf ut; ut.modtime = st.st_mtime; ut.actime = st.st_atime; image->writeMetadata(); ::utime(QFile::encodeName(filePath), &ut); } else { image->writeMetadata(); } return true; } catch( Exiv2::Error& e ) { printExiv2ExceptionError("Cannot save metadata using Exiv2 ", e); } return false; }
// ***************************************************************************** // Main int main() try { // Container for all metadata Exiv2::ExifData exifData; // ************************************************************************* // Add to the Exif data // Create a ASCII string value (note the use of create) Exiv2::Value* v = Exiv2::Value::create(Exiv2::asciiString); // Set the value to a string v->read("1999:12:31 23:59:59"); // Add the value together with its key to the Exif data container Exiv2::ExifKey key("Exif.Photo.DateTimeOriginal"); exifData.add(key, v); std::cout << "Added key \"" << key << "\", value \"" << *v << "\"\n"; // Delete the memory allocated by Value::create delete v; // Now create a more interesting value (without using the create method) Exiv2::URationalValue* rv = new Exiv2::URationalValue; // Set two rational components from a string rv->read("1/2 1/3"); // Add more elements through the extended interface of rational value rv->value_.push_back(std::make_pair(2,3)); rv->value_.push_back(std::make_pair(3,4)); // Add the key and value pair to the Exif data key = Exiv2::ExifKey("Exif.Image.PrimaryChromaticities"); exifData.add(key, rv); std::cout << "Added key \"" << key << "\", value \"" << *rv << "\"\n"; // Delete memory allocated on the heap delete rv; // ************************************************************************* // Modify Exif data // Find the timestamp metadatum by its key key = Exiv2::ExifKey("Exif.Photo.DateTimeOriginal"); Exiv2::ExifData::iterator pos = exifData.findKey(key); if (pos == exifData.end()) throw Exiv2::Error("Key not found"); // Modify the value std::string date = pos->toString(); date.replace(0,4,"2000"); pos->setValue(date); std::cout << "Modified key \"" << key << "\", new value \"" << pos->value() << "\"\n"; // Find the other key key = Exiv2::ExifKey("Exif.Image.PrimaryChromaticities"); pos = exifData.findKey(key); if (pos == exifData.end()) throw Exiv2::Error("Key not found"); // Get a pointer to a copy of the value v = pos->getValue(); // Downcast the Value pointer to its actual type rv = dynamic_cast<Exiv2::URationalValue*>(v); if (rv == 0) throw Exiv2::Error("Downcast failed"); // Modify the value directly through the interface of URationalValue rv->value_[2] = std::make_pair(88,77); // Copy the modified value back to the metadatum pos->setValue(rv); // Delete the memory allocated by getValue delete v; std::cout << "Modified key \"" << key << "\", new value \"" << pos->value() << "\"\n"; // ************************************************************************* // Delete metadata from the Exif data container // Delete the metadatum at iterator position pos key = Exiv2::ExifKey("Exif.Image.PrimaryChromaticities"); pos = exifData.findKey(key); if (pos == exifData.end()) throw Exiv2::Error("Key not found"); exifData.erase(pos); std::cout << "Deleted key \"" << key << "\"\n"; // ************************************************************************* // Finally, write the remaining Exif data to an image file int rc = exifData.write("img_2158.jpg"); if (rc) { std::string error = Exiv2::ExifData::strError(rc, "img_2158.jpg"); throw Exiv2::Error(error); } return 0; } catch (Exiv2::Error& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; return -1; }
bool ptImageHelper::WriteExif(const QString &AFileName, const std::vector<uint8_t> &AExifBuffer, Exiv2::IptcData &AIptcData, Exiv2::XmpData &AXmpData) { try { #if EXIV2_TEST_VERSION(0,17,91) /* Exiv2 0.18-pre1 */ Exiv2::ExifData hInExifData; Exiv2::ExifParser::decode(hInExifData, AExifBuffer.data() + CExifHeader.size(), AExifBuffer.size() - CExifHeader.size()); // Reset orientation Exiv2::ExifData::iterator pos = hInExifData.begin(); if ((pos = hInExifData.findKey(Exiv2::ExifKey("Exif.Image.Orientation"))) != hInExifData.end()) { pos->setValue("1"); // Normal orientation } // Adapted from UFRaw, necessary for Tiff files QStringList ExifKeys; ExifKeys << "Exif.Image.ImageWidth" << "Exif.Image.ImageLength" << "Exif.Image.BitsPerSample" << "Exif.Image.Compression" << "Exif.Image.PhotometricInterpretation" << "Exif.Image.FillOrder" << "Exif.Image.SamplesPerPixel" << "Exif.Image.StripOffsets" << "Exif.Image.RowsPerStrip" << "Exif.Image.StripByteCounts" << "Exif.Image.XResolution" << "Exif.Image.YResolution" << "Exif.Image.PlanarConfiguration" << "Exif.Image.ResolutionUnit"; for (short i = 0; i < ExifKeys.count(); i++) { if ((pos = hInExifData.findKey(Exiv2::ExifKey(ExifKeys.at(i).toLocal8Bit().data()))) != hInExifData.end()) hInExifData.erase(pos); } if (Settings->GetInt("EraseExifThumbnail")) { Exiv2::ExifThumb Thumb(hInExifData); Thumb.erase(); } QStringList JpegExtensions; JpegExtensions << "jpg" << "JPG" << "Jpg" << "jpeg" << "Jpeg" << "JPEG"; bool deleteDNGdata = false; for (short i = 0; i < JpegExtensions.count(); i++) { if (!AFileName.endsWith(JpegExtensions.at(i))) deleteDNGdata = true; } Exiv2::Image::AutoPtr Exiv2Image = Exiv2::ImageFactory::open(AFileName.toLocal8Bit().data()); Exiv2Image->readMetadata(); Exiv2::ExifData outExifData = Exiv2Image->exifData(); for (auto hPos = hInExifData.begin(); hPos != hInExifData.end(); hPos++) { if (!deleteDNGdata || (*hPos).key() != "Exif.Image.DNGPrivateData") { outExifData.add(*hPos); } } // IPTC data QStringList Tags = Settings->GetStringList("TagsList"); QStringList DigikamTags = Settings->GetStringList("DigikamTagsList"); Exiv2::StringValue StringValue; for (int i = 0; i < Tags.size(); i++) { StringValue.read(Tags.at(i).toStdString()); AIptcData.add(Exiv2::IptcKey("Iptc.Application2.Keywords"), &StringValue); } // XMP data for (int i = 0; i < Tags.size(); i++) { AXmpData["Xmp.dc.subject"] = Tags.at(i).toStdString(); } for (int i = 0; i < DigikamTags.size(); i++) { AXmpData["Xmp.digiKam.TagsList"] = DigikamTags.at(i).toStdString(); } // Image rating outExifData["Exif.Image.Rating"] = Settings->GetInt("ImageRating"); AXmpData["Xmp.xmp.Rating"] = Settings->GetInt("ImageRating"); // Program name outExifData["Exif.Image.ProcessingSoftware"] = ProgramName; outExifData["Exif.Image.Software"] = ProgramName; AIptcData["Iptc.Application2.Program"] = ProgramName; AIptcData["Iptc.Application2.ProgramVersion"] = "idle"; AXmpData["Xmp.xmp.CreatorTool"] = ProgramName; AXmpData["Xmp.tiff.Software"] = ProgramName; // Title QString TitleWorking = Settings->GetString("ImageTitle"); StringClean(TitleWorking); if (TitleWorking != "") { outExifData["Exif.Photo.UserComment"] = TitleWorking.toStdString(); AIptcData["Iptc.Application2.Caption"] = TitleWorking.toStdString(); AXmpData["Xmp.dc.description"] = TitleWorking.toStdString(); AXmpData["Xmp.exif.UserComment"] = TitleWorking.toStdString(); AXmpData["Xmp.tiff.ImageDescription"] = TitleWorking.toStdString(); } // Copyright QString CopyrightWorking = Settings->GetString("Copyright"); StringClean(CopyrightWorking); if (CopyrightWorking != "") { outExifData["Exif.Image.Copyright"] = CopyrightWorking.toStdString(); AIptcData["Iptc.Application2.Copyright"] = CopyrightWorking.toStdString(); AXmpData["Xmp.tiff.Copyright"] = CopyrightWorking.toStdString(); } Exiv2Image->setExifData(outExifData); Exiv2Image->setIptcData(AIptcData); Exiv2Image->setXmpData(AXmpData); Exiv2Image->writeMetadata(); return true; #endif } catch (Exiv2::AnyError& Error) { if (Settings->GetInt("JobMode") == 0) { ptMessageBox::warning(0 ,"Exiv2 Error","No exif data written!\nCaught Exiv2 exception '" + QString(Error.what()) + "'\n"); } else { std::cout << "Caught Exiv2 exception '" << Error << "'\n"; } } return false; }
bool KExiv2::setImageOrientation(ImageOrientation orientation, bool setProgramName) const { if (!setProgramId(setProgramName)) return false; try { if (orientation < ORIENTATION_UNSPECIFIED || orientation > ORIENTATION_ROT_270) { kDebug() << "Image orientation value is not correct!"; return false; } // Set Exif values. d->exifMetadata()["Exif.Image.Orientation"] = static_cast<uint16_t>(orientation); kDebug() << "Exif.Image.Orientation tag set to: " << (int)orientation; // Set Xmp values. #ifdef _XMP_SUPPORT_ setXmpTagString("Xmp.tiff.Orientation", QString::number((int)orientation), false); #endif // _XMP_SUPPORT_ // -- Minolta/Sony Cameras ---------------------------------- // Minolta and Sony camera store image rotation in Makernote. // We remove these information to prevent duplicate values. Exiv2::ExifData::iterator it; Exiv2::ExifKey minoltaKey1("Exif.MinoltaCs7D.Rotation"); it = d->exifMetadata().findKey(minoltaKey1); if (it != d->exifMetadata().end()) { d->exifMetadata().erase(it); kDebug() << "Removing Exif.MinoltaCs7D.Rotation tag"; } Exiv2::ExifKey minoltaKey2("Exif.MinoltaCs5D.Rotation"); it = d->exifMetadata().findKey(minoltaKey2); if (it != d->exifMetadata().end()) { d->exifMetadata().erase(it); kDebug() << "Removing Exif.MinoltaCs5D.Rotation tag"; } // -- Exif embedded thumbnail ---------------------------------- Exiv2::ExifKey thumbKey("Exif.Thumbnail.Orientation"); it = d->exifMetadata().findKey(thumbKey); if (it != d->exifMetadata().end() && it->count()) { RotationMatrix operation((KExiv2Iface::KExiv2::ImageOrientation)it->toLong()); operation *= orientation; (*it) = static_cast<uint16_t>(operation.exifOrientation()); } return true; } catch( Exiv2::Error& e ) { d->printExiv2ExceptionError("Cannot set Exif Orientation tag using Exiv2 ", e); } catch(...) { kError() << "Default exception from Exiv2"; } return false; }
KExiv2::ImageOrientation KExiv2::getImageOrientation() const { try { Exiv2::ExifData exifData(d->exifMetadata()); Exiv2::ExifData::iterator it; long orientation; ImageOrientation imageOrient = ORIENTATION_NORMAL; // -- Standard Xmp tag -------------------------------- #ifdef _XMP_SUPPORT_ bool ok = false; QString str = getXmpTagString("Xmp.tiff.Orientation"); if (!str.isEmpty()) { orientation = str.toLong(&ok); if (ok) { kDebug() << "Orientation => Xmp.tiff.Orientation => " << (int)orientation; return (ImageOrientation)orientation; } } #endif // _XMP_SUPPORT_ // Because some camera set a wrong standard exif orientation tag, // We need to check makernote tags in first! // -- Minolta Cameras ---------------------------------- Exiv2::ExifKey minoltaKey1("Exif.MinoltaCs7D.Rotation"); it = exifData.findKey(minoltaKey1); if (it != exifData.end() && it->count()) { orientation = it->toLong(); kDebug() << "Orientation => Exif.MinoltaCs7D.Rotation => " << (int)orientation; switch(orientation) { case 76: imageOrient = ORIENTATION_ROT_90; break; case 82: imageOrient = ORIENTATION_ROT_270; break; } return imageOrient; } Exiv2::ExifKey minoltaKey2("Exif.MinoltaCs5D.Rotation"); it = exifData.findKey(minoltaKey2); if (it != exifData.end() && it->count()) { orientation = it->toLong(); kDebug() << "Orientation => Exif.MinoltaCs5D.Rotation => " << (int)orientation; switch(orientation) { case 76: imageOrient = ORIENTATION_ROT_90; break; case 82: imageOrient = ORIENTATION_ROT_270; break; } return imageOrient; } // -- Standard Exif tag -------------------------------- Exiv2::ExifKey keyStd("Exif.Image.Orientation"); it = exifData.findKey(keyStd); if (it != exifData.end() && it->count()) { orientation = it->toLong(); kDebug() << "Orientation => Exif.Image.Orientation => " << (int)orientation; return (ImageOrientation)orientation; } } catch( Exiv2::Error& e ) { d->printExiv2ExceptionError("Cannot parse Exif Orientation tag using Exiv2 ", e); } catch(...) { kError() << "Default exception from Exiv2"; } return ORIENTATION_UNSPECIFIED; }
long GalleryUtil::GetNaturalRotation(const QString &filePathString) { long rotateAngle = 0; #ifdef EXIF_SUPPORT QByteArray filePathBA = filePathString.toLocal8Bit(); const char *filePath = filePathBA.constData(); try { char *exifvalue = new char[1024]; ExifData *data = exif_data_new_from_file (filePath); if (data) { for (int i = 0; i < EXIF_IFD_COUNT; i++) { ExifEntry *entry = exif_content_get_entry (data->ifd[i], EXIF_TAG_ORIENTATION); ExifByteOrder byteorder = exif_data_get_byte_order (data); if (entry) { ExifShort v_short = exif_get_short (entry->data, byteorder); VERBOSE(VB_GENERAL|VB_EXTRA, QString("Exif entry=%1").arg(v_short)); /* See http://sylvana.net/jpegcrop/exif_orientation.html*/ if (v_short == 8) { rotateAngle = -90; } else if (v_short == 6) { rotateAngle = 90; } break; } } exif_data_free(data); } else { VERBOSE(VB_FILE, LOC_ERR + QString("Could not load exif data from '%1'") .arg(filePath)); } delete [] exifvalue; #if 0 Exiv2::ExifData exifData; int rc = exifData.read(filePath); if (!rc) { Exiv2::ExifKey key = Exiv2::ExifKey("Exif.Image.Orientation"); Exiv2::ExifData::iterator pos = exifData.findKey(key); if (pos != exifData.end()) { long orientation = pos->toLong(); switch (orientation) { case 6: rotateAngle = 90; break; case 8: rotateAngle = -90; break; default: rotateAngle = 0; break; } } } #endif } catch (...) { VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Failed to extract EXIF headers from '%1'") .arg(filePathString)); } #else // Shut the compiler up about the unused argument (void)filePathString; #endif // EXIF_SUPPORT return rotateAngle; }
QgsPoint QgsExifTools::getGeoTag( const QString &imagePath, bool &ok ) { ok = false; if ( !QFileInfo::exists( imagePath ) ) return QgsPoint(); try { std::unique_ptr< Exiv2::Image > image( Exiv2::ImageFactory::open( imagePath.toStdString() ) ); if ( !image ) return QgsPoint(); image->readMetadata(); Exiv2::ExifData &exifData = image->exifData(); if ( exifData.empty() ) return QgsPoint(); Exiv2::ExifData::iterator itLatRef = exifData.findKey( Exiv2::ExifKey( "Exif.GPSInfo.GPSLatitudeRef" ) ); Exiv2::ExifData::iterator itLatVal = exifData.findKey( Exiv2::ExifKey( "Exif.GPSInfo.GPSLatitude" ) ); Exiv2::ExifData::iterator itLonRef = exifData.findKey( Exiv2::ExifKey( "Exif.GPSInfo.GPSLongitudeRef" ) ); Exiv2::ExifData::iterator itLonVal = exifData.findKey( Exiv2::ExifKey( "Exif.GPSInfo.GPSLongitude" ) ); if ( itLatRef == exifData.end() || itLatVal == exifData.end() || itLonRef == exifData.end() || itLonVal == exifData.end() ) return QgsPoint(); auto readCoord = []( const QString & coord )->double { double res = 0; double div = 1; const QStringList parts = coord.split( QRegularExpression( QStringLiteral( "\\s+" ) ) ); for ( const QString &rational : parts ) { const QStringList pair = rational.split( '/' ); if ( pair.size() != 2 ) break; res += ( pair[0].toDouble() / pair[1].toDouble() ) / div; div *= 60; } return res; }; auto readRationale = []( const QString & rational )->double { const QStringList pair = rational.split( '/' ); if ( pair.size() != 2 ) return std::numeric_limits< double >::quiet_NaN(); return pair[0].toDouble() / pair[1].toDouble(); }; double lat = readCoord( QString::fromStdString( itLatVal->value().toString() ) ); double lon = readCoord( QString::fromStdString( itLonVal->value().toString() ) ); const QString latRef = QString::fromStdString( itLatRef->value().toString() ); const QString lonRef = QString::fromStdString( itLonRef->value().toString() ); if ( latRef.compare( QLatin1String( "S" ), Qt::CaseInsensitive ) == 0 ) { lat *= -1; } if ( lonRef.compare( QLatin1String( "W" ), Qt::CaseInsensitive ) == 0 ) { lon *= -1; } ok = true; Exiv2::ExifData::iterator itElevVal = exifData.findKey( Exiv2::ExifKey( "Exif.GPSInfo.GPSAltitude" ) ); Exiv2::ExifData::iterator itElevRefVal = exifData.findKey( Exiv2::ExifKey( "Exif.GPSInfo.GPSAltitudeRef" ) ); if ( itElevVal != exifData.end() ) { double elev = readRationale( QString::fromStdString( itElevVal->value().toString() ) ); if ( itElevRefVal != exifData.end() ) { const QString elevRef = QString::fromStdString( itElevRefVal->value().toString() ); if ( elevRef.compare( QLatin1String( "1" ), Qt::CaseInsensitive ) == 0 ) { elev *= -1; } } return QgsPoint( lon, lat, elev ); } else { return QgsPoint( lon, lat ); } } catch ( ... ) { return QgsPoint(); } }
QSize KExiv2::getImageDimensions() const { try { long width=-1, height=-1; // Try to get Exif.Photo tags Exiv2::ExifData exifData(d->exifMetadata()); Exiv2::ExifKey key("Exif.Photo.PixelXDimension"); Exiv2::ExifData::iterator it = exifData.findKey(key); if (it != exifData.end() && it->count()) width = it->toLong(); Exiv2::ExifKey key2("Exif.Photo.PixelYDimension"); Exiv2::ExifData::iterator it2 = exifData.findKey(key2); if (it2 != exifData.end() && it2->count()) height = it2->toLong(); if (width != -1 && height != -1) return QSize(width, height); // Try to get Exif.Image tags width = -1; height = -1; Exiv2::ExifKey key3("Exif.Image.ImageWidth"); Exiv2::ExifData::iterator it3 = exifData.findKey(key3); if (it3 != exifData.end() && it3->count()) width = it3->toLong(); Exiv2::ExifKey key4("Exif.Image.ImageLength"); Exiv2::ExifData::iterator it4 = exifData.findKey(key4); if (it4 != exifData.end() && it4->count()) height = it4->toLong(); if (width != -1 && height != -1) return QSize(width, height); #ifdef _XMP_SUPPORT_ // Try to get Xmp.tiff tags width = -1; height = -1; bool wOk = false; bool hOk = false; QString str = getXmpTagString("Xmp.tiff.ImageWidth"); if (!str.isEmpty()) width = str.toInt(&wOk); str = getXmpTagString("Xmp.tiff.ImageLength"); if (!str.isEmpty()) height = str.toInt(&hOk); if (wOk && hOk) return QSize(width, height); // Try to get Xmp.exif tags width = -1; height = -1; wOk = false; hOk = false; str = getXmpTagString("Xmp.exif.PixelXDimension"); if (!str.isEmpty()) width = str.toInt(&wOk); str = getXmpTagString("Xmp.exif.PixelYDimension"); if (!str.isEmpty()) height = str.toInt(&hOk); if (wOk && hOk) return QSize(width, height); #endif // _XMP_SUPPORT_ } catch( Exiv2::Error& e ) { d->printExiv2ExceptionError("Cannot parse image dimensions tag using Exiv2 ", e); } catch(...) { kError() << "Default exception from Exiv2"; } return QSize(); }
QDateTime KExiv2::getImageDateTime() const { try { // In first, trying to get Date & time from Exif tags. if (!d->exifMetadata().empty()) { Exiv2::ExifData exifData(d->exifMetadata()); { Exiv2::ExifKey key("Exif.Photo.DateTimeOriginal"); Exiv2::ExifData::iterator it = exifData.findKey(key); if (it != exifData.end()) { QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate); if (dateTime.isValid()) { kDebug() << "DateTime => Exif.Photo.DateTimeOriginal => " << dateTime; return dateTime; } } } { Exiv2::ExifKey key("Exif.Photo.DateTimeDigitized"); Exiv2::ExifData::iterator it = exifData.findKey(key); if (it != exifData.end()) { QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate); if (dateTime.isValid()) { kDebug() << "DateTime => Exif.Photo.DateTimeDigitized => " << dateTime; return dateTime; } } } { Exiv2::ExifKey key("Exif.Image.DateTime"); Exiv2::ExifData::iterator it = exifData.findKey(key); if (it != exifData.end()) { QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate); if (dateTime.isValid()) { kDebug() << "DateTime => Exif.Image.DateTime => " << dateTime; return dateTime; } } } } // In second, trying to get Date & time from Xmp tags. #ifdef _XMP_SUPPORT_ if (!d->xmpMetadata().empty()) { Exiv2::XmpData xmpData(d->xmpMetadata()); { Exiv2::XmpKey key("Xmp.exif.DateTimeOriginal"); Exiv2::XmpData::iterator it = xmpData.findKey(key); if (it != xmpData.end()) { QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate); if (dateTime.isValid()) { kDebug() << "DateTime => Xmp.exif.DateTimeOriginal => " << dateTime; return dateTime; } } } { Exiv2::XmpKey key("Xmp.exif.DateTimeDigitized"); Exiv2::XmpData::iterator it = xmpData.findKey(key); if (it != xmpData.end()) { QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate); if (dateTime.isValid()) { kDebug() << "DateTime => Xmp.exif.DateTimeDigitized => " << dateTime; return dateTime; } } } { Exiv2::XmpKey key("Xmp.photoshop.DateCreated"); Exiv2::XmpData::iterator it = xmpData.findKey(key); if (it != xmpData.end()) { QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate); if (dateTime.isValid()) { kDebug() << "DateTime => Xmp.photoshop.DateCreated => " << dateTime; return dateTime; } } } { Exiv2::XmpKey key("Xmp.xmp.CreateDate"); Exiv2::XmpData::iterator it = xmpData.findKey(key); if (it != xmpData.end()) { QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate); if (dateTime.isValid()) { kDebug() << "DateTime => Xmp.xmp.CreateDate => " << dateTime; return dateTime; } } } { Exiv2::XmpKey key("Xmp.tiff.DateTime"); Exiv2::XmpData::iterator it = xmpData.findKey(key); if (it != xmpData.end()) { QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate); if (dateTime.isValid()) { kDebug() << "DateTime => Xmp.tiff.DateTime => " << dateTime; return dateTime; } } } { Exiv2::XmpKey key("Xmp.xmp.ModifyDate"); Exiv2::XmpData::iterator it = xmpData.findKey(key); if (it != xmpData.end()) { QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate); if (dateTime.isValid()) { kDebug() << "DateTime => Xmp.xmp.ModifyDate => " << dateTime; return dateTime; } } } { Exiv2::XmpKey key("Xmp.xmp.MetadataDate"); Exiv2::XmpData::iterator it = xmpData.findKey(key); if (it != xmpData.end()) { QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate); if (dateTime.isValid()) { kDebug() << "DateTime => Xmp.xmp.MetadataDate => " << dateTime; return dateTime; } } } } #endif // _XMP_SUPPORT_ // In third, trying to get Date & time from Iptc tags. if (!d->iptcMetadata().empty()) { Exiv2::IptcData iptcData(d->iptcMetadata()); // Try creation Iptc date & time entries. Exiv2::IptcKey keyDateCreated("Iptc.Application2.DateCreated"); Exiv2::IptcData::iterator it = iptcData.findKey(keyDateCreated); if (it != iptcData.end()) { QString IptcDateCreated(it->toString().c_str()); Exiv2::IptcKey keyTimeCreated("Iptc.Application2.TimeCreated"); Exiv2::IptcData::iterator it2 = iptcData.findKey(keyTimeCreated); if (it2 != iptcData.end()) { QString IptcTimeCreated(it2->toString().c_str()); QDate date = QDate::fromString(IptcDateCreated, Qt::ISODate); QTime time = QTime::fromString(IptcTimeCreated, Qt::ISODate); QDateTime dateTime = QDateTime(date, time); if (dateTime.isValid()) { kDebug() << "DateTime => Iptc.Application2.DateCreated => " << dateTime; return dateTime; } } } // Try digitization Iptc date & time entries. Exiv2::IptcKey keyDigitizationDate("Iptc.Application2.DigitizationDate"); Exiv2::IptcData::iterator it3 = iptcData.findKey(keyDigitizationDate); if (it3 != iptcData.end()) { QString IptcDateDigitization(it3->toString().c_str()); Exiv2::IptcKey keyDigitizationTime("Iptc.Application2.DigitizationTime"); Exiv2::IptcData::iterator it4 = iptcData.findKey(keyDigitizationTime); if (it4 != iptcData.end()) { QString IptcTimeDigitization(it4->toString().c_str()); QDate date = QDate::fromString(IptcDateDigitization, Qt::ISODate); QTime time = QTime::fromString(IptcTimeDigitization, Qt::ISODate); QDateTime dateTime = QDateTime(date, time); if (dateTime.isValid()) { kDebug() << "DateTime => Iptc.Application2.DigitizationDate => " << dateTime; return dateTime; } } } } } catch( Exiv2::Error& e ) { d->printExiv2ExceptionError("Cannot parse Exif date & time tag using Exiv2 ", e); } catch(...) { kError() << "Default exception from Exiv2"; } return QDateTime(); }
// Overwrites existing value if found, otherwise creates a new one. // Passing invalidTypeId causes the type to be guessed. // Guessing types is accurate for IPTC, but not for EXIF. // Returns 0 on success EXIVSIMPLE_API int ModifyMeta(HIMAGE img, const char *key, const char *val, DllTypeId type) { assert(img && key && val); if (img==0 || key==0 || val==0) return -1; ImageWrapper *imgWrap = (ImageWrapper*)img; int rc = 2; Exiv2::IptcData &iptcData = imgWrap->image->iptcData(); Exiv2::ExifData &exifData = imgWrap->image->exifData(); std::string data(val); // if data starts and ends with quotes, remove them if (data.at(0) == '\"' && data.at(data.size()-1) == '\"') { data = data.substr(1, data.size()-2); } try { Exiv2::IptcKey iptcKey(key); rc = 1; if (type == invalidTypeId) type = (DllTypeId)Exiv2::IptcDataSets::dataSetType(iptcKey.tag(), iptcKey.record()); Exiv2::Value::AutoPtr value = Exiv2::Value::create((Exiv2::TypeId)type); value->read(data); Exiv2::IptcData::iterator iter = iptcData.findKey(iptcKey); if (iter != iptcData.end()) { iter->setValue(value.get()); rc = 0; } else { rc = iptcData.add(iptcKey, value.get()); } } catch(const Exiv2::AnyError&) { } if (rc) { // Failed with iptc, so try exif try { Exiv2::ExifKey exifKey(key); rc = 1; // No way to get value type for exif... string is the most common if (type == invalidTypeId) type = asciiString; Exiv2::Value::AutoPtr value = Exiv2::Value::create((Exiv2::TypeId)type); value->read(data); Exiv2::ExifData::iterator iter = exifData.findKey(exifKey); if (iter != exifData.end()) { iter->setValue(value.get()); rc = 0; } else { exifData.add(exifKey, value.get()); rc = 0; } } catch(const Exiv2::AnyError&) { } } return rc; }
QDateTime KExiv2::getDigitizationDateTime(bool fallbackToCreationTime) const { try { // In first, trying to get Date & time from Exif tags. if (!d->exifMetadata().empty()) { // Try Exif date time digitized. Exiv2::ExifData exifData(d->exifMetadata()); Exiv2::ExifKey key("Exif.Photo.DateTimeDigitized"); Exiv2::ExifData::iterator it = exifData.findKey(key); if (it != exifData.end()) { QDateTime dateTime = QDateTime::fromString(it->toString().c_str(), Qt::ISODate); if (dateTime.isValid()) { kDebug() << "DateTime (Exif digitalized): " << dateTime.toString().toAscii().constData(); return dateTime; } } } // In second, trying to get Date & time from Iptc tags. if (!d->iptcMetadata().empty()) { // Try digitization Iptc date time entries. Exiv2::IptcData iptcData(d->iptcMetadata()); Exiv2::IptcKey keyDigitizationDate("Iptc.Application2.DigitizationDate"); Exiv2::IptcData::iterator it = iptcData.findKey(keyDigitizationDate); if (it != iptcData.end()) { QString IptcDateDigitization(it->toString().c_str()); Exiv2::IptcKey keyDigitizationTime("Iptc.Application2.DigitizationTime"); Exiv2::IptcData::iterator it2 = iptcData.findKey(keyDigitizationTime); if (it2 != iptcData.end()) { QString IptcTimeDigitization(it2->toString().c_str()); QDate date = QDate::fromString(IptcDateDigitization, Qt::ISODate); QTime time = QTime::fromString(IptcTimeDigitization, Qt::ISODate); QDateTime dateTime = QDateTime(date, time); if (dateTime.isValid()) { kDebug() << "Date (IPTC digitalized): " << dateTime.toString().toAscii().constData(); return dateTime; } } } } } catch( Exiv2::Error& e ) { d->printExiv2ExceptionError("Cannot parse Exif digitization date & time tag using Exiv2 ", e); } catch(...) { kError() << "Default exception from Exiv2"; } if (fallbackToCreationTime) return getImageDateTime(); else return QDateTime(); }
QDateTime MetaEngine::getDigitizationDateTime(bool fallbackToCreationTime) const { try { // In first, trying to get Date & time from Exif tags. if (!d->exifMetadata().empty()) { // Try Exif date time digitized. Exiv2::ExifData exifData(d->exifMetadata()); Exiv2::ExifKey key("Exif.Photo.DateTimeDigitized"); Exiv2::ExifData::iterator it = exifData.findKey(key); if (it != exifData.end()) { QDateTime dateTime = QDateTime::fromString(QString::fromLatin1(it->toString().c_str()), Qt::ISODate); if (dateTime.isValid()) { qCDebug(DIGIKAM_METAENGINE_LOG) << "DateTime (Exif digitalized): " << dateTime.toString().toLatin1().constData(); return dateTime; } } } // In second, we trying XMP #ifdef _XMP_SUPPORT_ if (!d->xmpMetadata().empty()) { Exiv2::XmpData xmpData(d->xmpMetadata()); { Exiv2::XmpKey key("Xmp.exif.DateTimeDigitized"); Exiv2::XmpData::iterator it = xmpData.findKey(key); if (it != xmpData.end()) { QDateTime dateTime = QDateTime::fromString(QString::fromLatin1(it->toString().c_str()), Qt::ISODate); if (dateTime.isValid()) { qCDebug(DIGIKAM_METAENGINE_LOG) << "DateTime (XMP-Exif digitalized): " << dateTime.toString().toLatin1().constData(); return dateTime; } } } { Exiv2::XmpKey key("Xmp.video.DateTimeDigitized"); Exiv2::XmpData::iterator it = xmpData.findKey(key); if (it != xmpData.end()) { QDateTime dateTime = QDateTime::fromString(QString::fromLatin1(it->toString().c_str()), Qt::ISODate); if (dateTime.isValid()) { qCDebug(DIGIKAM_METAENGINE_LOG) << "DateTime (XMP-Video digitalized): " << dateTime.toString().toLatin1().constData(); return dateTime; } } } } #endif // _XMP_SUPPORT_ // In third, trying to get Date & time from Iptc tags. if (!d->iptcMetadata().empty()) { // Try digitization Iptc date time entries. Exiv2::IptcData iptcData(d->iptcMetadata()); Exiv2::IptcKey keyDigitizationDate("Iptc.Application2.DigitizationDate"); Exiv2::IptcData::iterator it = iptcData.findKey(keyDigitizationDate); if (it != iptcData.end()) { QString IptcDateDigitization(QString::fromLatin1(it->toString().c_str())); Exiv2::IptcKey keyDigitizationTime("Iptc.Application2.DigitizationTime"); Exiv2::IptcData::iterator it2 = iptcData.findKey(keyDigitizationTime); if (it2 != iptcData.end()) { QString IptcTimeDigitization(QString::fromLatin1(it2->toString().c_str())); QDate date = QDate::fromString(IptcDateDigitization, Qt::ISODate); QTime time = QTime::fromString(IptcTimeDigitization, Qt::ISODate); QDateTime dateTime = QDateTime(date, time); if (dateTime.isValid()) { qCDebug(DIGIKAM_METAENGINE_LOG) << "Date (IPTC digitalized): " << dateTime.toString().toLatin1().constData(); return dateTime; } } } } } catch( Exiv2::Error& e ) { d->printExiv2ExceptionError(QString::fromLatin1("Cannot parse Exif digitization date & time tag using Exiv2 "), e); } catch(...) { qCCritical(DIGIKAM_METAENGINE_LOG) << "Default exception from Exiv2"; } if (fallbackToCreationTime) return getImageDateTime(); else return QDateTime(); }