iText.NetでPDFを出力してみる。

iText.NET とは

iText は、Bruno Lowagie 氏と Paulo Soares 氏を中心として作成されている JAVA 用 PDF 生成ライブラリです。MPL/LGPL ライセンスで配布されており、商用ソフトウエアにも使用することができます。iText .NET は、本ライブラリを .NET Framework へ移植したものです。開発言語は、J# です。

使い方は豊富に用意されてるサンプル見りゃわかる。

ってだけでもアレなので。

ドキュメント斜め読み

オブジェクト構造なんかは慣れ親しんだjavadocのが見やすいよねっと。
http://www.1t3xt.info/api/

構造

基本になるオブジェクトはDocument*1でPDF全体を表すと。
データの追加はDocument.add(Element)で、ElementはKnown Implementing Classesを見るとParagraphとかPhrase、Anchorなんかが入ってるのを見るとHtmlをモデルにしてるっぽい感じ。

  Document
   ◆   +----- Header/Footer Authorなどの文書情報
    |
    +-----Element
           △
            +---- Block要素{Paragraph/Section/Chapter など}
            +---- inline要素{Image/Text など}
            

そう見ればJavascriptでDom使いながら要素使うのとたいして違いないなと。

ちょっとトリッキーな構造

HTMLに無くてPDFにある概念としてはページが最たるもんかなと。

ダラダラとデータを出力してる分にはDocumentが勝手に改ページしてくれて特にページを考える必要は無いんだけど、横にでかい表を出したいとかになると特定のページだけ用紙サイズを変えたり用紙の縦横を変えたいなんて要望があったりして。

そんな時にDocument.newPage()なわけだけど、

  public void hoge(){
    Document document = new Document();
    document.setPageSize(PageSize.A4);
    document.open();
    
    foreach (Image image in Images){
      if (image.横長()){
        document.setPageSize(PageSize.A4.rotate());
      }else{
        document.setPageSize(PageSize.A4);
      }
      document.add(image);
      document.newPage();
    }
    document.close();
  }

こんな感じに逐次用紙サイズを設定してもうまいこと行かなかった。

まぁよく考えればDocument.open()/Document.newPage()の時に用紙サイズが決定されてるんで、Document.setPageSize()の後に実行しなきゃならんてのはわかるんだけど。

ただデータ構造がある程度階層化されてるのに、データ出力段階でシーケンシャルに実行する必要があるってのはどうなんだろ。

PDFだけ考えれば

  Document
    +Page
       + Element

なのが良い気もするけど、Sectionみたいな論理単位とPageみたいな物理単位の2系統の階層ができちゃうのか。

まぁこういうもんだって覚えちゃえばいいんだろうけどね。

なんかちょっと納得いかないPdfEncryptor

PDFにパスワードで暗号化するときにPdfEncryptor*2を使うんだけど、interfaceが

 static void encrypt(PdfReader reader, 
                     OutputStream os, 
                     boolean strength, 
                     String userPassword, 
                     String ownerPassword, 
                     int permissions) ;

となってるので、新しく作ったドキュメントを暗号化しようとすると、一度ファイルを経由しないとできないのが若干納得がいかん。
というかPdfReader/Writerの世界とDocumentの世界で繋がってないのか?

Javaで言うとこのFilterOutputStream*3みたいな形か、暗号化自体はドキュメントにかけるんだからDocument.addSecurityToken()みたいな形のが良い気がするんだけどなぁ。

*1:com.lowagie.text.Document

*2:com.lowagie.text.pdf.PdfEncryptor

*3:http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/api/java/io/FilterOutputStream.html