TextRenderer.DrawText в растровом изображении против OnPaintBackground - PullRequest
7 голосов
/ 11 мая 2009

Если я использую TextRenderer.DrawText () с использованием объекта Graphics, предоставленного в OnPaintBackground, мой текст выглядит идеально. Если я создаю свое собственное растровое изображение и использую объект Graphics, полученный из моего растрового изображения, мой текст выглядит ужасно. Похоже, что это сглаживание текста, используя черный, а не цвет фона растрового изображения. Я могу избежать этой проблемы, если использую Graphics.DrawString (), но этот метод имеет ужасные проблемы с кернингом. Что я должен делать? Как правильно получить TextRenderer.DrawText () для сглаживания, используя содержимое растрового изображения?

Выглядит ужасно:

Bitmap bmp = new Bitmap(100, 100, PixelFormat.Format32bppArgb);
using (Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.Red);
TextFormatFlags tf = TextFormatFlags.Left;
TextRenderer.DrawText(g, @"C:\Development\Testing\blag", font, clip, Color.White, Color.Transparent, tf);
}

Выглядит хорошо, но я хочу сделать это на растровом изображении, а НЕ на поверхности элемента управления:

protected override void OnPaintBackground(PaintEventArgs e)
{
e.Graphics.Clear(Color.Red);
TextFormatFlags tf = TextFormatFlags.Left;
TextRenderer.DrawText(e.Graphics, @"C:\Development\Testing\blag", font, clip, Color.White, Color.Transparent, tf);
}

В чем разница?

Ответы [ 6 ]

9 голосов
/ 16 октября 2009

Ответ не использовать TextRenderer. TextRenderer - это оболочка для реализации рендеринга текста в GDI (не GDI +), которая имеет множество функций, но плохо взаимодействует с DC в памяти, как вы обнаружили.

Используйте Graphics.DrawString & Graphics.MeasureString, но не забудьте передать его StringFormat.GenericTypographic, чтобы получить точный размер и расположение.

Первоначально TextRenderer был представлен тем, что GDI + не поддерживал все сложные сценарии, которые сделал движок GDI Uniscribe. Со временем, однако, поддержка GDI + для сложных сценариев была расширена, и в наши дни не осталось никаких веских причин для использования TextRenderer (теперь это даже не самая быстрая из двух, на самом деле, как раз наоборот).

Действительно, хотя, если вы не сталкиваетесь с серьезными, измеримыми проблемами производительности, просто используйте Graphics.DrawString.

3 голосов
/ 16 июля 2010

Я считаю, что проблема в том, что рендеринг текста с открытым текстом не работает, если фон прозрачный. Несколько возможных решений.

Вариант 1. Заполните фон вашего растрового изображения цветом.

Если вы сделаете это (как это делал Тим Робинсон выше в своем примере кода с использованием g.Clear (Color.Red)), clear type будет работать правильно. Но ваше растровое изображение не будет полностью прозрачным, что может быть неприемлемо. Если вы используете Graphics.MeasureText, вы можете заполнить только прямоугольник вокруг текста, если хотите.

Вариант 2. Установите TextRenderingHint = TextRenderingHintAntiAliasGridFit

Похоже, что это отключает очистку типа. Текст будет отображаться с более низким качеством, чем на прозрачном шрифте на фоне, но намного лучше, чем текст с беспроблемным шрифтом на фоне, который не создается.

Вариант 3. Заполните текстовый прямоугольник белым, нарисуйте текст, а затем найдите все нетекстовые пиксели и верните их обратно в прозрачные.

using (Bitmap bmp = new Bitmap(someWidth, someHeight))
{
    using (Graphics g = Graphics.FromImage(bmp))
    {
        // figure out where our text will go
        Point textPoint = new Point(someX, someY);
        Size textSize = g.MeasureString(someText, someFont).ToSize();
        Rectangle textRect = new Rectangle(textPoint, textSize);

        // fill that rect with white
        g.FillRectangle(Brushes.White, textRect);

        // draw the text
        g.DrawString(someText, someFont, Brushes.Black, textPoint);

        // set any pure white pixels back to transparent
        for (int x = textRect.Left; x <= textRect.Left + textRect.Width; x++)
        {
            for (int y = textRect.Top; y <= textRect.Top + textRect.Height; y++)
            {
                Color c = bmp.GetPixel(x, y);
                if (c.A == 255 && c.R == 255 && c.G == 255 && c.B == 255)
                {
                    bmp.SetPixel(x, y, Color.Transparent);
                }
            }
        }
    }
}

Я знаю, это ужасный взлом, но похоже, что он работает.

2 голосов
/ 28 октября 2011

Ответ заключается в использовании BuffersGraphicsContext. Это та же система, которая используется внутри .NET при установке стиля ControlStyles.OptimizedDoubleBuffer для элемента управления.

См. http://msdn.microsoft.com/en-us/library/b367a457.aspx для получения дополнительной информации о двойной буферизации в .NET.

0 голосов
/ 09 апреля 2010

Другое возможное решение: нарисуйте все это на экране, растровое изображение с текстом сверху, а затем напишите некоторый код для «захвата экрана» этой части экрана. Практически не во всех случаях, но вы правы, DrawString создает странный текст, а DrawText на растровое изображение выглядит ужасно.

0 голосов
/ 12 мая 2009

Можете ли вы опубликовать самую маленькую программу, которая страдает от этой проблемы? Я не могу воспроизвести это так - сглаживание выглядит нормально:

    using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;

public class Program
{
    public static void Main()
    {
        Bitmap bmp = new Bitmap(100, 100, PixelFormat.Format32bppArgb);
        using (Font font = new Font("Arial", 10, GraphicsUnit.Point))
        using (Graphics g = Graphics.FromImage(bmp))
        {
            Rectangle clip = Rectangle.FromLTRB(0, 0, 100, 100);
            g.Clear(Color.Red);
            TextFormatFlags tf = TextFormatFlags.Left;
            TextRenderer.DrawText(g, @"C:\Development\Testing\blag", font, clip, Color.White, Color.Transparent, tf);
        }

        Form form = new Form();
        form.BackgroundImage = bmp;
        Application.Run(form);
    }
}
0 голосов
/ 11 мая 2009

Если размер вашего растрового изображения не совпадает с размером области отображения, это может быть просто проблемой изменения размера, когда .NET масштабирует растровое изображение до размера экрана, и вы получаете забавно выглядящий текст.

Можно ли выполнить тестирование с помощью растрового изображения, созданного с тем же размером, что и область отображения?

...