JPedalを使って、PDFのサムネイルを作る

2013.06.17.月
技術

どもども、常角です。
4ヵ月半ぶりです。

すっかり忘れ何かと忙しく、またもやこんなに時間が空いてしまいました。
さて、今回の御題は・・・JPedalです。
JPedalってなんぞや?って思う人もいるでしょうか?
それとも、JPedalについて探してたらここに流れ着いた人もいるでしょうか?
要は、Java用のPDFライブラリです。
詳しくは、すごい昔にマイナビニュースで紹介されているので、こっちを見てください。
このJPedal、そのすごい昔のマイナビニュースにも、「日本語への対応が弱い」と書いてあるのですが、2013年現在もそれは変わっておらず、日本語のソースがほとんどありません。
仕事で使う機会があり、その日本語ソースの少なさからえらく苦労したので、微力ながら日本語ソースを増やしてみようかなーと思った所存。

今回必要となるのは言うまでもなくJPedalのJarファイル、無償版と有償版があるようなのですが、使うのは無償版。
常角はここでダウンロードしてきました。
基本はJavaプロジェクトでビルド・パスに追加してやればOKです。
ただ、Tomcatプロジェクトで使う場合には、Tomcatのlibフォルダにも入れてやらないと、ClassNotFoundになるので注意。

参考にしたサイトはここここ
前者は恐らく公式のAPI(英語)。
後者はJPedalを使って、色々なことをやってるサイト(中国語)。
文章読めなくても、結構参考になります。
ただ、どちらも有償版ベースなので、いざ使ってみようとしたら、無償版にはないものは結構あります。
ご注意を。

やたら前フリが長くなってしまいました。
ここから実際の処理を説明していこうと思います。





さて、JPedalを使ったサムネイル作成処理に入ります。
この処理で使うのは、JPedal内の「PdfDecoder」「PdfPageData」という二つのクラスです。
「PdfPageData」はなくてもサムネイル自体は作れるのですが、ページのサイズはこのクラスを使って取得しますので、一緒に解説します。

Ⅰ.とりあえず最初は、必要最小限の処理、PDF⇒画像ファイルです。

PdfDecoder pdfDecoder = new PdfDecoder(true);   ・・・ ①
pdfDecoder.openPdfArray(bytes);          ・・・ ②
pdfDecoder.decodePage(1);             ・・・ ③
pdfDecoder.setPageParameters(0.5f,1);       ・・・ ④
BufferedImage bi = pdfDecoder.getPageAsImage(1);  ・・・ ⑤

① 初期化-引数は省略可ですが、最初はとりあえずtrueで問題ないかと
② 処理したいPDFファイルの情報を入力します、型はbyte[]。
inputStreamとかはそのまま使えないので、変換した奴を突っ込んでください。
ここでPDF以外のファイルデータを入れようとしたら、エラーが出ます。
③ どのページを対象とするか、int型で指定します。
実際のページ数より大きな数を入れたらエラー
④ 変換のパラメータをセットします。
第1は倍率、float型で0~1の間の値を入れます。
第2は対象のページ番号・・・あれ?じゃあdecodePageは? とりあえず、同じ数字を入れておいてください。
省略していますが、第3もあります。 どうも画像の回転量を決めるようですが、使った事ないので省略。
⑤ BufferedImageを返します。 引数はページ番号。
上ので設定した値を使って、イメージデータを作成します。
基本的に、引数は上のと同じ値を。そうしないと、当たり前ですが倍率設定が反映されないです。

これで、見慣れたBuffredImageが取得できます。
後は適当に、画面に表示するなり、ファイルを出力するなりの処理をしてやってください。

Ⅱ.次に、「PdfPageData」の使い方です。
名前から予想はつくと思いますが、PDFのページ情報各種を取得するためのクラスです。


PdfPageData pageData = pdfDecoder.getPdfPageData(); ・・・ ①
int pageCount = pageData.getPageCount();           ・・・ ②
int width = pageData.getCropBoxWidth(1);           ・・・ ③
int height = pageData.getCropBoxHeight(1);         ・・・ ③


① 初期化処理です。
「PdfDecoder」クラスに、「PdfPageData」クラスを取得する関数があるので、それをそのまま使います。

② ページ数を取得する。
全てのページに対して処理を行う場合とか、色々使えます。
PdfDecoderクラスからは、直接使えない罠がありますので注意です。

③ 幅と高さを取得する。
引数にはページ番号を指定し、そのページのそれぞれのサイズを返します。
ページ数と同様に、PdfDecoderからは取得できないようです。
Ⅰ-④で指定するサイズの計算とかに使ったりできます。

Ⅲ.エラーをキャッチする。
専用のExceptionとして、PdfExceptionというものが用意されています。
Ⅰ-②で引数に指定するByteデータがPDFのものじゃなかったり、存在しないページ数を指定したりすると、このExceptionが発生します。

・・・と、まあ。
こんな感じで、処理自体はシンプルです。
日本語ソースが皆無に近く、非常に苦労しましたが、実際に処理を作り終えてみると、50行にも達しませんでした。
とはいえ、実は、
・保護されているPDFは変換時にエラーが出る。
・特定の文字コードの場合、変換する時に文字情報が画像に反映されない。
などの問題があったりします。
前者は読み込むPDFに保護をかけないようにするという事で放置。
後者は普通にPDFを作っても、そういった現象が発生する文字コードは使われないようなので、こちらも放置。
という事になっています。
無論、直しておいた方がいいのですが、運用での回避で十分かと。。。
(特に後者にいたっては、ネットから落としてきたPDFを使ってたまたま発見したもので、逆にどうやっても、変換したら文字が表示されないPDFを自分で作ることができませんでした)
もし、回避策とか知ってる方がいたら、是非教えてください。

では、今回はここまでです。
たぶん次は、Androidネタになるんじゃないかなーと思います。