5

I want to use Glyph to render right-to-left languages text (e.g. Arabic or mix English and Arabic).

I'm using this code:

    Typeface typeface = new Typeface(new FontFamily("Arial"),
                      FontStyles.Italic,
                      FontWeights.Normal,
                      FontStretches.Normal);

       GlyphTypeface glyphTypeface;
       if (!typeface.TryGetGlyphTypeface(out glyphTypeface))
           throw new InvalidOperationException("No glyphtypeface found");

       string text = "Hello  ,  سلام";
       double size = 40;

       ushort[] glyphIndexes = new ushort[text.Length];
       double[] advanceWidths = new double[text.Length];

       double totalWidth = 0;

       for (int n = 0; n < text.Length; n++)
       {
           ushort glyphIndex = glyphTypeface.CharacterToGlyphMap[text[n]];
           glyphIndexes[n] = glyphIndex;

           double width = glyphTypeface.AdvanceWidths[glyphIndex] * size;
           advanceWidths[n] = width;

           totalWidth += width;
       }

       Point origin = new Point(50, 50);

       GlyphRun glyphRun = new GlyphRun(glyphTypeface, 0, false, size,
           glyphIndexes, origin, advanceWidths, null, null, null, null,
           null, null);

       dc.DrawGlyphRun(Brushes.Black, glyphRun);

But the problem is that Arabic characters are shown separately, like this:

 Hello  ,  س ل ا م

please guide me

------------------------------------------------------

UPDATE:

This is result of Obfuscate's solution: image1

The problem is that the Arabic letters are rendered separately.

But this is what I want: image2

Maria
  • 344
  • 8
  • 30
  • Might have to break into two strings since one is LRT and the other is RTL – codebender Nov 25 '17 at 22:17
  • Why do you need to use Glyphs in the first place? Maybe you're working in too low a lever instead of harnessing some higher-level facility to render text? Do WPF controls render the text OK in the first place? – George Birbilis Nov 26 '17 at 16:33
  • @George , I need to use Glyphs because performance.(the above code is a small sample) , I've found [this great Github project to test of all WPF text rendering approaches ](https://github.com/dgrunwald/WPF-Text-Rendering-Benchmark) and I realized that Glyph is what I need. – Maria Nov 26 '17 at 18:30
  • @George و The problem is only when I use the Glyphs. Arabic text working properly with Textblock , Textbox ,Textline and Formatedtext . – Maria Nov 26 '17 at 18:49
  • So an idea could be to check if Silverlight controls show that text ok. Then if they do work ok in Silverlight, see if Moonlight also does show that ok (the opensource clone of Silverlight - never got up to version 5 though - from the Mono project). Then if it works at Moonlight checkout the source code at https://github.com/mono/moon to see how they do it (guess they don't pass it on to the OS, but implement it themselves). Unfortunately there was no WPF for Mono, only some XAML stuff / WindowsBase - see http://www.mono-project.com/docs/gui/wpf/ in case that stuff is helpful – George Birbilis Nov 28 '17 at 22:57
  • However, I think the issue is that you try to render glyphs one by one, so the system doesn't know to combine them. Is there a possibility that some of those functions get an array (via overloaded methods) instead of a single item? – George Birbilis Nov 28 '17 at 22:59
  • Does this work (pure XAML sample)? https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/draw-text-using-glyphs - I see that a whole string is passed in for display – George Birbilis Nov 28 '17 at 23:04
  • Also, TextFormatter and TextLine combination from https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/advanced-text-formatting looks promising – George Birbilis Nov 28 '17 at 23:07
  • Also read http://www.silverlightrecipes.com/2009/02/displaying-arabic-text-in-silverlight.html and then see if you can reuse code from http://silverlightrtl.codeplex.com/ and checkout the libraries its home page mentions (mind this comment "The drawback of this approach is that currently optional ligature is not implemented, the only ligature available now is the mandatory Lam-Alef ligature. Also Tashkeel characters is not displayed correctly because Silverlight will display the Tashkeel glyph beside the affected glyph and not over or under it. Arabic-Indic numbers are not supported yet too.") – George Birbilis Nov 28 '17 at 23:40
  • @George, Thank you very much for your suggestions and explanations, I'll try them out. – Maria Nov 29 '17 at 09:35

1 Answers1

2

Try formatting two strings with different CultureInfo

string x = string.Format(new CultureInfo("en-US"), "{0}" ,text1);
string y = string.Format(new CultureInfo("ar-SA"), "{0}", text2);

Updated with solution... The xaml has a Canvas.

<Window x:Class="StackOverflowCS.MainWindow"
        Title="MainWindow" Height="600" Width="800">
    <Grid>
        <Canvas Name="MyCanvas" Height="600"  Width="800"/>
    </Grid>
</Window>

The MainWindow (WPF)

   public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            Size s = new Size(200,50);
            GlyphElement gex = new GlyphElement(
               string.Format(new CultureInfo("en-US"), "{0}", "Hello"), Brushes.Red, s);
            MyCanvas.Children.Add(gex);
            Canvas.SetTop(gex, 10);
            Canvas.SetLeft(gex, 10);

            GlyphElement gey = new GlyphElement(
               string.Format(new CultureInfo("ar-SA"), "{0}", "سلام"), Brushes.Black, s);
            MyCanvas.Children.Add(gey);
            Canvas.SetTop(gey, 100);
            Canvas.SetLeft(gey, 10);
        }
    }

Wrap the GlyphElement in a FrameworkElement

    class GlyphElement : FrameworkElement
    {
        private GlyphRunner gr;
        public GlyphElement(string text, Brush br, Size size) { gr = new GlyphRunner(text, br, size); }
        protected override Visual GetVisualChild(int index) { return gr; }
        protected override int VisualChildrenCount { get { return 1; } }
    }

Wrap the GlyphRunner in a DrawingVisual

    public class GlyphRunner : DrawingVisual
    {
        public GlyphRunner(string text, Brush bc, Size size)
        {
            DrawingImage di = CreateGlyph(text, new Point(0, 0), bc);
            using (DrawingContext dc = RenderOpen())
            {
                dc.DrawImage(di,new Rect(size));
            }
        }

        // small updates to your code follow     
        public DrawingImage CreateGlyph(string text, Point origin, Brush bc)
        {
            Typeface typeface = new Typeface(new FontFamily("Arial"),
                                 FontStyles.Normal,
                                 FontWeights.Normal,
                                 FontStretches.Normal);

            GlyphTypeface glyphTypeface;
            if (!typeface.TryGetGlyphTypeface(out glyphTypeface))
                throw new InvalidOperationException("No glyphtypeface found");

            ushort[] glyphIndexes = new ushort[text.Length];
            double[] advanceWidths = new double[text.Length];

            double totalWidth = 0;

            for (int n = 0; n < text.Length; n++)
            {
                ushort glyphIndex = glyphTypeface.CharacterToGlyphMap[text[n]];
                glyphIndexes[n] = glyphIndex;

                double width = glyphTypeface.AdvanceWidths[glyphIndex];
                advanceWidths[n] = width;

                totalWidth += width;
            }

            float ppd = (float)VisualTreeHelper.GetDpi(this).PixelsPerDip;
            GlyphRun gr =  new GlyphRun(glyphTypeface, 0, false, 1.0, ppd, glyphIndexes, origin, advanceWidths, null, null, null, null, null, null);
            GlyphRunDrawing glyphRunDrawing = new GlyphRunDrawing(bc, gr);
            return new DrawingImage(glyphRunDrawing);
        }

    }
codebender
  • 469
  • 1
  • 6
  • 23
  • Thanks for the reply , but the BidiLevel only affected on direction like this : if it set to 0 : م ا ل س , if it set to 1 or more : س ل ا م , But my problem is that characters are shown separately, Arabic characters should be like this : سلام – Maria Nov 25 '17 at 22:31
  • also I used XmlLanguage flag (the last parameter) but not affected. – Maria Nov 25 '17 at 22:32
  • I've tested it on a WPF Canvas in the updated answer. – codebender Nov 26 '17 at 01:36
  • I'v tested your code, but unfortunately Its result was not what I want. ,But anyway, thank you very much, +1 for your help – Maria Nov 26 '17 at 10:27
  • I will start bounty tomorrow. – Maria Nov 26 '17 at 10:41
  • Weird, that's not how mine displays. Maybe it's related to the Windows language pack being used on your system? – codebender Nov 26 '17 at 15:12