Pillow icon indicating copy to clipboard operation
Pillow copied to clipboard

Devanagari font not working

Open manishp11 opened this issue 9 years ago • 31 comments

input

I am printing text written in devanagari 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 = Image.new("RGB", (imgx, imgy))

# load image
image = Image.open("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)

image.save("output.png", "PNG")

manishp11 avatar Nov 24 '16 03:11 manishp11

That appears to be a very complicated way to draw text. Have you tried the more straightforward way to use the api? http://pillow.readthedocs.io/en/3.4.x/reference/ImageDraw.html#example-draw-partial-opacity-text

wiredfool avatar Nov 25 '16 10:11 wiredfool

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 scribe.py and 'cffi_wrapper.py` in chamanti_ocr.

rakeshvar avatar Nov 27 '16 08:11 rakeshvar

@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.

manishp11 avatar Nov 27 '16 09:11 manishp11

ok it doesn't seem 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

manishp11 avatar Nov 27 '16 09:11 manishp11

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 avatar Nov 27 '16 15:11 wiredfool

@wiredfool i am security tester not a developer its wasn't 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.

manishp11 avatar Nov 27 '16 17:11 manishp11

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.

wiredfool avatar Nov 27 '16 19:11 wiredfool

@manishp11 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.

rakeshvar avatar Nov 28 '16 07:11 rakeshvar

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 avatar Nov 28 '16 10:11 wiredfool

@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.

rakeshvar avatar Nov 29 '16 11:11 rakeshvar

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?

wiredfool avatar Nov 29 '16 18:11 wiredfool

@wiredfool If I understand correctly, you'd like @rakeshvar to provide a license for https://github.com/rakeshvar/unicode_text_to_image_array so we can use it in Pillow?

aclark4life avatar Jan 08 '17 00:01 aclark4life

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.

wiredfool avatar Jan 08 '17 08:01 wiredfool

Hi, Please let me know complex font rendering for Indic fonts are working now? I am using PIL on windows. Thanks.

nengine avatar May 01 '17 01:05 nengine

Most likely you need a text = text.decode('utf8') if you are python 2.x . See my comments in

https://github.com/rougier/freetype-py/issues/57

And also the changes I recently made to freetype-py https://github.com/rougier/freetype-py/pull/52/commits/a4e35f785d4ab912dbfe2d28d2b50158512c4b35

HinTak avatar May 08 '17 19:05 HinTak

Actually from __future__ import unicode_literals should also work for python 2.x

HinTak avatar May 08 '17 19:05 HinTak

Thanks HinTak, It is drawing fine with regular consonants, but what I meant was that when a vowel symbol is top on top of consonant like ကိ (little o shape on top of က) Pillow is rendering separately as shown below. Please let me know if this is something I could do with freetype-py too?

sylb = txt2png(u"ကိ",fopath, 80, 128)

image

nengine avatar May 08 '17 19:05 nengine

I have modified example 1 ( https://github.com/rougier/freetype-py/issues/54#issuecomment-298186703 ) to use the lohit font, and the initial phrase, and it seems to work:

+    filename= '/usr/share/fonts/lohit-devanagari/Lohit-Devanagari.ttf'
+    text    = 'तपःस्वाध्यायनिरतं तपस्वी वाग्विदां वरम्'

Here is the result (obviously I cannot read Devnagri, so you'll have to check it yourself): example_1-cairo1

I am fairly sure you need harfbuzz for "ကိ (little o shape on top of က)".

HinTak avatar May 08 '17 20:05 HinTak

@HinTak The rendering is not correct. It should look like तपःस्वाध्यायनिरतं स्वा ध्या नि etc. are wrong.

rakeshvar avatar May 08 '17 22:05 rakeshvar

I did example 1 with text below and it came out similar to Pillow which is not correct. So it seems like I would need harfbuzz as you indicated. Would it be possible natively inside Pillow (or) freetype-py? @rakeshvar unicode_text_to_image_array repo works on Linux, but I can't make it work on Windows 10, so this is why I am interested in Pillow (or) freetype-py to work on Windows.

Many thanks,

text = u'ကိ'

image

nengine avatar May 08 '17 22:05 nengine

Here is freetype-py 's hello world example quickly changed to do the initial phrase (I can't read it - just cut-and-paste)

hello-world-cairo

HinTak avatar May 08 '17 22:05 HinTak

Hmm, harfbuzz can be built for windows (and so does pango).... but it is quite an unnatural/involved task to do.

HinTak avatar May 08 '17 22:05 HinTak

There is already a pull request for complex text support https://github.com/python-pillow/Pillow/pull/2284.

khaledhosny avatar May 16 '17 15:05 khaledhosny

This should be fixed in 4.2.0 with the merge of #2576

wiredfool avatar Jul 01 '17 10:07 wiredfool

thanks @wiredfool. please let me know if this is going work with windows as well?

nengine avatar Jul 01 '17 15:07 nengine

Short answer -- Not now. Dependencies are harder to build on windows, and libfribidi is GPL, so we wouldn't be able to distribute it in the binaries, at least by default.

wiredfool avatar Jul 01 '17 16:07 wiredfool

No problem. Thanks.

nengine avatar Jul 01 '17 17:07 nengine

@wiredfool @rakeshvar @aclark4life

This repo doesn't provide correct output.

The text कामकाजी महिलाओं के लिए देश में दिल्ली असुरक्षित, सिक्किम सबसे बेहतर: रिपोर्ट produces the following incorrect output

screen shot 2018-08-12 at 10 23 40 pm

Was trying to produce a solution for https://stackoverflow.com/questions/39630916/how-can-i-print-hindi-sentencesunicode-on-image-in-python

pankajsinghal avatar Aug 12 '18 17:08 pankajsinghal

@pankajsinghal does this commit mean that your problem is resolved?

radarhere avatar Jun 22 '19 02:06 radarhere

have you solve the problem that pillow rendering hindi incorrect?

KosukeHao avatar Jun 26 '19 10:06 KosukeHao