summaryrefslogtreecommitdiff
path: root/lib/lettering/glyph.py
blob: 3bedd7edcc7765814d6d8d522848150d7052c1d4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# Authors: see git history
#
# Copyright (c) 2010 Authors
# Licensed under the GNU GPL version 3.0 or later.  See the file LICENSE for details.

from copy import copy

from inkex import paths, transforms

from ..svg import get_guides
from ..svg.path import get_correction_transform
from ..svg.tags import SVG_GROUP_TAG, SVG_PATH_TAG


class Glyph(object):
    """Represents a single character in a single font variant.

    For example, the font inkstitch_small may have variants for left-to-right,
    right-to-left, etc.  Each variant would have a set of Glyphs, one for each
    character in that variant.

    Properties:
      width -- total width of this glyph including all component satins
      node  -- svg:g XML node containing the component satins in this character
    """

    def __init__(self, group):
        """Create a Glyph.

        The nodes will be copied out of their parent SVG document (with nested
        transforms applied).  The original nodes will be unmodified.

        Arguments:
          group -- an svg:g XML node containing all the paths that make up
            this Glyph.  Nested groups are allowed.
        """

        self._process_baseline(group.getroottree().getroot())
        self.node = self._process_group(group)
        self._process_bbox()
        self._move_to_origin()

    def _process_group(self, group):
        new_group = copy(group)
        # new_group.attrib.pop('transform', None)
        # delete references to the original group's children
        del new_group[:]

        for node in group:
            if node.tag == SVG_GROUP_TAG:
                new_group.append(self._process_group(node))
            else:
                node_copy = copy(node)

                if "d" in node.attrib:
                    transform = -transforms.Transform(get_correction_transform(node, True))
                    path = paths.Path(node.get("d")).transform(transform).to_absolute()
                    node_copy.set("d", str(path))

                # Delete transforms from paths and groups, since we applied
                # them to the paths already.
                node_copy.attrib.pop('transform', None)

                new_group.append(node_copy)

        return new_group

    def _process_baseline(self, svg):
        for guide in get_guides(svg):
            if guide.label == "baseline":
                self.baseline = guide.position.y
                break
        else:
            # no baseline guide found, assume 0 for lack of anything better to use...
            self.baseline = 0

    def _process_bbox(self):
        bbox = [paths.Path(node.get("d")).bounding_box() for node in self.node.iterdescendants(SVG_PATH_TAG)]
        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 _move_to_origin(self):
        translate_x = -self.min_x
        translate_y = -self.baseline
        transform = transforms.Transform("translate(%s, %s)" % (translate_x, translate_y))

        for node in self.node.iter(SVG_PATH_TAG):
            path = paths.Path(node.get("d"))
            path = path.transform(transform)
            node.set('d', str(path))
            node.attrib.pop('transform', None)