Search code examples
c#c++directxsharpdxdirectwrite

SharpDx: Setting character width


I am writing a C# Direct2D application using SharpDX, however I can understand answers/examples that are provided in C++.

I want to render text and change the width of certain characters to look like the picture:

enter image description here

The letter B expanded to 200% and the letter D is reduced to 50%

In the code below I draw the geometry of the glyphs And so it is possible to change the width of geometry But that's not a good solution, because a geometry drawing comes out as blurred as you see in the picture.

enter image description here

In conclusion, there are two questions:

  1. How I change the width of the characters?

  2. How to draw geometries of letters without blurring. (it is possible to render geometry with ClearType?)

    private void RenderGlyphRun1(FontFace1 fontFace)
    {
        var Offsets = new List<GlyphOffset>();
        var fontEmSize_ = 12;
        GlyphRun glyphRun = new GlyphRun();
        glyphRun.FontFace = fontFace;
        glyphRun.FontSize = fontEmSize_;
        glyphRun.BidiLevel = 1;
        var left = 650f;
        var top = 50f;
    
        var baseLine = (float)(fontFace.Metrics.LineGap + fontFace.Metrics.Ascent) /
            fontFace.Metrics.DesignUnitsPerEm * glyphRun.FontSize;
    
        string textToDraw = "ABCDE";
        foreach (char letter in textToDraw)
        {
            Offsets.Add(new GlyphOffset());
        }
    
        var charArr = textToDraw.Select(x => (int)x).ToArray();
        glyphRun.Indices = fontFace.GetGlyphIndices(charArr);
    
        var metrics = fontFace.GetDesignGlyphMetrics(glyphRun.Indices, false);
        glyphRun.Advances = metrics.Select(x => (float)x.AdvanceWidth /
                 fontFace.Metrics.DesignUnitsPerEm * glyphRun.FontSize).ToArray();
    
        glyphRun.Offsets = Offsets.ToArray();
    
        RenderTarget2D.BeginDraw();
        RenderTarget2D.Clear(SharpDX.Color.White);
    
        RenderTarget2D.DrawGlyphRun(new Vector2(left, top),
            glyphRun, new SharpDX.Direct2D1.SolidColorBrush(RenderTarget2D, SharpDX.Color.Black),
            MeasuringMode.Natural);
    
        top += baseLine;
    
        var pathGeometry = new PathGeometry(Factory2D);
        var geometrySink = pathGeometry.Open();
    
        fontFace.GetGlyphRunOutline(glyphRun.FontSize, glyphRun.Indices,
            glyphRun.Advances, glyphRun.Offsets, glyphRun.IsSideways,
            glyphRun.BidiLevel % 2 != 0, geometrySink);
    
        geometrySink.Close();
        geometrySink.Dispose();
        fontFace.Dispose();
    
        var matrix = new Matrix3x2()
        {
            M11 = 1,
            M12 = 0,
            M21 = 0,
            M22 = 1,
            M31 = left,
            M32 = top
        };
    
        var transformedGeometry = new TransformedGeometry(Factory2D, pathGeometry, matrix);
        var brushColor = (Color4)SharpDX.Color.Black;
        var brush = new SolidColorBrush(RenderTarget2D, brushColor);
        RenderTarget2D.FillGeometry(transformedGeometry, brush);
    
        pathGeometry.Dispose();
        transformedGeometry.Dispose();
        brush.Dispose();
    
        RenderTarget2D.EndDraw();
    }       
    

Solution

  • Since some of the letters should be narrow and some are normal and some are wide, you can not use one GlyphRun, but must create 3 different GlyphRun.

    To cause all letters of any GlyphRun to be wide or narrow:

    1. Configure Transform to RenderTarget
    2. Draw the GlyphRun
    3. Return the original Transform

    Wide transform: RenderTarget2D.Transform = new SharpDX.Mathematics.Interop.RawMatrix3x2(1.5f, 0, 0, 1, 0, 0);

    Narrow transform: RenderTarget2D.Transform = new SharpDX.Mathematics.Interop.RawMatrix3x2(0.5f, 0, 0, 1, 0, 0);

    After this solution you do not need to convert GlyphRun to geometry and get mixed up with blurred letters.