Action Scriptを使ったら、PDFのページ並べ替え作業が劇的に短縮できる!


 Acrobatでページ並べ替えをする作業が、ActionScriptを使うと劇的に短縮できることがわかったので、ここに覚え書きしておくことにします。
 なお、当方が使用しているのは Acrobat Pro DC (2015 Release)ですが、movePageメソッドが使えるのならOK。
(チュートリアルによれば、Acrobat Pro 5.0以降でいける模様です。なお、残念ながら無料バージョンの Acrobat Reader では使えません。Action Script全般に関してそうですが)

どういうときに movePage メソッドが必要なのか

 個人的に、なぜこれが必須になったか、という例を挙げることにしましょう。
 ズバリ、「本バッサリ裁断してスキャンかけた後、本のPDFを作成するとき」です。

<自分が困ったケース>
1. 本の末尾には、必ず索引がついているものです。ところが、往々にして日本語の本では、索引の部分だけ、ページが逆順になっていることがあります。
 例えば、[索引3]→[索引2]→[索引1]→奥付→裏表紙、という順番になっているケースがあるんです。日本語の本に多いです。
 PDFにしたとき、これが見づらくて仕方ありません。
 だから、この最後の索引の部分だけ、[索引1]→[索引2]→[索引3]→奥付→裏表紙、という形に並べ替えたかったのです。

2. 両面スキャンすると、片面だけどうしても横筋が入ってしまう現象が発生しました。読み取り部分をクリーンしてみたものの、効果ナシ。
 じゃあ2ページごとに横筋が入ってるPDFで我慢できるか?と言うところなのですが。実際に見てみたら分かると思いますが、これ、ものーっすごく不愉快です。2ページごとにイライラさせられるのは必定です。

 じゃあ、どうするか。
 スキャナーを2回回します。片面だけでやれば、なぜか横筋が入らなかったのです。すぐにスキャナを新調・修理に出すという状況下になかったので、コレで凌ぐしかなかったのです。

 最初は、1ページから片面で表だけを読み取らせる。これで出来上がるのが
 1, 3, 5, 7, 9, 11, 13, … (最後-1) :奇数ページ(正順)だけからなるPDF。

 次は、裏返して最後のページから、片面で裏だけを読み取らせる。これで出来上がるのが
 (最後), (最後-2), (最後-4), … , 8, 6, 4, 2 :偶数ページ(逆順)だけからなるPDF。
 
 この2つのPDFを単純結合したら、
 1, 3, 5, 7, 9, 11, 13, … (最後-1), (最後), (最後-2), (最後-4), … , 8, 6, 4, 2 というPDFが出来上がります。
 これを、
 1, 2, 3, 4, 5, 6, 7, 8, 9, …, (最後-2), (最後-1), (最後) というふうに、普通の順番に並べ替えたかったのです。

 いろいろとネットを捜索した結果、

全てのページを逆さまにしてしまうコード
for (i = this.numPages - 1; i >= 0; i--) this.movePage(i);

 という処理を見つけました。

 Acrobat で ActionScript を実行させる方法は、[ツール]―[アクションウィザード]―[新規アクション]。
 左ペインの[その他のツール]をクリック、[Javascriptを実行]をクリックすると、右ペインに勝手に「Javascriptを実行」のメニューが追加されるはずです。
 その真ん中くらいにある「設定を指定」をクリック。
 すると、JavaScriptエディターが飛び出してきます。そこに、コードを書く。書いたらOKで閉じる。で、[保存]を押すとアクション名と説明を入力させる画面が出てきます。
 そこでOKしたら、アクションリストの一番下、カスタムコマンドという所にそのメニューがポンと追加されているはずです。

 これを実際に作動させてみると、確かに全てのPDFのページが逆になったので、ビックリしました
 ただ、この情報だけでは、自分のやらせたい処理をどう実現したら良いのか分からない・・・

 どうすればよいかわからない中、Action Script の チュートリアルにたどり着きました。これが、勝因を切り開く結果となりました。

Action Scriptのチュートリアル

JavaScript™ for Acrobat® API Reference
Adobe® Acrobat® SDK
April 2007 Version 8.1
https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/js_api_reference.pdf

ここのp.324に、movePage メソッドの説明がありました。

これがものすごく重要な情報で、つまり、文法が分かったのです。

movePage( 第1引数, 第2引数 )
 第1引数に、動かしたいページ番号を入れる。(省略した場合は最初のページ)
 第2引数に、「どのページの後に入れるか」のそのページ番号を入れる。(省略した場合は最後のページ)

 注意点は、0基準なので、ページ番号を -1 してやらなければならない、と。
 例えば Acrobatで p.10 と表示されていたら、それは ActionScript 側では p.9 として認識されている、ということですね。

ではいよいよ実装

  • PDFの特定のページ箇所だけ、順番を逆にする方法
     例えば、PDFのAcrobat表記で「654, 655, 656, 657」ページだけ「657, 656, 655, 654」にしたい、とします。
     AcrionScript側で認識している番号に [ ] を付けて表すことにします。
      1回目:[656] を [652] の後へ →「657, 654, 655, 656」
      2回目:[656] を [653] の後へ →「657, 656, 654, 655」
      3回目:[656] を [654] の後へ →「657, 656, 655, 654」

 よって、求める ActionScript は、次のようになります。

特定の範囲のページのみを逆さまにしてしまうコード
StartPage = 654; /*ここは逆にしたい(Acrobatでの)開始ページを指定*/
EndPage = 657;   /*ここは逆にしたい(Acrobatでの)終了ページを指定*/
MPN = EndPage - 1;
MoveTimes = EndPage - StartPage;
for (i = 0; i < MoveTimes; i++) this.movePage(MPN, StartPage - 2 + i);


  • 1, 3, 5,…,(最後-1),(最後),(最後-2),(最後-4),…, 8, 6, 4, 2 となっているPDFを、
    1, 2, 3, 4, 5, 6, 7, 8, 9, …, (最後-2), (最後-1), (最後) と普通に並べ替える方法

 小さい例で考えると一般化しやすいですね。
 PDFのAcrobat表記「1, 3, 5, 6, 4, 2」を「1, 2, 3, 4, 5, 6」にすると考えると、
  1回目:[5] を [0] の後へ →「1, 2, 3, 5, 6, 4」
  2回目:[5] を [2] の後へ →「1, 2, 3, 4, 5, 6」

 理解を確実にするために、もう1個増やしましょうか。
 PDFのAcrobat表記「1, 3, 5, 7, 8, 6, 4, 2」を「1, 2, 3, 4, 5, 6, 7, 8」にすると考えると、
  1回目:[7] を [0] の後へ →「1, 2, 3, 5, 7, 8, 6, 4」
  2回目:[7] を [2] の後へ →「1, 2, 3, 4, 5, 7, 8, 6」
  3回目:[7] を [4] の後へ →「1, 2, 3, 4, 5, 6, 7, 8」

 これで、構造が見えました。よって、求める ActionScript は、次のようになります。

「奇数(順)+偶数(逆)」を1から順序よく整列させるコード
MoveTimes = this.numPages / 2 - 1;
MPN = this.numPages - 1;
for (i = 0; i < MoveTimes; i++) this.movePage(MPN, 2*i);



たったこれだけで終わってしまう・・・


  • 2, 1, 4, 3, …,(最後-2),(最後-3),(最後),(最後-1) となっているPDFを、
    1, 2, 3, 4, 5, 6, 7, 8, 9, …, (最後-2), (最後-1), (最後) と普通に並べ替える方法

 これ、主に日本語の "左から開く形の和書PDFあるある" です。

 2ページ1面開きでコピーした後、何らかの仕掛けを使って、真ん中でそのPDFをブッタ切る、ということをやることがあります。この手が使えたら、コピーする手間が半分で済みますから。

 で、それで機械的にプログラムで真ん中で2つにブッタ切った時、必ず発生する形です。

 プログラムで真っ二つにブッタ切る方法は、例えば私が知ってる限りでは

 [方法1] muPDFをダウンロードして適当なフォルダに格納した後、コマンドプロンプトを呼び出して、

PDFを真っ二つに割るコマンド
mutool poster -x 2 (真ん中でブッタ切りたいPDF名).pdf (出力させたいPDFを名).pdf

と書いてポンと押してやる方法。

 [方法2]PDFの印刷のプロパティで「ポスター(2枚)」にして出力させることで、半分に分割することができます。たしか、99%とか98%にしてやらないとちゃんと半分に切れてくれなかったはずです。

 [方法3]TeXで \includepdf[angle=0, viewport=0mm 0mm 128.5mm 182mm, pages=\thepg]{\pdffn} というようにページの半分の箇所を指定して、実際はページの大きさは変わってないけど、左半分、右半分にフォーカスを移して、1ページづつになっているように見せかける、という技法

 この3つの方法、探せば必ずどこかに書いてある方法です。私、これをすべて試したのですが、この不具合は解消しなかったのです。

 なら、どうしていたのか。

 Acrobatの画面を見ながら、マウスのドラッグでいちいち偶数ページを2個前に持ってって・・・、ってのを、PDF丸ごと延々とやるしかなかったのです😂。本が800ページとかになると、400回もこの作業をやらなければいけなかったのです。・・・苦痛以外の何物でもありませんでした

 しかし、これも、いとも簡単に済んでしまうことが、判明してしまったのです。

 小さい例で考えたら構造が見やすくなります。
 PDFのAcrobat表記「2, 1, 4, 3, 6, 5」を「1, 2, 3, 4, 5, 6」にすると考えると、
  1回目:[1] を [-1] の後へ →「1, 2, 4, 3, 6, 5」
  2回目:[3] を [1] の後へ →「1, 2, 3, 4, 6, 5」
  3回目:[5] を [3] の後へ →「1, 2, 3, 4, 5, 6」

 1~6ページまでをやるとしたら、6/2=3回、開始ページから始まって、+2づつインクリメントしてやればいい、ってことですね。

 よって、求める ActionScript は、次のようになります。

指定ページ間だけ、奇数と偶数ページを逆にするスクリプト(和書・左開きの本)
StartPage = 8; /*ここは開始したい(Acrobat上の)開始ページを指定*/
EndPage = 493;   /*ここは終了したい(Acrobat上の)終了ページを指定*/
MoveTimes = ((EndPage - StartPage)+1)/2;
for (i = 0; i < MoveTimes; i++) this.movePage(StartPage+2*i, StartPage+2*(i-1));

今まで苦労していたのは、一体何だったのか・・・・




なんで、なんで、これにもっと早く気づかなかった ―――――――――――
もっと早くにAcrobatのJavascript操作という可能性に気が付き、ActionScriptにチャレンジするべきでした。多分100時間くらいムダにしていると思います

 あとがき

 少量であれば手作業でもなんとかなると思いますが、自炊PDFが大量になってくると、死ねる作業量になってきます。600ページとか800ページの本が何十冊もあると。
 Action Script があるとないでは、天地の差がついてくるでしょう。
 
 今まで、手作業でページ整列作業をやっていただけに、確信を持って、そう言えます。
 まさにAcrobat Proを使う利点に、初めて目覚めました。
 いろいろとネットを調べ回ったのですが、movePagesについて書いているドキュメントがなかったので、ここにageておくことにします。
 
 自分と同じような作業に悩んでいる人にとって、確実に作業時間を爆縮することでしょう。
 どなたかの朗報にならんことを祈りつつ。



(2020/12/16 追記)
新たなテクニックを1つ、追記しておくことにします。

指定間のページ内の、奇数のページだけを削除する方法

 deletePagesを使うと、ページ削除ができます。

指定ページ間内の、奇数のページだけを削除するスクリプト
/* 指定ページ間内の、奇数のページだけを削除するスクリプト*/
StartPage = 2; /* Acrobat上に出ている開始ページ-1(0頁スタートで考える)を指定(よって、必ず偶数)*/
EndPage = 1566; /* Acrobat上に出ている終了ページ-1(0頁スタートで考える)を指定(よって、必ず偶数)*/

MoveTimes = (EndPage - StartPage)/2;
for (i = 0; i < MoveTimes; i++) {
 deletePage = EndPage-2*i;
 this.deletePages(deletePage);
}

 注意点は、Acrobat Proで4ページ、と表示されていたら、ActionScriptの方ではそれは3ページとして認識されている、ということです。(0ページがスタートとみなされている)
 DeletePages の文法構造上、1枚1枚削除するしか方法がありませんでした。
1500ページの文書だと、15分くらいかかってしまいます。それでも、手作業に比べれば断然マシだと言えます。
 (必ず奇数)としましたが、if文つけて分岐させれば、偶数でも奇数でも対応できるようになります。メンドクサイのでしてないだけです。
 分岐バージョンは、下の参考ページの方のほうが詳しいです。



参考にしました。ありがとうございます。
・Acrobat Pro DCのスクリプトについてのメモ
https://qiita.com/tetsuya-k/items/eb37668d559ba98d22ac