2009-05-11 23 views
7

Si uso TextRenderer.DrawText() utilizando el objeto Graphics proporcionado en OnPaintBackground, mi texto se ve perfecto. Si creo mi propio mapa de bits y uso el objeto Graphics obtenido de mi mapa de bits mi texto se ve terrible. Parece que está suavizando el texto con negro, no el color de fondo del mapa de bits. Puedo evitar este problema si uso Graphics.DrawString(), pero este método tiene problemas de kerning horribles. ¿Que debería hacer? ¿Cómo puedo obtener TextRenderer.DrawText() para anti-alias correctamente utilizando los contenidos de Bitmap?TextRenderer.DrawText en mapa de bits vs OnPaintBackground

ve terrible:

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); 
} 

Se ve bien, pero quiero hacer esto en un mapa de bits, NO sobre la superficie del control:

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); 
} 

¿Cuál es la diferencia?

Respuesta

9

La respuesta no es utilizar TextRenderer. TextRenderer es un contenedor para la implementación de GDI (no GDI +) de la representación de texto, que tiene muchas características, pero no interopera bien con los DC en memoria como usted ha descubierto.

Use Graphics.DrawString & Graphics.MeasureString, pero recuerde pasarlo StringFormat.GenericTypographic para obtener el tamaño y el posicionamiento precisos.

El motivo por el cual TextRenderer se introdujo inicialmente fue que GDI + no admitía todas las secuencias de comandos complejas que el motor Uniscribe de GDI. Con el tiempo, sin embargo, el soporte de GDI + para scripts complejos se ha ampliado, y en estos días no quedan razones buenas para usar TextRenderer (ni siquiera es el más rápido de los dos, de hecho aparece todo lo contrario).

Realmente, sin embargo, a menos que se encuentre con problemas de rendimiento graves y medibles, simplemente use Graphics.DrawString.

+0

'TextRenderer faster' ?? ¿Estás seguro? Este artículo dice que es más lento que GDI +: http://theartofdev.com/2014/04/21/text-rendering-methods-comparison-or-gdi-vs-gdi-revised/ – qakmak

+0

@qakmak Fue [hace 9 años ] (http://blogs.msdn.com/b/cjacks/archive/2006/05/19/602021.aspx) pero supongo que puede haber cambiado. El código del artículo al que se vincula muestra 'DrawString' para que sea mucho más rápido en mi máquina también. –

-1

Si su mapa de bits no es del mismo tamaño que su área de visualización, podría tratarse simplemente de un problema de redimensionamiento, donde .NET adapta el mapa de bits al tamaño de visualización y obtiene un texto de aspecto gracioso.

¿Se puede probar con un mapa de bits creado con el mismo tamaño que el área de visualización?

+0

Ambos son del mismo tamaño y DPI. –

+0

Supongo que como los mapas de bits no tienen transparencia incorporada, puede intentar usar una clase de imagen diferente como su lienzo en memoria. El Color.Transparent probablemente se interprete como Color.Black en este caso. ¿Vale la pena intentarlo? – Mike

+0

Lo he intentado usando Image o Bitmap, y usando una variedad de diferentes PixelFormats. El verdadero problema es que TextRenderer no está suavizando el texto con lo que está en el mapa de bits, sino con el color negro (por alguna razón). –

-1

¿Puedes publicar el programa más pequeño que tenga este problema? Yo no podrá reproducirla como esto - el antialiasing se ve bien:

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); 
    } 
} 
+2

Intente agregar esta línea: g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; Además, si usa "Color.LightBlue" como fondo, el problema es mucho más visible. Es el texto antialiasing lo que lo arruina. –

+0

Además, no importa si "Application.SetCompatibleTextRenderingDefault (false);" está configurado como verdadero o falso. –

0

Otra posible solución: dibuje todo en la pantalla, mapa de bits con texto en la parte superior, y luego escriba un código para 'capturar la pantalla' esa parte de la pantalla. No es práctico en todos los casos, pero tiene razón, DrawString crea texto extraño y DrawText en un mapa de bits se ve horrible.

3

Creo que el problema es que la representación de texto de tipo claro no funciona si el fondo es transparente. Algunas posibles soluciones

Opción 1. Llene el fondo de su mapa de bits con un color.

Si hace esto (como hizo Tim Robinson arriba en su ejemplo de código usando g.Clear (Color.Red)), el tipo claro hará lo correcto. Pero su mapa de bits no será completamente transparente, lo que podría no ser aceptable. Si usa Graphics.MeasureText, puede completar solo el rectángulo alrededor de su texto, si lo desea.

Opción 2. Conjunto TextRenderingHint = TextRenderingHintAntiAliasGridFit

Esto parece desactivar Tipo clara. El texto se representará con una calidad inferior a la del tipo claro en un fondo, pero mucho mejor que el tipo de desorden sin ningún fondo.

Opción 3. Rellene el rectángulo de texto con blanco, dibuje el texto y luego encuentre todos los píxeles que no sean de texto y vuelva a ponerlos en transparente.

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); 
       } 
      } 
     } 
    } 
} 

Lo sé, es un hack horrible, pero parece que funciona.

Cuestiones relacionadas