Print as pdf in the same folder of the original file

Is possible to automate this:

  1. from any application, choose save to pdf (or print to pdf, or print to a pdf printer);
  2. save the file in the same folder of the original file;
  3. set password (no copy) of this new file?

Thanks.
Gianluca.

You may try this code :

property definePasswordInPrintDialog : true
# false --> define the password at the beginning then everything is automated
# true --> define the password by hand in the print dialog. You will have to click the buttons !

tell application "System Events" -- get frontmost process
	set frontmostProcess to first process where it is frontmost -- this will be the script process
	if name of frontmostProcess is in {"Script Editor", "AppleScript Editor", "Time Machine", "Finder"} then
		set visible of frontmostProcess to false -- hide the script process
		repeat while (frontmostProcess is frontmost) -- wait until the script is hiden
			delay 0.2
		end repeat
		set theApp to name of first process where it is frontmost -- get name of frontmost process (ignoring the script process)
		set frontmost of frontmostProcess to true -- unhide the script process
	else
		set theApp to name of frontmostProcess
	end if
	set fileApp to path of file of process theApp
end tell # System Events

# Get the path to the document to export.
tell application fileApp to set sourcePath to path of document 1

if not definePasswordInPrintDialog then
	-- display dialog "Enter your password" default answer "??????"  # activate this one if you want to see what you type
	display dialog "Enter your password" default answer "??????" with hidden answer # activate this one if you want to hide what you type
	set thePassword to text returned of result
end if

tell application "System Events"
	tell disk item sourcePath
		set {sourceName, sourceFolder, sourceNameExtension} to {its name, path of its container, its name extension}
		if sourceNameExtension > "" then
			set bareName to text 1 thru -(2 + (count sourceNameExtension)) of sourceName
		else
			set bareName to sourceName
		end if
	end tell # disk item
	# Builds an unique PDF name
	set cnt to 1
	set thePDFname to bareName & ".pdf"
	repeat
		if not (exists disk item (sourceFolder & thePDFname)) then
			exit repeat
		else
			set cnt to cnt + 1
			set thePDFname to bareName & "#" & cnt & ".pdf"
		end if
	end repeat
end tell # System Events
# converts the folder path to a POSIX one to pass it in the dialog
log sourceFolder
set posixFolderPath to POSIX path of sourceFolder

# Code borrowed from Nigel Garvey (http://macscripter.net/viewtopic.php?id=41654)
tell application "System Events"
	tell process theApp
		set frontmost to true
		keystroke "p" using {command down}
		
		tell window 1
			repeat until exists sheet 1
				delay 0.2
			end repeat
			tell sheet 1
				set PDFButton to first menu button
				click PDFButton
				-- log (get name of menu items of menu 1 of PDFButton)
				--> {"Ouvrir le PDF dans Aperçu", "Enregistrer au format PDF.", "Enregistrer au format PostScript.", "Faxer le document PDF.", missing value, "@ PDF-BAT.qfilter", "@ PDF-prépresse CMJN.qfilter", "@ PDF-web.qfilter", "@ PDFX3-ISO.qfilter", "Add PDF to iTunes", "Envoyer le document PDF par courrier électronique", "Enregistrer le document PDF dans le dossier de reçus web", missing value, "Modifier le menu."}
				click menu item 2 of menu 1 of PDFButton
				(*
Wait for the availability of the Print sheet *)
				repeat
					if exists sheet 1 then exit repeat
					delay 0.1
				end repeat
				(*
Set the name of the new PDF *)
				tell sheet 1
					set value of text field 1 to thePDFname
					# Open the pane allowing the setting of destination folder
					
					keystroke "g" using {command down, shift down}
					repeat until exists sheet 1
						delay 0.02
					end repeat
					# Set the destination folder
					tell sheet 1
						set value of text field 1 to posixFolderPath
						-- log (get name of buttons) (*Aller, Annuler*)
						click button 1
					end tell
					
					-- log (get class of UI elements) --> {group, button, button, button, group, checkbox, text field, static text, static text, text field}
					tell group 1
						-- log (get class of UI elements) --> {text field, static text, button, text field, static text, text field, static text, static text, text field}
						click button 1
					end tell
				end tell # sheet 1 (the Save As one)
			end tell -- sheet
		end tell -- window
		# Wait for the dialog allowing to define password
		repeat
			delay 0.2
			if exists (window 1 whose subrole is "AXDialog") then exit repeat
		end repeat
		tell (window 1 whose subrole is "AXDialog")
			-- log (get properties of UI elements)
			(*
Resume of the properties
01 - static text,  position:{797, 267}, value:"Mot de passe :" - to Open
01 - text field, position:{896, 411}, subrole:"AXSecureTextField" - to Print or Copy
02 - static text,  position:{797, 413}, value:"Mot de passe :" - to Print or Copy
03 - text field, position:{896, 443}, subrole:"AXSecureTextField" - to Print or Copy
04 - text field, position:{896, 265}, subrole:"AXSecureTextField" - to Open
05 - text field, position:{896, 297}, subrole:"AXSecureTextField" - to Open
03 - static text, position:{797, 299}, value:"Confirmation :" - to Open
04 - static text, position:{797, 445}, value:"Confirmation :" - to Print or Copy
01 - checkbox, "Demander un mot de passe pour imprimer le document" - to Print
02 - checkbox, "Exiger un mot de passe pour ouvrir le document" - to Open
03 - checkbox, "Demander un mot de passe pour copier du texte, des 
images et tout autre contenu" - to Copy
01 - button, "OK"
02 - button, "Annuler"
05 - static text, "Options de sécurité PDF"
*)
			# Here you must be patient, the system take some time before displaying the dialog
			click checkbox 3
			if not definePasswordInPrintDialog then
				set value of text field 1 to thePassword
				set value of text field 2 to thePassword
				click button 1
			end if
		end tell # (window 1 whose subrole is "AXDialog")
		if not definePasswordInPrintDialog then
			tell window 1 to tell sheet 1
				tell sheet 1
					log (get name of buttons) --> 	(*Enregistrer, Nouveau dossier, Annuler*)
					keystroke return
				end tell
				log (get name of buttons) --> (*missing value, Masquer les détails, missing value, Annuler, Imprimer*)
				keystroke return
			end tell
		end if
	end tell # process
end tell # System Events

Yvan KOENIG running El Capitan 10.11.3 in French (VALLAURIS, France) vendredi 5 février 2016 19:34:56

great! good job, but I can’t use… or… I don’t know how to use.

I did so:

  1. create an application from applescript;
  2. modified pdf-print menu, adding the app.

But, when I try, it close immediately…

Save the script as an application.
Open a document. I tested with a rtfd file open in TextEdit.
Double click the script icon or launch it thru a shortcut linked to it with FastScript.

The script will print the open document in a PDF file.

Yvan KOENIG running El Capitan 10.11.3 in French (VALLAURIS, France) vendredi 5 février 2016 22:04:20

thanks! with textedit works! I’ll try with other application (with word and with chrome it doesn’t work)

I’m not a sooth sayer so I have no idea of what your message really means.
Did the script quits ?
Did it issue an error message ?
If it issue an error message, which one is it ?

I can’t test with Word because Merdosoft products aren’t allowed to enter my home and my machines.

I mad a test with LibreOffice. This app has no AppleScript support so the script fails when it’s asked to get the sourcePath of the open document.
I may partially override that extracting the title of the window to get the name of the file but I have no way to get its complete path so I can’t identify the folder in which it is stored.
So I will have to store the PDF without knowing the source folder.
More, LibreOffice doesn’t match the standard behavior of the Print function.
The Print dialog is not a sheet of the document window, it is a window of its own.

I will try to enhance the script according to that.

I’m puzzled about Chrome. As far as I know, it’s a web navigator so I have no idea of what may be the source folder of the displayed window.

Yvan KOENIG running El Capitan 10.11.3 in French (VALLAURIS, France) samedi 6 février 2016 12:36:18

Here is an enhanced version.
I tested it with TextEdit, Numbers and LibreOffice.

property definePasswordInPrintDialogByHand : false
# false --> define the password at the beginning then everything is automated
# true --> define the password by hand in the print dialog. You will have to click the buttons !

property nbTrials : 10

#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#

set Print_loc to localized string "Print" in bundle ((path to application id ("com.apple.preview")) as «class furl») --> "Imprimer"

tell application "System Events" -- get frontmost process
	set frontmostProcess to first process where it is frontmost -- this will be the script process
	if name of frontmostProcess is in {"Script Editor", "AppleScript Editor", "Time Machine"} then
		set visible of frontmostProcess to false -- hide the script process
		repeat while (frontmostProcess is frontmost) -- wait until the script is hiden
			delay 0.2
		end repeat
		set theProcess to name of first process where it is frontmost -- get name of frontmost process (ignoring the script process)
		set frontmost of frontmostProcess to true -- unhide the script process
	else
		set theProcess to name of frontmostProcess
	end if
	if theProcess is "Finder" then error "Don't apply upon Finder"
	set fileApp to path of file of process theProcess
end tell # System Events

try
	# Try to get the path to the document to export if the app behaves like TextEdit.
	# It returns a POSIX path
	tell application fileApp to set sourcePath to path of document 1
	tell application "System Events" to tell disk item sourcePath
		set {sourceName, sourceFolder, sourceNameExtension} to {its name, path of its container, its name extension}
	end tell
on error
	try
		# Try to get the path to the document to export if the app behaves like iWork's ones.
		# Must coerce the returned file as text.
		tell application fileApp to set sourcePath to (file of document 1 as text)
		tell application "System Events" to tell disk item sourcePath
			set {sourceName, sourceFolder, sourceNameExtension} to {its name, path of its container, its name extension}
		end tell
	on error
		# It seems that the app doesn't support AppleScript.
		# Extracts the source name from System Events.
		tell application "System Events" to tell process theProcess
			set frontmost to true
			set sourceName to title of window 1
			-- log result --> (*Bon_de_commande.xls*)
		end tell
		# Defines a fake sourceFolder
		set sourceFolder to path to desktop as text
		# Extracts the name extension
		set maybeList to my decoupe(sourceName, ".")
		if (count maybeList) = 1 then
			set sourceNameExtension to ""
		else
			set sourceNameExtension to (maybeList's item -1) as text --> "xls"
		end if
	end try
end try

if not definePasswordInPrintDialogByHand then
	-- tell application "SystemUIServer" todisplay dialog "Enter your password" default answer "??????"  # activate this one if you want to see what you type
	tell application "SystemUIServer" to display dialog "Enter your password" default answer "??????" with hidden answer # activate this one if you want to hide what you type
	set thePassword to text returned of result
end if

tell application "System Events"
	if sourceNameExtension > "" then
		set bareName to text 1 thru -(2 + (count sourceNameExtension)) of sourceName
	else
		set bareName to sourceName
	end if
	# Builds an unique PDF name
	set cnt to 1
	set thePDFname to bareName & ".pdf"
	repeat
		if not (exists disk item (sourceFolder & thePDFname)) then
			exit repeat
		else
			set cnt to cnt + 1
			set thePDFname to bareName & "#" & cnt & ".pdf"
		end if
	end repeat
end tell # System Events
# converts the folder path to a POSIX one to pass it in the dialog
-- log sourceFolder
set posixFolderPath to POSIX path of sourceFolder

# Code borrowed from Nigel Garvey (http://macscripter.net/viewtopic.php?id=41654)
tell application "System Events" to tell process theProcess
	set frontmost to true
	keystroke "p" using {command down}
	tell window 1
		-- log (get its title) --> 	(*Imprimer*)
		set knt to 0
		repeat nbTrials times
			set knt to knt + 1
			delay 0.2
			if exists sheet 1 then exit repeat
		end repeat
	end tell # window 
end tell # process of System Events

if knt < nbTrials then
	# Issuing cmd + P opened a sheet.
	my useAsheet(theProcess, thePDFname, posixFolderPath, thePassword)
else
	tell application "System Events" to tell process theProcess
		set frontmost to true
		tell window 1 to set itsTitle to its title --> (*Imprimer*)
	end tell # process of System Events
	if itsTitle is not sourceName then
		# issuing cmd + P opened a dialog window.
		my useAwindow(theProcess, thePDFname, posixFolderPath, thePassword)
	else
		# Maybe issuing cmd + P revealed a Page Setup Inspector
		tell application "System Events" to tell process theProcess
			set frontmost to true
			tell window sourceName
				-- log (get class of UI elements) --> (*scroll area, button, scroll area, button, button, radio group, scroll area, button, button, static text, radio group, button, button, button, menu button, toolbar, image, static text*)
				-- log (get name of buttons) --> 	(*missing value, missing value, missing value, Terminé, Imprimer., missing value, missing value, missing value*)
				try
					set printButton to name of first button whose name contains Print_loc
				on error errMsg number errNbr
					# Maybe it's just that the app isn't localized
					set printButton to ""
					set theButtons to name of buttons
					repeat with aButton in theButtons
						if (aButton as text) contains "Print" then
							set printButton to aButton as text
							exit repeat
						end if
					end repeat
					if printButton = "" then error "Unknown behavior, " & errMsg & ", #" & errNbr
				end try
				click button printButton
			end tell # window sourceName
			my useAsheet(theProcess, thePDFname, posixFolderPath, thePassword)
		end tell # process of System Events.
	end if
end if

#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#

on decoupe(t, d)
	local oTIDs, l
	set {oTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, d}
	set l to text items of t
	set AppleScript's text item delimiters to oTIDs
	return l
end decoupe

#=====

on useAsheet(theProcess, thePDFname, posixFolderPath, thePassword)
	tell application "System Events"
		tell process theProcess
			set frontmost to true
			# We are here if the Print dialog is a sheet
			tell window 1
				-- log (get its title) --> (*Paper Sizes.rtfd*)
				tell sheet 1
					-- log (get its title) --> (*missing value*)
					set PDFButton to first menu button
					# Reveal the local menu
					click PDFButton
					-- log (get name of menu items of menu 1 of PDFButton)
					--> {"Ouvrir le PDF dans Aperçu", "Enregistrer au format PDF.", "Enregistrer au format PostScript.", "Faxer le document PDF.", missing value, "@ PDF-BAT.qfilter", "@ PDF-prépresse CMJN.qfilter", "@ PDF-web.qfilter", "@ PDFX3-ISO.qfilter", "Add PDF to iTunes", "Envoyer le document PDF par courrier électronique", "Enregistrer le document PDF dans le dossier de reçus web", missing value, "Modifier le menu."}
					click menu item 2 of menu 1 of PDFButton
					(*
Wait for the availability of the Print sheet *)
					set knt to 0
					repeat nbTrials times
						set knt to knt + 1
						delay 0.1
						if exists sheet 1 then exit repeat
					end repeat
					if knt ≥ nbTrials then error number -128
					
					tell sheet 1
						-- log (get its title) --> (*missing value*)
						set value of text field 1 to thePDFname # Set the name of the new PDF
						# Open the pane allowing the setting of destination folder
						
						keystroke "g" using {command down, shift down}
						set knt to 0
						repeat nbTrials times
							set knt to knt + 1
							delay 0.2
							if exists sheet 1 then exit repeat
						end repeat
						if knt ≥ nbTrials then error number -128
						
						tell sheet 1
							-- log (get its title) --> (*missing value*)
							set value of text field 1 to posixFolderPath # Set the destination folder
							-- log (get name of buttons) (*Aller, Annuler*)
							click button 1
						end tell
						-- log (get class of UI elements) --> {group, button, button, button, group, checkbox, text field, static text, static text, text field}
						tell group 1
							-- log (get class of UI elements) --> {text field, static text, button, text field, static text, text field, static text, static text, text field}
							click button 1
						end tell
					end tell # the «Save As» sheet
				end tell -- the «Print» sheet
			end tell -- the document window
			
			# Wait for the dialog allowing to define password
			set knt to 0
			repeat nbTrials times
				set knt to knt + 1
				delay 0.2
				if exists (window 1 whose subrole is "AXDialog") then exit repeat
			end repeat
			if knt ≥ nbTrials then error number -128
			tell (window 1 whose subrole is "AXDialog")
				-- log (get its title) --> (*Options de sécurité PDF*)
				-- log (get properties of UI elements)
				(*
Resume of the properties
static text 1,  position:{797, 267}, value:"Mot de passe :" - to Open
text field 1, position:{896, 411}, subrole:"AXSecureTextField" - to Print or Copy
static text 2,  position:{797, 413}, value:"Mot de passe :" - to Print or Copy
text field 3, position:{896, 443}, subrole:"AXSecureTextField" - to Print or Copy
text field 4, position:{896, 265}, subrole:"AXSecureTextField" - to Open
text field 5, position:{896, 297}, subrole:"AXSecureTextField" - to Open
static text 3, position:{797, 299}, value:"Confirmation :" - to Open
static text 4, position:{797, 445}, value:"Confirmation :" - to Print or Copy
checkbox 1, "Demander un mot de passe pour imprimer le document" - to Print
checkbox 2, "Exiger un mot de passe pour ouvrir le document" - to Open
checkbox 3, "Demander un mot de passe pour copier du texte, des 
images et tout autre contenu" - to Copy
button 1, "OK"
button 2, "Annuler"
static text 5, "Options de sécurité PDF"
*)
				# Here you must be patient, the system take some time before displaying the dialog
				click checkbox 3
				if not definePasswordInPrintDialogByHand then
					set value of text field 1 to thePassword
					set value of text field 2 to thePassword
					click button 1
				end if
			end tell # (window 1 whose subrole is "AXDialog")
			
			if not definePasswordInPrintDialogByHand then
				tell window 1 to tell sheet 1
					-- log (get its title) --> (*Imprimer*)
					tell sheet 1
						-- log (get its title) --> (*missing value*)
						-- log (get name of buttons) --> 	(*Enregistrer, Nouveau dossier, Annuler*)
						click button 1 # idem keystroke return
					end tell
					-- log (get name of buttons) --> (*missing value, Masquer les détails, missing value, Annuler, Imprimer*)
					keystroke return
				end tell
			end if
			
		end tell # process
	end tell # System Events
end useAsheet

#=====

on useAwindow(theProcess, thePDFname, posixFolderPath, thePassword)
	tell application "System Events"
		tell process theProcess
			# We are here if the Print dialog is a window
			-- log (get subrole of windows) --> 	(*AXDialog, AXStandardWindow*)
			tell window 1
				-- log (get its title) --> (*Imprimer*)
				set PDFButton to first menu button
				# Reveal the local menu
				click PDFButton
				-- log (get name of menu items of menu 1 of PDFButton)
				--> {"Ouvrir le PDF dans Aperçu", "Enregistrer au format PDF.", "Enregistrer au format PostScript.", "Faxer le document PDF.", missing value, "@ PDF-BAT.qfilter", "@ PDF-prépresse CMJN.qfilter", "@ PDF-web.qfilter", "@ PDFX3-ISO.qfilter", "Add PDF to iTunes", "Envoyer le document PDF par courrier électronique", "Enregistrer le document PDF dans le dossier de reçus web", missing value, "Modifier le menu."}
				click menu item 2 of menu 1 of PDFButton
				(*
Wait for the availability of the Print sheet *)
				set knt to 0
				repeat nbTrials times
					set knt to knt + 1
					delay 0.1
					if exists sheet 1 then exit repeat
				end repeat
				if knt ≥ nbTrials then error number -128
				
				tell sheet 1
					-- log (get its title) --> (*missing value*)
					set value of text field 1 to thePDFname # Set the name of the new PDF
					# Open the pane allowing the setting of destination folder
					keystroke "g" using {command down, shift down}
					set knt to 0
					repeat nbTrials times
						set knt to knt + 1
						delay 0.2
						if exists sheet 1 then exit repeat
					end repeat
					if knt ≥ nbTrials then error number -128
					
					tell sheet 1
						-- log (get its title) --> (*missing value*)
						set value of text field 1 to posixFolderPath # Set the destination folder
						-- log (get name of buttons) (*Aller, Annuler*)
						click button 1
					end tell
					-- log (get class of UI elements) --> {group, button, button, button, group, checkbox, text field, static text, static text, text field}
					tell group 1
						-- log (get class of UI elements) --> {text field, static text, button, text field, static text, text field, static text, static text, text field}
						click button 1
					end tell
				end tell # the «Save As» sheet
			end tell -- the document window
			
			# Wait for the dialog allowing to define password
			set knt to 0
			repeat nbTrials times
				set knt to knt + 1
				delay 0.2
				if exists (window 1 whose subrole is "AXDialog") then exit repeat
			end repeat
			if knt ≥ nbTrials then error number -128
			tell (window 1 whose subrole is "AXDialog")
				-- log (get its title) --> (*Options de sécurité PDF*)
				-- log (get properties of UI elements)
				(*
Resume of the properties
static text 1,  position:{797, 267}, value:"Mot de passe :" - to Open
text field 1, position:{896, 411}, subrole:"AXSecureTextField" - to Print or Copy
static text 2,  position:{797, 413}, value:"Mot de passe :" - to Print or Copy
text field 3, position:{896, 443}, subrole:"AXSecureTextField" - to Print or Copy
text field 4, position:{896, 265}, subrole:"AXSecureTextField" - to Open
text field 5, position:{896, 297}, subrole:"AXSecureTextField" - to Open
static text 3, position:{797, 299}, value:"Confirmation :" - to Open
static text 4, position:{797, 445}, value:"Confirmation :" - to Print or Copy
checkbox 1, "Demander un mot de passe pour imprimer le document" - to Print
checkbox 2, "Exiger un mot de passe pour ouvrir le document" - to Open
checkbox 3, "Demander un mot de passe pour copier du texte, des 
images et tout autre contenu" - to Copy
button 1, "OK"
button 2, "Annuler"
static text 5, "Options de sécurité PDF"
*)
				# Here you must be patient, the system take some time before displaying the dialog
				click checkbox 3
				if not definePasswordInPrintDialogByHand then
					set value of text field 1 to thePassword
					set value of text field 2 to thePassword
					click button 1
				end if
			end tell # (window 1 whose subrole is "AXDialog")
			
			if not definePasswordInPrintDialogByHand then
				tell window 1
					-- log (get its title) --> (*Imprimer*)
					tell sheet 1
						-- log (get its title) --> (*missing value*)
						-- log (get name of buttons) --> 	(*Enregistrer, Nouveau dossier, Annuler*)
						click button 1 # keystroke return
					end tell # sheet
				end tell # window Imprimer
			end if
		end tell # process
	end tell # System Events
end useAwindow

I left numerous log instructions (disabled) which were useful during the building process.
I guess that they would be useful if you use the script as the beginning of an other one triggering the same dialogs.

Yvan KOENIG running El Capitan 10.11.3 in French (VALLAURIS, France) samedi 6 février 2016 20:24:08