Devnagri font not working #2255

manishp11 opened this Issue Nov 24, 2016 · 13 comments


None yet

4 participants

manishp11 commented Nov 24, 2016 edited


I am printing text written in devnagri unicode to jpg and png

all i can see in images in boxes.

python 2 and 3 both, with pillow pip install

# Draw (Bitmap Font) Text to Image
# coding: utf-8
from PIL import Image, ImageDraw, ImageFont

def reverseColor(r, g, b):
    return (255 - r, 255 - g, 255 - b)
def grayscaleColor(r, g, b):
    a = (r + g + b) / 3
    return (a, a, a)

text = "तपःस्वाध्यायनिरतं तपस्वी वाग्विदां वरम्"
textColor = (0, 255, 0) # RGB lime
#textBackgroundColor = (255, 0, 0) # RGB Red
textX = 200 # text width in pixels
textY = 50 # text height in pixels
textTopLeftX = 100
textTopLeftY = 100

# create new image
# imgx = 1920 # image width in pixels
# imgy = 1080 # image height in pixels
# image ="RGB", (imgx, imgy))

# load image
image ="input.png")
(imgx, imgy) = image.size
image = image.resize((imgx, imgy), Image.BICUBIC)

font = ImageFont.truetype("Devnew.ttf", 15) # load default bitmap font
(width, height) = font.getsize(text)
textImage = font.getmask(text)
pixels = image.load()
for y in range(imgy):
    by = int(height * (y - textTopLeftY) / textY + 0.5)
    if by >= 0 and by < height:
        for x in range(imgx):
            bx = int(width * (x - textTopLeftX) / textX + 0.5)
            if bx >= 0 and bx < width:
                if textImage.getpixel((bx, by)) == 0: # text background
                    # pass # transparent background
                    # pixels[x, y] = textBackgroundColor
                    (r, g, b, a) = pixels[x, y]
                    #(r, g, b) = pixels[x, y]
                    #pixels[x, y] = grayscaleColor(r, g, b)
                else: # text foreground
                    pixels[x, y] = textColor                
                    (r, g, b, a) = pixels[x, y]
                    # (r, g, b) = pixels[x, y]
                    # pixels[x, y] = reverseColor(r, g, b)"output.png", "PNG")

That appears to be a very complicated way to draw text. Have you tried the more straightforward way to use the api?


This has been an issue for a long time. I had the same issue with Indic text rendering. After trying a lot, I finally use cffi in python3. See and '` in chamanti_ocr.


@wiredfool my problem is not with drawing text
i am able to draw it with the default font but facing issue with the font i am using actually not only this font i have tried.
all are attached below.

@rakeshvar thats for the clearification can you share some working POC work for the fonts i am working with as i need these fonts only to work on.


ok it dosnt seems i can upload them, so you can refer the name of the fonts.
Devnew.ttf Lohit-Marathi.ttf Sarai_07.ttf chandas1-2.ttf gargi.ttf lohit_kok.ttf lohit_mai.ttf lohit_sd.ttf nakula.ttf samanata.ttf Lohit-Devanagari.ttf Samyak-Devanagari.ttf kalimati.ttf lohit_ks.ttf lohit_ne.ttf mangal.ttf sahadeva.ttf


I'm not sure I have access to any of those fonts, but I suspect that this is a case of not having the normalization step from unicode -> combined glyphs. There's a PR that adds support for it in #1682, but it needs work.


@wiredfool i am security tester not a devoloper its wasnt already easy for me so #1682 seems tough for me to go for. thanks for your support i will keep looking for some other way around.


If you can render standard uncomplicated fonts, then I'd bet that #1682 is one solution, however convoluted.

FWIW, your rendering looks quite complicated, and it appears that it's a really slow equivalent to the standard ImageDraw.text command. In general, if you're looping over pixels in python, there's a better way.


Check out this repo to see how to get unicode text as a numpy array in Python3. You will have to tweak with it to get what you need. It does not use Pillow or Harfbuf, etc.

wiredfool commented Nov 28, 2016 edited

That repo seems to work on my machine. It's pretty easy to skip the dependency on numpy and directly output an image from the scribe function:

    return Image.frombuffer('L', (width, height), data, "raw", 'L', 0, 1)
    #return np.frombuffer(data, dtype=np.uint8).reshape((height, width))

and then later just display the image, rather than trimming it and dumping to the console.

I think that image could be directly used as a font mask in ImageDraw.text.

The question I have is: What's the level of correctness/generality here? Is this a general solution for 'complex' scripts, bypassing the need for harfbuf with different dependencies, or is this just working because the string in the script has already been preprocessed?


@wiredfool That repo uses the same mechanism that linux uses to display complex scripts. i.e. via the pango, cairo and pangocairo libraries. The repo does it in a dependable way using cffi. O, also in that repo I use eight-bit images. One can use 24-bit images instead.
The string is not pre-processed in anyway. It is just raw unicode, as it ought to be.

wiredfool commented Nov 29, 2016 edited

Ok, so it's a complete solution through a different stack than we're using. This has potential.

Do you have a license for it? Hopefully something compatible with Pillow?

@aclark4life aclark4life added this to the Future milestone Jan 8, 2017

@wiredfool If I understand correctly, you'd like @rakeshvar to provide a license for so we can use it in Pillow?


Maybe, there's been development since then in a different implementation using harfbuzz and raqm.

Otoh, this might be a reasonable alternate implementation, as it's a small interface and we don't actually have to ship the binaries.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment