Scripting a Photoshop droplet to resize and add watermark (twice)

Hi there,

I’m completely new to Applescript, and I’ve been trying unsuccessfully for the past five or six hours to write a droplet to do the following things for a single file or bunch of files:

  1. Open the file in Photoshop
  2. Image resize to 640 px wide (this probably needs a layer rename since the image would be the background layer)
  3. Add a watermark from application bundle as a new layer ” bundled so I can give the whole thing to people
  4. Align bottom and right edges of watermark layer and background layer
  5. Move watermark layer up and left 10 px each (i.e., 10 px offset from bottom right)
  6. Change opacity of watermark layer to 20%
  7. Save a jpeg, adding “wm_640” to the file name
  8. Revert to initial history state
  9. Do the whole thing again at 1020 px and with a different watermark file (otherwise the same)

The whole time I’ve been stuck on 1 (cries). I’ve tried using the recursive image processing droplet preset that’s included with Applescript Editor and can’t even get the example script to work. I’ve done some programming in Java and C++, but I’m having a hard time getting the paradigm straight for Applescripting. Here are a few things that I can’t seem to get a quick/easy answer for anywhere:

  1. If I use a run application rather than a droplet and tell Photoshop to open a file using an alias:
tell application "Adobe Photoshop CS5.1"
open file "some:alias:to:a:file"
end tell

it works no problem, but when I use:

tell application "Adobe Photoshop CS5.1"
	set myFile to (choose file) as alias
	open myFile
end tell

I get an error:

What’s the difference between the two? How should I be telling Photoshop to open files generally?

  1. If I use the default file processing statements in the Recursive Image File Processing Droplet, I get an error:

If I can’t even get the default to work, how am I going to get Photoshop to work?

  1. In order to accomplish what I’m setting out to do above, how should I be approaching the problem? What’s the paradigm for scripting Photoshop? Any tips you can give to someone just starting out? My understanding is that I should:

    i. Open my main image file using “tell “Adobe Photoshop” to open…”
    ii. Adding my watermark image using “move”
    iii. Position watermark image (somehow)
    iv. Change opacity (this one should be easy)
    v. Save off a jpg (again, this one should be easy)

Sorry if this question is meandering all over the place, but there’s just so much here I can’t wrap my head around I didn’t really no where to start. Any help at all would be very enthusiastically appreciated.

Hi,

all versions of Photoshop should be able to open files with this syntax


set myFile to (choose file) as text
tell application "Adobe Photoshop CS5.1"
	open file myFile
end tell

hi,

if I remember it right then “move” won’t work, you’ll have to duplicate the layer from the frontmost open document to the targetdocument. Get bounds, set bounds, opacity … finish.

call for help when getting into troubles :slight_smile:

Edit: If not done yet, then open “Funktionsverzeichnis” (sorry don’t remember the english name …) of PS from ScriptEditor … + calling for properties of an objekt will give you good advice for scripting …

Bye

Hans

Many thanks to both StefanK and Hans-Gerard. Things are working OK now, I’m getting my image resized, but I can’t seem to open bundled resources correctly.

I dragged my “watermark.png” image to the “Bundle Contents” sidebar, and am using the following file processing statements:

on process_item(this_item)
    set myPath to alias this_item as text
    tell application "Adobe Photoshop CS5.1"
        open file myPath
        set thisDocument to current document
        set ruler units of settings to pixel units
        resize image thisDocument width 640
        set wmPath to path to resource "watermark.png"
        open file wmPath
    end tell
end process_item

but I always get the following error:

Do I have to do something special to make sure the script can find the bundled resources?

hi,

if you mean the resources of PS-Bundle these should work:

set wm to (path to application "Adobe Photoshop CS3" as text) & "contents:Resources:watermark.psd"
--or:
set wm to (path to resource "watermark.psd" in bundle application "Adobe Photoshop CS3") as text

tell application "Adobe Photoshop CS3"
	open file wm
end tell

Thanks, Hans-Gerd. Actually I mean the path to files that I bundle with my script. If you save a script as an app or bundle you can bundle files (such as images) with the script. These files are used by the script when it runs. In my case I want to bundle the watermark image so that when people run the script they don’t need to manually look for the watermark file.

If you look at the Script Editor window there’s a button marked Bundle Contents. That’s where bundled files go, but I can’t get my script to see those files. I keep getting an error.

Ah,

thought of a new possibility in Photoshop 5 which I don’t own.

But it’s the same:

	set wm to (path to resource "watermark.psd" in bundle path to me) as text

Happy scripting :slight_smile:

Hans

It worked! Thank you so much.

OK, I have everything running perfectly, only the folder recursion doesn’t seem to work ” there’s some problem with an alias not getting converted properly and stopping the script. I think I need to set something to “alias as text”, but I’ve tried a few things and nothing seems to be working. The error that I get is, as soon as the script digs into the first folder, it can’t turn the first file it sees into an HFS file path:

Looking at this code, does anyone have a guess what the problem might be? I think the problem is in the first part of the process_folder method:

	set this_item to alias ((this_folder as Unicode text) & (item i of these_items))

but I’m not sure. Any help would be really appreciated.

property type_list : {"JPEG", "TIFF", "PNGf", "8BPS", "BMPf", "GIFf", "PDF ", "PICT"}
property extension_list : {"jpg", "jpeg", "tif", "tiff", "png", "psd", "bmp", "gif", "jp2", "pdf", "pict", "pct", "sgi", "tga"}
property typeIDs_list : {"public.jpeg", "public.tiff", "public.png", "com.adobe.photoshop-image", "com.microsoft.bmp", "com.compuserve.gif", "public.jpeg-2000", "com.adobe.pdf", "com.apple.pict", "com.sgi.sgi-image", "com.truevision.tga-image"}
global myFolder
global wmYN
global wmColor
global nameUse
global rootName
global nameCount

-- This droplet processes files dropped onto the applet 
on open these_items
	-- FILTER THE DRAGGED-ON ITEMS BY CHECKING THEIR PROPERTIES AGAINST THE LISTS ABOVE
	set wmColor to null
	set nameCount to 0
	set nameUse to null
	set myFolder to choose folder with prompt "Choose where to put your finished images" -- where you're going to store the jpgs
	repeat with i from 1 to the count of these_items
		set totalFiles to count of these_items
		set this_item to item i of these_items
		set the item_info to info for this_item without size
		if folder of the item_info is true then
			process_folder(this_item)
		else
			try
				set this_extension to the name extension of item_info
			on error
				set this_extension to ""
			end try
			try
				set this_filetype to the file type of item_info
			on error
				set this_filetype to ""
			end try
			try
				set this_typeID to the type identifier of item_info
			on error
				set this_typeID to ""
			end try
			if (folder of the item_info is false) and (alias of the item_info is false) and ((this_filetype is in the type_list) or (this_extension is in the extension_list) or (this_typeID is in typeIDs_list)) then
				-- THE ITEM IS AN IMAGE FILE AND CAN BE PROCESSED
				process_item(this_item)
			end if
		end if
	end repeat
end open

-- this sub-routine processes folders 
on process_folder(this_folder)
	set these_items to list folder this_folder without invisibles
	repeat with i from 1 to the count of these_items
		set this_item to alias ((this_folder as Unicode text) & (item i of these_items))
		set the item_info to info for this_item without size
		if folder of the item_info is true then
			process_folder(this_item)
		else
			try
				set this_extension to the name extension of item_info
			on error
				set this_extension to ""
			end try
			try
				set this_filetype to the file type of item_info
			on error
				set this_filetype to ""
			end try
			try
				set this_typeID to the type identifier of item_info
			on error
				set this_typeID to ""
			end try
			if (folder of the item_info is false) and (alias of the item_info is false) and ((this_filetype is in the type_list) or (this_extension is in the extension_list) or (this_typeID is in typeIDs_list)) then
				-- THE ITEM IS AN IMAGE FILE AND CAN BE PROCESSED
				process_item(this_item)
			end if
		end if
	end repeat
end process_folder

-- this sub-routine processes files 
on process_item(this_item)
	set this_image to alias this_item as text
	tell application id "com.adobe.photoshop"
		set saveUnits to ruler units of settings
		set display dialogs to never
		open file this_image
		if wmColor is not in {"White for all", "Black for all"} then
			set wmColor to choose from list {"Black", "Black for all", "White", "White for all"} with prompt "What color should the watermark be?" default items "White for all" without multiple selections allowed and empty selection allowed
		end if
		if wmColor is false then
			error number -128
		end if
		if nameUse is not "Just increment this for all" then
			set nameBox to display dialog "What should I call these things?" default answer ("image") with title "Choose the name stem for your images" buttons {"Cancel", "Just increment this for all", "OK"} default button "OK"
			set nameUse to button returned of nameBox -- this will determine whether or not to increment stem names 
			set rootName to text returned of nameBox -- this will be the root part of all of your file names
			set currentName to rootName
		else
			set nameCount to nameCount + 1
			set currentName to rootName & (nameCount as text)
		end if
		set thisDocument to current document
		set initialState to current history state of thisDocument
		set ruler units of settings to pixel units
	end tell
	DoSmall(thisDocument, currentName, initialState)
	DoBig(thisDocument, currentName, initialState)
	tell application id "com.adobe.photoshop"
		close thisDocument without saving
		set ruler units of settings to saveUnits
	end tell
end process_item

to DoSmall(thisDocument, currentName, initialState)
	tell application id "com.adobe.photoshop"
		set initWidth to width of thisDocument
		if initWidth < 640 then
			resize image thisDocument width 640 resample method bicubic smoother
		else if initWidth > 640 then
			resize image thisDocument width 640 resample method bicubic sharper
		end if
		set myHeight to height of thisDocument
		set myWidth to width of thisDocument
		if wmColor is in {"White", "White for all"} then
			set wmFile to (path to resource "water_250_white.png" in bundle path to me) as text
		else if wmColor is in {"Black", "Black for all"} then
			set wmFile to (path to resource "water_250_black.png" in bundle path to me) as text
		end if
		open file wmFile
		set wmDocument to current document
		set wmHeight to height of wmDocument
		set wmWidth to width of wmDocument
		duplicate current layer of wmDocument to thisDocument
		close wmDocument without saving
		translate current layer of thisDocument delta x (myWidth - wmWidth - 10) delta y (myHeight - wmHeight - 10)
		set opacity of current layer of thisDocument to 20
		set myPath to (myFolder as text) & (currentName) & "_640"
		set myOptions to {class:JPEG save options, embed color profile:false, quality:12}
		save thisDocument as JPEG in file myPath with options myOptions appending lowercase extension
		set current history state of thisDocument to initialState
	end tell
end DoSmall

to DoBig(thisDocument, currentName, initialState)
	tell application id "com.adobe.photoshop"
		set initWidth to width of thisDocument
		if initWidth < 1020 then
			resize image thisDocument width 1020 resample method bicubic smoother
		else if initWidth > 1020 then
			resize image thisDocument width 1020 resample method bicubic sharper
		end if
		set myHeight to height of thisDocument
		set myWidth to width of thisDocument
		if wmColor is in {"White", "White for all"} then
			set wmFile to (path to resource "water_400_white.png" in bundle path to me) as text
		else if wmColor is in {"Black", "Black for all"} then
			set wmFile to (path to resource "water_400_black.png" in bundle path to me) as text
		end if
		open file wmFile
		set wmDocument to current document
		set wmHeight to height of wmDocument
		set wmWidth to width of wmDocument
		duplicate current layer of wmDocument to thisDocument
		close wmDocument without saving
		translate current layer of thisDocument delta x (myWidth - wmWidth - 16) delta y (myHeight - wmHeight - 16)
		set opacity of current layer of thisDocument to 20
		set myPath to (myFolder as text) & (currentName) & "_1020"
		set myOptions to {class:JPEG save options, embed color profile:false, quality:12}
		save thisDocument as JPEG in file myPath with options myOptions appending lowercase extension
		set current history state of thisDocument to initialState
	end tell
end DoBig

Hi,

this line causes the error


 display dialog this_item

this_item is an alias specifier, but display dialog expects a string
Use


 display dialog (this_item as text)

Thanks, but that’s actually just a display dialog I was using for debugging, not a part of the main code. I included it by accident, but it’s erased now. Any other ideas? :smiley:

Hi,

while having a short look I guess it’s because you’re tryring to cource an alias to alias:
process_item(this_item)–is already an alias

–>> set this_image to alias this_item as text --causes the error

should be: set this_image to this_item as text

… because a few lines later you cource it to file …

Hope this will work :slight_smile:

Bye

Hans

That’s it! Thank you so much.