2016-02-03 30 views
17

TL; DR: C'è un modo per dire a ReportLab di utilizzare un carattere specifico e il fallback a un altro se mancano glifi per alcuni caratteri? In alternativa, Conoscete un font TrueType condensato che contiene i glifi per tutte le lingue europee, ebraico, russo, cinese, giapponese e arabo?ReportLab: funziona con caratteri cinesi/Unicode

Ho creato report con ReportLab e ho riscontrato problemi con il rendering di stringhe contenenti caratteri cinesi. Il font che ho utilizzato è DejaVu Sans Condensed, che non contiene i glifi per il cinese (tuttavia, contiene cirillico, ebraico, arabo e tutti i tipi di Umlauts per il supporto linguistico europeo - il che lo rende piuttosto versatile e di cui ho bisogno di tanto in tanto)

Cinese, tuttavia, non è supportato dal tipo di carattere e non sono stato in grado di trovare un carattere TrueType che supporti TUTTE le lingue e soddisfi i nostri requisiti di progettazione grafica. Come soluzione temporanea, ho fatto in modo che i report per i clienti cinesi usassero un font completamente diverso, contenente solo glifi in inglese e cinese, sperando che i caratteri in altre lingue non fossero presenti nelle stringhe. Tuttavia questo è, per ovvi motivi, goffo e rompe il disegno grafico, dal momento che non è DejaVu Sans, attorno al quale è stato progettato l'intero look & feel.

Quindi la domanda è, come gestire la necessità di supportare più lingue in un documento e mantenere l'utilizzo di un carattere specificato per ciascuna lingua. Ciò è reso più complicato dal fatto che a volte le stringhe contengono un mix di lingue, quindi determinare quale font ONE dovrebbe essere usato per ogni stringa non è un'opzione.

C'è un modo per dire a ReportLab di utilizzare un carattere specifico e il fallback a un altro se mancano glifi per alcuni caratteri? Ho trovato vaghi accenni nei documenti che dovrebbe essere possibile, anche se potrei capirlo in modo errato.

In alternativa, conosci un font TrueType condensato che contiene i glifi per tutte le lingue europee, ebraico, russo, cinese, giapponese e arabo?

Grazie.

+0

Non so una risposta completa, ma credo che l'utilizzo di font unicode [link] https://en.wikipedia.org/wiki/Unicode_font dovrebbe aiutarti a mostrare i caratteri in molte lingue – bmbigbang

risposta

3

Questa domanda mi ha affascinato per tutta la settimana, quindi dal momento che è il fine settimana mi sono tuffato e ho trovato esattamente una soluzione che ho chiamato MultiFontParagraph è un normale Paragraph con una grande differenza è possibile impostare esattamente un ordine di fallback dei font.

Example of the font fallback working

Per esempio, questo testo giapponese a caso ho tirato di internet utilizzato il seguente tipo di carattere di ripiego "Bauhaus", "Arial", "HanaMinA". Controlla se il primo carattere ha un glifo per il personaggio, in tal caso lo usa, se non lo riporta al carattere successivo. Attualmente il codice non è molto efficiente poiché posiziona i tag attorno a ciascun personaggio, questo può essere facilmente risolto ma per chiarezza non l'ho fatto qui.

utilizzando il seguente codice ho creato l'esempio precedente:

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')]) 

La fonte del MultiFontParagraph(git) è la seguente:

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

Non l'ho ancora testato , ma sembra che funzionerebbe. Il fatto è che, sebbene questa soluzione sia corretta, era esattamente la soluzione che stavo cercando di evitare :) Poiché non c'è altro modo che scorrere tutti i caratteri per ogni carattere nel testo, e alcuni dei report sono centinaia di pagine, questo potrebbe causare un notevole calo delle prestazioni. Inoltre, 'Paragraph()' non è l'unico elemento problematico. In alcuni casi disegno anche il testo direttamente su una tela (non usando il costrutto Flowable), sebbene questa soluzione possa essere replicata lì. Comunque, grazie per la risposta e complimenti per la soluzione. – ztorage

+2

Oh, a proposito, ho finito per fondere i vari tipi di carattere di cui ho bisogno in un file TTF. Ciò rende il tutto perfettamente funzionante. – ztorage

+0

L'unione dei caratteri è sempre la soluzione più semplice a mio avviso. Ma con questa soluzione la complessità non è così alta nel peggiore dei casi è O (N * F * 1) dove N sono il numero di caratteri e F il numero di caratteri specificati e il 1 per il dizionario cerca ma se il i tipi di carattere corretti sono scelti, sarà sufficiente controllare 2 o 3 tipi di carattere per trovare un carattere che sia in grado di fornire il carattere necessario. – B8vrede

1

Da Google Noto Fonts:

Google è stato lo sviluppo di una famiglia di font chiamata Noto, che mira a supportare tutte le lingue wi un aspetto armonioso.

Il unified Noto Sans font include un singolo carattere, che supporta 581 lingue dalle seguenti aree:

enter image description here

Altri, come l'ebraico, l'arabo e giapponese sono elencati come elementi separati sul sito web di Noto.