2007年12月21日金曜日

pdf-rendererを試してみる

InfoQ: SunがオープンソースPDF Rendererをリリース

との事なので、JWSでSwingなアプリからもわざわざブラウザを起動すること無くアプリ内でPDFを開けるよぅになったはず!ってワケで試してみる。pdf-rendererはdownloadしてclasspathに追加されている事が前提。また、適当なPDFファイルを用意しておく。
public class Main {
  public static void main(String[] args) {
    java.io.File file = new java.io.File(args[0]);
    com.sun.pdfview.PDFFile pdfFile = null;
    java.nio.channels.FileChannel channel = null;
    try {
      channel = new java.io.RandomAccessFile(file, "r").getChannel();
      pdfFile = new com.sun.pdfview.PDFFile(channel.map(
          java.nio.channels.FileChannel.MapMode.READ_ONLY, 0, channel
              .size()));
      System.out.println("getNumPages() = " + pdfFile.getNumPages());
    } catch (java.io.IOException ex) {
      ex.printStackTrace();
    }
  }
}
これだと単にPDFのページ数を表示するだけだが、第一引数にpdfファイル名を指定してやるとページ数が正しく表示される。ちゃんと読めてるよぅだ!後は表示の時に、pdfの鬼門である「日本語」が大丈夫か?Frameを使って表示してみる。
@SuppressWarnings("serial")
public class MyFrame extends javax.swing.JFrame implements
    java.awt.image.ImageObserver, Runnable {

  public static void main(String[] args) {
    java.io.File file = new java.io.File(args[0]);
    com.sun.pdfview.PDFFile pdfFile = null;
    java.nio.channels.FileChannel channel = null;
    try {
      channel = new java.io.RandomAccessFile(file, "r").getChannel();
      pdfFile = new com.sun.pdfview.PDFFile(channel.map(
          java.nio.channels.FileChannel.MapMode.READ_ONLY, 0, channel
              .size()));
      new MyFrame(pdfFile).setVisible(true);
    } catch (java.io.IOException ex) {
      ex.printStackTrace();
    }
  }

  public MyFrame(com.sun.pdfview.PDFFile pdfFile) {
    setDefaultCloseOperation(DISPOSE_ON_CLOSE);
    setLayout(new java.awt.BorderLayout());
    setTitle("pdf-renderer");
    javax.swing.JTabbedPane tabbedPane = new javax.swing.JTabbedPane();
    tabbedPane
        .setTabLayoutPolicy(javax.swing.JTabbedPane.SCROLL_TAB_LAYOUT);
    this.pdfFile = pdfFile;
    numPages = pdfFile.getNumPages();
    images = new java.awt.Image[numPages];
    panels = new PDFPagePanel[numPages];

    for (int i = 0; i < numPages; i++) {
      panels[i] = new PDFPagePanel();
      javax.swing.JScrollPane scrollPane = new javax.swing.JScrollPane();
      scrollPane.getViewport().add(panels[i]);
      tabbedPane.addTab(String.format("page:%03d/%03d", new Object[] {
          (i + 1), numPages }), scrollPane);
      System.out.println("create panel:" + panels[i].toString());
    }
    getContentPane().add(tabbedPane, java.awt.BorderLayout.CENTER);
    new Thread(this).start();
    tabbedPane.setPreferredSize(new java.awt.Dimension(800, 600));
    pack();
  }

  com.sun.pdfview.PDFFile pdfFile;

  int numPages;

  PDFPagePanel[] panels;

  java.awt.Image[] images;

  public void run() {
    for (int i = 0; i < numPages; i++) {
      com.sun.pdfview.PDFPage pdfPage = pdfFile.getPage(i);
      panels[i].setPdfPage(pdfPage);
    }
  }

  @SuppressWarnings("serial")
  class PDFPagePanel extends javax.swing.JPanel implements
      java.awt.image.ImageObserver {
    com.sun.pdfview.PDFPage pdfPage;

    java.awt.Image image;

    public void paint(java.awt.Graphics g) {
      if (image != null) {
        g.setColor(java.awt.Color.gray);
        int width = getWidth();
        g.fillRect(0, 0, width, getHeight());
        g.drawImage(image, 0, 0, this);
      }
    }

    public void setPdfPage(com.sun.pdfview.PDFPage pdfPage) {
      this.pdfPage = pdfPage;
      image = pdfPage.getImage((int) pdfPage.getWidth(), (int) pdfPage
          .getHeight(), null, this, true, true);
      System.out.println(image.toString());
    }
  }
}
ちょっと長いけど、重要な部分は少しだけ。実行すると、日本語も問題なく表示できた!これは便利なんじゃね!? ついでに余談。これを試した環境が「3D機能を有効にしたUbuntu」だったのだが、この環境では「SwingのBorderLayoutが画面リサイズに対応できていない」という現象が出てはまった。画面効果をOffにするとちゃんとリサイズ対応してくれた。こういうのは知らないとマジではまる。
コメントを投稿