Hi everyone,
I'm trying to use Automator to batch process PDF files. I have hundreds of academic journal article PDFs whose page sizes vary from 5x7 inches to A4 format (8.27 x 11.69 inches). I want to scale all the PDFs to US Letter size (8.5 x 11.0 inches) such that smaller originals remain 100% scale but are centered on the larger page and larger originals are scaled down to fit the page.
Manually opening a PDF in Preview.app, scaling it to US Letter paper, and using the Save as PDF option is producing the desired output for me. I captured my workflow using the Watch Me Do action in Automator, then adjusted it into the following AppleScript.
-- a Get Specified Finder Items action to specify the input PDFs precedes this script
on run {input, parameters}
repeat with filePath in input
-- Open the file in Preview
tell application "Preview"
open filePath
activate
end tell
-- Give Preview some time to open the file
delay 2.0
-- Press ⌘P
set timeoutSeconds to 0.25
set uiScript to "keystroke \"p\" using command down"
my doWithTimeout(uiScript, timeoutSeconds)
-- Click the “Scale to Fit:” radio button.
delay 2.0
set timeoutSeconds to 2.0
set uiScript to "click radio button \"Scale to Fit:\" of radio group 1 of group 1 of group 2 of scroll area 2 of splitter group 1 of sheet 1 of window 1 of application process \"Preview\""
my doWithTimeout(uiScript, timeoutSeconds)
-- Click the “<fill in title>” menu button.
delay 4.0
set timeoutSeconds to 2.000000
set uiScript to "click menu button 1 of group 2 of splitter group 1 of sheet 1 of window 1 of application process \"Preview\""
my doWithTimeout( uiScript, timeoutSeconds )
-- Save as PDF…
delay 2.0
set timeoutSeconds to 2.0
set uiScript to "click menu item 2 of menu 1 of splitter group 1 of sheet 1 of window 1 of application process \"Preview\""
my doWithTimeout(uiScript, timeoutSeconds)
-- Click the “Save” button.
delay 8.0
set timeoutSeconds to 2.0
set uiScript to "click UI Element \"Save\" of sheet 1 of sheet 1 of window 1 of application process \"Preview\""
my doWithTimeout(uiScript, timeoutSeconds)
-- Press ⌘W to close the file
delay 0.25
set timeoutSeconds to 2.0
set uiScript to "keystroke \"w\" using command down"
my doWithTimeout(uiScript, timeoutSeconds)
end repeat
return input
end run
on doWithTimeout(uiScript, timeoutSeconds)
set endDate to (current date) + timeoutSeconds
repeat
try
run script "tell application \"System Events\"
" & uiScript & "
end tell"
exit repeat
on error errorMessage
if ((current date) > endDate) then
error "Can not " & uiScript
end if
end try
end repeat
end doWithTimeout
My problem arises at the Save as PDF step. When this action runs, I see the PDF menu pop open:
but the Save as PDF... menu item doesn't get clicked. Instead, I get an error:
Can anyone advise on how to overcome this error?
It's tricky trying to figure out the proper GUI scripting path for accessing items in the menu. I was able avoid the issue all together by accessing the menu item using two down arrow keystrokes followed by an enter keystroke. Here's the modified script:
on run {input, parameters}
repeat with filePath in input
-- Open the file in Preview
tell application "Preview"
open filePath
activate
end tell
-- Give Preview some time to open the file
delay 2.0
-- Press ⌘P
tell application "System Events"
tell process "Preview"
keystroke "p" using command down
end tell
end tell
-- set timeoutSeconds to 0.25
-- set uiScript to "keystroke \"p\" using command down"
-- my doWithTimeout(uiScript, timeoutSeconds)
-- Click the “Scale to Fit:” radio button.
delay 2.0
set timeoutSeconds to 2.0
set uiScript to "click radio button \"Scale to Fit:\" of radio group 1 of group 1 of group 2 of scroll area 2 of splitter group 1 of sheet 1 of window 1 of application process \"Preview\""
my doWithTimeout(uiScript, timeoutSeconds)
-- Click the “<fill in title>” menu button.
delay 4.0
set timeoutSeconds to 2.0
set uiScript to "click menu button 1 of group 2 of splitter group 1 of sheet 1 of window 1 of application process \"Preview\""
my doWithTimeout(uiScript, timeoutSeconds)
-- Save as PDF…
delay 2.0
set timeoutSeconds to 2.0
set uiScript to "click menu button 1 of group 2 of splitter group 1 of sheet 1 of window 1 of application process \"Preview\""
my doWithTimeout(uiScript, timeoutSeconds)
-- type down arrow twice
tell application "System Events"
tell process "Preview"
keystroke (ASCII character 31) -- type a down arrow
-- note, 'keystroke (ASCII character 31)' is the same as 'key code 125'
end tell
end tell
delay 0.1
tell application "System Events"
tell process "Preview"
keystroke (ASCII character 31) -- type a down arrow
end tell
end tell
delay 0.1
-- type the enter key
tell application "System Events"
tell process "Preview"
keystroke (ASCII character 13) -- type a return
-- note, 'keystroke (ASCII character 13)' is the same as 'key code 36'
end tell
end tell
delay 0.1
--set uiScript to "select menu item 2 of menu 1 of menu button 1 of group 2 of splitter group 1 of sheet 1 of window 1 of application process \"Preview\""
--my doWithTimeout(uiScript, timeoutSeconds)
-- Click the “Save” button.
delay 8.0
set timeoutSeconds to 2.0
set uiScript to "click UI Element \"Save\" of sheet 1 of sheet 1 of window 1 of application process \"Preview\""
my doWithTimeout(uiScript, timeoutSeconds)
-- Press ⌘W to close the file
delay 0.25
set timeoutSeconds to 2.0
set uiScript to "keystroke \"w\" using command down"
my doWithTimeout(uiScript, timeoutSeconds)
end repeat
return input
end run
on doWithTimeout(uiScript, timeoutSeconds)
set endDate to (current date) + timeoutSeconds
repeat
try
run script "tell application \"System Events\"
" & uiScript & "
end tell"
exit repeat
on error errorMessage
if ((current date) > endDate) then
error "Can not " & uiScript
end if
end try
end repeat
end doWithTimeout
note, I made some minor changes to the ⌘P part to get it working over here at this end. I had this working on Sequoia 15.3.1 (24D70).