如何在OSX上编程生成任何文档的PDF?

18

我正在为OSX项目工作,其中用户可以选择一组文档(从任何应用程序),我需要从中生成PDF。标准的Macintosh打印对话框有一个PDF按钮,其中包括许多与PDF相关的命令,包括“另存为PDF...”。但是,我需要在不需要用户交互的情况下生成PDF文件。我希望这可以使用任何类型的文档。

到目前为止,我探索过的选项如下:

  • Automator动作。Automator有一个PDF库,但它提供用于处理PDF文件而不是生成PDF文件的动作。有一个Finder操作可将任何文件打印到实际打印机上,但只限于实际打印机。
  • AppleScript。某些应用程序具有生成PDF文件的功能(例如,如果您向Pages发送“save doc in“test.pdf””,它将生成PDF文件(但这仅适用于Pages - 我需要支持任何类型的文档)。
  • 自定义打印机。我可以创建虚拟打印机驱动程序,然后使用Automator操作,但我不喜欢在打印列表中添加额外的打印机会让用户感到困惑。

我的希望是,有一种方法可以与活动应用程序交互,就像用户执行以下步骤一样:

  1. 按Cmd-P(打开打印对话框)
  2. 单击“PDF”按钮
  3. 选择“另存为PDF...”(菜单中的第二项)
  4. 在保存对话框中键入文件名
  5. 单击“保存”

如果这是最好的方法(是吗?),那么真正的问题是:如何向外部应用程序发送UI事件(按键,鼠标事件,菜单选择)?

更新:仅澄清一点:我需要转换为PDF的文档是由其他应用程序创建的文档。例如,用户可以选择Word文档、Numbers电子表格、OmniGraffle图纸或Web页面。它们的共同点是每个文档都有一个关联的应用程序,该应用程序知道如何打印它(且OSX知道如何将打印输出呈现为PDF文件)。

所以,Cocoa Dev Central上的示例不起作用,因为它们是关于从我的应用程序生成PDF。

6个回答

6

我认为你可以使用AppleScript打开文档,然后使用 AppleScript UI脚本 来调用打印菜单。

例如:

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

3
如果您要在Safari中打开文件,这似乎是一个不错的方法,但我确定您不想为每个可能的应用程序编写代码。 - mcgrailm

3

请看一个名为CUPS-PDF的程序。

它是OS X的虚拟打印机,当您通过普通打印机打印时,它会执行“另存为PDF”方法,但每个传递给它的打印作业都会产生一个pdf输出。

安装后,您可以使用lp命令创建shell或AppleScripts。

例如,一旦设置了虚拟打印机,您就可以打印test.txt并自动将其保存为pdf。要使用AppleScript执行此操作,您需要使用以下代码:

do shell script "lp -d CUPS_PDF test.txt"

CUPS-PDF 应用程序将所有输出保存在 /Users/Shared/CUPS-PDF 中。我不确定您是否可以更改该路径,但您可以在脚本中检索文件并移动它。但需要注意几点:第一,lp 命令无法打印 .doc 文件。我认为有一些其他第三方应用程序可以让您这样做。其次,CUPS-PDF 应用程序在系统偏好设置的打印机窗格中显示为带有连字符的名称,但 CUPS 显示队列名称为带有下划线的名称。因此,在命令行上,您需要引用具有下划线的 CUPS 队列名称 CUPS_PDF。即使您不认为通过 lp 命令构建脚本非常有用,仍然想要涉及 GUI 脚本编写,那么拥有虚拟打印机也应该可以节省一些步骤。

1
你可以像这样使用杯子
    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

1
我已经在bash中为此创建了一个别名:
convert2pdf() {
  /System/Library/Printers/Libraries/convert -f "$1" -o "$2" -j "application/pdf"
}

1
-bash: /System/Library/Printers/Libraries/convert: 没有那个文件或目录。 - Mathias Bynens

0
我通过 Automator 的帮助(录制操作,然后将特定操作从“查看我的操作”窗口拖出以获得 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
# https://dev59.com/ynRB5IYBdhLWcg3w4bAo            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

0

"/System/Library/Printers/Libraries/./convert"在较新版本的MacOS中已被删除。

现在您可以使用sips。以下是AppleScript示例: do shell script: sips -s format pdf Filename.jpg --out Filename.pdf


那只适用于位图图像格式。 - benwiggy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接