python3中的Reportlab和pdfrw与matplotlib imshow()错误

hk8txs48  于 2023-08-06  发布在  Python
关注(0)|答案(2)|浏览(126)

我最近更新了一些在python2到python3中运行的代码,在使用reportlab与pdfrw和matplotlib imshow()时遇到了一个错误。
有人能在py3中重现这个错误吗?我也不确定这是一个reportlab问题还是一个pdfrw问题。

  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. from pdfrw import PdfReader
  4. from pdfrw.buildxobj import pagexobj
  5. from pdfrw.toreportlab import makerl
  6. from reportlab.lib.pagesizes import A4
  7. from reportlab.pdfgen import canvas
  8. fig = plt.figure(figsize=(5,5))
  9. plt.imshow(np.random.rand(10,10))
  10. plt.savefig('Imshow.pdf')
  11. MyReport = canvas.Canvas('foo.pdf', pagesize=A4)
  12. pages = PdfReader('Imshow.pdf').pages
  13. page = pagexobj(pages[0])
  14. MyReport.saveState()
  15. MyReport.doForm(makerl(MyReport, page))
  16. MyReport.restoreState()
  17. MyReport.save()

字符串
错误内容为

  1. UnicodeEncodeError: 'charmap' codec can't encode character '\x1f' in position 6: character maps to <undefined>


系统:Windows 10,Python 3.9,pdfrw 0.4,reportlab 3.6.8,

bmvo0sr5

bmvo0sr51#

问题在于pdfrw处理字符串和字节的方式。
pdfrw.PdfReader使用Latin-1编码加载整个源PDF。所有256个可能的字节值在Latin-1中都是有意义的,因此matplotlib图像中的所有二进制数据都被加载。但这会创建垃圾unicode,reportlab在重新编码时遇到问题(因为它不使用Latin-1)。
解决方案是找到真正应该是二进制的数据,并将其作为正确编码的bytes而不是str传递给reportlab。你需要破解pdfrw/toreportlab.py的第108行的函数_makestr
旧的原始代码(包括TODO标记!):

  1. def _makestr(rldoc, pdfobj):
  2. assert isinstance(pdfobj, (float, int, str)), repr(pdfobj)
  3. # TODO: Add fix for float like in pdfwriter
  4. return str(getattr(pdfobj, 'encoded', None) or pdfobj)

字符串
新增:

  1. def _makestr(rldoc, pdfobj):
  2. assert isinstance(pdfobj, (float, int, str)), repr(pdfobj)
  3. # TODO: Add fix for float like in pdfwriter
  4. value = str(getattr(pdfobj, 'encoded', None) or pdfobj)
  5. try:
  6. value.encode("ascii") # Don't return this, it is just a test.
  7. except UnicodeEncodeError:
  8. value = value.encode("Latin-1")
  9. return value


任何不能表示为ASCII的内容都使用原始的Latin-1编码进行编码,并作为bytes发送到reportlab。
根据我的测试,这似乎不会影响图中的非ASCII字符串(例如轴标签)。我猜他们通过pdfrw代码走了不同的路-但我不知道!
pdfrw作为一个项目似乎已经死亡,自2017年以来没有发布。如果任何人看到了这一点,并知道如何贡献一个补丁的项目,请随时(或让我知道)。

展开查看全部
nhaq1z21

nhaq1z212#

Aron Lockey谢谢。It works!!
def _makestr(rldoc,pdfobj):

  1. # --------- Original Code --------------------
  2. # assert isinstance(pdfobj, (float, int, str)), repr(pdfobj)
  3. # # TODO: Add fix for float like in pdfwriter
  4. # return str(getattr(pdfobj, 'encoded', None) or pdfobj)
  5. # --------- New Code --------------------
  6. assert isinstance(pdfobj, (float, int, str)), repr(pdfobj)
  7. # TODO: Add fix for float like in pdfwriter
  8. value = str(getattr(pdfobj, 'encoded', None) or pdfobj)
  9. try:
  10. value.encode("ascii") # Don't return this, it is just a test.
  11. except UnicodeEncodeError:
  12. value = value.encode("Latin-1")
  13. return value

字符串

展开查看全部

相关问题