OSDN Git Service

add and modify docstring
[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     書き換えたファイルのファイル名は、元の SVG ファイルの
61     末尾に '~' をつけたものになります。
62
63     引数:
64       glyph -- FontForge のもつグリフオブジェクト
65       file  -- FontForge の書き出した SVG ファイルのファイル名。文字列
66
67     Parses the SVG file that is output by FontForge, and outputs a new 
68     SVG file that can be displayed by a web browser.
69     The new file has a name which is equal to the original file name 
70     added '~' letter at the end.
71
72     Arguments:
73       glyph -- glyph object
74       file  -- SVG file name
75     '''
76     self.setup(glyph)
77     try:
78       self.out = open(file + '~', 'w')
79       fh = open(file, 'r')
80       self.parser.ParseFile(fh)
81     except:
82       print sys.exc_info()[0]
83     fh.close()
84     self.out.close()
85
86   def setup(self, glyph):
87     '''内部にもつ XML パーサーのセットアップを行います。'''
88     self.glyph = glyph
89     self.parser = xml.parsers.expat.ParserCreate()
90     self.parser.XmlDeclHandler = self.startXmlDeclaration
91     self.parser.StartDoctypeDeclHandler = self.startDoctypeDeclaration
92     self.parser.StartElementHandler = self.startElement
93     self.parser.EndElementHandler = self.endElement
94
95   def startXmlDeclaration(self, version, encoding, standalone):
96     '''XML 宣言部分のパースと書き出しを行います。'''
97     self.out.write('<?xml')
98     if version:
99       self.out.write(' version="%s"' % version)
100     if encoding:
101       self.out.write(' encoding="%s"' % encoding)
102     if standalone != -1:
103       val = 'yes' if standalone == 1 else 'no'
104       self.out.write(' standalone="%s"' % val)
105     self.out.write('?>')
106
107   def startDoctypeDeclaration(self, doctype, sysId, pubId, hasSubset):
108     '''DOCTYPE 部分のパースと書き出しを行います。'''
109     self.out.write('<!DOCTYPE %s' % doctype)
110     if pubId:
111       self.out.write(' PUBLIC "%s"' % pubId)
112     if sysId:
113       self.out.write(' "%s"' % sysId)
114     self.out.write('>')
115     if self.with_comment:
116       self.out.write('<!-- %s -->' % COPYRIGHT)
117
118   def startElement(self, name, attrs):
119     '''各要素の開始部分を読み込み、その部分の書き出しを行います。'''
120     self.out.write('<%s' % name)
121     isSvg = name == 'svg'
122     isPath = name == 'path'
123     if isSvg:
124       self.out.write(' xmlns="http://www.w3.org/2000/svg"')
125     for k in attrs.keys():
126       if isSvg and k == 'viewBox':
127         org = attrs[k].split()
128         w = self.glyph.width - int(org[0])
129         # here, using magic numbers at the values of top and height.
130         # if using this script for some other fonts,
131         # you might have to change these values.
132         val = '%s -100 %d 1200' % (org[0], w)
133         self.out.write(' %s="%s"' % (k, val))
134       elif isPath and k == 'fill':
135         self.out.write(' %s="%s"' % (k, self.fill_color))
136       else:
137         self.out.write(' %s="%s"' % (k, attrs[k]))
138     self.out.write('>')
139
140   def endElement(self, name):
141     '''各要素の終了部分を読み込み、その部分の書き出しを行います。'''
142     self.out.write('</%s>' % name)
143
144 # --------------------------------------------
145 # function
146 # --------------------------------------------
147 def make_svg(glyph, filename, customizer):
148   '''
149   SVG ファイルの生成と書き換えを行います。
150
151   まず FontForge の export 機能で SVG ファイルを生成し、次いで SvgCustomizer で
152   その内容を書き換えます。
153   SVGCustomizer は末尾に '~' の付いたファイルを出力するので、最後にファイル名を
154   書き換えます。
155
156   Exporting SVG file of the specified glyph, and outputing new displayable one.
157   '''
158   glyph.export(filename, 1)
159   customizer.execute(glyph, filename)
160   
161   os.remove(filename)
162   os.rename('%s~' % filename, filename)
163
164 if __name__ == '__main__':
165
166   class InvalidArgumentError(Exception):
167     '''コマンドライン引数が正しくない場合に生成される例外です。'''
168     def __init__(self, value):
169       self.value = value
170
171   def parse_args():
172     '''
173     コマンドライン引数の処理をします。
174     第一引数はフォントファイル、第二引数は保存先のディレクトリです。
175     オプションは下記のとおりです。
176
177      -f, --fill :
178             SVG のパスを塗りつぶす色を指定します。
179             省略すると、black が指定されたことになります。
180      -c, --comment :
181             コピーライトコメントを付ける場合に指定します。
182     '''
183     usage = 'usage: %prog [-f color] [-c] fontfile directory'
184     p = optparse.OptionParser(usage=usage)
185     p.add_option('-f', '--fill', dest='color', default='black',
186                  help='name of color that is used when filling the svg pathes')
187     p.add_option('-c', '--comment', dest='comment', 
188                  action='store_true', default=False,
189                  help='write mshio\'s copyright as comment in each output file')
190     (opt, args) = p.parse_args()
191
192     if len(args) != 2:
193       p.error("incorrect number of arguments")
194       raise InvalidArgumentError
195
196     return (args[0], args[1], opt.color, opt.comment)
197
198
199   try:
200     (font_path, output_dir, color_name, comment) = parse_args()
201   except InvalidArgumentError:
202     sys.exit(1)
203
204   customizer = SvgCustomizer(color_name, comment)
205   font = fontforge.open(font_path)
206   for g in font:
207     if g[0] != '.':
208       glyph = font[g]
209       if glyph.unicode > 0:
210         path = '%s/%04x.svg' % (output_dir, glyph.unicode)
211         print path
212         make_svg(glyph, path, customizer)