reportlab/platypus/paraparser.py
changeset 2857 487dc2450eec
parent 2836 66fb84201abe
child 2860 3f14d66194c2
--- a/reportlab/platypus/paraparser.py	Fri Sep 28 12:52:01 2007 +0000
+++ b/reportlab/platypus/paraparser.py	Mon Oct 01 15:25:36 2007 +0000
@@ -11,6 +11,7 @@
 import unicodedata
 import reportlab.lib.sequencer
 from reportlab.lib.abag import ABag
+from reportlab.lib.utils import ImageReader
 
 from reportlab.lib import xmllib
 
@@ -24,6 +25,19 @@
 subFraction = 0.5   # fraction of font size that a sub script should be lowered
 superFraction = 0.5 # fraction of font size that a super script should be raised
 
+
+def _convnum(s, unit=1):
+    if s[0] in ['+','-']:
+        try:
+            return ('relative',int(s)*unit)
+        except ValueError:
+            return ('relative',float(s)*unit)
+    else:
+        try:
+            return int(s)*unit
+        except ValueError:
+            return float(s)*unit
+
 def _num(s, unit=1):
     """Convert a string like '10cm' to an int or float (in points).
        The default unit is point, but optionally you can use other
@@ -47,16 +61,28 @@
     if s[-4:]=='pica':
         unit=pica
         s = s[:-4]
-    if s[0] in ['+','-']:
-        try:
-            return ('relative',int(s)*unit)
-        except ValueError:
-            return ('relative',float(s)*unit)
-    else:
-        try:
-            return int(s)*unit
-        except ValueError:
-            return float(s)*unit
+    return _convnum(s,unit)
+
+class _PCT:
+    def __init__(self,v):
+        self._value = v*0.01
+
+    def normalizedValue(self,normalizer):
+        return normalizer*self._value
+
+def _valignpc(s):
+    s = s.lower()
+    if s in ('baseline','sub','super','top','text-top','middle','bottom','text-bottom'):
+        return s
+    if s.endswith('%'):
+        n = _convnum(s[:-1])
+        if isinstance(n,tuple):
+            n = n[1]
+        return _PCT(n)
+    n = _num(s)
+    if isinstance(n,tuple):
+        n = n[1]
+    return n
 
 def _autoLeading(x):
     x = x.lower()
@@ -136,6 +162,12 @@
                 'bgcolor':('backColor',toColor),
                 'href': ('href', None),
                 }
+_imgAttrMap = {
+                'src': ('src', None),
+                'width': ('width',_num),
+                'height':('height',_num),
+                'valign':('valign',_valignpc),
+                }
 
 def _addAttributeNames(m):
     K = m.keys()
@@ -354,6 +386,7 @@
 #       <a name="anchorpoint"/>
 #       <unichar name="unicode character name"/>
 #       <unichar value="unicode code point"/>
+#       <img src="path" width="1in" height="1in" valign="bottom"/>
 #       <greek> - </greek>
 #
 #       The whole may be surrounded by <para> </para> tags
@@ -461,6 +494,28 @@
             del self._stack[-1]
             assert frag.link!=None
 
+    def start_img(self,attributes):
+        A = self.getAttributes(attributes,_imgAttrMap)
+        if not A.get('src'):
+            self._syntax_error('<img> needs src attribute')
+        A['_selfClosingTag'] = 'img'
+        self._push(**A)
+
+    def end_img(self):
+        frag = self._stack[-1]
+        assert getattr(frag,'_selfClosingTag',''),'Parser failure in <img/>'
+        defn = frag.cbDefn = ABag()
+        defn.kind = 'img'
+        defn.src = getattr(frag,'src',None)
+        defn.image = ImageReader(defn.src)
+        size = defn.image.getSize()
+        defn.width = getattr(frag,'width',size[0])
+        defn.height = getattr(frag,'height',size[1])
+        defn.valign = getattr(frag,'valign','bottom')
+        del frag._selfClosingTag
+        self.handle_data('')
+        self._pop()
+
     #### super script
     def start_super( self, attributes ):
         self._push(super=1)
@@ -750,7 +805,8 @@
 
         frag = copy.copy(self._stack[-1])
         if hasattr(frag,'cbDefn'):
-            if data!='': self._syntax_error('Only <onDraw> tag allowed')
+            kind = frag.cbDefn.kind
+            if data: self._syntax_error('Only empty <%s> tag allowed' % kind)
         elif hasattr(frag,'_selfClosingTag'):
             if data!='': self._syntax_error('No content allowed in %s tag' % frag._selfClosingTag)
             return
@@ -875,7 +931,7 @@
             for l in rv:
                 print l.fontName,l.fontSize,l.textColor,l.bold, l.rise, '|%s|'%l.text[:25],
                 if hasattr(l,'cbDefn'):
-                    print 'cbDefn',l.cbDefn.name,l.cbDefn.label,l.cbDefn.kind
+                    print 'cbDefn',getattr(l.cbDefn,'name',''),getattr(l.cbDefn,'label',''),l.cbDefn.kind
                 else: print
 
     style=ParaFrag()
@@ -991,3 +1047,4 @@
     check_text('''Here comes <font face="Helvetica" size="14pt">Helvetica 14</font> with <Strong>strong</Strong> <em>emphasis</em>.''')
     check_text('''Here comes <font face="Courier" size="3cm">Courier 3cm</font> and normal again.''')
     check_text('''Before the break <br/>the middle line <br/> and the last line.''')
+    check_text('''This should be an inline image <img src='../docs/images/testimg.gif'/>!''')