tutorial - c# drawstring vertical text
System.Drawing: representación de texto dañado con DrawString encima de píxeles transparentes (4)
Al renderizar texto en un mapa de bits, encuentro que el texto se ve muy mal cuando se procesa en la parte superior de un área con alfa no opaca. El problema es progresivamente peor a medida que los píxeles subyacentes se vuelven más transparentes. Si tuviera que adivinar, diría que cuando los píxeles subyacentes son transparentes, el renderizador de texto dibuja cualquier píxel "gris" anti-alias como negro sólido.
Aquí hay algunas capturas de pantalla:
Texto dibujado sobre píxeles transparentes:
Texto dibujado sobre píxeles semitransparentes:
Texto dibujado en píxeles opacos:
Aquí está el código usado para representar el texto:
g.SmoothingMode = SmoothingMode.HighQuality;
g.DrawString("Press the spacebar", Font, Brushes.Black, textLeft, textTop);
El primer resultado es lo que obtienes cuando dibujas texto negro sobre fondo negro, probablemente Color.Transparent. El segundo fue dibujado sobre un fondo casi negro. El tercero se dibujó en el mismo fondo con el que se muestra.
El suavizado no puede funcionar cuando se utiliza un fondo transparente. Los colores utilizados para los píxeles antialias no combinarán la forma de la letra en el fondo cuando el texto se muestre con un fondo diferente. Esos píxeles ahora serán muy visibles y harán que el texto se vea muy mal.
Tenga en cuenta que SmoothingMode no afecta la salida de texto. Se verá un poco menos malo si usa un TextRenderingHint de menor calidad y un color de fondo grisáceo con un alfa de cero. Solo TextRenderingHint.SingleBitPerPixelGridFit evita todos los problemas de antialiasing.
Obtener una solución perfecta para esto es muy difícil. El efecto de cristal de Vista en la barra de título de la ventana utiliza un sombreado muy sutil para darle al texto un color de fondo bien definido. Necesitarías la herramienta ZoomIt de SysInternals para verla realmente. Función DrawThemeTextEx () con un iGlowSize distinto de cero.
La opción que usé para solucionar este problema fue:
Graphics graphics = new Graphics();
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
Hay algunas otras opciones útiles en TextRenderingHint
Espero eso ayude
Si está buscando algo que preserve antialiasing un poco mejor que GDI + de manera predeterminada, puede llamar a Graphics.Clear
con una clave de croma, luego eliminar manualmente los artefactos de croma que resultan. (Consulte ¿Por qué DrawString se ve tan horrible? Y el problema de texto con aspecto feo ).
Así es como finalmente terminé resolviendo un problema similar:
static Bitmap TextToBitmap(string text, Font font, Color foregroundColor)
{
SizeF textSize;
using ( var g = Graphics.FromHwndInternal(IntPtr.Zero) )
textSize = g.MeasureString(text, font);
var image = new Bitmap((int)Math.Ceiling(textSize.Width), (int)Math.Ceiling(textSize.Height));
var brush = new SolidBrush(foregroundColor);
using ( var g = Graphics.FromImage(image) )
{
g.Clear(Color.Magenta);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.DrawString(text, font, brush, 0, 0);
g.Flush();
}
image.MakeTransparent(Color.Magenta);
// The image now has a transparent background, but around each letter are antialiasing artifacts still keyed to magenta. We need to remove those.
RemoveChroma(image, foregroundColor, Color.Magenta);
return image;
}
static unsafe void RemoveChroma(Bitmap image, Color foregroundColor, Color chroma)
{
if (image == null) throw new ArgumentNullException("image");
BitmapData data = null;
try
{
data = image.LockBits(new Rectangle(Point.Empty, image.Size), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
for ( int y = data.Height - 1; y >= 0; --y )
{
int* row = (int*)(data.Scan0 + (y * data.Stride));
for ( int x = data.Width - 1; x >= 0; --x )
{
if ( row[x] == 0 ) continue;
Color pixel = Color.FromArgb(row[x]);
if ( (pixel != foregroundColor) &&
((pixel.B >= foregroundColor.B) && (pixel.B <= chroma.B)) &&
((pixel.G >= foregroundColor.G) && (pixel.G <= chroma.G)) &&
((pixel.R >= foregroundColor.R) && (pixel.R <= chroma.R)) )
{
row[x] = Color.FromArgb(
255 - ((int)
((Math.Abs(pixel.B - foregroundColor.B) +
Math.Abs(pixel.G - foregroundColor.G) +
Math.Abs(pixel.R - foregroundColor.R)) / 3)),
foregroundColor).ToArgb();
}
}
}
}
finally
{
if (data != null) image.UnlockBits(data);
}
}
Es una pena que GDI / GDI + ya no lo haga, pero sería sensato, ¿no? :)
Si no puede usar un contexto unsafe
, podría usar fácilmente la misma lógica con Bitmap.GetPixel
y Bitmap.SetPixel
, aunque será significativamente más lento.
Hay una respuesta muy simple a esto ...
g.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAliasGridFit
Si configura esto antes de procesar su texto, saldrá claro. Además, este método admite más tamaños de fuente (El valor predeterminado solo sube al tamaño 56).
Gracias por leer esta publicación.