mpcabd / python-arabic-reshaper

Reconstruct Arabic sentences to be used in applications that don't support Arabic
MIT License
398 stars 80 forks source link

Lines are in reverse order when a paragraph is rendered in a block with multiple lines after using bidi #45

Closed HadySoliman closed 4 years ago

HadySoliman commented 4 years ago

I'm having an issue with writing fetched data from google sheets over an image. the code works all perfectly but the data is written in LFT. and base_dir doesn't change it. الكلام بيتدي من فوق لتحت

`confixed = arabic_reshaper.reshape(confessionFetch) finalconf = get_display(confixed, base_dir='R')

Using Arial font, also tried Cairo and Tajweel but still same issue. Also I use Nider in order to print the fetched data over the image.

amazing work tho. really helped me out but I'd appreciate your input on my issue. thank you`

mpcabd commented 4 years ago

Hello Hady,

Please share the code, a sample data, and what you're expecting.

Regards

HadySoliman commented 4 years ago

Thank you for your response.

Okay first, My data's source is google sheets, a simple table with rows (ID, Confession and Age) I use google sheets api to connect the data to my python script using gspread and google oauth2client in order to fetch the Confession column ( which is mostly paragraphs, around 100 to 200 arabic words). Once the data / confession is stored into the confessions Variable in my code, I run it by the arabic reshape functions and get display. then the output is processed by Nodir in order to add the the paragraphs into an image. the output is fine, arabic is showing but the lines are starting from the bottom instead of the top right side.

Screen Shot 2020-07-10 at 11 17 38 PM

but the actual paragraph in google sheets is

هتكلم عربي اريح ليا انا عايزة اتكلم عن حالات التحرش اللي حصلتلي لاني مبقتش قادرة اكتم اكتر من كدا و كمان المجتمع مش بيرحم كميه ناس مقرفه بتلوم البنت بدل ما تحميها خلتني مش طايقه اعبش وسط القرف دا انا اول مرا حد اتحرش بيا كنت ف ابتدائي مسكني من ورا و فضل يحسس عليا مكنتش فاهمة ايه اللي بيحصل بس كنت مخنوقه و مش عارفه اطلع اب صوت كان عندي 9 سنين و اتعرضت تاني للتحرش ف الثانوي كنت راكبة ميكروباص وواحد غضل يلزق فيا معرفتش اعمل ايه خوفت انزل و انا نازله يلمس جسمي بس مقدرتش اصوت او ازعق كنت خايفه كله اللي عملت اني نزلت جري من الميكروباص و مرا كمان كنت ماشيه مع صاحبتي

As you can notice "هتكلم عربي اريح ليا" is at the beginning and in the generated image it's at the end.

from nider.core import Font
from nider.core import Outline
from nider.models import Content
from nider.models import Linkback
from nider.models import Paragraph
from nider.models import InstagramSquarePost
from nider.models import TwitterPost

import arabic_reshaper
from bidi.algorithm import get_display

import gspread
from oauth2client.service_account import ServiceAccountCredentials
from pprint import pprint

scope = ["https://spreadsheets.google.com/feeds",'https://www.googleapis.com/auth/spreadsheets',"https://www.googleapis.com/auth/drive.file","https://www.googleapis.com/auth/drive"]

creds = ServiceAccountCredentials.from_json_keyfile_name("CCImager-a446cdb64a5b.json", scope)

client = gspread.authorize(creds)

sheet = client.open("tutorial").sheet1

data = sheet.get_all_records()
confessionFetch =sheet.cell(2,2).value #upgrade to loop to move on filter confessions we yeb3at lel paragraph

linkbacktext="انا شغاله كويس قوي قوي "

confixed = arabic_reshaper.reshape(confessionFetch)
finalconf = get_display(confixed)

reshaped_text = arabic_reshaper.reshape(linkbacktext)    # correct its shape
bidi_text2 = get_display(reshaped_text)

roboto_font_folder = '/Users/Hady/Downloads/roboto 2/'
arabic_font = '/Users/Hady/Downloads/arial/'
text_outline = Outline(2, '#121212')

para = Paragraph(text=finalconf,
                 font=Font(arabic_font+ 'arial.ttf', 25),
                 text_width=55,
                 color='#ededed',
                 outline=text_outline,
                 line_padding=10
                 )

linkback = Linkback(text=bidi_text2,
                    font=Font(arabic_font + 'arial.ttf', 20),
                    color='#ededed',
                    outline=text_outline
                    )

content = Content(paragraph=para, linkback=linkback)

InstImg = InstagramSquarePost(content, fullpath='instagram.png')
TwittImg = TwitterPost(content, fullpath='twitter.png')

InstImg.draw_on_texture('texture.jpg')
TwittImg.draw_on_texture('texture.jpg')
mpcabd commented 4 years ago

Ahh I see, it's definitely expected as a side effect of the bidi algorithm, since the text will be reversed to make it work when rendered. If you were rendering the text on one line you won't see this issue, but because nider is rendering the paragraph in a block with multiple lines, you will see this effect. The only way that I know to get around it is to break the text into smaller chunks before you reshape it, where each chunk is guaranteed to fit on one line when rendered, then reshape and reverse each chunk separately, and then you either join the chunks in reverse order or draw them line by line yourself.

A way to make this better is for the reshaper to be aware of which font you're using, the size of the font, the bounding box when the text is rendered, and then we can make the reshaper have some functionality to help with this effect. It's not a simple task, and it might even be something outside the scope of the reshaper; however, I'll try to see if there's anything I can do to solve it, but for now, please try to get around the issue by breaking the text yourself.

Regards, and good luck.

mpcabd commented 4 years ago

Mind you that the problem gets much more complicated when you have sentences that are not in Arabic mixed within the Arabic text, as those are not reversed by bidi and then even if you reorder the lines yourself, you will still get the wrong text as you'd need to split and reverse the non-Arabic sentences yourself, which is really cumbersome and cannot be done deterministically

result1 result2 result3 result4

HadySoliman commented 4 years ago

thank you for your response

I tried switching to Pillow-Imaging instead of nider, and still faced the same issue. the only thing that got me close is using text.wrap & and text.fill but it wasn't dynamic, I had to use a fixed length size for a fixed amount of chars.

is there any other possible way to get over this issue without the need to draw line by line? as im building this for a huge system that gets a lot of data everyday so this process has to be dynamic

mpcabd commented 4 years ago

Nothing that I'm aware of, sorry.

samamou commented 2 years ago

Thank you for your response.

Okay first, My data's source is google sheets, a simple table with rows (ID, Confession and Age) I use google sheets api to connect the data to my python script using gspread and google oauth2client in order to fetch the Confession column ( which is mostly paragraphs, around 100 to 200 arabic words). Once the data / confession is stored into the confessions Variable in my code, I run it by the arabic reshape functions and get display. then the output is processed by Nodir in order to add the the paragraphs into an image. the output is fine, arabic is showing but the lines are starting from the bottom instead of the top right side. Screen Shot 2020-07-10 at 11 17 38 PM

but the actual paragraph in google sheets is

هتكلم عربي اريح ليا انا عايزة اتكلم عن حالات التحرش اللي حصلتلي لاني مبقتش قادرة اكتم اكتر من كدا و كمان المجتمع مش بيرحم كميه ناس مقرفه بتلوم البنت بدل ما تحميها خلتني مش طايقه اعبش وسط القرف دا انا اول مرا حد اتحرش بيا كنت ف ابتدائي مسكني من ورا و فضل يحسس عليا مكنتش فاهمة ايه اللي بيحصل بس كنت مخنوقه و مش عارفه اطلع اب صوت كان عندي 9 سنين و اتعرضت تاني للتحرش ف الثانوي كنت راكبة ميكروباص وواحد غضل يلزق فيا معرفتش اعمل ايه خوفت انزل و انا نازله يلمس جسمي بس مقدرتش اصوت او ازعق كنت خايفه كله اللي عملت اني نزلت جري من الميكروباص و مرا كمان كنت ماشيه مع صاحبتي

As you can notice "هتكلم عربي اريح ليا" is at the beginning and in the generated image it's at the end.

from nider.core import Font
from nider.core import Outline
from nider.models import Content
from nider.models import Linkback
from nider.models import Paragraph
from nider.models import InstagramSquarePost
from nider.models import TwitterPost

import arabic_reshaper
from bidi.algorithm import get_display

import gspread
from oauth2client.service_account import ServiceAccountCredentials
from pprint import pprint

scope = ["https://spreadsheets.google.com/feeds",'https://www.googleapis.com/auth/spreadsheets',"https://www.googleapis.com/auth/drive.file","https://www.googleapis.com/auth/drive"]

creds = ServiceAccountCredentials.from_json_keyfile_name("CCImager-a446cdb64a5b.json", scope)

client = gspread.authorize(creds)

sheet = client.open("tutorial").sheet1

data = sheet.get_all_records()
confessionFetch =sheet.cell(2,2).value #upgrade to loop to move on filter confessions we yeb3at lel paragraph

linkbacktext="انا شغاله كويس قوي قوي "

confixed = arabic_reshaper.reshape(confessionFetch)
finalconf = get_display(confixed)

reshaped_text = arabic_reshaper.reshape(linkbacktext)    # correct its shape
bidi_text2 = get_display(reshaped_text)

roboto_font_folder = '/Users/Hady/Downloads/roboto 2/'
arabic_font = '/Users/Hady/Downloads/arial/'
text_outline = Outline(2, '#121212')

para = Paragraph(text=finalconf,
                 font=Font(arabic_font+ 'arial.ttf', 25),
                 text_width=55,
                 color='#ededed',
                 outline=text_outline,
                 line_padding=10
                 )

linkback = Linkback(text=bidi_text2,
                    font=Font(arabic_font + 'arial.ttf', 20),
                    color='#ededed',
                    outline=text_outline
                    )

content = Content(paragraph=para, linkback=linkback)

InstImg = InstagramSquarePost(content, fullpath='instagram.png')
TwittImg = TwitterPost(content, fullpath='twitter.png')

InstImg.draw_on_texture('texture.jpg')
TwittImg.draw_on_texture('texture.jpg')

Were you able to find a solution? Having the same issue

usamasindhu commented 10 months ago

is there any progress on this issue or someone find solution or any workaround please mention, Thanks

mpcabd commented 10 months ago

@usamasindhu there is no way to make it work from within the reshaper itself without making it aware of how you're using the text and where you're rendering it. This is too far away from the purpose of the reshaper itself, sorry.