UnicodeEncodeError: 'latin-1' codec can't encode character '\u2013' (writing to PDF)

UnicodeEncodeError: 'latin-1' codec can't encode character '\u2013' (writing to PDF)

我在使用 python 写入 .pdf 时遇到了 Unicode 的问题,其中包含可变内容。

它正在输出这个错误:

UnicodeEncodeError: 'latin-1' codec can't encode character '\u2013'

它基本上是被 em dash 抓住了。

我尝试使用那个变量,其中内容有一个 'em dash' 并用一个 '.encode('utf-8')' 重新定义它,例如,如下:

Body = msg.Body

BodyC = Body.encode('utf-8')

现在我得到 以下错误:

Traceback (most recent call last):
  File "script.py", line 37, in <module>
    pdf.cell(200, 10, txt="Bod: " + BodyC,  ln=4, align="C")
TypeError: can only concatenate str (not "bytes") to str

下面是我的完整代码,我怎样才能简单地修复“Body”变量内容中的 Unicode 错误。

正在转换为 utf-8western,“latin-1”之外的任何内容。有什么建议吗?

完整代码:

from fpdf import FPDF
import win32com.client

outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
msg = outlook.OpenSharedItem(r"C:\User\language\python\Msg-To-PDF\test_msg.msg")

print (msg.SenderName)
print (msg.SenderEmailAddress)
print (msg.SentOn)
print (msg.To)
print (msg.CC)
print (msg.BCC)
print (msg.Subject)
print (msg.Body)

SenderName = msg.SenderName
SenderEmailAddress = msg.SenderEmailAddress
SentOn = msg.SentOn
To = msg.To
CC = msg.CC
BCC = msg.BCC
Subject = msg.Subject
Body = msg.Body
BodyC = Body.encode('utf-8')

pdf = FPDF()
pdf.add_page()

# pdf.add_font('DejaVu', '', 'DejaVuSansCondensed.ttf', uni=True)
pdf.set_font("Helvetica", style = '', size = 11)
pdf.cell(200, 10, txt="From: " + SenderName, ln=1, align="C")
# pdf.cell(200, 10, border=SentOn, ln=1, align="C")
pdf.cell(200, 10, txt="To: " + To, ln=1, align="C")
pdf.cell(200, 10, txt="CC: " + CC, ln=1, align="C")
pdf.cell(200, 10, txt="BCC: " + BCC, ln=1, align="C")
pdf.cell(200, 10, txt="Subject: " + Subject, ln=1, align="C")
pdf.cell(200, 10, txt="Bod: " + BodyC,  ln=4, align="C")

pdf.output("Sample.pdf")


解决方法是在将所有文本传递到库之前将其转换为 latin-1 编码。您可以使用以下命令执行此操作:

text2 = text.encode('latin-1', 'replace').decode('latin-1')

text2 将没有任何 non-latin-1 个字符。但是,某些字符可能会替换为 ?

此错误的原因是您试图在 PDF 中呈现超出 latin-1 编码代码范围的字符。 FPDF 使用 latin-1 作为其所有内置字体的默认编码。

因此,作为解决方法,您可以从文本中删除所有不适合 latin-1 编码的字符。 (有关此解决方法,请参阅我的其他答案)。

要修复此错误并能够在 PDF 中呈现这些字符,您需要使用支持更广泛字符的字体。为了解决这个问题,FPDF 库支持 Unicode 字体。

例如,您可以获得免费的 Google Noto fonts,它支持广泛的 Unicode 端点。对于大多数西方语言,我会推荐 NotoSans 字体集。但您也可以获得许多其他语言和文字的字体,包括中文、希伯来语或阿拉伯语。

以下是在 FPDF 代码中启用 Unicode 字体的方法:

首先你需要告诉 FPDF 库在哪里可以找到字体文件。在此示例中,我将其设置为当前文件夹的子文件夹 fonts

import fpdf
fpdf.set_global("SYSTEM_TTFONTS", os.path.join(os.path.dirname(__file__),'fonts'))

然后您需要将字体添加到您的 PDF 文档中。在此示例中,我为普通、粗体、斜体和粗斜体样式添加了 NotoSans 字体:

pdf = fpdf.FPDF()
pdf.add_font("NotoSans", style="", fname="NotoSans-Regular.ttf", uni=True)
pdf.add_font("NotoSans", style="B", fname="NotoSans-Bold.ttf", uni=True)
pdf.add_font("NotoSans", style="I", fname="NotoSans-Italic.ttf", uni=True)
pdf.add_font("NotoSans", style="BI", fname="NotoSans-BoldItalic.ttf", uni=True)

现在您可以通过 set_font() 在您的 PDF 文档中正常使用新字体。以下是普通文本的示例:

pdf.set_font("NotoSans", size=12)

您还可以通过 .set_doc_option() 方法(文档 here)更改编码。我尝试了 Erik 的方法,它对我有用,但是在添加了一些更复杂的东西(例如第二个 PDF 并使用需要创建新的 class 的 write_html() 方法)之后,我又回到了有同样的错误。更改整个文档的编码应该可以解决您所说的整体问题。

readthedocs 页面说您只能使用 latin-1 或 windows-1252,但根据调试器,pdf.set_doc_option('core_fonts_encoding', 'utf-8') 对我有效。请注意,有些字符需要修复,例如在 PDF 中显示为 [TM] 的撇号 (')。

希望这是您正在寻找的此问题的全局修复程序,即使晚了几个月!

我正在尝试对 Erik 的解决方案进行一些更改,它非常适合混合使用英语和阿拉伯语文本。下面发布了使用 pyFPDF 生成 PDF 的示例代码。

from datetime import datetime
def getFileName():
    now=datetime.now()
    time = now.strftime('%d_%H_%M_%S')
    filename = "Test_"+time + ".pdf"
    return filename


from fpdf import FPDF

pdf = FPDF()

#Download NotoSansArabic-Regular.ttf from Google noto fonts
pdf.add_font("NotoSansArabic", style="", fname="./fonts/NotoSansArabic-Regular.ttf", uni=True)


pdf.add_page()

pdf.set_font('Arial', '', 12)
pdf.write(8, 'Hello World')
pdf.ln(8)

# مرحبا Marhaba in arabic 
pdf.set_font('NotoSansArabic', '', 12)
text = 'مرحبا'
pdf.write(8, text)
pdf.ln(8)

pdf.output(getFileName(), 'F')