macOS で自炊データを PDF 化する際の覚え書き

      macOS
この記事の所要時間 : 5 分

目次

きっかけ

特筆するほどでも無いのだが、手元の自炊データ (e.g. JPG, PNG) をスマホや Kindle で読みたかったのがきっかけだった。

もちろんやり方はいろいろあるとは思うし、自動化も普通にやればできるだろうという見通しはあったが、いちいち毎回調べながらやるのも億劫なのでまとめておくことにした。

目標

JPG や PNG 形式の自炊データを、電子書籍リーダーで読める PDF 形式に変換する。

要件の整理

スキャナーやデジカメなどを使用して書籍を自炊した場合、各ページの 画像ファイルが JPG や PNG など形式で大量に作成される。 また、特に変わったことをしなければ、それらのファイルはページの順番に応じて昇順のファイル名が振られていて、書籍毎に書籍のタイトルの付けられたディレクトリ配下にまとめられていることだろう。 やりたいこととしては、こうした大量の画像ファイルを元の書籍のページ順に並べて、一つの PDF ファイルとしたい。

上記をふまえると、変換処理を行う際に想定される入力は、書籍の画像ファイルの配置されたディレクトリへのパスであり、ディレクトリの構成は以下のようになっていると想定できる。

$ cd BookTitle      # 書籍タイトルディレクトリ
$ tree .
.
├── Page001.jpg     # 各ページの画像ファイル
├── Page002.jpg
├── Page003.jpg
.
.
├── Page198.jpg
└── Page199.jpg

また、PDF にする書籍がシリーズ物だったりして複数あるケースも想定すると、以下のような形でディレクトリが階層化されているケースも考えられる。

$ tree .
.
├── Series                  # シリーズ名ディレクトリ
│   ├── Subseries           # サブシリーズ名ディレクトリ
│   │   ├── BookTitle1
│   │   │   ├── Page001.jpg
│   │   │   ├── Page002.jpg
│   │   │   .
│   │   │   .
│   │   │   └── Page199.jpg
│   │   └── BookTitle2
│   │        ├── Page001.jpg
│   │        ├── Page002.jpg
│   │        .
│   │        .
│   │        └── Page199.jpg
│   └─── BookTitle3
│       ├── Page001.jpg
│       ├── Page002.jpg
│       .
│       .
│       └── Page199.jpg
└── BookTitle4
    ├── Page001.jpg
    ├── Page002.jpg
    .
    .
    └── Page199.jpg

このケースだと、異なる深さのディレクトリに階層に、書籍タイトルディレクトリが存在し、その配下に各ページの画像ファイルが存在する。

そこで今回の要件を、「上記のように階層化のディレクトリのルートへのパスを入力として与えた場合に、その配下に存在する全ての書籍(上記例における、BookTitle1 ~ 4)をまとめて PDF として出力すること」として定義した。

環境

  • macOS High Sierra

手順

要件が、以下の 2 ステップで実現できることは言わずもがだと思う。

  1. 入力として受け取ったディレクトリ階層から、書籍タイトルディレクトリへのパスを抽出する
  2. 各書籍タイトルディレクトリ配下の画像ファイル群を PDF に変換し、書籍タイトルのファイル名で保存する

今回は、これらの処理を Bash のスクリプトで実現する。

① 書籍名ディレクトリの抽出

やるべきこととしては、要件の整理 の章で例として挙げたようなディレクトリ階層の中から、最下層のディレクトリのみを抽出すれば良いのだが、POSIX コマンドの中に単体でこれを実現できそうなものは無かった。(find コマンドのオプションなんかで実現できるかとも思ったが、無理そうだった。)

そこで Stack Exchange 上の Gilles 氏による回答 を参考に findawk のコマンドを組み合わせて、以下のような関数で実現した。1

leaf () {
    { find "$1" -type d; echo; } | \
    awk 'index($0,prev"/")!=1 && NR!=1 {print prev}
         1 {sub(/\/$/,""); prev=$0}'
}

簡単に処理内容を説明すると、関数内 1 行目では特に変わったことはしておらず、普通に find コマンドで、入力として受け取ったパス配下のディレクトリを出力している。 ただ、今回は最終的に最下層のディレクトリのみを出力したいため、後の awk コマンドでその判定を行う際には一行先読みを行う必要が発生し、関数内 1 行目の echo コマンドによる空行の出力はそのためのものである。

関数内 2 行目、3 行目の awk コマンドが少しトリッキーだが、以下のような処理を行っている。

  1. 入力行に prev 変数の文字列(一つ前の行のもの)が存在しないかどうかをチェックし、存在しなければ prev を出力
  2. 入力行の末尾のスラッシュを削除し、prev 変数にセット

なお、NR!=1awk の入力の一行目については print を行わないこと、関数内 3 行目の 1 は真偽値(True)を意味し、常に後続の処理を実行することを意味する。

この leaf 関数は、使い勝手が良いので、.bashrc なり .zshrc などに登録しておくと良いかもしれない。

② 画像ファイル群を PDF へ変換

いろいろな方法がありそうだが、王道の ImageMagick を使うのが一番手っ取り早そうだったので、これを使用した。2

macOS であれば、Homebrew を使用して、以下のコマンド一つで ImageMagick のインストールが行える。

$ brew install imagemagick 

上記コマンドで ImageMagick をインストールすると、convert というコマンドが使用可能になり、以下のように画像ファイルを PDF へ変換が可能となる。

$ convert *.jpg BookTitle.pdf

変換対象の画像ファイルを上記のようにワイルドカード指定すると、ファイル名の昇順で PDF のページに変換される。

また、そのままの画質のまま変換を行うと、作成される PDF のファイルサイズがかなり大きくなってしまうため、以下のように -quality オプション (1 ~ 100) で画質を落とすことも可能。

$ convert *.jpg -quality 20 BookTitle.pdf

元の画像にもよるかと思うが、手元で試し感じだと quality は 20 程度にまで下げても、十分に文字の判読が可能な形で変換を行うことができた。

まとめ

以下のような Bash スクリプトを作成し、はじめに定義した要件の通りの変換処理を実現することができた。

変換対象の画像ファイルが存在するディレクトリを第一引数として指定し、画質を第二引数として指定(省略可能、既定値 20)することで、対象ディレクトリ配下の全ての画像ファイルを PDF に変換することができる。

$ ./images2pdf path/to/images 50


comments powered by Disqus