diff options
Diffstat (limited to 'lib/extensions/lettering_along_path.py')
| -rw-r--r-- | lib/extensions/lettering_along_path.py | 143 |
1 files changed, 84 insertions, 59 deletions
diff --git a/lib/extensions/lettering_along_path.py b/lib/extensions/lettering_along_path.py index 608479be..10e62dd6 100644 --- a/lib/extensions/lettering_along_path.py +++ b/lib/extensions/lettering_along_path.py @@ -6,7 +6,7 @@ import json from math import atan2, degrees -from inkex import Boolean, Transform, errormsg +from inkex import Transform, errormsg from inkex.units import convert_unit from ..elements import Stroke @@ -26,7 +26,7 @@ class LetteringAlongPath(InkstitchExtension): def __init__(self, *args, **kwargs): InkstitchExtension.__init__(self, *args, **kwargs) self.arg_parser.add_argument("--notebook") - self.arg_parser.add_argument("-s", "--stretch-spaces", type=Boolean, default=False, dest="stretch_spaces") + self.arg_parser.add_argument("-p", "--text-position", type=str, default='left', dest="text_position") def effect(self): # we ignore everything but the first path/text @@ -35,32 +35,70 @@ class LetteringAlongPath(InkstitchExtension): errormsg(_("Please select one path and one Ink/Stitch lettering group.")) return - glyphs = [glyph for glyph in text.iterdescendants(SVG_GROUP_TAG) if glyph.label and len(glyph.label) == 1] - if not glyphs: + TextAlongPath(self.svg, text, path, self.options.text_position) + + def get_selection(self): + groups = list() + paths = list() + + for node in self.svg.selection: + lettering = False + if node.tag == SVG_GROUP_TAG and INKSTITCH_LETTERING in node.attrib: + groups.append(node) + lettering = True + continue + + for group in node.iterancestors(SVG_GROUP_TAG): + if INKSTITCH_LETTERING in group.attrib: + groups.append(group) + lettering = True + break + + if not lettering and node.tag in EMBROIDERABLE_TAGS: + paths.append(node) + + if not groups or not paths: + return [None, None] + + return [groups[0], paths[0]] + + +class TextAlongPath: + ''' + Aligns an Ink/Stitch Lettering group along a path + ''' + def __init__(self, svg, text, path, text_position): + self.svg = svg + self.text = text + self.path = Stroke(path).as_multi_line_string().geoms[0] + self.text_position = text_position + + self.glyphs = [glyph for glyph in self.text.iterdescendants(SVG_GROUP_TAG) if glyph.label and len(glyph.label) == 1] + if not self.glyphs: errormsg(_("The text doesn't contain any glyphs.")) return - self.load_settings(text) + self.load_settings() - if glyphs[0].get('transform', None) is not None: - glyphs = self._reset_glyph_transforms(text, glyphs) + if self.glyphs[0].get('transform', None) is not None: + self._reset_glyph_transforms() - path = Stroke(path).as_multi_line_string().geoms[0] - hidden_commands = self.hide_commands(glyphs) - space_indices, stretch_space, text_baseline = self.get_position_and_stretch_values(path, text, glyphs) - self.transform_glyphs(glyphs, path, stretch_space, space_indices, text_baseline) + hidden_commands = self.hide_commands() + space_indices, stretch_space, text_baseline = self.get_position_and_stretch_values() + start_position = self.get_start_position() + self.transform_glyphs(start_position, stretch_space, space_indices, text_baseline) self.restore_commands(hidden_commands) - def _reset_glyph_transforms(self, text_group, glyphs): + def _reset_glyph_transforms(self): font = get_font_by_id(self.settings.font) if font is not None: try: - text_group = list(text_group.iterchildren(SVG_GROUP_TAG))[0] + text_group = list(self.text.iterchildren(SVG_GROUP_TAG))[0] except IndexError: pass for glyph in text_group.iterchildren(): text_group.remove(glyph) - text = font.render_text( + rendered_text = font.render_text( self.settings.text, text_group, None, # we don't know the font variant (?) @@ -68,21 +106,30 @@ class LetteringAlongPath(InkstitchExtension): self.settings.trim_option, self.settings.use_trim_symbols ) - return [glyph for glyph in text.iterdescendants(SVG_GROUP_TAG) if glyph.label and len(glyph.label) == 1] - return glyphs - - def get_position_and_stretch_values(self, path, text, glyphs): - text_bbox = glyphs[0].getparent().bounding_box() + self.glyphs = [glyph for glyph in rendered_text.iterdescendants(SVG_GROUP_TAG) if glyph.label and len(glyph.label) == 1] + + def get_start_position(self): + start_position = 0 + text_length = self.text_length() + path_length = self.path.length + if self.text_position == 'center': + start_position = (path_length - text_length) / 2 + if self.text_position == 'right': + start_position = path_length - text_length + return start_position + + def get_position_and_stretch_values(self): + text_bbox = self.glyphs[0].getparent().bounding_box() text_baseline = text_bbox.bottom - if self.options.stretch_spaces: - text_content = self.settings["text"] + if self.text_position == 'stretch': + text_content = self.settings.text space_indices = [i for i, t in enumerate(text_content) if t == " "] - text_bbox = text.bounding_box() + text_bbox = self.text.bounding_box() text_width = convert_unit(text_bbox.width, 'px', self.svg.unit) if len(text_content) - 1 != 0: - path_length = path.length + path_length = self.path.length stretch_space = (path_length - text_width) / (len(text_content) - 1) else: stretch_space = 0 @@ -92,10 +139,13 @@ class LetteringAlongPath(InkstitchExtension): return space_indices, stretch_space, text_baseline - def hide_commands(self, glyphs): + def text_length(self): + return convert_unit(self.text.bounding_box().width, 'px', self.svg.unit) + + def hide_commands(self): # hide commmands for bounding box calculation hidden_commands = [] - for glyph in glyphs: + for glyph in self.glyphs: for group in glyph.iterdescendants(SVG_GROUP_TAG): if group.get_id().startswith("command_group") and group.style('display', 'inline') != 'none': hidden_commands.append(group) @@ -106,13 +156,13 @@ class LetteringAlongPath(InkstitchExtension): for command in hidden_commands: command.style['display'] = "inline" - def transform_glyphs(self, glyphs, path, stretch_space, space_indices, text_baseline): + def transform_glyphs(self, start_position, stretch_space, space_indices, text_baseline): text_scale = Transform(f'scale({self.settings.scale / 100})') - distance = 0 + distance = start_position old_bbox = None i = 0 - for glyph in glyphs: + for glyph in self.glyphs: # dimensions bbox = glyph.bounding_box() transformed_bbox = glyph.bounding_box(glyph.getparent().composed_transform()) @@ -124,15 +174,15 @@ class LetteringAlongPath(InkstitchExtension): if old_bbox: distance += convert_unit(transformed_left - old_bbox.right, 'px', self.svg.unit) + stretch_space - if self.options.stretch_spaces and i in space_indices: + if self.text_position == 'stretch' and i in space_indices: distance += stretch_space i += 1 new_distance = distance + width # calculate and apply transform - first = path.interpolate(distance) - last = path.interpolate(new_distance) + first = self.path.interpolate(distance) + last = self.path.interpolate(new_distance) angle = degrees(atan2(last.y - first.y, last.x - first.x)) % 360 translate = InkstitchPoint(first.x, first.y) - InkstitchPoint(left, text_baseline) @@ -146,7 +196,7 @@ class LetteringAlongPath(InkstitchExtension): old_bbox = transformed_bbox i += 1 - def load_settings(self, text): + def load_settings(self): """Load the settings saved into the text element""" self.settings = DotDict({ @@ -158,33 +208,8 @@ class LetteringAlongPath(InkstitchExtension): "use_trim_symbols": False }) - if INKSTITCH_LETTERING in text.attrib: + if INKSTITCH_LETTERING in self.text.attrib: try: - self.settings.update(json.loads(text.get(INKSTITCH_LETTERING))) + self.settings.update(json.loads(self.text.get(INKSTITCH_LETTERING))) except (TypeError, ValueError): pass - - def get_selection(self): - groups = list() - paths = list() - - for node in self.svg.selection: - lettering = False - if node.tag == SVG_GROUP_TAG and INKSTITCH_LETTERING in node.attrib: - groups.append(node) - lettering = True - continue - - for group in node.iterancestors(SVG_GROUP_TAG): - if INKSTITCH_LETTERING in group.attrib: - groups.append(group) - lettering = True - break - - if not lettering and node.tag in EMBROIDERABLE_TAGS: - paths.append(node) - - if not groups or not paths: - return [None, None] - - return [groups[0], paths[0]] |
