Search code examples
pythoncairopycairo

Is there a way to change letter spacing in PyCairo? (Or change a text width without affecting the height)


I'm creating an application that uses Cairo to display text over an image, among other things.

Is there a way I can change the text width without modifying the height? I can already scale the font size based on the width.

A way to manage tracking & kearning would be ideal. It doesn't look like that's built in, but I'd like to know what pieces I would use to build that functionality (or any functionality to modify only the width).


Solution

  • Pango / PangoCairo

    Pango seems to offer a lot of customization.

    Its Markup format allows you to specify letter_spacing.

    I don't have an in-depth knowledge of the framework yet, but it's worth looking into.

    Make your own function

    You could also create a function to split a text into characters, display each one, move the context back a little after displaying each character. Something like the following:

    # This is just an example. It could definitely use improvement.
    def foo(cr, text, tracking): 
        # Normal tracking = 0. Negative spacing shrinks, positive expands.
    
        i = 0
        for c in text:
            x, y = cr.get_current_point()
            cr.show_text(c)
            counter += 1
            cr.move_to( x - i*tracking, y)
    

    You could also define this method in your own subclass of Context:

    class myContext(Context):
        def foo(self, text, spacing):
            # replace every cr above with self
            
    

    Once you have a method set, you can just do foo(cr, "bob", -3) for a slimmer bob.

    You can also use cr.text_extents(text) in your code to figure out text size & scale spacing. As far as I know, there's not an easy way to get the font size from a Context in Cairo.