動的にロードしたフォントをPDFに埋め込む

製品開発担当の大です。こんにちは。

今日はシーオーリポーツ for Java Ver.3の機能を使用して動的にロードしたフォントをPDFに埋め込む方法をご紹介します。

シーオーリポーツ for Javaでは、Ver.2からPDFにフォントを埋め込むことが可能になりました。しかしVer.2では対象のフォントが事前にシステムにインストールされている必要があり、またフォントファイルを絶対パスで指定しなければならないなど使い勝手の悪い部分がありました。Ver.3では対象のフォントがシステムにインストールされていなくても、動的にロードして使用し埋め込むこともできるようになりました。

フォントが埋め込まれたPDF

フォントが埋め込まれたPDF

今回作成する帳票

今回作成する帳票は以下のようにフォーム上にラベルが2つ置いてあるだけのシンプルなものです。ひとつはIPAmj明朝体、もうひとつはMS Pゴシック体のフォントが指定されています。(実際にシステム開発で利用する場合はそれぞれのフォントの再配布条件等を確認してライセンス上問題のないフォントをご利用ください)

ラベルを配置したフォームファイル

ラベルを配置したフォームファイル

これらのフォントをリソースに含めたwarをデプロイして、AWS Elastic BeanstalkのTomcatで実行しフォントを埋め込んだPDFを作成します。プラットフォームのLinuxシステムにはどちらのフォントもインストールされていません。

事前準備としてElastic Beanstalkの設定画面でJVMコマンドラインオプションに

-Duser.language=ja -Duser.country=JP

を追加しておきます。これにより、日本語フォント名が使えるようになります。

JVM引数の設定

JVM引数の設定

動的なフォントのロード

Javaで動的にロードしたフォントを使用するには、まずFontクラスのcreateFontsを使用してFontオブジェクトを作成し、それをGraphicsEnvironmentに登録します。

static {
    var cl = MethodHandles.lookup().lookupClass();
    var env = GraphicsEnvironment.getLocalGraphicsEnvironment();

    for (var fontName : List.of("/ipamjm.ttf", "/msgothic.ttc")) {
        try (var stream = cl.getResourceAsStream(fontName)) {
            for (var font : Font.createFonts(stream)) {
                env.registerFont(font);
            }
        } catch (IOException | FontFormatException ex) {
            ex.printStackTrace();
        }
    }

}

createFontsはJava9から導入されたメソッドです。ひとつのフォントファイルに複数のフォントが入っているttcファイルの場合、Java8以前のcreateFontメソッドでは最初のフォントしかロードすることが出来ませんでした。今回の帳票ではmsgothic.ttcの2番目に入っているMS Pゴシックを使用していますので、createFontsのあるバージョンのJavaが必要です。

PDFにフォントを埋め込む

シーオーリポーツ for Java Ver.3ではフォントを埋め込む場合、フォントのストリームを指定することができるようになりました。先ほどのcreateFontsと同様にgetResourceAsStreamで取得したフォントのストリームを使用します。

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    try {
        var stream = new ByteArrayOutputStream();
        createPDF(stream);
        response.setHeader("Content-Disposition", "attachment;filename=\"example.pdf\"");
        response.setContentType("application/octet-stream");
        response.getOutputStream().write(stream.toByteArray());
    } catch (Exception ex) {
        throw new ServletException(ex);
    }
}
private void createPDF(OutputStream stream) throws IOException {
    var job = new CrStreamOutJob(CorDocumentType.PDF, stream);
    var doc = job.<CrPdfDocument> getDocument();
    var draw = new CrDraw();
    try (var ipamjm = getClass().getResourceAsStream("/ipamjm.ttf");
         var msgoth = getClass().getResourceAsStream("/msgothic.ttc")) {
        doc.setFontSettings("IPAmj明朝", FontSettings.forEmbed(ipamjm, CorPdfFontEmbedMode.SUBSET));
        doc.setFontSettings("MS Pゴシック", FontSettings.forEmbed(msgoth, CorPdfFontEmbedMode.SUBSET));
        try (var form = CrForm.open(draw, getClass().getResourceAsStream("/Form1.rse"))) {
            job.start(draw);
            form.printOut();
            job.end();
        } catch (CrException ex) {
            job.abort();
            throw ex;
        }

    } finally {
        draw.deleteInstance();
    }
}

デプロイ、実行

完成したWebアプリをElastic Beanstalkにデプロイして実行します。

実行結果

実行結果

あらかじめフォントがインストールされていない環境でも、フォントを埋め込んだPDFが作成されましたね!

こちらからダウンロードできる体験版でもこの動作を確認できます。ぜひお試しください。