mirror of
https://github.com/rsms/inter.git
synced 2024-12-02 15:54:46 +03:00
265 lines
6.8 KiB
Python
265 lines
6.8 KiB
Python
|
# 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()
|