Python ReportLab:使用中文/Unicode字符

Python ReportLab:使用中文/Unicode字符,python,unicode,fonts,reportlab,chinese-locale,Python,Unicode,Fonts,Reportlab,Chinese Locale,TL;博士: 有没有办法告诉ReportLab使用特定的字体,如果缺少某些字符的标志符号,可以使用另一种字体?或者,你知道一种浓缩的TrueType字体,它包含所有欧洲语言的字形,希伯来语、俄语、汉语、日语和阿拉伯语 我一直在使用ReportLab创建报告,在呈现包含汉字的字符串时遇到问题。我一直使用的字体是DejaVu Sans Condensed,它不包含中文的字形(但是,它确实包含西里尔文、希伯来文、阿拉伯文和各种欧洲语言支持的Umlauts,这使得它非常通用,我不时需要它们) 然而,中文

TL;博士: 有没有办法告诉ReportLab使用特定的字体,如果缺少某些字符的标志符号,可以使用另一种字体?或者,你知道一种浓缩的TrueType字体,它包含所有欧洲语言的字形,希伯来语、俄语、汉语、日语和阿拉伯语

我一直在使用ReportLab创建报告,在呈现包含汉字的字符串时遇到问题。我一直使用的字体是DejaVu Sans Condensed,它不包含中文的字形(但是,它确实包含西里尔文、希伯来文、阿拉伯文和各种欧洲语言支持的Umlauts,这使得它非常通用,我不时需要它们)

然而,中文是不支持的字体,我还没有找到一个TrueType字体支持所有的语言,并满足我们的图形设计要求。作为一种临时解决办法,我这样做是为了让中国客户的报告使用完全不同的字体,只包含英文和中文字形,希望字符串中不会出现其他语言的字符。然而,由于明显的原因,这是笨重的,打破了图形设计,因为它不是DejaVu Sans,整个外观和感觉都是围绕它设计的

因此,问题是,您将如何处理在一个文档中支持多种语言的需求,并为每种语言保持指定字体的使用。由于有时字符串包含多种语言的混合,这就变得更加复杂,因此确定每个字符串应使用哪种字体不是一个选项

有没有办法告诉ReportLab使用特定的字体,如果缺少某些字符的标志符号,可以使用另一种字体?我在文档中发现了一些模糊的提示,认为这是可能的,尽管我可能理解不正确

或者,你知道一种浓缩的TrueType字体,它包含所有欧洲语言的字形,希伯来语、俄语、汉语、日语和阿拉伯语


谢谢。

这个问题吸引了我整整一周的时间,所以因为是周末,我就深入其中,准确地找到了一个解决方案,我称之为
多字体段落
这是一个正常的
段落
,有一个很大的区别,你可以准确地设置字体回退顺序

例如,我从互联网上随机抽取的这篇日语文本使用了以下字体fallback
“Bauhaus”、“Arial”、“HanaMinA”
。它检查第一种字体是否有字符的标志符号,如果有,则使用它,如果没有,则返回到下一种字体。目前,代码不是很有效,因为它在每个字符周围放置了标记,这很容易修复,但为了清楚起见,我没有在这里这样做

我使用以下代码创建了上述示例:

foreign_string = u'6905\u897f\u963f\u79d1\u8857\uff0c\u5927\u53a6\uff03\u5927'
P = MultiFontParagraph(foreign_string, styles["Normal"],
                     [  ("Bauhaus", "C:\Windows\Fonts\\BAUHS93.TTF"),
                        ("Arial", "C:\Windows\Fonts\\arial.ttf"),
                        ("HanaMinA", 'C:\Windows\Fonts\HanaMinA.ttf')])
多字体段落的来源如下:

from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.platypus import Paragraph


class MultiFontParagraph(Paragraph):
    # Created by B8Vrede for http://stackoverflow.com/questions/35172207/
    def __init__(self, text, style, fonts_locations):

        font_list = []
        for font_name, font_location in fonts_locations:
            # Load the font
            font = TTFont(font_name, font_location)

            # Get the char width of all known symbols
            font_widths = font.face.charWidths

            # Register the font to able it use
            pdfmetrics.registerFont(font)

            # Store the font and info in a list for lookup
            font_list.append((font_name, font_widths))

        # Set up the string to hold the new text
        new_text = u''

        # Loop through the string
        for char in text:

            # Loop through the fonts
            for font_name, font_widths in font_list:

                # Check whether this font know the width of the character
                # If so it has a Glyph for it so use it
                if ord(char) in font_widths:

                    # Set the working font for the current character
                    new_text += u'<font name="{}">{}</font>'.format(font_name, char)
                    break

        Paragraph.__init__(self, new_text, style)
从reportlab.pdfbase导入pdfmetrics
从reportlab.pdfbase.TTFont导入TTFont
从reportlab.platypus导入段落
类别多字体段落(段落):
#由B8Vrede为创建http://stackoverflow.com/questions/35172207/
定义初始化(自身、文本、样式、字体位置):
字体列表=[]
对于字体名称,字体位置中的字体位置:
#加载字体
font=TTFont(字体名称、字体位置)
#获取所有已知符号的字符宽度
font\u widths=font.face.charWidths
#注册字体以使其能够使用
pdfmetrics.registerFont(字体)
#将字体和信息存储在列表中以便查找
字体列表。追加((字体名称、字体宽度))
#设置字符串以保存新文本
新文本=u''
#在字符串中循环
对于文本中的字符:
#循环浏览字体
对于字体名称,字体列表中的字体宽度:
#检查此字体是否知道字符的宽度
#如果是这样,它有一个字形,所以使用它
如果字体宽度为ord(字符):
#设置当前字符的工作字体
新文本+=u'{}.格式(字体名称,字符)
打破
段落.uuu初始(自我、新文本、样式)
来自:

谷歌一直在开发一个名为Noto的字体系列,该系列旨在以和谐的外观支持所有语言

包含单一字体,支持以下领域的581种语言:


Noto网站上还分别列出了希伯来语、阿拉伯语和日语等其他文字。

我不知道完整的asnwer,但我相信使用任何unicode字体[link]都可以帮助您以多种语言显示字符。我还没有测试过它,但它似乎可以工作。问题是,虽然这个解决方案是正确的,但它正是我试图避免的解决方案:)因为除了迭代文本中每个字符的所有字体之外,没有其他方法,而且有些报告有数百页长,这可能会导致性能下降。另外,
段落()
不是唯一有问题的元素。在某些情况下,我还直接在画布上绘制文本(不使用Flowable结构),尽管这个解决方案可以在画布上复制。无论如何,谢谢你对这个解决方案的回应和赞誉。哦,顺便说一句,我最终将我需要的不同字体合并到一个TTF文件中。这使得整个工作无缝进行。我认为合并字体总是最简单的解决方案。但是这个解决方案的复杂度并没有那么高,在最坏的情况下是O(N*F*1),其中N是字符数,F是指定的字体数,1用于字典查找,但是如果选择了正确的字体,则只需检查2或3种字体,就可以找到能够提供所需字符的字体。