-
-
Save CatherineH/499a312a04582a00e7559ac0c8f133fa to your computer and use it in GitHub Desktop.
from svgpathtools import wsvg, Line, QuadraticBezier, Path | |
from freetype import Face | |
def tuple_to_imag(t): | |
return t[0] + t[1] * 1j | |
face = Face('./Vera.ttf') | |
face.set_char_size(48 * 64) | |
face.load_char('a') | |
outline = face.glyph.outline | |
y = [t[1] for t in outline.points] | |
# flip the points | |
outline_points = [(p[0], max(y) - p[1]) for p in outline.points] | |
start, end = 0, 0 | |
paths = [] | |
for i in range(len(outline.contours)): | |
end = outline.contours[i] | |
points = outline_points[start:end + 1] | |
points.append(points[0]) | |
tags = outline.tags[start:end + 1] | |
tags.append(tags[0]) | |
segments = [[points[0], ], ] | |
for j in range(1, len(points)): | |
segments[-1].append(points[j]) | |
if tags[j] and j < (len(points) - 1): | |
segments.append([points[j], ]) | |
for segment in segments: | |
if len(segment) == 2: | |
paths.append(Line(start=tuple_to_imag(segment[0]), | |
end=tuple_to_imag(segment[1]))) | |
elif len(segment) == 3: | |
paths.append(QuadraticBezier(start=tuple_to_imag(segment[0]), | |
control=tuple_to_imag(segment[1]), | |
end=tuple_to_imag(segment[2]))) | |
elif len(segment) == 4: | |
C = ((segment[1][0] + segment[2][0]) / 2.0, | |
(segment[1][1] + segment[2][1]) / 2.0) | |
paths.append(QuadraticBezier(start=tuple_to_imag(segment[0]), | |
control=tuple_to_imag(segment[1]), | |
end=tuple_to_imag(C))) | |
paths.append(QuadraticBezier(start=tuple_to_imag(C), | |
control=tuple_to_imag(segment[2]), | |
end=tuple_to_imag(segment[3]))) | |
else: | |
print(f"incompatible segment length: {len(segment)}") | |
start = end + 1 | |
path = Path(*paths) | |
wsvg(path, filename="text.svg") |
as test with char 'B' and
face = Face('C:\Windows\Fonts\arial.ttf')
there are some segments of length 5 and 6
this seems to be Ok (as TrueType infact has only quads):
...
elif len(segment) == 5:
C12 = segment[1]
C23 = segment[2]
C34 = segment[3]
P1 = segment[0]
P2 = ((segment[1][0] + segment[2][0]) / 2.0,
(segment[1][1] + segment[2][1]) / 2.0)
P3 = ((segment[2][0] + segment[3][0]) / 2.0,
(segment[2][1] + segment[3][1]) / 2.0)
P4 = segment[4]
paths.append(QuadraticBezier(start=tuple_to_imag(P1),
control=tuple_to_imag(C12),
end=tuple_to_imag(P2)))
paths.append(QuadraticBezier(start=tuple_to_imag(P2),
control=tuple_to_imag(C23),
end=tuple_to_imag(P3)))
paths.append(QuadraticBezier(start=tuple_to_imag(P3),
control=tuple_to_imag(C34),
end=tuple_to_imag(P4)))
elif len(segment) == 6:
C12 = segment[1]
C23 = segment[2]
C34 = segment[3]
C45 = segment[4]
P1 = segment[0]
P2 = ((segment[1][0] + segment[2][0]) / 2.0,
(segment[1][1] + segment[2][1]) / 2.0)
P3 = ((segment[2][0] + segment[3][0]) / 2.0,
(segment[2][1] + segment[3][1]) / 2.0)
P4 = ((segment[3][0] + segment[4][0]) / 2.0,
(segment[3][1] + segment[4][1]) / 2.0)
P5 = segment[5]
paths.append(QuadraticBezier(start=tuple_to_imag(P1),
control=tuple_to_imag(C12),
end=tuple_to_imag(P2)))
paths.append(QuadraticBezier(start=tuple_to_imag(P2),
control=tuple_to_imag(C23),
end=tuple_to_imag(P3)))
paths.append(QuadraticBezier(start=tuple_to_imag(P3),
control=tuple_to_imag(C34),
end=tuple_to_imag(P4)))
paths.append(QuadraticBezier(start=tuple_to_imag(P4),
control=tuple_to_imag(C45),
end=tuple_to_imag(P5)))
By the way:
def move_to(a, ctx):
ctx.append("M {},{}".format(a.x, a.y))
def line_to(a, ctx):
ctx.append("L {},{}".format(a.x, a.y))
def conic_to(a, b, ctx):
ctx.append("Q {},{} {},{}".format(a.x, a.y, b.x, b.y))
def cubic_to(a, b, c, ctx):
ctx.append("C {},{} {},{} {},{}".format(a.x, a.y, b.x, b.y, c.x, c.y))
ctx = []
outline.decompose(ctx, move_to=move_to, line_to=line_to, conic_to=conic_to, cubic_to=cubic_to)
works, but gives svg "y" in the opposite direction
https://github.com/rougier/freetype-py/releases
https://github.com/rougier/freetype-py/blob/master/examples/glyph-vector-decompose.py
Has someone here understood the face.set_char_size() and how to get a 'reasonable' svg font size ?
how to get the right scaling back to for example to style="font-size=11" , when working with svg ?
Thanks in advance,
XM
... and with ctx:
svg = """
<svg xmlns="http://www.w3.org/2000/svg"
width="100mm"
height="100mm"
viewBox="0 0 100 100"
version="1.1"
<path
transform="scale(0.00338) scale(10)"
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
d="{}"
/>
""".format(" ".join(ctx))
print(svg)
@CatherineH The link was just an example. Also I'm quite bad in understanding heavily math-ed papers :D
Does that mean that
FT_Outline_Decompose
isn't as helpful as you first thought?