Symfoware

Symfowareについての考察blog

Apache PDFBox 出力する文字列の幅、高さを取得する

Apache PDFBox 2.0系のスナップショットで、
出力する文字の幅や高さを取得する方法をメモしておきます。


文字の幅



文字列の幅はPDFontのgetStringWidthで取得できます。


  1. import org.apache.pdfbox.pdmodel.font.PDFont;
  2. import org.apache.pdfbox.pdmodel.font.PDType1Font;
  3. public class Sample {
  4.     public static void main(String... args) throws Exception {
  5.         
  6.         // フォント作成
  7.         PDFont font = PDType1Font.TIMES_ROMAN;
  8.         // 文字の幅を取得
  9.         System.out.println(font.getStringWidth("123456"));
  10.     }
  11. }




出力結果は以下のとおり。


3000.0




これがそのまま幅になるわけではなく、フォントサイズを乗じて1000で割ります。

例えばサイズ16で出力する場合は、このようなコードになり、
幅は「48.0」となります。


  1. import org.apache.pdfbox.pdmodel.font.PDFont;
  2. import org.apache.pdfbox.pdmodel.font.PDType1Font;
  3. public class Sample {
  4.     public static void main(String... args) throws Exception {
  5.         
  6.         // フォント作成
  7.         PDFont font = PDType1Font.TIMES_ROMAN;
  8.         // 文字の幅を取得
  9.         float width = font.getStringWidth("123456");
  10.         // 16ptで出力する場合
  11.         System.out.println(width * 16f / 1000f);
  12.     }
  13. }




こんなコードで、実際に線を出力して確認してみます。


  1. import java.awt.Color;
  2. import org.apache.pdfbox.pdmodel.PDDocument;
  3. import org.apache.pdfbox.pdmodel.PDPage;
  4. import org.apache.pdfbox.pdmodel.PDPageContentStream;
  5. import org.apache.pdfbox.pdmodel.font.PDFont;
  6. import org.apache.pdfbox.pdmodel.font.PDType0Font;
  7. import org.apache.pdfbox.pdmodel.font.PDType1Font;
  8. import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
  9. public class Sample {
  10.     public static void main(String... args) throws Exception {
  11.         
  12.         // フォント作成
  13.         PDFont font = PDType1Font.TIMES_ROMAN;
  14.         // 文字の幅を取得
  15.         float width = font.getStringWidth("123456");
  16.         // 16ptで出力する場合
  17.         float realWidth = width * 16f / 1000f;
  18.         
  19.         
  20.         
  21.         PDDocument doc = new PDDocument();
  22.         // 新しいページを追加
  23.         PDPage page = new PDPage();
  24.         doc.addPage(page);
  25.         
  26.         // 出力用のストリームを開く
  27.         PDPageContentStream contents = new PDPageContentStream(doc, page);
  28.         
  29.         // テキスト出力開始
  30.         contents.beginText();
  31.         // 使用するフォントに読み込んだフォントを指定。
  32.         // 第二引数はフォントサイズ
  33.         contents.setFont(font, 16);
  34.         
  35.         // テキストの出力位置を指定。
  36.         // 左下がX:0 Y:0の座標となる
  37.         contents.newLineAtOffset(100, 500);
  38.         contents.showText("123456");
  39.         
  40.         // テキスト出力終了
  41.         contents.endText();
  42.         
  43.         // 最初と最後にラインを描画
  44.         contents.setStrokingColor(Color.red);
  45.         contents.moveTo(100f, 500f);
  46.         contents.lineTo(100f, 520f);
  47.         contents.stroke();
  48.         
  49.         contents.moveTo(100f + realWidth, 500f);
  50.         contents.lineTo(100f + realWidth, 520f);
  51.         contents.stroke();        
  52.         
  53.         
  54.         // ストリームを閉じる
  55.         contents.close();
  56.         // pdfファイルを出力
  57.         doc.save("sample.pdf");
  58.         doc.close();
  59.         
  60.     }
  61. }




サイズ16

641_01.png


サイズ26

641_02.png


サイズ36

641_03.png


概ね良いようです。


たぬきフォントをお借りして、日本語でも試してみます。
http://tanukifont.com/tanuki-permanent-marker/


  1. import java.awt.Color;
  2. import java.io.File;
  3. import org.apache.pdfbox.pdmodel.PDDocument;
  4. import org.apache.pdfbox.pdmodel.PDPage;
  5. import org.apache.pdfbox.pdmodel.PDPageContentStream;
  6. import org.apache.pdfbox.pdmodel.font.PDFont;
  7. import org.apache.pdfbox.pdmodel.font.PDType0Font;
  8. public class Sample {
  9.     public static void main(String... args) throws Exception {
  10.         
  11.         
  12.         PDDocument doc = new PDDocument();
  13.         
  14.         // フォント作成
  15.         PDFont font = PDType0Font.load(doc, new File("TanukiMagic.ttf"));
  16.         
  17.         // 文字の幅を取得
  18.         float width = font.getStringWidth("123日本語");
  19.         // 16ptで出力する場合
  20.         float realWidth = width * 46f / 1000f;
  21.         // 新しいページを追加
  22.         PDPage page = new PDPage();
  23.         doc.addPage(page);
  24.         
  25.         // 出力用のストリームを開く
  26.         PDPageContentStream contents = new PDPageContentStream(doc, page);
  27.         
  28.         // テキスト出力開始
  29.         contents.beginText();
  30.         // 使用するフォントに読み込んだフォントを指定。
  31.         // 第二引数はフォントサイズ
  32.         contents.setFont(font, 46);
  33.         
  34.         // テキストの出力位置を指定。
  35.         // 左下がX:0 Y:0の座標となる
  36.         contents.newLineAtOffset(100, 500);
  37.         contents.showText("123日本語");
  38.         
  39.         // テキスト出力終了
  40.         contents.endText();
  41.         
  42.         // 最初と最後にラインを描画
  43.         contents.setStrokingColor(Color.red);
  44.         contents.moveTo(100f, 500f);
  45.         contents.lineTo(100f, 520f);
  46.         contents.stroke();
  47.         
  48.         contents.moveTo(100f + realWidth, 500f);
  49.         contents.lineTo(100f + realWidth, 520f);
  50.         contents.stroke();        
  51.         
  52.         
  53.         // ストリームを閉じる
  54.         contents.close();
  55.         // pdfファイルを出力
  56.         doc.save("sample.pdf");
  57.         doc.close();
  58.         
  59.     }
  60. }




サイズ16

641_04.png


サイズ46

641_05.png


問題なさそうです。






縦幅



フォントの高さはgetHeightで取得出来ます。
これは、取得した値にフォントサイズを乗じれば望みの値になる模様。


  1. import java.awt.Color;
  2. import java.io.File;
  3. import org.apache.pdfbox.pdmodel.PDDocument;
  4. import org.apache.pdfbox.pdmodel.PDPage;
  5. import org.apache.pdfbox.pdmodel.PDPageContentStream;
  6. import org.apache.pdfbox.pdmodel.font.PDFont;
  7. import org.apache.pdfbox.pdmodel.font.PDType0Font;
  8. public class Sample {
  9.     public static void main(String... args) throws Exception {
  10.         
  11.         
  12.         PDDocument doc = new PDDocument();
  13.         
  14.         // フォント作成
  15.         PDFont font = PDType0Font.load(doc, new File("TanukiMagic.ttf"));
  16.         
  17.         // 文字の高さを取得
  18.         float height = font.getHeight('H');
  19.         // 実際の高さはフォントサイズを乗じたもの
  20.         float realHeight = height * 46f;
  21.         
  22.         // 新しいページを追加
  23.         PDPage page = new PDPage();
  24.         doc.addPage(page);
  25.         
  26.         // 出力用のストリームを開く
  27.         PDPageContentStream contents = new PDPageContentStream(doc, page);
  28.         
  29.         // テキスト出力開始
  30.         contents.beginText();
  31.         // 使用するフォントに読み込んだフォントを指定。
  32.         // 第二引数はフォントサイズ
  33.         contents.setFont(font, 46);
  34.         
  35.         // テキストの出力位置を指定。
  36.         // 左下がX:0 Y:0の座標となる
  37.         contents.newLineAtOffset(100, 500);
  38.         contents.showText("123日本語");
  39.         
  40.         // テキスト出力終了
  41.         contents.endText();
  42.         
  43.         // 最初と最後にラインを描画
  44.         contents.setStrokingColor(Color.red);
  45.         contents.moveTo(100f, 500f);
  46.         contents.lineTo(300f, 500f);
  47.         contents.stroke();
  48.         
  49.         contents.moveTo(100f, 500f + realHeight);
  50.         contents.lineTo(300f, 500f + realHeight);
  51.         contents.stroke();
  52.         
  53.         
  54.         // ストリームを閉じる
  55.         contents.close();
  56.         // pdfファイルを出力
  57.         doc.save("sample.pdf");
  58.         doc.close();
  59.         
  60.     }
  61. }




高さは正しく取得できているようですね。

641_06.png


ただ、参考として出力したガイドラインがちょっと上にずれています。
これは、フォントのAscentやDescentを考慮していないからです。

こちらの図がわかりやすいかと。
Get font metrics in C#

Descentを取得し、その分線の描画位置を下にずらします。
ちなみに、Descentもフォントサイズを乗じて1000で割ると望みの値になります。
負数で取得できるので、そのまま加えればOKです。


  1. import java.awt.Color;
  2. import java.io.File;
  3. import org.apache.pdfbox.pdmodel.PDDocument;
  4. import org.apache.pdfbox.pdmodel.PDPage;
  5. import org.apache.pdfbox.pdmodel.PDPageContentStream;
  6. import org.apache.pdfbox.pdmodel.font.PDFont;
  7. import org.apache.pdfbox.pdmodel.font.PDType0Font;
  8. public class Sample {
  9.     public static void main(String... args) throws Exception {
  10.         
  11.         
  12.         PDDocument doc = new PDDocument();
  13.         
  14.         // フォント作成
  15.         PDFont font = PDType0Font.load(doc, new File("TanukiMagic.ttf"));
  16.         
  17.         // 文字の高さを取得
  18.         float height = font.getHeight('H');
  19.         // 実際の高さはフォントサイズを乗じたもの
  20.         float realHeight = height * 46f;
  21.         
  22.         // Descent取得
  23.         float descent = font.getFontDescriptor().getDescent();
  24.         // 実際の値に変換
  25.         float realDescent = descent * 46f / 1000f;
  26.         
  27.         // 新しいページを追加
  28.         PDPage page = new PDPage();
  29.         doc.addPage(page);
  30.         
  31.         // 出力用のストリームを開く
  32.         PDPageContentStream contents = new PDPageContentStream(doc, page);
  33.         
  34.         // テキスト出力開始
  35.         contents.beginText();
  36.         // 使用するフォントに読み込んだフォントを指定。
  37.         // 第二引数はフォントサイズ
  38.         contents.setFont(font, 46);
  39.         
  40.         // テキストの出力位置を指定。
  41.         // 左下がX:0 Y:0の座標となる
  42.         contents.newLineAtOffset(100, 500);
  43.         contents.showText("123日本語");
  44.         
  45.         // テキスト出力終了
  46.         contents.endText();
  47.         
  48.         // 最初と最後にラインを描画
  49.         contents.setStrokingColor(Color.red);
  50.         
  51.         // Descent分微調整
  52.         contents.moveTo(100f, 500f + realDescent);
  53.         contents.lineTo(300f, 500f + realDescent);
  54.         contents.stroke();
  55.         
  56.         contents.moveTo(100f, 500f + realHeight + realDescent);
  57.         contents.lineTo(300f, 500f + realHeight + realDescent);
  58.         contents.stroke();
  59.         
  60.         
  61.         // ストリームを閉じる
  62.         contents.close();
  63.         // pdfファイルを出力
  64.         doc.save("sample.pdf");
  65.         doc.close();
  66.         
  67.     }
  68. }




これでぴったりはまりました。

641_07.png


関連記事

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2015/08/26(水) 22:00:50|
  2. Java
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集
<<Apache PDFBox 円の塗りつぶしと破線の描画 | ホーム | Thinreports + JavaでPDF帳票を出力する>>

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://symfoware.blog68.fc2.com/tb.php/1791-12382378
この記事にトラックバックする(FC2ブログユーザー)