TextRenderer.DrawText в растровом изображении против OnPaintBackground
Если я использую 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 ответов
Ответ не использовать TextRenderer
, TextRenderer - это оболочка для реализации рендеринга текста с помощью GDI (не GDI+), которая имеет множество функций, но плохо взаимодействует с контроллерами домена в памяти, как вы обнаружили.
использование Graphics.DrawString
& Graphics.MeasureString
, но не забудьте передать его StringFormat.GenericTypographic, чтобы получить точный размер и расположение.
Первоначально TextRenderer был представлен тем, что GDI + не поддерживает все сложные сценарии, которые делает движок GDI Uniscribe. Однако со временем поддержка GDI + для сложных сценариев была расширена, и в наши дни не осталось никаких веских причин для использования TextRenderer (это уже не самая быстрая из двух, на самом деле, как раз наоборот).
Правда, если только вы не столкнетесь с серьезными, измеримыми проблемами производительности, просто используйте Graphics.DrawString
,
Я полагаю, что проблема в том, что рендеринг текста с открытым текстом не работает, если фон прозрачный. Несколько возможных решений.
Вариант 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);
}
}
}
}
}
Я знаю, это ужасный взлом, но, похоже, работает.
Ответ заключается в использованииBuffersGraphicsContext
, Это та же система, которая используется внутри.NET при установке ControlStyles.OptimizedDoubleBuffer
стиль на контроле.
См. http://msdn.microsoft.com/en-us/library/b367a457.aspx для получения дополнительной информации о двойной буферизации в.NET.
Еще одно возможное решение: нарисуйте все это на экране, растровое изображение с текстом сверху, а затем напишите некоторый код для "захвата экрана" этой части экрана. Практически не во всех случаях, но вы правы, DrawString создает странный текст, а DrawText на растровое изображение выглядит ужасно.
Если размер вашего растрового изображения не совпадает с размером области отображения, это может быть просто проблемой изменения размера, когда.NET масштабирует растровое изображение до размера отображения, и вы получаете забавно выглядящий текст.
Можете ли вы проверить с помощью растрового изображения, созданного в том же размере, что и ваша область отображения?
Можете ли вы опубликовать самую маленькую программу, которая страдает от этой проблемы? Я не могу воспроизвести это так - сглаживание выглядит нормально:
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);
}
}