Sample Script for Adding Captions

This article will give you some ideas for adding captions to images using a script. We will be using AppleScript but ExtendScript users can easily convert the script as needed.

Our sample script will depend on the following:

  • Images have been saved with the description field defined for the image’s caption and the author field defined for the image’s credit line.
  • Measurements for the document have been set to points
  • The document contains a paragraph style for Credit and Caption
  • The document contains an object style named Caption

Script Outline

The outline for our sample script will include the following steps:

  • Check to make sure a rectangle is selected in an active document
  • If a rectangle is selected and it contains an image, check for the image’s metadata
  • If the image’s metadata contains information for the description and/or author field, a text frame will be created below the image and assigned the Caption object style
  • The Caption text frame will be populated with a credit and caption paragraph as defined in the image’s metadata.
  • The credit text will be styled using the Credit paragraph style
  • The caption text will be styled using the Caption paragraph style

Check for Selection

The first task for our script will be to check for a selected rectangle:

  set desiredClass to «class crec» 
      set errStr to "Expects rectangle with image to be selected"
      tell application "Adobe InDesign CC 2014"
        --make sure document is not in modal state 
        if modal state
           error "Please close modal dialogs before running script"
        end if
        set selList to selection
        if length of selList = 0 then
           error errStr
        end if
        (*if rectangle containing an image is selected, 
        return reference to the rectangle*)
        if class of item 1 of selList is desiredClass then
           set rectRef to item 1 of selList
           if (count of page items of rectRef) > 0 and class of page item 1 of rectRef is image then
               return rectRef
           end if  
        end if
        --if the script gets here, rectangle with image is not selected
        error errStr
   end tell 

There are three places in the above where an error message could be generated. To handle this, we will place our code inside of a handler called checkSelection and call it from within a try/end try block:

   try
      --check for selection
      set desiredClass to «class crec»
      set rectRef to checkSelection (desiredClass)
   on error errStr
      activate
      display alert "Error: " & errStr
   end try
   on checkSelection (desiredClass)
      --put code from above with exception of the first line here
   end checkSelection

At this point you should be able to test the script to make sure it works as expected. Run it with no selection, then with a page item other than a rectangle selected, then with an empty rectangle selected, and then finally with a rectangle having an image.

Notice that the script uses a four-letter code–often called a raw code–to define the rectangle class. This makes it possible to define the class outside of a tell statement to the application.

Get Metadata

Now that we have a reference to the container for the image, we can look at the image’s metadata. This will involve getting the properties of the image’s link–or link xmp. For this, the code can be tested at the top of the script prior to setting it up as a handler. Below the end try statement in the code above, add the following:

   tell application "Adobe InDesign CC 2014"
      set imageRef to image 1 of rectRef
      set linkRef to item link of imageRef
      set linkM to properties of link xmp of linkRef
      set creditStr to ""
      set descStr to ""
      try 
         if description of linkM is not "" then
            set descStr to description of linkM
         end if
      end try
      try
         if author of linkM is not "" then
            set creditStr to author of linkM
         end if
      end try
   end tell
   return {descStr, creditStr}

Test your script with a rectangle having metadata assigned and one without. There will always be a value returned even if there is no metadata as the values for the two variables default to empty strings.

Once tested, place the following handler template at the bottom of your script.

   (*Returns author and description metadata fields for image of container reference passed*)
   on getMetadata (rectRef)
   end getMetadata

Cut all of the code from below the end try statement and paste it inside the handler template.

After the variable rectRef is defined inside the try statement block, add a call to the getMetadata handler:

   set {creditStr, capStr} to getMetadata(rectRef)

Check For Styles

If a value is returned for the variables creditStrcapStr, or both, the script will create and populate the caption text frame. For this the script will need to make sure the paragraph styles “Credit” and “Caption” exist as well as an object style named “Caption.”

The following is a minimalistic approach. It makes sure there are styles, but does not set any properties other than the name. Add the following five lines after end try at the top of your script and the two handlers following to the bottom.

   if creditStr & capStr is not "" then
      set parastyleList to {"Caption", "Credit"}
      set parastyleRefs to checkParastyles (parastyleList)
      set objstyleRef to checkObjstyle ("Caption")
   end if
   (*Makes sure paragraph styles named in parastyleList exist; list of style references is returned*)
   on checkParastyles (parastyleList)
      set parastyleRefs to {}
      tell application "Adobe InDesign CC 2014"
         tell document 1
            repeat with i from 1 to length of parastyleList
               set parastyleName to item i of parastyleList
               if (exists paragraph style parastyleName) then
                  set parastyleRef to paragraph style parastyleName
               else
                  set parastyleRef to make paragraph style with properties {name: parastyleName}
               end if
               set end of parastyleRefs to parastyleRef
            end repeat
         end tell
      end tell
      return parastyleRefs
   end checkParastyles
   (*Makes sure object style named in objstyleName variable exists; reference to the style is returned*)
   on checkObjstyle (objstyleName)
      tell application "Adobe InDesign CC 2014"
         tell document 1
            if (exists object style objstyleName) then
               set objstyleRef to object style objstyleName
           else
               set objstyleRef to make object style with properties {name: objstyleName}
           end if
         end tell
      end tell
      return objstyleRef
   end checkObjStyle

With this code added, the script makes sure the styles are in the document even if their styling is not defined.

Create Caption

With all of the pieces for the script in place, the final step is to create the text frame and populate it.

Below the end if statement added at the bottom of the try statement block above, add the following call to a handler named createCaption.

   createCaption(rectRef, creditStr, capStr, parastyleRefs, objstyleRef)

The createCaption can now be written as follows:
Put it at the end of your script.

  (*Creates caption text frame using reference to container, credit and caption strings, as well as references to paragraph and object styles*) 
   on createCaption(containerRef, creditStr, capStr, parastyleRefs, objstyleRef)
      tell application "Adobe InDesign CC 2014"
	 set docRef to document 1
	 set pageRef to parent page of containerRef
	 copy geometric bounds of containerRef to {yp, x0, y1, x1}
	 set captionStr to creditStr & return & capStr
	 tell pageRef
	    set frameRef to make text frame with properties {geometric bounds:{y1, x0, (y1 + 60), x1}, contents:captionStr, applied object style:objstyleRef}
	 end tell
	 repeat with i from 1 to length of parastyleRefs
	    if paragraph i of frameRef is not "" then
		set applied paragraph style of paragraph i of frameRef to item i of parastyleRefs
	    else
		delete paragraph i of frameRef
	    end if
	 end repeat
	 set baseLn to (baseline of line -1 of paragraph -1 of frameRef) + 6
	 set geometric bounds of frameRef to {y1, x0, baseLn, x1}
      end tell
   end createCaption

You may wonder why the bottom of the caption frame was calculated rather than using fit given frame to content. The fit method affects both horizontal and vertical dimensions of the frame which is not what is wanted if the caption text is shorter than the width of the image container.

Onward and Upward

Make sure you place a copy of the script in InDesign’s Scripts Panel and give it a keyboard shortcut.

The sample script can be just a beginning for a full-featured script. You may wish to add an interface to the script to give the user the option to choose one or more of the following:

  • The position for the caption frame: below or to the right
  • The layer on which to place the caption frame: same as image, or layer by name
  • The amount of spacing to allow between the caption frame and the image. Remember that this can be controlled by text insets defined in the caption text frame’s applied object style.

Once you have your script running the way you want it, pat yourself on the back each time you or your user saves uses the keyboard shortcut to have the caption created without any additional effort required.