Action Script Access To XMP
Action Script Access To XMP
ACTIONSCRIPT
PROGRAMMER’S GUIDE
2
NOTICE: All information contained herein is the property of Adobe Systems Incorporated. No part of this publication
(whether in hardcopy or electronic form) may be reproduced or transmitted, in any form or by any means, electronic,
mechanical, photocopying, recording, or otherwise, without the prior written consent of Adobe Systems Incorporated.
Adobe, the Adobe logo, Acrobat, Acrobat Distiller, Framemaker, InDesign, Photoshop, PostScript, the PostScript logo, and
XMP are either registered trademarks or trademarks of Adobe Systems Incorporated in the United States and/or other
countries. MS-DOS, Windows, and Windows NT are either registered trademarks or trademarks of Microsoft Corporation
in the United States and/or other countries. Apple, Macintosh, and QuickTime are trademarks of Apple Computer, Inc.,
registered in the United States and other countries. UNIX is a trademark in the United States and other countries,
licensed exclusively through X/Open Company, Ltd. All other trademarks are the property of their respective owners.
This publication and the information herein is furnished AS IS, is subject to change without notice, and should not be
construed as a commitment by Adobe Systems Incorporated. Adobe Systems Incorporated assumes no responsibility or
liability for any errors or inaccuracies, makes no warranty of any kind (express, implied, or statutory) with respect to this
publication, and expressly disclaims any and all warranties of merchantability, fitness for particular purposes, and
noninfringement of third party rights.
Contents 3
Contents
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Manipulating metadata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Working with simple properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Data types for simple properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Working with structured properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Working with array properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Working with language alternatives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Working with qualifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
Handling dates and times . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
Iterating XMP properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
Error Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Programmer’s Guide
The ActionScript XMP Library is intended to be used with Adobe Flash and Flex technology, to read,
modify and create XMP packets in the RDF/XML format.
Readers of this document should be familiar with the XMP Technology. The XMP Specification, available
from Adobe Developer Center (XMP), provides a complete formal specification for XMP. Before working
with the XMP Library for ActionScript, you must be familiar with, at a minimum, the XMP Data Model.
X Part 1, Data and Serialization Models covers the basic metadata representation model that is the
foundation of the XMP standard format. The Data Model prescribes how XMP metadata can be
organized; it is independent of file format or specific usage. The Serialization Model prescribes how
the Data Model is represented in XML, specifically RDF.
X Part 2, Standard Schemas, provides detailed property lists and descriptions for standard XMP metadata
schemas; these include general-purpose schemas such as Dublin Core, and special-purpose schemas
for Adobe applications such as Photoshop. It also provides information on extending existing schemas
and creating new schemas.
X Part 3, Storage in Files, provides information about how serialized XMP metadata is packaged into XMP
Packets and embedded in different file formats. It includes information about how XMP relates to and
incorporates other metadata formats, and how to reconcile values that are represented in multiple
metadata formats.
Introduction
This library is an ActionScript 3 implementation of the C/C++ XMPCore library. It is written entirely in
ActionScript 3 and and has no other dependencies. The XMPCore library is the component that is used to
manipulate the contents XMP Packets using the XMP Data Model; it does not deal with how XMP Packets
are embedded in files.
XMP metadata is represented in memory as an object tree that reflects the XMP data model, as described
in the XMP Specification: Part 1, Data and Serialization Models. The XMPCore ActionScript Library allows
direct access to every node of the tree. The root node represents the XMP Packet itself. Each tree node
represents an XMP property. Properties can be simple (key-value pairs) or complex (structures). Complex
properties can be nested to any depth; that is, stuctures or arrays can contain other structures or arrays.
Properties can have qualifiers that describe their values; for example, the xml:lang qualifier contains the
language associated with each item in an alternative text array.
You can use the API functions to iterate the nodes recursively, in order to traverse the complete tree if
needed. The library assures that the data tree is always in a valid state and can therefore be serialized into a
well-formed XMP Packet at any time. If you use an API function incorrectly, the library throws an exception.
X The data model represents a set of XMP data in memory. The API allows you to create, modify, or delete
XMP properties.
X The parser reads an XMP packet in RDF/XML format into the data model in memory.
4
Programmer’s Guide XMPCore ActionScript library 5
1. Create or open the Flex project in Flash Builder, or Eclipse with the Flash Builder plug-in.
2. If a libs/ folder does not yet exist in the project’s root folder, create it.
3. Copy the XMPCore.swc library into the libs/ folder. Flash Builder automatically recognizes libraries in
this folder.
4. To check it, open the project properties and select the "Flex Build Path" page. In the "Library path" tab,
open the libs/ folder and verify that the XMPCore library is available.
Programmer’s Guide XMP namespaces and prefixes 6
Each XMP property that is added or requested must be an XML QName, consisting of a namespace and a
local name. In XML representation, namespaces are always bound to a prefix, which is used in the tags as a
shortcut for the whole namespace URI. This is a snippet from an XMP packet that shows the association of
a namespace with the prefix xmp, and the use of that prefix in addressing an element:
<rdf:Description xmlns:xmp="http://ns.adobe.com/xap/1.0/">
<xmp:CreatorTool="Photoshop">
...
</rdf:Description>
For example, for the RDF XML expression above, read access to the CreatorTool property looks like this:
var meta: XMPMeta = new XMPMeta();
var xmp:Namespace = new Namespace("http://ns.adobe.com/xap/1.0/");
meta.xmp::CreatorTool = "Photoshop";
Here, the variable xmp is a Namespace object whose value is the actual namespace URI. It is common
practice and avoids confusion to use the default XML prefix as the name of this variable (as shown in the
example), although this is not required.
Each metadata property becomes a dynamic property of the XMP object, in a hierachical tree structure. You
access each node using its fully qualified name; that is, the namespace object and the property key name,
with a double colon between them.
Programmer’s Guide Parsing and serializing metadata 7
For example, if you have assigned an XMPMeta object to the variable meta, and a Namespace object to the
variable my, the following assigns a value to a field contained in a nested structure, using dot notation:
inner struct
Similarly, you can access array values at any depth using square brackets.
inner array
meta.Iptc4xmpExt:LocationShown[1].Iptc4xmpExt:City = "Hamburg";
meta.Iptc4xmpExt:LocationShown[1].Iptc4xmpExt:CountryName = "Germany";
Compared to the native C++ XMP parser, some legacy functionality has been removed for the
ActionScript library in favor of small footprint and performance:
Z Alias functionality has been removed. Since all existing XMPCore implementations have not
created aliased properties for some years, this change does not break existing XMP packets
created with any newer application (approximately since CS1).
Z Latin1 characters are not tolerated in XMP packets anymore. Only valid UTF-8 or UTF-16 (LE and
BE) encodings are accepted.
X The serializer serializes the memory model to RDF/XML, as a String, ByteArray or XML object. The API
provides options for configuring the XML output. The most commonly used options are for encoding
and the absolute length of the resulting packet.
Prefixes are not stored in the data model. The parser collects the namespace prefixes, to be used when the
same XMPMeta object is serialized after modification. The Adobe standard namespaces, defined in the XMP
Specification: Part 2, Standard Schemas, are stored in a global namespace registry of the library. You can
also register custom prefixes for your own namespaces; if the serializer does not find a registered prefix for
a certain namespace, it generates prefixes of the form "ns1", "ns2" and so on.
Programmer’s Guide Parsing and serializing metadata 8
X Create and fill an XMPMeta object by parsing an XMP packet from a String:
var metaStr: String = "<x:xmpmeta xmlns:x="adobe:ns:meta/">" +
...
"</x:xmpmeta>";
var meta: XMPMeta = new XMPMeta(metaStr);
X Create and fill an XMPMeta object by parsing an XMP packet from an XML object:
var metaXML: XML = <x:xmpmeta xmlns:x="adobe:ns:meta/">
...
</x:xmpmeta>;
var meta2: XMPMeta = new XMPMeta(metaXML);
X Create and fill an XMPMeta object by parsing from a ByteArray, which is useful when the packet is read
from a file or stream.
X Use the SerializeOptions object to set non-default serialization options, and pass it to one of the
serialization methods. For example, to serialize in UTF-16LE encoding to a packet with the exact length
8192:
var options: SerializeOptions = new SerializeOptions();
options.encoding = SerializeOptions.UTF16LE;
options.exactPacketLength = 8192;
var buffer:ByteBuffer = meta.serializeToBuffer(options);
X To simplify debugging or write unit tests, use the dumpObject() method to serialize to a
human-readable, debug format:
trace(meta.dumpObject());
Programmer’s Guide Manipulating metadata 9
Manipulating metadata
This section describes some typical workflows, with source code examples. For details of functions and
usage, see the “XMPCore ActionScript Library Reference” on page 16.
X Delete properties by setting the value to null, or use the delete operator:
meta.my::simpleProp = null;
—or—
delete meta.my::simpleProp;
X Use the exists() method or the standard toString() method to find out whether a property
currently exists in an XMP object:
trace( meta.xmpNS::Rating.exists() ); // true
trace( meta.my::simpleProp.exists() ); // false
trace( meta.my::simpleProp.toString() ); // null
You can assign all kinds of literal data types to simple properties; however, they are all converted to String
before the value is added.
X Boolean values are converted to "True" or "False" (with a leading capital letter)
X Date objects are converted to ISO 8601 format (see “Handling dates and times” on page 12).
Programmer’s Guide Manipulating metadata 10
The XMPMeta object provides convenience methods for retrieving String property values as literal types:
toBoolean()
toInteger()
toFloat()
toDate()
X Continuing the example using the XMPMeta object (meta) and Namespace object (my), we add a
structure with two simple property fields:
meta.my::struct = new XMPStruct();
meta.my::struct.my::structField1 = "value 1";
meta.my::struct.my::structField2 = "value 2";
X Structured properties can be nested. In this example, we add a nested struct named
my::innerStruct to my:struct, which contains two additional simple-property fields.
Z You can accomplish the same thing by first creating the inner XMPStruct object, and add it to the
XMP object afterward:
var struct: XMPStruct = new XMPStruct();
struct.my::innerField1 = "field 1";
struct.my::innerField2 = "field 1";
Z For convenience, you can also create nested structures implicitly, simply by adding the first field to
it:
meta.my::implicitlyCreated.my::field1 = "value 1";
meta.my::implicitlyCreated.my::field2 = "value 2";
See “Implicit property creation” on page 13 for more details of this technique.
X Delete structures in the same way as simple properties, by setting them to null or using the delete
operator. All direct and nested child properties are also deleted:
meta.my::struct = null
—or—
delete meta.my::struct
Programmer’s Guide Manipulating metadata 11
To add items, use the square brackets, "[...]" operator, or the append() and insert() methods of the
XMPArray object.
X Arrays start with index 1 and must be filled from start to end.
X You cannot add an item at an index that is beyond the index of the last existing member plus one. For
example, an array with the length 5 accepts indexes [1..5] for reading and [1..6] for writing; the index
value of 6 appends a new item.
X The last() method accesses the last item; you can use the function as an index value, ["last()"].
var index = 3;
meta.my::seqArray[index] = "three"; // use a variable as an index
meta.my::seqArray.append("five");
meta.my::seqArray.insert(4, "four");
Arrays can contain other arrays or structures as items. The property types of the items can be mixed,
although this is not commonly used in XMP.
Arrays can also be created implicitly by adding the first item; see “Implicit property creation” on page 13.
For instance, the last example can created simply by adding the nested structure field; the outer array and
the structure itself are created automatically:
meta.my::arrayOfStructs[1].my::structField = 4711;
Programmer’s Guide Manipulating metadata 12
The API provides a convenience accessor, lang[], to handle localized text. Use it as if it were a nested array
in the alt-text array (although it is not an acual property); use the language code as the index variable to
access language-specific items. For example, to set values:
meta.my::localizedText = XMPArray.newAlt();
meta.my::localizedText.lang["en-US"] = "English"; // default
meta.my::localizedText.lang["de-DE"] = "German";
meta.my::localizedText.lang["fr-FR"] = "French";
For the format of the locale, use a String that conforms to the RFC 3066 notation, with two or three
two-character codes for the language, country, and optional dialect, in the form xx-YY-zz. The provided
locale is automatically normalized to the described format.
Many applications work with only one default language, that has no specific locale. In this case, the
constant "x-default" is used as locale.
dc::title.lang["x-default"] = "unspecific language"; // default
trace(dc::title.lang["x-default"]);
If the "x-default" is requested from an array that does not have this entry, the first array item is returned.
The API provides a convenience accessor, qualifier, to access the qualifiers associated with a node. Use it
as if it were a property of XMPProperty, XMPArray and XMPStruct (although it is not an acual property),
which itself has dynamic properties for the qualifiers. Access these by their fully-qualified names, in the
same way that you access the dynamic properties of the XMNode objects.
meta.my::myProp.qualifier.my::myQualifier = "description";
XMPProperty XMPQualifier
accessor
Programmer’s Guide Manipulating metadata 13
Retrieving the value as a String returns the ISO representation of the date. To retrieve the date as
ActionScript Date object, call the toDate() method of the XMPProperty:
var date:Date = meta.my::dateTime.toDate();
Additional utility methods in the XMPDateTime class are described in the “XMPCore ActionScript Library
Reference” on page 16.
The for command iterates through the contained property names, while the for each command iterates
through the property values. Note that the properties returned by the iterator can themselves be
structures or arrays.
For example:
X Structure and array properties are implicitly created with all of the implied elements when a first child
is added to them at any level.
This feature offers a more intuitive and usable API, but use it carefully and make sure you understand the
mechanism to make the best use of it.
These examples illustrate implicit creation of the various types of properties, comparing it with explicit
creation.
Simple properties
X Without implicit property creation:
meta.my::simpleProp = new XMPProperty();
meta.my::simpleProp = 5;
Structures
X Without implicit property creation:
meta.my::manuallyCreated = new XMPStruct();
meta.my::manuallyCreated.my::manuallyCreated2 = new XMPStruct();
meta.my::manuallyCreated.my::manuallyCreated2.my::field1 = "value 1";
meta.my::manuallyCreated.my::manuallyCreated2.my::field2 = "value 2";
X With implicit property creation, both the outer and nested structure are created automatically:
meta.my::implicitlyCreated.my::implicitlyCreated2.my::field1 = "value 1";
meta.my::implicitlyCreated.my::implicitlyCreated2.my::field2 = "value 2";
Programmer’s Guide Error Handling 15
Arrays
Arrays can be created by adding the first item, either with the square bracket operator, [1], or the
append() method of XMPArray. You cannot implicitly create an array with any other index but one:
X Without implicit property creation, you must create the XMPArray object explicitly:
meta.my::array = XMPArray.newBag();
X With implicit property creation, the array object is created when you add the first item:
meta.my::array[1] = "first";
meta.my::array[2] = "second";
Implicit arrays are always bag-type arrays, but you can change the type after creation. For example, this
creates the array initially as bag, then changes it to a sequence:
meta.my::seqence.append("first");
meta.my::seqence.append("second");
meta.my::seqence.setType(XMPArray.SEQ);
Qualifiers
You cannot create a property implicitly by defining a qualifier for a property that does not yet exist.
This, however, does not create a property, but instead throws an exception:
meta.my::undefinedProp.qualifier.my::x = "value";
Error Handling
All errors that occur while using the API create and throw an XMPException object that contains an error
ID (defined in XMPError) and a human-readable message. Exceptions that are thrown by ActionScript itself
are also encapsulated in XMPException.
The best practice is to put independent sections of XMP processing code into try ... catch blocks that
handle only the XMPException, as shown in the following example.
The XMPMeta object is not transaction-based; properties that have been created explicitly before the
exception occurrs are not deleted. If, however, a processing exception occurs after one or more properties
have been created implicitly, these are automatically removed.
Programmer’s Guide Error Handling 16
In this example, where a structure property would be created implicitly if no error occured, nothing is
added to the XMP object:
try {
meta.my::struct.my::nestedStruct.my::array[1234] = 5;
} catch (e: XMPException) {
trace (e); // out of bounds...
}
In this case, the implicit creation process temporarily creates my::struct, my::nestedStruct and my::array.
However, because the index 1234 does not exist in the array, the command throws an "Out of bounds"
(with errorId = XMPError.BADINDEX) exception, and deletes the temporary nodes before actually
adding them to the XMP object.