WORKING WITH IMAGE METADATA

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.

EXTERNAL OBJECT SCRIPTS

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:

EXTERNAL OBJECT

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');
 }

CREATING AN XMP FILE OBJECT

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)
    1. Filepath
      The fsName for the target file object derived from its file path
    2. Format
      The list of constant values for the supported file format numeric values are found on page 264 of the JavaScriptToolsGuide. Because our sample script will be working with a file saved using Photoshop’s schema for saving a file’s metadata, we can use the constant XMPConst.NS_PHOTOSHOP
    3. Open Flags
      The flags you will need for creating the XMPFile object constructors are found on page 268 of the JavaScriptToolsGuide. For our purpose we will use the OPEN_FOR_READ flag

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.

GETTING METADATA INFORMATION

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.

PHOTOSHOP TO THE RESCUE

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.

SAMPLE SCRIPT

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

RUNNING THE SCRIPT

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.