TTCファイルを分解(分割)する
構造解析とは全く関係ありませんが・・・
通常ほとんど意識することはありませんが、フォントファイルの中にはTTC(TrueType Collection)という形式のファイルがあります。これはその名の通りTrueTypeフォントをいくつかまとめたものですが、フォントファイルをいじくりたいときには扱えなかったり、Linuxで扱いたくても扱えなかったりということがあります。そんな時は通常のTTFファイルに分割すれば操作できるようになるようです。
以前はMicrosoftから分割用のプログラムが配布されていたようですが、最近は公開されていない(まあ、ネットで探せば転がってますが)のでPerlで作ってみました。単純にTTCを分割したい場合に使えます。
動作保証もサポートもしません。また、著作権のあるフォントファイルを扱う場合はその規約に従って下さい。
内容
TTC形式はシンプルなフォーマットで、TTFファイルをまとめただけ、というような形式です。本スクリプトでは以下のような処理をしています。もっと細かい動作はスクリプトを読んでください。なお、対応しているTTCはVersion 1のみです(2にも使えるかもしれませんが、手元に確認環境がありません・・・)。
エラー処理などはほとんどしていないので、ヘンなファイルを読み込ませると誤動作の恐れがあります。動作確認はWinXP付属のmsgothic.ttcでしか行っていないので他のファイルではどうなるかはわかりませんので注意して下さい 。
- TTCのヘッダ読み込み
- 含まれているTTFのヘッダ読み込み
- TTFの書き出し
ってなところです。
SplitTTC
- 動作確認:Perl 5.10.0 (Vine Linux 5.0)
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
#!/usr/bin/perl # SplitTTC for spliting TTC file. # by Nob-rin,2009 # 2009-10-20 use strict; use open IO => ":raw"; $| = 1; my $TTC = {}; # TTC header info my @TTFS; # TTF header info list my $OUTFILE = "out%02d.ttf"; # Output file name template # Open TTC file my $buf; if($ARGV[0] eq ""){ print "Usage: splitttc TTCFile\n"; exit(0); } open(my $fh,$ARGV[0]) || die "Can't open $ARGV[0] [$!]\n"; read($fh,$buf,12); (@$TTC{qw/TTCTag Version numFonts/}) = unpack("A4H8N1",$buf); $TTC->{TTCTag} eq "ttcf" && $TTC->{Version} eq "00010000" || die "Format error. File must be TTC ver.1.\n"; # Reading TTF headers for(my $i=0;$i<$TTC->{numFonts};$i++){ my $ttf = {}; read($fh,$buf,4); $ttf->{offset} = unpack("N1",$buf); push(@TTFS,$ttf); } # Reading TTF tables foreach my $ttf (@TTFS) { seek($fh,$ttf->{offset},0); read($fh,$buf,12); @$ttf{qw/sfntVersion numTables searchRange entrySelector rangeShift/} = unpack("H8nnnn",$buf); $ttf->{tables} = []; for(my $i=0;$i<$ttf->{numTables};$i++){ read($fh,$buf,16); my $h = {}; @$h{qw/tag checkSum offset length/} = unpack("a4NNN",$buf); push(@{$ttf->{tables}},$h); } } # Writing out TTF files my $cnt = 0; foreach my $ttf (@TTFS) { my $fname = sprintf($OUTFILE,$cnt); print "Writing $fname ... "; open(my $out,sprintf(">$fname",$cnt)); # Space for TTF header print {$out} chr(0) x 12; # TTF header print {$out} chr(0) x (16 * $ttf->{numTables}); # TTF tables # Writing TTF data body foreach my $t (@{$ttf->{tables}}) { seek($fh,$t->{offset},0); read($fh,$buf,$t->{length}); if($t->{length} % 4){ $buf .= chr(0) x (4 - $t->{length} % 4) } # Insert padding $t->{offset} = tell($out); # Getting offset value print {$out} $buf; } # Write TTF headers seek($out,0,0); print {$out} pack("H8nnnn",@$ttf{qw/sfntVersion numTables searchRange entrySelector rangeShift/}); foreach my $t (@{$ttf->{tables}}) { print {$out} pack("a4NNN",@$t{qw/tag checkSum offset length/}); } close $out; print "Done\n"; $cnt++ } close $fh;
使い方
モジュールは使っていないのでPerlがインストールされていれば使えるはずです。
% perl splitttc.pl msgothic.ttc Writing out00.ttf ... Done Writing out01.ttf ... Done Writing out02.ttf ... Done
こんな風に書き出されます。
参考
- http://www.microsoft.com/typography/otspec/ -- OpenType specification
コメント
コメントなどありましたらよろしくお願いします。
- PDF::API2でmsgothicが使えず困ってました。msminchoでもうまく動きましたよ。out00が等幅、out01がプロポーショナル・フォントみたいですね。 -- tom-leo-zero 2010-01-08 (金) 13:50:21
- 検証ありがとうございます。意外と汎用性ありましたね(^^; -- どぶお 2010-01-08 (金) 20:34:25