Skip to content

dragonee/photoshop-processor

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Batch processing and form letters for Photoshop

This tool is a Photoshop Script Library that generates multiple files from one PSD template, changing text or adding different images for each output file.

The main usecases for this script are:

  • Form letters;
  • Named certificates & diplomas;
  • Wedding invitations.

This script requires minimal knowledge of JavaScript to use it. If you are completely new to automation and programming, you can read this handy automation guide.

Features

  • Setting text layer contents.
    • Scaling down text to fit in the given boundaries.
    • Centering text on a specific layer.
  • Replacing parts of text layer.
  • Setting a variant of text specified in the layer (e.g. Mr|Mrs).
  • Adding an image (e.g. company logo) to a file.
    • Scaling and centering of the image.
  • A fluent syntax that separates data from transformation description.

Minimal example

Copy the Processor.jsxinc file to a directory and create a file named example.jsx in the same directory:

#include "Processor.jsxinc"

processor = new Processor()

processor.transform(function(t) {
    t.putTextOnLayer('TEXT')
     .centerToBoundaryLayer('BOUNDARY')
})

processor.generate({
    'paths': {
        'output': 'C:/My/Path/To/A/Directory',
    },

    'putTextOnLayer.TEXT': {
        'einstein': 'Albert Einstein',
        'planck': 'Max Planck',
    },
})

Now, create a PSD file named example.psd, which contains two layers:

  • A layer named TEXT (with or without contents);
  • A shape layer named BOUNDARY (to center the text layer inside it).

Most likely the BOUNDARY layer will be an invisible rectangle on top of a larger background. Otherwise a longer text could connect with edges of the layer without any padding inside.

Open example.psd in Photoshop and run example.jsx via File → Scripts → Browse…

In C:/My/Path/To/A/Directory, the processor will create three directories, JPG, PDF and PSD with two files inside each (XXX being the specific extension):

  • example-einstein.XXX
  • example-planck.XXX

How it works

For each entry in your data, the processor duplicates the active document, runs every transform on the copy, and saves it. Output files are named <output>/<FORMAT>/<template>-<suffix>.<ext>, where <template> is the open document's name and <suffix> identifies the entry (see Suffixes).

A transform points at a layer by name (searched recursively, case-insensitive) and fills it with the matching value from your data. If there is no data for an entry, text layers are hidden automatically.

API

Processor

var processor = new Processor()
Method Description
processor.transform(callback) Define the transforms. callback receives a builder t (see below).
processor.data(data) Set the data object (paths, suffixes, per-layer values).
processor.setOutput(output) Set the output formats without running.
processor.generate(data) Shortcut for data(data) then run. Uses the output set earlier (or the default).
processor.output(output) Shortcut for setOutput(output) then run. Use this last when data is already set.
processor.getDefaultConfiguration(type) Returns the default save/export options for a format ('PSD', 'PDF', 'PNG', 'JPG').

A run is triggered by either generate(...) or output(...) — whichever you call last.

Transforms — the builder t

Inside transform(function(t) { ... }) you add transforms. Each returns the transform object so you can chain the positioning & sizing methods.

Builder method Data key What it does
t.putTextOnLayer('NAME') putTextOnLayer.NAME Replaces the text layer's contents with the data value.
t.replaceTextOnLayer('NAME') replaceTextOnLayer.NAME Replaces {0}, {1}… and {key} placeholders inside the layer's existing text.
t.putTextVariationOnLayer('NAME') putTextVariationOnLayer.NAME Picks one of several choices; the data value is the index of the chosen variant.
t.addImageLayer('NAME') addImageLayer.NAME Opens an image file and places it above the named layer. The data value is a filename (relative to paths.input).

Text transforms hide their layer when an entry has no value. Image transforms simply skip the entry if the file is missing.

putTextOnLayer

t.putTextOnLayer('TEXT')
'putTextOnLayer.TEXT': ['Albert Einstein', 'Max Planck']

Use \r inside a string for line breaks.

replaceTextOnLayer

Keeps the layer text and only substitutes placeholders. {0}, {1}… read from a positional array; {key} reads from a named sub-key.

t.replaceTextOnLayer('FMT')   // layer text e.g. "Certificate no. {0} for {name}"
'replaceTextOnLayer.FMT':      [ ['001'], ['002'] ],   // fills {0}
'replaceTextOnLayer.FMT.name': [ 'Ada', 'Alan' ],      // fills {name}

putTextVariationOnLayer

The data value is the index of the variant to use. Choices come from one of three sources:

// 1. From a `.choices` data key (default)
t.putTextVariationOnLayer('VARIANT')
'putTextVariationOnLayer.VARIANT.choices': ['she', 'he'],
'putTextVariationOnLayer.VARIANT':         [0, 1],          // -> "she", "he"

// 2. From the layer's own text, split by a separator
t.putTextVariationOnLayer('VARIANT_B').separatedBy('|')      // layer text: "she|he"
'putTextVariationOnLayer.VARIANT_B':       [1, 0],

// 3. From a fixed list in the script
t.putTextVariationOnLayer('VARIANT_C').fromChoices(['Mr', 'Mrs'])

addImageLayer

t.addImageLayer('IMAGE')
'paths': { 'input': '/path/to/images', 'output': '...' },
'addImageLayer.IMAGE': { 'ar': 'logo.png' },   // filename resolved against paths.input

Images are scaled down to fit and centered on the document by default. Add .centerToBoundaryLayer('NAME') to fit/center them inside a specific layer instead.

Positioning & sizing

These chain onto any transform and control where the result is placed and how it is scaled.

Method Effect
.withBoundary(x, y) Fit inside fixed dimensions, e.g. .withBoundary('30mm', '10mm').
.withBoundaryLayer('NAME') Fit inside the bounds of the named layer.
.centerToLayer('NAME') Center the result on the named layer (no resizing).
.centerToBoundaryLayer('NAME') Both: fit inside and center on the named layer.

Text layers shrink their font (down to half the original size) to fit; if they still don't fit, the text is left at its original size and coloured red to flag the overflow. Images are scaled proportionally and never enlarged beyond 100%.

Data object

processor.data({
    'paths': {
        'input':  '/path/to/images',    // base folder for addImageLayer filenames
        'output': '/path/to/output',    // FORMAT subfolders are created here
    },

    'suffixes': ['einstein', 'planck'], // optional, see below

    // one key per transform: '<type>.<LAYER>'
    'putTextOnLayer.TEXT': ['Albert Einstein', 'Max Planck'],
})

Suffixes

The suffix is the part of the output filename after the template name. The list of suffixes (and thus how many files are produced) is resolved in this order:

  • An explicit 'suffixes': [...] array — used as-is for filenames.
  • Object data ({ 'einstein': '…', 'planck': '…' }) — the object's keys become suffixes, and each transform looks up its value by suffix.
  • Array data (['…', '…']) — values are matched by position, and suffixes default to numeric indexes (0, 1, …) unless suffixes is provided.

You can mix arrays and objects across transforms; just keep their lengths/keys aligned with your suffixes.

Output formats

processor.output(['PSD', 'JPG', { format: 'PDF', merged: true }])

Each entry can be:

  • A format string: 'PSD', 'PDF', 'PNG', 'JPG'/'JPEG' — saved with sensible defaults.
  • A config object: { format: 'JPG', quality: 90, merged: true } — any extra keys override the default save/export options. merged: true flattens visible layers before saving (e.g. a flat PDF alongside a layered PSD).
  • A genuine Photoshop options object (new PhotoshopSaveOptions(), new ExportOptionsSaveForWeb(), …) for full control.

If you call processor.output() with no argument, it defaults to ['PSD', 'JPG', { format: 'PDF', merged: true }].

Layer helper

A global layers object is available for ad-hoc layer manipulation (also used internally):

Method Description
layers.find(ref, name) Recursively find a layer by name (case-insensitive).
layers.select(ref, name) Make the named layer active.
layers.toggle(ref, name, visible) Show (1) or hide (0) the named layer.
layers.remove(ref, name) Delete the named layer.

Tips & patterns

  • Treat your data as a table. With arrays, each transform key is a column and each index is a row — one output file per row. Keep every array (and suffixes) the same length and aligned, and group related rows with blank lines so the script reads like a spreadsheet.
  • Put meaningful information in the suffix. The suffix becomes the file name, so encode whatever you'll need to sort, find or act on later — language, variant, even print quantity (e.g. 510a-eval-en-1szt). No separate tracking sheet required.
  • Leave a value blank to get a blank. An empty string ('') clears a text layer, while an omitted/undefined entry hides it — so you can generate filled files and spare blank ones in the same run.
  • Image layers accept PSD files, not just PNG/JPG — handy for reusing one template with several swappable badges or logos.

Bugs and issues

The script was tested on Adobe CS6 on Mac. If you find some issues using it, create an issue in the issue tracker on this repository.

About

Photoshop library to create form letters, wedding invitations, diplomas and certificates etc.

Topics

Resources

License

Stars

2 stars

Watchers

1 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors