Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RTL Direction not having any effect #4511

Closed
CovertError opened this issue Apr 1, 2020 · 7 comments · Fixed by #4930
Closed

RTL Direction not having any effect #4511

CovertError opened this issue Apr 1, 2020 · 7 comments · Fixed by #4930

Comments

@CovertError
Copy link

CovertError commented Apr 1, 2020

What did you do?

I'm trying to put text on top of an image and I also set the direction to RTL when doing this before I used to get some library not installed called libraqm but no with it install it still doesn't work I'm testing with the Arabic language

What did you expect to happen?

the text goes RTL

What actually happened?

the text went LTR

What are your OS, Python and Pillow versions?

  • OS: Ubuntu 18
  • Python: 3.6
  • Pillow: latest version
def PhotoAlterer(name):
    image = Image.open('check.jpeg')

    draw = ImageDraw.Draw(image)

    font = ImageFont.truetype('din-next-lt-w23-medium.ttf', size=60)

    text_to_be_reshaped = '%s' % name
    reshaped_text = arabic_reshaper.reshape(text_to_be_reshaped)
    (x, y) = (1050, 427)
    color = 'rgb(255, 255, 255)'  # white color
    draw.text((x, y), reshaped_text , fill=color, font=font, direction="rtl")

    image.save('pImg/%s.png' % name)
@radarhere
Copy link
Member

Could you adjust the code that you've provided so that it's self-contained? At the moment, I don't know the value of name or what arabic_reshaper does.

@radarhere
Copy link
Member

This is the sequel to #4496

So from that, it seems reasonable to presume that arabic_reshaper is https://pypi.org/project/arabic-reshaper/, and that 'محمد' is a valid value for text_to_be_reshaped.

from PIL import Image, ImageDraw, ImageFont
import arabic_reshaper

def PhotoAlterer(name):
    image = Image.open('check.jpeg')

    draw = ImageDraw.Draw(image)

    font = ImageFont.truetype('din-next-lt-w23-medium.ttf', size=60)

    text_to_be_reshaped = '%s' % name
    reshaped_text = arabic_reshaper.reshape(text_to_be_reshaped)
    (x, y) = (1050, 427)
    color = 'rgb(255, 255, 255)'  # white color
    draw.text((x, y), reshaped_text , fill=color, font=font, direction="rtl")

    image.save('pImg/%s.png' % name)

PhotoAlterer('محمد')

You may be interested in #3081 (comment), but more likely, you're looking for #3125 (comment)

The direction parameter sets the overall paragraph direction, the individual character's direction is determined by BiDi algorithm. Unicode bidi control characters can be to force text direction to be LTR or RTL and override the algorithm (though that is not usually something very useful todo, expect for ancient scripts that can be written in either direction or pseudo RTL localization strings).

@CovertError
Copy link
Author

CovertError commented Apr 13, 2020

yes I have tried that library but the same thing still happens the text just keeps going LTR my temp solution to this is to find the size of the message and subtract it for the x coordinates like so

gettingTextSize = draw.textsize(reshaped_text, font=font)
spaceToAdd = gettingTextSize.__getitem__(0)
width = 1050 - (spaceToAdd)

@CovertError
Copy link
Author

CovertError commented Apr 13, 2020

Could you adjust the code that you've provided so that it's self-contained? At the moment, I don't know the value of name or what arabic_reshaper does.

arabic_reshaper is really helpful if fixes the Arabic language with python somehow without it Arabic letters wouldn't be attached together so let's say "محمد" this is how it should look like and it's just the name Mohammed but in Arabic, so without the arabic_reshaper it would look like "م ح م د" I had to use spaces to emulate it but essentially the letters would be separated

maybe a good it's good to just shift to using arabic_reshaper instead of libraqm I'm really sure what are you using it for but it's just easier to work with other libraries like arabic_reshaper

@nulano
Copy link
Contributor

nulano commented Apr 13, 2020

I have opened Ubuntu 18.04 live in VirtualBox with a full Pillow install from master with raqm following the Installation documentation to test this. I ran the following commands in a Python console:

from PIL import Image, ImageDraw, ImageFont
import arabic_reshaper
from bidi.algorithm import get_display as bidi_get_display
im = Image.new("RGB", (400, 400), "white")
d = ImageDraw.Draw(im)
text = "\u0645\u062D\u0645\u062F"   # محمد in unicode code points
reshaped = arabic_reshaper.reshape(text)
reshaped.encode("unicode-escape")    # prints b'\\ufee3\\ufea4\\ufee4\\ufeaa'
bidi = bidi_get_display(reshaped)
bidi.encode("unicode-escape")    # prints b'\\ufeaa\\ufee4\\ufea4\\ufee3'

# test without libraqm
fb = ImageFont.truetype("KacstBook.ttf", 60, layout_engine=ImageFont.LAYOUT_BASIC)
d.text((0,   0), text, "black", font=fb)    # shows م l ح l م l د (l added to stop browser shaping)
d.text((0, 100), text, "black", font=fb, direction='ltr')    # fails as expected
d.text((0, 200), text, "black", font=fb, direction='rtl')    # fails as expected
d.text((100,   0), reshaped, "black", font=fb)    # shows محمد, but reversed
d.text((100, 100), reshaped, "black", font=fb, direction='ltr')    # fails as expected
d.text((100, 200), reshaped, "black", font=fb, direction='rtl')    # fails as expected
d.text((0, 300), bidi, "black", font=fb)    # shows محمد correctly

# test with libraqm
fr = ImageFont.truetype("KacstBook.ttf", 60, layout_engine=ImageFont.LAYOUT_RAQM)
d.text((200,   0), text, "black", font=fr)    # shows محمد correctly
d.text((200, 100), text, "black", font=fr, direction='ltr')    # shows محمد
d.text((200, 200), text, "black", font=fr, direction='rtl')    # shows محمد
d.text((300,   0), reshaped, "black", font=fr)    # shows محمد correctly
d.text((300, 100), reshaped, "black", font=fr, direction='ltr')    # shows محمد
d.text((300, 200), reshaped, "black", font=fr, direction='rtl')    # shows محمد
d.text((300, 300), bidi, "black", font=fb)    # shows محمد, but reversed

im.save("a.png")

As you can see, you can either use libraqm to handle text shaping (in which case arabic_reshaper has no effect and python_bidi causes a conflict), or you can use arabic_reshaper+python_bidi with the basic layout in Pillow (the 'legacy' option).

The direction parameter has no effect on arabic, as it only affects the direction of symbols (e.g. a comma, plus, minus, ...) as @radarhere quoted in the comment above. See also #3125 (comment) from the same discussion:

With regards to 2 in the original post, I don't think this is how rtl works. English characters are strong characters, and have a definite directionality. However, weak characters, such as arithmetical symbols, do not and are able to be shown right-to-left by Pillow.

@nulano
Copy link
Contributor

nulano commented Apr 13, 2020

yes I have tried that library but the same thing still happens the text just keeps going LTR my temp solution to this is to find the size of the message and subtract it for the x coordinates like so

gettingTextSize = draw.textsize(reshaped_text, font=font)
spaceToAdd = gettingTextSize.__getitem__(0)
width = 1050 - (spaceToAdd)

Oh, I think I see the problem now. The xy parameter always specifies the top-left point of the text. The direction parameter is not used to make text appear to the left of this point, but as a hint to the shaping algorithm used by libraqm. If you wish to have text appear to the left of this point, you have to use the steps such as in your comment.

# using libraqm
fr = ImageFont.truetype("KacstBook.ttf", 60, layout_engine=ImageFont.LAYOUT_RAQM)
text = "\u0645\u062D\u0645\u062F"   # محمد in unicode code points
x, y = (1050, 427)
w, h = d.textsize(text, font=fr)
d.text((x-w, y), text, "black", font=fr)

# using arabic_reshaper + python_bidi
fb = ImageFont.truetype("KacstBook.ttf", 60, layout_engine=ImageFont.LAYOUT_BASIC)
text = "\u0645\u062D\u0645\u062F"   # محمد in unicode code points
reshaped = arabic_reshaper.reshape(text)
bidi_text = bidi.algorithm.get_display(reshaped)
x, y = (1050, 427)
w, h = d.textsize(bidi_text, font=fb)
d.text((x-w, y), text, "black", font=fb)

To see what the direction parameter actually does, pass it undirected text, such as "+-=" (as mentioned in my previous comment):

font = ImageFont.truetype("DejaVuSans.ttf", 60, layout_engine=ImageFont.LAYOUT_RAQM)
draw.text((0, 0), "+-=", "black", font=font, direction="ltr")    # shows +-=
draw.text((0, 100), "+-=", "black", font=font, direction="rtl")    # shows =-+

@nulano
Copy link
Contributor

nulano commented Apr 13, 2020

If you wish to have text appear to the left of this point, you have to use the steps such as in your comment.

Looking at the docs, it looks like there is an undocumented parameter anchor=None that might be intended for this. Looking through the history, this has been present since the PIL fork, but never implemented, and always ignored. The only other mention I can find is in #285 ("might be implemented in the future"). #1660 seems to have attempted to do this in a different way, but was not accepted. I'll try to make a PR for this using the anchor parameter later today.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants