初歩のシェルスクリプトで遊ぶ[ぬかみそフォントの制作サポート(1)]

OTEditとNフォントとUnicode-CID対応

OTEditが文字数の多いOpenTypeフォント、「Pr6N」に対応してる、と分かって、さてどうすんべかと。
単に文字数が多いだけでなくて、いわゆるNフォントのようなので。Unicodeで作ったTrueTypeフォントをコピーしてOpenTypeにするとき、手順が変わるんじゃないかってのを、現在検討してます。
以下、そのメモ。

資料がねぇよ

使いやすい資料が見つからん。

168文字をどうするか

字形変更分の168文字をどうするかってのが、中心になる問題。
たとえば「辻」の文字を作ったTTFファイルを、コピーしてOTFに変換したとき、stdフォントだとCID3056番にコピーされた。これが、Pr6Nだと8267番にコピーされる。
3056番は1点しんにょうで、8267番は2点しんにょう。だからテキストエディタで「辻」って打って、フォントを指定すると、同じunicodeの文字からでも違う文字のCIDが指定されて、1点しんにょうになったり、2点になったりする。
フォントの制作手順として、まず1点しんにょうで作っている現状のnukamisoだと、今までの手順で「N」フォントにコピーすると、1点しんにょうの「辻」を、2点のところにコピーしちゃう。これはまずい。
今までどおりNでないProフォントで出すなら問題なさそうだけど、文字数を増やしたいのなら、Nフォントにすることを検討しなきゃなんないな、手順を変えてツールを作り替えなきゃなんないな、ってのが今ここです。

とりあえず資料作り_ダウンロードとcsvファイルへの変換

フォントエディタ OTEdit for Windows のダウンロード | フォント・外字ソフトのことなら武蔵システム
武蔵システムから資料として、UnicodeとCIDの対応表がダウンロードできる。これを元にして、資料つくります。
zip書庫がふたつ、1-4と1-7のがあります。それぞれのzipの「UnicodeとCIDの対応.xls」、これらを、テキストファイルに変換して、1枚の資料にまとめます。

  1. UnicodeとCIDの対応.xls」のファイルをLibreOfficeで開く
  2. csvファイルに変換保存する。区切り文字は「タブ」。それぞれファイル名は、
  3. テキストエディタcsvを開き、1行目、「Unicode CID」の行を削除する
  4. 改行コードをLFに書き換える

こんな感じのテキストファイルになります。unicode0x0020は、CID1。なんてのの繰り返し。

0020	1
0021	2
0022	3
0023	4
0024	5
0025	6
0026	7
0027	8
0028	9
0029	10
002A	11
002B	12
002C	13
002D	14

シェルでの作業_Unicodeに重複が無いことを確認する

  1. テキストファイルの行数を数える
  2. テキストファイルからUnicodeのみ抜き出して、ソートして重複行を除き、行数を数える
  3. 同様にCIDのみ抜き出し、ソートして重複行を除き、行数を数える
$ cat ./1-4.csv | wc -l
10164
$ cat ./1-4.csv | cut -f 1 | sort | uniq | wc -l
10164
$ cat ./1-4.csv | cut -f 2 | sort | uniq | wc -l
9866
$ cat ./1-7.csv | wc -l
15846
$ cat ./1-7.csv | cut -f 1 | sort | uniq | wc -l
15846
$ cat ./1-7.csv | cut -f 2 | sort | uniq | wc -l
15539

UnicodeとCIDの列を調べると、

  • unicodeに重複はない。
  • CIDには、重複がある。

unicodeに重複は無いと分かったので、unicodeを軸に処理する。

1-7に取りこぼしが無いか確認する

1-4の文字は、すべて1-7に含まれてるはず。このへんを確認する。
unicode CID」の列になっているcsvファイルの、左側1列、unicodeだけ抜き出したテキストファイルを作る

$ cut -f 1 0< ./1-4.csv 1>1-4_f1.txt
$ cut -f 1 0< ./1-7.csv 1>1-7_f1.txt

これらはそれぞれ、unicodeの数字に重複が無いことは確認できているから、

$ wc 1-4_f1.txt 
10164 10164 51013 1-4_f1.txt

行数は10164行、単語数も当然、10164。10164種類の16進数が、すべて「1-7_f1.txt」にも入ってることを確認すればいい。
例えば文字コード「9BFA」が、「1-7_f1.txt」に入っていることを確認するなら、恰好悪いやり方だけど、grepしてみると分かる。

$ grep -x -e '9BFA' ./1-7_f1.txt 
9BFA

このように、Unicodeが入ってるなら一行分の出力が得られる。もし「1-7_f1.txt」に含まれていない文字を探したなら、

$ grep -x -e '_9BFA' ./1-7_f1.txt
(出力なし)

出力が得られない。

このgrepを、1-4に含まれるunicodeひとつにつき一回ずつ、繰り返す

$ cat ./1-4_f1.txt | xargs -I '{}' grep -x -e '{}' ./1-7_f1.txt
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029

xargsで繰り返して、 grep -x で一行単位で検索する。
行数がgrepに引っかかった数になると分かったので、以上のコマンドの行数を数える。

$ cat ./1-4_f1.txt | xargs -I '{}' grep -x -e '{}' ./1-7_f1.txt | wc
  10164   10164   51013

10164回、grepで探したら見つかった。1-4に入ってるunicodeは、すべて取りこぼしなく、1-7にも入ってる、と確認した。

ふたつの表を結合する

1-4のテキストファイルと1-7のテキストファイルを、Unicodeを軸にして、ひとつの表にまとめる。
joinのためにsortしておいて、一時ファイルを作ってから、joinで結合する。
2列めと3列目を逆にしたものも作っておく。

$ sort ./1-4.csv 1>1-4_sort.csv
$ sort ./1-7.csv 1>1-7_sort.csv
$ join -a 1 ./1-7_sort.csv ./1-4_sort.csv 1> join1-7_1-4.csv
$ join -a 2 ./1-4_sort.csv ./1-7_sort.csv 1> join1-4_1-7.csv

結果はこんな感じです。Unicode,CIDの2004,CIDの90、というように。

0020 1 1
0021 2 2
0022 3 3
0023 4 4
0024 5 5
0025 6 6
0026 7 7
0027 8 8
0028 9 9
0029 10 10
002A 11 11
002B 12 12
002C 13 13
002D 14 14
002E 15 15

横道にいったん入り、差分をつくる

先ほど作っておいた、2列目と3列目が逆になったcsvファイル。これをdiffで比較すると、「辻」がそれぞれ異なるCIDにコピーされたように、違うCIDにコピーされる行を抜き出せます。

$ diff  ./join1-7_1-4.csv ./join1-4_1-7.csv
987c987
< 2225 15489 666
---
> 2225 666 15489
1888c1888
< 2F5B 7965 1383
---
> 2F5B 1383 7965
3200c3200
< 5026 7674 1863
---
> 5026 1863 7674

$ diff  ./join1-7_1-4.csv ./join1-4_1-7.csv | grep -e '^<'
< 2225 15489 666
< 2F5B 7965 1383
< 5026 7674 1863
< 50C5 7662 1735
< 5132 7798 3813
< 514E 13949 3136
< 51A4 7817 4228
< 51DE 20300 14352
< 5307 20301 8404
< 537F 7661 1698
< 53A9 20271 1243

$ diff  ./join1-7_1-4.csv ./join1-4_1-7.csv | grep -e '^<' | cut -f 2- -d ' '
2225 15489 666
2F5B 7965 1383
5026 7674 1863
50C5 7662 1735
5132 7798 3813
514E 13949 3136
51A4 7817 4228
51DE 20300 14352
5307 20301 8404
537F 7661 1698
53A9 20271 1243
53C9 20281 2085
53DB 7978 3412

10進数と検索用文字を付加する

結合したcsvテキストファイルは
Unicode CID2004 CID90」
の並びになってます。CIDが無いものは空白。このテキストファイルを、以下のシェルスクリプトに通します。これはdashじゃだめで、「#!/bin/bash」が必須。

#!/bin/bash
# ===============================================================================
# ■ unicodeの16進数を10進数に変換して、新しく列に追加する_ ttedit_20210306.sh
# 
# ・input
# unicode(HEX)	CID2004	CID90
# 
# ・output
# unicode(DEC)	unicode(HEX)	CID2004	CID90	文字
# 
# 空のCID90には、0を入れる
# 
# ===============================================================================

while read uniCode cID2004 cID90 ; do

# ユニコード16進数を10進数に変換する
uniCodeDec=`bc --standard << __STDIN
obase=10
ibase=16
${uniCode}
__STDIN`

# もし空なら0にセット
cID90="${cID90:-0}"

printf "%s	%s	%s	%s	\U${uniCode}\n" "${uniCodeDec}" "${uniCode}" "${cID2004}" "${cID90}"

done
$ cat ./join1-7_1-4.csv | ./ttedit_20210306.sh
32	0020	1	1	 
33	0021	2	2	!
34	0022	3	3	"
35	0023	4	4	#
36	0024	5	5	$
37	0025	6	6	%
38	0026	7	7	&
39	0027	8	8	'
40	0028	9	9	(
41	0029	10	10	)
  • 16進数のunicodeを10進数に変換して、1列目に追加
  • 16進数のunicodeを、bashのprintfの機能を利用して、可読文字に変換、最終列に追加
  • 空のCID、CID90の列に、「0」を入れる
  • 空白区切りをタブ区切りに整形する

この出力を「sort -V」すると、1列目の10進数でソートされて、Unicode順に並びます。