bool xmp_files_open(XmpFilePtr xf, const char *path, XmpOpenFileOptions options) { CHECK_PTR(xf, false); RESET_ERROR; SXMPFiles *txf = (SXMPFiles*)xf; try { return txf->OpenFile(path, XMP_FT_UNKNOWN, options); } catch(const XMP_Error & e) { set_error(e); } return false; }
bool xmp_files_close(XmpFilePtr xf, XmpCloseFileOptions options) { CHECK_PTR(xf, false); RESET_ERROR; try { SXMPFiles *txf = (SXMPFiles*)xf; txf->CloseFile(options); } catch(const XMP_Error & e) { set_error(e); return false; } return true; }
bool xmp_files_put_xmp(XmpFilePtr xf, XmpPtr xmp) { CHECK_PTR(xf, false); CHECK_PTR(xmp, false); RESET_ERROR; SXMPFiles *txf = (SXMPFiles*)xf; try { txf->PutXMP(*(SXMPMeta*)xmp); } catch(const XMP_Error & e) { set_error(e); return false; } return true; }
bool xmp_files_can_put_xmp(XmpFilePtr xf, XmpPtr xmp) { CHECK_PTR(xf, false); RESET_ERROR; SXMPFiles *txf = (SXMPFiles*)xf; bool result = false; try { result = txf->CanPutXMP(*(SXMPMeta*)xmp); } catch(const XMP_Error & e) { set_error(e); return false; } return result; }
bool xmp_files_get_xmp(XmpFilePtr xf, XmpPtr xmp) { CHECK_PTR(xf, false); CHECK_PTR(xmp, false); RESET_ERROR; bool result = false; try { SXMPFiles *txf = (SXMPFiles*)xf; result = txf->GetXMP((SXMPMeta*)xmp); } catch(const XMP_Error & e) { set_error(e); } return result; }
bool xmp_files_get_file_info(XmpFilePtr xf, XmpStringPtr filePath, XmpOpenFileOptions *options, XmpFileType * file_format, XmpFileFormatOptions *handler_flags) { CHECK_PTR(xf, false); RESET_ERROR; bool result = false; SXMPFiles *txf = (SXMPFiles*)xf; try { result = txf->GetFileInfo(STRING(filePath), (XMP_OptionBits *)options, (XMP_FileFormat *)file_format, (XMP_OptionBits *)handler_flags); } catch(const XMP_Error & e) { set_error(e); return false; } return result; }
XmpPtr xmp_files_get_new_xmp(XmpFilePtr xf) { CHECK_PTR(xf, NULL); RESET_ERROR; SXMPMeta *xmp = new SXMPMeta(); SXMPFiles *txf = (SXMPFiles*)xf; bool result = false; try { result = txf->GetXMP(xmp); if(!result) { delete xmp; return NULL; } } catch(const XMP_Error & e) { set_error(e); } return (XmpPtr)xmp; }
static void ProcessFile ( const char * fileName ) { bool ok; char buffer [1000]; SXMPMeta xmpMeta; SXMPFiles xmpFile; XMP_FileFormat format; XMP_OptionBits openFlags, handlerFlags; XMP_PacketInfo xmpPacket; sprintf ( buffer, "Dumping main XMP for %s", fileName ); WriteMinorLabel ( sLogFile, buffer ); xmpFile.OpenFile ( fileName, kXMP_UnknownFile, kXMPFiles_OpenForRead ); ok = xmpFile.GetFileInfo ( 0, &openFlags, &format, &handlerFlags ); if ( ! ok ) return; fprintf ( sLogFile, "File info : format = \"%.4s\", handler flags = %.8X\n", &format, handlerFlags ); fflush ( sLogFile ); ok = xmpFile.GetXMP ( &xmpMeta, 0, &xmpPacket ); if ( ! ok ) return; XMP_Int32 offset = (XMP_Int32)xmpPacket.offset; XMP_Int32 length = xmpPacket.length; fprintf ( sLogFile, "Packet info : offset = %d, length = %d\n", offset, length ); fflush ( sLogFile ); fprintf ( sLogFile, "\nInitial XMP from %s\n", fileName ); xmpMeta.DumpObject ( DumpCallback, sLogFile ); xmpFile.CloseFile(); } // ProcessFile
/** * Initializes the toolkit and attempts to open a file for updating its metadata. Initially * an attempt to open the file is done with a handler, if this fails then the file is opened with * packet scanning. Once the file is open several properties are read and displayed in the console. * * Several properties are then modified, first by checking for their existence and then, if they * exist, by updating their values. The updated properties are then displayed again in the console. * * Next a new XMP object is created from an RDF stream, the properties from the new XMP object are * appended to the original XMP object and the updated properties are displayed in the console for * last time. * * The updated XMP object is then serialized in different formats and written to text files. Lastly, * the modified XMP is written back to the resource file. */ int main ( int argc, const char * argv[] ) { if ( argc != 2 ) // 2 := command and 1 parameter { cout << "usage: ModifyingXMP (filename)" << endl; return 0; } string filename = string( argv[1] ); if(!SXMPMeta::Initialize()) { cout << "Could not initialize toolkit!"; return -1; } XMP_OptionBits options = 0; #if UNIX_ENV options |= kXMPFiles_ServerMode; #endif // Must initialize SXMPFiles before we use it if(SXMPFiles::Initialize(options)) { try { // Options to open the file with - open for editing and use a smart handler XMP_OptionBits opts = kXMPFiles_OpenForUpdate | kXMPFiles_OpenUseSmartHandler; bool ok; SXMPFiles myFile; std::string status = ""; // First we try and open the file ok = myFile.OpenFile(filename, kXMP_UnknownFile, opts); if( ! ok ) { status += "No smart handler available for " + filename + "\n"; status += "Trying packet scanning.\n"; // Now try using packet scanning opts = kXMPFiles_OpenForUpdate | kXMPFiles_OpenUsePacketScanning; ok = myFile.OpenFile(filename, kXMP_UnknownFile, opts); } // If the file is open then read get the XMP data if(ok) { cout << status << endl; cout << filename << " is opened successfully" << endl; // Create the XMP object and get the XMP data SXMPMeta meta; myFile.GetXMP(&meta); // Display some properties in the console displayPropertyValues(&meta); /////////////////////////////////////////////////// // Now modify the XMP if(meta.DoesPropertyExist(kXMP_NS_XMP, "CreatorTool")) { // Update xap:CreatorTool - we don't need to set any option bits meta.SetProperty(kXMP_NS_XMP, "CreatorTool", "Updated By XMP SDK", 0); } // Update the Metadata Date XMP_DateTime updatedTime; // Get the current time. This is a UTC time automatically // adjusted for the local time SXMPUtils::CurrentDateTime(&updatedTime); if(meta.DoesPropertyExist(kXMP_NS_XMP, "MetadataDate")) { meta.SetProperty_Date(kXMP_NS_XMP, "MetadataDate", updatedTime, 0); } // Add an item onto the dc:creator array // Note the options used, kXMP_PropArrayIsOrdered, if the array does not exist it will be created meta.AppendArrayItem(kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered, "Author Name", 0); meta.AppendArrayItem(kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered, "Another Author Name", 0); // Now update alt-text properties meta.SetLocalizedText(kXMP_NS_DC, "title", "en", "en-US", "An English title"); meta.SetLocalizedText(kXMP_NS_DC, "title", "fr", "fr-FR", "Un titre Francais"); // Display the properties again to show changes cout << "After update:" << endl; displayPropertyValues(&meta); // Create a new XMP object from an RDF string SXMPMeta rdfMeta = createXMPFromRDF(); // Append the newly created properties onto the original XMP object // This will: // a) Add ANY new TOP LEVEL properties in the source (rdfMeta) to the destination (meta) // b) Replace any top level properties in the source with the matching properties from the destination SXMPUtils::ApplyTemplate(&meta, rdfMeta, kXMPTemplate_AddNewProperties | kXMPTemplate_ReplaceExistingProperties | kXMPTemplate_IncludeInternalProperties); // Display the properties again to show changes cout << "After Appending Properties:" << endl; displayPropertyValues(&meta); // Serialize the packet and write the buffer to a file // Let the padding be computed and use the default linefeed and indents without limits string metaBuffer; meta.SerializeToBuffer(&metaBuffer, 0, 0, "", "", 0); // Write the packet to a file as RDF writeRDFToFile(&metaBuffer, filename+"_XMP_RDF.txt"); // Write the packet to a file but this time as compact RDF XMP_OptionBits outOpts = kXMP_OmitPacketWrapper | kXMP_UseCompactFormat; meta.SerializeToBuffer(&metaBuffer, outOpts); writeRDFToFile(&metaBuffer, filename+"_XMP_RDF_Compact.txt"); // Check we can put the XMP packet back into the file if(myFile.CanPutXMP(meta)) { // If so then update the file with the modified XMP myFile.PutXMP(meta); } // Close the SXMPFile. This *must* be called. The XMP is not // actually written and the disk file is not closed until this call is made. myFile.CloseFile(); } else { cout << "Unable to open " << filename << endl; } } catch(XMP_Error & e) { cout << "ERROR: " << e.GetErrMsg() << endl; } // Terminate the toolkit SXMPFiles::Terminate(); SXMPMeta::Terminate(); } else { cout << "Could not initialize SXMPFiles."; return -1; } return 0; }
/** * Initializes the toolkit and attempts to open a file for reading metadata. Initially * an attempt to open the file is done with a handler, if this fails then the file is opened with * packet scanning. Once the file is open several properties are read and displayed in the console. * The XMP object is then dumped to a text file and the resource file is closed. */ int main ( int argc, const char * argv[] ) { if ( argc != 2 ) // 2 := command and 1 parameter { cout << "usage: ReadingXMP (filename)" << endl; return 0; } string filename = string( argv[1] ); if(!SXMPMeta::Initialize()) { cout << "Could not initialize toolkit!"; return -1; } // Must initialize SXMPFiles before we use it if ( ! SXMPFiles::Initialize() ) { cout << "Could not initialize SXMPFiles."; return -1; } try { // Options to open the file with - read only and use a file handler XMP_OptionBits opts = kXMPFiles_OpenForRead | kXMPFiles_OpenUseSmartHandler; bool ok; SXMPFiles myFile; std::string status = ""; // First we try and open the file ok = myFile.OpenFile(filename, kXMP_UnknownFile, opts); if( ! ok ) { status += "No smart handler available for " + filename + "\n"; status += "Trying packet scanning.\n"; // Now try using packet scanning opts = kXMPFiles_OpenForUpdate | kXMPFiles_OpenUsePacketScanning; ok = myFile.OpenFile(filename, kXMP_UnknownFile, opts); } // If the file is open then read the metadata if(ok) { cout << status << endl; cout << filename << " is opened successfully" << endl; // Create the xmp object and get the xmp data SXMPMeta meta; myFile.GetXMP(&meta); bool exists; // Read a simple property string simpleValue; //Stores the value for the property exists = meta.GetProperty(kXMP_NS_XMP, "CreatorTool", &simpleValue, NULL); if(exists) cout << "CreatorTool = " << simpleValue << endl; else simpleValue.clear(); // Get the first element in the dc:creator array string elementValue; exists = meta.GetArrayItem(kXMP_NS_DC, "creator", 1, &elementValue, NULL); if(exists) cout << "dc:creator = " << elementValue << endl; else elementValue.clear(); // Get the the entire dc:subject array string propValue; int arrSize = meta.CountArrayItems(kXMP_NS_DC, "subject"); for(int i = 1; i <= arrSize;i++) { meta.GetArrayItem(kXMP_NS_DC, "subject", i, &propValue, 0); cout << "dc:subject[" << i << "] = " << propValue << endl; } // Get the dc:title for English and French string itemValue; string actualLang; meta.GetLocalizedText(kXMP_NS_DC, "title", "en", "en-US", NULL, &itemValue, NULL); cout << "dc:title in English = " << itemValue << endl; meta.GetLocalizedText(kXMP_NS_DC, "title", "fr", "fr-FR", NULL, &itemValue, NULL); cout << "dc:title in French = " << itemValue << endl; // Get dc:MetadataDate XMP_DateTime myDate; if(meta.GetProperty_Date(kXMP_NS_XMP, "MetadataDate", &myDate, NULL)) { // Convert the date struct into a convenient string and display it string myDateStr; SXMPUtils::ConvertFromDate(myDate, &myDateStr); cout << "meta:MetadataDate = " << myDateStr << endl; } // See if the flash struct exists and see if it was used string path, value; exists = meta.DoesStructFieldExist(kXMP_NS_EXIF, "Flash", kXMP_NS_EXIF,"Fired"); if(exists) { bool flashFired; SXMPUtils::ComposeStructFieldPath(kXMP_NS_EXIF, "Flash", kXMP_NS_EXIF, "Fired", &path); meta.GetProperty_Bool(kXMP_NS_EXIF, path.c_str(), &flashFired, NULL); string flash = (flashFired) ? "True" : "False"; cout << "Flash Used = " << flash << endl; } // Dump the current xmp object to a file ofstream dumpFile; dumpFile.open("XMPDump.txt", ios::out); meta.DumpObject(DumpXMPToFile, &dumpFile); dumpFile.close(); cout << endl << "XMP dumped to XMPDump.txt" << endl; // Close the SXMPFile. The resource file is already closed if it was // opened as read only but this call must still be made. myFile.CloseFile(); } else { cout << "Unable to open " << filename << endl; } } catch(XMP_Error & e) { cout << "ERROR: " << e.GetErrMsg() << endl; } // Terminate the toolkit SXMPFiles::Terminate(); SXMPMeta::Terminate(); return 0; }
/** * Reads some metadata from a file and appends some custom XMP to it. Then does several * iterations, using various iterators. Each iteration is displayed in the console window. */ int main() { if(SXMPMeta::Initialize()) { XMP_OptionBits options = 0; #if UNIX_ENV options |= kXMPFiles_ServerMode; #endif if ( SXMPFiles::Initialize ( options ) ) { bool ok; SXMPFiles myFile; XMP_OptionBits opts = kXMPFiles_OpenForRead | kXMPFiles_OpenUseSmartHandler; ok = myFile.OpenFile("../../../testfiles/Image1.jpg", kXMP_UnknownFile, opts); if(ok) { SXMPMeta xmp; myFile.GetXMP(&xmp); // Add some custom metadata to the XMP object SXMPMeta custXMP(rdf, (XMP_StringLen) strlen(rdf)); SXMPUtils::ApplyTemplate(&xmp, custXMP, kXMPTemplate_AddNewProperties); // Store any details from the iter.Next() call string schemaNS, propPath, propVal; // Only visit the immediate children that are leaf properties of the Dublin Core schema SXMPIterator dcLeafIter(xmp, kXMP_NS_DC, (kXMP_IterJustChildren | kXMP_IterJustLeafNodes)); while(dcLeafIter.Next(&schemaNS, &propPath, &propVal)) { cout << schemaNS << " " << propPath << " = " << propVal << endl; } cout << "----------------------------------" << endl; // Visit one property from the XMP Basic schema SXMPIterator xmpKeywordsIter(xmp, kXMP_NS_XMP, "Keywords", kXMP_IterJustLeafNodes); while(xmpKeywordsIter.Next(&schemaNS, &propPath, &propVal)) { cout << schemaNS << " " << propPath << " = " << propVal << endl; } cout << "----------------------------------" << endl; // Visit the Dublin Core schema, omit any quailifiers and only // show the leaf properties SXMPIterator dcIter(xmp, kXMP_NS_DC, (kXMP_IterOmitQualifiers | kXMP_IterJustLeafNodes)); while(dcIter.Next(&schemaNS, &propPath, &propVal)) { cout << schemaNS << " " << propPath << " = " << propVal << endl; } cout << "----------------------------------" << endl; // Visit the Dublin Core schema, omit any quailifiers, // show the leaf properties but only return the leaf name and not the full path SXMPIterator dcIter2(xmp, kXMP_NS_DC, (kXMP_IterOmitQualifiers | kXMP_IterJustLeafNodes | kXMP_IterJustLeafName)); while(dcIter2.Next(&schemaNS, &propPath, &propVal)) { cout << schemaNS << " " << propPath << " = " << propVal << endl; } cout << "----------------------------------" << endl; // Iterate over a single namespace. Show all properties within // the Photoshop schema SXMPIterator exifIter(xmp, kXMP_NS_Photoshop); while(exifIter.Next(&schemaNS, &propPath, &propVal)) { cout << schemaNS << " " << propPath << " = " << propVal << endl; } cout << "----------------------------------" << endl; // Just visit the leaf nodes of EXIF properties. That is just // properties that may have values. SXMPIterator exifLeafIter(xmp, kXMP_NS_EXIF, kXMP_IterJustLeafNodes); while(exifLeafIter.Next(&schemaNS, &propPath, &propVal)) { cout << schemaNS << " " << propPath << " = " << propVal << endl; } cout << "----------------------------------" << endl; // Iterate over all properties but skip the EXIF schema and skip the custom schema // and continue visiting nodes SXMPIterator skipExifIter (xmp); while(skipExifIter.Next(&schemaNS, &propPath, &propVal)) { if(schemaNS == kXMP_NS_EXIF || schemaNS == kXMP_NS_SDK) { skipExifIter.Skip(kXMP_IterSkipSubtree); } else { cout << schemaNS << " " << propPath << " = " << propVal << endl; } } cout << "----------------------------------" << endl; // Iterate over all properties but skip the EXIF schema // and any remaining siblings of the current node. SXMPIterator stopAfterExifIter ( xmp ); while(stopAfterExifIter.Next(&schemaNS, &propPath, &propVal)) { if(schemaNS == kXMP_NS_EXIF || schemaNS == kXMP_NS_SDK) { stopAfterExifIter.Skip(kXMP_IterSkipSiblings); } else { cout << schemaNS << " " << propPath << " = " << propVal << endl; } } cout << "----------------------------------" << endl; ////////////////////////////////////////////////////////////////////////////////////// // Iterate over the custom XMP // Visit the immediate children of this node. // No qualifiers are visisted as they are below the property being visisted. SXMPIterator justChildrenIter(xmp, kXMP_NS_SDK, kXMP_IterJustChildren); while(justChildrenIter.Next(&schemaNS, &propPath, &propVal)) { cout << propPath << " = " << propVal << endl; } cout << "----------------------------------" << endl; // Visit the immediate children of this node but only those that may have values. // No qualifiers are visisted as they are below the property being visisted. SXMPIterator justChildrenAndLeafIter(xmp, kXMP_NS_SDK, (kXMP_IterJustChildren | kXMP_IterJustLeafNodes)); while(justChildrenAndLeafIter.Next(&schemaNS, &propPath, &propVal)) { cout << propPath << " = " << propVal << endl; } cout << "----------------------------------" << endl; // Visit the leaf nodes of TopStructProperty SXMPIterator myTopStructIter(xmp, kXMP_NS_SDK, "MyTopStruct", kXMP_IterJustLeafNodes); while(myTopStructIter.Next(&schemaNS, &propPath, &propVal)) { cout << propPath << " = " << propVal << endl; } cout << "----------------------------------" << endl; // Visit the leaf nodes of the TopStructProperty but only return the names for // the leaf components and not the full path SXMPIterator xmyTopStructIterShortNames(xmp, kXMP_NS_SDK, "MyTopStruct", (kXMP_IterJustLeafNodes | kXMP_IterJustLeafName)); while(xmyTopStructIterShortNames.Next(&schemaNS, &propPath, &propVal)) { cout << propPath << " = " << propVal << endl; } cout << "----------------------------------" << endl; // Visit a property and all of the qualifiers SXMPIterator iterArrayProp (xmp, kXMP_NS_SDK, "ArrayWithStructures", kXMP_IterJustLeafNodes ); while(iterArrayProp.Next(&schemaNS, &propPath, &propVal)) { cout << propPath << " = " << propVal << endl; } cout << "----------------------------------" << endl; // Visit a property and omit all of the qualifiers SXMPIterator iterArrayPropNoQual (xmp, kXMP_NS_SDK, "ArrayWithStructures", (kXMP_IterJustLeafNodes | kXMP_IterOmitQualifiers)); while(iterArrayPropNoQual.Next(&schemaNS, &propPath, &propVal)) { cout << propPath << " = " << propVal << endl; } cout << "----------------------------------" << endl; // Skip a subtree and continue onwards. Once 'Item 4' is found then the we can skip all of the // siblings of the current node. If the the current node were a top level node the iteration // would be complete as all siblings would be skipped. However, when 'Item 4' is found the current // node is not at the top level so there are other nodes further up the tree that still need to be // visited. SXMPIterator skipIter (xmp, kXMP_NS_SDK, (kXMP_IterJustLeafNodes | kXMP_IterOmitQualifiers | kXMP_IterJustLeafName)); while(skipIter.Next(&schemaNS, &propPath, &propVal)) { if(propVal == "Item 4") { skipIter.Skip(kXMP_IterSkipSiblings); } else { cout << schemaNS << " " << propPath << " = " << propVal << endl; } } /* // Visit all properties and qualifiers SXMPIterator allPropsIter(xmp); while(allPropsIter.Next(&schemaNS, &propPath, &propVal)) { cout << schemaNS << " " << propPath << " = " << propVal << endl; } */ } } } SXMPFiles::Terminate(); SXMPMeta::Terminate(); return 0; }