OSDN Git Service

15eaf0ea33f23b2bd226b89e6f743d406ddc29e8
[sawarabi-fonts/sawarabi-fonts.git] / script / export_to_svg.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 # Copyright (C) 2009, mshio <mshio@users.sourceforge.jp>
5 #
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.
10 #
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.
15 #
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/>.
18
19 import fontforge
20 import optparse
21 import os
22 import sys
23 import xml.parsers.expat
24
25 COPYRIGHT = 'copyright (c) 2008-2009 mshio (mshio@users.sourceforge.jp)'
26
27 class SvgCustomizer:
28   '''
29   FontForge が書き出した SVG ファイルの内容を書き換え、
30   ウェブブラウザで表示できるようにするためのクラスです。
31
32   インスタンスを生成した後、execute メソッドを呼び出してください。
33
34   This class is for converting SVG files that are generated by FontForge
35   to ones that can be displayed by a web browser.
36
37   After getting an instance, call its execute method.
38   '''
39
40   def __init__(self, fill_color, comment):
41     '''
42     コンストラクタ
43
44     引数:
45       fill_color -- SVG のパスを塗りつぶすための色。文字列
46       comment    -- コピーライトコメントを付けるかどうか。True/False
47
48     Constructor
49
50     Arguments:
51       fill_color -- color name for filling svg pathes.
52       comment    -- True if adding copyright comment.
53     '''
54     self.fill_color = fill_color
55     self.with_comment = comment
56
57   def execute(self, glyph, file):
58     '''
59     FontForge が書き出した SVG ファイルを解析し、目的の形式に書き換えます。
60
61     引数:
62       glyph -- FontForge のもつグリフオブジェクト
63       file  -- FontForge の書き出した SVG ファイルのファイル名。文字列
64
65     Parses the SVG file that is output by FontForge, and outputs a new 
66     SVG file that can be displayed by a web browser.
67
68     Arguments:
69       glyph -- glyph object
70       file  -- SVG file name
71     '''
72     self.setup(glyph)
73     try:
74       c = self.get_contents(file)
75       self.out = open(file, 'w')
76       self.parser.Parse(c, 1)
77     except:
78       print sys.exc_info()[0]
79     self.out.close()
80
81   def setup(self, glyph):
82     '''内部にもつ XML パーサーのセットアップを行います。'''
83     self.glyph = glyph
84     self.parser = xml.parsers.expat.ParserCreate()
85     self.parser.XmlDeclHandler = self.start_xml_declaration
86     self.parser.StartDoctypeDeclHandler = self.start_doctype_declaration
87     self.parser.StartElementHandler = self.start_element
88     self.parser.EndElementHandler = self.end_element
89
90   def get_contents(self, file):
91     '''指定したファイルの内容を読み込んで返します。'''
92     h = open(file, 'r')
93     c = h.read()
94     h.close()
95     return c
96
97   def start_xml_declaration(self, version, encoding, standalone):
98     '''XML 宣言部分のパースと書き出しを行います。'''
99     self.out.write('<?xml')
100     if version:
101       self.out.write(' version="%s"' % version)
102     if encoding:
103       self.out.write(' encoding="%s"' % encoding)
104     if standalone != -1:
105       val = 'yes' if standalone == 1 else 'no'
106       self.out.write(' standalone="%s"' % val)
107     self.out.write('?>')
108
109   def start_doctype_declaration(self, doctype, sys_id, pub_id, has_subset):
110     '''DOCTYPE 部分のパースと書き出しを行います。'''
111     self.out.write('<!DOCTYPE %s' % doctype)
112     if pub_id:
113       self.out.write(' PUBLIC "%s"' % pub_id)
114     if sys_id:
115       self.out.write(' "%s"' % sys_id)
116     self.out.write('>')
117     if self.with_comment:
118       self.out.write('<!-- %s -->' % COPYRIGHT)
119
120   def start_element(self, name, attrs):
121     '''各要素の開始部分を読み込み、その部分の書き出しを行います。'''
122     self.out.write('<%s' % name)
123     is_svg = name == 'svg'
124     is_path = name == 'path'
125     if is_svg:
126       self.out.write(' xmlns="http://www.w3.org/2000/svg"')
127     for k in attrs.keys():
128       if is_svg and k == 'viewBox':
129         org = attrs[k].split()
130         w = self.glyph.width - int(org[0])
131         # here, using magic numbers at the values of top and height.
132         # if using this script for some other fonts,
133         # you might have to change these values.
134         val = '%s -100 %d 1200' % (org[0], w)
135         self.out.write(' %s="%s"' % (k, val))
136       elif is_path and k == 'fill':
137         self.out.write(' %s="%s"' % (k, self.fill_color))
138       else:
139         self.out.write(' %s="%s"' % (k, attrs[k]))
140     self.out.write('>')
141
142   def end_element(self, name):
143     '''各要素の終了部分を読み込み、その部分の書き出しを行います。'''
144     self.out.write('</%s>' % name)
145
146 # --------------------------------------------
147 # function
148 # --------------------------------------------
149 def make_svg(glyph, filename, customizer):
150   '''
151   SVG ファイルの生成と書き換えを行います。
152
153   まず FontForge の export 機能で SVG ファイルを生成し、次いで SvgCustomizer で
154   その内容を書き換えます。
155
156   引数:
157     glyph      -- 書き出す対象のグリフオブジェクト
158     filename   -- FontForge が書き出す SVG ファイルの名前
159     customizer -- SvgCustomizer のインスタンス
160
161   Exports a SVG file from the specified glyph, and outputs new displayable one.
162
163   Arguments:
164     glyph      -- target glyph object
165     filename   -- file name of the SVG file that will be output by FontForge
166     customizer -- an instance of SvgCustomizer
167   '''
168   glyph.export(filename, 1)
169   customizer.execute(glyph, filename)
170
171
172 if __name__ == '__main__':
173
174   class InvalidArgumentError(Exception):
175     '''コマンドライン引数が正しくない場合に生成される例外です。'''
176     def __init__(self, value):
177       self.value = value
178
179   def parse_args():
180     '''
181     コマンドライン引数の処理をします。
182     第一引数はフォントファイル、第二引数は保存先のディレクトリです。
183     オプションは下記のとおりです。
184
185      -f, --fill :
186             SVG のパスを塗りつぶす色を指定します。
187             省略すると、black が指定されたことになります。
188      -c, --comment :
189             コピーライトコメントを付ける場合に指定します。
190
191     Processes the arguments of command line.
192     The first of them is font file path, and the second of them is path of
193     directory in which the svg files will be stored.
194     The options are like this:
195
196      -f, --fill:
197             The color name with which fill the svg pathes.
198             Default is 'black.'
199      -c, --comment:
200             When this option is specified, the copyright is written as comment
201             in each svg files.
202     '''
203     usage = 'usage: %prog [-f color] [-c] fontfile directory'
204     p = optparse.OptionParser(usage=usage)
205     p.add_option('-f', '--fill', dest='color', default='black',
206                  help='name of color that is used when filling the svg pathes')
207     p.add_option('-c', '--comment', dest='comment', 
208                  action='store_true', default=False,
209                  help="write mshio's copyright as comment in each output files")
210     (opt, args) = p.parse_args()
211
212     if len(args) != 2:
213       p.error('incorrect number of arguments')
214       raise InvalidArgumentError
215
216     return (args[0], args[1], opt.color, opt.comment)
217
218
219   try:
220     (font_path, output_dir, color_name, comment) = parse_args()
221   except InvalidArgumentError:
222     sys.exit(1)
223
224   customizer = SvgCustomizer(color_name, comment)
225   font = fontforge.open(font_path)
226   for g in font:
227     if g[0] != '.':
228       glyph = font[g]
229       if glyph.unicode > 0:
230         path = '%s/%04x.svg' % (output_dir, glyph.unicode)
231         print path
232         make_svg(glyph, path, customizer)