TeX Alchemist Online

TeX のこと,フォントのこと,Mac のこと

macOS 12.3 以降の環境でコマンドラインからPDFのページ数をカウントする

macOS のコマンドラインからPDFのページ数をカウントするには Python (PyObjC) が最も汎用的だった

かつて,コマンドラインからPDFのページ数をカウントする方法を色々模索しました。

doratex.hatenablog.jp

このとき,結論としては「Python (PyObjC) を使う」という方法が最も汎用的(あらゆる macOS 環境下で追加ツールをインストールせず実行できる)という結果になりました。

macOS Monterey 12.3 で Python が削除された!

しかし,WWDC 2019Xcode 11 Beta の Release Notes で予告されていたように,macOS 12.3 でとうとう Python が macOS 標準ツールから削除されてしまい,「macOS ならばどの環境でも Python が使える」という仮定は崩れてしまいました。

この件については,次の記事でも述べたとおりです。

doratex.hatenablog.jp

これに伴い,「Python (PyObjC)を使ってPDFのページ数カウントを行う」というのは,可搬性のある方法とは言えなくなりました。

Python (PyObjC) から AppleScriptObjC へ

そこで,今後 Python (PyObjC) に代わり可搬性のある手段の地位を確立しうるのが,AppleScriptObjC です。AppleScriptObjC は,OS X 10.10 Yosemite から導入された,AppleScript の中から Objective-C のクラスを呼び出すブリッジです。

前回の記事でも,番外編として AppleScriptObjC を使う方法を紹介していました。これを,コマンドラインから使えるようにしてみましょう。

前回の記事の番外編で紹介したAppleScriptObjCのソースはこちらでした。

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

--- 与えられたPDFのページ数を返すハンドラ pdfPageCount
on pdfPageCount(aPDF)
    set aPath to POSIX path of aPDF
    set aURL to current application's NSURL's fileURLWithPath:aPath
    set aDoc to current application's PDFDocument's alloc's initWithURL:aURL
    aDoc's pageCount()
end pdfPageCount

--- テスト:ダイアログで選択したPDFファイルのページ数を表示する
set pdf to choose file of type {"com.adobe.pdf"}
set pages to my pdfPageCount(pdf)
display dialog ("Pages: " & pages) buttons {"OK"}

これをコマンドラインから呼び出すのにふさわしい形に変形していきましょう。

まず,ワンライナー化しやすくするため,行数を切り詰めます。

use framework "Quartz"
(current application's PDFDocument's alloc's initWithURL:(current application's NSURL's fileURLWithPath:"<<PATH>>"))'s pageCount()

ここの <<PATH>> のところにシェルからファイルの絶対POSIXパスを代入する想定です。ただし,macOS 標準では realpath コマンドがインストールされていないので,Stack Exchange の記事 に従い,汎用的に使える realpath 関数をシェル関数として用意しておきます。

#!/bin/bash
function realpath () {
  f=$@;
  if [ -d "$f" ]; then
    base="";
    dir="$f";
  else
    base="/$(basename "$f")";
    dir=$(dirname "$f");
  fi;
  dir=$(cd "$dir" && /bin/pwd);
  echo "$dir$base"
}

function pdfPageCount () {
  ABSPATH="$(realpath $1)"
  /usr/bin/osascript -e 'use framework "Quartz"' -e "(current application's PDFDocument's alloc's initWithURL:(current application's NSURL's fileURLWithPath:\"$ABSPATH\"))'s pageCount()"
}

このシェル関数が定義された下であれば,

$ pdfPageCount ../"ho ge".pdf
100

のように,コマンドラインからPDFのページ数を取得できます。

このように,Python (PyObjC) がなくなった今となっては,AppleScriptObjCを使ってmacOSのAPIを呼び出す方法は,macOS がインストールされたあらゆる環境下で動作させられる方法として貴重な手段となります。