Graphics.DrawString vs TextRenderer.DrawText? Que puede ofrecer una mejor calidad

TextRenderer se basa en GDI y Graphics.DrawString se basa en GDI +. ¿Cuál de estas funciones puede entregar texto de mejor calidad al dibujar texto en una imagen?

Solo mis 2 centavos: siempre uso Graphics.DrawString, excepto cuando necesito hacer una pintura personalizada para mis controles (Windows Forms). Por ejemplo, en un cuadro de lista que tiene el conjunto OwnerDraw, si adjunto un controlador de eventos DrawItem que pinta completamente los elementos, incluido el texto del elemento. O en un control personalizado, tengo que pintarme a mí mismo.

En una aplicación que utiliza estilos visuales en un sistema operativo que lo admite y lo tiene habilitado, el texto dibujado con Graphics.DrawString parece “off” en comparación con el texto normal dibujado por otros controles. Esto parece ser principalmente debido a las diferencias en la forma en que se maneja (o no) “ClearType”, aunque no estoy seguro y no tengo documentos para respaldar esa afirmación. (Parece algo parecido a lo que hizo el texto en .Net 1.x o al cambiar FlatStyle de Standard a System y vv)

Solo en tales casos (la pintura de texto en Winforms controla) uso TextRenderer.DrawText para hacer que el texto se mezcle mejor con los otros controles.

Si “mezclar con los nativos” no es una de tus preocupaciones (lo que parece, ya que quieres dibujar en una imagen), iría por Graphics.DrawString. Además, si desea imprimir, debe hacerlo, ya que TextRenderer solo funciona en la pantalla (no en el canvas de la impresora).

Voy a publicar mi respuesta desde aquí , solo para que la información se transmita.


Hay dos formas de dibujar texto en .NET:

  • GDI + ( graphics.MeasureString y graphics.DrawString )
  • GDI ( TextRenderer.MeasureText y TextRenderer.DrawText )

En .NET 1.1, todo utilizó GDI + para la representación de texto. Pero hubo algunos problemas:

  • Hay algunos problemas de rendimiento causados ​​por la naturaleza algo apátrida de GDI +, donde los contextos del dispositivo se establecerían y luego se restauraría el original después de cada llamada.
  • Los motores de configuración para texto internacional se han actualizado muchas veces para Windows / Uniscribe y para Avalon (Windows Presentation Foundation), pero no se han actualizado para GDI +, lo que hace que el soporte de representación internacional para nuevos idiomas no tenga el mismo nivel de calidad.

Entonces sabían que querían cambiar el framework .NET para dejar de usar el sistema de renderizado de texto de GDI + y usar GDI . Al principio esperaban que simplemente pudieran cambiar:

 graphics.DrawString 

para llamar a la antigua API de DrawText lugar de GDI +. Pero no pudieron hacer que el ajuste y el ajuste del texto coincidan exactamente como lo hizo GDI + .

En Windows Forms 2.0, agregamos soporte para dibujar texto GDI. Al principio teníamos planes grandiosos de pinchar y pinchar en la API de DrawText de modo que pudiéramos hacer coincidir exactamente cómo funciona la API DrawString de GDI +. De hecho, creo que nos acercamos mucho, pero existen diferencias fundamentales en el ajuste de palabras y el espaciado de caracteres que, como simples consumidores de ambas API, Windows Forms no pudo resolver.

Así que ahora tenemos un problema: queremos cambiar a todos a las nuevas API de TextRenderer para que el texto se vea mejor, se localice mejor, se dibuje de forma más consistente con otros diálogos en el sistema operativo … … pero no queremos Romper a las personas que cuentan con la cadena de medidas GDI + para calcular dónde debe alinearse su texto.

Así que se vieron obligados a mantener los graphics.DrawString DrawString para llamar a GDI + (razones de compatibilidad; personas que llamaban a graphics.DrawString DrawString de repente se daría cuenta de que su texto no se ajustaba como solía hacerlo). Desde MSDN :

La clase TextRenderer basada en GDI se introdujo en .NET Framework 2.0 para mejorar el rendimiento, mejorar el texto y mejorar el soporte para fonts internacionales. En versiones anteriores de .NET Framework, la clase Graphics basada en GDI + se usaba para realizar todo el procesamiento de texto. GDI calcula el espaciado de caracteres y el ajuste de palabras de forma diferente a GDI +. En una aplicación de Windows Forms que utiliza la clase Graphics para representar texto, esto podría hacer que el texto de los controles que usan TextRenderer parezca diferente del otro texto en la aplicación. Para resolver esta incompatibilidad, puede establecer la propiedad UseCompatibleTextRendering en true para un control específico. Para establecer UseCompatibleTextRendering en true para todos los controles admitidos en la aplicación, llame al método Application.SetCompatibleTextRenderingDefault con un parámetro de true .

Se creó una nueva clase estática TextRenderer para envolver el renderizado de texto GDI. Tiene dos métodos:

 TextRenderer.MeasureText TextRenderer.DrawText 

Nota: TextRenderer es un envoltorio alrededor de GDI, mientras que graphics.DrawString sigue siendo un envoltorio alrededor de GDI +.


Luego estaba la cuestión de qué hacer con todos los controles .NET existentes, por ejemplo:

  • Label
  • Button
  • TextBox

Querían cambiarlos para usar TextRenderer (es decir, GDI), pero tenían que tener cuidado. Puede haber personas que dependen de que sus controles se dibujen como lo hicieron en .NET 1.1. Y así nació ” renderización de texto compatible “.

Por defecto, los controles en la aplicación se comportan como lo hicieron en .NET 1.1 (son ” compatibles “).

Desactiva el modo de compatibilidad llamando a:

 Application.SetCompatibleTextRenderingDefault(false); 

Esto hace que su aplicación sea mejor, más rápida y con mejor soporte internacional. Para resumir:

 SetCompatibleTextRenderingDefault(true) SetCompatibleTextRenderingDefault(false) ======================================= ======================================== default opt-in bad good the one we don't want to use the one we want to use uses GDI+ for text rendering uses GDI for text rendering graphics.MeasureString TextRenderer.MeasureText graphics.DrawString TextRenderer.DrawText Behaves same as 1.1 Behaves *similar* to 1.1 Looks better Localizes better Faster 

También es útil tener en cuenta la asignación entre GDI + TextRenderingHint y la calidad LOGFONT correspondiente utilizada para el dibujo de fonts GDI:

 TextRenderingHint mapped by TextRenderer to LOGFONT quality ======================== ========================================================= ClearTypeGridFit CLEARTYPE_QUALITY (5) (Windows XP: CLEARTYPE_NATURAL (6)) AntiAliasGridFit ANTIALIASED_QUALITY (4) AntiAlias ANTIALIASED_QUALITY (4) SingleBitPerPixelGridFit PROOF_QUALITY (2) SingleBitPerPixel DRAFT_QUALITY (1) else (egSystemDefault) DEFAULT_QUALITY (0) 

Muestras

Aquí hay algunas comparaciones de GDI + (graphics.DrawString) versos GDI (TextRenderer.DrawText) texto que rinde:

GDI + : TextRenderingHintClearTypeGridFit , GDI : CLEARTYPE_QUALITY :

enter image description here

GDI + : TextRenderingHintAntiAlias , GDI : ANTIALIASED_QUALITY :

enter image description here

GDI + : TextRenderingHintAntiAliasGridFit , GDI : no admitido, utiliza ANTIALIASED_QUALITY :

enter image description here

GDI + : TextRenderingHintSingleBitPerPixelGridFit , GDI : PROOF_QUALITY :

enter image description here

GDI + : TextRenderingHintSingleBitPerPixel , GDI : DRAFT_QUALITY :

enter image description here

DRAFT_QUALITY parece extraño que DRAFT_QUALITY sea ​​idéntico a PROOF_QUALITY , que es idéntico a CLEARTYPE_QUALITY .

Ver también

  • UseCompatibleTextRendering – Compatible con whaaaaaat?
  • Clasificando todo: una mirada rápida al TextRenderer de Whidbey
  • MSDN: Estructura de LOGFONT
  • AppCompat Guy: rendimiento de representación de texto GDI vs. GDI +
  • Texto GDI +, independencia de resolución y métodos de representación. O bien, ¿por qué mi texto se ve diferente en GDI + y en GDI?

Mi experiencia personal (solo conozco estas dos diferencias):

DrawString admite Alpha Channel, Anti Aliasing

TextRenderer admite Uniscribe

Voy a arrojar un código de prueba:

 class Form1: Form { private string str = "hello world hello world hello world"; private int x = 32, yLabel = 0, yDraw = 64, yRenderer = 32; public Form1() { Font = new Font("Times", 16); Label label = new Label(); label.BorderStyle = BorderStyle.FixedSingle; label.AutoSize = true; label.Text = str; label.Location = new Point(x, yLabel); Controls.Add(label); } protected override void OnPaint(PaintEventArgs e) { SizeF a; // TextRenderer a = TextRenderer.MeasureText(str, Font); TextRenderer.DrawText(e.Graphics, str, Font, new Point(x, yRenderer), Color.Pink); e.Graphics.DrawRectangle(new Pen(Color.Blue), x, yRenderer, a.Width, a.Height); // DrawString e.Graphics.DrawString(str, Font, new SolidBrush(Color.Red), x, yDraw); a = e.Graphics.MeasureString(str, Font); e.Graphics.DrawRectangle(new Pen(Color.Lime), x, yDraw, a.Width, a.Height); base.OnPaint(e); } } 

En pocas palabras: en comparación con una etiqueta simple, TextRenderer es más preciso.