diff options
author | Rasmus Andersson <rasmus@notion.se> | 2018-09-04 02:59:55 +0300 |
---|---|---|
committer | Rasmus Andersson <rasmus@notion.se> | 2018-09-04 02:59:55 +0300 |
commit | 3099bc6495489489feca8f28d2132c38ced8776a (patch) | |
tree | fe8e8484c24d8ff15bfec5ed30b67d6453bcc2ef /misc/tools/svg.py | |
parent | 11435926ba33c024670acbfdc7bb35d1991ef614 (diff) | |
download | inter-3099bc6495489489feca8f28d2132c38ced8776a.tar.xz |
upgrade misc/tools/gen-metrics-and-svgs.py to new toolchain
Diffstat (limited to 'misc/tools/svg.py')
-rw-r--r-- | misc/tools/svg.py | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/misc/tools/svg.py b/misc/tools/svg.py new file mode 100644 index 000000000..e09eed7c1 --- /dev/null +++ b/misc/tools/svg.py @@ -0,0 +1,264 @@ +# encoding: utf8 +# +# The MIT License +# +# Copyright (c) 2010 Type Supply LLC +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# https://github.com/typesupply/ufo2svg +# +from __future__ import absolute_import +from fontTools.pens.basePen import BasePen + + +def valueToString(v): + """ + >>> valueToString(0) + '0' + >>> valueToString(10) + '10' + >>> valueToString(-10) + '-10' + >>> valueToString(0.1) + '0.1' + >>> valueToString(0.0001) + '0.0001' + >>> valueToString(0.00001) + '0' + >>> valueToString(10.0001) + '10.0001' + >>> valueToString(10.00001) + '10' + """ + if int(v) == v: + v = "%d" % (int(v)) + else: + v = "%.4f" % v + # strip unnecessary zeros + # there is probably an easier way to do this + compiled = [] + for c in reversed(v): + if not compiled and c == "0": + continue + compiled.append(c) + v = "".join(reversed(compiled)) + if v.endswith("."): + v = v[:-1] + if not v: + v = "0" + return v + + +def pointToString(pt): + # return " ".join([valueToString(i) for i in pt]) + return valueToString(pt[0]) + " " + valueToString(pt[1]) + + +class SVGPathPen(BasePen): + + def __init__(self, glyphSet, yMul): + BasePen.__init__(self, glyphSet) + self._commands = [] + self._lastCommand = None + self._lastX = None + self._lastY = None + self._yMul = yMul + + # def pointToString(self, pt): + # pts = [] + # n = 0 + # for i in pt: + # if n == 1: + # i = i * self._yMul + # pts.append(valueToString(i)) + # n = n + 1 + # return " ".join(pts) + + + def pt(self, pt1): + return (pt1[0], pt1[1] * self._yMul) + + + def _handleAnchor(self): + """ + >>> pen = SVGPathPen(None) + >>> pen.moveTo((0, 0)) + >>> pen.moveTo((10, 10)) + >>> pen._commands + ['M10 10'] + """ + if self._lastCommand == "M": + self._commands.pop(-1) + + def _moveTo(self, pt): + """ + >>> pen = SVGPathPen(None) + >>> pen.moveTo((0, 0)) + >>> pen._commands + ['M0 0'] + + >>> pen = SVGPathPen(None) + >>> pen.moveTo((10, 0)) + >>> pen._commands + ['M10 0'] + + >>> pen = SVGPathPen(None) + >>> pen.moveTo((0, 10)) + >>> pen._commands + ['M0 10'] + """ + pt = self.pt(pt) + self._handleAnchor() + t = "M%s" % (pointToString(pt)) + self._commands.append(t) + self._lastCommand = "M" + self._lastX, self._lastY = pt + + def _lineTo(self, pt): + """ + # duplicate point + >>> pen = SVGPathPen(None) + >>> pen.moveTo((10, 10)) + >>> pen.lineTo((10, 10)) + >>> pen._commands + ['M10 10'] + + # vertical line + >>> pen = SVGPathPen(None) + >>> pen.moveTo((10, 10)) + >>> pen.lineTo((10, 0)) + >>> pen._commands + ['M10 10', 'V0'] + + # horizontal line + >>> pen = SVGPathPen(None) + >>> pen.moveTo((10, 10)) + >>> pen.lineTo((0, 10)) + >>> pen._commands + ['M10 10', 'H0'] + + # basic + >>> pen = SVGPathPen(None) + >>> pen.lineTo((70, 80)) + >>> pen._commands + ['L70 80'] + + # basic following a moveto + >>> pen = SVGPathPen(None) + >>> pen.moveTo((0, 0)) + >>> pen.lineTo((10, 10)) + >>> pen._commands + ['M0 0', ' 10 10'] + """ + pt = self.pt(pt) + x, y = pt + # duplicate point + if x == self._lastX and y == self._lastY: + return + # vertical line + elif x == self._lastX: + cmd = "V" + pts = valueToString(y) + # horizontal line + elif y == self._lastY: + cmd = "H" + pts = valueToString(x) + # previous was a moveto + elif self._lastCommand == "M": + cmd = None + pts = " " + pointToString(pt) + # basic + else: + cmd = "L" + pts = pointToString(pt) + # write the string + t = "" + if cmd: + t += cmd + self._lastCommand = cmd + t += pts + self._commands.append(t) + # store for future reference + self._lastX, self._lastY = pt + + def _curveToOne(self, pt1, pt2, pt3): + """ + >>> pen = SVGPathPen(None) + >>> pen.curveTo((10, 20), (30, 40), (50, 60)) + >>> pen._commands + ['C10 20 30 40 50 60'] + """ + pt1 = self.pt(pt1) + pt2 = self.pt(pt2) + pt3 = self.pt(pt3) + t = "C" + t += pointToString(pt1) + " " + t += pointToString(pt2) + " " + t += pointToString(pt3) + self._commands.append(t) + self._lastCommand = "C" + self._lastX, self._lastY = pt3 + + def _qCurveToOne(self, pt1, pt2): + """ + >>> pen = SVGPathPen(None) + >>> pen.qCurveTo((10, 20), (30, 40)) + >>> pen._commands + ['Q10 20 30 40'] + """ + assert pt2 is not None + pt1 = self.pt(pt1) + pt2 = self.pt(pt2) + t = "Q" + t += pointToString(pt1) + " " + t += pointToString(pt2) + self._commands.append(t) + self._lastCommand = "Q" + self._lastX, self._lastY = pt2 + + def _closePath(self): + """ + >>> pen = SVGPathPen(None) + >>> pen.closePath() + >>> pen._commands + ['Z'] + """ + self._commands.append("Z") + self._lastCommand = "Z" + self._lastX = self._lastY = None + + def _endPath(self): + """ + >>> pen = SVGPathPen(None) + >>> pen.endPath() + >>> pen._commands + ['Z'] + """ + self._closePath() + self._lastCommand = None + self._lastX = self._lastY = None + + def getCommands(self): + return "".join(self._commands) + + +if __name__ == "__main__": + import doctest + doctest.testmod() |