Home » scripting

I process my images using a combination of Adobe Lightroom and Photoshop, in common with just about every other photographer on the planet. To maximize time spent behind the camera, much of the Photoshop work is automated using Actions, which are a way to record and playback a sequence of Photoshop commands. In other programs such as Microsoft Word or Excel, these are called macros.

Actions are a way of automating Photoshop processes that are performed frequently, but they have one fundamental limitation: there is no way for an action to make a decision by evaluating some condition and doing something different based on the result.

For example, a Photoshop action might downsize an image by 10%. Using the Batch feature of Photoshop, you could apply that action to all images in a folder. However, if you want to downsize only those images in the folder that are larger than, say, 3000 pixels on the longest side, actions and batching can’t help you. There’s no way for an action to evaluate a condition like “longest side > 3000 pixels”. This is where scripting comes in — you can write a small program (the script), that interacts with Photoshop to perform more complex tasks. Although it might not sound like it, scripting is a form of programming. There is no getting around the fact that you have to learn something about how to write programs to use scripting, and this is its disadvantage compared to Actions.

Photoshop has been “scriptable” since version 7, but scripting support has gotten much better since Photoshop CS2. You can use AppleScript, Microsoft Visual Basic, or Javascript. Some people like to get into language “wars of religion” — I will say only this: Javascript is the only language that works across PC, Mac or UNIX, and this is a good reason for preferring it, but my primary motivation was efficiency. I chose Javascript because I had learned to program in C and Java. Despite its name, Javascript has very little in common with Java, but both Java and Javascript have very similar syntax to the languages C and C++.

If you are going to do any Photoshop scripting, there are two very helpful PDF documents you need to read. Fortunately, they are installed on your hard drive by the Photoshop installer. The Photoshop Scripting Guide and the Javascript Reference Guide are both in the Photoshop program directory. I won’t re-hash those documents, but will provide an example that you can pick apart to figure out how to write your own scripts.

An example script: saving image metadata as XMP files

Some Photoshop commands cannot be recorded as Actions, such as some “File Info” (metadata) changes. Metadata (literally, “data about data”) are things like the caption, keywords, title and other information about an image, accessed through the “File Info…” on the File menu. This data is stored as an XML document inside of the image file by Photoshop. The flavor of XML that Photoshop stores is called XMP, and you can save, load and append .xmp files to images using the Advanced panel of the File Info dialog box. The problem is that you can’t record saving and loading XMP files in an action. I wanted to use the XMP data in another program to automate keyword display on my web site, so I ended up writing a Javascript program to automate this function.

The code below scans a folder full of JPEG files and outputs the XMP file for any image that has metadata. It is commented, and in conjunction with the documents from Adobe, you ought to be able to understand how the program works, and perhaps adapt it to your own needs. This code is provided free, and purely for its educational value. Enjoy!


// Output xmp.js
// (c) Copyright 2004 Mathew Lodge
// Rev 2, 02-Mar-2004
//
// This script prompts the user for an input directory, which contains JPEG source images.
// It outputs one .xmp metadata file per image, unless the file has no XMP metadata.

// Uncomment the next line to show the debugger
$.level = 1; debugger;

// Save current dialog preferences
var startDisplayDialogs = app.displayDialogs;

// Don't display dialogs
app.displayDialogs = DialogModes.NO;

// Constants
var FILE_TYPE = ".jpg"; // The type of files that this script works on -- you can change
var SEARCH_MASK = "*" + FILE_TYPE; // Image file filter to find only those files
var XMP_TYPE = ".xmp"; // File extension for XMP output files
var MAC_XMP_TYPE = "XMPT"; // Macintosh file type for .xmp files
var MAC_XMP_CREATOR = "8BIM"; // Macintosh file creator for .xmp files

// Set of exception strings for error handling
var X_NOINPUT = "noInput";
var X_BADDOC = "badDoc";
var X_WERROR = "writeError";
var X_CERROR = "closeError";

try {
	// Ask user for input folder
	var inputFolder = Folder.selectDialog("Select a folder to process");
	if (inputFolder == null)
		throw X_NOINPUT;

    // get all files in the input folder
	var fileList = inputFolder.getFiles(SEARCH_MASK);

	// Open each file in turn
	for (var i = 0; i < fileList.length; i++) {
	    // Only want to open non-hidden files (and no folders)
		if ((fileList[i] instanceof File) && (fileList[i].hidden == false)) {
			// Open the file in Photoshop
			var docRef = open(fileList[i]);
			if (docRef == null)
				throw X_BADDOC;

			if (docRef.xmpMetadata != null) {
				// Document has XMP metadata, so process it
				var inFileName = fileList[i].name; // Filename without path
				// Replace the file's current extension (e.g. .jpg) with .xmp
				var outFileName = inFileName.toLowerCase(); // Output file is lower case
				outFileName = outFileName.replace(FILE_TYPE, XMP_TYPE); // Make .xmp
				var outputXMP = new File(inputFolder + "/" + outFileName);
				// Open file for writing. Mac type and creator are ignored on other systems
				var success = outputXMP.open("w", MAC_XMP_TYPE, MAC_XMP_CREATOR);
				if (!success)
					throw X_WERROR;

				// Write out the meta data
				success = outputXMP.writeln(docRef.xmpMetadata.rawData);
				if (!success)
					throw X_WERROR;

				// Close the file
				success = outputXMP.close();
				if (!success)
					throw X_CERROR;
			}
			// Close the Photoshop file
			docRef.close(SaveOptions.DONOTSAVECHANGES);
		}
    }
}
catch (exception) {
	// Show degbug message and then quit
	alert(exception);
}
finally {
	// Reset app preferences
	app.displayDialogs = startDisplayDialogs;
}

A sparkline is a small line graph designed to be used in-line within text to illustrate a time series; the concept was developed by data presentation guru Edward Tufte. Here’s an example:

University of California 403(b) pension fund cumulative return Jan 1990-April 2004 (original data)

Equities 267%
Bonds 154%

The idea is to show, using minimal space, how a value varies over time. One advantage of sparklines’ compactness is that several can be used together to allow at-a-glance comparison between a set of time series. At Tufte’s web site there is a longer description of sparklines, with further examples, from a sample chapter of Tufte’s book, Beautiful Evidence. Sparklines are tangentially related to photography – they are used alongside images as a graphical design element in qualitative and quantitative analysis.

Sparklines can be hard to produce. Most graphing packages are designed to produce large graphs or charts, and it can be very hard to generate the wide-but-thin lines for incorporation in documents. This was the motivation for writing a Photoshop script that would automate the production of sparklines. It works by reading a data series from a text file and plotting a sparkline image as a Photoshop path, and then stroking it with the pencil tool. This produces a bitmap image which can then be cut-and-pasted into the target document. The user retains control of the color and line style of the sparkline by setting the Photoshop foreground color and pencil tool settings before running the script.

Mac support and PS CS2 testing

Some Mac users had reported problems with the Sparkline script not being able to open text data files. Thanks to the help of two kindly Mac contributors, I found and fixed the problem. In addition, the script has been tested on Photoshop CS2. All the changes are incorporated in Version 2 of the script below.

Installing the sparkline script

The code of the sparkline script for Adobe Photoshop CS/CS2/CS3 is included below. While it will run on Mac or PC Photoshop, it does not work on any earlier versions. You can also right click (Mac: Option click) here to download the script. Select “Save as…” from the menu that pops up, and save it somewhere where you can find it on your computer.

The script works on textual data files, where the first line is the name of the quantity being charted, and the remainder of the lines are the data values. To start you off, here’s a sample data file for wind speed. Using Microsoft Excel, it’s easy to create data files in this format: put the legend in cell A1, then the data values in cells A2, A3 and so on, and then do File->Save As… and select “Text file” for the output format.

To install the script, first locate Adobe Photoshop’s main directory on your computer. On my (Windows) computer, it’s in C:Program FilesAdobePhotoshop CS

On the PC, save the script as Sparklinev2.js in the directory <Photoshop dir>PresetsScripts

On the Mac, save the script as Sparklinev2.js in the directory <Photoshop dir>/Presets/Scripts

Start Photoshop (or re-start it, if it was already running). You should now see the Sparkline script on the File->Scripts menu:

Using the script

First of all, select the foreground color and Pencil tool settings that you want to use for the Sparkline. To select a foreground color, double click on the foreground color swatch in the palette menu. To select the pencil tool, right-click (Mac: option-click) on the palette menu as shown:

Then, set the pencil defaults to whatever you’d prefer using the tool menu just below the Photoshop menu bar:

Click File->Scripts->Sparkline (as shown in the screen shot above) to start the script. You will be promoted to locate the file containing the sparkline data:

Click “Open”; the script will open the file and then prompt you for the height of the sparkline, in pixels. The default height is 50 pixels, which is 50 points (0.7″) high on a typical 72dpi computer screen, and 12 points high when printed on paper at 300dpi (you can change the default height by editing the script).

The script will then ask if you want to automatically scale the sparkline to the document height. If you select Yes, then the script uses the minimum and maximum values present in the data file to scale the Y axis such that the minimum value is plotted at the bottom of the document, and the maximum value is plotted at the top, like this (a border has been added to make it easier to see the effect):

If you select No, then the script will prompt you for the Y intercept (the data value that will be plotted at the bottom of the document) and the maximum Y value (which will be plotted at the top of the document). For example, using a Y intercept of 0 and a max Y value of 50, the same data would be plotted as follows (again, border added for clarity):

Finally, the script asks for the X axis pixel spacing between points. The default setting of 1 plots each point of the sparkline immediately adjacent (one pixel away) from the previous point. To make the sparkline shorter, use a value less than 1. To make it longer, use a value greater than one. For example:

X axis pixel spacing of 0.3:

X axis pixel spacing of 0.5:

Advanced topics: Use of time travel

Because the script creates a regular Photoshop document complete with history, you can use the Photoshop history palette to “go back in time” and change the way that the path is stroked. For example, to use a Brush stroke rather than a Pencil stroke, you’d go back in the document history to the point where the path has been saved, but before it has been stroked. Then stroke it with the Brush, rather than the Pencil.

First of all, open both the History and Paths palettes. Then, use the History palette to go back to the document state before the stroke occurred:

Then, right click (Mac: option-click) on the Sparkline path in the channels palette. Select “Stroke path…” from the pop-up menu.

The following dialog will appear, and you can elect to stroke the path using the Brush, or indeed any of the other Photoshop tools:

Script source code