3
votes

I rendering text to bitmap using WPF. I would like to turn off anti-aliasing, I mean I want the pixels be white or black. But the text is still blured, some pixels are even grey.

Here is my code. Some lines are probably not needed.

RenderTargetBitmap bm = new RenderTargetBitmap(bitmapWidth, bitmapHeight, dpiX, dpiY, PixelFormats.Pbgra32);

DrawingVisual drawing_visual = new DrawingVisual();

RenderOptions.SetEdgeMode(drawing_visual, EdgeMode.Unspecified);            
RenderOptions.SetBitmapScalingMode(drawing_visual, BitmapScalingMode.Linear);

RenderOptions.SetEdgeMode(bm, EdgeMode.Unspecified);
RenderOptions.SetBitmapScalingMode(bm, BitmapScalingMode.Linear);

DrawingContext drawing_context = drawing_visual.RenderOpen();            

FormattedText ft = new FormattedText("my text", CultureInfo.InvariantCulture, System.Windows.FlowDirection.LeftToRight, typeface, fontSize, Brushes.Black);
        drawing_context.DrawText(ft, new Point(0, 0));

drawing_context.Close();
bm.Render(drawing_visual); 

Rendered image:

blured image

To check the solution, you can download source code from GitHub:

https://github.com/qub1n/Font-rendering.git
2
Text deserves special treatment with WPF. Maybe you should try TextOptions.TextFormattingMode and/or TextRenderingMode instead: blogs.msdn.microsoft.com/text/2009/08/24/…Simon Mourier
TextFormattingMode didn't solved it and TextRenderingMode does not contains setting without anti-aliasing.Tomas Kubes
Are you interested by screen visualization or bitmap (file like .png) creation? They are quite different.Simon Mourier
Especially in bitmap, I want to export it.Tomas Kubes
How about setting EdgeMode to Aliased?l33t

2 Answers

3
votes

The important notion here is the TextRenderingMode. It's logical, since you don't want anti-aliased text, you must set the TextRenderingMode to Aliased. The difficulty is where to put it...

I recommend you create a DrawingImage instead, like this, as the start object (use it as your canvas source, instead of a bitmap):

    public static DrawingImage CreateImage(int heightPixel, Typeface typeface, double fontSize, string text)
    {
        var group = new DrawingGroup();
        using (var context = group.Open())
        {
            var ft = new FormattedText(text, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, typeface, fontSize, Brushes.Black, null,
                TextFormattingMode.Display); // this is the important line here!
            context.DrawText(ft, new Point(0, 0));
        }

        return new DrawingImage(group);
    }

Note the also important TextFormattingMode value set to Display. If you don't do this and keep the default value (Ideal), then you'll still have anti-aliasing.

Now, for rendering on the display, you will have to use TextRenderingMode on a Visual element, so in your example, on your canvas element:

    <controls:ImageCanvas ... TextOptions.TextRenderingMode="Aliased" ... />

and for rendering on a bitmap, you'll have to create an intermediary Visual, here an Image object, so you can apply the TextRenderingMode on it:

    public static void SaveToFile(string filePath, DrawingImage drawing)
    {
        var image = new Image { Source = drawing };
        image.Arrange(new Rect(new Size(drawing.Width, drawing.Height)));

        // this is the important line here!
        TextOptions.SetTextRenderingMode(image, TextRenderingMode.Aliased);

        // note if you use a different DPI than the screen (96 here), you still will have anti-aliasing
        // as the system is pretty automatic anyway
        var bitmap = new RenderTargetBitmap((int)drawing.Width, (int)drawing.Height, 96, 96, PixelFormats.Pbgra32);
        bitmap.Render(image);

        using (var fileStream = new FileStream(filePath, FileMode.Create))
        {
            var encoder = new PngBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(bitmap));
            encoder.Save(fileStream);
        }
    }
0
votes

It turns out that setting TextOptions.SetTextRenderingMode() on drawinVisual does not work. Accepted answer still has aliasing issues in the bitmap generated (it's better with TextFormattingMode.Display but still not exactly unaliased).

What worked for me was setting internal property on drawing visual:


    var visual = new DrawingVisual();
    var property = typeof(Visual).GetProperty("VisualTextRenderingMode", 
                BindingFlags.NonPublic | BindingFlags.Instance);

    property.SetValue(visual, TextRenderingMode.Aliased);