Exemple #1
0
class _PDFRenderer(Renderer):
    """This draws onto a PDF document.  It needs to be a class
    rather than a function, as some PDF-specific state tracking is
    needed outside of the state info in the SVG model."""

    def __init__(self):
        self._stroke = 0
        self._fill = 0
        self._tracker = StateTracker()

    def drawNode(self, node):
        """This is the recursive method called for each node
        in the tree"""
        #print "pdf:drawNode", self
        #if node.__class__ is Wedge: stop
        if not (isinstance(node, Path) and node.isClipPath):
            self._canvas.saveState()

        #apply state changes
        deltas = getStateDelta(node)
        self._tracker.push(deltas)
        self.applyStateChanges(deltas, {})

        #draw the object, or recurse
        self.drawNodeDispatcher(node)

        self._tracker.pop()
        if not (isinstance(node, Path) and node.isClipPath):
            self._canvas.restoreState()

    def drawRect(self, rect):
        if rect.rx == rect.ry == 0:
            #plain old rectangle
            self._canvas.rect(
                    rect.x, rect.y,
                    rect.width, rect.height,
                    stroke=self._stroke,
                    fill=self._fill
                    )
        else:
            #cheat and assume ry = rx; better to generalize
            #pdfgen roundRect function.  TODO
            self._canvas.roundRect(
                    rect.x, rect.y,
                    rect.width, rect.height, rect.rx,
                    fill=self._fill,
                    stroke=self._stroke
                    )

    def drawImage(self, image):
        path = image.path
        # currently not implemented in other renderers
        if path and (hasattr(path,'mode') or os.path.exists(image.path)):
            self._canvas.drawInlineImage(
                    path,
                    image.x, image.y,
                    image.width, image.height
                    )

    def drawLine(self, line):
        if self._stroke:
            self._canvas.line(line.x1, line.y1, line.x2, line.y2)

    def drawCircle(self, circle):
            self._canvas.circle(
                    circle.cx, circle.cy, circle.r,
                    fill=self._fill,
                    stroke=self._stroke
                    )

    def drawPolyLine(self, polyline):
        if self._stroke:
            assert len(polyline.points) >= 2, 'Polyline must have 2 or more points'
            head, tail = polyline.points[0:2], polyline.points[2:],
            path = self._canvas.beginPath()
            path.moveTo(head[0], head[1])
            for i in range(0, len(tail), 2):
                path.lineTo(tail[i], tail[i+1])
            self._canvas.drawPath(path)

    def drawWedge(self, wedge):
        centerx, centery, radius, startangledegrees, endangledegrees = \
         wedge.centerx, wedge.centery, wedge.radius, wedge.startangledegrees, wedge.endangledegrees
        yradius, radius1, yradius1 = wedge._xtraRadii()
        if yradius is None: yradius = radius
        angle = endangledegrees-startangledegrees
        path = self._canvas.beginPath()
        if (radius1==0 or radius1 is None) and (yradius1==0 or yradius1 is None):
            path.moveTo(centerx, centery)
            path.arcTo(centerx-radius, centery-yradius, centerx+radius, centery+yradius,
                   startangledegrees, angle)
        else:
            path.arc(centerx-radius, centery-yradius, centerx+radius, centery+yradius,
                   startangledegrees, angle)
            path.arcTo(centerx-radius1, centery-yradius1, centerx+radius1, centery+yradius1,
                   endangledegrees, -angle)
        path.close()
        self._canvas.drawPath(path,
                    fill=self._fill,
                    stroke=self._stroke)

    def drawEllipse(self, ellipse):
        #need to convert to pdfgen's bounding box representation
        x1 = ellipse.cx - ellipse.rx
        x2 = ellipse.cx + ellipse.rx
        y1 = ellipse.cy - ellipse.ry
        y2 = ellipse.cy + ellipse.ry
        self._canvas.ellipse(x1,y1,x2,y2,fill=self._fill,stroke=self._stroke)

    def drawPolygon(self, polygon):
        assert len(polygon.points) >= 2, 'Polyline must have 2 or more points'
        head, tail = polygon.points[0:2], polygon.points[2:],
        path = self._canvas.beginPath()
        path.moveTo(head[0], head[1])
        for i in range(0, len(tail), 2):
            path.lineTo(tail[i], tail[i+1])
        path.close()
        self._canvas.drawPath(
                            path,
                            stroke=self._stroke,
                            fill=self._fill
                            )

    def drawString(self, stringObj):
        if self._fill:
            S = self._tracker.getState()
            text_anchor, x, y, text, enc = S['textAnchor'], stringObj.x,stringObj.y,stringObj.text, stringObj.encoding
            if not text_anchor in ['start','inherited']:
                font, font_size = S['fontName'], S['fontSize']
                textLen = stringWidth(text, font, font_size, enc)
                if text_anchor=='end':
                    x -= textLen
                elif text_anchor=='middle':
                    x -= textLen*0.5
                elif text_anchor=='numeric':
                    x -= numericXShift(text_anchor,text,textLen,font,font_size,enc)
                else:
                    raise ValueError('bad value for textAnchor '+str(text_anchor))
            t = self._canvas.beginText(x,y)
            t.textLine(text)
            self._canvas.drawText(t)

    def drawPath(self, path):
        from reportlab.graphics.shapes import _renderPath
        pdfPath = self._canvas.beginPath()
        drawFuncs = (pdfPath.moveTo, pdfPath.lineTo, pdfPath.curveTo, pdfPath.close)
        isClosed = _renderPath(path, drawFuncs)
        if isClosed:
            fill = self._fill
        else:
            fill = 0
        if path.isClipPath:
            self._canvas.clipPath(pdfPath, fill=fill, stroke=self._stroke)
        else:
            self._canvas.drawPath(pdfPath,
                        fill=fill,
                        stroke=self._stroke)

    def setStrokeColor(self,c):
        self._canvas.setStrokeColor(c)

    def setFillColor(self,c):
        self._canvas.setFillColor(c)

    def applyStateChanges(self, delta, newState):
        """This takes a set of states, and outputs the PDF operators
        needed to set those properties"""
        for key, value in delta.items():
            if key == 'transform':
                self._canvas.transform(value[0], value[1], value[2],
                                 value[3], value[4], value[5])
            elif key == 'strokeColor':
                #this has different semantics in PDF to SVG;
                #we always have a color, and either do or do
                #not apply it; in SVG one can have a 'None' color
                if value is None:
                    self._stroke = 0
                else:
                    self._stroke = 1
                    self.setStrokeColor(value)
            elif key == 'strokeWidth':
                self._canvas.setLineWidth(value)
            elif key == 'strokeLineCap':  #0,1,2
                self._canvas.setLineCap(value)
            elif key == 'strokeLineJoin':
                self._canvas.setLineJoin(value)
#            elif key == 'stroke_dasharray':
#                self._canvas.setDash(array=value)
            elif key == 'strokeDashArray':
                if value:
                    if isinstance(value,(list,tuple)) and len(value)==2 and isinstance(value[1],(tuple,list)):
                        phase = value[0]
                        value = value[1]
                    else:
                        phase = 0
                    self._canvas.setDash(value,phase)
                else:
                    self._canvas.setDash()
            elif key == 'fillColor':
                #this has different semantics in PDF to SVG;
                #we always have a color, and either do or do
                #not apply it; in SVG one can have a 'None' color
                if value is None:
                    self._fill = 0
                else:
                    self._fill = 1
                    self.setFillColor(value)
            elif key in ['fontSize', 'fontName']:
                # both need setting together in PDF
                # one or both might be in the deltas,
                # so need to get whichever is missing
                fontname = delta.get('fontName', self._canvas._fontname)
                fontsize = delta.get('fontSize', self._canvas._fontsize)
                self._canvas.setFont(fontname, fontsize)
            elif key=='fillOpacity':
                if value is not None:
                    self._canvas.setFillAlpha(value)
            elif key=='strokeOpacity':
                if value is not None:
                    self._canvas.setStrokeAlpha(value)
            elif key=='fillOverprint':
                self._canvas.setFillOverprint(value)
            elif key=='strokeOverprint':
                self._canvas.setStrokeOverprint(value)
            elif key=='overprintMask':
                self._canvas.setOverprintMask(value)
Exemple #2
0
class _PSRenderer(Renderer):
    """This draws onto a EPS document.  It needs to be a class
    rather than a function, as some EPS-specific state tracking is
    needed outside of the state info in the SVG model."""

    def __init__(self):
        self._tracker = StateTracker()

    def drawNode(self, node):
        """This is the recursive method called for each node
        in the tree"""
        self._canvas.comment('begin node %r'%node)
        color = self._canvas._color
        if not (isinstance(node, Path) and node.isClipPath):
            self._canvas.saveState()

        #apply state changes
        deltas = getStateDelta(node)
        self._tracker.push(deltas)
        self.applyStateChanges(deltas, {})

        #draw the object, or recurse
        self.drawNodeDispatcher(node)

        rDeltas = self._tracker.pop()
        if not (isinstance(node, Path) and node.isClipPath):
            self._canvas.restoreState()
        self._canvas.comment('end node %r'%node)
        self._canvas._color = color

        #restore things we might have lost (without actually doing anything).
        for k, v in rDeltas.items():
            if k in self._restores:
                setattr(self._canvas,self._restores[k],v)

##  _restores = {'stroke':'_stroke','stroke_width': '_lineWidth','stroke_linecap':'_lineCap',
##              'stroke_linejoin':'_lineJoin','fill':'_fill','font_family':'_font',
##              'font_size':'_fontSize'}
    _restores = {'strokeColor':'_strokeColor','strokeWidth': '_lineWidth','strokeLineCap':'_lineCap',
                'strokeLineJoin':'_lineJoin','fillColor':'_fillColor','fontName':'_font',
                'fontSize':'_fontSize'}

    def drawRect(self, rect):
        if rect.rx == rect.ry == 0:
            #plain old rectangle
            self._canvas.rect(
                    rect.x, rect.y,
                    rect.x+rect.width, rect.y+rect.height)
        else:
            #cheat and assume ry = rx; better to generalize
            #pdfgen roundRect function.  TODO
            self._canvas.roundRect(
                    rect.x, rect.y,
                    rect.x+rect.width, rect.y+rect.height, rect.rx, rect.ry
                    )

    def drawLine(self, line):
        if self._canvas._strokeColor:
            self._canvas.line(line.x1, line.y1, line.x2, line.y2)

    def drawCircle(self, circle):
        self._canvas.circle( circle.cx, circle.cy, circle.r)

    def drawWedge(self, wedge):
        yradius, radius1, yradius1 = wedge._xtraRadii()
        if (radius1==0 or radius1 is None) and (yradius1==0 or yradius1 is None):
            startangledegrees = wedge.startangledegrees
            endangledegrees = wedge.endangledegrees
            centerx= wedge.centerx
            centery = wedge.centery
            radius = wedge.radius
            extent = endangledegrees - startangledegrees
            self._canvas.drawArc(centerx-radius, centery-yradius, centerx+radius, centery+yradius,
                startangledegrees, extent, fromcenter=1)
        else:
            self.drawPolygon(wedge.asPolygon())

    def drawPolyLine(self, p):
        if self._canvas._strokeColor:
            self._canvas.polyLine(_pointsFromList(p.points))

    def drawEllipse(self, ellipse):
        #need to convert to pdfgen's bounding box representation
        x1 = ellipse.cx - ellipse.rx
        x2 = ellipse.cx + ellipse.rx
        y1 = ellipse.cy - ellipse.ry
        y2 = ellipse.cy + ellipse.ry
        self._canvas.ellipse(x1,y1,x2,y2)

    def drawPolygon(self, p):
        self._canvas.polygon(_pointsFromList(p.points), closed=1)

    def drawString(self, stringObj):
        if self._canvas._fillColor:
            S = self._tracker.getState()
            text_anchor, x, y, text = S['textAnchor'], stringObj.x,stringObj.y,stringObj.text
            if not text_anchor in ['start','inherited']:
                font, fontSize = S['fontName'], S['fontSize']
                textLen = stringWidth(text, font,fontSize)
                if text_anchor=='end':
                    x -= textLen
                elif text_anchor=='middle':
                    x -= textLen/2
                elif text_anchor=='numeric':
                    x -= numericXShift(text_anchor,text,textLen,font,fontSize,encoding='winansi')
                else:
                    raise ValueError, 'bad value for text_anchor '+str(text_anchor)
            self._canvas.drawString(x,y,text)

    def drawPath(self, path):
        from reportlab.graphics.shapes import _renderPath
        c = self._canvas
        drawFuncs = (c.moveTo, c.lineTo, c.curveTo, c.closePath)
        isClosed = _renderPath(path, drawFuncs)
        if not isClosed:
            c._fillColor = None
        c._fillAndStroke([], clip=path.isClipPath)

    def applyStateChanges(self, delta, newState):
        """This takes a set of states, and outputs the operators
        needed to set those properties"""
        for key, value in delta.items():
            if key == 'transform':
                self._canvas.transform(value[0], value[1], value[2],
                                 value[3], value[4], value[5])
            elif key == 'strokeColor':
                #this has different semantics in PDF to SVG;
                #we always have a color, and either do or do
                #not apply it; in SVG one can have a 'None' color
                self._canvas.setStrokeColor(value)
            elif key == 'strokeWidth':
                self._canvas.setLineWidth(value)
            elif key == 'strokeLineCap':  #0,1,2
                self._canvas.setLineCap(value)
            elif key == 'strokeLineJoin':
                self._canvas.setLineJoin(value)
            elif key == 'strokeDashArray':
                if value:
                    self._canvas.setDash(value)
                else:
                    self._canvas.setDash()
##          elif key == 'stroke_opacity':
##              warnOnce('Stroke Opacity not supported yet')
            elif key == 'fillColor':
                #this has different semantics in PDF to SVG;
                #we always have a color, and either do or do
                #not apply it; in SVG one can have a 'None' color
                self._canvas.setFillColor(value)
##          elif key == 'fill_rule':
##              warnOnce('Fill rules not done yet')
##          elif key == 'fill_opacity':
##              warnOnce('Fill opacity not done yet')
            elif key in ['fontSize', 'fontName']:
                # both need setting together in PDF
                # one or both might be in the deltas,
                # so need to get whichever is missing
                fontname = delta.get('fontName', self._canvas._font)
                fontsize = delta.get('fontSize', self._canvas._fontSize)
                self._canvas.setFont(fontname, fontsize)

    def drawImage(self, image):
        from reportlab.lib.utils import ImageReader
        im = ImageReader(image.path)
        x0 = image.x
        y0 = image.y
        x1 = image.width
        if x1 is not None: x1 += x0
        y1 = image.height
        if y1 is not None: y1 += y0
        self._canvas.drawImage(im._image,x0,y0,x1,y1)
Exemple #3
0
class _SVGRenderer(Renderer):
    """This draws onto an SVG document.
    """

    def __init__(self):
        self._tracker = StateTracker()
        self.verbose = 0

    def drawNode(self, node):
        """This is the recursive method called for each node in the tree.
        """

        if self.verbose:
            print "### begin _SVGRenderer.drawNode"

        self._canvas.comment("begin node %s" % ` node `)
        color = self._canvas._color
        if not (isinstance(node, Path) and node.isClipPath):
            pass  # self._canvas.saveState()

        # apply state changes
        deltas = getStateDelta(node)
        self._tracker.push(deltas)
        self.applyStateChanges(deltas, {})

        # draw the object, or recurse
        self.drawNodeDispatcher(node)

        rDeltas = self._tracker.pop()
        if not (isinstance(node, Path) and node.isClipPath):
            pass  # self._canvas.restoreState()
        self._canvas.comment("end node %s" % ` node `)
        self._canvas._color = color

        # restore things we might have lost (without actually doing anything).
        for k, v in rDeltas.items():
            if self._restores.has_key(k):
                setattr(self._canvas, self._restores[k], v)

        if self.verbose:
            print "### end _SVGRenderer.drawNode"

    _restores = {
        "strokeColor": "_strokeColor",
        "strokeWidth": "_lineWidth",
        "strokeLineCap": "_lineCap",
        "strokeLineJoin": "_lineJoin",
        "fillColor": "_fillColor",
        "fontName": "_font",
        "fontSize": "_fontSize",
    }

    def drawGroup(self, group):
        if self.verbose:
            print "### begin _SVGRenderer.drawGroup"

        currGroup = self._canvas.startGroup()
        a, b, c, d, e, f = self._tracker.getCTM()
        for childNode in group.getContents():
            if isinstance(childNode, UserNode):
                node2 = childNode.provideNode()
            else:
                node2 = childNode
            self.drawNode(node2)
        self._canvas.transform(a, b, c, d, e, f)
        self._canvas.endGroup(currGroup)

        if self.verbose:
            print "### end _SVGRenderer.drawGroup"

    def drawRect(self, rect):
        if rect.rx == rect.ry == 0:
            # plain old rectangle
            self._canvas.rect(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height)
        else:
            # cheat and assume ry = rx; better to generalize
            # pdfgen roundRect function.  TODO
            self._canvas.roundRect(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height, rect.rx, rect.ry)

    def drawString(self, stringObj):
        if self._canvas._fillColor:
            S = self._tracker.getState()
            text_anchor, x, y, text = S["textAnchor"], stringObj.x, stringObj.y, stringObj.text
            if not text_anchor in ["start", "inherited"]:
                font, fontSize = S["fontName"], S["fontSize"]
                textLen = stringWidth(text, font, fontSize)
                if text_anchor == "end":
                    x = x - textLen
                elif text_anchor == "middle":
                    x = x - textLen / 2
                else:
                    raise ValueError, "bad value for text_anchor " + str(text_anchor)
            self._canvas.drawString(text, x, y)

    def drawLine(self, line):
        if self._canvas._strokeColor:
            self._canvas.line(line.x1, line.y1, line.x2, line.y2)

    def drawCircle(self, circle):
        self._canvas.circle(circle.cx, circle.cy, circle.r)

    def drawWedge(self, wedge):
        centerx, centery, radius, startangledegrees, endangledegrees = (
            wedge.centerx,
            wedge.centery,
            wedge.radius,
            wedge.startangledegrees,
            wedge.endangledegrees,
        )
        yradius = wedge.yradius or wedge.radius
        (x1, y1) = (centerx - radius, centery - yradius)
        (x2, y2) = (centerx + radius, centery + yradius)
        extent = endangledegrees - startangledegrees
        self._canvas.drawArc(x1, y1, x2, y2, startangledegrees, extent, fromcenter=1)

    def drawPolyLine(self, p):
        if self._canvas._strokeColor:
            self._canvas.polyLine(_pointsFromList(p.points))

    def drawEllipse(self, ellipse):
        # need to convert to pdfgen's bounding box representation
        x1 = ellipse.cx - ellipse.rx
        x2 = ellipse.cx + ellipse.rx
        y1 = ellipse.cy - ellipse.ry
        y2 = ellipse.cy + ellipse.ry
        self._canvas.ellipse(x1, y1, x2, y2)

    def drawPolygon(self, p):
        self._canvas.polygon(_pointsFromList(p.points), closed=1)

    def drawPath(self, path):
        # print "### drawPath", path.points
        from reportlab.graphics.shapes import _renderPath

        c = self._canvas
        drawFuncs = (c.moveTo, c.lineTo, c.curveTo, c.closePath)
        isClosed = _renderPath(path, drawFuncs)
        if not isClosed:
            c._fillColor = None
        c._fillAndStroke([], clip=path.isClipPath)

    def applyStateChanges(self, delta, newState):
        """This takes a set of states, and outputs the operators
        needed to set those properties"""

        for key, value in delta.items():
            if key == "transform":
                pass
                # self._canvas.transform(value[0], value[1], value[2], value[3], value[4], value[5])
            elif key == "strokeColor":
                self._canvas.setStrokeColor(value)
            elif key == "strokeWidth":
                self._canvas.setLineWidth(value)
            elif key == "strokeLineCap":  # 0,1,2
                self._canvas.setLineCap(value)
            elif key == "strokeLineJoin":
                self._canvas.setLineJoin(value)
            elif key == "strokeDashArray":
                if value:
                    self._canvas.setDash(value)
                else:
                    self._canvas.setDash()
            elif key == "fillColor":
                self._canvas.setFillColor(value)
            elif key in ["fontSize", "fontName"]:
                fontname = delta.get("fontName", self._canvas._font)
                fontsize = delta.get("fontSize", self._canvas._fontSize)
                self._canvas.setFont(fontname, fontsize)
class _SVGRenderer(Renderer):
    """This draws onto an SVG document.
    """

    def __init__(self):
        self._tracker = StateTracker()
        self.verbose = 0

    def drawNode(self, node):
        """This is the recursive method called for each node in the tree.
        """

        if self.verbose: print "### begin _SVGRenderer.drawNode"

        self._canvas.comment('begin node %s'%`node`)
        color = self._canvas._color
        if not (isinstance(node, Path) and node.isClipPath):
            pass # self._canvas.saveState()

        #apply state changes
        deltas = getStateDelta(node)
        self._tracker.push(deltas)
        self.applyStateChanges(deltas, {})

        #draw the object, or recurse
        self.drawNodeDispatcher(node)

        rDeltas = self._tracker.pop()
        if not (isinstance(node, Path) and node.isClipPath):
            pass # self._canvas.restoreState()
        self._canvas.comment('end node %s'%`node`)
        self._canvas._color = color

        #restore things we might have lost (without actually doing anything).
        for k, v in rDeltas.items():
            if self._restores.has_key(k):
                setattr(self._canvas,self._restores[k],v)

        if self.verbose: print "### end _SVGRenderer.drawNode"

    _restores = {'strokeColor':'_strokeColor','strokeWidth': '_lineWidth','strokeLineCap':'_lineCap',
                'strokeLineJoin':'_lineJoin','fillColor':'_fillColor','fontName':'_font',
                'fontSize':'_fontSize'}


    def drawGroup(self, group):
        if self.verbose: print "### begin _SVGRenderer.drawGroup"

        currGroup = self._canvas.startGroup()
        a, b, c, d, e, f = self._tracker.getState()['transform']
        for childNode in group.getContents():
            if isinstance(childNode, UserNode):
                node2 = childNode.provideNode()
            else:
                node2 = childNode
            self.drawNode(node2)
        self._canvas.transform(a, b, c, d, e, f)
        self._canvas.endGroup(currGroup)

        if self.verbose: print "### end _SVGRenderer.drawGroup"


    def drawRect(self, rect):
        if rect.rx == rect.ry == 0:
            #plain old rectangle
            self._canvas.rect(
                    rect.x, rect.y,
                    rect.x+rect.width, rect.y+rect.height)
        else:
            #cheat and assume ry = rx; better to generalize
            #pdfgen roundRect function.  TODO
            self._canvas.roundRect(
                    rect.x, rect.y,
                    rect.x+rect.width, rect.y+rect.height,
                    rect.rx, rect.ry
                    )


    def drawString(self, stringObj):
        if self._canvas._fillColor:
            S = self._tracker.getState()
            text_anchor, x, y, text = S['textAnchor'], stringObj.x, stringObj.y, stringObj.text
            if not text_anchor in ['start', 'inherited']:
                font, fontSize = S['fontName'], S['fontSize']
                textLen = stringWidth(text, font,fontSize)
                if text_anchor=='end':
                    x = x-textLen
                elif text_anchor=='middle':
                    x = x - textLen/2
                else:
                    raise ValueError, 'bad value for text_anchor ' + str(text_anchor)
            self._canvas.drawString(text,x,y)


    def drawLine(self, line):
        if self._canvas._strokeColor:
            self._canvas.line(line.x1, line.y1, line.x2, line.y2)


    def drawCircle(self, circle):
        self._canvas.circle( circle.cx, circle.cy, circle.r)


    def drawWedge(self, wedge):
        centerx, centery, radius, startangledegrees, endangledegrees = \
         wedge.centerx, wedge.centery, wedge.radius, wedge.startangledegrees, wedge.endangledegrees
        yradius = wedge.yradius or wedge.radius
        (x1, y1) = (centerx-radius, centery-yradius)
        (x2, y2) = (centerx+radius, centery+yradius)
        extent = endangledegrees - startangledegrees
        self._canvas.drawArc(x1, y1, x2, y2, startangledegrees, extent, fromcenter=1)


    def drawPolyLine(self, p):
        if self._canvas._strokeColor:
            self._canvas.polyLine(_pointsFromList(p.points))


    def drawEllipse(self, ellipse):
        #need to convert to pdfgen's bounding box representation
        x1 = ellipse.cx - ellipse.rx
        x2 = ellipse.cx + ellipse.rx
        y1 = ellipse.cy - ellipse.ry
        y2 = ellipse.cy + ellipse.ry
        self._canvas.ellipse(x1,y1,x2,y2)


    def drawPolygon(self, p):
        self._canvas.polygon(_pointsFromList(p.points), closed=1)


    def drawPath(self, path):
        # print "### drawPath", path.points
        from reportlab.graphics.shapes import _renderPath
        c = self._canvas
        drawFuncs = (c.moveTo, c.lineTo, c.curveTo, c.closePath)
        isClosed = _renderPath(path, drawFuncs)
        if not isClosed:
            c._fillColor = None
        c._fillAndStroke([], clip=path.isClipPath)


    def applyStateChanges(self, delta, newState):
        """This takes a set of states, and outputs the operators
        needed to set those properties"""

        for key, value in delta.items():
            if key == 'transform':
                pass
                #self._canvas.transform(value[0], value[1], value[2], value[3], value[4], value[5])
            elif key == 'strokeColor':
                self._canvas.setStrokeColor(value)
            elif key == 'strokeWidth':
                self._canvas.setLineWidth(value)
            elif key == 'strokeLineCap':  #0,1,2
                self._canvas.setLineCap(value)
            elif key == 'strokeLineJoin':
                self._canvas.setLineJoin(value)
            elif key == 'strokeDashArray':
                if value:
                    self._canvas.setDash(value)
                else:
                    self._canvas.setDash()
            elif key == 'fillColor':
                self._canvas.setFillColor(value)
            elif key in ['fontSize', 'fontName']:
                fontname = delta.get('fontName', self._canvas._font)
                fontsize = delta.get('fontSize', self._canvas._fontSize)
                self._canvas.setFont(fontname, fontsize)
Exemple #5
0
class _PMRenderer(Renderer):
    """This draws onto a pix map image. It needs to be a class
    rather than a function, as some image-specific state tracking is
    needed outside of the state info in the SVG model."""

    def __init__(self):
        self._tracker = StateTracker()

    def pop(self):
        self._tracker.pop()
        self.applyState()

    def push(self,node):
        deltas = getStateDelta(node)
        self._tracker.push(deltas)
        self.applyState()

    def applyState(self):
        s = self._tracker.getState()
        self._canvas.ctm = s['ctm']
        self._canvas.strokeWidth = s['strokeWidth']
        alpha = s['strokeOpacity']
        if alpha is not None:
            self._canvas.strokeOpacity = alpha
        self._canvas.setStrokeColor(s['strokeColor'])
        self._canvas.lineCap = s['strokeLineCap']
        self._canvas.lineJoin = s['strokeLineJoin']
        da = s['strokeDashArray']
        da = da and (0,da) or None
        self._canvas.dashArray = da
        alpha = s['fillOpacity']
        if alpha is not None:
            self._canvas.fillOpacity = alpha
        self._canvas.setFillColor(s['fillColor'])
        self._canvas.setFont(s['fontName'], s['fontSize'])

    def initState(self,x,y):
        deltas = STATE_DEFAULTS.copy()
        deltas['transform'] = self._canvas._baseCTM[0:4]+(x,y)
        self._tracker.push(deltas)
        self.applyState()

    def drawNode(self, node):
        """This is the recursive method called for each node
        in the tree"""

        #apply state changes
        self.push(node)

        #draw the object, or recurse
        self.drawNodeDispatcher(node)

        # restore the state
        self.pop()

    def drawRect(self, rect):
        c = self._canvas
        if rect.rx == rect.ry == 0:
            #plain old rectangle, draw clockwise (x-axis to y-axis) direction
            c.rect(rect.x,rect.y, rect.width, rect.height)
        else:
            c.roundRect(rect.x,rect.y, rect.width, rect.height, rect.rx, rect.ry)

    def drawLine(self, line):
        self._canvas.line(line.x1,line.y1,line.x2,line.y2)

    def drawImage(self, image):
        if image.path and os.path.exists(image.path):
            if type(image.path) is type(''):
                im = _getImage().open(image.path).convert('RGB')
            else:
                im = image.path.convert('RGB')
            srcW, srcH = im.size
            dstW, dstH = image.width, image.height
            if dstW is None: dstW = srcW
            if dstH is None: dstH = srcH
            self._canvas._aapixbuf(
                    image.x, image.y, dstW, dstH,
                    im.tostring(), srcW, srcH, 3,
                    )

    def drawCircle(self, circle):
        c = self._canvas
        c.circle(circle.cx,circle.cy, circle.r)
        c.fillstrokepath()

    def drawPolyLine(self, polyline, _doClose=0):
        P = polyline.points
        assert len(P) >= 2, 'Polyline must have 1 or more points'
        c = self._canvas
        c.pathBegin()
        c.moveTo(P[0], P[1])
        for i in range(2, len(P), 2):
            c.lineTo(P[i], P[i+1])
        if _doClose:
            c.pathClose()
            c.pathFill()
        c.pathStroke()

    def drawEllipse(self, ellipse):
        c=self._canvas
        c.ellipse(ellipse.cx, ellipse.cy, ellipse.rx,ellipse.ry)
        c.fillstrokepath()

    def drawPolygon(self, polygon):
        self.drawPolyLine(polygon,_doClose=1)

    def drawString(self, stringObj):
        canv = self._canvas
        fill = canv.fillColor
        if fill is not None:
            S = self._tracker.getState()
            text_anchor = S['textAnchor']
            fontName = S['fontName']
            fontSize = S['fontSize']
            text = stringObj.text
            x = stringObj.x
            y = stringObj.y
            if not text_anchor in ['start','inherited']:
                textLen = stringWidth(text, fontName,fontSize)
                if text_anchor=='end':
                    x -= textLen
                elif text_anchor=='middle':
                    x -= textLen/2
                elif text_anchor=='numeric':
                    x -= numericXShift(text_anchor,text,textLen,fontName,fontSize,stringObj.encoding)
                else:
                    raise ValueError, 'bad value for textAnchor '+str(text_anchor)
            canv.drawString(x,y,text,_fontInfo=(fontName,fontSize))

    def drawPath(self, path):
        c = self._canvas
        if path is EmptyClipPath:
            del c._clipPaths[-1]
            if c._clipPaths:
                P = c._clipPaths[-1]
                icp = P.isClipPath
                P.isClipPath = 1
                self.drawPath(P)
                P.isClipPath = icp
            else:
                c.clipPathClear()
            return
        c.pathBegin()
        drawFuncs = (c.moveTo, c.lineTo, c.curveTo, c.pathClose)
        from reportlab.graphics.shapes import _renderPath
        isClosed = _renderPath(path, drawFuncs)
        if path.isClipPath:
            c.clipPathSet()
            c._clipPaths.append(path)
        else:
            if isClosed: c.pathFill()
            c.pathStroke()
Exemple #6
0
class _PSRenderer(Renderer):
    """This draws onto a EPS document.  It needs to be a class
    rather than a function, as some EPS-specific state tracking is
    needed outside of the state info in the SVG model."""
    def __init__(self):
        self._tracker = StateTracker()

    def drawNode(self, node):
        """This is the recursive method called for each node
        in the tree"""
        self._canvas.comment('begin node %r' % node)
        color = self._canvas._color
        if not (isinstance(node, Path) and node.isClipPath):
            self._canvas.saveState()

        #apply state changes
        deltas = getStateDelta(node)
        self._tracker.push(deltas)
        self.applyStateChanges(deltas, {})

        #draw the object, or recurse
        self.drawNodeDispatcher(node)

        rDeltas = self._tracker.pop()
        if not (isinstance(node, Path) and node.isClipPath):
            self._canvas.restoreState()
        self._canvas.comment('end node %r' % node)
        self._canvas._color = color

        #restore things we might have lost (without actually doing anything).
        for k, v in rDeltas.items():
            if k in self._restores:
                setattr(self._canvas, self._restores[k], v)

##  _restores = {'stroke':'_stroke','stroke_width': '_lineWidth','stroke_linecap':'_lineCap',
##              'stroke_linejoin':'_lineJoin','fill':'_fill','font_family':'_font',
##              'font_size':'_fontSize'}

    _restores = {
        'strokeColor': '_strokeColor',
        'strokeWidth': '_lineWidth',
        'strokeLineCap': '_lineCap',
        'strokeLineJoin': '_lineJoin',
        'fillColor': '_fillColor',
        'fontName': '_font',
        'fontSize': '_fontSize'
    }

    def drawRect(self, rect):
        if rect.rx == rect.ry == 0:
            #plain old rectangle
            self._canvas.rect(rect.x, rect.y, rect.x + rect.width,
                              rect.y + rect.height)
        else:
            #cheat and assume ry = rx; better to generalize
            #pdfgen roundRect function.  TODO
            self._canvas.roundRect(rect.x, rect.y, rect.x + rect.width,
                                   rect.y + rect.height, rect.rx, rect.ry)

    def drawLine(self, line):
        if self._canvas._strokeColor:
            self._canvas.line(line.x1, line.y1, line.x2, line.y2)

    def drawCircle(self, circle):
        self._canvas.circle(circle.cx, circle.cy, circle.r)

    def drawWedge(self, wedge):
        yradius, radius1, yradius1 = wedge._xtraRadii()
        if (radius1 == 0 or radius1 is None) and (yradius1 == 0
                                                  or yradius1 is None):
            startangledegrees = wedge.startangledegrees
            endangledegrees = wedge.endangledegrees
            centerx = wedge.centerx
            centery = wedge.centery
            radius = wedge.radius
            extent = endangledegrees - startangledegrees
            self._canvas.drawArc(centerx - radius,
                                 centery - yradius,
                                 centerx + radius,
                                 centery + yradius,
                                 startangledegrees,
                                 extent,
                                 fromcenter=1)
        else:
            self.drawPolygon(wedge.asPolygon())

    def drawPolyLine(self, p):
        if self._canvas._strokeColor:
            self._canvas.polyLine(_pointsFromList(p.points))

    def drawEllipse(self, ellipse):
        #need to convert to pdfgen's bounding box representation
        x1 = ellipse.cx - ellipse.rx
        x2 = ellipse.cx + ellipse.rx
        y1 = ellipse.cy - ellipse.ry
        y2 = ellipse.cy + ellipse.ry
        self._canvas.ellipse(x1, y1, x2, y2)

    def drawPolygon(self, p):
        self._canvas.polygon(_pointsFromList(p.points), closed=1)

    def drawString(self, stringObj):
        if self._canvas._fillColor:
            S = self._tracker.getState()
            text_anchor, x, y, text = S[
                'textAnchor'], stringObj.x, stringObj.y, stringObj.text
            if not text_anchor in ['start', 'inherited']:
                font, fontSize = S['fontName'], S['fontSize']
                textLen = stringWidth(text, font, fontSize)
                if text_anchor == 'end':
                    x -= textLen
                elif text_anchor == 'middle':
                    x -= textLen / 2
                elif text_anchor == 'numeric':
                    x -= numericXShift(text_anchor,
                                       text,
                                       textLen,
                                       font,
                                       fontSize,
                                       encoding='winansi')
                else:
                    raise ValueError('bad value for text_anchor ' +
                                     str(text_anchor))
            self._canvas.drawString(x, y, text)

    def drawPath(self, path):
        from reportlab.graphics.shapes import _renderPath
        c = self._canvas
        drawFuncs = (c.moveTo, c.lineTo, c.curveTo, c.closePath)
        isClosed = _renderPath(path, drawFuncs)
        if not isClosed:
            c._fillColor = None
        c._fillAndStroke([], clip=path.isClipPath)

    def applyStateChanges(self, delta, newState):
        """This takes a set of states, and outputs the operators
        needed to set those properties"""
        for key, value in delta.items():
            if key == 'transform':
                self._canvas.transform(value[0], value[1], value[2], value[3],
                                       value[4], value[5])
            elif key == 'strokeColor':
                #this has different semantics in PDF to SVG;
                #we always have a color, and either do or do
                #not apply it; in SVG one can have a 'None' color
                self._canvas.setStrokeColor(value)
            elif key == 'strokeWidth':
                self._canvas.setLineWidth(value)
            elif key == 'strokeLineCap':  #0,1,2
                self._canvas.setLineCap(value)
            elif key == 'strokeLineJoin':
                self._canvas.setLineJoin(value)
            elif key == 'strokeDashArray':
                if value:
                    if isinstance(
                            value,
                        (list, tuple)) and len(value) == 2 and isinstance(
                            value[1], (tuple, list)):
                        phase = value[0]
                        value = value[1]
                    else:
                        phase = 0
                    self._canvas.setDash(value, phase)
                else:
                    self._canvas.setDash()
##          elif key == 'stroke_opacity':
##              warnOnce('Stroke Opacity not supported yet')
            elif key == 'fillColor':
                #this has different semantics in PDF to SVG;
                #we always have a color, and either do or do
                #not apply it; in SVG one can have a 'None' color
                self._canvas.setFillColor(value)


##          elif key == 'fill_rule':
##              warnOnce('Fill rules not done yet')
##          elif key == 'fill_opacity':
##              warnOnce('Fill opacity not done yet')
            elif key in ['fontSize', 'fontName']:
                # both need setting together in PDF
                # one or both might be in the deltas,
                # so need to get whichever is missing
                fontname = delta.get('fontName', self._canvas._font)
                fontsize = delta.get('fontSize', self._canvas._fontSize)
                self._canvas.setFont(fontname, fontsize)

    def drawImage(self, image):
        from reportlab.lib.utils import ImageReader
        im = ImageReader(image.path)
        x0 = image.x
        y0 = image.y
        x1 = image.width
        if x1 is not None: x1 += x0
        y1 = image.height
        if y1 is not None: y1 += y0
        self._canvas.drawImage(im._image, x0, y0, x1, y1)
Exemple #7
0
class _SVGRenderer(Renderer):
    """This draws onto an SVG document.
    """
    def __init__(self):
        self._tracker = StateTracker()
        self.verbose = 0

    def drawNode(self, node):
        """This is the recursive method called for each node in the tree.
        """

        if self.verbose: print("### begin _SVGRenderer.drawNode(%r)" % node)

        self._canvas.comment('begin node %r' % node)
        color = self._canvas._color
        style = self._canvas.style.copy()
        if not (isinstance(node, Path) and node.isClipPath):
            pass  # self._canvas.saveState()

        #apply state changes
        deltas = getStateDelta(node)
        self._tracker.push(deltas)
        self.applyStateChanges(deltas, {})

        #draw the object, or recurse
        self.drawNodeDispatcher(node)

        rDeltas = self._tracker.pop()
        if not (isinstance(node, Path) and node.isClipPath):
            pass  #self._canvas.restoreState()
        self._canvas.comment('end node %r' % node)
        self._canvas._color = color

        #restore things we might have lost (without actually doing anything).
        for k, v in rDeltas.items():
            if k in self._restores:
                setattr(self._canvas, self._restores[k], v)
        self._canvas.style = style

        if self.verbose: print("### end _SVGRenderer.drawNode(%r)" % node)

    _restores = {
        'strokeColor': '_strokeColor',
        'strokeWidth': '_lineWidth',
        'strokeLineCap': '_lineCap',
        'strokeLineJoin': '_lineJoin',
        'fillColor': '_fillColor',
        'fontName': '_font',
        'fontSize': '_fontSize'
    }

    def _get_link_info_dict(self, obj):
        #We do not want None or False as the link, even if it is the
        #attribute's value - use the empty string instead.
        url = getattr(obj, "hrefURL", "") or ""
        title = getattr(obj, "hrefTitle", "") or ""
        if url:
            #Is it valid to have a link with no href?  The XML requires
            #the xlink:href to be present, but you might just want a
            #tool tip shown (via the xlink:title attribute).  Note that
            #giving an href of "" is equivalent to "the current page"
            #(a relative link saying go nowhere).
            return {"xlink:href": url, "xlink:title": title, "target": "_top"}
            #Currently of all the mainstream browsers I have tested, only Safari/webkit
            #will show  SVG images embedded in HTML using a simple <img src="..." /> tag.
            #However, the links don't work (Safari 3.2.1 on the Mac).
            #
            #Therefore I use the following, which also works for Firefox, Opera, and
            #IE 6.0 with Adobe SVG Viewer 6 beta:
            #<object data="..." type="image/svg+xml" width="430" height="150" class="img">
            #
            #Once displayed, Firefox and Safari treat the SVG like a frame, and
            #by default clicking on links acts "in frame" and replaces the image.
            #Opera does what I expect, and replaces the whole page with the link.
            #
            #Therefore I use target="_top" to force the links to replace the whole page.
            #This now works as expected on Safari 3.2.1, Firefox 3.0.6, Opera 9.20.
            #Perhaps the target attribute should be an option, perhaps defaulting to
            #"_top" as used here?
        else:
            return None

    def drawGroup(self, group):
        if self.verbose: print("### begin _SVGRenderer.drawGroup")

        currGroup = self._canvas.startGroup()
        a, b, c, d, e, f = self._tracker.getState()['transform']
        for childNode in group.getContents():
            if isinstance(childNode, UserNode):
                node2 = childNode.provideNode()
            else:
                node2 = childNode
            self.drawNode(node2)
        self._canvas.transform(a, b, c, d, e, f)
        self._canvas.endGroup(currGroup)

        if self.verbose: print("### end _SVGRenderer.drawGroup")

    def drawRect(self, rect):
        link_info = self._get_link_info_dict(rect)
        svgAttrs = getattr(rect, '_svgAttrs', {})
        if rect.rx == rect.ry == 0:
            #plain old rectangle
            self._canvas.rect(rect.x,
                              rect.y,
                              rect.x + rect.width,
                              rect.y + rect.height,
                              link_info=link_info,
                              **svgAttrs)
        else:
            #cheat and assume ry = rx; better to generalize
            #pdfgen roundRect function.  TODO
            self._canvas.roundRect(rect.x,
                                   rect.y,
                                   rect.x + rect.width,
                                   rect.y + rect.height,
                                   rect.rx,
                                   rect.ry,
                                   link_info=link_info,
                                   **svgAttrs)

    def drawString(self, stringObj):
        if self._canvas._fillColor:
            S = self._tracker.getState()
            text_anchor, x, y, text = S[
                'textAnchor'], stringObj.x, stringObj.y, stringObj.text
            if not text_anchor in ('start', 'inherited'):
                font, fontSize = S['fontName'], S['fontSize']
                textLen = stringWidth(text, font, fontSize)
                if text_anchor == 'end':
                    x -= textLen
                elif text_anchor == 'middle':
                    x -= textLen / 2
                elif text_anchor == 'numeric':
                    x -= numericXShift(text_anchor, text, textLen, font,
                                       fontSize)
                else:
                    raise ValueError('bad value for text_anchor ' +
                                     str(text_anchor))
            self._canvas.drawString(
                text,
                x,
                y,
                link_info=self._get_link_info_dict(stringObj),
                **getattr(stringObj, '_svgAttrs', {}))

    def drawLine(self, line):
        if self._canvas._strokeColor:
            self._canvas.line(line.x1, line.y1, line.x2, line.y2)

    def drawCircle(self, circle):
        self._canvas.circle(circle.cx,
                            circle.cy,
                            circle.r,
                            link_info=self._get_link_info_dict(circle))

    def drawWedge(self, wedge):
        centerx, centery, radius, startangledegrees, endangledegrees = \
         wedge.centerx, wedge.centery, wedge.radius, wedge.startangledegrees, wedge.endangledegrees
        yradius = wedge.yradius or wedge.radius
        (x1, y1) = (centerx - radius, centery - yradius)
        (x2, y2) = (centerx + radius, centery + yradius)
        extent = endangledegrees - startangledegrees
        self._canvas.drawArc(x1,
                             y1,
                             x2,
                             y2,
                             startangledegrees,
                             extent,
                             fromcenter=1)

    def drawPolyLine(self, p):
        if self._canvas._strokeColor:
            self._canvas.polyLine(_pointsFromList(p.points))

    def drawEllipse(self, ellipse):
        #need to convert to pdfgen's bounding box representation
        x1 = ellipse.cx - ellipse.rx
        x2 = ellipse.cx + ellipse.rx
        y1 = ellipse.cy - ellipse.ry
        y2 = ellipse.cy + ellipse.ry
        self._canvas.ellipse(x1,
                             y1,
                             x2,
                             y2,
                             link_info=self._get_link_info_dict(ellipse))

    def drawPolygon(self, p):
        self._canvas.polygon(_pointsFromList(p.points),
                             closed=1,
                             link_info=self._get_link_info_dict(p))

    def drawPath(self, path):
        # print "### drawPath", path.points
        from reportlab.graphics.shapes import _renderPath
        c = self._canvas
        drawFuncs = (c.moveTo, c.lineTo, c.curveTo, c.closePath)
        isClosed = _renderPath(path, drawFuncs)
        if isClosed:
            #Only try and add links to closed paths...
            link_info = self._get_link_info_dict(path)
        else:
            c._fillColor = None
            link_info = None
        c._fillAndStroke([], clip=path.isClipPath, link_info=link_info)

    def applyStateChanges(self, delta, newState):
        """This takes a set of states, and outputs the operators
        needed to set those properties"""

        for key, value in delta.items():
            if key == 'transform':
                pass
                #self._canvas.transform(value[0], value[1], value[2], value[3], value[4], value[5])
            elif key == 'strokeColor':
                self._canvas.setStrokeColor(value)
            elif key == 'strokeWidth':
                self._canvas.setLineWidth(value)
            elif key == 'strokeLineCap':  #0,1,2
                self._canvas.setLineCap(value)
            elif key == 'strokeLineJoin':
                self._canvas.setLineJoin(value)
            elif key == 'strokeDashArray':
                if value:
                    if isinstance(
                            value,
                        (list, tuple)) and len(value) == 2 and isinstance(
                            value[1], (tuple, list)):
                        phase = value[0]
                        value = value[1]
                    else:
                        phase = 0
                    self._canvas.setDash(value, phase)
                else:
                    self._canvas.setDash()
            elif key == 'fillColor':
                self._canvas.setFillColor(value)
            elif key in ['fontSize', 'fontName']:
                fontname = delta.get('fontName', self._canvas._font)
                fontsize = delta.get('fontSize', self._canvas._fontSize)
                self._canvas.setFont(fontname, fontsize)
class _PDFRenderer(Renderer):
    """This draws onto a PDF document.  It needs to be a class
    rather than a function, as some PDF-specific state tracking is
    needed outside of the state info in the SVG model."""
    def __init__(self):
        self._stroke = 0
        self._fill = 0
        self._tracker = StateTracker()

    def drawNode(self, node):
        """This is the recursive method called for each node
        in the tree"""
        #print "pdf:drawNode", self
        #if node.__class__ is Wedge: stop
        if not (isinstance(node, Path) and node.isClipPath):
            self._canvas.saveState()

        #apply state changes
        deltas = getStateDelta(node)
        self._tracker.push(deltas)
        self.applyStateChanges(deltas, {})

        #draw the object, or recurse
        self.drawNodeDispatcher(node)

        self._tracker.pop()
        if not (isinstance(node, Path) and node.isClipPath):
            self._canvas.restoreState()

    def drawRect(self, rect):
        if rect.rx == rect.ry == 0:
            #plain old rectangle
            self._canvas.rect(rect.x,
                              rect.y,
                              rect.width,
                              rect.height,
                              stroke=self._stroke,
                              fill=self._fill)
        else:
            #cheat and assume ry = rx; better to generalize
            #pdfgen roundRect function.  TODO
            self._canvas.roundRect(rect.x,
                                   rect.y,
                                   rect.width,
                                   rect.height,
                                   rect.rx,
                                   fill=self._fill,
                                   stroke=self._stroke)

    def drawImage(self, image):
        path = image.path
        # currently not implemented in other renderers
        if path and (hasattr(path, 'mode') or os.path.exists(image.path)):
            self._canvas.drawInlineImage(path, image.x, image.y, image.width,
                                         image.height)

    def drawLine(self, line):
        if self._stroke:
            self._canvas.line(line.x1, line.y1, line.x2, line.y2)

    def drawCircle(self, circle):
        self._canvas.circle(circle.cx,
                            circle.cy,
                            circle.r,
                            fill=self._fill,
                            stroke=self._stroke)

    def drawPolyLine(self, polyline):
        if self._stroke:
            assert len(
                polyline.points) >= 2, 'Polyline must have 2 or more points'
            head, tail = polyline.points[0:2], polyline.points[2:],
            path = self._canvas.beginPath()
            path.moveTo(head[0], head[1])
            for i in range(0, len(tail), 2):
                path.lineTo(tail[i], tail[i + 1])
            self._canvas.drawPath(path)

    def drawWedge(self, wedge):
        centerx, centery, radius, startangledegrees, endangledegrees = \
         wedge.centerx, wedge.centery, wedge.radius, wedge.startangledegrees, wedge.endangledegrees
        yradius, radius1, yradius1 = wedge._xtraRadii()
        if yradius is None: yradius = radius
        angle = endangledegrees - startangledegrees
        path = self._canvas.beginPath()
        if (radius1 == 0 or radius1 is None) and (yradius1 == 0
                                                  or yradius1 is None):
            path.moveTo(centerx, centery)
            path.arcTo(centerx - radius, centery - yradius, centerx + radius,
                       centery + yradius, startangledegrees, angle)
        else:
            path.arc(centerx - radius, centery - yradius, centerx + radius,
                     centery + yradius, startangledegrees, angle)
            path.arcTo(centerx - radius1, centery - yradius1,
                       centerx + radius1, centery + yradius1, endangledegrees,
                       -angle)
        path.close()
        self._canvas.drawPath(path, fill=self._fill, stroke=self._stroke)

    def drawEllipse(self, ellipse):
        #need to convert to pdfgen's bounding box representation
        x1 = ellipse.cx - ellipse.rx
        x2 = ellipse.cx + ellipse.rx
        y1 = ellipse.cy - ellipse.ry
        y2 = ellipse.cy + ellipse.ry
        self._canvas.ellipse(x1,
                             y1,
                             x2,
                             y2,
                             fill=self._fill,
                             stroke=self._stroke)

    def drawPolygon(self, polygon):
        assert len(polygon.points) >= 2, 'Polyline must have 2 or more points'
        head, tail = polygon.points[0:2], polygon.points[2:],
        path = self._canvas.beginPath()
        path.moveTo(head[0], head[1])
        for i in range(0, len(tail), 2):
            path.lineTo(tail[i], tail[i + 1])
        path.close()
        self._canvas.drawPath(path, stroke=self._stroke, fill=self._fill)

    def drawString(self, stringObj):
        if self._fill:
            S = self._tracker.getState()
            text_anchor, x, y, text, enc = S[
                'textAnchor'], stringObj.x, stringObj.y, stringObj.text, stringObj.encoding
            if not text_anchor in ['start', 'inherited']:
                font, font_size = S['fontName'], S['fontSize']
                textLen = stringWidth(text, font, font_size, enc)
                if text_anchor == 'end':
                    x -= textLen
                elif text_anchor == 'middle':
                    x -= textLen * 0.5
                elif text_anchor == 'numeric':
                    x -= numericXShift(text_anchor, text, textLen, font,
                                       font_size, enc)
                else:
                    raise ValueError('bad value for textAnchor ' +
                                     str(text_anchor))
            t = self._canvas.beginText(x, y)
            t.textLine(text)
            self._canvas.drawText(t)

    def drawPath(self, path):
        from reportlab.graphics.shapes import _renderPath
        pdfPath = self._canvas.beginPath()
        drawFuncs = (pdfPath.moveTo, pdfPath.lineTo, pdfPath.curveTo,
                     pdfPath.close)
        isClosed = _renderPath(path, drawFuncs)
        if isClosed:
            fill = self._fill
        else:
            fill = 0
        if path.isClipPath:
            self._canvas.clipPath(pdfPath, fill=fill, stroke=self._stroke)
        else:
            self._canvas.drawPath(pdfPath, fill=fill, stroke=self._stroke)

    def setStrokeColor(self, c):
        self._canvas.setStrokeColor(c)

    def setFillColor(self, c):
        self._canvas.setFillColor(c)

    def applyStateChanges(self, delta, newState):
        """This takes a set of states, and outputs the PDF operators
        needed to set those properties"""
        for key, value in delta.items():
            if key == 'transform':
                self._canvas.transform(value[0], value[1], value[2], value[3],
                                       value[4], value[5])
            elif key == 'strokeColor':
                #this has different semantics in PDF to SVG;
                #we always have a color, and either do or do
                #not apply it; in SVG one can have a 'None' color
                if value is None:
                    self._stroke = 0
                else:
                    self._stroke = 1
                    self.setStrokeColor(value)
            elif key == 'strokeWidth':
                self._canvas.setLineWidth(value)
            elif key == 'strokeLineCap':  #0,1,2
                self._canvas.setLineCap(value)
            elif key == 'strokeLineJoin':
                self._canvas.setLineJoin(value)


#            elif key == 'stroke_dasharray':
#                self._canvas.setDash(array=value)
            elif key == 'strokeDashArray':
                if value:
                    if isinstance(
                            value,
                        (list, tuple)) and len(value) == 2 and isinstance(
                            value[1], (tuple, list)):
                        phase = value[0]
                        value = value[1]
                    else:
                        phase = 0
                    self._canvas.setDash(value, phase)
                else:
                    self._canvas.setDash()
            elif key == 'fillColor':
                #this has different semantics in PDF to SVG;
                #we always have a color, and either do or do
                #not apply it; in SVG one can have a 'None' color
                if value is None:
                    self._fill = 0
                else:
                    self._fill = 1
                    self.setFillColor(value)
            elif key in ['fontSize', 'fontName']:
                # both need setting together in PDF
                # one or both might be in the deltas,
                # so need to get whichever is missing
                fontname = delta.get('fontName', self._canvas._fontname)
                fontsize = delta.get('fontSize', self._canvas._fontsize)
                self._canvas.setFont(fontname, fontsize)
            elif key == 'fillOpacity':
                if value is not None:
                    self._canvas.setFillAlpha(value)
            elif key == 'strokeOpacity':
                if value is not None:
                    self._canvas.setStrokeAlpha(value)
            elif key == 'fillOverprint':
                self._canvas.setFillOverprint(value)
            elif key == 'strokeOverprint':
                self._canvas.setStrokeOverprint(value)
            elif key == 'overprintMask':
                self._canvas.setOverprintMask(value)
Exemple #9
0
class _PMRenderer(Renderer):
    """This draws onto a pix map image. It needs to be a class
    rather than a function, as some image-specific state tracking is
    needed outside of the state info in the SVG model."""

    def __init__(self):
        self._tracker = StateTracker()

    def pop(self):
        self._tracker.pop()
        self.applyState()

    def push(self,node):
        deltas = getStateDelta(node)
        self._tracker.push(deltas)
        self.applyState()

    def applyState(self):
        s = self._tracker.getState()
        self._canvas.ctm = s['ctm']
        self._canvas.strokeWidth = s['strokeWidth']
        alpha = s['strokeOpacity']
        if alpha is not None:
            self._canvas.strokeOpacity = alpha
        self._canvas.setStrokeColor(s['strokeColor'])
        self._canvas.lineCap = s['strokeLineCap']
        self._canvas.lineJoin = s['strokeLineJoin']
        da = s['strokeDashArray']
        da = da and (0,da) or None
        self._canvas.dashArray = da
        alpha = s['fillOpacity']
        if alpha is not None:
            self._canvas.fillOpacity = alpha
        self._canvas.setFillColor(s['fillColor'])
        self._canvas.setFont(s['fontName'], s['fontSize'])

    def initState(self,x,y):
        deltas = STATE_DEFAULTS.copy()
        deltas['transform'] = self._canvas._baseCTM[0:4]+(x,y)
        self._tracker.push(deltas)
        self.applyState()

    def drawNode(self, node):
        """This is the recursive method called for each node
        in the tree"""

        #apply state changes
        self.push(node)

        #draw the object, or recurse
        self.drawNodeDispatcher(node)

        # restore the state
        self.pop()

    def drawRect(self, rect):
        c = self._canvas
        if rect.rx == rect.ry == 0:
            #plain old rectangle, draw clockwise (x-axis to y-axis) direction
            c.rect(rect.x,rect.y, rect.width, rect.height)
        else:
            c.roundRect(rect.x,rect.y, rect.width, rect.height, rect.rx, rect.ry)

    def drawLine(self, line):
        self._canvas.line(line.x1,line.y1,line.x2,line.y2)

    def drawImage(self, image):
        if image.path and os.path.exists(image.path):
            if type(image.path) is type(''):
                im = _getImage().open(image.path).convert('RGB')
            else:
                im = image.path.convert('RGB')
            srcW, srcH = im.size
            dstW, dstH = image.width, image.height
            if dstW is None: dstW = srcW
            if dstH is None: dstH = srcH
            self._canvas._aapixbuf(
                    image.x, image.y, dstW, dstH,
                    im.tostring(), srcW, srcH, 3,
                    )

    def drawCircle(self, circle):
        c = self._canvas
        c.circle(circle.cx,circle.cy, circle.r)
        c.fillstrokepath()

    def drawPolyLine(self, polyline, _doClose=0):
        P = polyline.points
        assert len(P) >= 2, 'Polyline must have 1 or more points'
        c = self._canvas
        c.pathBegin()
        c.moveTo(P[0], P[1])
        for i in range(2, len(P), 2):
            c.lineTo(P[i], P[i+1])
        if _doClose:
            c.pathClose()
            c.pathFill()
        c.pathStroke()

    def drawEllipse(self, ellipse):
        c=self._canvas
        c.ellipse(ellipse.cx, ellipse.cy, ellipse.rx,ellipse.ry)
        c.fillstrokepath()

    def drawPolygon(self, polygon):
        self.drawPolyLine(polygon,_doClose=1)

    def drawString(self, stringObj):
        canv = self._canvas
        fill = canv.fillColor
        if fill is not None:
            S = self._tracker.getState()
            text_anchor = S['textAnchor']
            fontName = S['fontName']
            fontSize = S['fontSize']
            text = stringObj.text
            x = stringObj.x
            y = stringObj.y
            if not text_anchor in ['start','inherited']:
                textLen = stringWidth(text, fontName,fontSize)
                if text_anchor=='end':
                    x -= textLen
                elif text_anchor=='middle':
                    x -= textLen/2
                elif text_anchor=='numeric':
                    x -= numericXShift(text_anchor,text,textLen,fontName,fontSize,stringObj.encoding)
                else:
                    raise ValueError, 'bad value for textAnchor '+str(text_anchor)
            canv.drawString(x,y,text,_fontInfo=(fontName,fontSize))

    def drawPath(self, path):
        c = self._canvas
        if path is EmptyClipPath:
            del c._clipPaths[-1]
            if c._clipPaths:
                P = c._clipPaths[-1]
                icp = P.isClipPath
                P.isClipPath = 1
                self.drawPath(P)
                P.isClipPath = icp
            else:
                c.clipPathClear()
            return
        c.pathBegin()
        drawFuncs = (c.moveTo, c.lineTo, c.curveTo, c.pathClose)
        from reportlab.graphics.shapes import _renderPath
        isClosed = _renderPath(path, drawFuncs)
        if path.isClipPath:
            c.clipPathSet()
            c._clipPaths.append(path)
        else:
            if isClosed: c.pathFill()
            c.pathStroke()
class _SVGRenderer(Renderer):
    """This draws onto an SVG document.
    """

    def __init__(self):
        self._tracker = StateTracker()
        self.verbose = 0

    def drawNode(self, node):
        """This is the recursive method called for each node in the tree.
        """

        if self.verbose: print "### begin _SVGRenderer.drawNode(%r)" % node

        self._canvas.comment('begin node %r'%node)
        color = self._canvas._color
        style = self._canvas.style.copy()
        if not (isinstance(node, Path) and node.isClipPath):
            pass # self._canvas.saveState()

        #apply state changes
        deltas = getStateDelta(node)
        self._tracker.push(deltas)
        self.applyStateChanges(deltas, {})

        #draw the object, or recurse
        self.drawNodeDispatcher(node)

        rDeltas = self._tracker.pop()
        if not (isinstance(node, Path) and node.isClipPath):
            pass #self._canvas.restoreState()
        self._canvas.comment('end node %r'%node)
        self._canvas._color = color

        #restore things we might have lost (without actually doing anything).
        for k, v in rDeltas.items():
            if k in self._restores:
                setattr(self._canvas,self._restores[k],v)
        self._canvas.style = style

        if self.verbose: print "### end _SVGRenderer.drawNode(%r)" % node

    _restores = {'strokeColor':'_strokeColor','strokeWidth': '_lineWidth','strokeLineCap':'_lineCap',
                'strokeLineJoin':'_lineJoin','fillColor':'_fillColor','fontName':'_font',
                'fontSize':'_fontSize'}

    def _get_link_info_dict(self, obj):
        #We do not want None or False as the link, even if it is the
        #attribute's value - use the empty string instead.
        url = getattr(obj, "hrefURL", "") or ""
        title = getattr(obj, "hrefTitle", "") or ""
        if url :
            #Is it valid to have a link with no href?  The XML requires
            #the xlink:href to be present, but you might just want a
            #tool tip shown (via the xlink:title attribute).  Note that
            #giving an href of "" is equivalent to "the current page"
            #(a relative link saying go nowhere).
            return {"xlink:href":url, "xlink:title":title, "target":"_top"}
            #Currently of all the mainstream browsers I have tested, only Safari/webkit
            #will show  SVG images embedded in HTML using a simple <img src="..." /> tag.
            #However, the links don't work (Safari 3.2.1 on the Mac).
            #
            #Therefore I use the following, which also works for Firefox, Opera, and
            #IE 6.0 with Adobe SVG Viewer 6 beta:
            #<object data="..." type="image/svg+xml" width="430" height="150" class="img">
            #
            #Once displayed, Firefox and Safari treat the SVG like a frame, and
            #by default clicking on links acts "in frame" and replaces the image.
            #Opera does what I expect, and replaces the whole page with the link.
            #
            #Therefore I use target="_top" to force the links to replace the whole page.
            #This now works as expected on Safari 3.2.1, Firefox 3.0.6, Opera 9.20. 
            #Perhaps the target attribute should be an option, perhaps defaulting to
            #"_top" as used here?
        else :
            return None

    def drawGroup(self, group):
        if self.verbose: print "### begin _SVGRenderer.drawGroup"

        currGroup = self._canvas.startGroup()
        a, b, c, d, e, f = self._tracker.getState()['transform']
        for childNode in group.getContents():
            if isinstance(childNode, UserNode):
                node2 = childNode.provideNode()
            else:
                node2 = childNode
            self.drawNode(node2)
        self._canvas.transform(a, b, c, d, e, f)
        self._canvas.endGroup(currGroup)

        if self.verbose: print "### end _SVGRenderer.drawGroup"

    def drawRect(self, rect):
        link_info = self._get_link_info_dict(rect)
        if rect.rx == rect.ry == 0:
            #plain old rectangle
            self._canvas.rect(
                    rect.x, rect.y,
                    rect.x+rect.width, rect.y+rect.height, link_info=link_info)
        else:
            #cheat and assume ry = rx; better to generalize
            #pdfgen roundRect function.  TODO
            self._canvas.roundRect(
                    rect.x, rect.y,
                    rect.x+rect.width, rect.y+rect.height,
                    rect.rx, rect.ry,
                    link_info=link_info)

    def drawString(self, stringObj):
        if self._canvas._fillColor:
            S = self._tracker.getState()
            text_anchor, x, y, text = S['textAnchor'], stringObj.x, stringObj.y, stringObj.text
            if not text_anchor in ('start', 'inherited'):
                font, fontSize = S['fontName'], S['fontSize']
                textLen = stringWidth(text, font,fontSize)
                if text_anchor=='end':
                    x -= textLen
                elif text_anchor=='middle':
                    x -= textLen/2
                elif text_anchor=='numeric':
                    x -= numericXShift(text_anchor,text,textLen,font,fontSize)
                else:
                    raise ValueError, 'bad value for text_anchor ' + str(text_anchor)
            self._canvas.drawString(text,x,y,link_info=self._get_link_info_dict(stringObj))

    def drawLine(self, line):
        if self._canvas._strokeColor:
            self._canvas.line(line.x1, line.y1, line.x2, line.y2)

    def drawCircle(self, circle):
        self._canvas.circle( circle.cx, circle.cy, circle.r, link_info=self._get_link_info_dict(circle))

    def drawWedge(self, wedge):
        centerx, centery, radius, startangledegrees, endangledegrees = \
         wedge.centerx, wedge.centery, wedge.radius, wedge.startangledegrees, wedge.endangledegrees
        yradius = wedge.yradius or wedge.radius
        (x1, y1) = (centerx-radius, centery-yradius)
        (x2, y2) = (centerx+radius, centery+yradius)
        extent = endangledegrees - startangledegrees
        self._canvas.drawArc(x1, y1, x2, y2, startangledegrees, extent, fromcenter=1)

    def drawPolyLine(self, p):
        if self._canvas._strokeColor:
            self._canvas.polyLine(_pointsFromList(p.points))

    def drawEllipse(self, ellipse):
        #need to convert to pdfgen's bounding box representation
        x1 = ellipse.cx - ellipse.rx
        x2 = ellipse.cx + ellipse.rx
        y1 = ellipse.cy - ellipse.ry
        y2 = ellipse.cy + ellipse.ry
        self._canvas.ellipse(x1,y1,x2,y2, link_info=self._get_link_info_dict(ellipse))

    def drawPolygon(self, p):
        self._canvas.polygon(_pointsFromList(p.points), closed=1, link_info=self._get_link_info_dict(p))

    def drawPath(self, path):
        # print "### drawPath", path.points
        from reportlab.graphics.shapes import _renderPath
        c = self._canvas
        drawFuncs = (c.moveTo, c.lineTo, c.curveTo, c.closePath)
        isClosed = _renderPath(path, drawFuncs)
        if isClosed:
            #Only try and add links to closed paths...
            link_info = self._get_link_info_dict(path)
        else :
            c._fillColor = None
            link_info = None
        c._fillAndStroke([], clip=path.isClipPath, link_info=link_info)

    def applyStateChanges(self, delta, newState):
        """This takes a set of states, and outputs the operators
        needed to set those properties"""

        for key, value in delta.items():
            if key == 'transform':
                pass
                #self._canvas.transform(value[0], value[1], value[2], value[3], value[4], value[5])
            elif key == 'strokeColor':
                self._canvas.setStrokeColor(value)
            elif key == 'strokeWidth':
                self._canvas.setLineWidth(value)
            elif key == 'strokeLineCap':  #0,1,2
                self._canvas.setLineCap(value)
            elif key == 'strokeLineJoin':
                self._canvas.setLineJoin(value)
            elif key == 'strokeDashArray':
                if value:
                    if isinstance(value,(list,tuple)) and len(value)==2 and isinstance(value[1],(tuple,list)):
                        phase = value[0]
                        value = value[1]
                    else:
                        phase = 0
                    self._canvas.setDash(value,phase)
                else:
                    self._canvas.setDash()
            elif key == 'fillColor':
                self._canvas.setFillColor(value)
            elif key in ['fontSize', 'fontName']:
                fontname = delta.get('fontName', self._canvas._font)
                fontsize = delta.get('fontSize', self._canvas._fontSize)
                self._canvas.setFont(fontname, fontsize)