2 # -*- coding: utf-8 -*-
4 # Copyright (C) 2009-2010, mshio <mshio@users.sourceforge.jp>
6 # This program is free software: you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 import xml.parsers.expat
26 COPYRIGHT = 'Copyright: (c) 2008-%d mshio <mshio@users.sourceforge.jp>'
30 FontForge が書き出した SVG ファイルの内容を書き換え、
31 ウェブブラウザで表示できるようにするためのクラスです。
33 インスタンスを生成した後、execute メソッドを呼び出してください。
35 This class is for converting SVG files that are generated by FontForge
36 to ones that can be displayed by a web browser.
38 After getting an instance, call its execute method.
41 def __init__(self, fill_color, comment):
46 fill_color -- SVG のパスを塗りつぶすための色。文字列
47 comment -- コピーライトコメントを付けるかどうか。True/False
52 fill_color -- color name for filling svg pathes.
53 comment -- True if adding copyright comment.
55 self.fill_color = fill_color
56 self.with_comment = comment
58 def execute(self, glyph, file):
60 FontForge が書き出した SVG ファイルを解析し、目的の形式に書き換えます。
63 glyph -- FontForge のもつグリフオブジェクト
64 file -- FontForge の書き出した SVG ファイルのファイル名。文字列
66 Parses the SVG file that is output by FontForge, and outputs a new
67 SVG file that can be displayed by a web browser.
75 c = self.get_contents(file)
76 self.out = open(file, 'w')
77 self.parser.Parse(c, 1)
79 print sys.exc_info()[0]
82 def setup(self, glyph):
83 '''内部にもつ XML パーサーのセットアップを行います。'''
85 self.parser = xml.parsers.expat.ParserCreate()
86 self.parser.XmlDeclHandler = self.start_xml_declaration
87 self.parser.StartDoctypeDeclHandler = self.start_doctype_declaration
88 self.parser.StartElementHandler = self.start_element
89 self.parser.EndElementHandler = self.end_element
91 def get_contents(self, file):
92 '''指定したファイルの内容を読み込んで返します。'''
98 def start_xml_declaration(self, version, encoding, standalone):
99 '''XML 宣言部分のパースと書き出しを行います。'''
100 self.out.write('<?xml')
102 self.out.write(' version="%s"' % version)
104 self.out.write(' encoding="%s"' % encoding)
106 val = 'yes' if standalone == 1 else 'no'
107 self.out.write(' standalone="%s"' % val)
110 def start_doctype_declaration(self, doctype, sys_id, pub_id, has_subset):
111 '''DOCTYPE 部分のパースと書き出しを行います。'''
112 self.out.write('<!DOCTYPE %s' % doctype)
114 self.out.write(' PUBLIC "%s"' % pub_id)
116 self.out.write(' "%s"' % sys_id)
119 def start_element(self, name, attrs):
121 各要素の開始部分を読み込み、その部分の書き出しを行います。
122 要素名が 'svg' の場合、xmlns 属性を付加し、さらに viewBox の値を変更し、
123 またさらにコピーライトの出力が指示されている場合は、svg 要素の後に
124 metadata 要素を追加し、そこにコピーライトを出力します。
125 要素名が 'path' の場合は、fill 属性の有無をチェックし、
128 self.out.write('<%s' % name)
129 is_svg = name == 'svg'
130 is_path = name == 'path'
132 self.out.write(' xmlns="http://www.w3.org/2000/svg"')
133 for k in attrs.keys():
134 if is_svg and k == 'viewBox':
135 org = attrs[k].split()
136 w = self.glyph.width - int(org[0])
137 # here, using magic numbers at the values of top and height.
138 # if using this script for some other fonts,
139 # you might have to change these values.
140 val = '%s -100 %d 1200' % (org[0], w)
141 self.out.write(' %s="%s"' % (k, val))
142 elif is_path and k == 'fill':
143 self.out.write(' %s="%s"' % (k, self.fill_color))
145 self.out.write(' %s="%s"' % (k, attrs[k]))
147 # output copyright string
148 if is_svg and self.with_comment:
149 c = COPYRIGHT % time.localtime()[0]
150 self.out.write('<metadata><![CDATA[ %s ]]></metadata>' % c)
152 def end_element(self, name):
153 '''各要素の終了部分を読み込み、その部分の書き出しを行います。'''
154 self.out.write('</%s>' % name)
159 def make_svg(customizer, glyph, output_dir):
161 SVG ファイルの生成と書き換えを行います。
163 まず FontForge の export 機能で SVG ファイルを生成し、
164 次いで SvgCustomizer でその内容を書き換えます。
167 customizer -- SvgCustomizer のインスタンス
168 glyph -- 書き出す対象のグリフオブジェクト
169 output_dir -- 出力先のディレクトリ
171 Exports a SVG file from the specified glyph, and
172 outputs new one that can be displayed with a web browser.
175 customizer -- an instance of SvgCustomizer
176 glyph -- target glyph object
177 output_dir -- directory for SVG files that will be outputed by this script
179 path = '%s/%04x.svg' % (output_dir, glyph.unicode)
181 glyph.export(path, 1)
182 customizer.execute(glyph, path)
185 if __name__ == '__main__':
187 class InvalidArgumentError(Exception):
188 '''コマンドライン引数が正しくない場合に生成される例外です。'''
189 def __init__(self, value):
195 第一引数はフォントファイル、第二引数は保存先のディレクトリです。
199 SVG のパスを塗りつぶす色を指定します。
200 省略すると、black が指定されたことになります。
202 コピーライト(内容は固定)を含める場合に指定します。
203 コピーライトは、metadata のデータとして挿入されます。
205 フォントが持つ全グリフではなく、特定の文字のみの
206 SVG ファイルを出力したい場合に指定します。
207 指定は、16 進数の文字コード(Unicode)で行います。
209 Processes the arguments of command line.
210 The first of them is font file path, and the second of them is path of
211 directory in which the svg files will be stored.
212 The options are like this:
215 The color name with which fill the svg pathes.
218 When this option is specified, the copyright is written as
219 'metadata' in each svg files.
221 Character code (hex). When this option is specified,
222 this script will output only a SVG file of the specified character.
223 When not, it will output ones of all glyphs.
225 usage = 'usage: %prog [-f color] [-c] fontfile directory'
226 p = optparse.OptionParser(usage=usage)
227 p.add_option('-f', '--fill', dest='color', default='black',
228 help='name of color that is used when filling the svg pathes')
229 p.add_option('-c', '--copyright', dest='copyright',
230 action='store_true', default=False,
231 help="write mshio's copyright in each output files")
232 p.add_option('-g', '--glyph', dest='code', default=None,
233 help='char code that wants to be output')
234 (opt, args) = p.parse_args()
237 p.error('incorrect number of arguments')
238 raise InvalidArgumentError
240 return (args[0], args[1], opt.color, opt.copyright, opt.code)
244 (font_path, output_dir, color_name, comment, code) = parse_args()
245 except InvalidArgumentError:
248 char_code = int(code, 16) if code else None
250 customizer = SvgCustomizer(color_name, comment)
251 font = fontforge.open(font_path)
253 make_svg(customizer, font[char_code], output_dir)
258 if glyph.unicode > 0:
259 make_svg(customizer, glyph, output_dir)