コード例 #1
0
ファイル: test_inkex_paths.py プロジェクト: wachin/inkscape
    def test_transformation(self):
        t = Transform(matrix=((1, 2, 3), (4, 5, 6)))

        first = Vector2d()
        prev = Vector2d(31, 97)
        prev_prev = Vector2d(5, 7)

        for Cmd in (Line, Move, Curve, Smooth, Quadratic, TepidQuadratic, Arc):
            random_seg = self.get_random_cmd(Cmd)
            self.assertTrue(random_seg.transform(t)
                            is not random_seg)  # transform returns copy
            self.assertEqual(
                random_seg.transform(t).name,
                Cmd.name)  # transform does not change Command type

            T = Transform()
            T.add_translate(10, 20)
            A = [
                T.apply_to_point(p)
                for p in random_seg.control_points(first, prev, prev_prev)
            ]
            first2, prev2, prev_prev2 = (T.apply_to_point(p)
                                         for p in (first, prev, prev_prev))
            B = list(
                random_seg.translate(Vector2d(10, 20)).control_points(
                    first2, prev2, prev_prev2))
            self.assertAlmostTuple(A, B)

            T = Transform()
            T.add_scale(10, 20)
            A = [
                T.apply_to_point(p)
                for p in random_seg.control_points(first, prev, prev_prev)
            ]
            first2, prev2, prev_prev2 = (T.apply_to_point(p)
                                         for p in (first, prev, prev_prev))
            B = list(
                random_seg.scale(
                    (10, 20)).control_points(first2, prev2, prev_prev2))
            self.assertAlmostTuple(A, B)

            T = Transform()
            T.add_rotate(35, 15, 28)
            A = [
                T.apply_to_point(p)
                for p in random_seg.control_points(first, prev, prev_prev)
            ]
            first2, prev2, prev_prev2 = (T.apply_to_point(p)
                                         for p in (first, prev, prev_prev))
            B = list(
                random_seg.rotate(35, Vector2d(15, 28)).control_points(
                    first2, prev2, prev_prev2))
            self.assertAlmostTuple(A, B)
コード例 #2
0
ファイル: test_inkex_paths.py プロジェクト: wachin/inkscape
    def test_transformation_preserve_type(self):
        import re
        paths = [
            "M 10 10 A 100 100 0 1 0 100 100 C 10 15 20 20 5 5 Z",
            "m 10 10 a 100 100 0 1 0 100 100 c 10 15 20 20 5 5 z",
            "m 10 10 l 100 200 L 20 30 C 10 20 30 40 11 12",
            "M 10 10 Q 12 13 14 15 T 11 32 T 32 11",
            "m 10 10 q 12 13 14 15 t 11 32 t 32 11",
        ]
        t = Transform(matrix=((1, 2, 3), (4, 5, 6)))
        for path_str in paths:
            path = Path(path_str)
            new_path = path.transform(t)
            cmds = "".join([cmd.letter for cmd in new_path])
            expected = re.sub(r"\d|\s|,", "", path_str)

            self.assertEqual(expected, cmds)
            self.assertAlmostTuple(
                [t.apply_to_point(p) for p in path.control_points],
                list(new_path.control_points))
コード例 #3
0
    def recursiveFuseTransform(self,
                               node,
                               transf=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]):
        # Modification by David Burghoff:
        # Since transforms apply to an object's clips, before applying the transform
        # we will need to duplicate the clip path and transform it
        clippathurl = node.get('clip-path')
        if clippathurl is not None and node.get("transform") is not None:
            myn = node
            while not (myn.getparent() == None):  # get svg handle
                myn = myn.getparent()
            svg = myn
            clippath = svg.getElementById(clippathurl[5:-1])
            if clippath is not None:
                d = clippath.duplicate()
                clippathurl = "url(#" + d.get("id") + ")"
                node.set("clip-path", clippathurl)
                for k in d.getchildren():
                    if k.get('transform') is not None:
                        tr = Transform(node.get("transform")) * Transform(
                            k.get('transform'))
                    else:
                        tr = Transform(node.get("transform"))
                    k.set('transform', tr)

        transf = Transform(transf) * Transform(node.get("transform", None))

        if 'transform' in node.attrib:
            del node.attrib['transform']

        node = ApplyTransform.objectToPath(node)

        if transf == NULL_TRANSFORM:
            # Don't do anything if there is effectively no transform applied
            # reduces alerts for unsupported nodes
            pass
        elif 'd' in node.attrib:
            d = node.get('d')
            p = CubicSuperPath(d)
            p = Path(p).to_absolute().transform(transf, True)
            node.set('d', str(Path(CubicSuperPath(p).to_path())))

            self.scaleStrokeWidth(node, transf)

        elif node.tag in [
                inkex.addNS('polygon', 'svg'),
                inkex.addNS('polyline', 'svg')
        ]:
            points = node.get('points')
            points = points.strip().split(' ')
            for k, p in enumerate(points):
                if ',' in p:
                    p = p.split(',')
                    p = [float(p[0]), float(p[1])]
                    p = transf.apply_to_point(p)
                    p = [str(p[0]), str(p[1])]
                    p = ','.join(p)
                    points[k] = p
            points = ' '.join(points)
            node.set('points', points)

            self.scaleStrokeWidth(node, transf)

        elif node.tag in [
                inkex.addNS("ellipse", "svg"),
                inkex.addNS("circle", "svg")
        ]:

            def isequal(a, b):
                return abs(a - b) <= transf.absolute_tolerance

            if node.TAG == "ellipse":
                rx = float(node.get("rx"))
                ry = float(node.get("ry"))
            else:
                rx = float(node.get("r"))
                ry = rx

            cx = float(node.get("cx"))
            cy = float(node.get("cy"))
            sqxy1 = (cx - rx, cy - ry)
            sqxy2 = (cx + rx, cy - ry)
            sqxy3 = (cx + rx, cy + ry)
            newxy1 = transf.apply_to_point(sqxy1)
            newxy2 = transf.apply_to_point(sqxy2)
            newxy3 = transf.apply_to_point(sqxy3)

            node.set("cx", (newxy1[0] + newxy3[0]) / 2)
            node.set("cy", (newxy1[1] + newxy3[1]) / 2)
            edgex = math.sqrt(
                abs(newxy1[0] - newxy2[0])**2 + abs(newxy1[1] - newxy2[1])**2)
            edgey = math.sqrt(
                abs(newxy2[0] - newxy3[0])**2 + abs(newxy2[1] - newxy3[1])**2)

            if not isequal(edgex, edgey) and (
                    node.TAG == "circle" or not isequal(newxy2[0], newxy3[0])
                    or not isequal(newxy1[1], newxy2[1])):
                inkex.utils.errormsg(
                    "Warning: Shape %s (%s) is approximate only, try Object to path first for better results"
                    % (node.TAG, node.get("id")))

            if node.TAG == "ellipse":
                node.set("rx", edgex / 2)
                node.set("ry", edgey / 2)
            else:
                node.set("r", edgex / 2)

        # Modficiation by David Burghoff: Added support for lines
        elif node.tag in inkex.addNS('line', 'svg'):
            x1 = node.get('x1')
            x2 = node.get('x2')
            y1 = node.get('y1')
            y2 = node.get('y2')
            p1 = transf.apply_to_point([x1, y1])
            p2 = transf.apply_to_point([x2, y2])
            node.set('x1', str(p1[0]))
            node.set('y1', str(p1[1]))
            node.set('x2', str(p2[0]))
            node.set('y2', str(p2[1]))
            self.scaleStrokeWidth(node, transf)

        elif node.typename in ['Rectangle']:
            x = float(node.get('x'))
            y = float(node.get('y'))
            w = float(node.get('width'))
            h = float(node.get('height'))
            pts = [[x, y], [x + w, y], [x + w, y + h], [x, y + h], [x, y]]
            xs = []
            ys = []
            for p in pts:
                p = transf.apply_to_point(p)
                xs.append(p.x)
                ys.append(p.y)

            node.set('x', str(min(xs)))
            node.set('y', str(min(ys)))
            node.set('width', str(max(xs) - min(xs)))
            node.set('height', str(max(ys) - min(ys)))
            self.scaleStrokeWidth(node, transf)

        elif node.tag in [
                inkex.addNS('text', 'svg'),
                inkex.addNS('image', 'svg'),
                inkex.addNS('use', 'svg')
        ]:
            inkex.utils.errormsg(
                "Shape %s (%s) not yet supported, try Object to path first" %
                (node.TAG, node.get("id")))

        else:
            # e.g. <g style="...">
            self.scaleStrokeWidth(node, transf)

        for child in node.getchildren():
            self.recursiveFuseTransform(child, transf)
コード例 #4
0
    def recursiveFuseTransform(self,
                               node,
                               transf=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]):

        transf = Transform(transf) * Transform(node.get("transform", None))

        if 'transform' in node.attrib:
            del node.attrib['transform']

        node = ApplyTransform.objectToPath(node)

        if transf == NULL_TRANSFORM:
            # Don't do anything if there is effectively no transform applied
            # reduces alerts for unsupported nodes
            pass
        elif 'd' in node.attrib:
            d = node.get('d')
            p = CubicSuperPath(d)
            p = Path(p).to_absolute().transform(transf, True)
            node.set('d', Path(CubicSuperPath(p).to_path()))

            self.scaleStrokeWidth(node, transf)

        elif node.tag in [
                inkex.addNS('polygon', 'svg'),
                inkex.addNS('polyline', 'svg')
        ]:
            points = node.get('points')
            points = points.strip().split(' ')
            for k, p in enumerate(points):
                if ',' in p:
                    p = p.split(',')
                    p = [float(p[0]), float(p[1])]
                    p = transf.apply_to_point(p)
                    p = [str(p[0]), str(p[1])]
                    p = ','.join(p)
                    points[k] = p
            points = ' '.join(points)
            node.set('points', points)

            self.scaleStrokeWidth(node, transf)

        elif node.tag in [
                inkex.addNS("ellipse", "svg"),
                inkex.addNS("circle", "svg")
        ]:

            def isequal(a, b):
                return abs(a - b) <= transf.absolute_tolerance

            if node.TAG == "ellipse":
                rx = float(node.get("rx"))
                ry = float(node.get("ry"))
            else:
                rx = float(node.get("r"))
                ry = rx

            cx = float(node.get("cx"))
            cy = float(node.get("cy"))
            sqxy1 = (cx - rx, cy - ry)
            sqxy2 = (cx + rx, cy - ry)
            sqxy3 = (cx + rx, cy + ry)
            newxy1 = transf.apply_to_point(sqxy1)
            newxy2 = transf.apply_to_point(sqxy2)
            newxy3 = transf.apply_to_point(sqxy3)

            node.set("cx", (newxy1[0] + newxy3[0]) / 2)
            node.set("cy", (newxy1[1] + newxy3[1]) / 2)
            edgex = math.sqrt(
                abs(newxy1[0] - newxy2[0])**2 + abs(newxy1[1] - newxy2[1])**2)
            edgey = math.sqrt(
                abs(newxy2[0] - newxy3[0])**2 + abs(newxy2[1] - newxy3[1])**2)

            if not isequal(edgex, edgey) and (
                    node.TAG == "circle" or not isequal(newxy2[0], newxy3[0])
                    or not isequal(newxy1[1], newxy2[1])):
                inkex.utils.errormsg(
                    "Warning: Shape %s (%s) is approximate only, try Object to path first for better results"
                    % (node.TAG, node.get("id")))

            if node.TAG == "ellipse":
                node.set("rx", edgex / 2)
                node.set("ry", edgey / 2)
            else:
                node.set("r", edgex / 2)

        elif node.tag in [
                inkex.addNS('rect', 'svg'),
                inkex.addNS('text', 'svg'),
                inkex.addNS('image', 'svg'),
                inkex.addNS('use', 'svg')
        ]:
            inkex.utils.errormsg(
                "Shape %s (%s) not yet supported, try Object to path first" %
                (node.TAG, node.get("id")))

        else:
            # e.g. <g style="...">
            self.scaleStrokeWidth(node, transf)

        for child in node.getchildren():
            self.recursiveFuseTransform(child, transf)
コード例 #5
0
 def test_apply_to_point(self):
     """Test applying the transformation to a point"""
     trans = Transform('translate(10, 10)')
     self.assertEqual(trans.apply_to_point((10, 10)).to_tuple(), (20, 20))
     self.assertRaises(ValueError, trans.apply_to_point, '')
コード例 #6
0
    def recursiveFuseTransform(self,
                               element,
                               transf=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]):

        transf = Transform(transf) * Transform(element.get(
            "transform",
            None))  #a, b, c, d = linear transformations / e, f = translations

        if 'transform' in element.attrib:
            del element.attrib['transform']

        element = ApplyTransform.objectToPath(element)

        if transf == NULL_TRANSFORM:
            # Don't do anything if there is effectively no transform applied
            # reduces alerts for unsupported elements
            pass
        elif 'd' in element.attrib:
            d = element.get('d')
            p = CubicSuperPath(d)
            p = Path(p).to_absolute().transform(transf, True)
            element.set('d', str(Path(CubicSuperPath(p).to_path())))

            self.scaleStrokeWidth(element, transf)

        elif element.tag in [
                inkex.addNS('polygon', 'svg'),
                inkex.addNS('polyline', 'svg')
        ]:
            points = element.get('points')
            points = points.strip().split(' ')
            for k, p in enumerate(points):
                if ',' in p:
                    p = p.split(',')
                    p = [float(p[0]), float(p[1])]
                    p = transf.apply_to_point(p)
                    p = [str(p[0]), str(p[1])]
                    p = ','.join(p)
                    points[k] = p
            points = ' '.join(points)
            element.set('points', points)

            self.scaleStrokeWidth(element, transf)

        elif element.tag in [
                inkex.addNS("ellipse", "svg"),
                inkex.addNS("circle", "svg")
        ]:

            def isequal(a, b):
                return abs(a - b) <= transf.absolute_tolerance

            if element.TAG == "ellipse":
                rx = float(element.get("rx"))
                ry = float(element.get("ry"))
            else:
                rx = float(element.get("r"))
                ry = rx

            cx = float(element.get("cx"))
            cy = float(element.get("cy"))
            sqxy1 = (cx - rx, cy - ry)
            sqxy2 = (cx + rx, cy - ry)
            sqxy3 = (cx + rx, cy + ry)
            newxy1 = transf.apply_to_point(sqxy1)
            newxy2 = transf.apply_to_point(sqxy2)
            newxy3 = transf.apply_to_point(sqxy3)

            element.set("cx", (newxy1[0] + newxy3[0]) / 2)
            element.set("cy", (newxy1[1] + newxy3[1]) / 2)
            edgex = math.sqrt(
                abs(newxy1[0] - newxy2[0])**2 + abs(newxy1[1] - newxy2[1])**2)
            edgey = math.sqrt(
                abs(newxy2[0] - newxy3[0])**2 + abs(newxy2[1] - newxy3[1])**2)

            if not isequal(edgex,
                           edgey) and (element.TAG == "circle"
                                       or not isequal(newxy2[0], newxy3[0])
                                       or not isequal(newxy1[1], newxy2[1])):
                inkex.utils.errormsg(
                    "Warning: Shape %s (%s) is approximate only, try Object to path first for better results"
                    % (element.TAG, element.get("id")))

            if element.TAG == "ellipse":
                element.set("rx", edgex / 2)
                element.set("ry", edgey / 2)
            else:
                element.set("r", edgex / 2)

        # this is unstable at the moment
        elif element.tag == inkex.addNS("use", "svg"):
            href = None
            old_href_key = '{http://www.w3.org/1999/xlink}href'
            new_href_key = 'href'
            if element.attrib.has_key(
                    old_href_key
            ) is True:  # {http://www.w3.org/1999/xlink}href (which gets displayed as 'xlink:href') attribute is deprecated. the newer attribute is just 'href'
                href = element.attrib.get(old_href_key)
                #element.attrib.pop(old_href_key)
            if element.attrib.has_key(new_href_key) is True:
                href = element.attrib.get(
                    new_href_key
                )  #we might overwrite the previous deprecated xlink:href but it's okay
                #element.attrib.pop(new_href_key)

            #get the linked object from href attribute
            linkedObject = self.document.getroot().xpath(
                "//*[@id = '%s']" %
                href.lstrip('#'))  #we must remove hashtag symbol
            linkedObjectCopy = copy.copy(linkedObject[0])
            objectType = linkedObject[0].tag

            if objectType == inkex.addNS("image", "svg"):
                mask = None  #image might have an alpha channel
                new_mask_id = self.svg.get_unique_id("mask")
                newMask = None
                if element.attrib.has_key('mask') is True:
                    mask = element.attrib.get('mask')
                    #element.attrib.pop('mask')

                #get the linked mask from mask attribute. We remove the old and create a new
                if mask is not None:
                    linkedMask = self.document.getroot().xpath(
                        "//*[@id = '%s']" % mask.lstrip('url(#').rstrip(')')
                    )  #we must remove hashtag symbol
                    linkedMask[0].delete()
                    maskAttributes = {'id': new_mask_id}
                    newMask = etree.SubElement(self.document.getroot(),
                                               inkex.addNS('mask', 'svg'),
                                               maskAttributes)

                width = float(linkedObjectCopy.get('width')) * transf.a
                height = float(linkedObjectCopy.get('height')) * transf.d
                linkedObjectCopy.set('width', '{:1.6f}'.format(width))
                linkedObjectCopy.set('height', '{:1.6f}'.format(height))
                linkedObjectCopy.set('x', '{:1.6f}'.format(transf.e))
                linkedObjectCopy.set('y', '{:1.6f}'.format(transf.f))
                if newMask is not None:
                    linkedObjectCopy.set('mask', 'url(#' + new_mask_id + ')')
                    maskRectAttributes = {
                        'x': '{:1.6f}'.format(transf.e),
                        'y': '{:1.6f}'.format(transf.f),
                        'width': '{:1.6f}'.format(width),
                        'height': '{:1.6f}'.format(height),
                        'style': 'fill:#ffffff;'
                    }
                    maskRect = etree.SubElement(newMask,
                                                inkex.addNS('rect', 'svg'),
                                                maskRectAttributes)
                self.document.getroot().append(
                    linkedObjectCopy
                )  #for each svg:use we append a copy to the document root
                element.delete()  #then we remove the use object
            else:
                #self.recursiveFuseTransform(linkedObjectCopy, transf)
                self.recursiveFuseTransform(element.unlink(), transf)

        elif element.tag in [
                inkex.addNS('rect', 'svg'),
                inkex.addNS('text', 'svg'),
                inkex.addNS('image', 'svg')
        ]:
            inkex.utils.errormsg(
                "Shape %s (%s) not yet supported, try Object to path first" %
                (element.TAG, element.get("id")))

        else:
            # e.g. <g style="...">
            self.scaleStrokeWidth(element, transf)

        for child in element.getchildren():
            self.recursiveFuseTransform(child, transf)