2016-02-03 4 views
17

TL; DR: Есть ли способ сообщить ReportLab использовать определенный шрифт и отступить к другому, если отсутствуют символы глифов для некоторых символов? Альтернативно, Знаете ли вы о конденсированном шрифте TrueType, который содержит глифы для всех европейских языков, иврит, русский, китайский, японский и арабский?ReportLab: работа с символами китайского/юникода

Я создавал отчеты с ReportLab и сталкивался с проблемами с строками рендеринга, содержащими китайские символы. Шрифт, который я использовал, - DejaVu Sans Condensed, который не содержит глифов для китайцев (однако он содержит кириллицу, иврит, арабский язык и всевозможные Umlauts для поддержки европейского языка, что делает его довольно универсальным, и мне нужно их все время от времени)

Китайский язык, однако, не поддерживается шрифтом, и я не смог найти шрифт TrueType, который поддерживает ВСЕ языки, и соответствует нашим требованиям графического дизайна. В качестве временного решения я сделал так, чтобы в отчетах для китайских клиентов использовался совершенно другой шрифт, содержащий только английские и китайские глифы, надеясь, что символы на других языках не будут присутствовать в строках. Однако по понятным причинам это неудобно и ломает графический дизайн, так как это не DejaVu Sans, вокруг которого было спроектировано все изображение &.

Итак, вопрос, как вы будете иметь дело с необходимостью поддерживать несколько языков в одном документе и поддерживать использование определенного шрифта для каждого языка. Это усложняется из-за того, что иногда строки содержат сочетание языков, поэтому определение того, какой шрифт ONE следует использовать для каждой строки, не является вариантом.

Есть ли способ сообщить ReportLab использовать конкретный шрифт и отступить к другому, если отсутствуют символы глифов для некоторых символов? Я нашел неопределенные намеки в документах, что это должно быть возможно, хотя я могу понять это неправильно.

Альтернативно, знаете ли вы о конденсированном шрифте TrueType, который содержит глифы для всех европейских языков, иврит, русский, китайский, японский и арабский?

Спасибо.

+0

Я не знаю полного анфаса, но я верю, используя любые шрифты из юникода [link] https://en.wikipedia.org/wiki/Unicode_font должен помочь вам показать символы на многих языках – bmbigbang

ответ

3

Этот вопрос завораживал меня всей неделей, так что на выходных я нырнул прямо в него и точно нашел решение, которое я назвал MultiFontParagraph, это нормальный Paragraph с одной большой разницей, вы можете точно установить резервный запас шрифта.

Example of the font fallback working

Например, это случайный текст на японском языке я вытащил из Интернета использовал следующий шрифт запасной вариант "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')]) 

Источник MultiFontParagraph(git) выглядит следующим образом:

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) 
+1

Я еще не тестировал его , но, похоже, это сработает. Дело в том, что, хотя это решение является правильным, именно это решение я пытался избежать :) Поскольку нет никакого способа, кроме повторения всех шрифтов для каждого символа в тексте, а некоторые из отчетов - сотни страниц, это может привести к довольно быстрому результату. Плюс, 'Параграф()' не является единственным проблемным элементом. Я также рисую текст непосредственно на холсте в некоторых случаях (не используя конструкцию Flowable), хотя это решение можно реплицировать там. Во всяком случае, спасибо за ответ и высокую оценку решения. – ztorage

+2

О, кстати, я закончил тем, что объединил разные шрифты, которые мне нужны, в один файл TTF. Это делает все, чтобы работать без проблем. – ztorage

+0

Слияние шрифтов всегда самое легкое решение, я думаю. Но с этим решением сложность не такая высокая, в худшем случае это O (N * F * 1), где N - количество символов, а F - количество указанных шрифтов, а 1 для словаря - вверх, но если правильные шрифты выбраны, он должен будет проверить только 2 или 3 шрифта, чтобы найти шрифт, который может предоставить необходимый символ. – B8vrede

1

От Google Noto Fonts:

Google было разработка семейства шрифтов под названием Noto, целью которого является поддержка всего языка с гармоничным внешним видом.

unified Noto Sans font включает в себя один шрифт, поддерживающий 581 языков из следующих областей:

enter image description here

Другие, такие как иврит, арабский и японский перечислены как отдельные элементы на веб-сайте Ното.

Смежные вопросы