PDFBoxによるカバーページ(その9)

DejaVuSans.ttfでは気付かなかったがArialUni.TTFにしたら簡単なPDFの作成になんと24秒もかかった。調べた結果(使えそうなプロファイラがわからずSystem.currentTimeMillis()で1行1行使用時間を測った。何かフリーで良いのはないのか)Glyphテーブルのパースにほとんどの時間が費やされていた。DejaVuSansとArialUniの文字数を考えれば遅くなるのは理解できるが差がありすぎる。そこでまずiTextの相当箇所を見てみたら、そもそもパースしていなかった。正確にはboundingBoxを求める部分はパースしているけど、グリフパスの部分はパースしていなかった。サブフォントの作成に問題がないか調べないまま、とりあえずPDFBoxの方も同じようにパースを止めたところ、特に問題はなく時間は10分の1以下になった。これでもiTextに比べると遅いが何とか実用にはなると思われる。

PDFBox全体でこのグリフパスを使用している箇所は1箇所だけ存在した。1箇所とはいえ存在する以上、ただ止めたでは問題があるので、Glyphテーブルのパースを行うか否かのフラグをAbstractTTFParserクラスに追加して、何も指定しなければ従来通りとなるようにした。

なお、時間がかかるのは`new PDType0TTFont()`なので、DSpaceではこのフォントをstaticに作成して使いまわすようにすれば、Systemスタート後の最初のカバーページ作成が遅いだけで、2件目以後はまったく問題がない。なので、サブフォントの作成で問題があったらそのままにしようと思っていた。

ちなみに次のように使う。実際に使用する文字だけの埋め込みフォントを作成するPDType0TTFont.reloadFont()を利用側で呼び出す必要がないようにしたいが良い方法が思いつかない。

import java.io.File;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.edit.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType0TTFont;

public class Type0TTFTest
{
	public static void main(String[] args ) throws Exception
	{
		PDDocument document = new PDDocument();
		PDPage page = new PDPage(PDPage.PAGE_SIZE_A4);
		document.addPage(page);
		PDPageContentStream stream = new PDPageContentStream(document, page);

		PDType0TTFont font = new PDType0TTFont("/usr/local/share/fonts/ArialUni.ttf", false);
		String text = "Kh\u1ea3o日本語";
		stream.beginText();
		stream.setFont(font, 12);
		stream.moveTextPositionByAmount(50, 600);
		stream.drawStringByCID(font, text);
		stream.endText();

		font.reloadFont(document);
		stream.close();
		document.save("type0ttf.pdf");
		document.close();
	}
}

そういえば、このシリーズのカバーページの元となったPeter Dietzのコードを、Peter自身がPDFBoxを使って描き直した(いずこも同じことを考えるものである)ものがDSpaceバージョン5に入ることになった。ただし、標準Type1フォントしか対応していないので、日本語などは表示できない。