目次
はじめに
今まで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アプリとして提供するソリューションはアリかも知れません。