One IT Thing

IT業界を楽しむ為の学習系雑記

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
-, , ,

執筆者:

関連記事

JavaでRSA暗号を使う際にCRYPTREC暗号リストに足元をすくわれる可能性を回避する

標準的な暗号しか使わないケースでもJavaでRSAを使う時はBouncyCastleを入れておいた方が無難、という話です。 “ECB”という文字列がプログラム中にあると監査に引 …

Spring&JSPの検証環境を速攻で作る

2019年現在、オワコン風潮の強いJSPですが使っているプロジェクトもまだまだあり、枯れた技術を好む官公庁系のプロジェクトでは根強いシェアを誇っています。実装検証をする為に環境を作る機会があったりする …

StripeとJavaで単発Web決済を一通り流してみる

会社仕事でも個人ビジネスでも、商品やサービスの対価として利用者に課金方法を提供したい時があるかと思います。 最もメジャーな決済方法であるクレジットカードで課金してもらう仕組みを導入したいところですが、 …

SpringBootアプリにBootstrap4を追加(WebJars使用)

SpringBootにCSSやJSを追加する場合は概ね以下のパターンがあるんじゃないかと思います。(bowerはもう使わない方向で) CDNで外部から読み込む<script src=&#8221 …

JUnitコードの自動生成も出来る古の神Eclipseプラグイン「CodeProAnalytix」は今でも使える

デスマーチPM「各社のPG進捗が遅れていてユニットテストを書く暇が全く無いんですよ、なにかいい手は有りませんかね・・・? 因みに本プロジェクトはカバレッジ100%で請け負っています!(キリッ)」 何故 …


shingo nakanishi。東京で消耗中の職歴20年越え中年ITエンジニアです。「生涯現役プログラマを楽しむ」ことができる働き方探しをライフワークにしています。

19歳(1996年)から書き始めた個人日記が5,000日を超え、残りの人生は発信をして行きたいと思い、令和元日からこのサイトを開始しました。勉強と試行錯誤をしながら、自分が経験したIT関連情報を投稿しています。