[Tutorial] Advanced automation and scripting with AppleScript

Discuss Pixelmator Pro tutorials and share useful resources.
User avatar

2020-09-17 13:11:57

Pixelmator Pro includes extensive and full-featured support for AppleScript, the scripting language created by Apple that lets you directly control apps using instructions written in an English-like scripting language.



Check out the full tutorial here.
User avatar

2020-09-17 21:25:08

I sent this comment to the support team, but maybe I should post it here instead. I'm new to AppleScript and I think it would be helpful if you had a few photo editing sample scripts. I would like to create a script that takes a folder of Pixelmator Pro files and applies the White Balance and Lightness corrections. I know these commands are in the Pixelmator Pro AppleScript dictionary, but I can't figure out the correct way to script this. If there was a sample of how to use these commands, that could serve as a template for using other commands. Thanks!
User avatar

2020-09-18 06:55:12

Thank you, thank you, THANK YOU for the AppleScript support! I will stay up late experimenting with it. I have a set of steps I take over and over, including a "Trim...", and now I can automate the process. Thank you so much. This is a giant leap upward and forward in terms of being a production tool.
User avatar

2020-09-18 12:16:59

by Max McCarty 2020-09-17 18:25:08 I sent this comment to the support team, but maybe I should post it here instead. I'm new to AppleScript and I think it would be helpful if you had a few photo editing sample scripts. I would like to create a script that takes a folder of Pixelmator Pro files and applies the White Balance and Lightness corrections. I know these commands are in the Pixelmator Pro AppleScript dictionary, but I can't figure out the correct way to script this. If there was a sample of how to use these commands, that could serve as a template for using other commands. Thanks!
Max, this is a great (perhaps the best) place to ask questions like this! Here's an example script that should do what you're looking for:
tell application "Pixelmator Pro"
	-- Open a prompt that lets you pick multiple Pixelmator Pro files to process
	-- and save references to all those images in the originalImages variable
	set originalImages to choose file with prompt ¬
		"Please select the images to process:" with multiple selections allowed
	-- Start a repeat loop that loops over each image
	repeat with a from 1 to number of originalImages
		-- Open the current image in the loop
		set currentImage to open item a of originalImages
		-- Apply the auto white balance adjustments
		auto white balance currentImage
		-- Apply the auto lightness adjustments
		auto light currentImage
		-- Export the images to the location chosen previously as Pixelmator Pro files
		save currentImage
		close currentImage without saving
	end repeat
	display notification (number of originalImages as text) & ¬
		" images have been successfully edited." with title "Auto WB and Auto Lightness"
end tell
And here's a way to script the same thing but export your changes to new documents rather than save them to the ones that were opened:
tell application "Pixelmator Pro"
	-- Open a prompt that lets you pick multiple Pixelmator Pro files to process 
	-- and save references to all those images in the originalImages variable
	set originalImages to choose file with prompt ¬
		"Please select the images to process:" with multiple selections allowed
	-- Open a prompt to choose the location where the files should be exported 
	set exportLocation to choose folder with prompt ¬
		"Please select where you'd like export the images:"
	-- Start a repeat loop that loops over each image
	repeat with a from 1 to number of originalImages
		-- Open the current image in the loop
		set currentImage to open item a of originalImages
		-- Apply the auto white balance adjustments
		auto white balance currentImage
		-- Apply the auto lightness adjustments
		auto light currentImage
		-- Export the images to the location chosen previously as Pixelmator Pro files
		export currentImage to file ((exportLocation as text) & ¬
			name of currentImage & "-edited" & ".pxd") as Pixelmator Pro
		-- Close the current image without saving
		close currentImage without saving
	end repeat
	display notification (number of originalImages as text) & ¬
		" images have been successfully edited." with title "Auto WB and Auto Lightness"
end tell
Feel free to try out those scripts and let me know how it goes!
by Christian Boyce 2020-09-18 03:55:12 Thank you, thank you, THANK YOU for the AppleScript support! I will stay up late experimenting with it. I have a set of steps I take over and over, including a "Trim...", and now I can automate the process. Thank you so much. This is a giant leap upward and forward in terms of being a production tool.
First of all, welcome to the forum, Christian! Second of all, that's really great to hear. I'll admit that even as a non-programmer, I spent many a fun evening hour tinkering with AppleScript, so I hope you'll enjoy yourself too.
User avatar

2020-09-18 16:24:49

You're the best! Thanks for these scripts. I'll play around with them this weekend!
User avatar

2020-09-20 12:44:15

Let me suggest a less complicated way to write scripts when they operate on only one layer and all other layers need to be ignored, such as your example script for creating a 3D text effect. Instead of all the work tracking then hiding other visible layers and then restoring their visibility back, copy the current layer into a temporary new document and then bring the results back in. Yes, you would have to create a new document and then close it without saving, but this is only a few statements compared to tracking visible layers, hiding them, and then making them visible again.
User avatar

2020-09-21 09:06:32

by Senior Moment Let me suggest a less complicated way to write scripts when they operate on only one layer and all other layers need to be ignored, such as your example script for creating a 3D text effect. Instead of all the work tracking then hiding other visible layers and then restoring their visibility back, copy the current layer into a temporary new document and then bring the results back in. Yes, you would have to create a new document and then close it without saving, but this is only a few statements compared to tracking visible layers, hiding them, and then making them visible again.
Yeah, usually there's no need to remember the visibility of layers even when writing scripts that operate on one layer in a document, but because this particular script uses the merge visible command, it does become necessary. I seem to recall that the merge command cannot take lists in the form of layers 3 thru 12 due to some AppleScript limitations, so I had to use this method. But in most other cases, again, this extra step isn't necessary. I also like your suggestion of creating another document, though I think there might be potential for it to be just as, if not more complex — you'd need to create a new document with the size of the current document, then cut the layer, paste it into the new document, then paste it back in and close the temp document without saving it. So, overall, my feeling is it would about the same, complexity-wise, though possibly with less potential for bugs. Of course, if you'd like to have a go at modifying the script yourself, feel free to do so, I'd love to see it!
User avatar

2020-09-22 21:59:14

As an exercise in curiosity I rewrote the 3D Text Effect script to perform its manipulations in a temporary document. Not having to track the working set of layers permits it to be 63 lines shorter, a distinct advantage in my view, so this technique could prove useful for scripts having to do similar layer manipulations. It turns out, creating a document from a copied layer in the clipboard creates a new document with the same attributes, so those didn't have to be specifically carried over. But I did run into an error where changing the color of the text in the temporary document caused it to unexpectedly wrap, damaging the effect. Adding a line to proportionally widen the text layer, either before or after the color change, bypassed the problem. I don't understand this, since the temporary document has the same image, canvas, and text layer properties as the source document, yet setting the text color works fine when done there.

Here is the rewrite:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

tell application "Pixelmator Pro"
	activate
	tell front document
		if not (count selected layers) = 1 then
			display alert "Make sure a single text layer is selected."
			return
		end if
		if not class of current layer = text layer then
			display alert "Make sure a single text layer is selected."
			return
		end if
		cut
	end tell
	make document from clipboard
	tell front document
		tell layer 1
			set fontSize to size of the text content
			set width to width + (width * 1.2) -- needed or text wraps when color is set
			set color of text content to {65535, 61096, 51260}
			convert into shape
		end tell
		tell styles of layer 1
			set stroke width to (fontSize / 25)
			set stroke position to center
		end tell
		tell layer 1
			set {coordX, coordY} to position
			repeat with stripeThickness from 1 to (fontSize / 18)
				duplicate
				set the position to {coordX - stripeThickness, coordY - stripeThickness}
			end repeat
		end tell
		set visible of layer 1 to false
		merge visible
		set visible of layer 1 to true
		repeat with currentLayerIndex from 2 to 4
			tell layer currentLayerIndex
				duplicate
				set {coordX, coordY} to position
			end tell
			set the position of layer (currentLayerIndex + 1) to ¬
				{coordX + stripeThickness, coordY + stripeThickness}
		end repeat
		set numberOfAdditionalStripes to 3
		select layer 2
		set currentLayerIndex to 2
		set rgbCodeList to {{10000, 12543, 23808}, {20736, 44544, 42752}, ¬
			{62976, 43776, 23040}, {55552, 22528, 20992}}
		set rgbColor to 1
		repeat with colorIndex from 1 to (1 + numberOfAdditionalStripes)
			set the fill color of the styles of layer currentLayerIndex to ¬
				{item rgbColor of rgbCodeList}
			set rgbColor to rgbColor + 1
			if rgbColor > 4 then
				set rgbColor to 1
			end if
			set currentLayerIndex to currentLayerIndex + 1
		end repeat
		tell styles of layer 1
			set stroke width to 0.0
		end tell
		merge visible
		copy
		close saving no
	end tell
	tell document 1
		paste
	end tell
end tell
While working on this rewrite I found two errors in Pixelmator Pro's Applescript implemtation: 1) The Dictionary text layer properties for font, size, and text color need to be presented as "get" and not "get/set". Attempting to set these cause a scripting error since setting properties must be done on the object that owns them, even though they can be readable from higher-up objects offering those same properties. 2) The delete command to delete a layer isn't working. Neither of the following work for me:
tell application "Pixelmator Pro"
	tell document 1
		delete current layer -- does nothing
		delete item 1 of selected layers -- execution fails
	end tell
end
User avatar

2020-09-23 13:31:04

Thanks to Andrius i received this script (below) to convert images to lossless HEIC.
It works fine for JPEGs.
For TIFFs it balks, with the following error:
error "Can’t make name of missing value into type Unicode text." number -1700 from name of missing value to Unicode text
Ive been on this every time i can for more than a week now and wasnt able to figure it out.
Tried making the script simply open a file without doing anything, also tried pre-setting source and destination - the same error pops up.
All works for a JPEG, but for a TIFF the script stops after opening the image file in Pixelmator Pro.

Anyone have any idea about what might be happening?

Any tip is greatly appreciated.
cheers
use scripting additions

tell application "Pixelmator Pro"
	set originalImages to choose file with prompt "Please select the images to process:" of type {"public.image"} with multiple selections allowed
	set exportLocation to choose folder with prompt "Please select where you'd like export the images:"
	repeat with a from 1 to number of originalImages
		set currentImage to open item a of originalImages
		export currentImage to file ((exportLocation as text) & name of currentImage & ".heic") as HEIC with properties {compression factor:100}
		close currentImage without saving
	end repeat
	display notification (number of originalImages as text) & " images exported to HEIC." with title "Export to HEIC"
end tell
User avatar

2020-09-23 14:12:41

Hey there, the script looks to be working fine with TIFFs for me so, if possible, could you share the TIFFs you're trying to process with me at andriusg@pixelmator.com? Here is also fine, if you prefer!
User avatar

2020-09-23 14:28:53

by Senior Moment 2020-09-22 18:59:14 As an exercise in curiosity I rewrote the 3D Text Effect script to perform its manipulations in a temporary document. Not having to track the working set of layers permits it to be 63 lines shorter, a distinct advantage in my view, so this technique could prove useful for scripts having to do similar layer manipulations.
Nice! This looks to also work faster and is more readable, too. Thanks for taking the time to do this!
User avatar

2020-09-23 21:44:23

by Andrius 2020-09-23 14:12:41 Hey there, the script looks to be working fine with TIFFs for me so, if possible, could you share the TIFFs you're trying to process with me at andriusg@pixelmator.com? Here is also fine, if you prefer!
hey, thx for helping, i wondered about that, but they are all Apple Photos app TIFF exports, hmm.. tiffs are gigantic so sending via we transfer, cheers!
User avatar

2020-09-24 08:44:31

Thanks for sharing the file, I managed to repro the issue. It looks like it's taking a long time to load the value of the name property and by the time the image is being exported, the value is still missing, resulting in the error. Here's a script that should work in these cases:
use scripting additions

tell application "Pixelmator Pro"
	set originalImages to choose file with prompt "Please select the images to process:" of type {"public.image"} with multiple selections allowed
	set exportLocation to choose folder with prompt "Please select where you'd like export the images:"
	repeat with a from 1 to number of originalImages
		set currentImage to open item a of originalImages
		set imageName to name of currentImage
		export currentImage to file ((exportLocation as text) & imageName & ".heic") as HEIC with properties {compression factor:100}
		close currentImage without saving
	end repeat
	display notification (number of originalImages as text) & " images exported to HEIC." with title "Export to HEIC"
end tell
I've also reported this to the team, we'll look into why this is happening with certain files!
User avatar

2020-09-24 09:33:29

Thank you! Your work with this will save me (& likely many cloud-storage users) countless hours of work and money - my gratitude cannot be overstated.

Something has changed, but an error still pops up, a new one:
error "Can’t get name of missing value." number -1728 from name of missing value
The highlighted word in the code is again name.
User avatar

2020-09-24 11:47:03

Huh. Is this with the same file or a different one? If it's a different one, any chance you could share that too?
User avatar

2020-09-24 12:00:11

Also, if Pixelmator Pro is having trouble getting the name of those files, let's try a workaround where we set the names using a Finder tell
use scripting additions

tell application "Finder"
	set originalImages to choose file with prompt "Please select the images to process:" of type {"public.image"} with multiple selections allowed
	set exportLocation to choose folder with prompt "Please select where you'd like export the images:"
	set originalImageNames to {}
	repeat with a from 1 to number of originalImages
		copy name of item a of originalImages to end of originalImageNames
	end repeat
end tell

tell application "Pixelmator Pro"
	repeat with a from 1 to number of originalImages
		set currentImage to open item a of originalImages
		set imageName to item a of originalImageNames
		export currentImage to file ((exportLocation as text) & imageName & ".heic") as HEIC with properties {compression factor:100}
		close currentImage without saving
	end repeat
	display notification (number of originalImages as text) & " images exported to HEIC." with title "Export to HEIC"
end tell
User avatar

2020-09-24 14:57:47

Same file.. but same with all (Mojave) Photos Exports.

The last script produced the original error:
error "Pixelmator Pro got an error: Can’t make missing value into type document." number -1700 from missing value to document
https://discussions.apple.com/thread/6732004
Was trying to go through this online for similar strangeness, apparently this person had the script working before a system update a loong time ago, but i have changed nothing in the system. Iv been scratching my head a lot with this. But if it works for you maybe we have got a clue? How are you exporting out of Photos tag-wise please?
User avatar

2020-09-25 09:43:15

OK, it looks like TIFF files exported from Photos might just be slow to open and that's what's causing a variety of issues. At least that's what it looks like to me. I was able to repro your error with some larger Photos exports reliably and here's a script that I got to work even with those photos:
use scripting additions

tell application "Finder"
	set originalImages to choose file with prompt "Please select the images to process:" of type {"public.image"} with multiple selections allowed
	set exportLocation to choose folder with prompt "Please select where you'd like export the images:"
	set originalImageNames to {}
	repeat with a from 1 to number of originalImages
		set extension hidden of item a of originalImages to true
		copy displayed name of item a of originalImages to end of originalImageNames
	end repeat
end tell

tell application "Pixelmator Pro"
	repeat with a from 1 to number of originalImages
		set currentImage to open item a of originalImages
		if currentImage = missing value then
			repeat with repeatCounter from 1 to 10
				try
					set currentImage to the front document
					if currentImage ≠ missing value then
						exit repeat
					end if
				on error
					delay 0.5
					if repeatCounter = 10 then
						activate
						display alert "Unable to set currentImage to the front document. Failed at image " & a & " of " & number of originalImages & "."
						return
					end if
				end try
			end repeat
		end if
		set imageName to item a of originalImageNames
		export currentImage to file ((exportLocation as text) & imageName & ".heic") as HEIC with properties {compression factor:100}
		close currentImage without saving
	end repeat
	display notification (number of originalImages as text) & " images exported to HEIC." with title "Export to HEIC"
end tell
Fingers crossed it works for you, too! You'll notice in the Pixelmator Pro tell, I try to give currentImage a value a set number of times. If you have some super large images, you can increase the delay or increase the number of attempts before the repeat loop breaks, I just didn't want to end up in an infinite loop just in case something goes wrong.
User avatar

2020-09-25 09:57:37

Hi, I have been on the fence about purchasing Pro (longtime regular Pixelmator customer, though) until I saw this post. I have been wanting this exact functionality forever! As an iOS dev, I've used Pixelmator to create app icons but it was a cumbersome process by hand to resize my 1024x1024 app store image to the smaller sizes (not to mention slightly blurry but I'm not an artist so I do my best.) I jumped into writing this process as a script but it doesn't seem like `export` allows references inside a `tell document` statement?

Here's my attempt:
set desktopPath to (path to desktop as text)
set folderPath to desktopPath & "Exports"
set exportFolder to ""

tell application "Finder"
	if exists folder folderPath is false then
		make new folder at desktopPath with properties {name:"exports"}
	end if
	
	set exportFolder to folder folderPath
end tell

tell application "Pixelmator Pro"
	tell its front document
		set imageBaseName to (exportFolder as text) & name
		
		# 1024 x 1024
		export it to file (imageBaseName & ".png") as PNG with properties {compression factor:100}
		
		set sizes to {180, 167, 152, 120, 76}
		repeat with size in sizes
			resize image width size height size resolution 72 algorithm ml super resolution
			export to file (imageBaseName & "@" & (size as text) & ".png") as PNG with properties {compression factor:100}
			undo
		end repeat
	end tell
end tell
But i get an error
"Pixelmator Pro got an error: Invalid key form." number -10002 from file "Macintosh HD:Users:cool_user:Desktop:exports:SOC Icon.pxd@1024.png" of document 1
User avatar

2020-09-25 11:00:19

Hey Nate, that's partially a (quite weird) syntax issue and partially a (well, quite weird) sandboxing issue. Syntax-wise, if you're inside a document tell block, you should use:
export it to (imageBaseName & ".png") as PNG with properties {compression factor:100}
However, this will only work for files that have already been opened by Pixelmator Pro during that session, which means the sandbox allows you to write to those files. If you simply changed your script to remove 'file', you wouldn't get the invalid key form error, but the script would fail silently.

With that in mind, here's a relatively simple way to rewrite your script to get it to work:
set desktopPath to (path to desktop as text)
set folderPath to desktopPath & "Exports"
set exportFolder to ""

tell application "Finder"
	if exists folder folderPath is false then
		make new folder at desktopPath with properties {name:"exports"}
	end if
	
	set exportFolder to folder folderPath
end tell

tell application "Pixelmator Pro"
	set imageBaseName to (exportFolder as text) & name of the front document
	
	# 1024 x 1024
	export the front document to file (imageBaseName & ".png") as PNG with properties {compression factor:100}
	
	set sizes to {180, 167, 152, 120, 76}
	repeat with size in sizes
		tell the front document to resize image width size height size resolution 72 algorithm ml super resolution
		export the front document to file (imageBaseName & "@" & (size as text) & ".png") as PNG with properties {compression factor:100}
		tell the front document to undo
	end repeat
end tell
User avatar

2020-09-25 11:15:18

Just to loop back, I had to change `undo` to `tell front document to undo` and my base name to `tell front document to set imageName to name` but otherwise, it works! This is so great.
User avatar

2020-09-25 11:36:40

Oh snap, yeah, I'll edit my script to fix those two things, silly oversight on my part! Glad to hear you managed to get everything working, though.
User avatar

2020-09-25 19:50:54

@Andrius Glory Glory.. It Works! i wish you and the Pixelmator team all get many times in hours of joy, the thousand hours you saved me. Can't recommend Pixelmator enough, since the very first versions it has been special and unique, but with this kind of support really nothing compares. Cheers!
User avatar

2020-09-26 15:34:53

Thank you for adding AppleScript support in Pixelmator Pro!

Is there a way to turn fill off completely for a shape layer? I have a shape that only needs a stroke, not a fill.

I have been able to set 'fill opacity' to 0, but would really like to do the equivalent of unchecking the Fill checkbox in the interface.

Thank you!
User avatar

2020-09-27 17:57:56

This should be easy, but how would you paste at a specific position?