int main(int argc, char* const argv[]) try { if (argc != 2) { std::cout << "Usage: " << argv[0] << " file\n"; return 1; } const char* path=argv[1]; Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path); assert(image.get() != 0); image->readMetadata(); Jzon::Object root; const char* FS="FS"; Jzon::Object fs ; root.Add (FS,fs) ; fileSystemPush(path,root.Get(FS)); Exiv2::ExifData &exifData = image->exifData(); for ( ExifData::const_iterator i = exifData.begin(); i != exifData.end() ; ++i ) { std::string key ; push(objectForKey(i->key(),key,root),key,i); } Exiv2::IptcData &iptcData = image->iptcData(); for (Exiv2::IptcData::const_iterator i = iptcData.begin(); i != iptcData.end(); ++i) { std::string key ; push(objectForKey(i->key(),key,root),key,i); } Exiv2::XmpData &xmpData = image->xmpData(); for (Exiv2::XmpData::const_iterator i = xmpData.begin(); i != xmpData.end(); ++i) { std::string key ; push(objectForKey(i->key(),key,root),key,i); } /* This is only for testing long paths { ExifData::const_iterator i = exifData.begin(); std::string key; push(objectForKey("This.Is.A.Rather.Long.Path.Key",key,root),key,i); } */ Jzon::Writer writer(root,Jzon::StandardFormat); writer.Write(); std::cout << writer.GetResult() << std::endl; return 0; } //catch (std::exception& e) { //catch (Exiv2::AnyError& e) { catch (Exiv2::Error& e) { std::cout << "Caught Exiv2 exception '" << e.what() << "'\n"; return -1; }
int main(int argc, char* const argv[]) try { if (argc != 2) { std::cout << "Usage: " << argv[0] << " file\n"; return 1; } std::string filename(argv[1]); Exiv2::DataBuf buf = Exiv2::readFile(filename); std::string xmpPacket; xmpPacket.assign(reinterpret_cast<char*>(buf.pData_), buf.size_); std::cerr << "-----> Decoding XMP data read from " << filename << " <-----\n"; Exiv2::XmpData xmpData; if (0 != Exiv2::XmpParser::decode(xmpData, xmpPacket)) { std::string error(argv[1]); error += ": Failed to parse file contents (XMP packet)"; throw Exiv2::Error(Exiv2::kerErrorMessage, error); } if (xmpData.empty()) { std::string error(argv[1]); error += ": No XMP properties found in the XMP packet"; throw Exiv2::Error(Exiv2::kerErrorMessage, error); } for (Exiv2::XmpData::const_iterator md = xmpData.begin(); md != xmpData.end(); ++md) { std::cout << std::setfill(' ') << std::left << std::setw(44) << md->key() << " " << std::setw(9) << std::setfill(' ') << std::left << md->typeName() << " " << std::dec << std::setw(3) << std::setfill(' ') << std::right << md->count() << " " << std::dec << md->value() << std::endl; } filename += "-new"; std::cerr << "-----> Encoding XMP data to write to " << filename << " <-----\n"; if (0 != Exiv2::XmpParser::encode(xmpPacket, xmpData)) { std::string error(argv[1]); error += ": Failed to encode the XMP data"; throw Exiv2::Error(Exiv2::kerErrorMessage, error); } Exiv2::FileIo file(filename); if (file.open("wb") != 0) { throw Exiv2::Error(Exiv2::kerFileOpenFailed, filename, "wb", Exiv2::strError()); } if (file.write(reinterpret_cast<const Exiv2::byte*>(xmpPacket.data()), static_cast<long>(xmpPacket.size())) == 0) { throw Exiv2::Error(Exiv2::kerCallFailed, filename, Exiv2::strError(), "FileIo::write"); } Exiv2::XmpParser::terminate(); return 0; } catch (Exiv2::AnyError& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; return -1; }
void KExiv2::Private::mergeXmpData(const Exiv2::XmpData& src, Exiv2::XmpData& dest) { for (Exiv2::XmpData::const_iterator it = src.begin(); it != src.end(); ++it) { Exiv2::XmpData::iterator destIt = dest.findKey(Exiv2::XmpKey(it->key())); if (destIt == dest.end()) { dest.add(*it); } else { *destIt = *it; } } }
void XmpSidecar::readMetadata() { #ifdef DEBUG std::cerr << "Reading XMP file " << io_->path() << "\n"; #endif if (io_->open() != 0) { throw Error(9, io_->path(), strError()); } IoCloser closer(*io_); // Ensure that this is the correct image type if (!isXmpType(*io_, false)) { if (io_->error() || io_->eof()) throw Error(14); throw Error(3, "XMP"); } // Read the XMP packet from the IO stream std::string xmpPacket; const long len = 64 * 1024; byte buf[len]; long l; while ((l = io_->read(buf, len)) > 0) { xmpPacket.append(reinterpret_cast<char*>(buf), l); } if (io_->error()) throw Error(14); clearMetadata(); xmpPacket_ = xmpPacket; if (xmpPacket_.size() > 0 && XmpParser::decode(xmpData_, xmpPacket_)) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to decode XMP metadata.\n"; #endif } // #1112 - store dates to deal with loss of TZ information during conversions for (Exiv2::XmpData::const_iterator it = xmpData_.begin(); it != xmpData_.end(); ++it) { std::string key(it->key()); if ( key.find("Date") != std::string::npos ) { std::string value(it->value().toString()); dates_[key] = value; } } copyXmpToIptc(xmpData_, iptcData_); copyXmpToExif(xmpData_, exifData_); } // XmpSidecar::readMetadata
void NegativeProcessor::setXmpFromRaw(const dng_date_time_info &dateTimeNow, const dng_string &appNameVersion) { // ----------------------------------------------------------------------------------------- // Copy existing XMP-tags in raw-file to DNG AutoPtr<dng_xmp> negXmp(new dng_xmp(m_host->Allocator())); for (Exiv2::XmpData::const_iterator it = m_RawXmp.begin(); it != m_RawXmp.end(); it++) { try { negXmp->Set(Exiv2::XmpProperties::nsInfo(it->groupName())->ns_, it->tagName().c_str(), it->toString().c_str()); } catch (dng_exception& e) { // the above will throw an exception when trying to add XMPs with unregistered (i.e., unknown) // namespaces -- we just drop them here. std::cerr << "Dropped XMP-entry from raw-file since namespace is unknown: " "NS: " << Exiv2::XmpProperties::nsInfo(it->groupName())->ns_ << ", " "path: " << it->tagName().c_str() << ", " "text: " << it->toString().c_str() << "\n"; } } // ----------------------------------------------------------------------------------------- // Set some base-XMP tags (incl. redundant creation date under Photoshop namespace - just to stay close to Adobe...) negXmp->UpdateDateTime(dateTimeNow); negXmp->UpdateMetadataDate(dateTimeNow); negXmp->SetString(XMP_NS_XAP, "CreatorTool", appNameVersion); negXmp->Set(XMP_NS_DC, "format", "image/dng"); negXmp->SetString(XMP_NS_PHOTOSHOP, "DateCreated", m_negative->GetExif()->fDateTimeOriginal.Encode_ISO_8601()); m_negative->ResetXMP(negXmp.Release()); }
int main(int argc, char* const argv[]) try { if (argc != 2) { std::cout << "Usage: " << argv[0] << " file\n"; return 1; } Exiv2::DataBuf buf = Exiv2::readFile(argv[1]); std::string xmpPacket; xmpPacket.assign(reinterpret_cast<char*>(buf.pData_), buf.size_); Exiv2::XmpData xmpData; if (0 != Exiv2::XmpParser::decode(xmpData, xmpPacket)) { std::string error(argv[1]); error += ": Failed to parse file contents (XMP packet)"; throw Exiv2::Error(1, error); } if (xmpData.empty()) { std::string error(argv[1]); error += ": No XMP properties found in the XMP packet"; throw Exiv2::Error(1, error); } for (Exiv2::XmpData::const_iterator md = xmpData.begin(); md != xmpData.end(); ++md) { std::cout << std::setfill(' ') << std::left << std::setw(44) << md->key() << " " << std::setw(9) << std::setfill(' ') << std::left << md->typeName() << " " << std::dec << std::setw(3) << std::setfill(' ') << std::right << md->count() << " " << std::dec << md->value() << std::endl; } Exiv2::XmpParser::terminate(); return 0; } catch (Exiv2::AnyError& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; return -1; }
int main() try { // The XMP property container Exiv2::XmpData xmpData; // ------------------------------------------------------------------------- // Teaser: Setting XMP properties doesn't get much easier than this: xmpData["Xmp.dc.source"] = "xmpsample.cpp"; // a simple text value xmpData["Xmp.dc.subject"] = "Palmtree"; // an array item xmpData["Xmp.dc.subject"] = "Rubbertree"; // add a 2nd array item // a language alternative with two entries and without default xmpData["Xmp.dc.title"] = "lang=de-DE Sonnenuntergang am Strand"; xmpData["Xmp.dc.title"] = "lang=en-US Sunset on the beach"; // ------------------------------------------------------------------------- // Any properties can be set provided the namespace is known. Values of any // type can be assigned to an Xmpdatum, if they have an output operator. The // default XMP value type for unknown properties is a simple text value. xmpData["Xmp.dc.one"] = -1; xmpData["Xmp.dc.two"] = 3.1415; xmpData["Xmp.dc.three"] = Exiv2::Rational(5, 7); xmpData["Xmp.dc.four"] = uint16_t(255); xmpData["Xmp.dc.five"] = int32_t(256); xmpData["Xmp.dc.six"] = false; // In addition, there is a dedicated assignment operator for Exiv2::Value Exiv2::XmpTextValue val("Seven"); xmpData["Xmp.dc.seven"] = val; xmpData["Xmp.dc.eight"] = true; // Extracting values assert(xmpData["Xmp.dc.one"].toLong() == -1); assert(xmpData["Xmp.dc.one"].value().ok()); const Exiv2::Value &getv1 = xmpData["Xmp.dc.one"].value(); assert(isEqual(getv1.toFloat(), -1)); assert(getv1.ok()); assert(getv1.toRational() == Exiv2::Rational(-1, 1)); assert(getv1.ok()); const Exiv2::Value &getv2 = xmpData["Xmp.dc.two"].value(); assert(isEqual(getv2.toFloat(), 3.1415f)); assert(getv2.ok()); assert(getv2.toLong() == 3); assert(getv2.ok()); Exiv2::Rational R = getv2.toRational(); assert(getv2.ok()); assert(isEqual(static_cast<float>(R.first) / R.second, 3.1415f )); const Exiv2::Value &getv3 = xmpData["Xmp.dc.three"].value(); assert(isEqual(getv3.toFloat(), 5.0f/7.0f)); assert(getv3.ok()); assert(getv3.toLong() == 0); // long(5.0 / 7.0) assert(getv3.ok()); assert(getv3.toRational() == Exiv2::Rational(5, 7)); assert(getv3.ok()); const Exiv2::Value &getv6 = xmpData["Xmp.dc.six"].value(); assert(getv6.toLong() == 0); assert(getv6.ok()); assert(getv6.toFloat() == 0.0); assert(getv6.ok()); assert(getv6.toRational() == Exiv2::Rational(0, 1)); assert(getv6.ok()); const Exiv2::Value &getv7 = xmpData["Xmp.dc.seven"].value(); getv7.toLong(); // this should fail assert(!getv7.ok()); const Exiv2::Value &getv8 = xmpData["Xmp.dc.eight"].value(); assert(getv8.toLong() == 1); assert(getv8.ok()); assert(getv8.toFloat() == 1.0); assert(getv8.ok()); assert(getv8.toRational() == Exiv2::Rational(1, 1)); assert(getv8.ok()); // Deleting an XMP property Exiv2::XmpData::iterator pos = xmpData.findKey(Exiv2::XmpKey("Xmp.dc.eight")); if (pos == xmpData.end()) throw Exiv2::Error(1, "Key not found"); xmpData.erase(pos); // ------------------------------------------------------------------------- // Exiv2 has specialized values for simple XMP properties, arrays of simple // properties and language alternatives. // Add a simple XMP property in a known namespace Exiv2::Value::AutoPtr v = Exiv2::Value::create(Exiv2::xmpText); v->read("image/jpeg"); xmpData.add(Exiv2::XmpKey("Xmp.dc.format"), v.get()); // Add an ordered array of text values. v = Exiv2::Value::create(Exiv2::xmpSeq); // or xmpBag or xmpAlt. v->read("1) The first creator"); // The sequence in which the array v->read("2) The second creator"); // elements are added is their v->read("3) And another one"); // order in the array. xmpData.add(Exiv2::XmpKey("Xmp.dc.creator"), v.get()); // Add a language alternative property v = Exiv2::Value::create(Exiv2::langAlt); v->read("lang=de-DE Hallo, Welt"); // The default doesn't need a v->read("Hello, World"); // qualifier xmpData.add(Exiv2::XmpKey("Xmp.dc.description"), v.get()); // According to the XMP specification, Xmp.tiff.ImageDescription is an // alias for Xmp.dc.description. Exiv2 treats an alias just like any // other property and leaves it to the application to implement specific // behaviour if desired. xmpData["Xmp.tiff.ImageDescription"] = "TIFF image description"; xmpData["Xmp.tiff.ImageDescription"] = "lang=de-DE TIFF Bildbeschreibung"; // ------------------------------------------------------------------------- // Register a namespace which Exiv2 doesn't know yet. This is only needed // when properties are added manually. If the XMP metadata is read from an // image, namespaces are decoded and registered at the same time. Exiv2::XmpProperties::registerNs("myNamespace/", "ns"); // ------------------------------------------------------------------------- // Add a property in the new custom namespace. xmpData["Xmp.ns.myProperty"] = "myValue"; // ------------------------------------------------------------------------- // There are no specialized values for structures, qualifiers and nested // types. However, these can be added by using an XmpTextValue and a path as // the key. // Add a structure Exiv2::XmpTextValue tv("16"); xmpData.add(Exiv2::XmpKey("Xmp.xmpDM.videoFrameSize/stDim:w"), &tv); tv.read("9"); xmpData.add(Exiv2::XmpKey("Xmp.xmpDM.videoFrameSize/stDim:h"), &tv); tv.read("inch"); xmpData.add(Exiv2::XmpKey("Xmp.xmpDM.videoFrameSize/stDim:unit"), &tv); // Add an element with a qualifier (using the namespace registered above) xmpData["Xmp.dc.publisher"] = "James Bond"; // creates an unordered array xmpData["Xmp.dc.publisher[1]/?ns:role"] = "secret agent"; // Add a qualifer to an array element of Xmp.dc.creator (added above) tv.read("programmer"); xmpData.add(Exiv2::XmpKey("Xmp.dc.creator[2]/?ns:role"), &tv); // Add an array of structures tv.read(""); // Clear the value tv.setXmpArrayType(Exiv2::XmpValue::xaBag); xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef"), &tv); // Set the array type. tv.setXmpArrayType(Exiv2::XmpValue::xaNone); tv.read("Birthday party"); xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef[1]/stJob:name"), &tv); tv.read("Photographer"); xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef[1]/stJob:role"), &tv); tv.read("Wedding ceremony"); xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef[2]/stJob:name"), &tv); tv.read("Best man"); xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef[2]/stJob:role"), &tv); // ------------------------------------------------------------------------- // Output XMP properties for (Exiv2::XmpData::const_iterator md = xmpData.begin(); md != xmpData.end(); ++md) { std::cout << std::setfill(' ') << std::left << std::setw(44) << md->key() << " " << std::setw(9) << std::setfill(' ') << std::left << md->typeName() << " " << std::dec << std::setw(3) << std::setfill(' ') << std::right << md->count() << " " << std::dec << md->value() << std::endl; } // ------------------------------------------------------------------------- // Serialize the XMP data and output the XMP packet std::string xmpPacket; if (0 != Exiv2::XmpParser::encode(xmpPacket, xmpData)) { throw Exiv2::Error(1, "Failed to serialize XMP data"); } std::cout << xmpPacket << "\n"; // Cleanup Exiv2::XmpParser::terminate(); return 0; } catch (Exiv2::AnyError& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; return -1; }
JSONNODE *ImgTagJson::genLitXmp(const Exiv2::Image::AutoPtr & image) { Exiv2::XmpData &data = image->xmpData(); data.sortByKey(); if (data.empty()) return NULL; Exiv2::XmpData::const_iterator end = data.end(); JMAP *grpmap = new JMAP(); JSONNODE *tree = json_new(JSON_NODE); for (Exiv2::XmpData::const_iterator i = data.begin(); i != end; ++i) { JSONNODE *grp; if (grpmap->find(i->groupName()) == grpmap->end()) { grp = json_new(JSON_NODE); json_set_name(grp, i->groupName().c_str()); grpmap->insert(JMAP::value_type(i->groupName(), grp)); } else grp = (grpmap->find(i->groupName()))->second; Exiv2::XmpData::const_iterator nxt = i + 1; if ((nxt != data.end()) && (i->key() == nxt->key())) { //cout << "Array Elem! " << i->key() << endl; JSONNODE *arr = json_new(JSON_ARRAY); json_set_name(arr, i->tagName().c_str()); json_push_back(arr, json_new_a((i->tagName()).c_str(), (i->print()).c_str())); while ((nxt != data.end()) && (nxt->key() == i->key())) { json_push_back(arr, json_new_a((nxt->tagName()).c_str(), (nxt->print()).c_str())); nxt++; } json_push_back(grp, arr); if (nxt == data.end()) break; i = nxt - 1; } else { json_push_back(grp, json_new_a((i->tagName()).c_str(), (i->print()).c_str())); } //cout << json_write_formatted(grp) << endl; } JMAP::iterator it; for(it = grpmap->begin(); it != grpmap->end(); it++) { json_push_back(tree, it->second); grpmap->erase(it); } //cout << it->first << endl; delete grpmap; //cout << json_write_formatted(tree) << endl; json_set_name(tree, "xmp"); return tree; }