Search code examples
pythonsvgunicodegraphicstruetype

font.getGlyphID gives KeyError on unicode


I'm trying to render SVG out of an unicode using Python's fonttools:

from fontTools.ttLib import TTFont
from fontTools.pens.svgPathPen import SVGPathPen

def unicode_to_svg(unicode_char, font_path, output_svg_path):
    # Load the TTF font using fonttools
    font = TTFont(font_path)

    # Get the glyph index for the Unicode character
    glyph_index = font.getGlyphID(unicode_char)

    # Convert the glyph to an SVG path
    glyph_set = font.getGlyphSet()
    glyph_name = font.getGlyphName(glyph_index)
    glyph = glyph_set[glyph_name]
    
    pen = SVGPathPen(glyph_set)
    glyph.draw(pen)
    svg_path_data = pen.getCommands()

    # Create the SVG content
    svg_content = f'''
    <svg width="3000" height="3000" xmlns="http://www.w3.org/2000/svg">
        <path d="{svg_path_data}" fill="red" />
    </svg>
    '''
    
    # Save the SVG content to a file
    with open(output_svg_path, 'w') as f:
        f.write(svg_content)

# Example usage
font_path = './Nikosh.ttf'
# unicode_char = 'A'
unicode_char = 'ম'
output_svg_path = 'output.svg'
unicode_to_svg(unicode_char, font_path, output_svg_path)

But the issue is, it works fine for English alphabets. But when I try to render unicode (such as Bengali) it gives me:

KeyError: 'ম'

On this line: glyph_index = font.getGlyphID(unicode_char)

I simply wanted to take a deeper dive into SVG rendering of different languages, fonts, texts, etc.

How can I resolve this issue? And make it SVG render-able for any unicode character?


Solution

  • help(font.getGlyphID)
    

    Help on method getGlyphID in module fontTools.ttLib.ttFont:

    getGlyphID(glyphName) method of fontTools.ttLib.ttFont.TTFont instance.
    Returns the ID of the glyph with the given name.

    The function char_in_font comes from my another project, included here unmodified… Check its output before passing to getGlyphID.

    from fontTools.ttLib import TTFont
    from fontTools.pens.svgPathPen import SVGPathPen
    
    def char_in_font(unicode_char, font):
        '''check if a char is in font, return its glyphName'''
        for cmap in font['cmap'].tables:
            if cmap.isUnicode() or cmap.getEncoding() == 'utf_16_be':
                if ord(unicode_char) in cmap.cmap:
                    # print(type(cmap))
                    auxcn = cmap.cmap[ord(unicode_char)]
                    # print(auxcn, type(auxcn))
                    return auxcn if auxcn != '' else '<nil>'
        return ''
    
    
    def unicode_to_svg(unicode_char, font_path, output_svg_path):
        # Load the TTF font using fonttools
        font = TTFont(font_path)
    
        # Get the glyph index for the Unicode character
        glyph_index = font.getGlyphID(char_in_font(unicode_char, font))
    
        # Convert the glyph to an SVG path
        glyph_set = font.getGlyphSet()
        glyph_name = font.getGlyphName(glyph_index)
        glyph = glyph_set[glyph_name]
        
        pen = SVGPathPen(glyph_set)
        glyph.draw(pen)
        svg_path_data = pen.getCommands()
    
        # Create the SVG content
        svg_content = f'''
        <svg width="3000" height="3000" xmlns="http://www.w3.org/2000/svg">
            <path d="{svg_path_data}" fill="red" />
        </svg>
        '''
        
        # Save the SVG content to a file
        with open(output_svg_path, 'w') as f:
            f.write(svg_content)
    
    
    # Example usage
    font_path = r'D:\Downloads\Fonty\Nikosh\Nikosh.ttf'
    # unicode_char = 'A'
    unicode_char = 'ম'
    output_svg_path = f'output{unicode_char}.svg'
    unicode_to_svg(unicode_char, font_path, output_svg_path)
    

    Output:

    .\SO\77072040.py
    start ""  outputম.svg
    

    enter image description here

    dir output*.svg
    
    09/09/2023  15:55               247 outputA.svg
    09/09/2023  16:18               751 outputম.svg
    
    start "" outputA.svg
    

    enter image description here