Beispiel #1
0
def writeGlyphToString(glyphName, glyphObject=None, drawPointsFunc=None, writer=None):
	"""Return .glif data for a glyph as a UTF-8 encoded string.
	The 'glyphObject' argument can be any kind of object (even None);
	the writeGlyphToString() method will attempt to get the following
	attributes from it:
		"width"     the advance with of the glyph
		"unicodes"  a list of unicode values for this glyph
		"note"      a string
		"lib"       a dictionary containing custom data

	All attributes are optional: if 'glyphObject' doesn't
	have the attribute, it will simply be skipped.

	To write outline data to the .glif file, writeGlyphToString() needs
	a function (any callable object actually) that will take one
	argument: an object that conforms to the PointPen protocol.
	The function will be called by writeGlyphToString(); it has to call the
	proper PointPen methods to transfer the outline to the .glif file.
	"""
	if writer is None:
		try:
			from xmlWriter import XMLWriter
		except ImportError:
			# try the other location
			from fontTools.misc.xmlWriter import XMLWriter
		aFile = StringIO()
		writer = XMLWriter(aFile, encoding="UTF-8")
	else:
		aFile = None
	writer.begintag("glyph", [("name", glyphName), ("format", "1")])
	writer.newline()

	width = getattr(glyphObject, "width", None)
	if width is not None:
		if not isinstance(width, (int, float)):
			raise GlifLibError, "width attribute must be int or float"
		writer.simpletag("advance", width=repr(width))
		writer.newline()

	unicodes = getattr(glyphObject, "unicodes", None)
	if unicodes:
		if isinstance(unicodes, int):
			unicodes = [unicodes]
		for code in unicodes:
			if not isinstance(code, int):
				raise GlifLibError, "unicode values must be int"
			hexCode = hex(code)[2:].upper()
			if len(hexCode) < 4:
				hexCode = "0" * (4 - len(hexCode)) + hexCode
			writer.simpletag("unicode", hex=hexCode)
			writer.newline()

	note = getattr(glyphObject, "note", None)
	if note is not None:
		if not isinstance(note, (str, unicode)):
			raise GlifLibError, "note attribute must be str or unicode"
		note = note.encode('utf-8')
		writer.begintag("note")
		writer.newline()
		for line in note.splitlines():
			writer.write(line.strip())
			writer.newline()
		writer.endtag("note")
		writer.newline()

	if drawPointsFunc is not None:
		writer.begintag("outline")
		writer.newline()
		pen = GLIFPointPen(writer)
		drawPointsFunc(pen)
		writer.endtag("outline")
		writer.newline()

	lib = getattr(glyphObject, "lib", None)
	if lib:
		from robofab.plistlib import PlistWriter
		if not isinstance(lib, dict):
			lib = dict(lib)
		writer.begintag("lib")
		writer.newline()
		plistWriter = PlistWriter(writer.file, indentLevel=writer.indentlevel,
				indent=writer.indentwhite, writeHeader=False)
		plistWriter.writeValue(lib)
		writer.endtag("lib")
		writer.newline()

	writer.endtag("glyph")
	writer.newline()
	if aFile is not None:
		return aFile.getvalue()
	else:
		return None
Beispiel #2
0
class SVGContext(BaseContext):
    
    _graphicsStateClass = SVGGraphicsState
    _svgFileClass = SVGFile

    _svgTagArguments = {
        "version" : "1.1", 
        "xmlns" : "http://www.w3.org/2000/svg",
        "xmlns:xlink" : "http://www.w3.org/1999/xlink"
        }

    _svgLineJoinStylesMap = {   
                    AppKit.NSMiterLineJoinStyle : "miter",
                    AppKit.NSRoundLineJoinStyle : "round",
                    AppKit.NSBevelLineJoinStyle : "bevel"
                    }

    _svgLineCapStylesMap = {
        AppKit.NSButtLineCapStyle : "butt",
        AppKit.NSSquareLineCapStyle : "square",
        AppKit.NSRoundLineCapStyle : "round",
    }

    fileExtensions = ["svg"]

    def shadow(self, offset, blur, color):
        warnings.warn("shadow is not supported in a svg context")

    def cmykShadow(self, offset, blur, color):
        warnings.warn("shadow is not supported in a svg context")

    def linearGradient(self, startPoint=None, endPoint=None, colors=None, locations=None):
        warnings.warn("linearGradient is not supported in a svg context")

    def radialGradient(self, startPoint=None, endPoint=None, colors=None, locations=None, startRadius=0, endRadius=100):
        warnings.warn("radialGradient is not supported in a svg context")

    def _newPage(self, width, height):
        self.reset()
        self.size(width, height)
        self._svgData = self._svgFileClass()
        self._svgContext = XMLWriter(self._svgData)
        self._svgContext.begintag("svg", width=self.width, height=self.height, **self._svgTagArguments)
        self._svgContext.newline()
        self._state.transformMatrix = self._state.transformMatrix.scale(1, -1).translate(0, -self.height)

    def _saveImage(self, path):
        self._svgContext.endtag("svg")
        self._svgData.writeToFile(path) 

    def _save(self):
        pass

    def _restore(self):
        pass

    def _drawPath(self):
        if self._state.path:
            self._svgBeginClipPath()
            data = self._svgDrawingAttributes()
            data["d"] = self._svgPath(self._state.path)
            data["transform"] = self._svgTransform(self._state.transformMatrix)
            self._svgContext.simpletag("path", **data)
            self._svgContext.newline()
            self._svgEndClipPath()

    def _clipPath(self):
        uniqueID = self._getUniqueID()
        self._svgContext.begintag("clipPath", id=uniqueID)
        self._svgContext.newline()
        data = dict()
        data["d"] = self._svgPath(self._state.path)
        data["transform"] = self._svgTransform(self._state.transformMatrix)
        data["clip-rule"] = "evenodd"
        self._svgContext.simpletag("path", **data)
        self._svgContext.newline()
        self._svgContext.endtag("clipPath")
        self._svgContext.newline()
        self._state.clipPathID = uniqueID

    def _textBox(self, txt, (x, y, w, h), align):
        attrString = self.attributedString(txt, align=align)
        setter = CoreText.CTFramesetterCreateWithAttributedString(attrString)
        path = CoreText.CGPathCreateMutable()
        CoreText.CGPathAddRect(path, None, CoreText.CGRectMake(x, y, w, h))
        box = CoreText.CTFramesetterCreateFrame(setter, (0, 0), path, None)

        self._save()
        self._svgBeginClipPath()
        data = self._svgDrawingAttributes()
        data["font-family"] = self._state.text.fontName
        data["font-size"] = self._state.text.fontSize
        data["transform"] = self._svgTransform(self._state.transformMatrix.translate(x, y + h).scale(1, -1))
        data["text-anchor"] = "start"

        lines = []
        
        ctLines = CoreText.CTFrameGetLines(box)
        for ctLine in ctLines:
            r = CoreText.CTLineGetStringRange(ctLine)
            line = txt[r.location:r.location+r.length]
            while line and line[-1] == " ":
                line = line[:-1]
            lines.append(line.replace("\n", ""))

        self._svgContext.begintag("text", **data)
        self._svgContext.newline()
        txt = []
        origins = CoreText.CTFrameGetLineOrigins(box, (0, len(ctLines)), None)
        for i, (originX, originY) in enumerate(origins):
            line = lines[i]
            self._svgContext.begintag("tspan", x=originX, y=h-originY)
            self._svgContext.newline()
            self._svgContext.write(line)
            self._svgContext.newline()
            self._svgContext.endtag("tspan")
            self._svgContext.newline()
        self._svgContext.endtag("text")
        self._svgContext.newline()
        self._svgEndClipPath()
Beispiel #3
0
class SVGContext(BaseContext):

    _graphicsStateClass = SVGGraphicsState
    _shadowClass = SVGShadow
    _colorClass = SVGColor
    _gradientClass = SVGGradient

    _svgFileClass = SVGFile

    _svgTagArguments = {
        "version": "1.1",
        "xmlns": "http://www.w3.org/2000/svg",
        "xmlns:xlink": "http://www.w3.org/1999/xlink"
        }

    _svgLineJoinStylesMap = {
                    AppKit.NSMiterLineJoinStyle: "miter",
                    AppKit.NSRoundLineJoinStyle: "round",
                    AppKit.NSBevelLineJoinStyle: "bevel"
                    }

    _svgLineCapStylesMap = {
        AppKit.NSButtLineCapStyle: "butt",
        AppKit.NSSquareLineCapStyle: "square",
        AppKit.NSRoundLineCapStyle: "round",
    }

    fileExtensions = ["svg"]

    def __init__(self):
        super(SVGContext, self).__init__()
        self._pages = []

    # not supported in a svg context

    def openTypeFeatures(self, *args, **features):
        warnings.warn("openTypeFeatures is not supported in a svg context")

    def cmykFill(self, c, m, y, k, a=1):
        warnings.warn("cmykFill is not supported in a svg context")

    def cmykStroke(self, c, m, y, k, a=1):
        warnings.warn("cmykStroke is not supported in a svg context")

    def cmykLinearGradient(self, startPoint=None, endPoint=None, colors=None, locations=None):
        warnings.warn("cmykLinearGradient is not supported in a svg context")

    def cmykRadialGradient(self, startPoint=None, endPoint=None, colors=None, locations=None, startRadius=0, endRadius=100):
        warnings.warn("cmykRadialGradient is not supported in a svg context")

    def cmykShadow(self, offset, blur, color):
        warnings.warn("cmykShadow is not supported in a svg context")

    # svg overwrites

    def shadow(self, offset, blur, color):
        super(SVGContext, self).shadow(offset, blur, color)
        if self._state.shadow is not None:
            self._state.shadow.writeDefs(self._svgContext)

    def linearGradient(self, startPoint=None, endPoint=None, colors=None, locations=None):
        super(SVGContext, self).linearGradient(startPoint, endPoint, colors, locations)
        if self._state.gradient is not None:
            self._state.gradient.writeDefs(self._svgContext)

    def radialGradient(self, startPoint=None, endPoint=None, colors=None, locations=None, startRadius=0, endRadius=100):
        super(SVGContext, self).radialGradient(startPoint, endPoint, colors, locations, startRadius, endRadius)
        if startRadius != 0:
            warnings.warn("radialGradient will clip the startRadius to '0' in a svg context.")
        if self._state.gradient is not None:
            self._state.gradient.writeDefs(self._svgContext)

    # svg

    def _reset(self):
        self._embeddedFonts = set()

    def _newPage(self, width, height):
        if hasattr(self, "_svgContext"):
            self._svgContext.endtag("svg")
        self.reset()
        self.size(width, height)
        self._svgData = self._svgFileClass()
        self._pages.append(self._svgData)
        self._svgContext = XMLWriter(self._svgData, encoding="utf-8")
        self._svgContext.width = self.width
        self._svgContext.height = self.height
        self._svgContext.begintag("svg", width=self.width, height=self.height, **self._svgTagArguments)
        self._svgContext.newline()
        self._state.transformMatrix = self._state.transformMatrix.scale(1, -1).translate(0, -self.height)

    def _saveImage(self, path, multipage):
        if multipage is None:
            multipage = False
        self._svgContext.endtag("svg")
        fileName, fileExt = os.path.splitext(path)
        firstPage = 0
        pageCount = len(self._pages)
        pathAdd = "_1"
        if not multipage:
            firstPage = pageCount - 1
            pathAdd = ""
        for index in range(firstPage, pageCount):
            page = self._pages[index]
            svgPath = fileName + pathAdd + fileExt
            page.writeToFile(svgPath)
            pathAdd = "_%s" % (index + 2)

    def _save(self):
        pass

    def _restore(self):
        pass

    def _drawPath(self):
        if self._state.path:
            self._svgBeginClipPath()
            data = self._svgDrawingAttributes()
            data["d"] = self._svgPath(self._state.path)
            data["transform"] = self._svgTransform(self._state.transformMatrix)
            if self._state.shadow is not None:
                data["filter"] = "url(#%s)" % self._state.shadow.tagID
            if self._state.gradient is not None:
                data["fill"] = "url(#%s)" % self._state.gradient.tagID
            self._svgContext.simpletag("path", **data)
            self._svgContext.newline()
            self._svgEndClipPath()

    def _clipPath(self):
        uniqueID = self._getUniqueID()
        self._svgContext.begintag("clipPath", id=uniqueID)
        self._svgContext.newline()
        data = dict()
        data["d"] = self._svgPath(self._state.path)
        data["transform"] = self._svgTransform(self._state.transformMatrix)
        data["clip-rule"] = "evenodd"
        self._svgContext.simpletag("path", **data)
        self._svgContext.newline()
        self._svgContext.endtag("clipPath")
        self._svgContext.newline()
        self._state.clipPathID = uniqueID

    def _textBox(self, txt, (x, y, w, h), align):
        canDoGradients = not isinstance(txt, FormattedString)
        if align == "justified":
            warnings.warn("justified text is not supported in a svg context")
        attrString = self.attributedString(txt, align=align)
        if self._state.text.hyphenation:
            attrString = self.hyphenateAttributedString(attrString, w)
        txt = attrString.string()

        setter = CoreText.CTFramesetterCreateWithAttributedString(attrString)
        path = CoreText.CGPathCreateMutable()
        CoreText.CGPathAddRect(path, None, CoreText.CGRectMake(x, y, w, h))
        box = CoreText.CTFramesetterCreateFrame(setter, (0, 0), path, None)

        self._svgBeginClipPath()
        defaultData = self._svgDrawingAttributes()

        data = {
            "text-anchor": "start",
            "transform": self._svgTransform(self._state.transformMatrix.translate(x, y + self.height).scale(1, -1))
            }
        if self._state.shadow is not None:
            data["filter"] = "url(#%s_flipped)" % self._state.shadow.tagID
        self._svgContext.begintag("text", **data)
        self._svgContext.newline()

        ctLines = CoreText.CTFrameGetLines(box)
        origins = CoreText.CTFrameGetLineOrigins(box, (0, len(ctLines)), None)
        for i, (originX, originY) in enumerate(origins):
            ctLine = ctLines[i]
            # bounds = CoreText.CTLineGetImageBounds(ctLine, self._pdfContext)
            # if bounds.size.width == 0:
            #     continue
            ctRuns = CoreText.CTLineGetGlyphRuns(ctLine)
            for ctRun in ctRuns:
                attributes = CoreText.CTRunGetAttributes(ctRun)
                font = attributes.get(AppKit.NSFontAttributeName)
                fillColor = attributes.get(AppKit.NSForegroundColorAttributeName)
                strokeColor = attributes.get(AppKit.NSStrokeColorAttributeName)
                strokeWidth = attributes.get(AppKit.NSStrokeWidthAttributeName, self._state.strokeWidth)
                baselineShift = attributes.get(AppKit.NSBaselineOffsetAttributeName, 0)

                fontName = font.fontName()
                fontSize = font.pointSize()

                spanData = dict(defaultData)
                spanData["fill"] = self._colorClass(fillColor).svgColor()
                spanData["stroke"] = self._colorClass(strokeColor).svgColor()
                spanData["stroke-width"] = strokeWidth
                spanData["font-family"] = fontName
                spanData["font-size"] = fontSize

                if canDoGradients and self._state.gradient is not None:
                    spanData["fill"] = "url(#%s_flipped)" % self._state.gradient.tagID

                self._save()

                r = CoreText.CTRunGetStringRange(ctRun)
                runTxt = txt.substringWithRange_((r.location, r.length))
                while runTxt and runTxt[-1] == " ":
                    runTxt = runTxt[:-1]
                runTxt = runTxt.replace("\n", "")
                runTxt = runTxt.encode("utf-8")

                runPos = CoreText.CTRunGetPositions(ctRun, (0, 1), None)
                runX = runY = 0
                if runPos:
                    runX = runPos[0].x
                    runY = runPos[0].y

                spanData["x"] = originX + runX
                spanData["y"] = self.height - originY - runY + baselineShift
                self._svgContext.begintag("tspan", **spanData)
                self._svgContext.newline()
                self._svgContext.write(runTxt)
                self._svgContext.newline()
                self._svgContext.endtag("tspan")
                self._svgContext.newline()
                self._restore()

        self._svgContext.endtag("text")
        self._svgContext.newline()
        self._svgEndClipPath()
Beispiel #4
0
class Logger(object):

    def __init__(self):
        self._file = StringIO()
        self._writer = XMLWriter(self._file, encoding="utf-8")

    def __del__(self):
        self._writer = None
        self._file.close()

    def logStart(self):
        self._writer.begintag("xml")

    def logEnd(self):
        self._writer.endtag("xml")

    def logMainSettings(self, glyphNames, script, langSys):
        self._writer.begintag("initialSettings")
        self._writer.newline()
        self._writer.simpletag("string", value=" ".join(glyphNames))
        self._writer.newline()
        self._writer.simpletag("script", value=script)
        self._writer.newline()
        self._writer.simpletag("langSys", value=langSys)
        self._writer.newline()
        self._writer.endtag("initialSettings")
        self._writer.newline()

    def logTableStart(self, table):
        name = table.__class__.__name__
        self._writer.begintag("table", name=name)
        self._writer.newline()
        self.logTableFeatureStates(table)

    def logTableEnd(self):
        self._writer.endtag("table")

    def logTableFeatureStates(self, table):
        self._writer.begintag("featureStates")
        self._writer.newline()
        for tag in sorted(table.getFeatureList()):
            state = table.getFeatureState(tag)
            self._writer.simpletag("feature", name=tag, state=int(state))
            self._writer.newline()
        self._writer.endtag("featureStates")
        self._writer.newline()

    def logApplicableLookups(self, table, lookups):
        self._writer.begintag("applicableLookups")
        self._writer.newline()
        if lookups:
            order = []
            last = None
            for tag, lookup in lookups:
                if tag != last:
                    if order:
                        self._logLookupList(last, order)
                    order = []
                    last = tag
                index = table.LookupList.Lookup.index(lookup)
                order.append(index)
            self._logLookupList(last, order)
        self._writer.endtag("applicableLookups")
        self._writer.newline()

    def _logLookupList(self, tag, lookups):
        lookups = " ".join([str(i) for i in lookups])
        self._writer.simpletag("lookups", feature=tag, indices=lookups)
        self._writer.newline()

    def logProcessingStart(self):
        self._writer.begintag("processing")
        self._writer.newline()

    def logProcessingEnd(self):
        self._writer.endtag("processing")
        self._writer.newline()

    def logLookupStart(self, table, tag, lookup):
        index = table.LookupList.Lookup.index(lookup)
        self._writer.begintag("lookup", feature=tag, index=index)
        self._writer.newline()

    def logLookupEnd(self):
        self._writer.endtag("lookup")
        self._writer.newline()

    def logSubTableStart(self, lookup, subtable):
        index = lookup.SubTable.index(subtable)
        lookupType = subtable.__class__.__name__
        self._writer.begintag("subTable", index=index, type=lookupType)
        self._writer.newline()

    def logSubTableEnd(self):
        self._writer.endtag("subTable")
        self._writer.newline()

    def logGlyphRecords(self, glyphRecords):
        for r in glyphRecords:
            self._writer.simpletag("glyphRecord", name=r.glyphName,
                xPlacement=r.xPlacement, yPlacement=r.yPlacement,
                xAdvance=r.xAdvance, yAdvance=r.yAdvance)
            self._writer.newline()

    def logInput(self, processed, unprocessed):
        self._writer.begintag("input")
        self._writer.newline()
        self._writer.begintag("processed")
        self._writer.newline()
        self.logGlyphRecords(processed)
        self._writer.endtag("processed")
        self._writer.newline()
        self._writer.begintag("unprocessed")
        self._writer.newline()
        self.logGlyphRecords(unprocessed)
        self._writer.endtag("unprocessed")
        self._writer.newline()
        self._writer.endtag("input")
        self._writer.newline()

    def logOutput(self, processed, unprocessed):
        self._writer.begintag("output")
        self._writer.newline()
        self._writer.begintag("processed")
        self._writer.newline()
        self.logGlyphRecords(processed)
        self._writer.endtag("processed")
        self._writer.newline()
        self._writer.begintag("unprocessed")
        self._writer.newline()
        self.logGlyphRecords(unprocessed)
        self._writer.endtag("unprocessed")
        self._writer.newline()
        self._writer.endtag("output")
        self._writer.newline()

    def logResults(self, processed):
        self._writer.begintag("results")
        self._writer.newline()
        self.logGlyphRecords(processed)
        self._writer.endtag("results")
        self._writer.newline()

    def getText(self):
        return self._file.getvalue()
Beispiel #5
0
class Logger(object):

    def __init__(self):
        self._file = StringIO()
        self._writer = XMLWriter(self._file, encoding="utf-8")

    def __del__(self):
        self._writer = None
        self._file.close()

    def logStart(self):
        self._writer.begintag("xml")

    def logEnd(self):
        self._writer.endtag("xml")

    def logMainSettings(self, glyphNames, script, langSys):
        self._writer.begintag("initialSettings")
        self._writer.newline()
        self._writer.simpletag("string", value=" ".join(glyphNames))
        self._writer.newline()
        self._writer.simpletag("script", value=script)
        self._writer.newline()
        self._writer.simpletag("langSys", value=langSys)
        self._writer.newline()
        self._writer.endtag("initialSettings")
        self._writer.newline()

    def logTableStart(self, table):
        name = table.__class__.__name__
        self._writer.begintag("table", name=name)
        self._writer.newline()
        self.logTableFeatureStates(table)

    def logTableEnd(self):
        self._writer.endtag("table")

    def logTableFeatureStates(self, table):
        self._writer.begintag("featureStates")
        self._writer.newline()
        for tag in sorted(table.getFeatureList()):
            state = table.getFeatureState(tag)
            self._writer.simpletag("feature", name=tag, state=int(state))
            self._writer.newline()
        self._writer.endtag("featureStates")
        self._writer.newline()

    def logApplicableLookups(self, table, lookups):
        self._writer.begintag("applicableLookups")
        self._writer.newline()
        if lookups:
            order = []
            last = None
            for tag, lookup in lookups:
                if tag != last:
                    if order:
                        self._logLookupList(last, order)
                    order = []
                    last = tag
                index = table.LookupList.Lookup.index(lookup)
                order.append(index)
            self._logLookupList(last, order)
        self._writer.endtag("applicableLookups")
        self._writer.newline()

    def _logLookupList(self, tag, lookups):
        lookups = " ".join([str(i) for i in lookups])
        self._writer.simpletag("lookups", feature=tag, indices=lookups)
        self._writer.newline()

    def logProcessingStart(self):
        self._writer.begintag("processing")
        self._writer.newline()

    def logProcessingEnd(self):
        self._writer.endtag("processing")
        self._writer.newline()

    def logLookupStart(self, table, tag, lookup):
        index = table.LookupList.Lookup.index(lookup)
        self._writer.begintag("lookup", feature=tag, index=index)
        self._writer.newline()

    def logLookupEnd(self):
        self._writer.endtag("lookup")
        self._writer.newline()

    def logSubTableStart(self, lookup, subtable):
        index = lookup.SubTable.index(subtable)
        lookupType = subtable.__class__.__name__
        self._writer.begintag("subTable", index=index, type=lookupType)
        self._writer.newline()

    def logSubTableEnd(self):
        self._writer.endtag("subTable")
        self._writer.newline()

    def logGlyphRecords(self, glyphRecords):
        for r in glyphRecords:
            self._writer.simpletag("glyphRecord", name=r.glyphName,
                xPlacement=r.xPlacement, yPlacement=r.yPlacement,
                xAdvance=r.xAdvance, yAdvance=r.yAdvance)
            self._writer.newline()

    def logInput(self, processed, unprocessed):
        self._writer.begintag("input")
        self._writer.newline()
        self._writer.begintag("processed")
        self._writer.newline()
        self.logGlyphRecords(processed)
        self._writer.endtag("processed")
        self._writer.newline()
        self._writer.begintag("unprocessed")
        self._writer.newline()
        self.logGlyphRecords(unprocessed)
        self._writer.endtag("unprocessed")
        self._writer.newline()
        self._writer.endtag("input")
        self._writer.newline()

    def logOutput(self, processed, unprocessed):
        self._writer.begintag("output")
        self._writer.newline()
        self._writer.begintag("processed")
        self._writer.newline()
        self.logGlyphRecords(processed)
        self._writer.endtag("processed")
        self._writer.newline()
        self._writer.begintag("unprocessed")
        self._writer.newline()
        self.logGlyphRecords(unprocessed)
        self._writer.endtag("unprocessed")
        self._writer.newline()
        self._writer.endtag("output")
        self._writer.newline()

    def logResults(self, processed):
        self._writer.begintag("results")
        self._writer.newline()
        self.logGlyphRecords(processed)
        self._writer.endtag("results")
        self._writer.newline()

    def getText(self):
        return self._file.getvalue()
Beispiel #6
0
class TestSuite(metaTestItem):
    '''
  Collection of all TestBlocks
  '''
    def __init__(self, TheOutPath='', TheFontList=[]):
        metaTestItem.__init__(self, 'fontQA', 'fontQA')
        if TheOutPath != '':
            self.OutPath = TheOutPath
        else:
            self.OutPath = os.path.join(fl.path, 'fontQA_report.xml')
        self.suite = self
        self.showReport = True
        if TheFontList == [] and len(fl) > 0:
            for i in range(len(fl)):
                self.testFontList.append(fl[i])
        else:
            self.testFontList = TheFontList
        self.testBlockList = self._childs

    def addBlock(self, TheName, TheTag):
        m = re.search(r"\W", TheTag)
        if m:
            raise ValueError, 'Second parameter has to contain only alphanumeric characters ( \w or [a-zA-Z0-9_] ) .'
        result = TestBlock(TheName, TheTag)
        self.append(result)
        return result

    def showDialog(self):
        self.dialog = SuiteDialog(self)
        result = self.dialog.Run()
        if result == 1:
            for anyBlock in self.testBlockList:
                anyBlock.isSelected = getattr(self.dialog, anyBlock.tag)
            self.OutPath = self.dialog.OutPath
            self.showReport = self.dialog.openInBrowser
        return result

    def doTest(self):
        go_on = False
        if len(fl) > 0:
            if self.OutPath == '':
                if self.showDialog == OK:
                    go_on = True
            else:
                if os.path.isdir(os.path.dirname(self.OutPath)):
                    go_on = True
        if go_on:
            fl.BeginProgress('checking fonts', len(self))
            self.XMLwriter = XMLWriter(self.OutPath, self.indentStr)
            procInst = '<?xml-stylesheet type="text/xsl" href="%s"?>' % XSL_FileName
            self.XMLwriter.writeraw(procInst)
            self.XMLwriter.newline()
            timeStr = time.strftime('%Y.%m.%d-%H:%M:%S', time.localtime())
            self.XMLwriter.begintag(self.name, RunDateTime=timeStr)
            self.XMLwriter.newline()
            self.XMLwriter.begintag('FontList')
            self.XMLwriter.newline()
            for anyFont in self.testFontList:
                self.XMLwriter.simpletag('Font',
                                         FullName=anyFont.full_name,
                                         Path=anyFont.file_name)
                self.XMLwriter.newline()
            self.XMLwriter.endtag('FontList')
            self.XMLwriter.newline()
            self.XMLwriter.begintag('TestSuite')
            self.XMLwriter.newline()
            counter = 1
            for anyBlock in self.testBlockList:
                if anyBlock.isSelected:
                    anyBlock.XMLwriter = self.XMLwriter
                    anyBlock._doTest()
                fl.TickProgress(counter)
                counter += 1
            self.XMLwriter.endtag('TestSuite')
            self.XMLwriter.newline()
            self.XMLwriter.endtag(self.name)
            self.XMLwriter.newline()
            self.XMLwriter.close()
            fl.EndProgress()
            styleSheetTargetPath = os.path.join(os.path.dirname(self.OutPath),
                                                XSL_FileName)
            if os.path.isfile(styleSheetTargetPath):
                os.remove(styleSheetTargetPath)
            shutil.copy2(XSL_FilePath, styleSheetTargetPath)
            if self.showReport:
                webbrowser.open(self.OutPath)
Beispiel #7
0
class SVGContext(BaseContext):

    _graphicsStateClass = SVGGraphicsState
    _shadowClass = SVGShadow
    _colorClass = SVGColor
    _gradientClass = SVGGradient

    _svgFileClass = SVGFile

    _svgTagArguments = {
        "version": "1.1",
        "xmlns": "http://www.w3.org/2000/svg",
        "xmlns:xlink": "http://www.w3.org/1999/xlink"
    }

    _svgLineJoinStylesMap = {
        AppKit.NSMiterLineJoinStyle: "miter",
        AppKit.NSRoundLineJoinStyle: "round",
        AppKit.NSBevelLineJoinStyle: "bevel"
    }

    _svgLineCapStylesMap = {
        AppKit.NSButtLineCapStyle: "butt",
        AppKit.NSSquareLineCapStyle: "square",
        AppKit.NSRoundLineCapStyle: "round",
    }

    fileExtensions = ["svg"]

    def __init__(self):
        super(SVGContext, self).__init__()
        self._pages = []

    # not supported in a svg context

    def openTypeFeatures(self, *args, **features):
        warnings.warn("openTypeFeatures is not supported in a svg context")

    def cmykFill(self, c, m, y, k, a=1):
        warnings.warn("cmykFill is not supported in a svg context")

    def cmykStroke(self, c, m, y, k, a=1):
        warnings.warn("cmykStroke is not supported in a svg context")

    def cmykLinearGradient(self,
                           startPoint=None,
                           endPoint=None,
                           colors=None,
                           locations=None):
        warnings.warn("cmykLinearGradient is not supported in a svg context")

    def cmykRadialGradient(self,
                           startPoint=None,
                           endPoint=None,
                           colors=None,
                           locations=None,
                           startRadius=0,
                           endRadius=100):
        warnings.warn("cmykRadialGradient is not supported in a svg context")

    def cmykShadow(self, offset, blur, color):
        warnings.warn("cmykShadow is not supported in a svg context")

    # svg overwrites

    def shadow(self, offset, blur, color):
        super(SVGContext, self).shadow(offset, blur, color)
        if self._state.shadow is not None:
            self._state.shadow.writeDefs(self._svgContext)

    def linearGradient(self,
                       startPoint=None,
                       endPoint=None,
                       colors=None,
                       locations=None):
        super(SVGContext, self).linearGradient(startPoint, endPoint, colors,
                                               locations)
        if self._state.gradient is not None:
            self._state.gradient.writeDefs(self._svgContext)

    def radialGradient(self,
                       startPoint=None,
                       endPoint=None,
                       colors=None,
                       locations=None,
                       startRadius=0,
                       endRadius=100):
        super(SVGContext,
              self).radialGradient(startPoint, endPoint, colors, locations,
                                   startRadius, endRadius)
        if startRadius != 0:
            warnings.warn(
                "radialGradient will clip the startRadius to '0' in a svg context."
            )
        if self._state.gradient is not None:
            self._state.gradient.writeDefs(self._svgContext)

    # svg

    def _newPage(self, width, height):
        if hasattr(self, "_svgContext"):
            self._svgContext.endtag("svg")
        self.reset()
        self.size(width, height)
        self._svgData = self._svgFileClass()
        self._pages.append(self._svgData)
        self._svgContext = XMLWriter(self._svgData, encoding="utf-8")
        self._svgContext.width = self.width
        self._svgContext.height = self.height
        self._svgContext.begintag("svg",
                                  width=self.width,
                                  height=self.height,
                                  **self._svgTagArguments)
        self._svgContext.newline()
        self._state.transformMatrix = self._state.transformMatrix.scale(
            1, -1).translate(0, -self.height)

    def _saveImage(self, path, multipage):
        if multipage is None:
            multipage = False
        self._svgContext.endtag("svg")
        fileName, fileExt = os.path.splitext(path)
        firstPage = 0
        pageCount = len(self._pages)
        pathAdd = "_1"
        if not multipage:
            firstPage = pageCount - 1
            pathAdd = ""
        for index in range(firstPage, pageCount):
            page = self._pages[index]
            svgPath = fileName + pathAdd + fileExt
            page.writeToFile(svgPath)
            pathAdd = "_%s" % (index + 2)

    def _save(self):
        pass

    def _restore(self):
        pass

    def _drawPath(self):
        if self._state.path:
            self._svgBeginClipPath()
            data = self._svgDrawingAttributes()
            data["d"] = self._svgPath(self._state.path)
            data["transform"] = self._svgTransform(self._state.transformMatrix)
            if self._state.shadow is not None:
                data["filter"] = "url(#%s)" % self._state.shadow.tagID
            if self._state.gradient is not None:
                data["fill"] = "url(#%s)" % self._state.gradient.tagID
            self._svgContext.simpletag("path", **data)
            self._svgContext.newline()
            self._svgEndClipPath()

    def _clipPath(self):
        uniqueID = self._getUniqueID()
        self._svgContext.begintag("clipPath", id=uniqueID)
        self._svgContext.newline()
        data = dict()
        data["d"] = self._svgPath(self._state.path)
        data["transform"] = self._svgTransform(self._state.transformMatrix)
        data["clip-rule"] = "evenodd"
        self._svgContext.simpletag("path", **data)
        self._svgContext.newline()
        self._svgContext.endtag("clipPath")
        self._svgContext.newline()
        self._state.clipPathID = uniqueID

    def _textBox(self, txt, (x, y, w, h), align):
        canDoGradients = not isinstance(txt, FormattedString)
        if align == "justified":
            warnings.warn("justified text is not supported in a svg context")
        attrString = self.attributedString(txt, align=align)
        if self._state.text.hyphenation:
            attrString = self.hyphenateAttributedString(attrString, w)
        txt = attrString.string()

        setter = CoreText.CTFramesetterCreateWithAttributedString(attrString)
        path = CoreText.CGPathCreateMutable()
        CoreText.CGPathAddRect(path, None, CoreText.CGRectMake(x, y, w, h))
        box = CoreText.CTFramesetterCreateFrame(setter, (0, 0), path, None)

        self._svgBeginClipPath()
        defaultData = self._svgDrawingAttributes()

        data = {"text-anchor": "start"}
        if self._state.shadow is not None:
            data["filter"] = "url(#%s_flipped)" % self._state.shadow.tagID
        self._svgContext.begintag("text", **data)
        self._svgContext.newline()

        ctLines = CoreText.CTFrameGetLines(box)
        origins = CoreText.CTFrameGetLineOrigins(box, (0, len(ctLines)), None)
        for i, (originX, originY) in enumerate(origins):
            ctLine = ctLines[i]
            # bounds = CoreText.CTLineGetImageBounds(ctLine, self._pdfContext)
            # if bounds.size.width == 0:
            #     continue
            ctRuns = CoreText.CTLineGetGlyphRuns(ctLine)
            for ctRun in ctRuns:
                attributes = CoreText.CTRunGetAttributes(ctRun)
                font = attributes.get(AppKit.NSFontAttributeName)
                fillColor = attributes.get(
                    AppKit.NSForegroundColorAttributeName)
                strokeColor = attributes.get(AppKit.NSStrokeColorAttributeName)
                strokeWidth = attributes.get(AppKit.NSStrokeWidthAttributeName,
                                             self._state.strokeWidth)

                fontName = font.fontName()
                fontSize = font.pointSize()

                spanData = dict(defaultData)
                spanData["fill"] = self._colorClass(fillColor).svgColor()
                spanData["stroke"] = self._colorClass(strokeColor).svgColor()
                spanData["stroke-width"] = strokeWidth
                spanData["font-family"] = fontName
                spanData["font-size"] = fontSize

                if canDoGradients and self._state.gradient is not None:
                    spanData[
                        "fill"] = "url(#%s_flipped)" % self._state.gradient.tagID

                self._save()

                r = CoreText.CTRunGetStringRange(ctRun)
                runTxt = txt.substringWithRange_((r.location, r.length))
                while runTxt and runTxt[-1] == " ":
                    runTxt = runTxt[:-1]
                runTxt = runTxt.replace("\n", "")
                runTxt = runTxt.encode("utf-8")

                runPos = CoreText.CTRunGetPositions(ctRun, (0, 1), None)
                runX = runY = 0
                if runPos:
                    runX = runPos[0].x
                    runY = runPos[0].y

                spanData["x"] = originX + runX + x
                spanData["y"] = self.height - y - originY - runY
                self._svgContext.begintag("tspan", **spanData)
                self._svgContext.newline()
                self._svgContext.write(runTxt)
                self._svgContext.newline()
                self._svgContext.endtag("tspan")
                self._svgContext.newline()
                self._restore()

        self._svgContext.endtag("text")
        self._svgContext.newline()
        self._svgEndClipPath()