まず、bouncycastle.org - latest releases から暗号化に必要な bcprov-jdk15-137.jar をダウンロードしてクラスパスに含める。


サンプルソースコード(PdfMoreInfoSample.java)

PDFのプロパティ指定と暗号化のサンプル。


import java.io.*;
import java.util.*;
 
import com.lowagie.text.*;
import com.lowagie.text.pdf.*;
 
public class PdfMoreInfoSample {
 
  public static void main(String[] args) {
 
    try {
      // 適当にPDFデータを作る
      byte[] pdfdata = createPdfData("hello");
      
      // PDFデータのプロパティを表示
      HashMap moreinfo = getMoreInfo(pdfdata);
      for (Iterator it = moreinfo.keySet().iterator(); it.hasNext();) {
        Object key = it.next();
        Object val = moreinfo.get(key);
        System.out.println(key + "=" + val);
        // 以下のようなデータが出力される
        // ModDate=D:20070401010203+09'00'
        // Producer=iText 2.0.4 (by lowagie.com)
        // CreationDate=D:20070401010203+09'00'
      }
      
      // PDFのプロパティ情報を構築
      // 値には文字列しか入れられない(ClassCastExceptionが発生したり)
      HashMap addedMoreInfo = new HashMap();
      
      // 文書のタイトル
      addedMoreInfo.put(new String("Title"), "the Title");
      
      // 著者
      addedMoreInfo.put("Author", "the Author");
      
      // PDF文書の主題
      addedMoreInfo.put("Subject", "the Subject");
      
      // キーワード
      addedMoreInfo.put("Keywords", "the Keywords");
      
      // リソースを作成したツール名称
      addedMoreInfo.put("Creator", "the Creator");
      
      // PDF文書を作成したツール名称(iTextのドキュメントには変更しないことが推奨されていた)
      // PdfDocument クラスのソースコード(version 2.0.4)には
      // "you can not change the name of the producer" とあるが……
      addedMoreInfo.put("Producer", "the Producer");
      
      // PDF文書の作成日
      // PdfDocument クラスのソースコード(version 2.0.4)には
      // "you can not set the creation date, only reset it" とあるが……
      addedMoreInfo.put("CreationDate", "2011/11/11 11:11:11");
      // PdfDate クラスを使う必要はない(むしろイマイチよくない)
      // Calendar cdcal = Calendar.getInstance();
      // cdcal.set(2011, Calendar.APRIL, 5, 6, 7, 8);
      // PdfDate cd = new PdfDate(cdcal);
      // addedMoreInfo.put("CreationDate", cd.getW3CDate());
      // 実は、日時以外も設定可能
      // addedMoreInfo.put("CreationDate", "abcde");
      
      // PDF文書の最終修正日
      addedMoreInfo.put("ModDate", "2012/12/12 12:12:12");
      
      // PDFデータにプロパティとPDFのバージョンを設定
      pdfdata = setMoreInfo(pdfdata, addedMoreInfo, PdfWriter.VERSION_1_2);
      
      // パスワード制限は最後に設定すること
      // setMoreInfo で制限が解除されてしまう
      pdfdata = setEncryption(pdfdata, "hogehoge");
      
      // PDFをファイルへ出力
      out(pdfdata, "20070802_moreinfo.pdf");
      
    } catch (Exception e) {
      e.printStackTrace();
    }
 
  }
 
  private static byte[] createPdfData(String text) throws Exception {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    Document document = new Document(PageSize.A4);
    PdfWriter writer = PdfWriter.getInstance(document, baos);
    document.open();
    Paragraph p = new Paragraph(text);
    document.add(p);
    writer.close();
    document.close();
    byte[] pdf = baos.toByteArray();
    return pdf;
  }
 
  static HashMap getMoreInfo(byte[] pdfdata) throws Exception {
    PdfReader reader = new PdfReader(pdfdata);
    HashMap baseInfo = reader.getInfo();
    reader.close();
    return baseInfo;
  }
 
  // PDF文書プロパティ指定
  static byte[] setMoreInfo(byte[] pdfdata, HashMap info, char version) throws Exception {
    PdfReader reader = new PdfReader(pdfdata);
    HashMap baseInfo = reader.getInfo();
    baseInfo.putAll(info);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    // PdfStamper には setThumbnail とか setTransition とかおもしろそうなメソッドが用意されている
    PdfStamper pdfStamper = new PdfStamper(reader, baos, version);
    pdfStamper.setMoreInfo(baseInfo);
    pdfStamper.close();
    reader.close();
    return baos.toByteArray();
  }
 
  // 暗号化
  static byte[] setEncryption(byte[] pdfdata, String password)
      throws Exception {
    PdfReader reader = new PdfReader(pdfdata);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    PdfStamper pdfStamper = new PdfStamper(reader, baos);
    // 印刷だけ許可&パスワード設定
    pdfStamper.setEncryption(true, null, password, PdfWriter.AllowPrinting);
    pdfStamper.close();
    reader.close();
    return baos.toByteArray();
  }
 
  private static void out(byte[] pdfdata, String file) throws Exception {
    OutputStream os = new BufferedOutputStream(new FileOutputStream(file));
    os.write(pdfdata);
    os.flush();
  }
 
}

出力したPDFファイル → 20070802_moreinfo.pdf

このPDFファイルを Adobe Reader で開いて、メニューから [ファイル] -> [プロパティ] -> [セキュリティ]タブにて、「印刷」だけ許可されるようになっているのが確認できる。
また、[ファイル] -> [プロパティ] -> [概要]タブにて、プロパティ情報がソースコードで指定されているものになっているのが確認できる。

PDFファイルの情報(プロパティ)

「文書のプロパティ(Document Properties)」の項目についてメモ。
この情報は Adobe Reader ならば [ファイル] -> [文書のプロパティ] からみることできる。

日本語版用語(英語版用語) : 値のサンプル日本語版 : 値のサンプル英語版
という感じで項目を羅列してみた。
英語版での表記は Google で画像検索してみつけたものを転記。


概要(Description)
------------------------------------------------------------------------------
ファイル(File) : test.pdf
タイトル(Title) : The test
作成者(Author) : Test Man
サブタイトル(Subject): for test
キーワード(Keywords): test, pdf, acrobat
作成日時(Created): 2007/04/01 01:02:03 : 4/01/2007 01:02:03 AM
更新日時(Modified) : 2007/04/01 01:02:03 : 4/01/2007 01:02:03 AM
アプリケーション(Application): Adobe Page Maker 7.0
------------------------------------------------------------------------------

詳細情報(Advanced)
------------------------------------------------------------------------------
PDF変換(PDF Producer): iText 1.4 (by lowagie.com)
PDFのバージョン(PDF Version): 1.4 (Acrobat 5.x)
場所(Location): C:\test\
ファイルサイズ(File Size):  2.32MB (2,430,581バイト) : 513.88 KB (526,212 Bytes)
用紙サイズ(Page Size) : 297 x 210 mm : 8.50 x 11.00 in
タグ付きPDF(Tagged PDF) : いいえ : No
ページ数(Number of Pages) : 1 : 2
Web表示用に最適化: いいえ : Yes
------------------------------------------------------------------------------

Ref. セマンティック・ウェブのコンシェルジュ - XMP(Extensible Metadata Platform) -Adobeが提唱する文書情報規格

tags: zlashdot Java Java PDF iText

Posted by NI-Lab. (@nilab)