しろもじメモランダム

文字についてあれこれと。

「Windows 8 で変わる文字 - 異体字と Unicode IVS」雑感

Microsoftセミナーに行ってきた。

目新しい情報はあまりなかったが、イベントレポート書いて的な圧力を Twitter 上で受けてしまったので、ここに雑感を書いてお茶を濁したいと思う。

今回の内容は

  • 前半:これまでの文字コード・漢字施策の変遷に関する、ざっくりとした説明
  • 後半:IVS自体と Windows 上におけるIVS対応についての、ざっくりとした説明

という感じだった。幅広い内容をたったの2時間で扱わなければならないので、どうしてもざっくりになってしまう。ある程度の基礎知識がある人であれば、「あーそうだったよね」と自分の頭の中を整理しつつ、まとめ・おさらい的な感覚で聞けると思うが、逆にまったくの初心者がこの2時間だけで理解するのは難しいと思う。文字コードマニヤ(笑)な人は「ここの説明が不十分」とか「これはこう説明した方が…」とかツッコみながら聞いていたのかもしれない。

個人的に興味があったのは、MS-DOS/Windows はこれまでどのように対応してきたかという点。Shift JIS の誕生からIVS対応まで、今回のセミナーでも各所で触れられていた。ただ、そのまわり(+裏?)には語り尽くせないぐらいのいろいろなエピソードがあると思うので、そのへんを何かの機会にまとめて教えてくれたらおもしろいんだけどなー、と感じる。

Window 8 上のIMEにおけるIVS対応については、Consumer Preview 版のときと同じくデフォルトではオフ(IVS入りの候補は出てこない)になっている。「頻繁に使用される名前、地名はIVSを含む単語としてIMEの辞書に搭載」*1してあるとのことで、設定をオン*2にして、例えば「くず」を変換すると、

  • 葛 [U+845B]:Windows Vista 以降のフォントではJIS2004字形
  • 葛󠄀 [U+845B U+E0100]:Adobe-Japan1 コレクション収録のJIS90字形

の両方が候補に出てくる。完璧を期すのであれば、これに加えてJIS2004字形を明示的に指定する

  • 葛󠄁 [U+845B U+E0101]:Adobe-Japan1 コレクション収録のJIS2004字形

も候補に出してほしいところだが、MS-IMEの辞書ではそうはなっていない。

ちなみに、「いばら」を変換すると

  • 茨 [U+8328]
  • 茨󠄀 [U+8328 U+E0100]*3

の両者が出てくるが、「いばらき」では

  • 茨城 [U+8328 U+57CE]

だけであって、IVSを使ったJIS90字形の

  • 茨󠄀城 [U+8328 U+E0100 U+57CE]

は出てこない。これについては、「茨城県などはJIS2004字形を使っているので、JIS90字形は辞書に入れていない」という、わかるようなわからないような説明があった。

IVS/IVDのコレクションの違いについてほとんど触れられておらず、これはどうなんだろう…という感もある。ただ普通のアプリケーションにとってみれば、Adobe-Japan1 であれ Hanyo-Denshi であれ、どちらもIVSとしての扱い方に差はないので、ここらへんのややこしい話にあまり深入りする必要はないかもしれない。

なお、『Unicode IVS/IVD入門』という本が先日発売されたが、今日の講師の方は「届いたばかりでまだ詳しく読んでいない」とおっしゃっていた。

Unicode IVS/IVD入門

Unicode IVS/IVD入門

セミナー後は、小形さんはじめ文字に詳しそうなみなさんと昼食をご一緒させていただいた。そこでのお話(IVSとは関係ない)も非常におもしろかったので、このあたりの内容、まとめて本なり何なりにならないかな…と思う。

そんな一日でした。レポートおわり。

*1:配布資料 p. 40

*2:「変換文字制限をしない」

*3:変換候補の「単漢字…」の中にある。

フォントファイルをFontForgeのアイコンにドラッグ&ドロップして開きたい

UbuntuFontForge をぼちぼち使うので、自分は Unity のランチャー*1FontForge のショートカットも登録している。フォントファイルをここにドラッグ&ドロップすれば、FontForge でそのファイルを開くことができる……と便利なのだが、なぜか FontForge のショートカットはそうはなっておらず、知らんぷりして「フォントを開く」ダイアログが出てくるだけになっている。

最近たびたびこのドラッグ&ドロップをやってしまって残念な気持ちになっていたので、これに対処する。ショートカットアイコンの実体は /usr/share/applications/fontforge.desktop なので、これを ~/.local/share/applications/*2 にコピーしていじればいいらしい。

$ cd ~/.local/share/applications/
$ cp /usr/share/applications/fontforge.desktop .

コピーした fontforge.desktop をエディタで開いてみると、11行目が

Exec=fontforge

となっているので、末尾に %F(ドロップされた全ファイルのパスに展開される)をつけて

Exec=fontforge %F

として保存。

$ chmod +x fontforge.desktop

とすると、Nautilus での表示が下のような FontForge のアイコンになる。

これをランチャーにドラッグ&ドロップして追加すれば完了*3

新しくランチャーに登録したアイコンへフォントファイルをドラッグ&ドロップすれば、ちゃんと FontForge で開けるようになる。複数のファイルをまとめてドラッグ&ドロップしても、これまたちゃんとすべて開いてくれる。

*1:画面左端にある、アプリケーションのショートカットアイコンが並んでいるあれ。

*2:なければ作成する。

*3:もともと FontForge をランチャーに登録していた場合には、古い方のアイコンは右クリックして削除。

米O'Reillyで買ったPDF本をkobo gloでも読めるように加工する

米 O'Reilly のアカウントを作って手持ちの紙本(同社から出ている英語版に限る)を登録すると、その電子書籍版が$4.99/冊で買えるらしい。自宅には CJKV Information Processing(第2版)と Fonts & Encodings があり、どちらもいろいろと役に立っているが、さすがにこれを持ち運ぼうと思うとつらい。

というわけで電子書籍版をさっそく買ってしまった。タイトルによっては eBub や mobi フォーマットも選択できるようだが、この2冊はPDF版のみ。残念ながら errata は反映されていない様子。

余白の除去

このPDFは版面の上下左右に余白が大きく取られているため、これをそのまま電子書籍端末で読もうとしても読みづらい。ググってみたところ、PDF内部の CropBox の値を書き換えて余白を除去する方法があった。

このページのスクリプトにすこし手を加え、次のようにしてみた。

続きを読む

svivs の現状について

Twitter を見ていて、あーそういやそんなもんあったなーと思いだしたのですが、以前 svivs というツールを作りました。

現状

当時は更新・拡張したい点などいくつかあったわけですが、結局のところ今まで放置状態になっています。理由としては、

  • Ubuntu をメインで使うようになったが、Adobe AIR の開発・実行環境は Linux に対応していない
  • 当時はIVSをサポートするOS・ブラウザ・その他アプリケーションが少なかったため、多くの環境で比較的確実に利用できる Adobe AIR を使っていたが、現在ではサポートが進んで問題にならなくなってきた
  • そもそも、Adobe AIR 自体が結局世間ではあまり使われていない気がする
  • めんど(ry

といったあたりで、残念ながら今後も放置状態が続くかと思われます。また、svivs 内部で利用しているIVDのバージョンが古いこともあり、今後の svivs の利用は推奨しません。次項の作業によってIVDを更新することは可能ですが、このような現状を把握した上で、自己責任でお願いします。

svivs で使われているIVDを更新するには

Unicode Consortium の公開するIVDは、これまで何回かアップデートが行われてきました。

svivs は当時最新版であった2010-11-14版のIVDを利用していますが、その後 Adobe-Japan1 と Hanyo-Denshi の両方のコレクションにIVSが追加された、2012-03-02版が出ています。これに対応させたい場合には、以下の作業を行なう必要があります*1

  1. Versions of the IVD のリンクから、最新版の IVD_Sequences.txt をダウンロードする
  2. \Program Files (x86)\svivs\IVD_Sequences.txt を、ダウンロードした IVD_Sequences.txt で上書きする
  3. \Users\{ユーザ名}\AppData\Roaming\net.shiromoji.Svivs\ivd.sqlite を削除する
  4. svivs を起動する

Adobe-Japan1, Hanyo-Denshi 以外のコレクションが新設されるなどした場合には対応できませんので、ご注意ください。

*1:パスは Windows 7 64bit 環境での例。自分の環境に合わせて適宜読み替えてください。

アウトラインのSVGからフォントを生成 #かな書いてみる

IVSやら何やら他の話題に飛びついていたので間が空いてしまったが、明朝かな書体制作のつづき。前回はアウトラインを作ったので、今回はここからフォントを生成したい。

SVGの分割

まず、これがアウトラインのファイル。Inkscape で作成し、SVGとして保存した。アウトラインは outline という名前のレイヤーの中に作っている。仮想ボディのサイズは100pxとした。

これをグリフごとに分割し、1文字1ファイルにする。今回は(も?)Perl で簡単なスクリプトを書き、これを利用した。単純なものなので、path 要素以外の要素(グループも含む)に対応していないなどいろいろと制限はある。また XML::Simple を利用しているので、実行するには XML::Simple のインストールが必要。

#!/usr/bin/perl
#
# SVGをグリフごとに分割
# usage: perl split_svg.pl svg_sheet.svg list.txt

use strict;
use warnings;
use autodie;
use utf8;
use 5.010;
binmode STDOUT, ":utf8";

use constant OUT_DIR => "glyphs";
use constant PIXELS_PER_EM =>  100;
use constant UNITS_PER_EM  => 1000;

use XML::Simple;

my ($svg_file, $list_file) = @ARGV;

# SVG 読み込み
my $svg = XMLin($svg_file, forcearray => 1, keyattr => []);

# 行数・列数を求める
my $row_max = int ($svg->{height} / PIXELS_PER_EM) - 1;
my $col_max = int ($svg->{width} / PIXELS_PER_EM) - 1;

# outline レイヤーを探す
my $groups = $svg->{g};
my $group_outline;
foreach my $group (@$groups) {
  if ($group->{'inkscape:label'} eq "outline") {
    $group_outline = $group;
    last;
  }
}
die "outlineレイヤーが存在しません" unless defined $group_outline;

# 変換行列を求める
my $transform = $group_outline->{transform};
my ($a, $b, $c, $d, $e, $f) = (1, 0, 0, 1, 0, 0);
if (!defined $transform) {
  # noop
} elsif ($transform =~ m/translate\((?<tx>-?\d+(.\d+)?(e-?\d+)?),(?<ty>-?\d+(.\d+)?(e-?\d+)?)\)/) {
  $e = $+{tx};
  $f = $+{ty};
} elsif ($transform =~ m/matrix\((?<a>-?\d+(.\d+)?(e-?\d+)?),(?<b>-?\d+(.\d+)?(e-?\d+)?)\),(?<c>-?\d+(.\d+)?(e-?\d+)?),(?<d>-?\d+(.\d+)?(e-?\d+)?),(?<e>-?\d+(.\d+)?(e-?\d+)?),(?<f>-?\d+(.\d+)?(e-?\d+)?)/) {
  $a = $+{a};  $c = $+{c};  $e = $+{e};
  $b = $+{b};  $d = $+{d};  $f = $+{f};
} else {
  die "未対応のtransformです: $transform"
}

# グリフごとに path を格納する変数
my @glyphs = ();
foreach my $row (0 .. $row_max) {
  foreach my $col (0 .. $col_max) {
    $glyphs[$row][$col] = [];
  }
}

# @glyphs にパスを格納
my $paths = $group_outline->{path};
foreach my $path (@$paths) {
  my @data_args = split /\s+/, $path->{d};
  my $new_data = "";
  my ($col, $row);
  my $is_moveto_point = 1;
  foreach my $data_arg (@data_args) {
    if ($data_arg =~ m/(?<x>-?\d+(.\d+)?),(?<y>-?\d+(.\d+)?)/) {
      my $x = $+{x};
      my $y = $+{y};
      if ($is_moveto_point) {
        $x = $a * $x + $c * $y + $e;
        $y = $b * $x + $d * $y + $f;
        $col = int ($x / PIXELS_PER_EM);
        $row = int ($y / PIXELS_PER_EM);
        $x %= PIXELS_PER_EM;
        $y %= PIXELS_PER_EM;
        $is_moveto_point = 0;
      }
      $x *= UNITS_PER_EM / PIXELS_PER_EM;
      $y *= UNITS_PER_EM / PIXELS_PER_EM;
      $data_arg = "$x,$y"
    }
    $new_data .= "$data_arg ";
  } 
  next if ($col < 0 || $col_max < $col || $row < 0 || $row_max < $row);
  $path->{d} = $new_data;
  push @{$glyphs[$row][$col]}, $path;
}

# リスト読み込み
my @glyphname_list = ();
open my $fh_list, '<:utf8', $list_file;
while (my $line = <$fh_list>) {
  chomp $line;
  my @list = map { sprintf "u%x", (unpack "U*", $_) } split / +/, $line;
  push @glyphname_list, \@list;
}
close $fh_list;

# 各グリフの SVG を生成
mkdir OUT_DIR if !-d OUT_DIR;
foreach my $row (0 .. $row_max) {
  foreach my $col (0 .. $col_max) {
    my $svg;
    $svg->{'xmlns:sodipodi'} = "http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
    $svg->{'xmlns:inkscape'} = "http://www.inkscape.org/namespaces/inkscape";
    $svg->{width} = UNITS_PER_EM;
    $svg->{height} = UNITS_PER_EM;
    $svg->{path} = $glyphs[$row][$col];
    my $svg_string = '<?xml version="1.0" encoding="UTF-8"?>';
    $svg_string .= "\n" . XMLout($svg, RootName => "svg");
    my $glyphname = $glyphname_list[$row][$col];
    next if (!defined $glyphname || $glyphname eq "u3000"); # u3000:全角スペース
    open my $fh_out, '>', OUT_DIR . "/$glyphname.svg";
    print $fh_out $svg_string;
    close $fh_out;
  }
}

exit 0;

SVGのどのマスがどのグリフか、割り当て表も用意しておく。

あ い う え お
か き く け こ
さ し す せ そ
た ち つ て と
な に ぬ ね の
は ひ ふ へ ほ
ま み む め も
や   ゆ   よ
ら り る れ ろ
わ ゐ ん ゑ を

これを例えば

> perl split_svg.pl hiragana_1.svg hiragana_list.txt

として実行すれば、glyphs ディレクトリに一字一字のSVGが生成される。

FontForge でフォント化

そして、このバラしたSVGファイルを FontForge に取り込み、フォントを生成する。

FontForge ではSVGの1pxがフォントの1ユニットに相当する。また、OpenType の標準は1000ユニット/emなので、インポート元のSVGを1000×1000pxにしておくとちょうど良い。今回は、split_svg.pl でバラすときにSVGのサイズを1000×1000pxへ変換しているので、あとはそのままインポートするだけでよい。

#!/usr/bin/fontforge -script

if ($argc != 2)
  Print("usage: fontforge -script " + $0 + " [version]")
  Quit()
endif

_version      = $1
_fontfilename = "zeromin_" + _version + ".otf"
_importfiles  = "glyphs/u*.svg"

New()

# .notdef作成
Select(0x0000)
SetWidth(1000)
SetGlyphName(".notdef")

# エンコードUnicodeを指定
Reencode("unicode")

# SVGをすべてインポート
Import(_importfiles, 0)

# 自動ヒントづけOFF
SelectAll()
DontAutoHint()

# パスの統合
RemoveOverlap()

# 整数値に丸める
RoundToInt()

# 半角スペース作成
Select(0u0020)
SetWidth(500)

# 全角スペース作成
Select(0u3000)
SetWidth(1000)

# フォント情報設定
SetFontNames("ZeroMin",\
             "ZeroMin",\
             "ZeroMin",\
             "Regular",\
             "© 2012 mashabow",\
             _version) 
SetOS2Value("WinAscent", 880)
SetOS2Value("WinDescent", 120)
SetOS2Value("HHeadAscent", 880)
SetOS2Value("HHeadDescent", -120)

# OTF生成
Generate(_fontfilename)
Print("generated: "+ _fontfilename)

Close()

Quit()

このスクリプトFontForge で動かせば*1、とりあえずはフォントが生成される。最初の明朝体ということで「ZeroMin」と仮に名付けてみた。

試し打ち

出来上がったフォントをインストールして、さっそく試し打ち。

んー。初めてにしてはまずまずなような気もしないでもないけど、やっぱり字面の大きさや寄り引き、太さなんかのバラつきが目立つ。実用にはちょっと堪えない。

というわけで、まだまだ先は長そう。

*1:unofficial fontforge-cygwin でのスクリプトの動かし方はこの記事を参照。

JIS X 0208 と JIS X 0213 が改正されていた件

昨年12月に小林さんの講演を聞いたとき、JIS X 0213 が近々改正されるというようなことをおっしゃっていた。そんなことはほとんど忘れていたのだが、

584 デフォルトの名無しさん 2012/03/11(日) 13:26:15.37
 そういや結局0213って改正するの? 常用漢字の関係で

588 デフォルトの名無しさん 2012/03/11(日) 16:02:37.18
 JISCのサイト言ったらいつのまにか改正されててワロタ
 誰も気づかなかったのか…

文字コード総合スレ part7

な、なんだってー!(AAry

JISCのサイトで調べてみると、たしかに2012年2月20日付で JIS X 0208JIS X 0213 が改正され、JIS X 0208:2012 と JIS X 0213:2012 になっている。それぞれ第5次規格、第3次規格にあたる。どちらも追補の形で出されており、PDFでは後ろ2ファイルが改正分になっている。

改正点はざっとこんな感じ。

  • 6.6.2「字体の表現としての字形」において、旧常用漢字表「(付)字体についての解説 第1 明朝体活字のデザインについて」から引用していた「例」を削除し、代わりに新常用漢字表から引用。
  • 附属書6(参考)「漢字の分類及び配列」の(旧)常用音訓を示す「[常]」を削除。(0208のみ)
  • 附属書12(参考)「この規格と常用漢字表との対応」を追加。区点位置・例示字体・音訓を示す。

というわけで、2010年11月30日の常用漢字表改定に合わせた小さな改正になっている。規格の内容自体に関しては、実質的な変更はない。

花園明朝OT+Web フォントによるIVSと OpenType feature tag の表示テスト

ブラウザ上で異体字を表示するには、2つの方法がある。異体字セレクタを使ってIVSで異体字を表現する方法と、CSS3の font-feature-settings プロパティを使って OpenType feature tag によるグリフ置換をする方法だ。今回、花園明朝OTを Web フォントとして利用し、この2つの方法で異体字の表示テストを行った。

方法の具体的な解説

IVSによる方法

IVS(Ideographic Variation Sequence)は親字(基底文字)にVS(Variation Selector; U+E0100–U+E01EF)をつけて異体字を表現する。詳しくは下の Wikipedia の記事などを参照。

この方法で表現される異体字は、基底文字の包摂範囲内に含まれることになっている。プレーンテキストとして扱えるので、HTMLで表示したければそのままIVS(=基底文字+VS)を書けばよい。通常の文字と同様、数値文字参照を使って書くこともできる。フォントやOS、アプリケーションが対応していない場合には、通常の基底文字のグリフが単に表示される(ことが望まれるが、VSが豆腐などで表示されてしまうことが多い)。

例えばHTMLで

葛 葛&#xe0100; 葛&#xe0101;

と書けば、

葛 葛󠄀 葛󠄁

のように表示される。

OpenType feature tag による方法

OpenType にはいろいろなタグが定義されているが、漢字に関係するタグは expt, hojo, jp78, jp83, jp90, nlck, trad, aalt などである。あるグリフから別のグリフへ、一対一や一対多で置換できる。Mac OS XInDesignIllustrator などでは以前から使われているが、それ以外の環境ではでは対応が進んでいないため、あまり使われていない。圧→壓 のように、包摂範囲外のグリフへの置換も定義されている。

プレーンテキストでは扱えないため、HTMLではCSS3の font-feature-settings プロパティを利用してタグを指定する。これはまだドラフト段階なので、実際にはベンダー接頭辞をつけて利用することになる。

例えば、jp90 タグを有効にするためには次のように指定する。

hoge {
  font-feature-settings:         "jp90" 1;
  -moz-font-feature-settings:    "jp90=1";
  -ms-font-feature-settings:     "jp90" 1;
  -webkit-font-feature-settings: "jp90" 1;
}

aalt のような一対多の置換を含むタグにおいて、n 番目のグリフに置換したい場合には、上の 1 の部分に n を指定する。

2013-05-03追記:この記事を書いた時点では -moz-font-feature-settings だけ指定方法が異なっていた("jp90=1")が、現在では他と同じ形式("jp90" 1)に変更されている。

表示のテスト

花園明朝OT ver. 0.510 を Web フォントとして利用し、表示テストを行った。フォントフォーマットはOTFとWOFF(Web Open Font Format)。OTFからWOFFへの変換については、武蔵システムのWOFFコンバータを利用した。

表示テストは Firefox, Safari, Chrome, Opera, IE8 の各ブラウザで行い、すべて最新版を用いた。OSは Windows XP SP3(そろそろ潮時ですかね…)。参考までに先日インストールした Windows 8 Comsumer Preview 上でもテストをしたが、OperaIE以外では差が見られなかった。

下の画像は、最も対応状況が優れていた Firefox での表示例。


▲ クリックで拡大

結果一覧

ブラウザ OS OTF WOFF IVS tag
Firefox 9.0 Win XP
Safari 5.1 Win XP × ×
Chrome 17.0 Win XP × ×*
Opera 11.61 Win XP × ×
IE 8.0 Win XP × × × ×
IE 10.0 Win 8 CP §
OTF
  • ○:OpenType フォーマットのフォントファイルを Web フォントとして利用できる。
  • ×:対応しておらず、他のフォントで表示される。
WOFF
  • ○:WOFFフォーマットのフォントファイルを Web フォントとして利用できる。
  • ×:対応しておらず、他のフォントで表示される。
IVS
  • ○:適切な異体字グリフが選択されて表示される。
  • ×:VSが豆腐や中黒、空白として表示されてしまう。
tag
  • ○:OpenType feature tag が利用できる。
  • ×:対応しておらず、無視される。

結果一覧の註

* Chrome における OpenType feature tag 対応

expt, hojo, jp78, jp83, jp90, nlck の各タグについては、指定するとデフォルトのフォントで描画されてしまうという不具合がある。trad, aalt については、無視される(これは対応していない場合に期待される動作)。expt, hojo, jp78, jp83, jp90, nlck はすべて一対一の置換である一方、trad, aalt には一対多の置換も含まれるという共通点がある。が、これが原因かどうかははっきりしない。

Opera における OpenType/WOFF 対応

OperaTrueType, OpenType, SVGフォント, WOFFの各形式に対応していると謳っているが、花園明朝OTでは表示できなかった。武蔵システムのサイトの情報でも、和文 OpenType や、そこから変換したWOFFは×になっている。CFFアウトラインの和文フォントがダメなんだろうか。

Opera におけるIVS対応

引用元が消えているが、Wikipedia によれば Windows 7 上の Opera でIVSが表示できるらしい。表には載せなかったが、今回 Windows 8 Comsumer Preview 上の Opera で表示できることを確認した。

§ IE10 における OpenType feature tag 対応

expt, hojo, jp78, jp83, jp90, nlck の各タグは正常に機能しグリフ置換が行われるが、trad, aalt については無視される。

また、IE10で花園明朝OTを表示させるとディセンダが大きく空いてしまうが、原因不明。

というわけで

Firefox がかなりいい感じ。他のブラウザの実装がいまいちなこともあり、実際に「使える」かどうかは疑問だが、覚えておくと何かの役に立つ……かも……?