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

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

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

import numpy as np
import matplotlib.pyplot as plt
from pdfrw import PdfReader
from pdfrw.buildxobj import pagexobj
from pdfrw.toreportlab import makerl
from reportlab.lib.pagesizes import A4
from reportlab.pdfgen import canvas

fig = plt.figure(figsize=(5,5))
plt.imshow(np.random.rand(10,10))
plt.savefig('Imshow.pdf')

MyReport = canvas.Canvas('foo.pdf', pagesize=A4)
pages = PdfReader('Imshow.pdf').pages
page = pagexobj(pages[0])
MyReport.saveState()
MyReport.doForm(makerl(MyReport, page))
MyReport.restoreState()
MyReport.save()

字符串
错误内容为

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标记!):

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

字符串
新增:

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


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

nhaq1z21

nhaq1z212#

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

# --------- Original Code --------------------
# assert isinstance(pdfobj, (float, int, str)), repr(pdfobj)
# # TODO: Add fix for float like in pdfwriter
# return str(getattr(pdfobj, 'encoded', None) or pdfobj)

# --------- New Code --------------------
assert isinstance(pdfobj, (float, int, str)), repr(pdfobj)
# TODO: Add fix for float like in pdfwriter
value = str(getattr(pdfobj, 'encoded', None) or pdfobj)
try:
    value.encode("ascii")  # Don't return this, it is just a test.
except UnicodeEncodeError:
    value = value.encode("Latin-1")
return value

字符串

相关问题