def _svgPath(self, path, transformMatrix=None): path = path.getNSBezierPath() if transformMatrix: path = path.copy() aT = AppKit.NSAffineTransform.transform() aT.setTransformStruct_(transformMatrix[:]) path.transformUsingAffineTransform_(aT) svg = "" for i in range(path.elementCount()): instruction, points = path.elementAtIndex_associatedPoints_(i) if instruction == AppKit.NSMoveToBezierPathElement: svg += "M%s,%s " % (formatNumber( points[0].x), formatNumber(points[0].y)) previousPoint = points[-1] elif instruction == AppKit.NSLineToBezierPathElement: x = points[0].x - previousPoint.x y = points[0].y - previousPoint.y svg += "l%s,%s " % (formatNumber(x), formatNumber(y)) previousPoint = points[-1] elif instruction == AppKit.NSCurveToBezierPathElement: offx1 = points[0].x - previousPoint.x offy1 = points[0].y - previousPoint.y offx2 = points[1].x - previousPoint.x offy2 = points[1].y - previousPoint.y x = points[2].x - previousPoint.x y = points[2].y - previousPoint.y svg += "c%s,%s,%s,%s,%s,%s " % ( formatNumber(offx1), formatNumber(offy1), formatNumber(offx2), formatNumber(offy2), formatNumber(x), formatNumber(y)) previousPoint = points[-1] elif instruction == AppKit.NSClosePathBezierPathElement: svg += "Z " return svg.strip()
def _svgDrawingAttributes(self): data = dict() fill = self._svgFillColor() if fill: c, a = fill data["fill"] = c if a != 1: data["fill-opacity"] = a else: data["fill"] = "none" stroke = self._svgStrokeColor() if stroke: c, a = stroke data["stroke"] = c if a != 1: data["stroke-opacity"] = a data["stroke-width"] = formatNumber(abs(self._state.strokeWidth)) if self._state.lineDash: data["stroke-dasharray"] = ",".join( [str(i) for i in self._state.lineDash]) if self._state.lineJoin in self._svgLineJoinStylesMap: data["stroke-linejoin"] = self._svgLineJoinStylesMap[ self._state.lineJoin] if self._state.lineCap in self._svgLineCapStylesMap: data["stroke-linecap"] = self._svgLineCapStylesMap[ self._state.lineCap] return data
def _svgPath(self, path, transformMatrix=None): path = path.getNSBezierPath() if transformMatrix: path = path.copy() aT = AppKit.NSAffineTransform.transform() aT.setTransformStruct_(transformMatrix[:]) path.transformUsingAffineTransform_(aT) svg = "" for i in range(path.elementCount()): instruction, points = path.elementAtIndex_associatedPoints_(i) if instruction == AppKit.NSMoveToBezierPathElement: svg += "M%s,%s " % (formatNumber(points[0].x), formatNumber(points[0].y)) previousPoint = points[-1] elif instruction == AppKit.NSLineToBezierPathElement: x = points[0].x - previousPoint.x y = points[0].y - previousPoint.y svg += "l%s,%s " % (formatNumber(x), formatNumber(y)) previousPoint = points[-1] elif instruction == AppKit.NSCurveToBezierPathElement: offx1 = points[0].x - previousPoint.x offy1 = points[0].y - previousPoint.y offx2 = points[1].x - previousPoint.x offy2 = points[1].y - previousPoint.y x = points[2].x - previousPoint.x y = points[2].y - previousPoint.y svg += "c%s,%s,%s,%s,%s,%s " % (formatNumber(offx1), formatNumber(offy1), formatNumber(offx2), formatNumber(offy2), formatNumber(x), formatNumber(y)) previousPoint = points[-1] elif instruction == AppKit.NSClosePathBezierPathElement: svg += "Z " return svg.strip()
def _svgDrawingAttributes(self): data = dict() fill = self._svgFillColor() if fill: data["fill"] = fill stroke = self._svgStrokeColor() if stroke: data["stroke"] = stroke data["stroke-width"] = formatNumber(abs(self._state.strokeWidth)) if self._state.lineDash: data["stroke-dasharray"] = ",".join([str(i) for i in self._state.lineDash]) if self._state.lineJoin in self._svgLineJoinStylesMap: data["stroke-linejoin"] = self._svgLineJoinStylesMap[self._state.lineJoin] if self._state.lineCap in self._svgLineCapStylesMap: data["stroke-linecap"] = self._svgLineCapStylesMap[self._state.lineCap] return data
def _textBox(self, txt, box, align): path, (x, y) = self._getPathForFrameSetter(box) canDoGradients = True if align == "justified": warnings.warn("justified text is not supported in a svg context") attrString = self.attributedString(txt, align=align) if self._state.hyphenation: attrString = self.hyphenateAttributedString(attrString, path) txt = attrString.string() setter = CoreText.CTFramesetterCreateWithAttributedString(attrString) 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: stringRange = CoreText.CTRunGetStringRange(ctRun) attributes = CoreText.CTRunGetAttributes(ctRun) font = attributes.get(AppKit.NSFontAttributeName) fontAttributes = font.fontDescriptor().fontAttributes() fillColor = attributes.get(AppKit.NSForegroundColorAttributeName) strokeColor = attributes.get(AppKit.NSStrokeColorAttributeName) strokeWidth = attributes.get(AppKit.NSStrokeWidthAttributeName, self._state.strokeWidth) baselineShift = attributes.get(AppKit.NSBaselineOffsetAttributeName, 0) openTypeFeatures = fontAttributes.get(CoreText.NSFontFeatureSettingsAttribute) fontName = font.fontName() fontSize = font.pointSize() spanData = dict(defaultData) fill = self._colorClass(fillColor).svgColor() if fill: c, a = fill spanData["fill"] = c if a != 1: spanData["fill-opacity"] = a stroke = self._colorClass(strokeColor).svgColor() if stroke: c, a = stroke spanData["stroke"] = c if a != 1: spanData["stroke-opacity"] = a spanData["stroke-width"] = formatNumber(abs(strokeWidth) * .5) spanData["font-family"] = fontName spanData["font-size"] = formatNumber(fontSize) if openTypeFeatures: featureTags = getFeatureTagsForFontAttributes(openTypeFeatures) spanData["style"] = self._svgStyle(**{ "font-feature-settings": self._svgStyleOpenTypeFeatures(featureTags) } ) if canDoGradients and self._state.gradient is not None: spanData["fill"] = "url(#%s_flipped)" % self._state.gradient.tagID self._save() runTxt = txt.substringWithRange_((stringRange.location, stringRange.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"] = formatNumber(originX + runX) spanData["y"] = formatNumber(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()
def _textBox(self, rawTxt, box, align): path, (x, y) = self._getPathForFrameSetter(box) canDoGradients = True if align == "justified": warnings.warn("justified text is not supported in a svg context") attrString = self.attributedString(rawTxt, align=align) if self._state.hyphenation: attrString = self.hyphenateAttributedString(attrString, path) txt = attrString.string() setter = CoreText.CTFramesetterCreateWithAttributedString(attrString) 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 if isinstance(rawTxt, FormattedString): if rawTxt.svgID: data["id"] = rawTxt.svgID if rawTxt.svgClass: data["class"] = rawTxt.svgClass if rawTxt.svgLink: self._svgContext.begintag("a", **{"xlink:href": rawTxt.svgLink}) self._svgContext.newline() 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: stringRange = CoreText.CTRunGetStringRange(ctRun) attributes = CoreText.CTRunGetAttributes(ctRun) font = attributes.get(AppKit.NSFontAttributeName) fontDescriptor = font.fontDescriptor() fillColor = attributes.get(AppKit.NSForegroundColorAttributeName) strokeColor = attributes.get(AppKit.NSStrokeColorAttributeName) strokeWidth = attributes.get(AppKit.NSStrokeWidthAttributeName, self._state.strokeWidth) baselineShift = attributes.get(AppKit.NSBaselineOffsetAttributeName, 0) openTypeFeatures = attributes.get("drawbot.openTypeFeatures") underline = attributes.get(AppKit.NSUnderlineStyleAttributeName) url = attributes.get(AppKit.NSLinkAttributeName) fontName = font.fontName() fontSize = font.pointSize() fontFallbacks = [fallbackFont.postscriptName() for fallbackFont in fontDescriptor.get(CoreText.NSFontCascadeListAttribute, [])] fontNames = ", ".join([fontName] + fontFallbacks) style = dict() spanData = dict(defaultData) fill = self._colorClass(fillColor).svgColor() if fill: c, a = fill spanData["fill"] = c if a != 1: spanData["fill-opacity"] = a stroke = self._colorClass(strokeColor).svgColor() if stroke: c, a = stroke spanData["stroke"] = c if a != 1: spanData["stroke-opacity"] = a spanData["stroke-width"] = formatNumber(abs(strokeWidth) * .5) spanData["font-family"] = fontNames spanData["font-size"] = formatNumber(fontSize) if openTypeFeatures: style["font-feature-settings"] = self._svgStyleOpenTypeFeatures(openTypeFeatures) if canDoGradients and self._state.gradient is not None: spanData["fill"] = "url(#%s_flipped)" % self._state.gradient.tagID if underline is not None: style["text-decoration"] = "underline" underlineStyle = self._svgUnderlineStylesMap.get(underline) if underlineStyle: style["text-decoration-style"] = underlineStyle if style: spanData["style"] = self._svgStyle(**style) self._save() runTxt = txt.substringWithRange_((stringRange.location, stringRange.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"] = formatNumber(originX + runX) spanData["y"] = formatNumber(self.height - originY - runY + baselineShift) if url is not None: self._svgContext.begintag("a", href=url.absoluteString()) self._svgContext.newline() self._svgContext.begintag("tspan", **spanData) self._svgContext.newline() self._svgContext.write(runTxt) self._svgContext.newline() self._svgContext.endtag("tspan") self._svgContext.newline() if url is not None: self._svgContext.endtag("a") self._svgContext.newline() self._restore() self._svgContext.endtag("text") self._svgContext.newline() if isinstance(rawTxt, FormattedString) and rawTxt.svgLink: self._svgContext.endtag("a") self._svgContext.newline() self._svgEndClipPath()