如何使用本机macOS工具以编程方式旋转PDF中的所有页面?

时间:2017-10-19 23:10:09

标签: macos pdf applescript

给定文件路径,我需要使用macOS中未包含的任何内容在该文件路径中旋转PDF中的所有页面。这个包装器将是AppleScript,因此我也可以访问命令行,因此默认情况下使用macOS安装所有脚本语言,但不需要brew或者只需要Python {{1} }。

5 个答案:

答案 0 :(得分:4)

可以使用标准预览应用程序执行PDF页面旋转。

打开PDF文档后,点击1或2次Tab键(取决于您的预览版本),以选择带有'cmd a'的侧栏上的所有页面。 然后按“cmd R”(或L)向右(或向左)旋转所有选定页面90%,最后点击“cmd w”关闭窗口。 预览将默认要求保存更改,然后只需按Enter键进行保存。

您可以使用System Events中的Keystroke指令在Applescript中模拟所有这些键。

要将此子例程用于许多PDF文件,您有2个解决方案,仍在Applescript中:

1)选择一个文件夹并循环浏览该文件夹的所有PDF文件以应用此子程序。

2)在“Finder”中选择您的文件,您的脚本将直接采用所有Finder选择的文件来应用相同的子程序。

这样的GUI脚本并不完美,但不可预测的是不能编写脚本...... -

答案 1 :(得分:1)

据我所知 macOS 没有任何一个本机命令行Unix可执行文件,它可以旋转所有页面 PDF < / strong>(同时保持基于文本的文本)。 sip可以旋转单个页面 PDF ,但生成的 PDF 封装的图片,而不是文本如果它是文本基础开始。另外,不确定是否只有普通 AppleScript 的方法,然后通过 UI脚本 默认 < strong>预览应用程序,无需转到 AppleScriptObjC Cocoa-AppleScript )和 Python 等。

使用第三方命令行实用程序可能是最简单的,但您说它必须仅使用默认部分 MACOS 即可。因此,我将提供 AppleScript 解决方案,该解决方案使用 UI脚本 默认 预览应用程序,用于 AppleScriptObjC 或没有第三方实用程序等的另一种方式。

此解决方案(提供(和编码))假定预览 PDF 文档的默认应用程序,并将其用于旋转 PDF 文档中的所有页面。它还设置为 Automator 工作流程。 (尽管还有其他方法可以合并下面显示的AppleScript 代码。)

首先,在 Finder 中,制作目标 PDF 文档的副本,然后使用这些文档。

Automator 中,创建新的工作流文档,添加以下操作

  • 获取指定的Finder项
    • 将复制的目标 PDF 文档添加到此操作
  • 运行AppleScript脚本
    • 使用下面的代码替换 默认代码

AppleScript 代码

on run {input}
    set thisLong to 0.25 -- # The value of 'thisLong' is decimal seconds delay between keystrokes, adjust as necessary.
    set theRotation to "r" -- # Valid values are 'l' or 'r' for Rotate Left or Rotate Right.
    set theViewMenuCheckedList to {}
    set theMenuItemChecked to missing value
    repeat with thisItem in input
        tell application "Finder" to open file thisItem -- # By default, in this use case, the PDF file will open in Preview.
        delay 1 --  # Adjust as necessary. This is the only 'delay' not defined by the value of 'thisLong'.
        tell application "System Events"
            perform action "AXRaise" of window 1 of application process "Preview" -- # Just to make sure 'window 1' is front-most.
            delay thisLong
            --  # Ascertain which of the first six 'View' menu items is checked.
            set theViewMenuCheckedList to (value of attribute "AXMenuItemMarkChar" of menu items 1 thru 6 of menu 1 of menu bar item 5 of menu bar 1 of application process "Preview")
            repeat with i from 1 to 6
                if item i in theViewMenuCheckedList is not missing value then
                    set theMenuItemChecked to i as integer
                    exit repeat
                end if
            end repeat
            --  # Process keystrokes based on which 'View' menu item is checked.
            --  # This is being done so the subsequent keystroke ⌘A 'Select All' 
            --  # occurs on the 'Thumbnails', not the body of the document.
            if theMenuItemChecked is not 2 then
                repeat with thisKey in {"2", "1", "2"}
                    keystroke thisKey using {option down, command down}
                    delay thisLong
                end repeat
            else
                repeat with thisKey in {"1", "2"}
                    keystroke thisKey using {option down, command down}
                    delay thisLong
                end repeat
            end if
            repeat with thisKey in {"a", theRotation as text, "s"} -- # {Select All, Rotate Direction, Save}
                keystroke thisKey using {command down}
                delay thisLong
            end repeat
            keystroke theMenuItemChecked as text using {option down, command down} -- # Resets the 'View' menu to the original view.
            delay thisLong
            keystroke "w" using {command down} -- # Close Window.
        end tell
    end repeat
end run

备注:

  • 由于此脚本使用 UI脚本,从 Automator (或脚本编辑器)运行时,正在运行应用必须添加到系统偏好设置&gt; 安全性&amp; 隐私&gt; 辅助功能,以便正确运行。保存为应用程序,需要添加已保存的应用程序。
  • 使用 UI脚本时,可能需要更改delay 命令的值才能在您的系统上使用(和/或{{1}尽管添加了delay 命令,但命令已添加到适当的位置。不言而喻,首先要对一组文档进行测试,以确保delay的值设置在您的系统上。在我的系统上,这就像编码一样。
  • 以这种方式使用 UI脚本时,一旦任务启动,必须​​让系统独立并让它完成处理文件。尝试多任务只会使焦点远离手头的任务并导致其失败。
  • 如果您需要旋转多次,请将其他thisLong添加到:

    theRotation as text,

    示例:

      repeat with thisKey in {"a", theRotation as text, "s"} -- # {Select All, Rotate Direction, Save}
    

答案 2 :(得分:1)

您可以使用 Cocoa-AppleScript PDFPage 的方法。

查看https://developer.apple.com/documentation/pdfkit/pdfdocument?language=objchttps://developer.apple.com/documentation/pdfkit/pdfpage?language=objc

这是脚本:

use scripting additions
use framework "Foundation"

set thisPath to POSIX path of (choose file of type {"pdf"} with prompt "Choose a PDF") --  a POSIX path, not an alias or an HFSPath
set thisDoc to current application's PDFDocument's alloc()'s initWithURL:(current application's NSURL's fileURLWithPath:thisPath)

set pCount to thisDoc's pageCount()
repeat with i from 0 to (pCount - 1)
    ((thisDoc's pageAtIndex:i)'s setRotation:90) -- rotate to 90,  the rotation must be a positive or negative multiple of 90: (0, 90, 180, 270 or -90 -180 -270)
end repeat
thisDoc's writeToFile:thisPath -- save --

注意:如果页面旋转 0 (无旋转),此脚本将正常工作,否则您必须获取页面的旋转并进行计算。

以下是向右或向左旋转页面的示例:

use scripting additions
use framework "Foundation"

set thisPath to POSIX path of (choose file of type {"pdf"} with prompt "Choose a PDF") --  a POSIX path, not an alias or an HFSPath
my rotatePages(thisPath, 90) -- rotate right , use -90 to rotate left

on rotatePages(thisPath, r)
    set thisDoc to current application's PDFDocument's alloc()'s initWithURL:(current application's NSURL's fileURLWithPath:thisPath)
    set pCount to thisDoc's pageCount()
    repeat with i from 0 to (pCount - 1)
        set thisPage to (thisDoc's pageAtIndex:i)
        (thisPage's setRotation:((thisPage's |rotation|()) + r)) -- add 90 to the current rotation, note: at 360, the value of the rotation will be set to 0, not to 360
    end repeat
    thisDoc's writeToFile:thisPath -- save --
end rotatePages

答案 3 :(得分:0)

这是我使用的解决方案。

  • Automator将PDF分离到与原始PDF相同级别的新文件夹中的各个页面
  • 某些AppleScript使用图像事件
  • 旋转单页PDF
  • 第二个Automator工作流程,将单独的PDF重新拼接在一起
  • AppleScript控制所有内容,根据需要使用do shell scriptopen每个Automator工作流程。

答案 4 :(得分:0)

MacOS自带了python,您可以在Automator (运行shell脚本 - 设置为python,将输入作为参数传递)中使用它来创建一个可以在Finder中处理PDF的服务。

#!/usr/bin/python
# coding=utf-8
import sys
import os
from Quartz import PDFDocument
from CoreFoundation import NSURL

if __name__ == '__main__':

    for filename in sys.argv[1:]:
        filename = filename.decode('utf-8')
        shortName = os.path.splitext(filename)[0]
        pdfURL = NSURL.fileURLWithPath_(filename)
        pdfDoc = PDFDocument.alloc().initWithURL_(pdfURL)
        pages = pdfDoc.pageCount()
        for p in range(0, pages):
            page = pdfDoc.pageAtIndex_(p)
            existingRotation = page.rotation()
            newRotation = existingRotation + 90
            page.setRotation_(newRotation)

        pdfDoc.writeToFile_(filename)

您可以在this GitHub site

找到大量类似的脚本和Automator工作流程