|||||||||||||||||||||

なんぶ電子

- 更新: 

PDFを画像に変換

Ghostscript help

Windowsを使っていて、PDFの1ページをまるごと画像にしたいと思ったことはありませんか。PrintScreen機能で用が足りることもありますが、画面に入りきらない場合は少し面倒です。

そのような時のために今回はフリーアプリのGhostscriptを使って、PDFを画像に変換したいと思います。

筆者の環境はWindows10の32bitですが、Ghostscriptはマルチプラットフォームなアプリなので他の環境でも同じことができると思います。

また同様のことをImageMagickというアプリでも処理できます。こちらの方がインストールや使い方は簡単なので手っ取り早く処理したいのなら、Ghostscriptに関する記述は読み飛ばして、ImageMagickの項目から読んでください。

Ghostscript

GhostscriptPostScriptやPDFのインタープリターです。意訳すると、印刷時によく用いられるデータを図形化するPostScriptというプログラミング言語やPDF形式を操作するためのアプリケーションです。

Linux(Debian)での印刷機能であるcupsをインストールするとと依存アプリとして同時にインストールされたりします。

筆者は「Microsoft Print to PDF」がない時代に、PDFファイルを作成する際、任意のプリンタドライバで作成したPostScriptデータをGhostscriptに同梱されているps2pdf.batで変換していました。

Ghostscriptのインストール

Windows10でインストールするには、ダウンロードページよりアーキテクチャに合うバージョンをダウンロードします。

フリーである「AGPLv3」バージョンと、商用利用のできる有料の「Artifex」バージョンがありますので、AGPLバージョンを選択してください。

Ghostscriptバイナリダウンロード

ダウンロードしたファイルをダブルクリックで実行します。インストーラーのバージョンにもよると思いますが、筆者がインストールした32ビットWindows用のバージョン9.53.3では、表示されるがまま進めていけば問題ありませんでした。

このアプリはコマンドプロンプトか、PowerShellから使うのですが、その際どこのフォルダにいてもファイル名だけで実行できるように、パスを通しておきます。

パスはWindowsの「コントロールパネル」→「システムとセキュリティ」→「システム」の画面から、「システムの詳細設定」→「環境変数」→「システム環境変数」→「PATH」の項目から設定します。

「新規作成」から次の2行を追加します。

C:¥Program Files¥gs¥gs9.53.3¥bin
C:¥Program Files¥gs¥gs9.53.3¥lib
Windows10のPATHの設定方法

これでインストールが完了です。

Ghostscriptのコマンドオプション

Windowsからはgswin32.exe -h、Debianからはgs -hで主なオプションのヘルプやデバイスの一覧が出てきます。

筆者の環境で表示されたオプションの一覧は次の通りでした。

  • -dNOPAUSE

    ページ毎にpauseを入れない設定です。

  • -q

    メッセージを少なくします。標準出力をリダイレクトする場合は必須です。

  • -g

    ページサイズをピクセルで指定します。
    例:幅100px×高120pxの場合「-g100x120」

  • -r

    解像度dpiを設定します。指定しない時の値は75というWebページの記述もみられましたが200ぐらいありそうです。ただいずれにしても小さいので値を指定した方がいいです。
    例:600dpi(1インチに600pxの解像度)の場合「-r600」

  • -dDEVICE=

    デバイスの指定。ここでは変換後フォーマットと考えるとわかりやすいかもしれません。このオプションは=の後に値を設定します。

    利用できるデバイスは、ヘルプで出力される後半の「Available devices:」で表示されます。

  • -dBATCH

    処理終了後にgsを終了させます。通常gswin32とコマンドを打つと、そのあとのプロンプトはgsへの入力となりquitコマンドを実行するまで終わりませんが、その終了を自動で行うモードです。

  • -sOutputFile=

    出力ファイルの指定です。このオプションは=の後に値を設定します。%dまたは%ldとすることでページ番号を指定できます。

Available devicesに表示されたのは次の通りでした。

Available devices

bbox bit bitcmyk bitrgb bitrgbtags bj10e bj200 bjc600 bjc800 bmp16 bmp16m bmp256 bmp32b bmpgray bmpmono bmpsep1 bmpsep8 cdeskjet cdj550 cdjcolor cdjmono chameleon declj250 deskjet devicen display djet500 djet500c eps2write eps9high eps9mid epson epsonc fpng ibmpro ijs ink_cov inkcov jetp3852 jpeg jpegcmyk jpeggray laserjet lbp8 lj250 ljet2p ljet3 ljet3d ljet4 ljet4d ljetplus m8510 mswinpr2 necp6 nullpage pam pamcmyk32 pamcmyk4 pbm pbmraw pclm pcx16 pcx24b pcx256 pcxcmyk pcxgray pcxmono pdfimage24 pdfimage32 pdfimage8 pdfwrite pgm pgmraw pgnm pgnmraw pj pjxl pjxl300 pkmraw plan planc plang plank planm planr plib plibc plibg plibk plibm png16 png16m png256 pngalpha pnggray pngmono pngmonod pnm pnmcmyk pnmraw ppm ppmraw ps2write psdcmyk psdcmyk16 psdcmykog psdrgb psdrgb16 pxlcolor pxlmono r4081 spotcmyk st800 stcolor t4693d2 t4693d4 t4693d8 tek4696 tiff12nc tiff24nc tiff32nc tiff48nc tiff64nc tiffcrle tiffg3 tiffg32d tiffg4 tiffgray tifflzw tiffpack tiffscaled tiffscaled24 tiffscaled32 tiffscaled4 tiffscaled8 tiffsep tiffsep1 txtwrite uniprint

PDFからの変換

先に出力されたオプションを使って変換をします。

筆者の環境では32ビットなので「gswin32」としていますが、64bitの場合は32の部分を64としてください。またDebian等の場合は「gswin32」ではなく「gs」となります。

Windowsバージョンではbinフォルダ内にはgswin32.exeのほかにcのついたgswin32c.exeも存在します。コマンドラインから実行した際に、cがついている方はそのままのウインドウで処理されますが、ついていない方は独自のウインドウが表示されます。

ページが1ページだけか、マルチページに対応しているtiffフォーマットに変換する場合は(読み出し時にはマルチページに対応したリーダーが必要です)、次のようにコマンドを入力します。

gswin32 -dNOPAUSE -r600 -sDEVICE=tiffg4 -dBATCH -sOutputFile=d:\sample.tiff d:\sample.pdf

PDFがマルチページで、それに対応していないフォーマットに変換する場合は%dを入れて出力ファイルを指定します。該当箇所にページ番号が入った形でページ毎にファイルが出力されます。

gswin32 -dNOPAUSE -r600 -sDEVICE=jpeg -dBATCH -sOutputFile=d:\sample%d.jpg d:\sample.pdf

jpegの他によく使いそうなものは、ビットマップにするbmp256、PNGにするpng16mがあります。

GIFにする方法は、変換アプリを利用するしかなさそうです。Linuxの場合はなら次のようにします。こちらはTEX Wiki:「Ghostscript/使い方」を参考にさせていただきました。

gs -q -dNOPAUSE -r200 -sDEVICE=ppmraw -dBATCH -sOutputFile=- sample.pdf | ppmquant 256 | ppmtogif>sample256.gif

これらの処理を解説します。

  1. まず-qオプションで余計な出力を止めます。
  2. 先ほどは-r600を指定しましたがppmへの変換で600を指定すると大きなファイルになるので200としています。
  3. -sOutputFileに-を指定することで一旦結果を標準出力に渡します。qオプションが指定されていないと余計なメッセージも混ざってエラーになってしまいます。
  4. |でppmquantにパイプし、256色に減色します。これは次で使うppmtogifの色数の上限に合わせています。
  5. さらにパイプでppmtogifというppmからgifに変換するLinuxのコマンドにデータを渡します。
  6. 処理の結果をリダイレクト(>)で出力します。

ppmquantやppmtogifはLinuxのコマンドのためWindowsでは利用できません。

Windowsで処理するならImageMagickを使えばできそうです。インストール方法は後述します。

ただしPDFファイルが複数ページ存在する場合は一括で処理することができません。

そこでGhostscriptの機能を使ってPDFを分割します。デバイスにpdfwriteというPDF出力を指定して、一旦ページ毎にPDFを出力します。

gswin32 -dNOPAUSE -r600 -sDEVICE=pdfwrite -dBATCH -sOutputFile=d:\split%d.pdf d:\sample.pdf

分割されたファイルを変換します。ここではmagick.exe(ImageMagick)の第一引数でpng形式を指定して標準入力を受け取りgifに変換しています。

gswin32 -dNOPAUSE -r600 -sDEVICE=png16m -dBATCH -sOutputFile=- d:\split1.pdf | magick.exe png:- d:\split1.gif

ImageMagickはバックグラウンドで動くようなので、レスポンスが戻ってきても、ImageMagickの処理が終わっていないことがあります。

ImageMagick

実はImageMagickから、PDFを直接画像に変換できます。PostScriptやPDFを扱うGhostscriptとは違ってこちらはイメージ全般を処理するアプリとなりますが、PDFも読み込むことができます。またPNGからGIFへといったイメージ変換も可能です。

ImageMagickのダウンロードページに「Windows Binary Release」という項目があるので、そこから環境にあったものをダウンロードします。筆者の場合は「ImageMagick-7.0.10-37-Q16-x86-static.exe」としました。32ビットならx86、64ビットならx64という部分はわかると思いますが、Q8とQ16は1ピクセル単位のビット数の違い、staticの有無はdllを含むか含まないか(表記がない方がdllを含みます)です。

インストール時の質問はすべてデフォルトのままでいいと思います。

ImageMagickで、dpiに600に指定して単一ページのPDFをgifに変換するには次のようにします。この時ファイル形式は拡張子で判断されます。

magick -density 600 d:\split2.pdf d:\split2.gif

PHPを利用する場合

ここまではOSのコマンドを利用していました。PHPから実行したい場合はPHPからOSコマンドを呼び出すことも可能ですが、ImageMagickを操作する専用ライブラリがあります。このライブラリは下流でGhostscriptを使いPDFを画像に変換する事ができます。目的によってはこちらを利用した方が効率がいい場合もありますので合わせて紹介します

Debian11では apt で php-imagick をインストールすることでほとんどの設定が終わります。Ghostscript も推奨の依存関係により自動でインストールされるようです。

ちなみに、aptで依存関係をチェックするにはつぎのように depends を指定して調べます。

# apt depends php-imagick

...
推奨: ghostscript
...

また depends のかわりに show で詳細を表示させても、依存性が表示されます。

...
# apt show php-imagick
...

筆者も最初知らなかったのですがImagemagickやそのライブラリのバージョンと共に表示される Q16 といった数値は、クォンタム深度(RGBの各チャンネルで何ビット利用できるか)が16bitであることを示します。つまりQ16の場合はRGBそれぞれで16bit(=65,536)の値を持つことができます。

話をもどして、apt で PHP用のimagemagickライブラリを取得します。

# apt install php-imagick
...

サーバーをリスタートした後に、phpinfo(); ページを表示させて Imagick のセクションがあれば稼働しています。

PHP imagick

aptを使用しない環境の場合はPECLからtgzファイルを取得してビルドし、extensionの設定をします。

こちらについては、以前apcuをビルドした時の記事も参考にしてください。

ビルド時の configureで「 configure: error: not found. Please provide a path to MagickWand-config or Wand-config program. 」がでた時は、libmagickwand-6.q16-dev をインストールします。

ビルド後インストールすると、筆者の環境では /usr/local/lib/php/extensions/no-debug-zts-20220829/imagick.so に配置されました。php.ini の extensionにこれを加えます。

ちなみにディレクトリ名の no-debug-zts の意味ですが、デバッグ情報を含まないZTS(スレッドセーフ版)用のモジュールであることを意味しているそうです。

もし、実行時に「 Uncaught ImagickException: attempt to perform an operation not allowed by the security policy `PDF' 」というエラーが表示されたら、/etc/ImageMagick-6/policy.xml を修正します。

ファイル内部にImageMagickからGhostScriptを利用するためのセキュリティポリシーが記述されている部分があります。コメントに「 disable ghostscript format types 」とあるのでわかると思います。ここには権限の剥奪の設定がかかれているので、PDFのエントリーをコメントアウトします。

plicy.xml

<!-- disable ghostscript format types -->
<policy domain="coder" rights="none" pattern="PS" />
<policy domain="coder" rights="none" pattern="PS2" />
<policy domain="coder" rights="none" pattern="PS3" />
<policy domain="coder" rights="none" pattern="EPS" />
<!-- <policy domain="coder" rights="none" pattern="PDF" /> -->
<policy domain="coder" rights="none" pattern="XPS" />

Windows環境の場合はPECLのWindowsマークで表示されるリンクから、対象となるアーキテクチャを選びバイナリ群をダウンロードします。

バイナリ群のうち php_imagick.dll をPHPの拡張ライブラリフォルダ(通常はPHPのルート¥extフォルダにあります)に入れ、php.iniのエクステンションの設定をします。

php.ini

extension=imagick

php_imagick.dll 以外のdllファイルはすべてapacheのbinフォルダへコピーします。

もし、Debian環境で

PHPでのコーディング

コンストラクタにソースファイルを指定して、setImageFormatメソッドを呼び出すと元のデータが指定したフォーマットに変換されます。

この時複数のページが存在したらファイル名は「-インデックス」という形に変換され複数のファイルに保存されます。

sample1.php

$image = new Imagick('test.pdf');
$image->setImageFormat('png');
$image->writeImage('conv.png');

先の例ではコンストラクタで元のファイルを指定していましたが、readImageメソッド明示して読み込むこともできます。また、データをすでにバイナリデータとして読み込み済みの時は readImageBlob に渡すこともできます。

writeImageメソッドで拡張子を指定する場合はsetImageFormatは省略できます。また、これらのふたつの間で違いがあった場合は、writeImageでの指定が優先されるようです。またwriteImageで拡張子判定ができずに、setImageFormatも指定されていない場合は元のフォーマットのまま保存されます。

sample2.php

$image = new Imagick();
$image->readImage('test.pdf');

# 読み込み済みのバイナリデータをセットする場合
#$image->readImageBlob($raw);

$image->writeImage('conv.png');

すべてのページを連結させたい場合は、appendImages メソッドを使います。このとき2点注意が必要です。まずこの処理の前に resetIterator を呼んでページのイテレーターをリセットしないと画像は最後のページだけになってしまいます。また、連結されたイメージは appendImages の戻り値にセットされるのでそれを受け取る必要があります。

sample3.php

$image = new Imagick('test.pdf');
$image->resetIterator();
$newimage=$image->appendImages(true);
$newimage->writeImage('conv.png');

ページ毎にデータを読み込みたい場合は、setIteratorIndex メソッドでページインデックスを指定します。ここではさらに、ファイルをバイナリで受け取って、base64でエンコードしてHTMLのimgタグとして出力します。

getNumberImages メソッドを使うともとのデータのページ数がわかります。またバイナリデータで取得する場合は保存形式が自動判定できないのので、インデックス毎にsetImageFormatを呼び出す必要があります。

sample4.php

...
for($i=0,$max=$image->getNumberImages(); $i < $max; $i++) {
    $image->setIteratorIndex($i);
    $image->setImageFormat('png');
    $raw = $image->getImageBlob();
    $b64 = base64_encode($raw);
    echo '<img src="data: image/png' . ';base64,' . $b64 .'"/>';    
}

ページ毎にオリジナルのページ名を付けたい場合は、ここで受け取ったバイナリ($raw)を file_put_contents などに渡すことで可能です。


他にもApacheのPDFBOXを利用してPDFを画像にする方法もあります。こちらはリンク先で紹介していますので、よろしければ合わせてご覧になってください。

筆者紹介


自分の写真
がーふぁ、とか、ふぃんてっく、とか世の中すっかりハイテクになってしまいました。プログラムのコーディングに触れることもある筆者ですが、自分の作業は硯と筆で文字をかいているみたいな古臭いものだと思っています。 今やこんな風にブログを書くことすらAIにとって代わられそうなほど技術は進んでいます。 生活やビジネスでPCを活用しようとするとき、そんな第一線の技術と比べてしまうとやる気が失せてしまいがちですが、おいしいお惣菜をネットで注文できる時代でも、手作りの味はすたれていません。 提示されたもの(アプリ)に自分を合わせるのでなく、自分の活動にあったアプリを作る。それがPC活用の基本なんじゃなかと思います。 そんな意見に同調していただける方向けにLinuxのDebianOSをはじめとした基本無料のアプリの使い方を紹介できたらなと考えています。

広告