【追記】この記事を macOS 12.3 以降の環境に対応させた記事を書きました。 doratex.hatenablog.jp
id:acetaminophen さんが,Windows環境でPDFのページ数をカウントするバッチファイルを,様々な手法で実装する試みをなされています。
そこで,Mac環境についても,コマンドラインからPDFのページ数をカウントする様々な手法をまとめておこうと思います。
目次
- 1. Spotlight 検索インデックスのメタデータを利用する(信頼性:低)
- 2. RubyCocoa を利用する(10.5 Leopard 〜 10.9 Mavericks)
- 3. pdfinfo を使う(要pdfinfo)
- 4. QPDF を使う(要QPDF)
- 5. Ghostscript を使う(要Ghostscript)
- 6. exctractbb を使う(要TeX環境)
- 7. pdfTeX を使う(要TeX環境,ネタ)
- 8. Swift を使う(要Xcode Command Line Tools,遅い)
- 9. Python (PyObjC) を使う(最も汎用的)
- 結論:決定版は Python!
- AppleScript から PyObjC を利用する
- 番外編:AppleScriptObjC を利用する(10.10 Yosemite ~)
1. Spotlight 検索インデックスのメタデータを利用する(信頼性:低)
Mac環境でのPDFページ数カウントの方法として,よくこの手法が紹介されているのを見かけます。Spotlight 検索用のメタデータに保存されているページ数の情報を取り出すという手法です。
$ mdls "hoge.pdf" | grep kMDItemNumberOfPages | awk '{print $3}'
ただし,この方法は,
- CD-ROM 内や,ユーザがシステム環境設定でSpotlight検索から除外している場所など,Spotlightのインデックス作成対象でない場所にあるPDFに対しては使えない。
- Spotlight のメタデータが壊れている場合もあり,正しい結果が返ってくるとは限らない。
といった欠点があり,あまり信頼できる方法ではありません。
2. RubyCocoa を利用する(10.5 Leopard 〜 10.9 Mavericks)
OS X 10.5 Leopard 〜 10.9 Mavericks には,RubyからCocoaを利用するブリッジである RubyCocoa が標準添付されていました。これを利用すれば,ワンライナーRubyスクリプトから Cocoa / Quartz の機能を呼び出し,PDFのページ数を次のようにカウントすることが可能でした。
$ ruby -e 'require "osx/cocoa";include OSX;require_framework "Quartz";puts PDFDocument.alloc.initWithURL(NSURL.fileURLWithPath("hoge.pdf")).pageCount'
OS X 10.9 Mavericks では,Ruby 2.0 が標準になったものの,Ruby 1.8 も同梱されていますので,次のように Ruby 1.8 の絶対パスを指定すれば動きます。
$ /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -e 'require "osx/cocoa";include OSX;require_framework "Quartz";puts PDFDocument.alloc.initWithURL(NSURL.fileURLWithPath("hoge.pdf")).pageCount'
しかし,OS X 10.10 Yosemite からは,とうとう Ruby 1.8 が削除されて Ruby 2.0 に一本化された影響により,RubyCocoa も標準添付されなくなりました。よって現在ではこの方法は標準では使えなくなっています。 Yosemite の Ruby 2.0 に対応した RubyCocoa の新版 がリリースされているようですので,各自がそれをインストールすれば再びこの手法が使えるようになるでしょう。 しかし,気軽に使える方法ではなくなってしまいましたので,別の手法を探します。
3. pdfinfo を使う(要pdfinfo)
Xpdf や Poppler の付属ツールである pdfinfo を使えば,その出力からPDFのページ数が得られます。
$ pdfinfo hoge.pdf | grep '^Pages: ' | awk '{print $2}'
pdfinfo は各自でインストールする必要があります。例えば MacPorts ならば,次のようにしてインストールできます。
$ sudo port install xpdf-tools
4. QPDF を使う(要QPDF)
QPDF をインストールしておけば,それを利用してPDFのページ数カウントができます。
$ qpdf --show-npages hoge.pdf
QPDFも MacPorts で簡単にインストールできます。
$ sudo port install qpdf
5. Ghostscript を使う(要Ghostscript)
Ghostscript が利用可能な環境であれば,Ghostscriptでページ数をカウントすることも可能です。
$ gs -q -dNODISPLAY -c '(hoge.pdf) (r) file runpdfbegin pdfpagecount = quit'
6. exctractbb を使う(要TeX環境)
最近の TeX 環境(TeX Live 2014 以上)がインストールされている環境であれば,extractbb -O
の標準出力を解析することでページ数を得ることができます。
$ extractbb -O 'hoge.pdf' | grep '^%%Pages:' | cut -d' ' -f 2
7. pdfTeX を使う(要TeX環境,ネタ)
これはネタ的な方法ですが,PDFのページ数を出力させる pdfTeX 用の plain TeX ソースをその場でコンパイルする方法です。
texput.log
というログファイルが出力されるので,後でその掃除をしています。
$ echo '\pdfoutput=1\pdfximage{hoge.pdf}\message{Pages:\the\pdflastximagepages}\bye' | pdftex -draftmode | grep '^Pages:' | cut -d':' -f 2; rm texput.log
8. Swift を使う(要Xcode Command Line Tools,遅い)
Xcode Command Line Tools がインストールされている環境であれば,Swift コンパイラをワンライナー実行用に使うことで,Quartz の機能を利用してPDFページ数カウントが可能です。
$ echo 'import Quartz;print(PDFDocument(url:URL(fileURLWithPath:"hoge.pdf"))!.pageCount)' | swift | sed -e '1,1d'
ただし,Swift のコンパイルが遅いので,実行時間が長く,この方法はあまり現実的ではありません。
9. Python (PyObjC) を使う(最も汎用的)
Python から OS X のAPIにアクセスするためのブリッジである PyObjC は,OS X 10.5 Leopard 以上で標準添付されており,現在の OS X 10.10 Yosemite でも標準で利用することができます。 Python から Quartz の機能を利用することで,PDFのページ数が得られます。
$ python -c "import os;import CoreGraphics as cg;print(cg.CGPDFDocumentCreateWithProvider(cg.CGDataProviderCreateWithFilename('hoge.pdf')).getNumberOfPages())"
結論:決定版は Python!
以上9種類の手法を比較してみると,現時点で「どのMac環境でも標準で使える方法」としては,Python に軍配が上がることが分かります。
ユーザに追加インストールを強いることなく,OS X 10.5 以上の全てのMac環境で利用可能で,動作速度にも問題ありませんので,Mac環境下におけるPDFページ数カウント法の決定版と言えるでしょう。
AppleScript から PyObjC を利用する
決定版である Python を使う方法を,AppleScript から利用可能なハンドラとしてもまとめておきましょう。
--- 与えられたPDFのページ数を返すハンドラ pdfPageCount on pdfPageCount(aPDF) return (do shell script (" python -c \"import os;import CoreGraphics as cg;print(cg.CGPDFDocumentCreateWithProvider(cg.CGDataProviderCreateWithFilename('" & POSIX path of aPDF & "')).getNumberOfPages())\"")) as integer 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"}
番外編:AppleScriptObjC を利用する(10.10 Yosemite ~)
OS X 10.10 Yosemite からは,通常の AppleScript の中から Objective-C のクラスを呼び出す AppleScriptObjC が使えるようになりました。この方法を使えば,do shell script による外部コマンド呼び出しを行うことなく,AppleScript からのPDFページ数カウントが可能です。
考え方としては,Swift を使う方法 と同様に,Quartz の機能を利用して OS X の CoreGraphics API を呼び出します。
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"}