utils.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. __all__ = (
  2. 'setFont',
  3. 'pathNumTrunc',
  4. 'processGlyph',
  5. 'text2PathDescription',
  6. 'text2Path',
  7. 'RenderPMError',
  8. )
  9. from . _renderPM import makeT1Font
  10. from reportlab.pdfbase.pdfmetrics import getFont, unicode2T1
  11. from reportlab.lib.utils import open_and_read, isBytes, rl_exec
  12. from .shapes import _baseGFontName, _PATH_OP_ARG_COUNT, _PATH_OP_NAMES, definePath
  13. from sys import exc_info
  14. class RenderPMError(Exception):
  15. pass
  16. def _errorDump(fontName, fontSize):
  17. s1, s2 = list(map(str,exc_info()[:2]))
  18. from reportlab import rl_config
  19. if rl_config.verbose>=2:
  20. import os
  21. _ = os.path.join(os.path.dirname(rl_config.__file__),'fonts')
  22. print('!!!!! %s: %s' % (_,os.listdir(_)))
  23. for _ in ('T1SearchPath','TTFSearchPath'):
  24. print('!!!!! rl_config.%s = %s' % (_,repr(getattr(rl_config,_))))
  25. code = 'raise RenderPMError("Error in setFont(%s,%s) missing the T1 files?\\nOriginally %s: %s")' % (repr(fontName),repr(fontSize),s1,s2)
  26. code += ' from None'
  27. rl_exec(code,dict(RenderPMError=RenderPMError))
  28. def setFont(gs,fontName,fontSize):
  29. try:
  30. gs.setFont(fontName,fontSize)
  31. except ValueError as e:
  32. if not e.args[0].endswith("Can't find font!"):
  33. _errorDump(fontName,fontSize)
  34. #here's where we try to add a font to the canvas
  35. try:
  36. f = getFont(fontName)
  37. makeT1Font(fontName,f.face.findT1File(),f.encoding.vector,open_and_read)
  38. except:
  39. _errorDump(fontName,fontSize)
  40. gs.setFont(fontName,fontSize)
  41. def pathNumTrunc(n):
  42. if int(n)==n: return int(n)
  43. return round(n,5)
  44. def processGlyph(G, truncate=1, pathReverse=0):
  45. O = []
  46. P = []
  47. R_append = [].append
  48. if G and len(G)==1 and G[0][0]=='lineTo':
  49. G = (('moveToClosed',)+G[0][1:],)+G #hack fix for some errors
  50. for g in (G or ())+(('end',),):
  51. op = g[0]
  52. if O and op in ['moveTo', 'moveToClosed','end']:
  53. if O[0]=='moveToClosed':
  54. del O[0]
  55. if pathReverse:
  56. P[1::2],P[0::2] = P[0::2],P[1::2] #exchange x and y
  57. P.reverse()
  58. O.reverse()
  59. O.insert(0,'moveTo')
  60. O.append('closePath')
  61. i = 0
  62. if truncate: P = list(map(pathNumTrunc,P))
  63. for o in O:
  64. j = i + _PATH_OP_ARG_COUNT[_PATH_OP_NAMES.index(o)]
  65. R_append((o,)+ tuple(P[i:j]))
  66. i = j
  67. O = []
  68. P = []
  69. O.append(op)
  70. P.extend(g[1:])
  71. return R_append.__self__
  72. def text2PathDescription(text, x=0, y=0, fontName=_baseGFontName, fontSize=1000,
  73. anchor='start', truncate=1, pathReverse=0, gs=None):
  74. font = getFont(fontName)
  75. if font._multiByte and not font._dynamicFont:
  76. raise ValueError("text2PathDescription doesn't support multi byte fonts like %r" % fontName)
  77. P_extend = [].extend
  78. if not anchor=='start':
  79. textLen = stringWidth(text, fontName, fontSize)
  80. if anchor=='end':
  81. x = x-textLen
  82. elif anchor=='middle':
  83. x = x - textLen/2.
  84. if gs is None:
  85. from ._renderPM import gstate
  86. gs = gstate(1,1)
  87. setFont(gs,fontName,fontSize)
  88. if font._dynamicFont:
  89. for g in gs._stringPath(text,x,y):
  90. P_extend(processGlyph(g,truncate=truncate,pathReverse=pathReverse))
  91. else:
  92. if isBytes(text):
  93. try:
  94. text = text.decode('utf8')
  95. except UnicodeDecodeError as e:
  96. i,j = e.args[2:4]
  97. raise UnicodeDecodeError(*(e.args[:4]+('%s\n%s-->%s<--%s' % (e.args[4],text[max(i-10,0):i],text[i:j],text[j:j+10]),)))
  98. fc = font
  99. FT = unicode2T1(text,[font]+font.substitutionFonts)
  100. nm1 = len(FT)-1
  101. for i, (f, t) in enumerate(FT):
  102. if f!=fc:
  103. setFont(gs,f.fontName,fontSize)
  104. fc = f
  105. for g in gs._stringPath(t,x,y):
  106. P_extend(processGlyph(g,truncate=truncate,pathReverse=pathReverse))
  107. if i!=nm1:
  108. x += f.stringWidth(t.decode(f.encName), fontSize)
  109. return P_extend.__self__
  110. def text2Path(text, x=0, y=0, fontName=_baseGFontName, fontSize=1000,
  111. anchor='start', truncate=1, pathReverse=0, gs=None, **kwds):
  112. return definePath(text2PathDescription(text,x=x,y=y,fontName=fontName,
  113. fontSize=fontSize,anchor=anchor,truncate=truncate,pathReverse=pathReverse, gs=gs),**kwds)