summaryrefslogtreecommitdiff
path: root/lib/lettering
diff options
context:
space:
mode:
authorKaalleen <36401965+kaalleen@users.noreply.github.com>2021-10-09 18:25:29 +0200
committerGitHub <noreply@github.com>2021-10-09 18:25:29 +0200
commit5a1ad7e4e8bebb31a679674ed8b4ca526138695c (patch)
tree254f906a6524abd3cb9a685975e563f09790bbaa /lib/lettering
parent0224794a0815f22a719d2880e175077b77214513 (diff)
Letters to font extension (#1312)
Diffstat (limited to 'lib/lettering')
-rw-r--r--lib/lettering/font.py38
-rw-r--r--lib/lettering/font_variant.py29
-rw-r--r--lib/lettering/glyph.py55
3 files changed, 110 insertions, 12 deletions
diff --git a/lib/lettering/font.py b/lib/lettering/font.py
index ff726a56..cd94e3a7 100644
--- a/lib/lettering/font.py
+++ b/lib/lettering/font.py
@@ -6,15 +6,18 @@
import json
import os
from copy import deepcopy
+from random import randint
import inkex
+from ..commands import ensure_symbol
from ..elements import nodes_to_elements
from ..exceptions import InkstitchException
from ..extensions.lettering_custom_font_dir import get_custom_font_dir
from ..i18n import _, get_languages
from ..stitches.auto_satin import auto_satin
-from ..svg.tags import INKSCAPE_LABEL, SVG_PATH_TAG
+from ..svg.tags import (CONNECTION_END, CONNECTION_START, INKSCAPE_LABEL,
+ SVG_PATH_TAG, SVG_USE_TAG, XLINK_HREF)
from ..utils import Point
from .font_variant import FontVariant
@@ -220,6 +223,8 @@ class Font(object):
element.set('style', '%s%s%s' % (style.to_str(), stroke_width, dash_array))
+ self._ensure_command_symbols(destination_group)
+
return destination_group
def get_variant(self, variant):
@@ -303,8 +308,39 @@ class Font(object):
position.x += self.horiz_adv_x.get(character, horiz_adv_x_default) - glyph.min_x
+ self._update_commands(node, glyph)
+
return node
+ def _update_commands(self, node, glyph):
+ for element, connectors in glyph.commands.items():
+ # update element
+ el = node.find(".//*[@id='%s']" % element)
+ # we cannot get a unique id from the document at this point
+ # so let's create a random id which will most probably work as well
+ new_element_id = "%s_%s" % (element, randint(0, 9999))
+ el.set_id(new_element_id)
+ for connector, symbol in connectors:
+ # update symbol
+ new_symbol_id = "%s_%s" % (symbol, randint(0, 9999))
+ s = node.find(".//*[@id='%s']" % symbol)
+ s.set_id(new_symbol_id)
+ # update connector
+ c = node.find(".//*[@id='%s']" % connector)
+ c.set(CONNECTION_END, "#%s" % new_element_id)
+ c.set(CONNECTION_START, "#%s" % new_symbol_id)
+
+ def _ensure_command_symbols(self, group):
+ # collect commands
+ commands = set()
+ for element in group.iterdescendants(SVG_USE_TAG):
+ xlink = element.get(XLINK_HREF, ' ')
+ if xlink.startswith('#inkstitch_'):
+ commands.add(xlink[11:])
+ # make sure all necessary command symbols are in the document
+ for command in commands:
+ ensure_symbol(group.getroottree().getroot(), command)
+
def _apply_auto_satin(self, group, trim):
"""Apply Auto-Satin to an SVG XML node tree with an svg:g at its root.
diff --git a/lib/lettering/font_variant.py b/lib/lettering/font_variant.py
index d9d8ed44..a7f353fe 100644
--- a/lib/lettering/font_variant.py
+++ b/lib/lettering/font_variant.py
@@ -7,7 +7,8 @@ import os
import inkex
-from ..svg.tags import INKSCAPE_GROUPMODE, INKSCAPE_LABEL
+from ..svg.tags import (INKSCAPE_GROUPMODE, INKSCAPE_LABEL, SVG_GROUP_TAG,
+ SVG_PATH_TAG, SVG_USE_TAG)
from .glyph import Glyph
@@ -60,7 +61,8 @@ class FontVariant(object):
def _load_glyphs(self):
svg_path = os.path.join(self.path, "%s.svg" % self.variant)
- svg = inkex.load_svg(svg_path)
+ svg = inkex.load_svg(svg_path).getroot()
+ svg = self._apply_transforms(svg)
glyph_layers = svg.xpath(".//svg:g[starts-with(@inkscape:label, 'GlyphLayer-')]", namespaces=inkex.NSS)
for layer in glyph_layers:
@@ -79,6 +81,29 @@ class FontVariant(object):
group.style.pop('display', None)
group.attrib.pop('display', None)
+ def _apply_transforms(self, svg):
+ # apply transforms to paths and use tags
+ for element in svg.iterdescendants((SVG_PATH_TAG, SVG_USE_TAG)):
+ transform = element.composed_transform()
+ if element.tag == SVG_PATH_TAG:
+ path = element.path.transform(transform)
+ element.set_path(path)
+ element.attrib.pop("transform", None)
+
+ if element.tag == SVG_USE_TAG:
+ oldx = element.get('x', 0)
+ oldy = element.get('y', 0)
+ newx, newy = transform.apply_to_point((oldx, oldy))
+ element.set('x', newx)
+ element.set('y', newy)
+ element.attrib.pop("transform", None)
+
+ # remove transforms after they have been applied
+ for group in svg.iterdescendants(SVG_GROUP_TAG):
+ group.attrib.pop('transform', None)
+
+ return svg
+
def __getitem__(self, character):
if character in self.glyphs:
return self.glyphs[character]
diff --git a/lib/lettering/glyph.py b/lib/lettering/glyph.py
index 047c12cf..f50d3bb4 100644
--- a/lib/lettering/glyph.py
+++ b/lib/lettering/glyph.py
@@ -5,10 +5,11 @@
from copy import copy
-from inkex import paths, transforms
+from inkex import paths, transforms, units
-from ..svg import get_guides
-from ..svg.tags import SVG_GROUP_TAG, SVG_PATH_TAG
+from ..svg import get_correction_transform, get_guides
+from ..svg.tags import (CONNECTION_END, SVG_GROUP_TAG, SVG_PATH_TAG,
+ SVG_USE_TAG, XLINK_HREF)
class Glyph(object):
@@ -38,6 +39,7 @@ class Glyph(object):
self.node = self._process_group(group)
self._process_bbox()
self._move_to_origin()
+ self._process_commands()
def _process_group(self, group):
new_group = copy(group)
@@ -50,13 +52,21 @@ class Glyph(object):
new_group.append(self._process_group(node))
else:
node_copy = copy(node)
+ transform = -transforms.Transform(get_correction_transform(node, True))
if "d" in node.attrib:
- node_copy.path = node.path.transform(node.composed_transform()).to_absolute()
-
- # Delete transforms from paths and groups, since we applied
- # them to the paths already.
- node_copy.attrib.pop('transform', None)
+ node_copy.path = node.path.transform(transform).to_absolute()
+
+ if not node.tag == SVG_USE_TAG:
+ # Delete transforms from paths and groups, since we applied
+ # them to the paths already.
+ node_copy.attrib.pop('transform', None)
+ else:
+ oldx = node.get('x', 0)
+ oldy = node.get('y', 0)
+ x, y = transform.apply_to_point((oldx, oldy))
+ node_copy.set('x', x)
+ node_copy.set('y', y)
new_group.append(node_copy)
@@ -72,11 +82,30 @@ class Glyph(object):
self.baseline = 0
def _process_bbox(self):
- bbox = [paths.Path(node.get("d")).bounding_box() for node in self.node.iterdescendants(SVG_PATH_TAG)]
+ bbox = [paths.Path(node.get("d")).bounding_box() for node in self.node.iterdescendants(SVG_PATH_TAG) if not node.get(CONNECTION_END, None)]
left, right = min([box.left for box in bbox]), max([box.right for box in bbox])
self.width = right - left
self.min_x = left
+ def _process_commands(self):
+ # Save object ids with commmands in a dictionary: {object_id: [connector_id, symbol_id]}
+ self.commands = {}
+
+ for node in self.node.iter(SVG_USE_TAG):
+ xlink = node.get(XLINK_HREF, ' ')
+ if not xlink.startswith('#inkstitch_'):
+ continue
+
+ try:
+ connector = self.node.xpath(".//*[@inkscape:connection-start='#%s']" % node.get('id', ' '))[0]
+ command_object = connector.get(CONNECTION_END)[1:]
+ try:
+ self.commands[command_object].append([connector.get_id(), node.get_id()])
+ except KeyError:
+ self.commands[command_object] = [[connector.get_id(), node.get_id()]]
+ except IndexError:
+ pass
+
def _move_to_origin(self):
translate_x = -self.min_x
translate_y = -self.baseline
@@ -87,3 +116,11 @@ class Glyph(object):
path = path.transform(transform)
node.set('d', str(path))
node.attrib.pop('transform', None)
+
+ # Move commands as well
+ for node in self.node.iter(SVG_USE_TAG):
+ oldx = units.convert_unit(node.get("x", 0), 'px', node.unit)
+ oldy = units.convert_unit(node.get("y", 0), 'px', node.unit)
+ x, y = transform.apply_to_point((oldx, oldy))
+ node.set('x', x)
+ node.set('y', y)