フォントファイルを書き換えてフォント名の文字化けを回避する

目次

公開日 2026-02-23 更新日 2026-02-25

ttfファイルを直接書き換えてみる

fonttoolsのttxコマンドを使ってフォント名を変更したttfファイルを作る方法もあるようですが、正しい指定をしてもutf-16でデコードされて化けているので、普通やらないような設定をしなければなりません。windows用のフォント名しか書かないことにできれば良いかもしれません。でも名前部分を書き換えて別名で保存するような仕様なので、それなら自分で書き換えてみようと考えました。

mac用のjaの部分をutf-16でデコードするのが原因と見られるので、mac_jaをwin_jaと同じバイト列を指すようにすれば、YOzフォントについては解決しそうです。ただし、ファイルにチェックサムがあるようなので、それを使用時に問題にされないようになっていればという条件がありますけれど、改変は数バイトだけなのでやって見る価値はあります。

というわけで、「直接書き換え」をやってみます。

結論を先に書くと、この書換はうまく行きます。fontconfigが正しい処理をするようになったときにも継続して使えるかどうかはfontconfigの使用するshift_jisのデコーダーによります。不具合がでるなら、バックアップを使ってもとに戻すか、フォントをインストールし直せば問題ありません。

また、YOz以外のフォントについては、それぞれ考える必要があります。macのエンコードにutf_16がないのが困りものです。mac-jap-jaの項目をなくすのが最も確実かもしれません。nameレコードの最終項目でmac-jap-jaの項目を上書きしてレコード数を減らすと可能でしょう。あるいは使っていないnameIDの項目に上書きする手もあります。08:製造者とか、09:ベンダーの名前とか、10:説明とか、使えそうです。この方法は次の「"IPA P明朝"と"IPA Pゴシック"のフォント名の文字化け対策」で解説しています。

お試しでYOzSを書き換える

まずはYOzSの化け具合を確認します。

adachi@banach:~$ fc-list -vb YOzS
Pattern has 26 elts (size 32)
	family: "奏穓"(s) "YOzS"(s)
	familylang: "ja"(s) "en"(s)
	style: "Regular"(s)
	stylelang: "en"(s)
	fullname: "奏穓"(s) "YOzS"(s)
	fullnamelang: "ja"(s) "en"(s)
	slant: 0(i)(s)
	weight: 80(f)(s)
	width: 100(f)(s)
	foundry: "Take"(s)
	file: "/usr/share/fonts/truetype/yozvox-yozfont/YOzRS_.ttf"(s)
	(以下略)

family(nameID=01)のみで良いかと思いますが、気になるならfullname(nameID=04)も対処します。style(nameID=02)はデコードに失敗したので出ていないので、変更しなくても大丈夫でしょう。

ファイルは、"/usr/share/fonts/truetype/yozvox-yozfont/YOzRS_.ttf" です。GhexというGUIで使えるバイナリーエディタを使いたいので、user領域にコピーします。YOzというフォルダの中にまとめておくことにします。バックアップを兼ねます。

adachi@banach:~$ cp /usr/share/fonts/truetype/yozvox-yozfont/YOzRS_.ttf YOz/
adachi@banach:~$ file /usr/share/fonts/truetype/yozvox-yozfont/YOzRS_.ttf
/usr/share/fonts/truetype/yozvox-yozfont/YOzRS_.ttf: TrueType Font data, 17 tables, 1st "GSUB", name offset 0x8c8a34
adachi@banach:~$ file YOz/YOzRS_.ttf
YOz/YOzRS_.ttf: TrueType Font data, 17 tables, 1st "GSUB", name offset 0x8c8a34

この name offset 0x8c8a34 を使って、nameテーブルを見ていきます。

adachi@banach:~$ hd YOz/YOzRS_.ttf|grep 8c8a30 -A20
008c8a30  00 00 00 00 00 00 00 21  01 92 00 01 00 00 00 00  |.......!........|
008c8a40  00 00 00 08 00 45 00 01  00 00 00 00 00 01 00 04  |.....E..........|
008c8a50  00 64 00 01 00 00 00 00  00 02 00 07 00 5d 00 01  |.d...........]..|
008c8a60  00 00 00 00 00 03 00 04  00 64 00 01 00 00 00 00  |.........d......|
008c8a70  00 04 00 04 00 64 00 01  00 00 00 00 00 05 00 0d  |.....d..........|
008c8a80  00 38 00 01 00 00 00 00  00 06 00 04 00 64 00 01  |.8...........d..|
008c8a90  00 00 00 00 00 07 00 04  00 64 00 01 00 01 00 0b  |.........d......|
008c8aa0  00 00 00 08 00 45 00 01  00 01 00 0b 00 01 00 04  |.....E..........|
008c8ab0  00 64 00 01 00 01 00 0b  00 02 00 07 00 5d 00 01  |.d...........]..|
008c8ac0  00 01 00 0b 00 03 00 04  00 64 00 01 00 01 00 0b  |.........d......|
008c8ad0  00 04 00 04 00 64 00 01  00 01 00 0b 00 05 00 0d  |.....d..........|
008c8ae0  00 38 00 01 00 01 00 0b  00 06 00 04 00 64 00 01  |.8...........d..|
008c8af0  00 01 00 0b 00 07 00 04  00 64 00 03 00 01 04 09  |.........d......|
008c8b00  00 00 00 10 00 1a 00 03  00 01 04 09 00 01 00 08  |................|
008c8b10  00 4d 00 03 00 01 04 09  00 02 00 0e 00 2a 00 03  |.M...........*..|
008c8b20  00 01 04 09 00 03 00 08  00 4d 00 03 00 01 04 09  |.........M......|
008c8b30  00 04 00 08 00 4d 00 03  00 01 04 09 00 05 00 1a  |.....M..........|
008c8b40  00 00 00 03 00 01 04 09  00 06 00 08 00 4d 00 03  |.............M..|
008c8b50  00 01 04 09 00 07 00 08  00 4d 00 03 00 01 04 11  |.........M......|
008c8b60  00 00 00 10 00 1a 00 03  00 01 04 11 00 01 00 08  |................|
008c8b70  00 4d 00 03 00 01 04 11  00 02 00 0e 00 2a 00 03  |.M...........*..|

オフセット0x8c8a34から2バイト単位で、nameテーブルフォーマット番号(0000)、データ数(0021)、文字列領域の先頭のオフセット位置(0x8c8a34から)(0192)とあって全部で6バイト。その後12バイトのデータが0x21件(10進で33件)続きます。その後に文字列領域があります。12バイトのデータの最後の2バイトがまたまたoffsetで、0x8c8a34 + 0x0192 に加えて文字列の位置が判明します。

今回は、最後のoffsetを書き換えるので、その位置(ファイル先頭からのオフセット)がわかっていると楽ができます。下の表に ⇐0x8c8a34 + 6 + 11 + 12×i などと書かれているのがそれです。

0x8c8a34⇒0000 0021 0192
          0001 0000 0000 0000 0008 0045 ⇐0x8c8a34 + 6 + 11
          0001 0000 0000 0001 0004 0064 ⇐0x8c8a34 + 6 + 11 + 12
          0001 0000 0000 0002 0007 005d ⇐0x8c8a34 + 6 + 11 + 12×2
          0001 0000 0000 0003 0004 0064 ⇐0x8c8a34 + 6 + 11 + 12×3
          0001 0000 0000 0004 0004 0064
          0001 0000 0000 0005 000d 0038
          0001 0000 0000 0006 0004 0064
          0001 0000 0000 0007 0004 0064
          0001 0001 000b 0000 0008 0045
          0001 0001 000b 0001 0004 0064  ⇐0x8c8a34 + 6 + 11 + 12×9
          0001 0001 000b 0002 0007 005d
          0001 0001 000b 0003 0004 0064
          0001 0001 000b 0004 0004 0064
          0001 0001 000b 0005 000d 0038
          0001 0001 000b 0006 0004 0064
          0001 0001 000b 0007 0004 0064
          0003 0001 0409 0000 0010 001a
          0003 0001 0409 0001 0008 004d
          0003 0001 0409 0002 000e 002a
          0003 0001 0409 0003 0008 004d
          0003 0001 0409 0004 0008 004d
          0003 0001 0409 0005 001a 0000
          0003 0001 0409 0006 0008 004d
          0003 0001 0409 0007 0008 004d
          0003 0001 0411 0000 0010 001a
          0003 0001 0411 0001 0008 004d
          0003 0001 0411 0002 000e 002a
          0003 ...
....
0x8c8a34 + 0x0192 + 0x0000⇒名前文字列の1番目(ここでは3-1-409:win-en用の 05:バージョン)
0x8c8a34 + 0x0192 + 0x001a⇒名前文字列の2番目(ここでは3-1-409,411:win-en,jp用の 00:著作権)
0x8c8a34 + 0x0192 + 0x002a⇒名前文字列の3番目(ここでは3-1-409,411:win-en,ja用の 02:style名)
0x8c8a34 + 0x0192 + 0x0038⇒名前文字列の4番目(ここでは1-0-0,1-1-b:mac-en,jp用の 05:バージョン)
0x8c8a34 + 0x0192 + 0x0045⇒名前文字列の5番目(ここでは1-0-0,1-1-b:mac-en,jp用の 00:著作権)
0x8c8a34 + 0x0192 + 0x004d⇒名前文字列の6番目(ここでは3-1-409,411:win-en,jp用の 01:family名・他)
....

この作業は手間なので pythonスクリプトを書いてやらせました。文字化けの原因を探ったときに作ったものにちょっと手を加えただけです。(offset.offsetの部分)

adachi@banach:~$ ./binaryOffset2.py YOz/YOzRS_.ttf 0x8c8a34

YOzSのnameオフセットテーブル(python出力)

注目すべき所に赤マークをつけました。1番目のテーブルでmac-jap-jaのnameID=1のところの 0044 0064 を win-uni-ja のnameID=1の 0008 004d と同じにする。書き換え場所の目印は 0x8c8ab1 ということです。2,3番目のテーブルは文字列のエンコーディングの確認のため残してあるものです。

encodingID の部分を改めて見てみると、mac-jap-ja も Win-uni-ja も encodeID の部分が 00 01 で共通しているのがわかります。encodeID は platformID によって解釈が替わります。macの場合は 0001 はjapaneseですが、winの場合はunicodeです。fontconfigがここを間違えてmacの0001もunicodeでencodeしていると解釈してしまっているのではないでしょうか。macにはunicodeというencodingIDはないようです。

filename='YOz/YOzRS_.ttf'
offset=0x8c8a34
formatOfNameRecord=0x0000
numOfNameRecord=0x0021
stringOffsetOfNameRecord=0x0192
nameオフセットテーブル
platformIDencodingIDlanguageID nameIDlengthoffsetoffset.offset
00 00 01 mac 00 00 rom 00 00 en 00 00 00 08 00 45 0x8c8a45
01 00 01 mac 00 00 rom 00 00 en 00 01 00 04 00 64 0x8c8a51
02 00 01 mac 00 00 rom 00 00 en 00 02 00 07 00 5d 0x8c8a5d
03 00 01 mac 00 00 rom 00 00 en 00 03 00 04 00 64 0x8c8a69
04 00 01 mac 00 00 rom 00 00 en 00 04 00 04 00 64 0x8c8a75
05 00 01 mac 00 00 rom 00 00 en 00 05 00 0d 00 38 0x8c8a81
06 00 01 mac 00 00 rom 00 00 en 00 06 00 04 00 64 0x8c8a8d
07 00 01 mac 00 00 rom 00 00 en 00 07 00 04 00 64 0x8c8a99
08 00 01 mac 00 01 jap 00 0b ja 00 00 00 08 00 45 0x8c8aa5
09 00 01 mac 00 01 jap 00 0b ja 00 01 00 04 00 64 0x8c8ab1
0a 00 01 mac 00 01 jap 00 0b ja 00 02 00 07 00 5d 0x8c8abd
0b 00 01 mac 00 01 jap 00 0b ja 00 03 00 04 00 64 0x8c8ac9
0c 00 01 mac 00 01 jap 00 0b ja 00 04 00 04 00 64 0x8c8ad5
0d 00 01 mac 00 01 jap 00 0b ja 00 05 00 0d 00 38 0x8c8ae1
0e 00 01 mac 00 01 jap 00 0b ja 00 06 00 04 00 64 0x8c8aed
0f 00 01 mac 00 01 jap 00 0b ja 00 07 00 04 00 64 0x8c8af9
10 00 03 win 00 01 uni 04 09 en 00 00 00 10 00 1a 0x8c8b05
11 00 03 win 00 01 uni 04 09 en 00 01 00 08 00 4d 0x8c8b11
12 00 03 win 00 01 uni 04 09 en 00 02 00 0e 00 2a 0x8c8b1d
13 00 03 win 00 01 uni 04 09 en 00 03 00 08 00 4d 0x8c8b29
14 00 03 win 00 01 uni 04 09 en 00 04 00 08 00 4d 0x8c8b35
15 00 03 win 00 01 uni 04 09 en 00 05 00 1a 00 00 0x8c8b41
16 00 03 win 00 01 uni 04 09 en 00 06 00 08 00 4d 0x8c8b4d
17 00 03 win 00 01 uni 04 09 en 00 07 00 08 00 4d 0x8c8b59
18 00 03 win 00 01 uni 04 11 ja 00 00 00 10 00 1a 0x8c8b65
19 00 03 win 00 01 uni 04 11 ja 00 01 00 08 00 4d 0x8c8b71
1a 00 03 win 00 01 uni 04 11 ja 00 02 00 0e 00 2a 0x8c8b7d
1b 00 03 win 00 01 uni 04 11 ja 00 03 00 08 00 4d 0x8c8b89
1c 00 03 win 00 01 uni 04 11 ja 00 04 00 08 00 4d 0x8c8b95
1d 00 03 win 00 01 uni 04 11 ja 00 05 00 1a 00 00 0x8c8ba1
1e 00 03 win 00 01 uni 04 11 ja 00 06 00 08 00 4d 0x8c8bad
1f 00 03 win 00 01 uni 04 11 ja 00 07 00 08 00 4d 0x8c8bb9
20 00 03 win 00 01 uni 04 11 ja 00 0d 00 08 00 55 0x8c8bc5
文字列へのオフセット、長さと、呼び出し元の一覧
offsetlength呼出元plat_lang_nameID
0000001a win_en_05, win_ja_05,
001a0010 win_en_00, win_ja_00,
002a000e win_en_02, win_ja_02,
0038000d mac_en_05, mac_ja_05,
00450008 mac_en_00, mac_ja_00,
004d0008 win_en_01, win_en_03, win_en_04, win_en_06, win_en_07, win_ja_01, win_ja_03, win_ja_04, win_ja_06, win_ja_07,
00550008 win_ja_13,
005d0007 mac_en_02, mac_ja_02,
00640004 mac_en_01, mac_en_03, mac_en_04, mac_en_06, mac_en_07, mac_ja_01, mac_ja_03, mac_ja_04, mac_ja_06, mac_ja_07,
文字列へのオフセット計算、バイト列とデコード例
offsetlength開始位置呼出元plat_lang呼出元nameID バイト列(デコード前の文字列)utf_16_beshift_jis
0000260x8c8bc6win_en,win_ja05 00 56 00 65 00 72 00 73 00 69 00 6f 00 6e 00 20 00 31 00 34 00 2e 00 30 00 34 Version 14.04Version 14.04
001a160x8c8be0win_en,win_ja00 00 59 00 2e 00 4f 00 7a 00 20 00 56 00 6f 00 78 Y.Oz VoxY.Oz Vox
002a140x8c8bf0win_en,win_ja02 00 52 00 65 00 67 00 75 00 6c 00 61 00 72 RegularRegular
0038130x8c8bfemac_en,mac_ja05 56 65 72 73 69 6f 6e 20 31 34 2e 30 34 噥牳楯渠ㄴ⸰�Version 14.04
004580x8c8c0bmac_en,mac_ja00 59 2e 4f 7a 20 56 6f 78 央佺⁖潸Y.Oz Vox
004d80x8c8c13win_en,win_ja01,03,04,06,07 00 59 00 4f 00 7a 00 53 YOzSYOzS
005580x8c8c1bwin_ja13 00 2d 00 2d 00 2d 00 2d --------
005d70x8c8c23mac_en,mac_ja02 52 65 67 75 6c 61 72 剥杵污�Regular
006440x8c8c2amac_en,mac_ja01,03,04,06,07 59 4f 7a 53 奏穓YOzS

GHexによる変更作業

書き換えはGUIで使えるGHexを使いました。GHexは設定で、1バイトごとから4バイトごとまで表示を変えられます。ここでは2バイトごと(正確には16bit)にしてあります。≡メニューから、[Jump to Byte]を選んで、 0x8c8ab1 を入力すると、0064の 64 の部分にカーソルが行きます。ここを 4Dにします。その2バイト前の 04 を 08 にします。これを忘れると、"YOzS" となるべきものが、"YO" となってしまいます。

下の図では、mac-jap-ja の01:familyname の他に、02:styleを 000E 002A に、04:fullnameを 0008 004D にしています。あとの2つは変えなくても問題ないはずです。

これを別名で保存します。バックアップのためです。YOzS_C.ttfとしました。

うまく行ったかどうかは、fc-listではまだ確認できないのでfc-queryを使います。

adachi@banach:~$ fc-query -b YOz/YOzRS_c.ttf 
Pattern has 26 elts (size 32)
	family: "YOzS"(s)
	familylang: "en"(s)
	style: "Regular"(s)
	stylelang: "en"(s)
	fullname: "YOzS"(s)
	fullnamelang: "en"(s)
	slant: 0(i)(s)
	weight: 80(f)(s)
	width: 100(f)(s)
	foundry: "Take"(s)
	file: "YOz/YOzRS_c.ttf"(s)

システムに組み入れられたフォントでなく、ユーザー領域にあるフォントファイルの中を確認しているということです。最初、fullnameの部分に文字化けが残っていたので 04:fullnameの部分も 0008 004D にしたわけです。"Regular"の部分はもともと文字化けはなかったのですが、気休めです。

これをこのまま/usr/share/fonts/truetype/yozvox-yozfont/にコピーして使うと、YOzSというフォントが複数あることになります。これはまずいので、/usr/share/fonts/にあるものを消してから、書き換えたファイルを同名でコピーすることにします。

作業はrootで行います。

root@banach:/home/adachi# rm /usr/share/fonts/truetype/yozvox-yozfont/YOzRS_.ttf
root@banach:/home/adachi# cp YOz/YOzRS_c.ttf /usr/share/fonts/truetype/yozvox-yozfont/YOzRS_.ttf

直接上書きすると、書き換わったことを認識してくれないようです。先にファイル削除をするとうまくいきます。"fc-cache -fv"をすれば認識してくれますが、いまのところ大丈夫です。

システムのYOzSの確認

システムのYOzSが文字化けしないことを確認します。

adachi@banach:~$ fc-list -vb YOzS
Pattern has 26 elts (size 32)
	family: "YOzS"(s)
	familylang: "en"(s)
	style: "Regular"(s)
	stylelang: "en"(s)
	fullname: "YOzS"(s)
	fullnamelang: "en"(s)
	slant: 0(i)(s)
	weight: 80(f)(s)
	width: 100(f)(s)
	foundry: "Take"(s)
	file: "/usr/share/fonts/truetype/yozvox-yozfont/YOzRS_.ttf"(s)

Calcのフォント設定です。YOzSが見えます。

奏穓がなくなっています。

GIMPのフォント選択でも、YOzS が見えます。Aaの違いがどこから来るのか不明です。