Recent

Author Topic: FPImage Font problem with Persian characters  (Read 26972 times)

Sanem

  • Full Member
  • ***
  • Posts: 173
FPImage Font problem with Persian characters
« on: May 25, 2016, 02:24:59 pm »
Hi
I am trying to write a persian word into FPImage, in NoGui program, but as you can see in Screen Shots, When Characters are English it shows them correctly but when I use Persian Characters the result is Ruined, its my code in lazarus 1.6 :

any help appreciated prior
 
Code: Pascal  [Select][+][-]
  1. program project1;
  2.  
  3. uses
  4.   Classes,
  5.   SysUtils,
  6.   FPimage,
  7.   FPImgCanv,
  8.   ftfont,
  9.   FPWritePNG,
  10.   FPCanvas;
  11.  
  12.   procedure TestFPImgFont;
  13.   var
  14.     Img: TFPMemoryImage;
  15.     Writer: TFPWriterPNG;
  16.     ms: TMemoryStream;
  17.     ImgCanvas: TFPImageCanvas;
  18.     fs: TFileStream;
  19.     AFont: TFreeTypeFont;
  20.   begin
  21.     Img := nil;
  22.     ImgCanvas := nil;
  23.     Writer := nil;
  24.     ms := nil;
  25.     fs := nil;
  26.     AFont := nil;
  27.     try
  28.       // initialize free type font manager
  29.       ftfont.InitEngine;
  30.       FontMgr.SearchPath := ExtractFilePath(ParamStr(0));
  31.       AFont := TFreeTypeFont.Create;
  32.       // create an image of width 200, height 100
  33.       Img := TFPMemoryImage.Create(200, 100);
  34.       Img.UsePalette := False;
  35.       // create the canvas with the drawing operations
  36.       ImgCanvas := TFPImageCanvas.Create(Img);
  37.       // paint white background
  38.       ImgCanvas.Brush.FPColor := colWhite;
  39.       ImgCanvas.Brush.Style := bsSolid;
  40.       ImgCanvas.Rectangle(0, 0, Img.Width, Img.Height);
  41.       // paint text
  42.       ImgCanvas.Font := AFont;
  43.       ImgCanvas.Font.Name := 'B Titr';
  44.       ImgCanvas.Font.Size := 20;
  45.       ImgCanvas.TextOut(10, 30, 'فارسی');
  46.       // write image as png to memory stream
  47.       Writer:=TFPWriterPNG.create;
  48.       ms:=TMemoryStream.Create;
  49.       writer.ImageWrite(ms,Img);
  50.       // write memory stream to file
  51.       ms.Position:=0;
  52.       fs:=TFileStream.Create('Font_FA.png',fmCreate);
  53.       fs.CopyFrom(ms,ms.Size);
  54.     finally
  55.       AFont.Free;
  56.       ms.Free;
  57.       Writer.Free;
  58.       ImgCanvas.Free;
  59.       Img.Free;
  60.       fs.Free;
  61.     end;
  62.   end;
  63.  
  64. begin
  65.   TestFPImgFont;
  66. end.
  67.  

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: FPImage Font problem with Persian characters
« Reply #1 on: May 25, 2016, 04:04:38 pm »
You are using FreeType which does not support Arabic scripts like Persian, according to their FAQ page:
Quote
It now supports Asian fonts, but not other complex scripts like Arabic.

In the future even if FreeType adds Arabic support, freetype.pp TFontManager needs to change the way it retrieves its glyphs:

Code: Pascal  [Select][+][-]
  1. function TFontManager.CreateGlyph (c : char) : PMgrGlyph;

What OS are you using?
« Last Edit: May 25, 2016, 04:06:39 pm by engkin »

Windsurfer

  • Sr. Member
  • ****
  • Posts: 368
    • Windsurfer
Re: FPImage Font problem with Persian characters
« Reply #2 on: May 25, 2016, 04:45:14 pm »
I think it does support Arabic. Scroll down this link: https://www.freetype.org/opentype/index.html to see a demo.

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: FPImage Font problem with Persian characters
« Reply #3 on: May 25, 2016, 05:03:19 pm »
I think it does support Arabic. Scroll down this link: https://www.freetype.org/opentype/index.html to see a demo.

Seems true, except the top of that page says something different:
Quote
Please go to homepage of the HarfBuzz library! FreeType 1 and its OpenType support is no longer maintained.

Even if FreeType supports (present, past, or future) Arabic scripts, TFontManager does not.

wp

  • Hero Member
  • *****
  • Posts: 11858
Re: FPImage Font problem with Persian characters
« Reply #4 on: May 25, 2016, 05:20:22 pm »
In the future even if FreeType adds Arabic support, freetype.pp TFontManager needs to change the way it retrieves its glyphs:
Code: Pascal  [Select][+][-]
  1. function TFontManager.CreateGlyph (c : char) : PMgrGlyph;
Convert the UTF8 string to Arabian codepage (1256)?
Code: Pascal  [Select][+][-]
  1. uses
  2.   lconvencoding;
  3.  
  4.   // in the demo code:
  5.   ImgCanvas.TextOut(10, 30, UTF8ToCP1256('فارسی'));
  6.  

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: FPImage Font problem with Persian characters
« Reply #5 on: May 25, 2016, 05:48:54 pm »
In the future even if FreeType adds Arabic support, freetype.pp TFontManager needs to change the way it retrieves its glyphs:
Code: Pascal  [Select][+][-]
  1. function TFontManager.CreateGlyph (c : char) : PMgrGlyph;
Convert the UTF8 string to Arabian codepage (1256)?
Code: Pascal  [Select][+][-]
  1. uses
  2.   lconvencoding;
  3.  
  4.   // in the demo code:
  5.   ImgCanvas.TextOut(10, 30, UTF8ToCP1256('فارسی'));
  6.  

Will not work, because:
1- As I understood, the chosen glyph depends on the letter before and the letter after.
2- FreeType needs to use the same encoding you are passing, maybe by calling FT_Select_Charmap.
3- FreeType does not seem to have that encoding.

On top of that, it will not work when you need to add a third language like Hebrew beside English and Persian.

Edit:
The last image (win.png) in this post shows how the letters are going to be without considering previous/next letters.

Windows [XP?] by default does not support Arabic scripts without adding it.
« Last Edit: May 25, 2016, 06:01:12 pm by engkin »

Sanem

  • Full Member
  • ***
  • Posts: 173
Re: FPImage Font problem with Persian characters
« Reply #6 on: May 26, 2016, 10:03:21 am »
Hi
thank you all for your replay.
engkin, Im using windows10 OS, and i saw the post you gave its link,thank you, i tested canvas of form and it work fine for persian chars using LCL,as you can see in screen shot, but in this demo i dont wanna use LCL because my program is nogui, so i need FPImage canvas to write persian chars correctly, so its not what i want!
so if it wont work because even if FreeType supports (present, past, or future) Arabic scripts, TFontManager does not, do you have a suggestion to display persian text in a FPImge??
« Last Edit: May 26, 2016, 10:23:21 am by simin_sh »

Sanem

  • Full Member
  • ***
  • Posts: 173
Re: FPImage Font problem with Persian characters
« Reply #7 on: May 26, 2016, 10:10:56 am »
Wp
I tested what you suggest, by adding

Code: Pascal  [Select][+][-]
  1. ImgCanvas.TextOut(10, 30, UTF8ToCP1256('فارسی'));  
  2.  

 to my code, but as you can see in screenshot it does not work because it seems that chars are unknown yet! but at least it knows the number of chars correctly now!

Graeme

  • Hero Member
  • *****
  • Posts: 1428
    • Graeme on the web
Re: FPImage Font problem with Persian characters
« Reply #8 on: May 27, 2016, 09:54:42 am »
With AggPas (as found in the fpGUI repository) I can output the Persian text using a Console or GUI application. The problem is, it renders the glyphs wrong way round. I believe the string contains 5 characters, which the AggPas output shows. But maybe somebody with better Right-to-Left knowledge knows what to change to render it in the right direction.

note:
  AggPas included with fpGUI has more features and bug fixes than the AggPas
  included with Lazarus.

AggPas (part of fpGUI, but can be used stand-alone):
  https://github.com/graemeg/fpGUI/tree/develop/src/corelib/render/software
--
fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal
http://fpgui.sourceforge.net/

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: FPImage Font problem with Persian characters
« Reply #9 on: May 27, 2016, 06:46:40 pm »
AggPas has the same problem just like FreeType.

The first step to solve this problem would be to specify the correct glyph to be used based on its location in the text.

With the help of Character Map I think the first letter in the example presented in the OP is called: Arabic Letter Feh U+0641

Based on its location in the word and the surrounding letters, there are at lease four different glyphs:
Isolated Form U+FED1
Initial Form U+FED3 
Medial Form U+FED4
Final Form U+FED2

The correct glyph should be the Initial Form U+FED3

Graeme

  • Hero Member
  • *****
  • Posts: 1428
    • Graeme on the web
Re: FPImage Font problem with Persian characters
« Reply #10 on: May 27, 2016, 11:19:14 pm »
AggPas has the same problem just like FreeType.
What is puzzling is that I'm running FreeBSD (X11), and pretty much everything running in X11 uses FreeType for font rendering. eg: Viewing the original post - sample code - I see the correct text. Copying and pasting that code sample (text) into Mate's Pluma editor, OpenOffice, LibreOffice, Mate Terminal etc...  Everywhere the text is displayed correctly. All those applications use FreeType. So FreeType doesn't seem to be the cause of the problem. The issue must lie elsewhere.

I personally have no idea how Right-to-Left text works, and even more so when Right-to-Left text is mixed with Left-to-Right text. For example:

Code: Pascal  [Select][+][-]
  1. BiDiText = {
  2.   'H', //index 0
  3.   'e', //index 1
  4.   'l', //index 2
  5.   'l', //index 3
  6.   'o', //index 4
  7.   '<hebrew char 1>' //index 5
  8.   '<hebrew char 2>' //index 6
  9.   '<hebrew char 3>' //index 7
  10.   ' ', //index 8
  11.   'W', //index 9
  12.   'o', //index 10
  13.   'r', //index 11
  14.   'l', //index 12
  15.   'd' } //index 13
  16.  

Somewhere, some software needs to step through the text stored in the BiDiText variable. It needs to look at each character, and decide the display order. The display order might look like so (using index numbers):

Code: Pascal  [Select][+][-]
  1. 0 1 2 3 4 7 6 5 8 9 10 11 12 13

So what tells the software that the display order needs to change? Is it the Unicode codepoint value (falling in a range of codepoints in the BMP known to be Right-to-Left)? Is there an embedded Unicode codepoint stored in the text that tell you to change direction (I know about Left-to-Right-Mark which is U+200E, Left-To-Right-Embedding is U+202A, Left-to-Right-Override is U+202D)?

As I said, I don't know how BiDi works at all, but I'm very interested to find out.
--
fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal
http://fpgui.sourceforge.net/

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: FPImage Font problem with Persian characters
« Reply #11 on: May 28, 2016, 05:41:11 am »
AggPas has the same problem just like FreeType.
What is puzzling is that I'm running FreeBSD (X11), and pretty much everything running in X11 uses FreeType for font rendering. eg: Viewing the original post - sample code - I see the correct text. Copying and pasting that code sample (text) into Mate's Pluma editor, OpenOffice, LibreOffice, Mate Terminal etc...  Everywhere the text is displayed correctly. All those applications use FreeType. So FreeType doesn't seem to be the cause of the problem. The issue must lie elsewhere.

FreeType is not the cause of the problem. FreeType is able of rendering individual glyphs and a few languages, but it does not support Arabic. It is stated in their website:
Quote
but not other complex scripts like Arabic.

Some of the applications mentioned in your post are using using HarfBuzz:
Quote
Harfbuzz is used directly by graphic rendering libraries such as Pango, and the layout engines in Firefox, LibreOffice and Chromium.
Harfbuzz can render glyphs using FreeType or its own implementation.

So what tells the software that the display order needs to change? Is it the Unicode codepoint value (falling in a range of codepoints in the BMP known to be Right-to-Left)?

Naturally yes. But that could be changed using control characters.

Is there an embedded Unicode codepoint stored in the text that tell you to change direction (I know about Left-to-Right-Mark which is U+200E, Left-To-Right-Embedding is U+202A, Left-to-Right-Override is U+202D)?

Control characters are not used usually. Their usage is to break the rules, like writing an English word from right to left.

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: FPImage Font problem with Persian characters
« Reply #12 on: May 28, 2016, 05:49:58 am »
do you have a suggestion to display persian text in a FPImge??

HarfBuzz comes with 32bit dlls if you don't mind being limited to 32bit and writing your own bindings. Another possibility, if you don't care about cross platform, to use Windows API.

Sanem

  • Full Member
  • ***
  • Posts: 173
Re: FPImage Font problem with Persian characters
« Reply #13 on: May 28, 2016, 12:00:39 pm »
I dont know how to use harfbuzz in my lazarus project, and i didnt find any sample of using harfbuzz in lazarus project all over the net where i searched, if its possible i wanna ask you to show me some sample codes or rifferences for work with harfbuzz in fpc.
thank you so much

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: FPImage Font problem with Persian characters
« Reply #14 on: May 28, 2016, 03:05:03 pm »
Here is the simplest way:
Code: Pascal  [Select][+][-]
  1. program project1;
  2. {$codepage UTF8}
  3.  
  4. {
  5. Based on:
  6. https://codeload.github.com/bert/262331/zip/b30b437b73ba054d69298aee7d73a5547126e7c7
  7. }
  8. uses
  9.   cairo, pango, pangocairo, sysutils;
  10.  
  11. var
  12.   cr: Pcairo_t;
  13.   filename: pchar ;
  14.   status: cairo_status_t ;
  15.   surface: Pcairo_surface_t;
  16.   layout: PPangoLayout;
  17.   desc: PPangoFontDescription;
  18.   ink: PPangoRectangle;
  19.   logical: PPangoRectangle;
  20.   width: PLongint;
  21.  
  22.   iWidth:LongInt;
  23.   Str, sWrap: string;
  24.  
  25. begin
  26.     if (argc <> 4) then
  27.     begin
  28.       WriteLn('Usage: pangocairo STRING WIDTH WRAP_MODE');
  29.       WriteLn('Using default values');
  30.       str := 'Just one more test اللغة العربية';
  31.       iWidth := 100;
  32.       sWrap := 'word';
  33.     end
  34.     else
  35.     begin
  36.       str := argv[1];
  37.       iWidth := StrToInt(argv[2]);
  38.       sWrap := argv[3];
  39.     end;
  40.  
  41.     { Create surface and clear to all-white. }
  42.     surface := cairo_pdf_surface_create ('foo.pdf', 200, 200);
  43.     cr := cairo_create (surface);
  44.     cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
  45.     cairo_paint (cr);
  46.  
  47.     { Create Pango layout. }
  48.     layout := pango_cairo_create_layout (cr);
  49.     desc := pango_font_description_from_string ('Sans 12');
  50.  
  51.     { Changing font/style examples }
  52.     //desc := pango_font_description_from_string ('Sans 40px');
  53.     //desc := pango_font_description_from_string ('Sans Bold 12');
  54.     //desc := pango_font_description_from_string ('Times New Roman 12');
  55.  
  56.     pango_layout_set_font_description (layout, desc);
  57.     pango_font_description_free (desc);
  58.     pango_layout_set_text (layout, @str[1], -1);
  59.     { Set Pango options according to command line. }
  60.     pango_layout_set_width (layout, iWidth);
  61.     if (CompareStr(sWrap, 'word')=0) then
  62.         pango_layout_set_wrap (layout, PANGO_WRAP_WORD)
  63.     else if (CompareStr(sWrap, 'char')=0) then
  64.         pango_layout_set_wrap (layout, PANGO_WRAP_CHAR)
  65.     else if (CompareStr(sWrap, 'word-char')=0) then
  66.         pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR)
  67.     else
  68.     begin
  69.       WriteLn('WRAP_MODE must be ''word'' or ''char'' or ''word-char''');
  70.       exit;
  71.     end;
  72.  
  73.     { Draw layout. }
  74.     cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
  75.     cairo_move_to (cr, 0, 0);
  76.     pango_cairo_show_layout (cr, layout);
  77.  
  78.     { Print various sizes. }
  79.     pango_layout_get_size (layout, width, nil);
  80.     if width<>nil then
  81.       writeln(format('size: width=%d', [width^]));
  82.  
  83.     pango_layout_get_extents (layout, ink, logical);
  84.     if (ink<>nil) and (logical<>nil) then
  85.       writeln(format('extents: ink width=%d, logical width=%d', [ink^.width, logical^.width]));
  86.  
  87.     pango_layout_get_pixel_extents (layout, ink, logical);
  88.     if (ink<>nil) and (logical<>nil) then
  89.       writeln(format('pixel extents: ink width=%d, logical width=%d',[ink^.width, logical^.width]));
  90.  
  91.     { Clean up. }
  92.     //g_object_unref (layout);
  93.     cairo_destroy (cr);
  94.     cairo_surface_finish (surface);
  95.     status := cairo_surface_status (surface);
  96.     cairo_surface_destroy (surface);
  97.     if (status <> CAIRO_STATUS_SUCCESS) then
  98.     begin
  99.       writeln(format('Could not save pdf to %s', [filename]));
  100.       exit;
  101.     end;
  102. end.

 

TinyPortal © 2005-2018