bgrabitmap / lazpaint

🎨 Cross-platform image editor with raster and vector layers similar to Paint.Net written in Lazarus (Free Pascal)
https://lazpaint.github.io/
GNU General Public License v3.0
401 stars 55 forks source link

TTextStyle.RightToLeft in TextRec not working #6

Closed almontasser closed 6 years ago

almontasser commented 8 years ago

TBGRABitmap.TextRec result (the forth line of the image attached) Should be as the TCanvas.TextRec result (the third line of the image attached).

image

and here is the code I used:

procedure TForm1.FormPaint(Sender: TObject);
var
  image: TBGRABitmap;
  TS: TTextStyle;
begin
  image := TBGRABitmap.Create(ClientWidth, ClientHeight);
  image.FontName := Font.Name;
  image.FontHeight := Font.Height;
  TS.Opaque := False;

  TS.RightToLeft := False;
  Canvas.TextRect(Rect(5, 5, 250, 20), 5, 5, 'TCanvas With RightToLeft := False', TS);
  Canvas.TextRect(Rect(250, 5, 500, 20), 250, 5, 'أب+', TS);

  image.TextRect(Rect(5, 20, 250, 35), 5, 20, 'TBGRABitmap With RightToLeft := False', TS, BGRA(0,0,0));
  image.TextRect(Rect(250, 20, 500, 35), 250, 20, 'أب+', TS, BGRA(0,0,0));
  image.Draw(Canvas, 0, 0, False);

  TS.RightToLeft := True;
  Canvas.TextRect(Rect(5, 35, 250, 50), 5, 35, 'TCanvas With RightToLeft := True', TS);
  Canvas.TextRect(Rect(250, 35, 500, 50), 250, 35, 'أب+', TS);

  image.TextRect(Rect(5, 50, 250, 65), 5, 50, 'TBGRABitmap With RightToLeft := True', TS, BGRA(0,0,0));
  image.TextRect(Rect(250, 50, 500, 65), 250, 50, 'أب+', TS, BGRA(0,0,0));
  image.Draw(Canvas, 0, 0, False);

  image.Free;
end;
lainz commented 8 years ago

Sure it's easy to solve.

In Lazarus trunk there is UTF8ReverseString https://github.com/alrieckert/lazarus/blob/master/components/lazutils/lazutf8.pas#L142

That can be used to reverse the string when that option is present. But warning: That function is not available with Lazarus 1.6 and FPC 3.0. Make sure to keep that in account.

Edit: the real TextRect is in the unit BGRAText, however using UTF8ReverseString is not usefull at all.

I've tested with

if style.RightToLeft then sUTF8 := UTF8ReverseString(sUTF8);

But seems that there are other calculations somewhere that affects the width of the string?

almontasser commented 8 years ago

That didn't solve it.

The problem is not in the order of the letters, the problem is when you mix right to left text with left to right text, like Arabic and English, or Arabic and Numbers, or Arabic and Symbols.

I'know I tried to locate it, and I got stuck.

TCanvas works as it suppose to, but TBGRABitmap don't.

lainz commented 8 years ago

Yes that happened to my the first time I tried to reverse the string. Everything was reversed and not only the part that is not english.

You know where to find the working code in TCanvas?

almontasser commented 8 years ago

https://github.com/alrieckert/lazarus/blob/master/lcl/include/canvas.inc#L1275

  if Style.RightToLeft then
    Options := Options or DT_RTLREADING;

  ...

    DrawText(DC, pChar(Text), Length(Text), fRect, Options);
lainz commented 8 years ago

Is strange because reading the BGRABitmap code it uses the Canvas to draw the Text, uses the same functions you're using with Canvas internally.

almontasser commented 8 years ago

It uses TextOut https://github.com/bgrabitmap/lazpaint/blob/master/bgrabitmap/bgratext.pas#L720

They don't check for RightToLeft at all.

lainz commented 8 years ago

You're right, that's the bug

almontasser commented 8 years ago

I gusse It will require a lot of work to support RightToLeft

almontasser commented 8 years ago

TCanvas uses ExtUTF8Out, and I was able to make print correctly when I pass it (ETO_RTLREADING=128) in the Options parameter.

https://github.com/alrieckert/lazarus/blob/master/lcl/include/canvas.inc#L1351

circular17 commented 7 years ago

Indeed that would be work to handle RightToLeft. In the meantime, you can use the Canvas property of BGRABitmap. It works ok as long as images have an opaque background.

circular17 commented 6 years ago

I fixed it on dev branch. I have used the LCL TextRect function. I suppose that also solves the ticket with missing unicode glyphs: https://github.com/bgrabitmap/bgrabitmap/issues/11

By the way, I've added a RightToLeft parameter to TBGRABitmap.TextOut. That allows to use RightToLeft option without having to supply the TRect for TextRect.

right_to_left testtext.zip