diff options
| author | Kaalleen <36401965+kaalleen@users.noreply.github.com> | 2021-10-09 18:25:29 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-10-09 18:25:29 +0200 |
| commit | 5a1ad7e4e8bebb31a679674ed8b4ca526138695c (patch) | |
| tree | 254f906a6524abd3cb9a685975e563f09790bbaa /lib/lettering | |
| parent | 0224794a0815f22a719d2880e175077b77214513 (diff) | |
Letters to font extension (#1312)
Diffstat (limited to 'lib/lettering')
| -rw-r--r-- | lib/lettering/font.py | 38 | ||||
| -rw-r--r-- | lib/lettering/font_variant.py | 29 | ||||
| -rw-r--r-- | lib/lettering/glyph.py | 55 |
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) |
