「PDFBox」の版間の差分

提供: 個人的記録
移動: 案内検索
(フォント辞書にFontFile2を設定してみる)
 
(同じ利用者による、間の9版が非表示)
44行目: 44行目:
 
|| B6 || 125×176 || 363×516
 
|| B6 || 125×176 || 363×516
 
|}
 
|}
 +
 +
== 文字列/図形の描画 ==
 +
PDFの文字列や図形はstreamで行う。streamはさまざまなオペレータの集合になっている。イメージ的にはdrawマクロみたいなもの。<br>
 +
streamはページに対し、以下のコードで生成する。
 +
<pre>
 +
PDPageContentStream stream = new PDPageContentStream(PDDocument, PDPage)
 +
</pre>
 +
図形や文字列のPDFのオペレータに対応するメソッドがある。<br>
 +
streamは必ずcloseすること。closeしないと描画が行われない。
 +
=== 文字列の出力 ===
 +
PDFでの文字列の出力は以下の手順で行う。
 +
<pre>
 +
PDPageContentStream stream = new PDPageContentStream(PDDocument, PDPage);
 +
stream.beginText()  //文字列出力の開始を通知
 +
stream.setFont(PDFont,フォントサイズ);  //フォントとサイズの指定。マルチバイト文字を出力する場合、対応するフォントの指定が必須。
 +
stream.moveTextPositionByAmount(横位置, 縦位置);    //文字列を出力する位置の指定。
 +
stream.drawString(文字列);              //文字列の出力
 +
stream.endText();              //文字列出力の終了を通知
 +
</pre>
 +
 +
==== フォントの指定 ====
 +
ASCII文字のみであれば組み込みのtype1フォントで用が足りるが、マルチバイト文字を出力することができない。<br>
 +
マルチバイト文字を出力するにはCIDフォントを設定する必要がある。
 +
<pre>
 +
//日本語文字列であることをしめすPDF辞書を定義
 +
COSDictionary systeminfo = new COSDictionary();
 +
systeminfo.setString(COSName.REGISTRY, "Adobe");
 +
systeminfo.setString(COSName.ORDERING, "Japan1");
 +
systeminfo.setInt(COSName.SUPPLEMENT, 6);
 +
 +
//フォントの書体を設定
 +
PDFontDescriptorDictionary fd = new PDFontDescriptorDictionary();
 +
fd.setFontName("MSゴシック");  //使用するフォント名を指定。フォントの埋め込みはできるのだろうか?
 +
fd.setFlags(4);
 +
fd.setFontBoundingBox(new PDRectangle(new BoundingBox(-500, -300, 1200, 1400)));
 +
fd.setItalicAngle(0);
 +
fd.setAscent(1400);
 +
fd.setDescent(-300);
 +
fd.setCapHeight(700);
 +
fd.setStemV(100);
 +
 +
//日本語CIDフォントを設定する
 +
COSDictionary cid = new COSDictionary();
 +
cid.setItem(COSName.TYPE, COSName.FONT);
 +
cid.setItem(COSName.SUBTYPE, COSName.CID_FONT_TYPE0);
 +
cid.setItem(COSName.BASE_FONT, COSName.getPDFName("KozGoPr6N-Medium"));  //ベースとなるフォント名を指定
 +
cid.setItem(COSName.CIDSYSTEMINFO, systeminfo);  //日本語用のフォントであることを指定
 +
cid.setItem(COSName.FONT_DESC, fd);  //フォントの書体を設定
 +
 +
//フォント設定
 +
COSDictionary font = new COSDictionary();
 +
font.setItem(COSName.TYPE, COSName.FONT);
 +
font.setItem(COSName.SUBTYPE, COSName.TYPE0);
 +
font.setItem(COSName.BASE_FONT, COSName.getPDFName("KozGoPr6N-Medium"));
 +
//文字コードはUCS2にしておく。
 +
//MS932にする場合、埋め込みで「COSName.ENCODING_90MS_RKSJ_H」という定数が用意されている。
 +
font.setItem(COSName.ENCODING, COSName.getPDFName("UniJIS-UCS2-H"));
 +
COSArray array = new COSArray();
 +
array.add(cid);
 +
font.setItem(COSName.DESCENDANT_FONTS, array);
 +
 +
//PDF用type0フォントの生成
 +
PDFont pdFont = new PDType0Font(font);
 +
 +
//ストリームにフォントと出力サイズをセット
 +
stream.setFont(pdFont, 40);
 +
stream.moveTextPositionByAmount(100, 100);  //文字列の出力位置に移動
 +
//drawStringはStringで受けるのだが、latain1の文字しか受け付けない。
 +
//文字列をフォントで指定したエンコードのバイト列に変換し、無理やりISO8859-1に変換して出力する必要がある。
 +
stream.drawString(new String(str.getBytes(Charset.forName("ISO-10646-UCS-2")),"ISO8859-1"));
 +
stream.endText();
 +
stream.close();
 +
</pre>
 +
 +
== 日本語フォントの埋め込み(試行錯誤中) ==
 +
とりあえず、TTFは読み込む手段をPDFBoxに設定されていたのでIPAexゴシックで試行錯誤中。
 +
=== loadTTFでフォントを読み込む ===
 +
<pre>
 +
PDFont pdFont = PDTrueTypeFont.loadTTF(PDDocument, "c:\\windows\\fonts\\ipaexg.ttf");
 +
</pre>
 +
この方法は例外が出て失敗
 +
=== フォント辞書にFontFile2を設定してみる ===
 +
<pre>
 +
PDFontDescriptorDictionary fd = new PDFontDescriptorDictionary();
 +
PDStream fStream = new PDStream(_document,new FileInputStream("c:\\windows\\fonts\\ipaexg.ttf"));
 +
fd.setFontFile2(fStream);
 +
fd.setFontName(new String("IPAexゴシック".getBytes("MS932"),"ISO8859-1")); //MS932のバイト列に直して書かないと名前がちゃんとしない
 +
</pre>
 +
この方法ではフォントの埋め込みもできているが、文字化けする。<br>
 +
化けた文字列をコピペでエディタにはるとちゃんとしているので、コードポイントとグリフがずれているっぽい。
 +
 +
http://blogs.yahoo.co.jp/bardiel_of_may/62498946.html
 +
 +
ここを参考にグリフの確認をしてみる予定。
 +
 +
=== Encoding をいじってみる ===
 +
PDFontに設定するEncodingとdrawStringで変換するエンコーディングをいろいろといじってみた。
 +
{| class="wikitable" style="width: 20em;"
 +
|-
 +
!PDFont||drawString||結果
 +
|-
 +
|Identity-H||UCS2||表示されない
 +
|-
 +
|Identity-H||MS932||表示されない
 +
|-
 +
|UniJIS-UCS2-H||UCS2||表示されるがグリフとコードポイントがずれる
 +
|-
 +
|90MS_RKSJ_H||MS932||表示されるがグリフとコードポイントがずれる
 +
|}
 +
 +
[[TTF]]からcmapテーブルを引っこ抜いて、to_unicodeを設定するしかないのか?
  
 
= 参考にしたサイト =
 
= 参考にしたサイト =
 
* http://labs.uchicom.com/pdfbox/
 
* http://labs.uchicom.com/pdfbox/
 
* http://d.hatena.ne.jp/seuzo/20090403/1238742091
 
* http://d.hatena.ne.jp/seuzo/20090403/1238742091
 +
 +
= コメント =
 +
<comments/>

2014年1月15日 (水) 13:39時点における最新版

Apache FoundationのPDF生成ライブラリ。
このページは1.8.3準拠で記述しています。
ライセンス

APL

本家サイト

http://pdfbox.apache.org/

Mavenでの導入

本家にもあるけど、今回はdependencyに以下を記述。

<dependency>
	<groupId>org.apache.pdfbox</groupId>
	<artifactId>pdfbox</artifactId>
	<version>1.8.3</version>
</dependency>

使い方

PDFページを追加する。

以下のコードで空白のページを追加することができる。
PDRectangleでページサイズを指定できるが、単位がポイントなのに注意(1ポイント=0.353mm)

PDDocument doc = new PDDocument();
PDRectangle rec = new PDRectangle(幅,高さ);
doc.addPage(new Page(rec));
doc.save("出力先.pdf");
doc.close();

紙のサイズとおおよそのポイント

紙サイズ変換表
サイズ mm表記 ポイント表記
A3 297×427 842×1191
A4 210×297 595×842
A5 148×210 420×595
B4 250×353 729×1032
B5 176×250 516×729
B6 125×176 363×516

文字列/図形の描画

PDFの文字列や図形はstreamで行う。streamはさまざまなオペレータの集合になっている。イメージ的にはdrawマクロみたいなもの。
streamはページに対し、以下のコードで生成する。

PDPageContentStream stream = new PDPageContentStream(PDDocument, PDPage)

図形や文字列のPDFのオペレータに対応するメソッドがある。
streamは必ずcloseすること。closeしないと描画が行われない。

文字列の出力

PDFでの文字列の出力は以下の手順で行う。

PDPageContentStream stream = new PDPageContentStream(PDDocument, PDPage);
stream.beginText()   //文字列出力の開始を通知
stream.setFont(PDFont,フォントサイズ);   //フォントとサイズの指定。マルチバイト文字を出力する場合、対応するフォントの指定が必須。
stream.moveTextPositionByAmount(横位置, 縦位置);    //文字列を出力する位置の指定。
stream.drawString(文字列);               //文字列の出力
stream.endText();              //文字列出力の終了を通知

フォントの指定

ASCII文字のみであれば組み込みのtype1フォントで用が足りるが、マルチバイト文字を出力することができない。
マルチバイト文字を出力するにはCIDフォントを設定する必要がある。

//日本語文字列であることをしめすPDF辞書を定義
COSDictionary systeminfo = new COSDictionary();
systeminfo.setString(COSName.REGISTRY, "Adobe");
systeminfo.setString(COSName.ORDERING, "Japan1");
systeminfo.setInt(COSName.SUPPLEMENT, 6);

//フォントの書体を設定
PDFontDescriptorDictionary fd = new PDFontDescriptorDictionary();
fd.setFontName("MSゴシック");   //使用するフォント名を指定。フォントの埋め込みはできるのだろうか?
fd.setFlags(4);
fd.setFontBoundingBox(new PDRectangle(new BoundingBox(-500, -300, 1200, 1400)));
fd.setItalicAngle(0);
fd.setAscent(1400);
fd.setDescent(-300);
fd.setCapHeight(700);
fd.setStemV(100);

//日本語CIDフォントを設定する
COSDictionary cid = new COSDictionary();
cid.setItem(COSName.TYPE, COSName.FONT);
cid.setItem(COSName.SUBTYPE, COSName.CID_FONT_TYPE0);
cid.setItem(COSName.BASE_FONT, COSName.getPDFName("KozGoPr6N-Medium"));  //ベースとなるフォント名を指定
cid.setItem(COSName.CIDSYSTEMINFO, systeminfo);  //日本語用のフォントであることを指定
cid.setItem(COSName.FONT_DESC, fd);  //フォントの書体を設定

//フォント設定
COSDictionary font = new COSDictionary();
font.setItem(COSName.TYPE, COSName.FONT);
font.setItem(COSName.SUBTYPE, COSName.TYPE0);
font.setItem(COSName.BASE_FONT, COSName.getPDFName("KozGoPr6N-Medium"));
//文字コードはUCS2にしておく。
//MS932にする場合、埋め込みで「COSName.ENCODING_90MS_RKSJ_H」という定数が用意されている。
font.setItem(COSName.ENCODING, COSName.getPDFName("UniJIS-UCS2-H"));
COSArray array = new COSArray();
array.add(cid);
font.setItem(COSName.DESCENDANT_FONTS, array);

//PDF用type0フォントの生成
PDFont pdFont = new PDType0Font(font);

//ストリームにフォントと出力サイズをセット
stream.setFont(pdFont, 40);
stream.moveTextPositionByAmount(100, 100);  //文字列の出力位置に移動
//drawStringはStringで受けるのだが、latain1の文字しか受け付けない。
//文字列をフォントで指定したエンコードのバイト列に変換し、無理やりISO8859-1に変換して出力する必要がある。
stream.drawString(new String(str.getBytes(Charset.forName("ISO-10646-UCS-2")),"ISO8859-1"));
stream.endText();
stream.close();

日本語フォントの埋め込み(試行錯誤中)

とりあえず、TTFは読み込む手段をPDFBoxに設定されていたのでIPAexゴシックで試行錯誤中。

loadTTFでフォントを読み込む

PDFont pdFont = PDTrueTypeFont.loadTTF(PDDocument, "c:\\windows\\fonts\\ipaexg.ttf");

この方法は例外が出て失敗

フォント辞書にFontFile2を設定してみる

PDFontDescriptorDictionary fd = new PDFontDescriptorDictionary();
PDStream fStream = new PDStream(_document,new FileInputStream("c:\\windows\\fonts\\ipaexg.ttf"));
fd.setFontFile2(fStream);
fd.setFontName(new String("IPAexゴシック".getBytes("MS932"),"ISO8859-1")); //MS932のバイト列に直して書かないと名前がちゃんとしない

この方法ではフォントの埋め込みもできているが、文字化けする。
化けた文字列をコピペでエディタにはるとちゃんとしているので、コードポイントとグリフがずれているっぽい。

http://blogs.yahoo.co.jp/bardiel_of_may/62498946.html

ここを参考にグリフの確認をしてみる予定。

Encoding をいじってみる

PDFontに設定するEncodingとdrawStringで変換するエンコーディングをいろいろといじってみた。

PDFont drawString 結果
Identity-H UCS2 表示されない
Identity-H MS932 表示されない
UniJIS-UCS2-H UCS2 表示されるがグリフとコードポイントがずれる
90MS_RKSJ_H MS932 表示されるがグリフとコードポイントがずれる

TTFからcmapテーブルを引っこ抜いて、to_unicodeを設定するしかないのか?

参考にしたサイト

コメント

コメント: