Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fit line to width with Pango and Cairo (Pycairo)

I've several lines of text and I'd like each to fit in width (scaling the font size) to the width of the Context. Is there a way of doing this? I'm using pangocairo and python for this.

like image 673
casasin Avatar asked Nov 04 '22 05:11

casasin


1 Answers

I wish to have time for a working solution, but you can start with something like:

import cairo
import pango
import pangocairo
import sys

W = 500
H = int(1.4 * W)

surf = cairo.ImageSurface(cairo.FORMAT_ARGB32, W, H)
context = cairo.Context(surf)

#draw a background rectangle:
context.rectangle(0, 0, W, H)
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 sorted([f.get_name() for f in   font_map.list_families()])

# context.set_antialias(cairo.ANTIALIAS_SUBPIXEL)

# Translates context so that desired text upperleft corner is at 0,0

text = """Fit line
to width with 
Pango 
and Cairo"""

fontname = "Arial"
context.set_source_rgb(0, 0, 0)

y = 0
for line in text.split("\n"):
    pangocairo_context = pangocairo.CairoContext(context)
    pangocairo_context.set_antialias(cairo.ANTIALIAS_SUBPIXEL)
    layout = pangocairo_context.create_layout()
    font = pango.FontDescription(fontname + " 25")
    layout.set_font_description(font)
    layout.set_text(line)
    pangocairo_context.update_layout(layout)
    w, h = layout.get_pixel_size()
    print w, h, y
    context.translate(0, y)
    pangocairo_context = pangocairo.CairoContext(context)
    pangocairo_context.set_antialias(cairo.ANTIALIAS_SUBPIXEL)
    layout = pangocairo_context.create_layout()
    font_descr = "{} {:0.1f}".format(fontname, float(W) / w * 25)
    font = pango.FontDescription(font_descr)
    layout.set_font_description(font)
    layout.set_text(line)
    _, y = layout.get_pixel_size()
    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)

Result:

result

I will left improving this algorithm as an exercise for the reader, you can try to:

  • verify the width of the layout after scaling the font and adjusting
  • render in a big font size and scale pangocairo_context instead
  • I don't know, in fact I knew nothing about pycairo until I read your question and goggled for the docs.
like image 106
Paulo Scardine Avatar answered Nov 13 '22 21:11

Paulo Scardine