static void ExportIPTC_SubjectCode ( const SXMPMeta & xmp, IPTC_Manager * iptc ) { std::string xmpValue, iimValue; XMP_OptionBits xmpFlags; bool found = xmp.GetProperty ( kXMP_NS_IPTCCore, "SubjectCode", 0, &xmpFlags ); if ( ! found ) { iptc->DeleteDataSet ( kIPTC_SubjectCode ); return; } if ( ! XMP_PropIsArray ( xmpFlags ) ) return; // ? Complain? Delete the DataSet? XMP_Index xmpCount = xmp.CountArrayItems ( kXMP_NS_IPTCCore, "SubjectCode" ); XMP_Index iptcCount = (XMP_Index) iptc->GetDataSet ( kIPTC_SubjectCode, 0 ); if ( xmpCount != iptcCount ) iptc->DeleteDataSet ( kIPTC_SubjectCode ); for ( XMP_Index ds = 0; ds < xmpCount; ++ds ) { // ! XMP arrays are indexed from 1, IPTC from 0. (void) xmp.GetArrayItem ( kXMP_NS_IPTCCore, "SubjectCode", ds+1, &xmpValue, &xmpFlags ); if ( ! XMP_PropIsSimple ( xmpFlags ) ) continue; // ? Complain? if ( xmpValue.size() != 8 ) continue; // ? Complain? iimValue = "IPTC:"; iimValue += xmpValue; iimValue += ":::"; // Add the separating colons for the empty name portions. iptc->SetDataSet_UTF8 ( kIPTC_SubjectCode, iimValue.c_str(), (XMP_Uns32)iimValue.size(), ds ); // ! Appends if necessary. } } // ExportIPTC_SubjectCode
static void ExportIPTC_Array ( const SXMPMeta & xmp, IPTC_Manager * iptc, const char * xmpNS, const char * xmpProp, XMP_Uns8 id ) { std::string value; XMP_OptionBits xmpFlags; bool found = xmp.GetProperty ( xmpNS, xmpProp, 0, &xmpFlags ); if ( ! found ) { iptc->DeleteDataSet ( id ); return; } if ( ! XMP_PropIsArray ( xmpFlags ) ) return; // ? Complain? Delete the DataSet? XMP_Index xmpCount = xmp.CountArrayItems ( xmpNS, xmpProp ); XMP_Index iptcCount = (XMP_Index) iptc->GetDataSet ( id, 0 ); if ( xmpCount != iptcCount ) iptc->DeleteDataSet ( id ); for ( XMP_Index ds = 0; ds < xmpCount; ++ds ) { // ! XMP arrays are indexed from 1, IPTC from 0. (void) xmp.GetArrayItem ( xmpNS, xmpProp, ds+1, &value, &xmpFlags ); if ( ! XMP_PropIsSimple ( xmpFlags ) ) continue; // ? Complain? NormalizeToCR ( &value ); iptc->SetDataSet_UTF8 ( id, value.c_str(), (XMP_Uns32)value.size(), ds ); // ! Appends if necessary. } } // ExportIPTC_Array
bool xmp_get_array_item(XmpPtr xmp, const char *schema, const char *name, int32_t index, XmpStringPtr property, uint32_t *propsBits) { CHECK_PTR(xmp, false); RESET_ERROR; bool ret = false; try { SXMPMeta *txmp = (SXMPMeta *)xmp; XMP_OptionBits optionBits; ret = txmp->GetArrayItem(schema, name, index, STRING(property), &optionBits); if(propsBits) { *propsBits = optionBits; } } catch(const XMP_Error & e) { set_error(e); } return ret; }
/** * 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; }
static void exportXMPtoListChunk( XMP_Uns32 id, XMP_Uns32 containerType, RIFF_MetaHandler* handler, ContainerChunk** listChunk, Mapping mapping[]) { // note: ContainerChunk**: adress of pointer to allow changing the pointer itself (i.e. chunk creation) SXMPMeta* xmp = &handler->xmpObj; bool listChunkIsNeeded = false; // assume for now // ! The NUL is optional in WAV to avoid a parsing bug in Audition 3 - can't handle implicit pad byte. bool optionalNUL = (handler->parent->format == kXMP_WAVFile); for ( int p=0; mapping[p].chunkID != 0; ++p ) { // go through all potential property mappings bool propExists = false; std::string value, actualLang; switch ( mapping[p].propType ) { // get property. if existing, remove from XMP (to avoid redundant storage) case prop_TIMEVALUE: propExists = xmp->GetStructField ( mapping[p].ns, mapping[p].prop, kXMP_NS_DM, "timeValue", &value, 0 ); break; case prop_LOCALIZED_TEXT: propExists = xmp->GetLocalizedText ( mapping[p].ns, mapping[p].prop, "", "x-default", &actualLang, &value, 0); if ( actualLang != "x-default" ) propExists = false; // no "x-default" => nothing to reconcile ! break; case prop_ARRAYITEM: propExists = xmp->GetArrayItem ( mapping[p].ns, mapping[p].prop, 1, &value, 0 ); break; case prop_SIMPLE: propExists = xmp->GetProperty ( mapping[p].ns, mapping[p].prop, &value, 0 ); break; default: XMP_Throw ( "internal error", kXMPErr_InternalFailure ); } if ( ! propExists ) { if ( *listChunk != 0 ) (*listChunk)->removeValue ( mapping[p].chunkID ); } else { listChunkIsNeeded = true; if ( *listChunk == 0 ) *listChunk = new ContainerChunk ( handler->riffChunks[0], id, containerType ); valueMap* cm = &(*listChunk)->childmap; valueMapIter result = cm->find( mapping[p].chunkID ); ValueChunk* propChunk = 0; if ( result != cm->end() ) { propChunk = result->second; } else { propChunk = new ValueChunk ( *listChunk, std::string(), mapping[p].chunkID ); } propChunk->SetValue ( value.c_str(), optionalNUL ); } } // for each property if ( (! listChunkIsNeeded) && (*listChunk != 0) && ((*listChunk)->children.size() == 0) ) { (*listChunk)->parent->replaceChildWithJunk ( *listChunk ); (*listChunk) = 0; // reset direct Chunk pointer } }