memorandums

日々の生活で問題解決したこと、知ってよかったことなどを自分が思い出すために記録しています。

PDFをEPUBにしたかっただけなのに半日かかってしまった

まえおき

書籍をスキャンしてPDF化したファイルが手元にありまして、MacならBookアプリで見れた方がいいなと思ったわけです。

ちなみにリアル書籍をスキャンすると当然ですが「見開き」になります。つまりリアル書籍の2ページがPDF1ページになります。

パソコンで見るには見開きでいいのですが、スマホで見ると見にくいので半分にカットしたくなったわけです。

そこで作ったのが以下のコマンドでした。

memorandums.hatenablog.com

ここまでで、とりあえず、リアル書籍をスキャンしてその画像ファイルをまとめたあと、見開きのPDFファイルを垂直に半分にかっとして単一ページにしたPDFが手元にある、という状況だということになります。長すぎて何を言っているかわからないですよね。。。

やったこと

このPDFをEPUBにするとなるとcalibreかなということでやってみたわけです。

calibre-ebook.com

すると、なぜかEPUBでは「見開き」になってしまうのです。。。なぜだろう?とにかく調べて調べて2,3時間が過ぎました。

どうやっても「見開き」にしかなりませんでした。

色々調べているうちにcalibreの内部ではpdftohtmlを使用していることがわかりました。

コマンドラインでやってみようとPopplerをインストールして、pdftohtmlが使えるようにしました。

で、コマンドラインでやってみますと「pdftohtml PDFファイル名」で、カレントディレクトリにhtmlファイルと画像ファイルが生成されます(スキャンしたPDFファイルなので画像だけが抽出されるわけです)。

その画像を見て「ハッ」としたわけです。あーそうか。。。見開きPDFを単一ページPDFに変換できたと思っていたのですが、画像を半分にカットしたわけではなく、画像ファイルは変えずにPDFで見える範囲を制限して単一ページっぽく見せているのだ。。。ということでした。

なので、いくらcalibreのオプションをいじっても生成されるEPUBファイルは見開きになるのでした。。。おしまい

リカバー処理

どうずればよかったか?ですが、まず、スキャンしたあとすぐにPDF化するのではなく、画像自体をImageMagickなどを使って半分にカットしてからPDF化すればいいのでしょうね。

ちなみにMacでは画像群からPDFに変換するのは簡単で、ファイルを選択して右クリックしてクイックアクションで「PDFを作成」を選択すればよいですね。

さらに個人的な問題としては、既に画像をPDF化してしまったファイルを処理したい(画像を半分にカットして見た目だけではなく実体も1ページ=1ページにする)ですね。ということでAIとともに以下、シェルスクリプトを作ってみました。

#!/bin/bash

# 引数(*.pdf)をつけたら画像を抽出する、なければ抽出処理はしない
if [ -n "$1" ]; then
  pdftohtml "$1"
  rm -f *html
fi

prev_size=""
prev_file=""

for file in $(ls -1 *.jpg | sort -V); do
    if [ -d "$file" ]; then
        continue
    fi

    size=$(stat -f%z "$file")  # Linux の場合。macOSなら stat -f%z "$file"

    if [ "$size" != "$prev_size" ]; then
        convert -crop 50%x100% "$file" "_$file"
    fi

    rm -f "$file"
    
    prev_size=$size
    prev_file=$file
done

例えば、n.pdfというファイルがあったとしたら、以下のように使います。

pdf21.sh n.pdf

もし、引数をつけなければ、カレントディレクトリにある画像ファイルを半分にカットするようにしています。なので、リアル書籍を見開きでスキャンした画像ファイルが複数入っているディレクトリ内で以下のように実行すると、半分にカットしたファイルだけが残りますので、あとは、画像ファイルを選択してPDFにすればいいな、ということです。はい。

pdf21.sh

個人的には大満足なツールになりました\(^o^)/

おまけ

ちなみに、カレントディレクトリ内のファイルの処理順を、MacのFinderで見えた順にしたかったんです。これが意外や意外で、単純な辞書順ではなかったんですね。今さら知りました。そういう順番に処理しないとページ順がスキャン順にならなくなるようでした。

で、調べると、Macでは以下のようにするといいようでした。なるほどです。

ls -1 *.jpg | sort -V

時間がかかったわけですが、灯台下暗しな発見があったのでよかったかな、と思います。

以上です。