Estoy tratando de representar texto en una parte específica de una imagen en una aplicación Web Forms. El usuario ingresará el texto, por lo que quiero variar el tamaño de la fuente para garantizar que encaje dentro del cuadro delimitador.Graphics.MeasureCharacterRanges dando cálculos de tamaño incorrecto
Tengo un código que estaba haciendo esto bien en mi implementación de prueba de concepto, pero ahora lo estoy intentando contra los activos del diseñador, que son más grandes, y estoy obteniendo algunos resultados extraños.
estoy ejecutando el cálculo del tamaño de la siguiente manera:
StringFormat fmt = new StringFormat();
fmt.Alignment = StringAlignment.Center;
fmt.LineAlignment = StringAlignment.Near;
fmt.FormatFlags = StringFormatFlags.NoClip;
fmt.Trimming = StringTrimming.None;
int size = __startingSize;
Font font = __fonts.GetFontBySize(size);
while (GetStringBounds(text, font, fmt).IsLargerThan(__textBoundingBox))
{
context.Trace.Write("MyHandler.ProcessRequest",
"Decrementing font size to " + size + ", as size is "
+ GetStringBounds(text, font, fmt).Size()
+ " and limit is " + __textBoundingBox.Size());
size--;
if (size < __minimumSize)
{
break;
}
font = __fonts.GetFontBySize(size);
}
context.Trace.Write("MyHandler.ProcessRequest", "Writing " + text + " in "
+ font.FontFamily.Name + " at " + font.SizeInPoints + "pt, size is "
+ GetStringBounds(text, font, fmt).Size()
+ " and limit is " + __textBoundingBox.Size());
Luego utilizo la siguiente línea al representar el texto en una imagen que estoy tirando desde el sistema de archivos:
g.DrawString(text, font, __brush, __textBoundingBox, fmt);
donde :
__fonts
es unaPrivateFontCollection
,PrivateFontCollection.GetFontBySize
es un método de extensión que devuelve unFontFamily
RectangleF __textBoundingBox = new RectangleF(150, 110, 212, 64);
int __minimumSize = 8;
int __startingSize = 48;
Brush __brush = Brushes.White;
int size
comienza en 48 y decrementos dentro de ese bucleGraphics g
tieneSmoothingMode.AntiAlias
yTextRenderingHint.AntiAlias
conjuntocontext
es unaSystem.Web.HttpContext
(este es un extracto del método de unIHttpHandler
ProcessRequest
)
Los otros métodos son:
private static RectangleF GetStringBounds(string text, Font font,
StringFormat fmt)
{
CharacterRange[] range = { new CharacterRange(0, text.Length) };
StringFormat myFormat = fmt.Clone() as StringFormat;
myFormat.SetMeasurableCharacterRanges(range);
using (Graphics g = Graphics.FromImage(new Bitmap(
(int) __textBoundingBox.Width - 1,
(int) __textBoundingBox.Height - 1)))
{
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
Region[] regions = g.MeasureCharacterRanges(text, font,
__textBoundingBox, myFormat);
return regions[0].GetBounds(g);
}
}
public static string Size(this RectangleF rect)
{
return rect.Width + "×" + rect.Height;
}
public static bool IsLargerThan(this RectangleF a, RectangleF b)
{
return (a.Width > b.Width) || (a.Height > b.Height);
}
Ahora tienen dos problemas.
En primer lugar, el texto a veces insiste en envolver insertando un salto de línea dentro de una palabra, cuando simplemente no se ajusta y hace que el ciclo while se reduzca nuevamente. No puedo ver por qué Graphics.MeasureCharacterRanges
piensa que esto encaja dentro del cuadro cuando no debería ser un término en una palabra. Este comportamiento se exhibe independientemente del conjunto de caracteres utilizado (lo obtengo en palabras del alfabeto latino, así como en otras partes de la gama Unicode, como cirílico, griego, georgiano y armenio). ¿Hay alguna configuración que deba usar para forzar Graphics.MeasureCharacterRanges
solo para que se ajuste la palabra en los espacios en blanco de los caracteres (o guiones)? Este primer problema es el mismo que post 2499067.
En segundo lugar, en la ampliación de la nueva imagen y el tamaño de fuente, Graphics.MeasureCharacterRanges
me está dando alturas que están desenfrenadas. El RectangleF
que estoy dibujando corresponde a un área visualmente visible de la imagen, por lo que puedo ver fácilmente cuando el texto se reduce más de lo necesario. Sin embargo, cuando le paso algo de texto, la llamada GetBounds
me da una altura que es casi el doble de lo que realmente está tomando.
El uso de ensayo y error para ajustar la __minimumSize
para forzar una salida del bucle while, puedo ver que el texto 24pt encaja dentro del cuadro delimitador, sin embargo Graphics.MeasureCharacterRanges
informa que la altura de ese texto, una vez que vuelve a la imagen, es 122px (cuando el cuadro delimitador tiene 64px de alto y cabe dentro de esa caja). De hecho, sin forzar la cuestión, el ciclo while itera a 18pt, en cuyo punto Graphics.MeasureCharacterRanges
devuelve un valor que se ajusta.
El extracto del registro de seguimiento es como sigue:
decrementar el tamaño de fuente a 24, como el tamaño es de 193 × 122 y el límite es 212 × 64
decrementar el tamaño de fuente a 23, como el tamaño es de 191 × 117 y el límite es 212 × 64
decrementar el tamaño de fuente a 22, como el tamaño es de 200 × 75 y el límite es 212 × 64
decrementar tamaño de la fuente a 21, como el tamaño es de 192 × 71 y el límite es 212 × fuente 64
decrementar tamaño a 20, ya que el tamaño es 198 × 68 y el límite es 212 × 64
Decre Menting tamaño de la fuente a 19, como el tamaño es de 185 × 65 y el límite es de 212 × 64
escritura Vennegoor of Hesselink en la norma DIN-Negro a 18 puntos, el tamaño es de 178 × 61 y el límite es de 212 × 64
Entonces, ¿por es Graphics.MeasureCharacterRanges
que me da un resultado incorrecto? Podría entender que es, por ejemplo, la altura de la línea de la fuente si el ciclo se detuvo alrededor de 21pt (que se ajustaría visualmente, si capturé los resultados y lo mido en Paint.Net), pero va mucho más lejos de lo que debería estar haciendo porque, francamente, está devolviendo los malditos resultados equivocados.
+1 para una de las preguntas más documentadas que he visto en mucho tiempo. – SouthShoreAK