Your prescription for increased productivity and profitability
Of course you know that metadata is the data hidden in a file that carries with it a wealth of information about the file. With images this can include all of the information about how and when the image was photographed. Within applications such as Photoshop and Bridge, this information is readily available. In Photoshop, the image metadata is found in a tabbed panel accessed from the File > File Info menu item. When this image is placed in an InDesign document much of this information is exposed when using the Object > Captions > Caption Setup. To access this metadata information using a script, the link XMP property of the image’s item link is at our disposal. It includes fields such as author, creator, creationDate, description, document title, key words, and copyright information.
Because having access to an image’s metadata can make or break an automated workflow, we provide a sample script for getting image metadata using both ExtendScript and AppleScript below. Besides, this is a good opportunity to show the similarities (and differences) between the syntax of the two scripting languages.
A sample script in ExtendScript can be written similar to the following:
if (app.selection.length > 0) { var selItem = app.selection[0]; try { if (selItem.constructor.name == "Rectangle" && selItem.images.length > 0) { var imageRef = selItem.images.item(0); } else if (selItem.constructor.name == "Image") { var imageRef = selItem.images.item(0); } else { throw ("image not selected"); } var linkRef = imageRef.itemLink; var imgDesc = linkRef.linkXmp.description; var imgAuthor = linkRef.linkXmp.author; var imgTitle = linkRef.linkXmp.documentTitle; } catch (e) { alert (e); } } [imgDesc, imgAuthor, imgTitle];
For AppleScript the same test script would look like the following:
tell application "Adobe InDesign CC 2015" set selList to selection if length of selList > 0 then set selItem to item 1 of selList try if class of selItem is rectangle and (count of images of selItem) > 0 then set imageRef to image 1 of selItem else if class of selItem is image then set imageRef to selItem else error ("image not selected") end if set linkRef to link xmp of item link of imageRef on error (e) activate display alert (e) end try set imgDesc to description of linkRef set imgAuthor to author of linkRef set imgTitle to document title of linkRef end if end tell {imgDesc, imgAuthor, imgTitle}
This information can then be used to populate a text frame for the image’s caption. The advantage of using a script over the Caption (autotext) feature in InDesign is that you can assign different styles to individual text items. But there is a serious limitation to the scope of the metadata information provided through link XMP. Additionally, both the Caption autotext feature in InDeisn and link XMP are lacking when it comes to GPS information. If this is the information that you want your script to work with, you will need to use an external object script.
Adobe has provided the adventurous scripter with tools to get the XMP from files. The metadata is stored within the file as XML, with the structure based on the XML schema for the different file formats. To understand this, you may want to spend some time with Adobe’s JavaScriptToolsGuideCC_.pdf. This is available from the Help menu in ExtendScript Toolkit (Adobe’s JavaScript editor). There is an entire chapter devoted to working with XMP, Chapter 10 “Scripting Access to XMP Metadata.” This chapter consists of 36 pages of information. But don’t despair, unless you really want to delve deeply into the subject, you can concentrate on a few XMPFile Object Functions, and listings for the constans for their numeric values:
First, to allow their various applications to share information externally, Adobe has created a script mechanism for JavaScript called BridgeTalk. To provide easy access to this mechanism there are scripts provided in a library. For working with metadata, there is a script in this library that creates an ExternalObject to manage external XMP information: ExternalObject(“lib:AdobeXMPScript”). To get a handle on what this is and how it works, a good read starts on page 201 of the JavaScriptToolsGuide. To create the external object for XMP we use ExtendScript to write:
if (ExternalObject.AdobeXMPScript == undefined){ ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript'); }
Once the script has created the external object, it needs access to the file’s metadata. As with other files, a temporary file object is created in the process of opening a file. The format for opening a file for metadata access, is as follows:
new XMPFile (filePath, format, openFlags)
Once you have the metadata file open, place its raw data into an xml object using getXMP()
. Be sure to close the reference to the opened file reference.
The getProperty
method can now be used to extract the data that you need from the file. For this you will need to know the string constant for the metadata XML Schema namespace
xmp.getProperty([the XMP constant for the metadata namespace], [the property]).toString();
Interestingly, the values returned from getProperty
are objects. If you don’t convert them to string values, the value returned is a BridgeTalk object.
Schema namespace string constants
These are the codes to use to tell JavaScript where to find the metadata information you want in the the file’s extensive XML list.
This last item is where the fun begins. Without knowing which namespace the information you want is in, your script will get nowhere.
To see the XML schema for a file’s metadata, just ask Photoshop. For example: Open any JPEG image in Photoshop. Open the File Info panel for the image (File > File Info). The last tab in this panel (Raw Data) is where you will find the information.
Raw Data tab in Photoshop’s File Info panel
Enter the text for the information you want in the Search field at the top (magnifying glass). Hopefully, the entry you are looking for will be highlighted in the list.
For our example, enter GPS in the Search field. The listing for GPSLatitude and GPSLongitude should be highlighted in the exif namespace.
On page 263 of the JavaScriptToolsGuide, you can discover that NS_EXIF is the constant to use for the exif namespace.
To put this all together, the sample script below gets the GPS information from a file located on our desktop named “marmot.jpg.” You will need to change the value of the variable filePath to the path to a JPEG file of your own for testing:
var filePath = "~/desktop/Marmot.jpg"; var fileRef = new File(filePath); if (fileRef instanceof File) { if (ExternalObject.AdobeXMPScript == undefined){ ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript'); } var xmpf = new XMPFile (fileRef.fsName, XMPConst.NS_PHOTOSHOP, XMPConst.OPEN_FOR_READ); var xmp = xmpf.getXMP(); xmpf.closeFile() var myLat = xmp.getProperty(XMPConst.NS_EXIF, "GPSLatitude").toString(); var myLong = xmp.getProperty(XMPConst.NS_EXIF, "GPSLongitude").toString(); myString = myLat + ", " + myLong; } myString
To test, make sure that your version of InDesign is selected in the application dropdown field at the top of the ExtendScript editor (ExtendScript Toolkit). Copy the script above into the edit window and be sure to change the value of the variable filePath to a path to your own file. Run the script from the editor and check out the result that should display in the editor’s JavaScript Console panel.
For a real world InDesign automation script, I suggest that an external script such as this should be run as a separate script using a doScript call from your main script. This will require that you pass the filePath string from the image reference to the script. To use the result of the script in your InDesign script, you will need to set up the doScript call to return the result (myString) back to the calling script.
To cover the subject of passing arguments to and from a doScript script, we will leave that task for our next blog. And, in honor of the Fourth of July holiday, this blog will be posted early (July 1). Watch for it, and spend some time with Adobe’s JavaScriptToolsGuide in the meantime.