読者です 読者をやめる 読者になる 読者になる

FIELD NOTES: 書を持って街へ出よう

合同会社フィールドワークス プログラマ兼代表のブログ

IPAmj明朝フォントの研究 ― 実装編 ―

前回の調査結果を元に Field Reports 1.4 に以下の機能を盛り込みました。

fet2011-12-23

サロゲートペア対応

従来は,PDFで定義済みのCMapである「UniJIS-UCS2-H」を使ってエンコーディングを行なっていましたが,これでは1文字=2バイトのコードまでしか対応できませんでした。

そこで,フォントファイルが存在する場合はエンコーディングとして「Identity-H」を使用することにしました。
Identity-Hの場合,文字コードは(0〜65,535)のCIDベースになります(TrueTypeフォントの場合はGID)。
UnicodeからCIDへの変換は,フォント自身が持っているcmapを使って行います。

これで,サロゲートペアで表現される文字もCIDまたはGIDに変換して,PDFに埋め込むことができるようになりました。

ただし,プログラミング言語によっては2バイトを超えるUnicode文字をエスケープシーケンスなどで表現できないので,数値参照文字も使えるようにしました。

&#dddd; または &#xhhhh; (ddddは10進数,hhhhは16進数)

ついでに,CIDまたはGIDで直接グリフを指定できるよう「グリフ参照文字」も使えるようにしました。

&@#dddd; または &@#xhhhh;l

異体字セレクタ

異体字セレクタ(IVS)の情報は,フォントファイルのcmapテーブルの中の「Format 14 」のサブテーブルに格納されています。

Field Reports は内部的には文字コードをUCS4で持っています。UCS4をCIDまたはGIDに変換する際に1文字先読みし,2文字目が異体字セレクタ(0x0E0100〜0x0E01EF)であれば,IVSを使って変換するようにしました。

グリフ名参照

前回触れたとおり,IPAmj明朝フォントの場合「post」テーブルにグリフ名→GIDの対応表が収納されています。

文字参照を独自拡張した「グリフ名参照」により,グリフ名を指定できるようにしました。
以下のような書式になります。

&@<グリフ名>;

使用例

以下に,サロゲートペア・異体字セレクタ・グリフ名参照を使用してPDFを作成した例を示します。

実行には,Field Reports のコマンドラインプログラムを使用しました。
下記のパラメータファイルを作成してコマンドラインプログラムに掛けると,先頭の実行例の様なPDFが作成されます。

サロゲートペア」では,Unicode 6.0に含まれるCJK統合漢字拡張漢字B集合〜D集合の文字の一部を表示しています。

異体字セレクタ」では,異体字セレクタを使って「邊」の異体字等を表示しています。

「グリフ名参照文字」では,IPAmj明朝に収納されている文字のうちUCSが未実装かつIVS実装されていない7,160文字の一部を表示しています。

{
    "resources": {
        "font": {
            "IPAmjMincho": {
                "path": "./ipamjm.ttf",
                "embed": true,
                "subset": true
            }
        }
    },

    "template": {"size": "A4"},

    "context": {
        "text": [
            {
                "new": "Tx",
                "font": "IPAmjMincho",
                "font-size": 14,
                "rect": [50, 750, 550, 780],
                "value": "【サロゲートペア】"
            },
            {
                "new": "Tx",
                "font": "IPAmjMincho",
                "font-size": 24,
                "multiline": true,
                "rect": [50, 650, 550, 750],
                "charref": true,
                "value": "&#x2000B;&#x20089;&#x200A2;&#x200A4;&#x201A2;
&#x20213;&#x2032B;&#x20371;&#x20381;&#x203F9;&#x2044A;&#x20509;
&#x205D6;&#x20628;&#x2074F;&#x20807;&#x2083A;&#x208B9;&#x2097C;
&#x2099D;\n&#x2A716;&#x2A729;&#x2a72a;&#x2a72c;&#x2a738;&#x2a73d;
&#x2a746;&#x2a752;&#x2a758;&#x2a75f;\n&#x2B740;&#x2B741;&#x2B742;
&#x2B743;&#x2B744;&#x2B745;&#x2B746;&#x2B747;&#x2B749;&#x2B74A;
&#x2B74C;&#x2B74D;"
            },
            {
                "new": "Tx",
                "font": "IPAmjMincho",
                "font-size": 14,
                "rect": [50, 600, 550, 630],
                "value": "【異体字セレクタ】"
            },
            {
                "new": "Tx",
                "font": "IPAmjMincho",
                "font-size": 24,
                "multiline": true,
                "rect": [50, 500, 550, 600],
                "value": "\u9089\U000E010F\u9089\U000E0119\u9089\U000E011B
\u9089\U000E011A\u9089\U000E011C\u9089\U000E011D\u9089\U000E0117
\u9089\U000E0116\u9089\U000E0115\u9089\U000E0114\u9089\U000E0118
\u9089\U000E0113\u9089\U000E0112\u9089\U000E0111\u9089\U000E0110\n
\u908A\U000E0108\u908A\U000E0109\u908A\U000E010A\u908A\U000E010B
\u908A\U000E010C\u908A\U000E010D\u908A\U000E010E\u908A\U000E010F
\u908A\U000E0110\n葛飾区 葛\U000E0102城市/蓮田市 蓮\U000E0104田市"
            },
            {
                "new": "Tx",
                "font": "IPAmjMincho",
                "font-size": 14,
                "rect": [50, 450, 550, 480],
                "value": "【グリフ名参照文字】"
            },
            {
                "new": "Tx",
                "font": "IPAmjMincho",
                "font-size": 24,
                "multiline": true,
                "rect": [50, 350, 550, 450],
                "charref": true,
                "value":"&@mj000007;&@mj000008;&@mj000012;&@mj000022;&@mj000023;
&@mj000028;&@mj000029;&@mj000036;&@mj000037;&@mj000045;&@mj000046;
&@mj000047;&@mj000048;&@mj000073;&@mj000074;&@mj000089;&@mj000105;
&@mj000106;&@mj000129;&@mj000130;&@mj000143;&@mj000144;&@mj000145;
&@mj000146;&@mj000156;&@mj000157;&@mj000175;&@mj000176;&@mj000183;
&@mj000184;&@mj000185;&@mj000206;&@mj000207;&@mj000208;&@mj000209;
&@mj000241;&@mj000242;&@mj000264;&@mj000265;&@mj000266;&@mj000267;
&@mj000269;&@mj000270;&@mj000276;&@mj000277;&@mj000278;&@mj000302;
&@mj000303;&@mj000309;&@mj000310;&@mj000311;&@mj000312;&@mj000317;
&@mj000318;&@mj000332;&@mj000333;&@mj000380;&@mj000381;&@mj000405;
&@mj000406;"
            }
        ]
    }
}
広告を非表示にする