pdfファイルから画像を取り出したり、画像化をしたり、ページを分けたり、結合したりする方法を調べたので、記録しておく。
すでにgimpを使えば画像関係の処理ができることはわかっている。解像度を指定して読み込んだり、ページをレイヤーにしてエクスポートするときにレイヤーをページにして出すこともできる。
今回はスキャナで読み取ったり、スクリーンショットでとった複数画像を複数ページのpdfにまとめるために、端末からコマンドで行えると便利だということで調べることとなった。
pdfといっても内容は様々で文字データで構成されたものもあるし、画像がそのままページになっているものもある。画像を含む文字データの場合もあるかもしれない。今回主に扱うのは画像がそのままページになっているものである。
2つのパッケージをレポートします。
(1)poppler-utilsパッケージからpdfimagesやpdftoppm, pdfinfo, pdfseparate, pdfuniteなどのコマンド。
(2)qpdfパッケージからqpdfというコマンドが持つ分割、連結、回転などの機能。
ここでパッケージはdebian系のLinuxが使用するaptというパッケージマネージャのソフトウェアの管理単位です。
今回扱うのはプリンタ付属のスキャナで読み取ってUSBメモリに保存したデータ。
いつもはxsaneでPCから読み取ってpngなどで保存しているが、今回はスキャナだけで読み取った。
jpgとpdfを選択できるが、jpgでは1枚スキャンするごとに2回センサが動いて時間がかかる。たぶん1枚ごとに調整をしていると思われる。pdfだと1パスで読み取ってくれる。
このスキャナのjpgは圧縮率を指定できないので、文字データでは画質に不安が残ることもありpdfにした。
pdfinfoで情報を得ると
adachi@fumita:~/work$ pdfinfo EPSON001.PDF Tagged: no UserProperties: no Suspects: no Form: none JavaScript: no Pages: 1 Encrypted: no Page size: 595 x 841 pts Page rot: 0 File size: 1846117 bytes Optimized: no PDF version: 1.4
841[pt]=841/72[in]=841/72*25.4[mm]=約297mm なので、A4サイズ。
pdfimagesは含まれる画像を抽出するコマンド。-listで一覧が取れる。今回のページは全体が1つの画像のはず。
adachi@fumita:~/work$ pdfimages -list EPSON001.PDF page num type width height color comp bpc enc interp object ID x-ppi y-ppi size ratio -------------------------------------------------------------------------------------------- 1 0 image 2480 3507 rgb 3 8 jpeg no 6 0 301 301 1802K 7.1%
なんと、中身はjpgだった。3507[px]=3507/841*72[dpi]=約300dpi これはスキャン時の指定通り。
adachi@fumita:~/work$ pdfimages EPSON001.PDF img001
これでimg001-000.ppmができる。ppmは無圧縮なので26.1MBになる。最初のP6で確認できる。
adachi@fumita:~/work$ hd img001-000.ppm |head 00000000 50 36 0a 32 34 38 30 20 33 35 30 37 0a 32 35 35 |P6.2480 3507.255| 00000010 0a e2 cf b1 d7 c4 a6 e6 d3 b5 fb e8 ca fa e7 c7 |................| 00000020 f6 e3 c3 f8 e5 c5 f4 e1 c1 f4 df c0 f3 de bf f2 |................| 00000030 dd be f3 de bf f5 e0 c1 f6 e1 c2 f7 e0 c1 f6 df |................| 00000040 c0 f2 dd be f4 df c0 f3 de bf ee d9 ba eb d6 b7 |................| 00000050 ec d7 b8 f1 dc bd f4 df c0 f5 e1 c0 f6 e2 c1 f7 |................| 00000060 e3 c2 f7 e3 c2 f5 e1 c0 f3 df be ef db ba ed d9 |................| 00000070 b8 ef d8 b6 ee d7 b5 ee d7 b5 f0 d9 b7 f4 dd bb |................| 00000080 f8 e1 bf fb e4 c2 fc e5 c3 f3 dc ba f3 dc ba f3 |................| 00000090 dc ba f5 de bc f7 e0 be f8 e1 bf f7 e0 be f7 df |................|
オプションで出力形式を、png, tiff, jpg, JPEG2000 などにすることができる
adachi@fumita:~/work$ pdfimages -j EPSON001.PDF img001
これはjpg。拡張子は自動でつく。
adachi@fumita:~/work$ hd img001-000.jpg |head 00000000 ff d8 ff e1 01 06 45 78 69 66 00 00 49 49 2a 00 |......Exif..II*.| 00000010 08 00 00 00 08 00 0e 01 02 00 10 00 00 00 6e 00 |..............n.| 00000020 00 00 0f 01 02 00 12 00 00 00 7e 00 00 00 10 01 |..........~.....| 00000030 02 00 0f 00 00 00 90 00 00 00 1a 01 05 00 01 00 |................| 00000040 00 00 a0 00 00 00 1b 01 05 00 01 00 00 00 a8 00 |................| 00000050 00 00 28 01 03 00 01 00 00 00 02 00 00 00 13 02 |..(.............| 00000060 03 00 01 00 00 00 02 00 00 00 69 87 04 00 01 00 |..........i.....| 00000070 00 00 b0 00 00 00 00 00 00 00 45 50 53 4f 4e 20 |..........EPSON | 00000080 4d 46 50 20 69 6d 61 67 65 00 53 45 49 4b 4f 20 |MFP image.SEIKO | 00000090 45 50 53 4f 4e 20 43 4f 52 50 2e 00 45 50 2d 38 |EPSON CORP..EP-8|
出力ファイル名に-000がつくのは、ページ内にたくさんの画像が埋め込まれていることを想定しているからだろう。今回のファイルはページそのものが一つの画像なので-000しかない。
-rwxrwxrwx 1 adachi adachi 1846117 1月 1 2018 EPSON001.PDF -rw-r--r-- 1 adachi adachi 1845247 10月 15 02:03 img001-000.jpg -rw-r--r-- 1 adachi adachi 26092097 10月 15 02:00 img001-000.ppm
今回はもともとpdfのページが画像だけで構成されているので、これを使う意味はないが、違いを把握しておく。
pdftoppmは文字データも含めてページを画像化する。デフォルトでは150dpiのppmという形式になる。今回のpdfimagesの出力と同様なものを得るには -jpegオプションと、-r 300 オプション(rの後にスペースが必要)を指定する必要がある。
adachi@fumita:~/work$ pdftoppm -jpeg -r 300 EPSON001.PDF img001bytoppm300
作成されるファイル名には-1がつくがページが複数ある時のためであろう。
中身がもともとjpegなのでエンコードし直していることになる。ファイルサイズから、圧縮率が上がっているように見受けられる。
-rwxrwxrwx 1 adachi adachi 1846117 1月 1 2018 EPSON001.PDF -rw-r--r-- 1 adachi adachi 873337 10月 15 03:01 img001bytoppm300-1.jpg
jpgの指定が、pdfimagesが-jで、pdftoppmが-jpegなのは不統一だが、間違えるとオプション一覧が出るのでそれとわかる。pngは両方共 -png。
この作業は後でqpdfで行うことにしたので、pdfuniteは試しただけになったが、一応記録しておく。
カレントディレクトリにあるEPSON001.PDF, EPSON002.PDF, EPSON003.PDF を連結してEall.pdfにするには、
adachi@fumita:~/work$ pdfunite EPSON001.PDF EPSON002.PDF EPSON003.PDF Eall.pdf
書かれた順で連結されて最後の引数のファイルが生成される。
shellの機能として、ls EPSON*.PDF や ls EPSON* が、EPSON001.PDF EPSON002.PDF EPSON003.PDF となるのであれば、それを使って簡素化できる。たとえば、
adachi@fumita:~/work$ pdfunite EPSON*.PDF Eall.pdf
今回の作業のきっかけは所有するスキャナで取る画像データが自由にならないことだった。
(1)jpgよりもpdfの方が動作が早いので文字中心の画像ならpdfにしたい。
(2)デフォルトで縦位置になってしまう。
(3)複数ページのデータは1ファイルにまとめたいが、複数ページのpdfにはしてくれない。
いままでは、画像ファイルにしてgimpで切り貼りしたり、htmlに貼り付けてページ送り機能をつけたりしたが、縦横比が違う画像データが扱いにくかったり、手間がかかったり、結局1ファイルにはならないという欠点がある。どうせpdfにするなら複数ページを持つpdfにしてしまうほうがよい。
今までpdfから画像ファイルを取り出して加工することを考えたのでpdfimagesなどを吟味していたが、pdfのままにしたほうが楽ができると気がついて方針を変更。qpdfを調べることにする。
qpdfを使えば全部のページをまとめて90, 180, 270度の回転ができるので、さらに手間が省ける。
debian10(buster)ではqpdfは標準では入っていないので、qpdfパッケージを追加した。qpdfが依存しているlibqpdf21というパッケージはすでに入っていた。
先程同様、カレントディレクトリにあるEPSON001.PDF, EPSON002.PDF, EPSON003.PDF を連結してEall.pdfにするには、
adachi@fumita:~/work$ qpdf EPSON001.PDF --pages EPSON001.PDF EPSON002.PDF EPSON003.PDF -- Eall.pdf
--pages と -- の間に書かれたファイルがその順で連結されて最後の引数のファイルが生成される。最初の引数(ここではEPSON001.PDF)は、ページデータ以外の情報(Creator, Producer, CreationDate, PDF versionなど)をそのファイルから引き継ぐことを意味する。連結するファイル以外を指定しても受け入れられる。引き継ぎたくない場合はファイル名の代わりに --empty と入れておく。
adachi@fumita:~/work$ qpdf --empty --pages EPSON001.PDF EPSON002.PDF EPSON003.PDF -- Eall.pdf
shellの機能として、ls EPSON*.PDF や ls EPSON* が、EPSON001.PDF EPSON002.PDF EPSON003.PDF となるのであれば、それを使って簡素化できる。たとえば、
adachi@fumita:~/work$ qpdf --empty --pages EPSON*.PDF -- Eall.pdf
qpdf --help で冒頭に
Usage: qpdf [ options ] { infilename | --empty } [ outfilename ]
と書かれているが、これに順番を合わせて、
adachi@fumita:~/work$ qpdf --pages EPSON*.PDF -- EPSON001.PDF Eall.pdf
と書いても同じだ。
さらに、連結するファイルの順序を調整したければ、テキストファイルを作ってそれを指定してもよい。
例えば、次のようなファイルを作っておいて、
adachi@fumita:~/work$ cat Elist.txt EPSON003.PDF EPSON002.PDF EPSON001.PDF
@をつけて指定するとこの順番で連結してくれる。
adachi@fumita:~/work$ qpdf --pages @Elist.txt -- --empty Eallr.pdf
この他、連結する元のファイルがすでに複数のページから構成されている場合には、ページを選択して指定することも可能。
全部のページを一度に回転させることも可能だし、一部のページだけを異なる回転にすることもできる。角度は90, 180, 270度のどれか。
全部をまとめて回転する例だけを示すと、
adachi@fumita:~/work$ qpdf --rotate=90 Eall.pdf Eallyoko.pdf
Eall.pdf のデータを時計回りで90度回転させて、Eallyoko.pdfを生成する。
1ページずつに分割するのは簡単。
adachi@fumita:~/work$ qpdf --split-pages Eall.pdf Esplited.pdf
出来上がるファイルには拡張子前に連番がつく。linuxの伝統で拡張子なしも許されるが、その場合は連番で終わる名前になる。
Esplited-1.pdf Esplited-2.pdf Esplited-3.pdf
もし、10ページからなるものを分割すると、次のようになる。
Esplited-01.pdf Esplited-02.pdf Esplited-03.pdf ...... Esplited-10.pdf
ページ番号を末尾以外に配置する場合は、%dで位置を指定する。
adachi@fumita:~/work$ qpdf --split-pages Eall.pdf E%dsplited.pdf
E1splited.pdf E2splited.pdf E3splited.pdf
こちらも、10ページなら0がついて二桁となる。
E01splited.pdf E02splited.pdf E03splited.pdf ...... E10splited.pdf
連結
qpdf --pages 入力ファイルリスト -- メタデータのファイル 出力ファイル qpdf --pages 入力ファイルリスト -- --empty 出力ファイル qpdf --pages s01.pdf s02.pdf s03.pdf -- s01.pdf outfile.pdf qpdf --pages s*.pdf -- s01.pdf outfile.pdf qpdf --pages @sflist.txt -- --empty outfile.pdf
回転
qpdf --rotate=90 入力ファイル 出力ファイル qpdf --rotate=90 infile.pdf outfile.pdf qpdf --rotate=180 infile.pdf outfile.pdf qpdf --rotate=270 infile.pdf outfile.pdf
分割
qpdf --split-pages 入力ファイル 出力ファイル(基本形) qpdf --split-pages infile.pdf outfile.pdf qpdf --split-pages infile.pdf out%dfile.pdf
ファイル情報
pdfinfo 入力ファイル
内部画像情報
pdfimages -list 入力ファイル
内部画像取出
ppmで:pdfimages 入力ファイル 出力画像ファイル jpgで:pdfimages -j 入力ファイル 出力画像ファイル pngで:pdfimages -png 入力ファイル 出力画像ファイル
ページの画像化
ppm,150dpiで:pdftoppm 入力ファイル 出力画像ファイル jpg,300dpiで:pdftoppm -jpeg -r 300 入力ファイル 出力画像ファイル png,300dpiで:pdftoppm -png -r 300 入力ファイル 出力画像ファイル
A4は210x297mm 300dpiでは210/25.4*300≒2480px 297/25.4*300≒3508px
このサイズの画像を揃えたら次のどれかで
300dpi ≒ 300/2.54 ≒ 118dpcm
convert -density 118 tori*.jpg output.pdf
単位を指定する
convert -units PixelsPerInch -density 300 tori*.jpg output.pdf
ファイルの一覧をテキストファイルzfに用意して使う場合。
convert -units PixelsPerInch -density 300 `cat zf` output.pdf
詳しくはまたいつか。