OSDN Git Service

make rewriting process able to done without temporary files
[sawarabi-fonts/sawarabi-fonts.git] / script / export_as_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 if __name__ == '__main__':
148
149   class InvalidArgumentError(Exception):
150     '''コマンドライン引数が正しくない場合に生成される例外です。'''
151     def __init__(self, value):
152       self.value = value
153
154   def parse_args():
155     '''
156     コマンドライン引数の処理をします。
157     第一引数はフォントファイル、第二引数は保存先のディレクトリです。
158     オプションは下記のとおりです。
159
160      -f, --fill :
161             SVG のパスを塗りつぶす色を指定します。
162             省略すると、black が指定されたことになります。
163      -c, --comment :
164             コピーライトコメントを付ける場合に指定します。
165
166     Processes the arguments of command line.
167     The first of them is font file path, and the second of them is path of
168     directory in which the svg files will be stored.
169     The options are like this:
170
171      -f, --fill:
172             The color name with which fill the svg pathes.
173             Default is 'black.'
174      -c, --comment:
175             When this option is specified, the copyright is written as comment
176             in each svg files.
177     '''
178     usage = 'usage: %prog [-f color] [-c] fontfile directory'
179     p = optparse.OptionParser(usage=usage)
180     p.add_option('-f', '--fill', dest='color', default='black',
181                  help='name of color that is used when filling the svg pathes')
182     p.add_option('-c', '--comment', dest='comment', 
183                  action='store_true', default=False,
184                  help="write mshio's copyright as comment in each output files")
185     (opt, args) = p.parse_args()
186
187     if len(args) != 2:
188       p.error('incorrect number of arguments')
189       raise InvalidArgumentError
190
191     return (args[0], args[1], opt.color, opt.comment)
192
193
194   try:
195     (font_path, output_dir, color_name, comment) = parse_args()
196   except InvalidArgumentError:
197     sys.exit(1)
198
199   customizer = SvgCustomizer(color_name, comment)
200   font = fontforge.open(font_path)
201   for g in font:
202     if g[0] != '.':
203       glyph = font[g]
204       if glyph.unicode > 0:
205         path = '%s/%04x.svg' % (output_dir, glyph.unicode)
206         print path
207         glyph.export(path, 1)
208         customizer.execute(glyph, path)