How can I draw text with different stroke and fill colors on images with python?
Here is some text with red stroke and gray fill.
I tried to do this with PIL but there was no option for setting the stroke color.
How can I draw text with different stroke and fill colors on images with python?
Here is some text with red stroke and gray fill.
I tried to do this with PIL but there was no option for setting the stroke color.
Using cairo (with much code taken from here):
import cairo def text_extent(font, font_size, text, *args, **kwargs): surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 0, 0) ctx = cairo.Context(surface) ctx.select_font_face(font, *args, **kwargs) ctx.set_font_size(font_size) return ctx.text_extents(text) text='Example' font="Sans" font_size=55.0 font_args=[cairo.FONT_SLANT_NORMAL] (x_bearing, y_bearing, text_width, text_height, x_advance, y_advance) = text_extent(font, font_size, text, *font_args) surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(text_width), int(text_height)) ctx = cairo.Context(surface) ctx.select_font_face(font, *font_args) ctx.set_font_size(font_size) ctx.move_to(-x_bearing, -y_bearing) ctx.text_path(text) ctx.set_source_rgb(0.47, 0.47, 0.47) ctx.fill_preserve() ctx.set_source_rgb(1, 0, 0) ctx.set_line_width(1.5) ctx.stroke() surface.write_to_png("/tmp/out.png")
PIL doesn't support this but you can fake it: Render the text four or eight times with the outline color using one pixel offsets:
x+1,y x-1,y x ,y+1 x ,y-1 (four times version)
x+1,y+1 x ,y+1 x-1,y+1 x+1,y x-1,y x+1,y-1 x ,y-1 x-1,y-1 (eight times version)
and then once at x,y with the fill color.
Using imagemagick:
import subprocess args = { 'bgColor': 'transparent', 'fgColor': 'light slate grey', 'fgOutlineColor': 'red', 'text': 'Example', 'size': 72, 'geometry': '350x100!', 'output': '/tmp/out.png', 'font': 'helvetica' } cmd = ['convert', 'xc:{bgColor}', '-resize', '{geometry}', '-gravity', 'Center', '-font', '{font}', '-pointsize', '{size}', '-fill', '{fgColor}', '-stroke', '{fgOutlineColor}', '-draw', "text 0,0 '{text}'", '-trim', '{output}'] cmd = [item.format(**args) for item in cmd] proc = subprocess.Popen(cmd) proc.communicate()
You can use Inkscape:
import subprocess subprocess.call("inkscape in.svg --export-text-to-path --export-plain-svg out.svg", shell = True) note: you have to download Inkscape to use this, so not practical for permanent use