java

IPAmj明朝のttfファイルをJVMに読み込ませてSwingで表示(要Java11)

投稿日:2019年7月8日

はじめに

今までIPAmj明朝をWebで表示する実験を何度か行ってきました。

Webアプリ上でIPAmj明朝フォントを表示するには、利用者のPCにIPAmj明朝フォントをインストールして貰わなければならないという欠点があります。

Webフォントにする手もありますが6万文字もあるとサイズがばかにならないですし、IME経由での文字入力が絶望的になります。

一転、デスクトップアプリならアプリにIPAmj明朝フォントを同梱して読み込ませ、フォント表示することが出来ます。

しかしこれも残念ながら、Javaのデスクトップアプリ開発APIである「Swing」はIVS(異体字セレクタ)を解釈する機能が実装されていなかった為、IPAmj明朝を使用しても異体字は文字化けする状況でした。

・・・でしたが、

Java11でSwingがIVSを認識するようになった

進化してますJavaさん。ということで文字化けせずに異体字を表示出来るか検証してみます。

Java Swingソース

プロジェクトルートにIPAmj明朝フォントのTTFファイルである「ipamjm.ttf」を置き、Javaから読み込んで使用します。

冒頭画像の10文字をUnicodeエスケープして、IPAmj明朝フォントを設定したJLabelのテキストとして表示してみます。

JavaでIVSが付いた文字を表示するにはWeb「&#x」と違い「\u」でUnicodeエスケープします。\uは確実に2バイトでないといけない為、「0xE0101」といったIVSコードポイントは「\uDB40\uDD01」にサロゲートペアにエンコードしてから使います。

package com.example.demo;

import java.awt.EventQueue;
import java.awt.Font;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;

public class IPAMJFontFrame extends JFrame {

    // フォント表示テスト用ラベル
    private JLabel label;

    // JFrame画面を構築
    public IPAMJFontFrame() throws Exception {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setTitle("IPAmj明朝表示確認");
        setSize(800, 200);
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

        // IPAmj明朝 ttfファイル読み込み、Fontインスタンス作成
        Font ipamjm = 
            Font.createFont(Font.TRUETYPE_FONT, new FileInputStream("ipamjm.ttf"));
        // 字体の違いが分かるように大きめフォントサイズに設定
        ipamjm = ipamjm.deriveFont(64F);

        // 確認用JLabel、フォントはIPAmj明朝に設定
        this.label = new JLabel();
        label.setFont(ipamjm);

        JPanel panel = new JPanel();
        panel.add(label);
        add(panel);

        setVisible(true);
    }

    public void setLabelText(String text) {
        this.label.setText(text);
    }

    public static void main(String[] args) {
        String javaVersion = System.getProperty("java.version");
        System.out.println(javaVersion);

        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    IPAMJFontFrame frame = new IPAMJFontFrame();

                    // 表示用にUnicodeエスケープ 
                    List<String> codeList = new ArrayList<String>();
                    codeList.add("\u9F8F\uDB40\uDD04");
                    codeList.add("\uD87A\uDFDB");
                    codeList.add("\uD87A\uDFE0");
                    codeList.add("\uD874\uDF80\uDB40\uDD01");
                    codeList.add("\u6E5B\uDB40\uDD01");
                    codeList.add("\u6F9A\uDB40\uDD02");
                    codeList.add("\u8352\uDB40\uDD08");
                    codeList.add("\uD86D\uDF51\uDB40\uDD02");
                    codeList.add("\uD875\uDCFD");
                    codeList.add("\u3407");
                    String codePoints = String.join("", codeList);

                    // 文字列を表示
                    frame.setLabelText(codePoints);

//                    byte[] array = { (byte) 0x84, (byte) 0x5B, (byte) 0xDB, (byte) 0x40, (byte) 0xDD, (byte) 0x04 };
//                    frame.setLabelText(new String(array, "UTF-16"));

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

実装完了です。

動作確認

Java 8(1.8.0_202)で実行

サロゲート文字は表示出来ていますがIVS(\uE0101または\uDB40\uDD01等)を解釈出来ておらず、その部分が文字化けしてしまっています。

Java 11(11.0.2)で実行

おお・・・。完璧に表示出来てます。

何気にSwingのデフォルトアイコンがDukeになっている発見。
(でも異体字の違いをなかなか発見出来ない罠・・・)

まとめ

これならPCにフォントをインストールしなくても、凡そ6万文字に及ぶIPAmj明朝フォントを表示することが出来ますね。

なんでもWeb化の潮流でデスクトップアプリが許容されるシーンは限られるかも知れませんが・・・。

ただ異体字が必要とされるシーンも限られているので、難しい文字を入力、表示する必要があるシステムでは、GUIアプリとして提供するソリューションはアリかも知れません。

-java
-, , ,

執筆者:

関連記事

Maven依存ライブラリのライセンスサマリを出す

Mavenで依存しているライブラリのライセンス累計を作成します。下記のように「ライセンス名 ライブラリ個数」の行がライセンス種別数分作られるイメージ。 BSD 4ASL2 43MIT 5 開発中のクロ …

Stripe+Java+Payment Request APIでApple Pay、Google Payを使ったテストWeb決済をしてみる

自分で作ったサービスを運用してチャリンチャリンしたい・・・エンジニアならこんな夢、一度は見たことがあるんじゃないでしょうか。 夢を実現する為、以前Stripeのcheckout.jsを使ったテストWe …

Jerseyで開発したRESTで任意リファラからのCORSアクセスを許可する

package jp.hoge.filter; import java.util.Properties; import javax.servlet.http.HttpServletRequest; i …

JavaとPerlでTCPソケット通信

目次1 はじめに2 対象読者3 実装3.1 TCPサーバ(Perl)3.2 TCPクライアント(Java)3.3 実行4 まとめ はじめに 前回の続きです。One IT ThingJavaとPerlで …

Doxygenでspring-frameworkをドキュメント化

以前にspring-frameworkのソースリーディングが出来る環境をOpenGrokで作りました。One IT ThingOpenGrokをインストールしてソースリーディング環境を作るhttps: …

 

shingo.nakanishi
 

東京在勤、1977年生まれ、IT職歴2n年、生涯技術者として楽しく生きることを目指しています。デスマに負けず健康第一。