-
For a few weeks, I'm trying to create an OTF-SVG font. I have mainly followed the code by adobe's tool for creating them. To explain my problem, I have created a simplified example of my situation and you find the scripts attached: source code The question is: How to get properly rescaled SVG glyphs in an OTF font? 1. Dummy Font CreationFirst, I create a dummy font having dummy glyphs. In this example, only the glyph To run the script, install fontforge and python and run 2. Attaching SVG FilesThe second step is to attach SVG files in the SVG table of the font. As suggested by opentypesvg tool, I remove both widht and height, as well as the viewport property of the To run the script, run 3. ResultTerminal output: (note that SVG and font have the same viewport and that font is correctly validated by fontforge) Inkscape: (the green background is the text-selection color of one character, it shows the maximum size a glyph can have) |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
So basically the problem was the rescaling of the SVG. I don't have a clear rule to follow, but I found a rule of thumb that works in my case. Here is the code I used, based on an Inkscape extension for baking transformations (scaling and transposing) to the SVG objects: import re, io
import inkex
from .applytransform import ApplyTransform # extension from here:https://github.com/Klowner/inkscape-applytransforms/blob/master/applytransform.py
number = r"[-+]?[0-9]*\.?[0-9]+"
SVG_VIEWPORT = re.compile(
# rf"<svg[^>]*viewBox=['\"]({number} +{number} +{number} +{number})['\"][^>]*>"
rf"<svg[^>]*(viewBox\s*=\s*['\"]{number} +{number} +{number} +{number}['\"])[^>]*>"
)
SVG_VIEWPORT_SIZE = re.compile(rf"{number} +{number} +{number} +{number}")
SVG_WIDTH = re.compile(r"<svg[^>]*(?:\s*(width\s*=\s*['\"][^'\"]+['\"]))\s*[^>]*>")
SVG_HEIGHT = re.compile(r"<svg[^>]*(?:\s*(height\s*=\s*['\"][^'\"]+['\"]))\s*[^>]*>")
SVG_CONTENT = re.compile(r"<svg[^>]*>(.+)</svg>", flags=re.DOTALL)
def fix_svg_for_fonts(svg: str, font_viewport: tuple, unitsPerEm: int) -> str:
# removing svg height and width attributes
for pattern in (SVG_HEIGHT, SVG_WIDTH):
match = pattern.search(svg)
if match is not None:
svg = svg[: match.start(1)] + ' ' + svg[match.end(1):]
x, y, w, h = font_viewport
# 1. remove svg viewport
match = SVG_VIEWPORT.search(svg)
if match is not None:
viewBox_string = match.group(1)
viewBox_content = SVG_VIEWPORT_SIZE.search(viewBox_string).group(0)
svg_viewport = tuple(int(i) for i in viewBox_content.split(" "))
svg = svg[: match.start(1)] + ' ' + svg[match.end(1):]
# 2. compute the rescale ratio (note: the reason of this computation is just a rule
# of thumb, don't know the exact rule...)
w = unitsPerEm / w
h = unitsPerEm / h
w_ratio = svg_viewport[2] / w / 4
h_ratio = svg_viewport[3] / h / 4
ratio = min(w_ratio, h_ratio)
# 3. compute transposition same here, even if it *maybe* makes more sense
x_transpose = x
y_transpose = ratio*y/2
# 4. Add a group containing any element inside the svg tag
svg_content = SVG_CONTENT.search(svg)
if svg_content is not None:
group = f'<g transform="matrix({ratio},0,0,{ratio},{x_transpose},{y_transpose})" >'
svg = svg[:svg_content.start(1)] + group + svg[svg_content.start(1)
:svg_content.end(1)] + '</g>' + svg[svg_content.end(1):]
# encode svg into BytesIO
svg = io.BytesIO(svg.encode("utf-8"))
d = ApplyTransform()
d.document = inkex.load_svg(svg)
d.svg = d.document.getroot()
d.effect()
new_svg = io.BytesIO()
d.save(new_svg)
# convert new_svg to string
svg = new_svg.getvalue().decode("utf-8")
return svg |
Beta Was this translation helpful? Give feedback.
-
cross-linking: adobe-type-tools/opentype-svg#28 |
Beta Was this translation helpful? Give feedback.
So basically the problem was the rescaling of the SVG. I don't have a clear rule to follow, but I found a rule of thumb that works in my case. Here is the code I used, based on an Inkscape extension for baking transformations (scaling and transposing) to the SVG objects: