iText-2.0.4.jar だけでも PDF は作成できるが、日本語フォントが描画できない。

iText, a JAVA-PDF library - ExtraJars1.0 にて iTextAsianCmaps.jar と iTextAsian.jar をダウンロードして実行時にクラスパスに含めるようにすれば日本語フォントが使える。

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

ついでに、いろいろなアフィン変換も試しまくり。


import java.awt.geom.*;
import java.io.*;
 
import com.lowagie.text.*;
import com.lowagie.text.pdf.*;
 
// iTextAsian.jar で日本語フォント
// アフィン変換いろいろ
public class PdfInPdfSample {
 
  public static void main(String[] args) throws Exception {
 
    byte[] a7 = createA7();
    byte[] a4 = createA4(a7);
    
    out(a7, "20070802_a7.pdf");
    out(a4, "20070802_a4.pdf");
  }
  
  private static byte[] createA7() throws Exception {
    
    // iTextで日本語を使うためには iTextAsian.jar が必要とのこと
    
    // http://itextdocs.lowagie.com/tutorial/fonts/getting/
    // iText Tutorial: Getting fonts
    // 
    // > Fonts from jars (and font packs):
    // > CID fonts are Postscript-based fonts which can support a large number of characters (65,536 max). The format is often used for CJK fonts (CJK = Chinese Japanese Korean). CID format makes it possible to change the character order (encoding) of a font through the use of character-to-glyph tables (CMaps) which are external to the font.
    // > If you want to use CJK fonts in iText, you need an extra jar: iTextAsian.jar. If you want to be able to read the text you generated with iText using CJK fonts, you will also need to download and install a special font pack for Acrobat Reader (or maybe your Reader will ask you to install such a font pack upon opening a PDF file with CJK fonts). For the rest, creating a CJK font supported by the iTextAsian.jar is as easy as using any other font:
    // > 
    // > BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
    // > Font FontChinese = new Font(bfChinese, 12, Font.NORMAL);
    // > Paragraph p = new Paragraph(chinese, FontChinese);
    // > document.add(p);
    // 
    // > This is the list of fonts supported in the iTextAsian.jar:
    // > 
    // >  * Chinese Simplified:
    // >  STSong-Light and STSongStd-Light with the encodings UniGB-UCS2-H and UniGB-UCS2-V
    // >  * Chinese Traditional:
    // >  MHei-Medium, MSung-Light and MSungStd-Light with the encodings UniCNS-UCS2-H and UniCNS-UCS2-V
    // >  * Japanese:
    // >  HeiseiMin-W3, HeiseiKakuGo-W5 and KozMinPro-Regular with the encodings UniJIS-UCS2-H, UniJIS-UCS2-V, UniJIS-UCS2-HW-H and UniJIS-UCS2-HW-V
    // >  * Korean:
    // >  HYGoThic-Medium, HYSMyeongJo-Medium and HYSMyeongJoStd with the encodings UniKS-UCS2-H and UniKS-UCS2-V
    // 
    // > CID fonts
    // > But that's not all, there is also an extra jar iTextAsianCmaps.jar. It contains the cmaps for lots of other CID fonts. This is how you can use them:
    // > 
    // > PdfEncodings.loadCmap(
    // >   "GBK2K-H",
    // >   PdfEncodings.CRLF_CID_NEWLINE); // needs to be done only once
    // > byte text[] = my_GB_encoded_text;
    // > String cid = PdfEncodings.convertCmap("GBK2K-H", text);
    // > BaseFont bf = BaseFont.createFont("STSong-Light", "Identity-H", false);
    // > Paragraph p = new Paragraph(cid, new Font(bf, 14));
    // > document .add(p);
 
    // iTextAsian.jar 内 \com\lowagie\text\pdf\fonts にあったファイル一覧
    // 
    // Adobe-CNS1-UCS2.cmap
    // Adobe-GB1-UCS2.cmap
    // Adobe-Japan1-UCS2.cmap
    // Adobe-Korea1-UCS2.cmap
    // cjkencodings.properties
    // cjkfonts.properties
    // HeiseiKakuGo-W5.properties
    // HeiseiMin-W3.properties
    // HYGoThic-Medium.properties
    // HYSMyeongJo-Medium.properties
    // HYSMyeongJoStd-Medium.properties
    // KozMinPro-Regular.properties
    // MHei-Medium.properties
    // MSung-Light.properties
    // MSungStd-Light.properties
    // STSong-Light.properties
    // STSongStd-Light.properties
    // UniCNS-UCS2-H.cmap
    // UniCNS-UCS2-V.cmap
    // UniGB-UCS2-H.cmap
    // UniGB-UCS2-V.cmap
    // UniJIS-UCS2-H.cmap
    // UniJIS-UCS2-HW-H.cmap
    // UniJIS-UCS2-HW-V.cmap
    // UniJIS-UCS2-V.cmap
    // UniKS-UCS2-H.cmap
    // UniKS-UCS2-V.cmap
 
    // 明朝体 KozMinPro-Regular
    Font font1 = new Font(
      BaseFont.createFont(
        "KozMinPro-Regular", "UniJIS-UCS2-H", BaseFont.NOT_EMBEDDED),
        10, Font.UNDERLINE);
    
    // 明朝体 HeiseiMin-W3
    Font font2 = new Font(
      BaseFont.createFont(
        "HeiseiMin-W3", "UniJIS-UCS2-V", BaseFont.NOT_EMBEDDED),
        11, Font.NORMAL);
    
    // ゴシック体 HeiseiKakuGo-W5
    Font font3 = new Font(
      BaseFont.createFont(
        "HeiseiKakuGo-W5", "UniJIS-UCS2-HW-H", BaseFont.NOT_EMBEDDED),
        12, Font.ITALIC);
 
    // ゴシック体 HeiseiKakuGo-W5
    Font font4 = new Font(
      BaseFont.createFont(
        "HeiseiKakuGo-W5", "UniJIS-UCS2-HW-V", BaseFont.NOT_EMBEDDED),
        13, Font.BOLD);
    
    // DPI
    float dpi = 72.0f;
    
    // A7作成
    ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
    Rectangle pagesize2 = PageSize.A7;
    // 左端のマージン: 5ミリメートル
    // 右端のマージン: 10ミリメートル
    // 上端のマージン: 5ミリメートル
    // 下端のマージン: 10ミリメートル
    float left = mm2pixel(1f, dpi);
    float right = mm2pixel(5f, dpi);
    float top = mm2pixel(5f, dpi);
    float bottom = mm2pixel(10f, dpi);
    Document document2 = new Document(pagesize2, left, right, top, bottom);
    PdfWriter writer2 = PdfWriter.getInstance(document2, baos2);
    document2.open();
    String text1 = "This is a paragraph.";
    Paragraph p1 = new Paragraph(text1, font1);
    p1.setAlignment(Paragraph.ALIGN_CENTER);
    document2.add(p1);
    String text2 = "これはパラグラフです。";
    Paragraph p2 = new Paragraph(text2, font2);
    document2.add(p2);
    String text3 = "あいうえおアイウエオABCABC";
    Paragraph p3 = new Paragraph(text3, font3);
    document2.add(p3);
    String text4 = "亜米利加伊太利亜独逸腐乱す";
    Paragraph p4 = new Paragraph(text4, font4);
    document2.add(p4);
    //PdfTemplate pdftmp = PdfTemplate.createTemplate(writer2, PageSize.A7.width(), PageSize.A7.height());
    PdfContentByte pcb2 = writer2.getDirectContent();
    java.awt.Graphics2D g2 = pcb2.createGraphics(pagesize2.getWidth(), pagesize2.getHeight());
    g2.setStroke(new java.awt.BasicStroke(4.0f));
    g2.setPaint(new java.awt.Color(0, 255, 0, 126));
    g2.fill(new Rectangle2D.Double(0, 0, pagesize2.getWidth() / 2, pagesize2.getHeight() / 2));
    g2.draw(new Rectangle2D.Double(0, 0, pagesize2.getWidth(), pagesize2.getHeight()));
    g2.dispose(); // dispose を忘れないで
    document2.close(); // close を忘れないで
    return baos2.toByteArray();
  }
  
  private static byte[] createA4(byte[] a7) throws Exception{
    
    PdfReader pr = new PdfReader(a7);
 
    // A4作成
    Rectangle pagesize = PageSize.A4;
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    Document document = new Document(pagesize, 0, 0, 0, 0);
    PdfWriter writer = PdfWriter.getInstance(document, baos);
    document.open();
    PdfContentByte pcb = writer.getDirectContent();
    PdfImportedPage page = writer.getImportedPage(pr, 1);
    
    java.awt.Graphics2D g = pcb.createGraphics(pagesize.getWidth(), pagesize.getHeight());
    g.setColor(java.awt.Color.RED);
    int w = (int)pagesize.getWidth();
    int h = (int)pagesize.getHeight();
    g.drawLine(0, 0, w, h);
    g.drawLine(w/4, 0, w/4, h);
    g.drawLine(w/2, 0, w/2, h);
    g.drawLine(3*w/4, 0, 3*w/4, h);
    g.drawLine(0, h/4, w, h/4);
    g.drawLine(0, h/2, w, h/2);
    g.drawLine(0, 3*h/4, w, 3*h/4);
    g.drawOval(w/4-5, h/2-5, 10, 10);
    g.drawString("Center of Rotate", w/4, h/2);
    g.dispose(); // dispose を忘れずに
 
    pcb.saveState(); // 状態を保存
    
    // 左下に載せ
    // PDF は左下が原点
    pcb.addTemplate(page,0,0);
 
    // 右上に載せ
    // concatCTM でアフィン変換連結
    float tx = pagesize.getWidth() - page.getWidth();
    float ty = pagesize.getHeight() - page.getHeight();
    pcb.concatCTM(1f, 0f, 0f, 1f, tx, ty);
    pcb.addTemplate(page,0,0);
    // saveState で保存しておいた状態に戻す。
    // concatCTM を逆にかけるという手もあるけど
    pcb.restoreState();
    //pcb.concatCTM(1f, 0f, 0f, 1f, -tx, -ty);
    pcb.saveState(); // 連続でrestoreできないので、saveState で状態を保存
 
    // 回転させ載せ
    for(int i=1; i<=3; i++){
      // PdfContentByte#transform でアフィン変換連結
      double x = pagesize.getWidth()  / 4.0;
      double y = pagesize.getHeight() / 2.0;
      AffineTransform at = AffineTransform.getRotateInstance(Math.toRadians(60*i), x, y);
      pcb.transform(at); // concatCTM と同じような
      pcb.addTemplate(page,0,0);
      pcb.restoreState();
      pcb.saveState(); // 連続でrestoreできないので、saveState で状態を保存
    }
     
    document.close(); // close を忘れないで
 
    return baos.toByteArray();
  }
  
  private static float mm2pixel(float mm, float dpi){
    // Ref. http://ja.wikipedia.org/wiki/%E3%82%A4%E3%83%B3%E3%83%81
    // 国際インチ(international inch): 1 インチ = 25.4 ミリメートル
    return mm * dpi / 25.4f;
  }
  
  private static void out(byte[] pdfdata, String file) throws Exception {
    OutputStream os =
      new BufferedOutputStream(
        new FileOutputStream(file));
    os.write(pdfdata);
    os.flush();
  }
  
}

出力したPDFファイル2つ
-20070802_a7.pdf
-20070802_a4.pdf

tags: zlashdot Java Java PDF iText

Posted by NI-Lab. (@nilab)