// =================================================================================================
// Copyright 2008 Adobe Systems Incorporated
// All Rights Reserved.
//
// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
// of the Adobe license agreement accompanying it.
// =================================================================================================
/**
* Tutorial solution for the Walkthrough 1 in the XMP Programmers Guide, Opening files and reading XMP.
* Demonstrates the basic use of the XMPFiles and XMPCore components, obtaining read-only XMP from a file
* and examining it through the XMP object.
*/
#include <cstdio>
#include <vector>
#include <string>
#include <cstring>
// Must be defined to instantiate template classes
#define TXMP_STRING_TYPE std::string
// Must be defined to give access to XMPFiles
#define XMP_INCLUDE_XMPFILES 1
// Ensure XMP templates are instantiated
#include "public/include/XMP.incl_cpp"
// Provide access to the API
#include "public/include/XMP.hpp"
#include <iostream>
#include <fstream>
using namespace std;
/**
* Client defined callback function to dump XMP to a file. In this case an output file stream is used
* to write a buffer, of length bufferSize, to a text file. This callback is called multiple
* times during the DumpObject() operation. See the XMP API reference for details of
* XMP_TextOutputProc() callbacks.
*/
XMP_Status DumpXMPToFile(void * refCon, XMP_StringPtr buffer, XMP_StringLen bufferSize)
{
XMP_Status status = 0;
try
{
ofstream * outFile = static_cast<ofstream*>(refCon);
(*outFile).write(buffer, bufferSize);
}
catch(XMP_Error & e)
{
cout << e.GetErrMsg() << endl;
return -1; // Return a bad status
}
return status;
}
/**
* 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;
}
XMP_OptionBits options = 0;
#if UNIX_ENV
options |= kXMPFiles_ServerMode;
#endif
// Must initialize SXMPFiles before we use it
if ( ! SXMPFiles::Initialize ( options ) )
{
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;
}