1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
|
// =================================================================================================
// 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 3 in the XMP Programmers Guide, Working with custom schema.
*
* Demonstrates how to work with a custom schema that has complex properties. It shows how to access
* and modify properties with complex paths using the path composition utilities from the XMP API
*/
#include <string>
// Must be defined to instantiate template classes
#define TXMP_STRING_TYPE std::string
// Ensure XMP templates are instantiated
#include "XMP.incl_cpp"
// Provide access to the API
#include "XMP.hpp"
#include <iostream>
#include <fstream>
// Made up namespace URI. Prefix will be xsdkEdit and xsdkUser
const XMP_StringPtr kXMP_NS_SDK_EDIT = "http://ns.adobe/meta/sdk/Edit/";
const XMP_StringPtr kXMP_NS_SDK_USERS = "http://ns.adobe/meta/sdk/User/";
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 XMPFileDump(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 status;
}
/**
* Client defined callback function to dump the registered namespaces 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 DumpNS(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 status;
}
/**
* Writes an XMP packet in XML format to a text file
*
* rdf - a pointer to the serialized XMP
* filename - the name of the file to write to
*/
void writeRDFToFile(string * rdf, string filename)
{
ofstream outFile;
outFile.open(filename.c_str(), ios::out);
outFile << *rdf;
outFile.close();
}
/**
* Registers the namespaces that will be used with the custom schema. Then adds several new
* properties to that schema. The properties are complex, containing nested arrays and structures.
*
* XMPFiles is not used in this sample, hence no external resource is updated with the metadata. The
* created XMP object is serialized and written as RDF to a text file, the XMP object is dumped to
* a text file and the registered namespaces are also dumped to a text file.*
*
*/
int main()
{
if(!SXMPMeta::Initialize())
{
cout << "Could not initialize Toolkit!";
}
else
{
try
{
// Register the namespaces
string actualPrefix;
SXMPMeta::RegisterNamespace(kXMP_NS_SDK_EDIT, "xsdkEdit", &actualPrefix);
SXMPMeta::RegisterNamespace(kXMP_NS_SDK_USERS, "xsdkUser",&actualPrefix);
SXMPMeta meta;
// Adds a user of the document
// 1. Add a new item onto the DocumentUsers array -
// 2. Compose a path to the last element of DocumentUsers array
// 3. Add a value for the User field of the UserDetails structure
// 4. Add a qualifier to the User field. Compose the path and set the value
// 5. Add a value for the DUID field of the UserDetails structure
// 6. Add a Contact property for the ContactDetails field of the UserDetails structure
// 7. Compose a path to the ContactDetails field of the UserDetails structure.
// 8. Create the fields of the ContactDetails structure and provide values
// Create/Append the top level DocumentUsers array. If the array exists a new item will be added
meta.AppendArrayItem(kXMP_NS_SDK_EDIT, "DocumentUsers", kXMP_PropValueIsArray, 0, kXMP_PropValueIsStruct);
// Compose a path to the last item in the DocumentUsers array, this will point to a UserDetails structure
string userItemPath;
SXMPUtils::ComposeArrayItemPath(kXMP_NS_SDK_EDIT, "DocumentUsers", kXMP_ArrayLastItem, &userItemPath);
// We now have a path to the structure, so we can set the field values
meta.SetStructField(kXMP_NS_SDK_EDIT, userItemPath.c_str(), kXMP_NS_SDK_USERS, "User", "John Smith", 0);
// Add a qualifier to the User field, first compose the path to the field and then add the qualifier
string userFieldPath;
SXMPUtils::ComposeStructFieldPath(kXMP_NS_SDK_EDIT, userItemPath.c_str(), kXMP_NS_SDK_USERS, "User", &userFieldPath);
meta.SetQualifier(kXMP_NS_SDK_EDIT, userFieldPath.c_str(), kXMP_NS_SDK_USERS, "Role", "Dev Engineer");
// Compose a path to the DUID and set field value
string duidPath;
SXMPUtils::ComposeStructFieldPath(kXMP_NS_SDK_EDIT, userItemPath.c_str(), kXMP_NS_SDK_USERS, "DUID", &duidPath);
meta.SetProperty_Int(kXMP_NS_SDK_EDIT, duidPath.c_str(), 2, 0);
// Add the ContactDetails field, this field is a Contact structure
meta.SetStructField(kXMP_NS_SDK_EDIT, userItemPath.c_str(), kXMP_NS_SDK_USERS, "ContactDetails", 0, kXMP_PropValueIsStruct);
// Compose a path to the field that has the ContactDetails structure
string contactStructPath;
SXMPUtils::ComposeStructFieldPath(kXMP_NS_SDK_EDIT, userItemPath.c_str(), kXMP_NS_SDK_USERS, "ContactDetails", &contactStructPath);
// Now add the fields - all empty initially
meta.SetStructField(kXMP_NS_SDK_EDIT, contactStructPath.c_str(), kXMP_NS_SDK_USERS, "Email", 0, kXMP_PropArrayIsAlternate);
meta.SetStructField(kXMP_NS_SDK_EDIT, contactStructPath.c_str(), kXMP_NS_SDK_USERS, "Telephone", 0, kXMP_PropValueIsArray);
meta.SetStructField(kXMP_NS_SDK_EDIT, contactStructPath.c_str(), kXMP_NS_SDK_USERS, "BaseLocation", "", 0);
// Add some values for the fields
// Email: Get the path to the field named 'Email' in the ContactDetails structure and use it to append items
string path;
SXMPUtils::ComposeStructFieldPath(kXMP_NS_SDK_EDIT, contactStructPath.c_str(), kXMP_NS_SDK_USERS, "Email", &path);
meta.AppendArrayItem(kXMP_NS_SDK_EDIT, path.c_str(), 0, "js@adobe.meta.com", 0);
meta.AppendArrayItem(kXMP_NS_SDK_EDIT, path.c_str(), 0, "js@adobe.home.com", 0);
// Telephone
SXMPUtils::ComposeStructFieldPath(kXMP_NS_SDK_EDIT, contactStructPath.c_str(), kXMP_NS_SDK_USERS, "Telephone", &path);
meta.AppendArrayItem(kXMP_NS_SDK_EDIT, path.c_str(), 0, "89112", 0);
meta.AppendArrayItem(kXMP_NS_SDK_EDIT, path.c_str(), 0, "84432", 0);
// BaseLocation
SXMPUtils::ComposeStructFieldPath(kXMP_NS_SDK_EDIT, contactStructPath.c_str(), kXMP_NS_SDK_USERS, "BaseLocation", &path);
meta.SetProperty(kXMP_NS_SDK_EDIT, path.c_str(), "London", 0);
// Add a user edit
// 1. Add an item (a structure) to the DocumentEdit array
// 2. Compose a path to the last item in the DocumentEdit array
// 3. Add fields and values to the EditDetails structure
// Create the array
meta.AppendArrayItem(kXMP_NS_SDK_EDIT, "DocumentEdit", kXMP_PropArrayIsOrdered, 0, kXMP_PropValueIsStruct);
// Compose a path to the last item of the DocumentEdit array, this gives the path to the structure
string lastItemPath;
SXMPUtils::ComposeArrayItemPath(kXMP_NS_SDK_EDIT, "DocumentEdit", kXMP_ArrayLastItem, &lastItemPath);
// Add the Date field
SXMPUtils::ComposeStructFieldPath(kXMP_NS_SDK_EDIT, lastItemPath.c_str(), kXMP_NS_SDK_EDIT, "EditDate", &path);
XMP_DateTime dt;
SXMPUtils::CurrentDateTime(&dt);
meta.SetProperty_Date(kXMP_NS_SDK_EDIT, path.c_str(), dt, 0);
// Add the DUID field
SXMPUtils::ComposeStructFieldPath(kXMP_NS_SDK_EDIT, lastItemPath.c_str(), kXMP_NS_SDK_EDIT, "DUID", &path);
meta.SetProperty_Int(kXMP_NS_SDK_EDIT, path.c_str(), 2, 0);
// Add the EditComments field
SXMPUtils::ComposeStructFieldPath(kXMP_NS_SDK_EDIT, lastItemPath.c_str(), kXMP_NS_SDK_EDIT, "EditComments", &path);
meta.SetLocalizedText(kXMP_NS_SDK_EDIT, path.c_str(), "en", "en-US", "Document created.", 0);
// Add the EditTool field
meta.SetStructField(kXMP_NS_SDK_EDIT, lastItemPath.c_str(), kXMP_NS_SDK_EDIT, "EditTool", "FrameXML", 0);
// Write the RDF to a file
cout << "writing RDF to file CS_RDF.txt" << endl;
string metaBuffer;
meta.SerializeToBuffer(&metaBuffer);
writeRDFToFile(&metaBuffer, "CS_RDF.txt");
// Dump the XMP object
cout << "dumping XMP object to file XMPDump.txt" << endl;
ofstream dumpFile;
dumpFile.open("XMPDump.txt", ios::out);
meta.DumpObject(XMPFileDump, &dumpFile);
dumpFile.close();
// Dump the namespaces to a file
cout << "dumping namespaces to file NameDump.txt" << endl;
dumpFile.open("NameDump.txt", ios::out);
meta.DumpNamespaces(XMPFileDump, &dumpFile);
dumpFile.close();
}
catch(XMP_Error & e)
{
cout << "ERROR: " << e.GetErrMsg();
}
SXMPMeta::Terminate();
}
return 0;
}
|