I'm working on a project for OSX where the user can pick a collection of documents (from any application) which I need to generate PDF's from. The standard Macintosh Print dialog has a PDF button which has a number of PDF-related commands including "Save as PDF...". However, I need to generate the PDF file without requiring user interactions. I ideally want this to work with any type of document.
我正在为OSX做一个项目,在这个项目中,用户可以从任何应用程序中选择一组文档,我需要从这些文档中生成PDF。标准的Macintosh打印对话框有一个PDF按钮,其中有许多与PDF相关的命令,包括“Save as PDF…”。但是,我需要生成PDF文件,而不需要用户交互。理想情况下,我希望它适用于任何类型的文档。
Here's the options I've explored so far:
下面是我到目前为止所探索的选项:
- Automator actions. There's a PDF library for Automator but it provides actions for working with PDF files, not generating them. There's a Finder action for printing any file but only to a real printer.
- Automator行动。有一个自动程序的PDF库,但是它提供了操作PDF文件的操作,而不是生成它们。有一个查找程序可以打印任何文件,但只能打印到真正的打印机。
- AppleScript. Some applications have the ability to generate PDF files (for instance, if you send 'save doc in "test.pdf"' to Pages it will generate a PDF (but this only works for Pages - I need support for any type of document).
- AppleScript。有些应用程序能够生成PDF文件(例如,如果您发送'save doc in '测试)。pdf“'到页它将生成pdf(但这只适用于页-我需要支持任何类型的文档)。
- Custom Printer. I could create a virtual printer driver and then use the automator action but I don't like the idea of confusing the user with an extra printer in the print list.
- 自定义打印机。我可以创建一个虚拟打印机驱动程序,然后使用自动操作,但是我不喜欢将用户与打印列表中的额外打印机混淆。
My hope is that there's some way to interact with the active application as if the user was carrying out the following steps:
我希望有一种方法可以与活动应用程序交互,就好像用户正在执行以下步骤:
- Do Cmd-P (opens the print dialog)
- 执行Cmd-P(打开打印对话框)
- Click the "PDF" button
- 单击“PDF”按钮
- Select "Save as PDF..." (second item in menu)
- 选择“保存为PDF……”(第二项菜单)
- Type in filename in save dialog
- 在“保存”对话框中键入文件名。
- Click "Save"
- 点击“保存”
If that's the best approach (is it?) then the real problem is: how do I send UI Events to an external application (keystrokes, mouse events, menu selections) ?
如果这是最好的方法(是吗?),那么真正的问题是:如何将UI事件发送到外部应用程序(击键、鼠标事件、菜单选择)?
Update: Just to clarify one point: the documents I need to convert to PDF are documents that are created by other applications. For example, the user might pick a Word document or a Numbers spreadsheet or an OmniGraffle drawing or a Web Page. The common denominator is that each of these documents has an associated application and that application knows how to print it (and OSX knows how to render print output to a PDF file).
更新:澄清一点:我需要转换为PDF的文档是由其他应用程序创建的文档。例如,用户可以选择一个Word文档或一个数字电子表格,或者一个杂色绘图或一个Web页面。它们的共同点是,每个文档都有一个关联的应用程序,该应用程序知道如何打印它(OSX知道如何将打印输出呈现给PDF文件)。
So, the samples at Cocoa Dev Central don't help because they're about generating a PDF from my application.
所以,Cocoa Dev Central的示例没有帮助,因为它们是关于从我的应用程序生成PDF的。
5 个解决方案
#1
6
I think you could use applescript to open a document and then use applescript UI scripting to invoke print menu.
我认为您可以使用applescript打开文档,然后使用applescript UI脚本调用print菜单。
For example :
例如:
tell application "System Events"
tell window of process "Safari"
set foremost to true
keystroke "p" using {command down}
delay 3
click menu button "PDF" of sheet 2
click menu item "Save as PDF…" of menu 1 of menu button "PDF" of sheet 2
keystroke "my_test.file"
keystroke return
delay 10
end tell
end tell
#2
2
Take a look at a program called CUPS-PDF
看看一个叫CUPS-PDF的程序。
It is a virtual printer for OS X which does what the "Save As PDF" method does when print through your normal printer except every print job passed through it results in a pdf output.
它是OS X的一个虚拟打印机,它的功能与“保存为PDF”方法在普通打印机上打印时所做的功能是一样的,除了通过它传递的每个打印作业都会产生PDF输出。
Once you install it then you could create shell or AppleScripts using the lp command.
安装之后,可以使用lp命令创建shell或applesscript。
For example, once the virtual printer is setup you could print test.txt and have it automatically save as a pdf. To do this using an AppleScript you would use the following code:
例如,一旦建立了虚拟打印机,就可以打印测试。并自动保存为pdf格式。要使用AppleScript处理,您需要使用以下代码:
do shell script "lp -d CUPS_PDF test.txt"
The CUPS-PDF app saves all output to /Users/Shared/CUPS-PDF. I am not sure if you can change that path but you could retrieve the file in your script and move it.
纸杯- pdf应用程序保存所有输出到/用户/共享/纸杯- pdf。我不确定是否可以更改该路径,但是可以在脚本中检索文件并移动它。
There are a few caveats though.
不过,也有一些需要注意的地方。
First, the lp command cannot print .doc files. I think there are some other third party apps which will allow you to do this though.
首先,lp命令不能打印.doc文件。我认为还有其他第三方应用可以让你做到这一点。
Second, the CUPS-PDF app shows in the Printer pane of System Preferences as having the hyphen in its name but CUPS shows the queue name as having an underscore. So, on the command line you need to refer to the CUPS queue name which is CUPS_PDF with an underscore.
其次,CUPS- pdf应用程序在System Preferences的打印窗格中显示为在名称中使用连字符,而CUPS将队列名称显示为带有下划线。因此,在命令行中,您需要引用CUPS队列名称,它是带有下划线的CUPS_PDF。
Even if you don't find it very useful to build a script via the lp command and still want to involve GUI scripting then having a virtual printer should save you some steps.
即使您不觉得通过lp命令构建脚本非常有用,并且仍然希望包含GUI脚本,那么使用虚拟打印机应该会为您节省一些步骤。
#3
1
you could use cups like this
你可以用这样的杯子
on open afile
set filename to name of (info for afile)
tell application "Finder"
set filepath to (container of (afile as alias)) as alias
end tell
set filepath to quoted form of POSIX path of filepath
set tid to AppleScript's text item delimiters
set AppleScript's text item delimiters to "."
set filename to text item 1 of filename
set AppleScript's text item delimiters to tid
set afile to quoted form of POSIX path of afile
do shell script "cupsfilter " & afile & " > " & filepath & filename & ".pdf"
end open
#4
1
I have created an alias in bash for this:
我在bash中创建了一个别名:
convert2pdf() {
/System/Library/Printers/Libraries/convert -f "$1" -o "$2" -j "application/pdf"
}
#5
0
I typed up the code below with the assistance of Automator (recording an action, and then dragging the specific action out of the "Watch Me Do" window in order to get the Applescript). If you want to print a PDF from an application other than Safari, you might have to run through the same process and tweak this Applescript around the Print dialogue, since each program might have a different Print GUI.
我在Automator的帮助下键入下面的代码(记录一个动作,然后从“Watch Me Do”窗口中拖出特定的动作以获得Applescript)。如果您想从Safari以外的应用程序打印PDF,您可能需要运行相同的过程,并围绕打印对话框调整这个Applescript,因为每个程序可能有不同的打印GUI。
# Convert the current Safari window to a PDF
# by Sebastain Gallese
# props to the following for helping me get frontmost window
# http://*.com/questions/480866/get-the-title-of-the-current-active-window- document-in-mac-os-x
global window_name
# This script works with Safari, you might have
# to tweak it to work with other applications
set myApplication to "Safari"
# You can name the PDF whatever you want
# Just make sure to delete it or move it or rename it
# Before running the script again
set myPDFName to "mynewpdfile"
tell application myApplication
activate
if the (count of windows) is not 0 then
set window_name to name of front window
end if
end tell
set timeoutSeconds to 2.0
set uiScript to "keystroke \"p\" using command down"
my doWithTimeout(uiScript, timeoutSeconds)
set uiScript to "click menu button \"PDF\" of sheet 1 of window \"" & window_name & "\" of application process \"" & myApplication & "\""
my doWithTimeout(uiScript, timeoutSeconds)
set uiScript to "click menu item 2 of menu 1 of menu button \"PDF\" of sheet 1 of window \"" & window_name & "\" of application process \"" & myApplication & "\""
my doWithTimeout(uiScript, timeoutSeconds)
set uiScript to "keystroke \"" & myPDFName & "\""
my doWithTimeout(uiScript, timeoutSeconds)
set uiScript to "keystroke return"
my doWithTimeout(uiScript, timeoutSeconds)
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
#1
6
I think you could use applescript to open a document and then use applescript UI scripting to invoke print menu.
我认为您可以使用applescript打开文档,然后使用applescript UI脚本调用print菜单。
For example :
例如:
tell application "System Events"
tell window of process "Safari"
set foremost to true
keystroke "p" using {command down}
delay 3
click menu button "PDF" of sheet 2
click menu item "Save as PDF…" of menu 1 of menu button "PDF" of sheet 2
keystroke "my_test.file"
keystroke return
delay 10
end tell
end tell
#2
2
Take a look at a program called CUPS-PDF
看看一个叫CUPS-PDF的程序。
It is a virtual printer for OS X which does what the "Save As PDF" method does when print through your normal printer except every print job passed through it results in a pdf output.
它是OS X的一个虚拟打印机,它的功能与“保存为PDF”方法在普通打印机上打印时所做的功能是一样的,除了通过它传递的每个打印作业都会产生PDF输出。
Once you install it then you could create shell or AppleScripts using the lp command.
安装之后,可以使用lp命令创建shell或applesscript。
For example, once the virtual printer is setup you could print test.txt and have it automatically save as a pdf. To do this using an AppleScript you would use the following code:
例如,一旦建立了虚拟打印机,就可以打印测试。并自动保存为pdf格式。要使用AppleScript处理,您需要使用以下代码:
do shell script "lp -d CUPS_PDF test.txt"
The CUPS-PDF app saves all output to /Users/Shared/CUPS-PDF. I am not sure if you can change that path but you could retrieve the file in your script and move it.
纸杯- pdf应用程序保存所有输出到/用户/共享/纸杯- pdf。我不确定是否可以更改该路径,但是可以在脚本中检索文件并移动它。
There are a few caveats though.
不过,也有一些需要注意的地方。
First, the lp command cannot print .doc files. I think there are some other third party apps which will allow you to do this though.
首先,lp命令不能打印.doc文件。我认为还有其他第三方应用可以让你做到这一点。
Second, the CUPS-PDF app shows in the Printer pane of System Preferences as having the hyphen in its name but CUPS shows the queue name as having an underscore. So, on the command line you need to refer to the CUPS queue name which is CUPS_PDF with an underscore.
其次,CUPS- pdf应用程序在System Preferences的打印窗格中显示为在名称中使用连字符,而CUPS将队列名称显示为带有下划线。因此,在命令行中,您需要引用CUPS队列名称,它是带有下划线的CUPS_PDF。
Even if you don't find it very useful to build a script via the lp command and still want to involve GUI scripting then having a virtual printer should save you some steps.
即使您不觉得通过lp命令构建脚本非常有用,并且仍然希望包含GUI脚本,那么使用虚拟打印机应该会为您节省一些步骤。
#3
1
you could use cups like this
你可以用这样的杯子
on open afile
set filename to name of (info for afile)
tell application "Finder"
set filepath to (container of (afile as alias)) as alias
end tell
set filepath to quoted form of POSIX path of filepath
set tid to AppleScript's text item delimiters
set AppleScript's text item delimiters to "."
set filename to text item 1 of filename
set AppleScript's text item delimiters to tid
set afile to quoted form of POSIX path of afile
do shell script "cupsfilter " & afile & " > " & filepath & filename & ".pdf"
end open
#4
1
I have created an alias in bash for this:
我在bash中创建了一个别名:
convert2pdf() {
/System/Library/Printers/Libraries/convert -f "$1" -o "$2" -j "application/pdf"
}
#5
0
I typed up the code below with the assistance of Automator (recording an action, and then dragging the specific action out of the "Watch Me Do" window in order to get the Applescript). If you want to print a PDF from an application other than Safari, you might have to run through the same process and tweak this Applescript around the Print dialogue, since each program might have a different Print GUI.
我在Automator的帮助下键入下面的代码(记录一个动作,然后从“Watch Me Do”窗口中拖出特定的动作以获得Applescript)。如果您想从Safari以外的应用程序打印PDF,您可能需要运行相同的过程,并围绕打印对话框调整这个Applescript,因为每个程序可能有不同的打印GUI。
# Convert the current Safari window to a PDF
# by Sebastain Gallese
# props to the following for helping me get frontmost window
# http://*.com/questions/480866/get-the-title-of-the-current-active-window- document-in-mac-os-x
global window_name
# This script works with Safari, you might have
# to tweak it to work with other applications
set myApplication to "Safari"
# You can name the PDF whatever you want
# Just make sure to delete it or move it or rename it
# Before running the script again
set myPDFName to "mynewpdfile"
tell application myApplication
activate
if the (count of windows) is not 0 then
set window_name to name of front window
end if
end tell
set timeoutSeconds to 2.0
set uiScript to "keystroke \"p\" using command down"
my doWithTimeout(uiScript, timeoutSeconds)
set uiScript to "click menu button \"PDF\" of sheet 1 of window \"" & window_name & "\" of application process \"" & myApplication & "\""
my doWithTimeout(uiScript, timeoutSeconds)
set uiScript to "click menu item 2 of menu 1 of menu button \"PDF\" of sheet 1 of window \"" & window_name & "\" of application process \"" & myApplication & "\""
my doWithTimeout(uiScript, timeoutSeconds)
set uiScript to "keystroke \"" & myPDFName & "\""
my doWithTimeout(uiScript, timeoutSeconds)
set uiScript to "keystroke return"
my doWithTimeout(uiScript, timeoutSeconds)
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