4

We are working on an Optical Character Recognition system and i want to compare how different renderers render text. I want to make a simple program that creates an image, writes some text on it with different fonts, sizes and styles and saves it to a .png file(I want to have all sizes, fonts styles i need in one file so they are easy to compare). I've managed to do it with GDI and GDI+ renderers using Bitmap. Now i'm trying to do the same thing in a WPF application, as I've heard rendering text there is different. Is it possible to use BitmapImage for that? Coming from Windows Forms I presume this problem should be pretty simple but i just can't seem to do it in WPF.

This is a simplified version of how i did it with GDI+ Renderer:

public void CreateAndSave()
{
    Bitmap bitmap = new Bitmap(500, 500, PixelFormat.Format24bppRgb);
    Graphics g = Graphics.FromImage(bitmap);
    g.Clear(Color.White);
    g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
    g.DrawString("sample text", font, brush, x, y);
    bitmap.Save(fileName);
}

Is there any similar way of doing this with WPF?

Kuczi
  • 357
  • 4
  • 18

2 Answers2

3

Such as methods like "DrawString" are costly in WPF. Instead of that doing that, you can create a canvas/grid and put the text box or labels etc. and then you can render that canvas/grid. You can use that code:

public void ConvertToBitmapSource(UIElement element)
{
    var target = new RenderTargetBitmap(
        (int)element.RenderSize.Width, (int)element.RenderSize.Height,
        96, 96, PixelFormats.Pbgra32);
    target.Render(element);

    var encoder = new PngBitmapEncoder();
    var outputFrame = BitmapFrame.Create(target);
    encoder.Frames.Add(outputFrame);

    using (var file = File.OpenWrite("TestImage.png"))
    {
        encoder.Save(file);
    }
}
Ugur
  • 1,257
  • 2
  • 20
  • 30
  • 1
    Thank you for your answer. This idea might work. The problem i have now is that i want a .png with a lot of different fonts and sizes and i would have to create a lot of labels to do that. Also when i use this method the text rendered in the .png is not the same as on the actual running application. That might be caused by the background being transparent. Is there a quick way of setting the background color of RenderTargetBitmap to white, or do i have to set every bit to white? – Kuczi Jul 27 '16 at 09:51
  • One way to that if you use a grid/canvas as UIElement, try to set the background of it as White. It will work – Ugur Jul 27 '16 at 10:00
  • I changed the background to white, but it appears that the background wasn't causing bad quality of text. Maybe if it renders the whole element onto a RenderTargetBitmap it doesn't care about how the text was rendered earlier. I also tried to use this method on a single label but it still isn't doing it. – Kuczi Jul 27 '16 at 10:27
  • So text quality depends on also resolution and dpi. You can arrange them but file size will be greater – Ugur Jul 27 '16 at 10:54
  • I set the dpi to 120 to match my systems dpi and its acceptably similar to the original. Thank you for help. – Kuczi Jul 27 '16 at 12:11
  • I have one more question. Is it possible to set where the element will be rendered on RenderTargetBitmap? – Kuczi Jul 27 '16 at 13:22
  • Yes it is possible. You can use such a code: var crop = new CroppedBitmap(target , new Int32Rect(50, 50, 250, 250)); BitmapEncoder pngEncoder = new PngBitmapEncoder(); pngEncoder.Frames.Add(BitmapFrame.Create(crop)); – Ugur Jul 27 '16 at 14:02
  • This only lets me choose which part of bitmap i'm saving. What I want to do is to have one big bitmap and save multiple UI elements next to each other on it. I want to make a bitmap with rendered labels, then change those labels and render them on that bitmap next to the previous ones so i can see the differences. – Kuczi Jul 28 '16 at 08:11
  • Check that for example answer code. You can add many frames encoder.Frames.Add(outputFrame); – Ugur Jul 28 '16 at 08:14
0

Use the FormattedText class to build a Geometry object, take an example from here: https://msdn.microsoft.com/en-us/library/system.windows.media.formattedtext.buildgeometry(v=vs.110).aspx

Then, use one of the BitmapEncoder classes to save the Geometry object you've built. Look at that example: https://stackoverflow.com/a/9081295/3730455

Community
  • 1
  • 1
OrMiz
  • 265
  • 2
  • 11