[reportlab-users] renderPM

Andrew Dalke reportlab-users@reportlab.com
Fri, 17 Oct 2003 04:26:05 -0600


Hello,

   Here's the summary version:

   - there's a typo in the graphics documentation; saveToFile
       should be drawToFile for the renderPM example

   - here is a more complete description of a way to get missing
       pfb files working for Mac OS X

   - there's a bus error bug somewhere in renderPM that I'm unable
       to track down


   I am trying to get renderPM to work under Mac OS X with Python 2.3
but I am having/did have a few problems.  I built it from a fresh copy
out of CVS on top of the latest standard distributions of PIL and
reportlab.  Here's the driver code

  =======
from reportlab.lib import colors
from reportlab.graphics.shapes import *
d = Drawing(400, 200)

d.add(Rect(50, 50, 300, 100, fillColor=colors.yellow))
d.add(String(150,100, 'Hello World',
fontSize=18, fillColor=colors.red))

from reportlab.graphics import renderPM
renderPM.drawToFile(d, 'example1.png', 'PNG')
  =======

This comes right from the documentation for the graphics
library except that the documented method 'saveToFile'
should really be 'drawToFile'.

Here's what I get when I run it

  =====
[Andrew-Dalkes-Computer:~/cvses/rl_addons/renderPM] dalke% python  
example1.py
Warn: Can't find .pfb for face 'Times-Roman'
Traceback (most recent call last):
   File "example1.py", line 12, in ?
     renderPM.drawToFile(d, 'example1.png', 'PNG')
   File  
"/usr/local/lib/python2.3/site-packages/reportlab/graphics/ 
renderPM.py", line 521, in drawToFile
     c = drawToPMCanvas(d, dpi=dpi, bg=bg, configPIL=configPIL,  
showBoundary=showBoundary)
   File  
"/usr/local/lib/python2.3/site-packages/reportlab/graphics/ 
renderPM.py", line 507, in drawToPMCanvas
     draw(d, c, 0, 0)
   File  
"/usr/local/lib/python2.3/site-packages/reportlab/graphics/ 
renderPM.py", line 51, in draw
     R.draw(drawing, canvas, x, y)
   File  
"/usr/local/lib/python2.3/site-packages/reportlab/graphics/ 
renderPM.py", line 97, in draw
     self.applyState()
   File  
"/usr/local/lib/python2.3/site-packages/reportlab/graphics/ 
renderPM.py", line 82, in applyState
     self._canvas.setFont(s['fontName'], s['fontSize'])
   File  
"/usr/local/lib/python2.3/site-packages/reportlab/graphics/ 
renderPM.py", line 329, in setFont
     _setFont(self._gs,fontName,fontSize)
   File  
"/usr/local/lib/python2.3/site-packages/reportlab/graphics/ 
renderPM.py", line 233, in _setFont
     raise RenderPMError, "Can't setFont(%s) missing the T1  
files?\nOriginally %s: %s" % (fontName,s1,s2)
reportlab.graphics.renderPM.RenderPMError: Can't setFont(Times-Roman)  
missing the T1 files?
Originally exceptions.TypeError: makeT1Font() argument 2 must be  
string, not None
  =====

This has been reported before.  The suggestion at
    
http://two.pairlist.net/pipermail/reportlab-users/2002-June/000072.html
is to
 >get the pfb's for the standard things from www.adobe.com. When
 >you get acrobat reader for windows it normally comes with a whole bunch
 >of [.pfb] files.

I looked in my Mac Acrobat reader files but didn't those files

dalke% find ~/Desktop/Adobe\ Reader\ 6.0/ -name '*.pfb' -print
dalke%

I also looked on Adobe's site but failed miserably to find them.

Luckily, Leighton Pritchard reported a solution at
    
http://two.pairlist.net/pipermail/reportlab-users/2003-August/ 
001980.html
which was to download the files from
http://www.genesys.ro/download/Networking/Allied_Telesyn/Switchblade_1/ 
ACROBAT/RESOURCE/FONT/

I made it work by:
   - making the directory "reportlab/fonts" (this is one of the paths  
defined
in T1SearchPath from reportlab/rl_config.py)
   - copy the files from that site, but make sure the filenames are in
       lower case (needed because of a string.lower in
           reportlab/pdfbase/pdfmetrics.py:TypeFace.findT1File )

I mention this here to suggest some documentation about this problem
(and hopefully a better source for those files) be included in
  renderPM README, and so that people searching for a solution based
on the keywords I tried will find an answer in one single file.


The last thing to note is that the test_renderPM.py test code gives

dalke% python test_renderPM.py
Bus error
dalke%

It occurs in the setattr when a == 'fillColor'

         for a in ('strokeColor','fillColor'):
             try:
                 setattr(g,a,(1,2,3))
                 print 'Wrong handling of bad '+a
             except ValueError:
                 pass

Here's the stack trace

Program received signal EXC_BAD_ACCESS, Could not access memory.
PyObject_GenericGetAttr (obj=0x515c88, name=0x510520) at  
Objects/object.c:1399
1399                    n = PyTuple_GET_SIZE(mro);
(gdb) where
#0  PyObject_GenericGetAttr (obj=0x515c88, name=0x510520) at  
Objects/object.c:1399
#1  0x00035e4c in PyObject_HasAttrString (v=0x515c88, name=0xb2  
<Address 0xb2 out of bounds>) at Objects/object.c:1182
#2  0x005894a4 in _set_gstateColor (value=0x515c88, c=0x99c1b8) at  
_renderPM.c:866
#3  0x005876d4 in gstate_setattr (self=0x99c160, name=0x40ff84  
"fillColor", value=0x515c88) at _renderPM.c:1006
#4  0x00034c50 in PyObject_SetAttr (v=0x99c160, name=0x40ff70,  
value=0x515c88) at Objects/object.c:1294
#5  0x0009debc in builtin_setattr (self=0xe07ec, args=0xb1) at  
Python/bltinmodule.c:913
#6  0x00086378 in call_function (pp_stack=0xbffff65c, oparg=177) at  
Python/ceval.c:3439
#7  0x00083f50 in eval_frame (f=0x8eedd0) at Python/ceval.c:2116
#8  0x000865c8 in fast_function (func=0xe07ec, pp_stack=0xbffff7ec,  
n=0, na=216420, nk=0) at Python/ceval.c:3518
#9  0x00086450 in call_function (pp_stack=0xbffff7ec, oparg=177) at  
Python/ceval.c:3458
#10 0x00083f50 in eval_frame (f=0x43cdc0) at Python/ceval.c:2116
#11 0x00085268 in PyEval_EvalCodeEx (co=0x470ce0, globals=0xb1,  
locals=0xb2, args=0x0, argcount=0, kws=0x0, kwcount=0, defs=0x0,  
defcount=0, closure=0x0) at Python/ceval.c:2663
#12 0x000880dc in PyEval_EvalCode (co=0xe07ec, globals=0xb1,  
locals=0x48004444) at Python/ceval.c:537
#13 0x0000c78c in run_node (n=0x0, filename=0xb1 <Address 0xb1 out of  
bounds>, globals=0x4019c0, locals=0x4019c0, flags=0x68220) at  
Python/pythonrun.c:1205
#14 0x0000bf38 in PyRun_SimpleFileExFlags (fp=0xa0006b4c,  
filename=0xbffffc22 "test_renderPM.py", closeit=4443916,  
flags=0x470ce0) at Python/pythonrun.c:802
#15 0x00006498 in Py_Main (argc=-2013264827, argv=0xbffffb74) at  
Modules/main.c:415
#16 0x00001eec in _start (argc=2, argv=0xbffffb74, envp=0xbffffb80) at  
/SourceCache/Csu/Csu-45/crt.c:267
#17 0x00001d6c in start ()

More specifically, it's testing the tuple (1,2,3) to see if it has
the attribute named "red"

(gdb) up
(gdb) up
#2  0x005894a4 in _set_gstateColor (value=0x515c88, c=0x99c1b8) at  
_renderPM.c:866
866             else if(PyObject_HasAttrString(value,"red")
(gdb) print *value
$3 = {
   ob_refcnt = 1,
   ob_type = 0xe57f4
}
(gdb) print *value->ob_type
$4 = {
   ob_refcnt = 47,
   ob_type = 0xe0ae4,
   ob_size = 0,
   tp_name = 0xd57ec "tuple",
   tp_basicsize = 12,
   tp_itemsize = 4,
   tp_dealloc = 0x68dd8 <tupledealloc>,
   tp_print = 0x68f48 <tupleprint>,
   tp_getattr = 0,
   tp_setattr = 0,
   tp_compare = 0,
   tp_repr = 0x69010 <tuplerepr>,
   tp_as_number = 0x0,
   tp_as_sequence = 0xe57a0,
   tp_as_mapping = 0xe57e8,
   tp_hash = 0x691d0 <tuplehash>,
   tp_call = 0,
   tp_str = 0,
   tp_getattro = 0x34d64 <PyObject_GenericGetAttr>,
   tp_setattro = 0,
   tp_as_buffer = 0x0,
   tp_flags = 17899,
   tp_doc = 0xe5708 "tuple() -> an empty tuple\ntuple(sequence) -> tuple  
initialized from sequence's items\n\nIf the argument is a tuple, the  
return value is the same object.",
   tp_traverse = 0x696c0 <tupletraverse>,
   tp_clear = 0,
   tp_richcompare = 0x69738 <tuplerichcompare>,
   tp_weaklistoffset = 0,
   tp_iter = 0x69d68 <tuple_iter>,
   tp_iternext = 0,
   tp_methods = 0xe57c8,
   tp_members = 0x0,
   tp_getset = 0x0,
   tp_base = 0xe0bfc,
   tp_dict = 0x9a1300,
   tp_descr_get = 0,
   tp_descr_set = 0,
   tp_dictoffset = 0,
   tp_init = 0,
   tp_alloc = 0,
   tp_new = 0x69964 <tuple_new>,
   tp_free = 0x91094 <PyObject_GC_Del>,
   tp_is_gc = 0,
   tp_bases = 0x4236f0,
   tp_mro = 0x0,
   tp_cache = 0x0,
   tp_subclasses = 0x0,
   tp_weaklist = 0x0,
   tp_del = 0
}

  Looking at the code, I can't figure out what's wrong .... Ahh, there's
a CVS commit on 2003/08/15 from mwh "fix obscure crash in descriptor
handling" which looks like it fixes a reference count bug, and it's
in the right section of code.  If there's an extra decref, that would
explain why the error occurs on the second time through the list.
However, rebuilding Python out of CVS doesn't remove the bus error.

I have very little experience with the Python/C API so this is as
far as I'll take it for now -- it only happens with a getattr
failure so shouldn't affect any of my production code.


					Andrew
					dalke@dalkescientific.com