Beispiel #1
0
    def test_from_svg_file(self):
        pen = RecordingPen()
        with NamedTemporaryFile(delete=False) as tmp:
            tmp.write(tobytes(SVG_DATA))
        try:
            svg = SVGPath(tmp.name)
            svg.draw(pen)
        finally:
            os.remove(tmp.name)

        assert pen.value == EXPECTED_PEN_COMMANDS
Beispiel #2
0
    def test_from_svg_file(self):
        pen = RecordingPen()
        with NamedTemporaryFile(delete=False) as tmp:
            tmp.write(tobytes(SVG_DATA))
        try:
            svg = SVGPath(tmp.name)
            svg.draw(pen)
        finally:
            os.remove(tmp.name)

        assert pen.value == EXPECTED_PEN_COMMANDS
Beispiel #3
0
def svg2glif(svg_file,
             name,
             width=0,
             height=0,
             unicodes=None,
             transform=None,
             version=2):
    """ Convert an SVG outline to a UFO glyph with given 'name', advance
    'width' and 'height' (int), and 'unicodes' (list of int).
    Return the resulting string in GLIF format (default: version 2).
    If 'transform' is provided, apply a transformation matrix before the
    conversion (must be tuple of 6 floats, or a FontTools Transform object).
    """
    glyph = SimpleNamespace(width=width, height=height, unicodes=unicodes)
    outline = SVGPath(svg_file, transform)

    # writeGlyphToString takes a callable (usually a glyph's drawPoints
    # method) that accepts a PointPen, however SVGPath currently only has
    # a draw method that accepts a segment pen. We need to wrap the call
    # with a converter pen.
    def drawPoints(pointPen):
        pen = SegmentToPointPen(pointPen)
        outline.draw(pen)

    return writeGlyphToString(name,
                              glyphObject=glyph,
                              drawPointsFunc=drawPoints,
                              formatVersion=version)
 def dropEvent(self, event):
     mimeData = event.mimeData()
     if mimeData.hasUrls():
         paths = mimeData.urls()
         # pick just one image
         path = paths[0].toLocalFile()
         fileName = os.path.basename(path)
         with open(path, "rb") as imgFile:
             data = imgFile.read()
         ext = os.path.splitext(path)[1][1:]
         # TODO: make sure we cleanup properly when replacing an image with
         # another
         if ext.lower() == "glif":
             otherGlyph = self._glyph.__class__()
             try:
                 readGlyphFromString(data, otherGlyph,
                                     otherGlyph.getPointPen())
             except Exception as e:
                 errorReports.showCriticalException(e)
                 return
             self._glyph.beginUndoGroup()
             otherGlyph.drawPoints(self._glyph.getPointPen())
             self._glyph.endUndoGroup()
             return
         if ext.lower() == "svg":
             try:
                 svgPath = SVGPath.fromstring(data)
             except Exception as e:
                 errorReports.showCriticalException(e)
                 return
             self._glyph.beginUndoGroup()
             svgPath.draw(self._glyph.getPen())
             self._glyph.endUndoGroup()
             return
         if ext.lower() != "png":
             # convert
             img = QImage(path)
             data = QByteArray()
             buffer = QBuffer(data)
             buffer.open(QIODevice.WriteOnly)
             img.save(buffer, "PNG")
             # format
             data = bytearray(data)
             fileName = "%s.png" % os.path.splitext(fileName)[0]
         imageSet = self._glyph.font.images
         try:
             imageSet[fileName] = data
         except Exception as e:
             errorReports.showCriticalException(e)
             return
         image = self._glyph.instantiateImage()
         image.fileName = fileName
         self._glyph.image = image
         event.setAccepted(True)
     else:
         super().dropEvent(event)
Beispiel #5
0
    def test_transform(self):
        pen = RecordingPen()
        svg = SVGPath.fromstring(SVG_DATA,
                                 transform=(1.0, 0, 0, -1.0, 0, 1000))
        svg.draw(pen)

        assert pen.value == [
            ("moveTo", ((100.0, 900.0), )), ("lineTo", ((300.0, 900.0), )),
            ("lineTo", ((200.0, 700.0), )), ("lineTo", ((100.0, 900.0), )),
            ("closePath", ()), ("moveTo", ((100.0, 800.0), )),
            ("curveTo", ((100.0, 900.0), (250.0, 900.0), (250.0, 800.0))),
            ("curveTo", ((250.0, 700.0), (400.0, 700.0), (400.0, 800.0))),
            ("endPath", ())
        ]
Beispiel #6
0
    def test_transform(self):
        pen = RecordingPen()
        svg = SVGPath.fromstring(SVG_DATA,
                                 transform=(1.0, 0, 0, -1.0, 0, 1000))
        svg.draw(pen)

        assert pen.value == [
            ("moveTo", ((100.0, 900.0),)),
            ("lineTo", ((300.0, 900.0),)),
            ("lineTo", ((200.0, 700.0),)),
            ("lineTo", ((100.0, 900.0),)),
            ("closePath", ()),
            ("moveTo", ((100.0, 800.0),)),
            ("curveTo", ((100.0, 900.0),
                         (250.0, 900.0),
                         (250.0, 800.0))),
            ("curveTo", ((250.0, 700.0),
                         (400.0, 700.0),
                         (400.0, 800.0))),
            ("endPath", ())
        ]
Beispiel #7
0
    def potrace(self,
                rect,
                poargs=[],
                invert=True,
                pen_class=None,
                context=None):
        import skia
        from PIL import Image
        from pathlib import Path
        from subprocess import run
        from fontTools.svgLib import SVGPath

        pc, ctx = self._get_renderer_state(pen_class, context)

        img = pc.Precompose(self, rect, context=ctx)
        pilimg = Image.fromarray(
            img.convert(alphaType=skia.kUnpremul_AlphaType))
        binpo = Path("bin/potrace")
        if not binpo.exists():
            binpo = Path(__file__).parent.parent.parent / "bin/potrace"

        with tempfile.NamedTemporaryFile(prefix="coldtype_tmp",
                                         suffix=".bmp") as tmp_bmp:
            pilimg.save(tmp_bmp.name)
            rargs = [str(binpo), "-s"]
            if invert:
                rargs.append("--invert")
            rargs.extend([str(x) for x in poargs])
            rargs.extend(["-o", "-", "--", tmp_bmp.name])
            if False:
                print(">>>", " ".join(rargs))
            result = run(rargs, capture_output=True)
            t = Transform()
            t = t.scale(0.1, 0.1)
            svgp = SVGPath.fromstring(result.stdout, transform=t)
            dp = self.single_pen_class()
            svgp.draw(dp)
            return dp.f(0)
Beispiel #8
0
def svg2glif(svg, name, width=0, height=0, unicodes=None, transform=None,
             version=2):
    """ Convert an SVG outline to a UFO glyph with given 'name', advance
    'width' and 'height' (int), and 'unicodes' (list of int).
    Return the resulting string in GLIF format (default: version 2).
    If 'transform' is provided, apply a transformation matrix before the
    conversion (must be tuple of 6 floats, or a FontTools Transform object).
    """
    glyph = SimpleNamespace(width=width, height=height, unicodes=unicodes)
    outline = SVGPath.fromstring(svg, transform=transform)

    # writeGlyphToString takes a callable (usually a glyph's drawPoints
    # method) that accepts a PointPen, however SVGPath currently only has
    # a draw method that accepts a segment pen. We need to wrap the call
    # with a converter pen.
    def drawPoints(pointPen):
        pen = SegmentToPointPen(pointPen)
        outline.draw(pen)

    return writeGlyphToString(name,
                              glyphObject=glyph,
                              drawPointsFunc=drawPoints,
                              formatVersion=version)
Beispiel #9
0
    def test_fromstring(self):
        pen = RecordingPen()
        svg = SVGPath.fromstring(SVG_DATA)
        svg.draw(pen)

        assert pen.value == EXPECTED_PEN_COMMANDS
Beispiel #10
0
 def paste(self):
     isGlyphTab = self.isGlyphTab()
     widget = self.stackWidget.currentWidget()
     if isGlyphTab:
         glyphs = (widget.activeGlyph(),)
     else:
         selection = self.glyphCellView.selection()
         glyphs = widget.glyphsForIndexes(selection)
     clipboard = QApplication.clipboard()
     mimeData = clipboard.mimeData()
     if mimeData.hasFormat("application/x-trufont-glyph-data"):
         data = pickle.loads(mimeData.data("application/x-trufont-glyph-data"))
         if len(data) == len(glyphs):
             for pickled, glyph in zip(data, glyphs):
                 if isGlyphTab:
                     pasteGlyph = glyph.__class__()
                     pasteGlyph.deserialize(pickled)
                     # TODO: if we serialize selected state, we don't need
                     # to do this
                     pasteGlyph.selected = True
                     if (
                         len(pasteGlyph)
                         or len(pasteGlyph.components)
                         or len(pasteGlyph.anchors)
                     ):
                         glyph.beginUndoGroup()
                         glyph.holdNotifications()
                         count = len(glyph)
                         pen = glyph.getPointPen()
                         # contours, components
                         pasteGlyph.drawPoints(pen)
                         for contour in glyph[count:]:
                             contour.selected = True
                         # anchors
                         for anchor in pasteGlyph.anchors:
                             glyph.appendAnchor(dict(anchor))
                         # guidelines
                         for guideline in pasteGlyph.guidelines:
                             glyph.appendGuideline(dict(guideline))
                         glyph.releaseHeldNotifications()
                         glyph.endUndoGroup()
                 else:
                     glyph.deserialize(pickled)
         return
     if mimeData.hasFormat("image/svg+xml"):
         if len(glyphs) == 1:
             glyph = glyphs[0]
             try:
                 svgPath = SVGPath.fromstring(mimeData.data("image/svg+xml"))
             except Exception:
                 pass
             else:
                 glyph.beginUndoGroup()
                 if not isGlyphTab:
                     glyph.clear()
                 svgPath.draw(glyph.getPen())
                 glyph.endUndoGroup()
                 return
     if mimeData.hasText():
         if len(glyphs) == 1:
             glyph = glyphs[0]
             otherGlyph = glyph.__class__()
             text = mimeData.text()
             try:
                 readGlyphFromString(text, otherGlyph, otherGlyph.getPointPen())
             except Exception:
                 try:
                     svgPath = SVGPath.fromstring(text)
                     svgPath.draw(otherGlyph.getPen())
                 except Exception:
                     return
             glyph.beginUndoGroup()
             if not isGlyphTab:
                 glyph.clear()
             otherGlyph.drawPoints(glyph.getPointPen())
             glyph.endUndoGroup()
Beispiel #11
0
    def test_fromstring(self):
        pen = RecordingPen()
        svg = SVGPath.fromstring(SVG_DATA)
        svg.draw(pen)

        assert pen.value == EXPECTED_PEN_COMMANDS
    def doImport(self, f, filePath):
        layerChoice = self.w.importBox.layerChoice.get()
        # Format the path names
        plistPath = os.path.splitext(filePath)[0] + ".plist"
        svgPath = os.path.splitext(filePath)[0] + ".svg"
        # Import the SVG
        outline = SVGPath(svgPath)
        svgGlyph = RGlyph()
        pen = svgGlyph.getPen()
        outline.draw(pen)

        # Read the Plist
        with open(plistPath, 'rb') as plistFile:
            plistData = load(plistFile)
            thisPageScale = plistData[
                "pageScale"]  # Use the pageScale and bufferFactor from the file, not from the extension prefs
            thisBufferFactor = plistData["bufferFactor"]
            xMax = plistData["xMax"] / thisPageScale
            yMax = plistData["yMax"] / thisPageScale
            rowCount = plistData["rowCount"]
            colCount = plistData["colCount"]
            pageWidth = plistData["pageWidth"] / thisPageScale
            pageHeight = plistData["pageHeight"] / thisPageScale
            glyphLocations = plistData["glyphLocations"]

            # Scale the glyph back to the normal size
            svgGlyph.scaleBy((1 / thisPageScale, 1 / thisPageScale))

            # Flip and move the SVG Glyph so that it's in the correct orientation
            svgGlyph.scaleBy((1, -1))
            svgGlyph.moveBy((0, pageHeight))

            # Find the location that grid location starts (which will be at the center of each glyph drawing)
            # Same as the export
            gridLocs = {}
            for rowNumber in range(rowCount):
                for colNumber in range(colCount):
                    gridID = "%s-%s" % (colNumber, rowNumber)
                    locX = ((colNumber * xMax * thisBufferFactor) +
                            xMax * thisBufferFactor)
                    locY = (pageHeight -
                            (rowNumber * yMax * thisBufferFactor) -
                            (yMax * thisBufferFactor))
                    gridLocs[gridID] = (locX, locY)

            # Find which contours from the SVG belong in which of the grid locations
            # Hold the contours aside by their index for now
            sortedContours = {}
            for cIdx, contour in enumerate(svgGlyph.contours):
                for gridID, gridLoc in gridLocs.items():
                    if contour.bounds[0] > gridLoc[0] - xMax and contour.bounds[
                            2] < gridLoc[0] + xMax:
                        if contour.bounds[
                                1] > gridLoc[1] - yMax and contour.bounds[
                                    3] < gridLoc[1] + yMax:
                            if not gridID in sortedContours:
                                sortedContours[gridID] = []
                            sortedContours[gridID].append(cIdx)

            # Draw the contours into glyphs
            for gn, gridID in glyphLocations:
                if not gn in f.keys():
                    f.newGlyph(gn)
                g = f[gn]
                if layerChoice == 0:
                    gf = g.getLayer(f.defaultLayerName)
                    # Import into the foregronud
                    gl = gf.getLayer("backup")
                    gl.appendGlyph(g)
                    gl.width = gf.width
                    gf.clear()
                    destGlyph = gf
                else:
                    # Import into the "import" layer
                    gl = g.getLayer("import")
                    gl.clear()
                    gl.width = g.width
                    destGlyph = gl
                # Import
                if gridID in sortedContours:
                    for cIdx in sortedContours[gridID]:
                        c = svgGlyph.contours[cIdx]
                        destGlyph.appendContour(c)
                # Move to the center of the grid location
                destGlyph.moveBy((-gridLocs[gridID][0], -gridLocs[gridID][1]))
                # ...and offset since the glyph drawing was centered up on the grid location
                destGlyph.moveBy((g.width * 0.5, yMax * 0.5))
                # Small amount of cleanup, remove single-point contours
                for c in destGlyph.contours:
                    if len(c.points) == 1:
                        destGlyph.removeContour(c)
                destGlyph.changed()