Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Devanagari text rendering improperly in PyGame

We have a small web app that we want to convert into something native. Right now, it's got a lot of moving parts (the backend, the browser etc.) and we'd like to convert it into a single tight application. We decided to use PyGame to do this and it's been fine so far except for a font rendering issue.

The string I'd like to render is कोझिकोड. This, correctly rendered looks like Correctly rendered.

The specific code points are \u0915 \u094b \u091d \u093f \u0915 \u094b and \u0921

Now, this looks fine in my editor and my browser but when I try to render it in PyGame, I get this Wrongly rendered. Basically, the vowel sign (\u093f ि) should have been on the left of the झ but it appears to its right (and to the left of the क) thereby messing it up completely. This doesn't happen in a browser or a text editor (with the same input string) so I'm guessing it a renderer problem in PyGame.

There is one crude fix which works only in this specific case which i s to put the ि (\u093f) before the झ (\u091d). In that case, it renders properly like so Crude fix. This relies on me knowing something about the language and putting that logic into the code. I have to deal with multiple languages here so that's not really feasible.

I don't have much experience with unicode so I don't know how to approach this problem. Is there something I can do to fix this?

In case it matters, I'm using the freesans font which is there on Debian and which has the necessary glyphs to render this.

Update: The code to actually render this is as follows

# -*- coding: utf-8 -*-
import time

import pygame

# Pygame setup and create root window
pygame.font.init()
screen = pygame.display.set_mode((320, 200))
empty = pygame.Surface((320, 200))


font_file = pygame.font.match_font("freesans")  # Select and
font = pygame.font.Font(font_file, 30)          # open the font
writing = font.render(u"कोिझकोड  कोझिकोड", True, (0, 0, 0))  # Render text on a surface
screen.fill((255, 255, 255)) # Clear the background
screen.blit(writing, (10, 10)) # Blit the text surface on the background
pygame.display.flip()  # Refresh the display

input() # Wait for input before quitting

This is what it looks like Error in rendering

The first word is rendered correctly but we've done it by inverting the vowel and the letter positions as I mentioned in the crude fix. The second is written properly but not rendered correctly.

Update 2: In the absence of anything else, I've decided to try to render the string into an image using an external program and then blit this image onto the PyGame Surface. I tried imagemagick but it messes us in the same way as this. Gimp works fine and so I'm planning to use the batch mode to get my work done.

like image 613
Noufal Ibrahim Avatar asked May 30 '17 05:05

Noufal Ibrahim


2 Answers

I think is a SDL_ttf problem (the underlying component which actually renders the text).

While my IDE correctly renders the string

The SDL_TTF program does not:

There is the code: https://gist.github.com/ilario-pierbattista/be6b967b05fa2f1eb322f35988a33ad0

I'm still looking for a solution

like image 63
Ilario Pierbattista Avatar answered Oct 13 '22 01:10

Ilario Pierbattista


I had to finally resort to a really ugly but usable workaround for my own situation. I wrote a script-fu plugin which takes a filename and a piece of text as arguments. It then writes out the text and saves it a png file using gimp. My program then loads this up and blits the png directly onto the surface.

like image 38
Noufal Ibrahim Avatar answered Oct 12 '22 23:10

Noufal Ibrahim