JavascriptでPDFを操作してみた

### はじめに
こんにちは。建築関係の仕事をしている普通のサラリーマンです。
仕事上、Acrobatを使用してPDF形式の図面や文書を装飾する機会が多いのですが、
もっと楽に成果物を作成できないかとググったところ、Javascriptで注釈等を操作できることを知り、
頑張って色々作ってみました。
今回は今まで作成したコードを公開します。少しでも誰かの役にたてば幸いです。

### デバッガを表示させる
まずはJavascriptを実行できる画面を表示させます。
ここではAdobe Acrobat起動時に表示させる方法を紹介します。

1.メモ帳を開き、以下のコードを書き込みます。

```javascript
console.show();
```

2.1のデータをデスクトップに保存します。
　　保存名はなんでもいいですが、拡張子は「.js」にしてください。
　　ここでは例として、「後で削除.js」とでもしておきましょう。

3.Acrobatが入っているフォルダに移動します。
　　　Acrobat 2017 Standardの場合：
　　　　　C:\Program Files　(x86)\Adobe\Acrobat 2017\Acrobat\Javascripts
　　　Acrobat Readerの場合：
　　　Acrobat Proの場合：
　　　　　
4.2で作成したファイルをD&Dで格納します。警告画面が出ますが、気にせず格納してください。

5.Acrobatを一度閉じたあと、再起動してみてください。デバッガ画面が表示されるはずです。
  表示されない場合は、一度画面を最小化後、再度最大化すると表示されます。
<img width="357" alt="デバッガー画面.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285784/d557a13a-591b-6ab8-d219-13e68cd930e6.png">


これで前準備は完了です。
この設定では毎回Adobe　Acrobatを起動するたびにデバッガ画面が表示されるようになるため、
不要になったら、３に格納した「後で削除.js」を削除してください。

### チートコード集
やっとここからがコード集となります。先程表示したデバッガ画面に、実行したいコードをコピーし、デバッガに貼り付けたコード全体をCtrl+A等で選択後、Ctrl+Enterでコードを実行できます。

#### ページサイズを取得するコード
PDFの文書サイズがA4かA3かを判定する場合などに使用しています。

```javascript
// ページサイズ取得
var aRect = this.getPageBox("Media");
var width = Math.round((((aRect[2] - aRect[0]) / 72) * 25.4));
var height = Math.round((((aRect[1] - aRect[3]) / 72) * 25.4));
console.println("width = " + width ", height = " + height);
```
#### 注釈テキストボックスを追加するコード
以前、試験のエビデンスとして取得した画面キャプチャに、
テスト項目番号等の情報を付加したい、という依頼があったのですが、
対象が１０００ページを超えていて、且つ時間もあまりない、というピンチを救ってもらったコードです。

```javascript
this.syncAnnotScan();

// 注釈に表示する文字の設定（Excel等で追加したい文字を以下の形式で作成すると便利です。）
var arrayContents = [
    "テスト"
    , "テスト１"
    , "テスト２"
];

var d = new Date();

// 1ページごとに１つずつ注釈を作成
for(var i = 0; i < arrayContents.length; i++) {
  // 注釈内容の設定
  var spans = new Array();
  spans[0] = new Object();
  spans[0].text = arrayContents[i];
  spans[0].textStyle = "bold";      // 太文字指定
  spans[0].textColor = color.red;   // フォントの色指定
  spans[0].textSize = 18;           // 文字サイズ指定
  spans[0].alignment = "center";   // 文字表示位置指定
  spans[0].fontStyle = "italic";   // フォントスタイル指定
  spans[0].underline = true;      // アンダーライン指定
  this.addAnnot({
    page: i,
    name: "FreeTextAnnot_" + util.printd("yyyymmddHHMMss", d) + "_" + i,
    type: "FreeText",
    rect: [200, 300, 350, 300 + 3 * 12],
    richContents: spans,
    strokeColor: color.black,
    width: 0
  });
}
```

#### 注釈サイズ取得
注釈サイズを確認したい場合に使用するためのコードです。
各ページに注釈を付ける前に注釈サイズを決めたい場合などに使えます。

```javascript
this.syncAnnotScan();
var annots = this.getAnnots({
  nPage: this.pageNum,
  nSortBy: ANSB_Author,
  bReverse: true
});
var msg = "注釈%sサイズ=[%s]";
for(var i = 0; i < annots.length; i++){
  console.println(util.printf("注釈%sサイズ=[%s]", i + 1, annots[i].rect));
  console.println(util.printf("注釈%sテキスト=[%s]", i + 1, annots[i].contents));
}
```

#### テキストボックス回転
A4サイズのPDFに追加した注釈テキストボックスを、
A3サイズのPDFにコピーすると、テキストボックスが反転して文字が逆さになる場合などに使えます。

```javascript
// 表示している頁の注釈テキストボックスをすべて回転したい場合
var kaiten = 180;    // 角度は0,90,180,270から指定可能です。
this.syncAnnotScan();
var annots = this.getAnnots({
  nPage: this.numPages - 1,
  nSortBy: ANSB_Author,
  bReverse: false
});

if(annots){
  for(var i = 0;i < annots.length; i++){
    if(annots[i].type == "FreeText"){
      annots[i].rotate = kaiten;
    }
  }
}

// --------------------------------------------
// 選択したテキストボックスのみ回転したい場合
var kaiten = 180;
this.syncAnnotScan();
var annots = this.selectedAnnots;
if(annots){
  for(var i = 0;i < annots.length; i++){
    if(annots[i].type == "FreeText"){
      annots[i].rotate = kaiten;
    }
  }
}
```

#### ドキュメントサイズ縮小
PDFの資料が、規定のサイズ（A3・A4等の、プリンターで印刷できるサイズ）に比べて少しだけ大きいサイズになっている場合に、縮小するためのコードです。私が印刷したかったのはA3とA4が混在している資料だったので、プリンタの設定だけではうまくいかないと思い、やむなく作成しました。
注）サイズ縮小は拡大率ではなくトリミングで小さくするため、A3をA4のように大幅に縮小しようとすると、一部しか残らないので使わないほうがいいです。

```javascript
// 全頁サイズを整数値の最大値に縮小
var last = this.getPrintParams().lastPage;
for(var i = 0; i < last + 1; i++){
  var McropBox = this.getPageBox("Media", i);
  var elm0 = Math.floor(McropBox[0]);
  var elm1 = Math.floor(McropBox[1]);
  var elm2 = Math.floor(McropBox[2]);
  var elm3 = Math.floor(McropBox[3]);
  this.setPageBoxes("Media", i, i, [elm0, elm1, elm2, elm3];
}
```
#### PDFページの並べ替え
wordで作成した建築確認用チェックリスト（100枚以上）の順番が入れ替わることになってしまい、いちいちwordの順番を変えるのが面倒だったので、PDFに変換後、求める順番に並び替えをするために作成しました。
ほかにも、2つ以上あるPDFデータを一つのPDFに結合したい時などにも応用できます。

```javascript
// 例）2ページ目のPDFを、0.pdfとして、1ページ目のPDFを、1.pdfとして出力する
// 出力されたデータを再度結合すると並び替え完了
var array1 = [2, 1];
try
{
  for (var i = 0; i < array1.length; i++)
    this.extractPages({
      nStart: array1[i] - 1,
      cPath: "/c/work/" + i +".pdf"
    });
}
catch (e) { console.println("Aborted: " + e) }
```

### 参照リンク
- API　Reference
Adobeの公式ドキュメントです。日本語サイトが404になっていたので、英語版のみ。
https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/js_api_reference.pdf

- PDF
Excel VBAからPDFを操作したい場合によく参照させて頂いています。
（acrobatだとセキュリティ的にできない、クリップボード貼り付けの自動化等）
http://pdf-file.nnn2.com/