GulpとGraphicsMagickでPDFを差分比較する。マルチページ・マルチファイル対応

# gulpとGraphicsMagickによるPDFの差分比較

DTPの校正を重ねる過程でしでかすと怒られるのが、「修正指示されていない部分で意図しない変更が発生してしまう」こと。特に大量のデータの入ったカタログのようなものを作る際、こちら側の作業ミスで大事な部分に間違い(たとえば電話番号や商品の価格など)のあるデータを入稿して何万部も刷ってしまうと、損害賠償問題にも発展してしまうかもしれない…。

意図しない変更が起こっていないかをチェックするには、修正を行う度に、古いバージョンと新しいバージョンで機械的な差分チェックをするのが一番だと思う。

![diff.png](https://qiita-image-store.s3.amazonaws.com/0/48238/6311cdcc-48dc-5140-c7b7-016dee26cad9.png)

## やりたいこと

* 前のバージョンのPDFと新しいバージョンのPDFを用意し、画像の差分比較をしたい
* PDFは複数ページで、印刷入稿を前提とした仕様になっているとする
* 一度に複数ファイルの比較をしたい
* 上記を自動処理したい
* 難しそうなので、新旧でページの入れ替えが起こっているケースには対応しなくてよいとする

## GraphicsMagickの compare コマンド

GraphicksMagickとはImageMagickに似たコマンドラインの画像変換アプリケーションだ。
これには compare というコマンドがあり、簡単に画像の差分比較が行える機能が付いている。

`gm compare -highlight-style xor -file (出力先ファイル名) (比較元1) (比較元2)`

ただし、マルチページのPDFをのまま全ページ通しで比較する機能はなさそうだったので、

* 比較元・比較先のPDFを一旦1ページごとに分解
* 分解したページを1つ1つ比較し、結果を画像に出力
* 結果を1つのPDFにまとめる

という順番で処理することにした。

## GitHub

リポジトリ: https://github.com/hokkey/image-compare
gulpfile: https://github.com/hokkey/image-compare/blob/master/gulpfile.coffee

### 動作確認環境

* OSX 10.10.5
* node.js v4.2.2
* gulp 3.9.1
* GraphicsMagick 1.3.23
* Ghostscript 9.18

最終的にGraphicsMagickを叩ければいいので実装はシェルスクリプトでもできそうだが、自分にシェルスクリプトのスキルがないのでgulpのタスクとして実装した。

※こちらの記事で@murashitasさんがシェルスクリプト版を作成していました!
[GraphicsMagickでPDFを差分比較（シェルスクリプト版） - Qiita](http://qiita.com/murashitas/items/79efe25d8c52f051f968)

## 事前準備

* homebrew, nodejs, homebrew, gulpを事前にインストールしておく
* graphicsmagickとghostscriptをインストールし、git cloneしてnpm installする

```
brew update && brew install graphicsmagick ghostscript
git clone https://github.com/hokkey/image-compare.git
cd image-compare
npm install
```

## 使い方

```
image-compare/
├── _old/
├── _new/
├── package.json
└── gulpfile.coffee
```

1. `_old/` ディレクトリへ比較元のPDFデータを入れる
2. `_new/` ディレクトリへ比較先のPDFデータを入れる
3. 新旧のPDFは **必ずファイル名が完全に一致** しているようにする。複数ファイルをまとめて入れても良い
4. gulpfile.coffee と同じ階層上で `gulp` を実行
5. _diff.pdf に差分が出力される

差分があった場合、_diff.pdfは下図のようになる。

![dest.png](https://qiita-image-store.s3.amazonaws.com/0/48238/803dcd3f-c646-5d58-24d9-a736fa28ca1d.png)

なお、gulpfile.coffee内にある`gm.compareStyle`の文字列を変えると、差分の表現を変えることができる。

![options.png](https://qiita-image-store.s3.amazonaws.com/0/48238/1401e58e-b20b-f7e6-c97b-da74351e86e3.png)

### やってること

1. `_old` 以下のPDFをすべて分解し、不可視階層 `.temp_old/` 以下に保存
2. `_new/` 以下のPDFをすべて分解し、不可視階層 `.temp_new/` 以下に保存
3. `.temp_old, .temp_new` 以下のファイルを順番に `gm compare` し、結果を `.temp_out/` 以下に保存
4. 各不可視フォルダ内のPDFをすべて結合して保存する

### 注意点

* _new.pdf, _old.pdf, _diff.pdfは、コマンドを実行する度に上書きされる
* 不可視フォルダ内のゴミは、gulpを行う度に削除される
* 不可視フォルダ内のゴミ削除は `gulp clean` コマンドでも可能
* 比較だけをやり直したい場合は `gulp compare` コマンドを実行する

## 感想

最初はImageMagickを使おうと思ったが、GraphicsMagickというライブラリの方が新しいものらしく、処理も高速だった。
また、今回はDTP用途を意図しているが、Web制作にも応用できるかもしれない。(PhantomJSでスクショを撮らせ、GraphicsMagickに比較させるとか)

## 今後の発展?

* 差分があるページだけを_diff.pdfにまとめられるオプションを追加する
* 結果を上書きせずに日付でフォルダに保存するようにする
* ElectronとかでGUIアプリ化してみたいな…
* [PhantomJS と CasperJS で複数ページを一括キャプチャする ｜ Tips Note](http://www.tam-tam.co.jp/tipsnote/javascript/post8686.html)にあるCasperJSと組み合わせて、Webデザインのデグレ抑止に使えたらいいな…
* DTP制作にCIっぽい考え方を取り入れられないかな…

# 参考：試してみた他の方法

PhotoshopやAcrobatでも差分の比較は可能だが、今回のような自動処理の構築はうまくいかなかった。参考までに以下へ記載する。

## AdobePhotoshopでの「差の絶対値」

Photoshopで「差の絶対値」を使って2枚の画像を重ねるという古典的な方法。
これはアクション化すればある程度自動化が見こめそうに思えたが、残念ながら上手く作れなかった。
もしかすると、JavaScriptを使えばできるのかもしれない。

[イトウ先生のTips note【Photoshop CS6 EXTENDED】2つの画像の違いを調べる、差の絶対値　−株式会社ボーンデジタル ブログ](http://www.wgn.co.jp/store/blog/item-1281.html)

## AdobeAcrobatProの「文書を比較…」

![acrobat.png](https://qiita-image-store.s3.amazonaws.com/0/48238/07026f49-cdd9-536c-abcf-062604f24e48.png)

AcrobatProには「文書を比較」というコマンドがある。Acrobatはある程度のマクロ機能や、JavaScriptAPIを使ったスクリプティングが可能になっているが、この「文書を比較」コマンドはそのどちらからも使用できない。本気でプラグイン開発をすれば可能かもしれないが、流石にそこまでやる気にはなれなかった。