SwingでPDF Rendererを利用する

PDF Rendererを使う最大のメリットは、PDF文書の内容を手軽にjava.awt.Imageオブジェクトとして取り扱える点である。ImageオブジェクトであればAWT/SwingなどのGUIアプリケーションにも簡単に取り込むことができるし、3Dオブジェクトのテクスチャイメージとして利用することもできる。Imageオブジェクトを取得する手順としては、まずPDFファイルの内容をPDFFileオブジェクトとして読み込み、次のようにgetPage()メソッドを実行する。

リスト1

PDFPage pdfPage = pdfFile.getPage(1);

getPage()メソッドは引数としてページ番号を受け取り、そのページの内容をPDFPageオブジェクトとして返す。PDFPageオブジェクトは、ページの高さや幅、縦横の向き、ページ番号などの情報を含んでいる。PDFPageからは、getImage()メソッドを実行することでそのページ全体を画像として見た場合のImageオブジェクトを生成することができる。getImage()には以下の6つの引数を渡す。

  1. イメージの幅
  2. イメージの高さ
  3. 紙面領域を表すRectangle2Dオブジェクト
  4. イメージの変更の通知を受け取るためのImageObserverオブジェクト
  5. 背景を白で埋めるか否か(trueならば白を描画し、falseならば何も描画しない)
  6. イメージをすべてレンダリングするまでメソッドのreturnを待つか否か(trueならば待ち、falseならばreturnする)

以下に示すgenerateImageFromPdfPage()メソッドは、PDFPageオブジェクトを受け取り、Imageオブジェクトを生成して返すメソッドの例である。

リスト2

private Image generateImageFromPdfPage(PDFPage page) {
    Rectangle2D rect = page.getBBox();
    int width = (int)rect.getWidth();
    int height = (int)rect.getHeight();
    // Imageオブジェクトの取得
    Image img = page.getImage(width, height, rect, null, true, true);
    return img;
}

PDFPageクラスのgetBBox()メソッドは、ページのバウンディングボックス、すなわち描画領域をjava.awt.geom.Rectangle2Dオブジェクトとして返すメソッドである。この例では、そこから取得した領域の幅と高さをgetImage()の第1、第2引数に、Rectangle2Dオブジェクトそのものを第3引数に指定している。

このgenerateImageFromPdfPage()メソッドを利用してPDF文書を描画するSwingプログラムの例を以下に示す。このコードはMyPdfViewerクラスのコンストラクタとして作成したもの。

リスト3

public MyPdfViewer() throws IOException {
    // PDFファイルの読み込み
    RandomAccessFile raf = new RandomAccessFile(new File("samplefile.pdf"), "r");
    FileChannel channel = raf.getChannel();
    ByteBuffer buf = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
    PDFFile pdfFile = new PDFFile(buf);

    // ページ数の取得
    int numpages = pdfFile.getNumPages();

    // ウィンドウの描画
    JFrame frame = new JFrame("MyPdfViewer");
    frame.setSize(630, 750);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JPanel panel = new JPanel(new GridLayout(0,1));
    JScrollPane scrollPane = new JScrollPane(panel);

    // Imageオブジェクトの生成
    for (int i=1; i <= numpages; i++) {
    PDFPage pdfPage = pdfFile.getPage(i);
    Image img = generateImageFromPdfPage(pdfPage);
    panel.add(new JLabel(new ImageIcon(img)));
    }

    frame.add(scrollPane);
    frame.setVisible(true);
}

PDFFileクラスのgetNumPages()メソッドは、PDF文書のページ数を返すメソッドである。このプログラムでは、読み込んだPDFファイルから順番に各ページのImageオブジェクトを生成し、それぞれJLabelに貼り付けてJPanel上に配置している。

このコンストラクタを呼び出すmain()メソッドは、SwingUtilitiesクラスのinvokeLater()メソッドを利用して次のようにした。

リスト4

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
                try {
                    MyPdfViewer viewer = new MyPdfViewer();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        });
}

このプログラムをコンパイルして実行すると図1のように表示される。PDFファイルの内容が、全ページ縦に並んで表示されていることがわかる。

図1 MyPdfViewer.javaの実行例

Java 3DでPDF Rendererを利用する

続いてJava 3Dを使った3D画像の中にPDFファイルを取り込んでみよう。Java 3Dの利用に必要なライブラリはこのサイトより入手することができる。Java 3Dの使用法などの解説は本筋ではないため省略するが、基本的には3Dキャンバス上に3Dオブジェクトを配置し、そこにテクスチャを貼り付けることで3D画像を作ることができる。Java3Dの場合、テクスチャ画像を読み込むためにTextureLoaderというクラスが用意されており、Imageオブジェクトを指定しての画像の読み込みもサポートしている。したがって、PDF Rendererを使って生成したImageオブジェクトをTextureLoaderで読み込ませれば、3DオブジェクトのテクスチャとしてPDFの内容を貼り付けることができるというわけだ。

Java 3DとPDF Rendererを利用してPDFファイルをテクスチャ画像として読み込むコードは次のようになる。

リスト5

PDFPage pdfPage = pdfFile.getPage(3);
Image img = generateImageFromPdfPage(pdfPage);

TextureLoader tLoader
    = new TextureLoader(img, universe.getCanvas());
Texture texture = tLoader.getTexture();
Appearance ap = new Appearance();
ap.setTexture(texture);

図2は3Dオブジェクトの平面部分に、テクスチャを利用してPDFの内容を貼り付けた例である。

図2 3DオブジェクトにPDFの内容を貼り付けた例

一方、図3は球状の3Dオブジェクトの表面にPDFの内容を表示した例だ。球オブジェクトの描画にはJava3Dに用意されたShpereクラスを利用している。

図3 球オブジェクトの表面にPDFを表示した例

以上のように、PDF Rendererを利用すればGUIプログラム中に簡単にPDF文書を取り込んで表示することができるようになる。PDFファイルの中身を描画するだけの機能を持ったシンプルなライブラリではあるが、うまく活用することでアプリケーションの描画能力を向上させることができるだろう。