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++; } }
void clearGPSFields(Exiv2::ExifData &exifData) { std::list<std::string> fields = {"Exif.GPSInfo.GPSLatitude", "Exif.GPSInfo.GPSLongitude", "Exif.GPSInfo.GPSMapDatum", "Exif.GPSInfo.GPSLatitudeRef", "Exif.GPSInfo.GPSLongitudeRef", "Exif.GPSInfo.GPSLatitude", "Exif.GPSInfo.GPSLongitude", "Exif.GPSInfo.GPSAltitude", "Exif.GPSInfo.GPSAltitudeRef", "Exif.GPSInfo.GPSTimeStamp", "Exif.GPSInfo.GPSDateStamp",}; for (auto fname : fields) { auto key = Exiv2::ExifKey(fname.c_str()); auto iter = exifData.findKey(key); while (iter != exifData.end()) { exifData.erase(iter); iter = exifData.findKey(key); } } }
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; }
// ***************************************************************************** // 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::ReadExif(const QString &AFileName, Exiv2::ExifData &AExifData, std::vector<uint8_t> &AExifBuffer) { if (AFileName.trimmed().isEmpty()) return false; try { if (Exiv2::ImageFactory::getType(AFileName.toLocal8Bit().data()) == Exiv2::ImageType::none) return false; Exiv2::Image::AutoPtr hImage = Exiv2::ImageFactory::open(AFileName.toLocal8Bit().data()); if (!hImage.get()) return false; hImage->readMetadata(); AExifData = hImage->exifData(); if (AExifData.empty()) { ptLogWarning(ptWarning_Argument, "No Exif data found in %s", AFileName.toLocal8Bit().data()); return false; } Exiv2::ExifData::iterator Pos; size_t Size; #if EXIV2_TEST_VERSION(0,17,91) /* Exiv2 0.18-pre1 */ Exiv2::Blob Blob; Exiv2::ExifParser::encode(Blob, Exiv2::bigEndian, AExifData); Size = Blob.size(); #else Exiv2::DataBuf Buf(AExifData.copy()); Size = Buf.size_; #endif /* If buffer too big for JPEG, try deleting some stuff. */ if (Size + CExifHeader.size() > CMaxHeaderLength) { if ((Pos = AExifData.findKey(Exiv2::ExifKey("Exif.Photo.MakerNote"))) != AExifData.end() ) { AExifData.erase(Pos); ptLogWarning(ptWarning_Argument, "Exif buffer too big, erasing Exif.Photo.MakerNote"); #if EXIV2_TEST_VERSION(0,17,91) /* Exiv2 0.18-pre1 */ Exiv2::ExifParser::encode(Blob, Exiv2::bigEndian, AExifData); Size = Blob.size(); #else Buf = AExifData.copy(); Size = Buf.size_; #endif } } // Erase embedded thumbnail if needed if (Settings->GetInt("EraseExifThumbnail") || (Size + CExifHeader.size()) > CMaxHeaderLength ) { #if EXIV2_TEST_VERSION(0,17,91) /* Exiv2 0.18-pre1 */ Exiv2::ExifThumb Thumb(AExifData); Thumb.erase(); #else AExifData.eraseThumbnail(); #endif if (!Settings->GetInt("EraseExifThumbnail")) ptLogWarning(ptWarning_Argument, "Exif buffer too big, erasing Thumbnail"); #if EXIV2_TEST_VERSION(0,17,91) /* Exiv2 0.18-pre1 */ Exiv2::ExifParser::encode(Blob, Exiv2::bigEndian, AExifData); Size = Blob.size(); #else Buf = AExifData.copy(); Size = Buf.size_; #endif } AExifBuffer.clear(); AExifBuffer.insert(AExifBuffer.end(), CExifHeader.begin(), CExifHeader.end()); #if EXIV2_TEST_VERSION(0,17,91) /* Exiv2 0.18-pre1 */ AExifBuffer.insert(AExifBuffer.end(), Blob.begin(), Blob.end()); #else // old code will currently not compile memcpy(AExifBuffer+sizeof(ExifHeader), Buf.pData_, Buf.size_); #endif return true; } catch(Exiv2::Error& Error) { // Exiv2 errors are in this context hopefully harmless // (unsupported tags etc.) ptLogWarning(ptWarning_Exiv2,"Exiv2 : %s\n",Error.what()); } return false; }