Python Imaging Library - Text rendering

前端 未结 6 915
终归单人心
终归单人心 2020-11-28 03:49

I\'m trying to render some text using PIL, but the result that comes out is, frankly, crap.

For example, here\'s some text I wrote in Photoshop:

相关标签:
6条回答
  • 2020-11-28 03:51

    Try using pycairo - the python bindings for the Cairo drawing library -- it is usefull for more refined drawing, with antialiased lines, and such - and you can generate vector based images as well

    Correctly handling fonts, and layout is complicated, and requires the use of the "pango" and "pangocairo" libraries as well. Although they are made for serious font work (all GTK+ widgets do use pango for font rendering), the available docuemtnation and examples are extremely poor.

    The sample bellow shows the prints available in the system and renders the sample text in a font family passed as parameter on the command line.

    # -*- coding: utf-8 -*-
    import cairo
    import pango
    import pangocairo
    import sys
    
    surf = cairo.ImageSurface(cairo.FORMAT_ARGB32, 320, 120)
    context = cairo.Context(surf)
    
    #draw a background rectangle:
    context.rectangle(0,0,320,120)
    context.set_source_rgb(1, 1, 1)
    context.fill()
    
    #get font families:
    
    font_map = pangocairo.cairo_font_map_get_default()
    families = font_map.list_families()
    
    # to see family names:
    print [f.get_name() for f in   font_map.list_families()]
    
    #context.set_antialias(cairo.ANTIALIAS_SUBPIXEL)
    
    # Positions drawing origin so that the text desired top-let corner is at 0,0
    context.translate(50,25)
    
    pangocairo_context = pangocairo.CairoContext(context)
    pangocairo_context.set_antialias(cairo.ANTIALIAS_SUBPIXEL)
    
    layout = pangocairo_context.create_layout()
    fontname = sys.argv[1] if len(sys.argv) >= 2 else "Sans"
    font = pango.FontDescription(fontname + " 25")
    layout.set_font_description(font)
    
    layout.set_text(u"Travis L.")
    context.set_source_rgb(0, 0, 0)
    pangocairo_context.update_layout(layout)
    pangocairo_context.show_layout(layout)
    
    with open("cairo_text.png", "wb") as image_file:
        surf.write_to_png(image_file)
    

    Rendred image

    0 讨论(0)
  • 2020-11-28 04:06

    In python3 there is an option for aliased fonts. I couldn't find this answer anywhere, hopefully it helps someone like me who found this question on google and had to dig a long time to find the answer.

    draw = ImageDraw.Draw(img)
            draw.fontmode = "L"
    

    Mentioned in the docs here

    0 讨论(0)
  • 2020-11-28 04:08

    Suggestion: use Wand or a different Imaging library

    Here's an example with wand -

    from wand.color import Color
    from wand.image import Image
    from wand.drawing import Drawing
    from wand.compat import nested
    
    with Drawing() as draw:
        with Image(width=1000, height=100, background=Color('lightblue')) as img:
            draw.font_family = 'Indie Flower'
            draw.font_size = 40.0
            draw.push()
            draw.fill_color = Color('hsl(0%, 0%, 0%)')
            draw.text(0,int(img.height/2 + 20), 'Hello, world!')
            draw.pop()
            draw(img)
            img.save(filename='image.png')
    

    0 讨论(0)
  • 2020-11-28 04:10

    I've never used PIL, but a quick review of the documentation for the Draw method indicates that PIL provides a way to render simple graphics. Photoshop provides a way to render complex graphics. To get anywhere close to Photoshop-like results requires, at a minimum, font hinting and anti-aliasing. PIL's documentation doesn't even hint at having such capabilities. You may want to look at using an external tool that might do a better job of rendering text on images. For example, ImageMagick (you'll want to use the 8-bit version, which handles standard 24-bit RGB). You can find some text drawing samples here: http://www.imagemagick.org/Usage/draw/

    0 讨论(0)
  • 2020-11-28 04:11

    I came up with my own solution that I find acceptable.

    What I did was render the text large, like 3x the size it needs to be then scale it resize it down with antialiasing, it's not 100% perfect, but it's a hell of a lot better than default, and doesn't require cairo or pango.

    for example,

    image = Image.new("RGBA", (600,150), (255,255,255))
    draw = ImageDraw.Draw(image)
    font = ImageFont.truetype("resources/HelveticaNeueLight.ttf", fontsize)
    
    draw.text((10, 0), txt, (0,0,0), font=font)
    img_resized = image.resize((188,45), Image.ANTIALIAS)
    

    and you endup with this result,

    final result

    which is a lot better than what I was getting before with the same font.

    0 讨论(0)
  • 2020-11-28 04:17

    You can also try to write the font two times it increases the quality immense.

    image = Image.new("RGBA", (288,432), (255,255,255))
    usr_font = ImageFont.truetype("resources/HelveticaNeueLight.ttf", 25)
    d_usr = ImageDraw.Draw(image)
    d_usr = d_usr.text((105,280), "Travis L.",(0,0,0), font=usr_font)
    d_usr = d_usr.text((105,280), "Travis L.",(0,0,0), font=usr_font)
    
    0 讨论(0)
提交回复
热议问题