changes to Render class; allow drawings to specify initialFontName/Size version-->3.3.9
authorrobin
Wed, 25 May 2016 15:25:35 +0100
changeset 4274 ec03159b74bb
parent 4273 c75089f14f46
child 4275 54ce6704aa97
changes to Render class; allow drawings to specify initialFontName/Size version-->3.3.9
src/reportlab/__init__.py
src/reportlab/graphics/renderPDF.py
src/reportlab/graphics/renderPM.py
src/reportlab/graphics/renderPS.py
src/reportlab/graphics/renderSVG.py
src/reportlab/graphics/renderbase.py
src/reportlab/graphics/shapes.py
--- a/src/reportlab/__init__.py	Tue May 24 12:55:12 2016 +0100
+++ b/src/reportlab/__init__.py	Wed May 25 15:25:35 2016 +0100
@@ -1,9 +1,9 @@
 #Copyright ReportLab Europe Ltd. 2000-2016
 #see license.txt for license details
 __doc__="""The Reportlab PDF generation library."""
-Version = "3.3.8"
+Version = "3.3.9"
 __version__=Version
-__date__='20160519'
+__date__='20160525'
 
 import sys, os
 
--- a/src/reportlab/graphics/renderPDF.py	Tue May 24 12:55:12 2016 +0100
+++ b/src/reportlab/graphics/renderPDF.py	Wed May 25 15:25:35 2016 +0100
@@ -20,7 +20,7 @@
 from reportlab.pdfbase.pdfmetrics import stringWidth
 from reportlab.lib.utils import getBytesIO
 from reportlab import rl_config
-from reportlab.graphics.renderbase import Renderer, StateTracker, getStateDelta, renderScaledDrawing
+from reportlab.graphics.renderbase import Renderer, StateTracker, getStateDelta, renderScaledDrawing, STATE_DEFAULTS
 
 # the main entry point for users...
 def draw(drawing, canvas, x, y, showBoundary=rl_config._unset_):
@@ -36,7 +36,6 @@
     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
@@ -269,7 +268,7 @@
     def draw(self):
         draw(self.drawing, self.canv, 0, 0)
 
-def drawToFile(d, fn, msg="", showBoundary=rl_config._unset_, autoSize=1):
+def drawToFile(d, fn, msg="", showBoundary=rl_config._unset_, autoSize=1, canvasKwds={}):
     """Makes a one-page PDF with just the drawing.
 
     If autoSize=1, the PDF will be the same size as
@@ -277,7 +276,10 @@
     an A4 page with a title above it - possibly overflowing
     if too big."""
     d = renderScaledDrawing(d)
-    c = Canvas(fn)
+    for x in ('Name','Size'):
+        a = 'initialFont'+x
+        canvasKwds[a] = getattr(d,a,canvasKwds.pop(a,STATE_DEFAULTS['font'+x]))
+    c = Canvas(fn,**canvasKwds)
     if msg:
         c.setFont(rl_config.defaultGraphicsFontName, 36)
         c.drawString(80, 750, msg)
@@ -304,10 +306,10 @@
         except:
             pass
 
-def drawToString(d, msg="", showBoundary=rl_config._unset_,autoSize=1):
+def drawToString(d, msg="", showBoundary=rl_config._unset_,autoSize=1,canvasKwds={}):
     "Returns a PDF as a string in memory, without touching the disk"
     s = getBytesIO()
-    drawToFile(d, s, msg=msg, showBoundary=showBoundary,autoSize=autoSize)
+    drawToFile(d, s, msg=msg, showBoundary=showBoundary,autoSize=autoSize, canvasKwds=canvasKwds)
     return s.getvalue()
 
 #########################################################
--- a/src/reportlab/graphics/renderPM.py	Tue May 24 12:55:12 2016 +0100
+++ b/src/reportlab/graphics/renderPM.py	Wed May 25 15:25:35 2016 +0100
@@ -55,9 +55,6 @@
     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()
@@ -93,7 +90,7 @@
         self._canvas.setFont(s['fontName'], s['fontSize'])
 
     def initState(self,x,y):
-        deltas = STATE_DEFAULTS.copy()
+        deltas = self._tracker._combined[-1]
         deltas['transform'] = self._canvas._baseCTM[0:4]+(x,y)
         self._tracker.push(deltas)
         self.applyState()
--- a/src/reportlab/graphics/renderPS.py	Tue May 24 12:55:12 2016 +0100
+++ b/src/reportlab/graphics/renderPS.py	Wed May 25 15:25:35 2016 +0100
@@ -700,9 +700,6 @@
     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"""
--- a/src/reportlab/graphics/renderSVG.py	Tue May 24 12:55:12 2016 +0100
+++ b/src/reportlab/graphics/renderSVG.py	Wed May 25 15:25:35 2016 +0100
@@ -676,7 +676,6 @@
     """
 
     def __init__(self):
-        self._tracker = StateTracker()
         self.verbose = 0
 
     def drawNode(self, node):
--- a/src/reportlab/graphics/renderbase.py	Tue May 24 12:55:12 2016 +0100
+++ b/src/reportlab/graphics/renderbase.py	Wed May 25 15:25:35 2016 +0100
@@ -30,7 +30,6 @@
             A[0]*B[4] + A[2]*B[5] + A[4],
             A[1]*B[4] + A[3]*B[5] + A[5])
 
-
 def getStateDelta(shape):
     """Used to compute when we need to change the graphics state.
     For example, if we have two adjacent red shapes we don't need
@@ -42,7 +41,6 @@
             delta[prop] = value
     return delta
 
-
 class StateTracker:
     """Keeps a stack of transforms and state
     properties.  It can contain any properties you
@@ -51,7 +49,7 @@
     method returns the current transformation
     matrix at any point, without needing to
     invert matrixes when you pop."""
-    def __init__(self, defaults=None):
+    def __init__(self, defaults=None, defaultObj=None):
         # one stack to keep track of what changes...
         self._deltas = []
 
@@ -61,11 +59,19 @@
         self._combined = []
         if defaults is None:
             defaults = STATE_DEFAULTS.copy()
+        if defaultObj:
+            for k in STATE_DEFAULTS.keys():
+                a = 'initial'+k[:1].upper()+k[1:]
+                if hasattr(defaultObj,a):
+                    defaults[k] = getattr(defaultObj,a)
         #ensure  that if we have a transform, we have a CTM
         if 'transform' in defaults:
             defaults['ctm'] = defaults['transform']
         self._combined.append(defaults)
 
+    def _applyDefaultObj(self,d):
+        return d
+
     def push(self,delta):
         """Take a new state dictionary of changes and push it onto
         the stack.  After doing this, the combined state is accessible
@@ -148,7 +154,6 @@
         print('popping:',st.pop())
         print('state:  ',st.getState(),'\n')
 
-
 def _expandUserNode(node,canvas):
     if isinstance(node, UserNode):
         try:
@@ -176,16 +181,13 @@
 class Renderer:
     """Virtual superclass for graphics renderers."""
 
-    def __init__(self):
-        self._tracker = StateTracker()
-        self._nodeStack = []   #track nodes visited
-
     def undefined(self, operation):
         raise ValueError("%s operation not defined at superclass class=%s" %(operation, self.__class__))
 
     def draw(self, drawing, canvas, x=0, y=0, showBoundary=rl_config._unset_):
         """This is the top level function, which draws the drawing at the given
         location. The recursive part is handled by drawNode."""
+        self._tracker = StateTracker(defaultObj=drawing)
         #stash references for ease of  communication
         if showBoundary is rl_config._unset_: showBoundary=rl_config.showBoundary
         self._canvas = canvas
@@ -201,11 +203,11 @@
             canvas.restoreState()
         finally:
             #remove any circular references
-            del self._canvas, self._drawing, canvas._drawing, drawing._parent
+            del self._canvas, self._drawing, canvas._drawing, drawing._parent, self._tracker
 
     def initState(self,x,y):
-        deltas = STATE_DEFAULTS.copy()
-        deltas['transform'] = [1,0,0,1,x,y]
+        deltas = self._tracker._combined[-1]
+        deltas['transform'] = tuple(list(deltas['transform'])[:4])+(x,y)
         self._tracker.push(deltas)
         self.applyStateChanges(deltas, {})
 
@@ -222,13 +224,13 @@
         """Return current state parameter for given key"""
         currentState = self._tracker._combined[-1]
         return currentState[key]
-    
+
     def fillDerivedValues(self, node):
         """Examine a node for any values which are Derived,
         and replace them with their calculated values.
         Generally things may look at the drawing or their
         parent.
-        
+
         """
         for key, value in node.__dict__.items():
             if isinstance(value, DerivedValue):
@@ -297,7 +299,7 @@
             node = _expandUserNode(node,canvas)
             if not node: continue
 
-            #here is where we do derived values - this seems to get everything. Touch wood.            
+            #here is where we do derived values - this seems to get everything. Touch wood.
             self.fillDerivedValues(node)
             try:
                 if hasattr(node,'_canvas'):
--- a/src/reportlab/graphics/shapes.py	Tue May 24 12:55:12 2016 +0100
+++ b/src/reportlab/graphics/shapes.py	Wed May 25 15:25:35 2016 +0100
@@ -62,7 +62,6 @@
     'textAnchor':  'start' # can be start, middle, end, inherited
     }
 
-
 ####################################################################
 # math utilities.  These could probably be moved into lib
 # somewhere.
@@ -171,7 +170,6 @@
     Y = [x[1] for x in C]
     return min(X), max(X), min(Y), max(Y), C
 
-
 class _DrawTimeResizeable:
     '''Addin class to provide the horribleness of _drawTimeResize'''
     def _drawTimeResize(self,w,h):
@@ -188,7 +186,6 @@
         for key, value in keywords.items():
             setattr(self, key, value)
 
-
 #################################################################
 #
 #    Helper functions for working out bounds
@@ -506,7 +503,6 @@
         """Convenience to help you set transforms"""
         self.transform = mmult(self.transform, scale(sx, sy))
 
-
     def skew(self, kx, ky):
         """Convenience to help you set transforms"""
         self.transform = mmult(mmult(self.transform, skewX(kx)),skewY(ky))
@@ -641,6 +637,8 @@
         #AR temporary hack to track back up.
         #fontName = AttrMapValue(isStringOrNone),
         renderScale = AttrMapValue(isNumber,desc="Global scaling for rendering"),
+        initialFontName = AttrMapValue(isStringOrNone,desc="override the STATE_DEFAULTS value for fontName"),
+        initialFontSize = AttrMapValue(isNumberOrNone,desc="override the STATE_DEFAULTS value for fontSize"),
         )
 
     _attrMap = AttrMap(BASE=Group,
@@ -917,7 +915,6 @@
         self.strokeOpacity = None
         self.setProperties(kw)
 
-
 class Line(LineShape):
     _attrMap = AttrMap(BASE=LineShape,
         x1 = AttrMapValue(isNumber,desc=""),
@@ -954,7 +951,6 @@
         #the above settings
         LineShape.__init__(self, kw)
 
-
 # path operator  constants
 _MOVETO, _LINETO, _CURVETO, _CLOSEPATH = list(range(4))
 _PATH_OP_ARG_COUNT = (2, 2, 6, 0)  # [moveTo, lineTo, curveTo, closePath]
@@ -1137,7 +1133,6 @@
     def getBounds(self):
         return (self.x, self.y, self.x + self.width, self.y + self.height)
 
-
 class Image(SolidShape):
     """Bitmap image."""
 
@@ -1445,7 +1440,6 @@
 
         raise NotImplementedError("this method must be redefined by the user/programmer")
 
-
 def test():
     r = Rect(10,10,200,50)
     import pprint
@@ -1463,6 +1457,5 @@
     w('verifying...')
     r.verify()
 
-
 if __name__=='__main__':
     test()