svglib
svglib copied to clipboard
Reportlab unable to find Arial font
When running this from the test suite, on reportlab 3.4.0 I get an error indicating some ArialMT file was not found:
Flatty:svglib dinu$ PYTHONPATH=. py.test tests/test_samples.py -k TestW3CSVG
===================================================== test session starts =====================================================
platform darwin -- Python 3.6.3, pytest-3.5.1, py-1.5.2, pluggy-0.6.0
rootdir: /Volumes/SanDisk128/mobiledev/src/repos/github/deeplook/svglib, inifile:
plugins: hypothesis-3.38.5, celery-4.1.0
collected 9 items / 7 deselected
tests/test_samples.py Fs [100%]
========================================================== FAILURES ===========================================================
_______________________________________________ TestW3CSVG.test_convert_pdf_png _______________________________________________
gs = <gstate object at 0x1099c5850>, fontName = 'Arial', fontSize = 30.0
def _setFont(gs,fontName,fontSize):
try:
> gs.setFont(fontName,fontSize)
E ValueError: _renderPM.gstate_setFont: Can't find font!
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderPM.py:242: ValueError
During handling of the above exception, another exception occurred:
gs = <gstate object at 0x1099c5850>, fontName = 'Arial', fontSize = 30.0
def _setFont(gs,fontName,fontSize):
try:
gs.setFont(fontName,fontSize)
except ValueError as e:
if not e.args[0].endswith("Can't find font!"): raise
#here's where we try to add a font to the canvas
try:
f = getFont(fontName)
> _renderPM.makeT1Font(fontName,f.face.findT1File(),f.encoding.vector,open_and_read)
E AttributeError: 'TTEncoding' object has no attribute 'vector'
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderPM.py:248: AttributeError
During handling of the above exception, another exception occurred:
self = <test_samples.TestW3CSVG object at 0x10bee5710>
def test_convert_pdf_png(self):
"""
Test converting W3C SVG files to PDF and PNG using svglib.
``renderPM.drawToFile()`` used in this test is known to trigger an
error sometimes in reportlab which was fixed in reportlab 3.3.26.
See https://github.com/deeplook/svglib/issues/47
"""
exclude_list = [
"paint-stroke-06-t.svg",
"paint-stroke-207-t.svg",
"coords-trans-09-t.svg", # renderPDF issue (div by 0)
]
paths = glob.glob("%s/svg/*.svg" % self.folder_path)
msg = "Destination folder '%s/svg' not found." % self.folder_path
assert len(paths) > 0, msg
for i, path in enumerate(paths):
print("working on [%d] %s" % (i, path))
if basename(path) in exclude_list:
print("excluded (to be tested later)")
continue
# convert
drawing = svglib.svg2rlg(path)
# save as PDF
base = splitext(path)[0] + '-svglib.pdf'
renderPDF.drawToFile(drawing, base, showBoundary=0)
# save as PNG
# (endless loop for file paint-stroke-06-t.svg)
base = splitext(path)[0] + '-svglib.png'
try:
# Can trigger an error in reportlab < 3.3.26.
> renderPM.drawToFile(drawing, base, 'PNG')
tests/test_samples.py:434:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderPM.py:680: in drawToFile
c = drawToPMCanvas(d, dpi=dpi, bg=bg, configPIL=configPIL, showBoundary=showBoundary)
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderPM.py:666: in drawToPMCanvas
draw(d, c, 0, 0, showBoundary=showBoundary)
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderPM.py:51: in draw
R.draw(renderScaledDrawing(drawing), canvas, x, y, showBoundary=showBoundary)
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderbase.py:201: in draw
self.drawNode(drawing)
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderPM.py:108: in drawNode
self.drawNodeDispatcher(node)
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderbase.py:282: in drawNodeDispatcher
self.drawGroup(node)
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderbase.py:311: in drawGroup
self.drawNode(node)
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderPM.py:108: in drawNode
self.drawNodeDispatcher(node)
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderbase.py:282: in drawNodeDispatcher
self.drawGroup(node)
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderbase.py:311: in drawGroup
self.drawNode(node)
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderPM.py:108: in drawNode
self.drawNodeDispatcher(node)
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderbase.py:282: in drawNodeDispatcher
self.drawGroup(node)
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderbase.py:311: in drawGroup
self.drawNode(node)
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderPM.py:108: in drawNode
self.drawNodeDispatcher(node)
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderbase.py:282: in drawNodeDispatcher
self.drawGroup(node)
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderbase.py:311: in drawGroup
self.drawNode(node)
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderPM.py:108: in drawNode
self.drawNodeDispatcher(node)
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderbase.py:282: in drawNodeDispatcher
self.drawGroup(node)
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderbase.py:311: in drawGroup
self.drawNode(node)
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderPM.py:108: in drawNode
self.drawNodeDispatcher(node)
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderbase.py:282: in drawNodeDispatcher
self.drawGroup(node)
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderbase.py:311: in drawGroup
self.drawNode(node)
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderPM.py:105: in drawNode
self.push(node)
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderPM.py:66: in push
self.applyState()
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderPM.py:92: in applyState
self._canvas.setFont(s['fontName'], s['fontSize'])
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderPM.py:399: in setFont
_setFont(self._gs,fontName,fontSize)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
gs = <gstate object at 0x1099c5850>, fontName = 'Arial', fontSize = 30.0
def _setFont(gs,fontName,fontSize):
try:
gs.setFont(fontName,fontSize)
except ValueError as e:
if not e.args[0].endswith("Can't find font!"): raise
#here's where we try to add a font to the canvas
try:
f = getFont(fontName)
_renderPM.makeT1Font(fontName,f.face.findT1File(),f.encoding.vector,open_and_read)
except:
s1, s2 = list(map(str,sys.exc_info()[:2]))
> raise RenderPMError("Can't setFont(%s) missing the T1 files?\nOriginally %s: %s" % (fontName,s1,s2))
E reportlab.graphics.renderPM.RenderPMError: Can't setFont(Arial) missing the T1 files?
E Originally <class 'AttributeError'>: 'TTEncoding' object has no attribute 'vector'
../../../../../bin/miniconda3/lib/python3.6/site-packages/reportlab/graphics/renderPM.py:251: RenderPMError
---------------------------------------------------- Captured stdout call -----------------------------------------------------
working on [0] /Volumes/SanDisk128/mobiledev/src/repos/github/deeplook/svglib/tests/samples/W3C_SVG_12_TinyTestSuite/svg/animate-elem-02-t.svg
---------------------------------------------------- Captured stderr call -----------------------------------------------------
Warn: Can't find .pfb for face 'b'ArialMT''
====================================== 1 failed, 1 skipped, 7 deselected in 1.67 seconds ======================================
My reportlab/fonts folder in this case (barely ever used) has this content, where nothing looks like Arial. On reportlab.com I have not found immediately some additional fonts to install. And I have likely never touched rl_config.py in this installation. @replabrobin any ideas?
Flatty:svglib dinu$ ll /Volumes/SanDisk128/mobiledev/bin/miniconda3/lib/python3.6/site-packages/reportlab/fonts/
total 3224
-rw-r--r-- 1 dinu staff 318 Jan 6 2018 00readme.txt
-rw-r--r-- 1 dinu staff 17976 Jan 6 2018 DarkGarden-copying-gpl.txt
-rw-r--r-- 1 dinu staff 1318 Jan 6 2018 DarkGarden-copying.txt
-rw-r--r-- 1 dinu staff 4122 Jan 6 2018 DarkGarden-readme.txt
-rw-r--r-- 1 dinu staff 519634 Jan 6 2018 DarkGarden.sfd
-rw-r--r-- 1 dinu staff 10351 Jan 6 2018 DarkGardenMK.afm
-rw-r--r-- 1 dinu staff 79824 Jan 6 2018 DarkGardenMK.pfb
-rw-r--r-- 1 dinu staff 65932 Jan 6 2018 Vera.ttf
-rw-r--r-- 1 dinu staff 63208 Jan 6 2018 VeraBI.ttf
-rw-r--r-- 1 dinu staff 58716 Jan 6 2018 VeraBd.ttf
-rw-r--r-- 1 dinu staff 63684 Jan 6 2018 VeraIt.ttf
-rw-r--r-- 1 dinu staff 32084 Jan 6 2018 _a______.pfb
-rw-r--r-- 1 dinu staff 31966 Jan 6 2018 _ab_____.pfb
-rw-r--r-- 1 dinu staff 32019 Jan 6 2018 _abi____.pfb
-rw-r--r-- 1 dinu staff 32115 Jan 6 2018 _ai_____.pfb
-rw-r--r-- 1 dinu staff 35377 Jan 6 2018 _eb_____.pfb
-rw-r--r-- 1 dinu staff 38543 Jan 6 2018 _ebi____.pfb
-rw-r--r-- 1 dinu staff 37518 Jan 6 2018 _ei_____.pfb
-rw-r--r-- 1 dinu staff 35380 Jan 6 2018 _er_____.pfb
-rw-r--r-- 1 dinu staff 5954 Jan 6 2018 bitstream-vera-license.txt
-rw-r--r-- 1 dinu staff 35500 Jan 6 2018 cob_____.pfb
-rw-r--r-- 1 dinu staff 50532 Jan 6 2018 cobo____.pfb
-rw-r--r-- 1 dinu staff 34585 Jan 6 2018 com_____.pfb
-rw-r--r-- 1 dinu staff 48468 Jan 6 2018 coo_____.pfb
-rw-r--r-- 1 dinu staff 34705 Jan 6 2018 sy______.pfb
-rw-r--r-- 1 dinu staff 49593 Jan 6 2018 zd______.pfb
-rw-r--r-- 1 dinu staff 75573 Jan 6 2018 zx______.pfb
-rw-r--r-- 1 dinu staff 96418 Jan 6 2018 zy______.pfb
The message indicates that the renderPM graphics state is being induced to use a font 'Arial' without that font being registered. I assume Arial is a reference to a font like MS has. Those are usually TTF and as we don't have a magic search by name for such fonts they must be registered using the normal registration mechanism.
On windows you can usually get 'arial' using
from reportlab.pdfbase.pdfmetrics import registerFont from reportlab.pdfbase.ttfonts import TTFont registerFont(TTFont('Arial','ARIAL.ttf'))
and it can then be passed to a canvas using setFont eg
from reportlab.graphics.renderPM import PMCanvas canv=PMCanvas(10,10) canv.setFont('Arial',10)
the main reason that we don't support searching arbitrarily for a font matching the given name is that it is quite hard. 'Arial' is a postscript name, obviously we don't want to support opening & parsing many ttf files to get at their postscript names (ditto for type1 etc etc).
The solution is to write a pluggable search mechanism that will map 'Arial' to the ttf file which can then be registered.
A long time ago I started on something like a caching lookup (reportlab/lib/fontfinder.py), but I have never implemented automatic font lookup psname --> font.
@replabrobin Isn't this something that fontconfig is intended to solve?
Theoretically yes, but only if you ask it the right questions; I am almost sure it can be made to work on windows and osx, but it's an extra large dependency for reportlab. Nothing prevents end users from using such a tool, but fontconfig itself is not easy to use.
Do I understand correctly that reportlab is the first tool I'm using that cannot pick up system fonts used by all other applications I ever used? I have never been forced to specify fonts by full file system path to be honest.
reportlab has a search path for fonts; font usage is a very grey area so far as licensing is concerned because font designers want payment. The default search path for ttf is
TTFSearchPath = ( 'c:/winnt/fonts', 'c:/windows/fonts', '/usr/lib/X11/fonts/TrueType/', '/usr/share/fonts/truetype', '/usr/share/fonts', #Linux, Fedora '/usr/share/fonts/dejavu', #Linux, Fedora '%(REPORTLAB_DIR)s/fonts', #special '%(REPORTLAB_DIR)s/../fonts', #special '%(REPORTLAB_DIR)s/../../fonts',#special '%(CWD)s/fonts', #special '~/fonts', '~/.fonts', '%(XDG_DATA_HOME)s/fonts', '~/.local/share/fonts', #mac os X - from #http://developer.apple.com/technotes/tn/tn2024.html '~/Library/Fonts', '/Library/Fonts', '/Network/Library/Fonts', '/System/Library/Fonts', ) but please note that you will likely have to use the ttf filename to register a font so the internal names are likely not of use.
There are several ways to override these settings.