J'essaie de restituer du texte dans une partie spécifique d'une image dans une application Web Forms. Le texte sera saisi par l'utilisateur, je veux donc faire varier la taille de la police pour m'assurer qu'elle tient dans le cadre.Graphics.MeasureCharacterRanges donnant des calculs de taille incorrecte
J'ai du code qui fonctionnait très bien sur ma mise en œuvre de preuve de concept, mais je l'essaie maintenant par rapport aux ressources du concepteur, qui sont plus grandes, et j'obtiens des résultats étranges.
Je suis en cours d'exécution du calcul de la taille comme suit:
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());
J'utilise la ligne suivante pour rendre le texte sur une image je tire du système de fichiers:
g.DrawString(text, font, __brush, __textBoundingBox, fmt);
où :
__fonts
est unPrivateFontCollection
,PrivateFontCollection.GetFontBySize
est une méthode d'extension qui retourne unFontFamily
RectangleF __textBoundingBox = new RectangleF(150, 110, 212, 64);
int __minimumSize = 8;
int __startingSize = 48;
Brush __brush = Brushes.White;
int size
commence à 48 et décrémentée dans cette boucleGraphics g
aSmoothingMode.AntiAlias
etTextRenderingHint.AntiAlias
miscontext
est unSystem.Web.HttpContext
(ce qui est un extrait de la méthodeProcessRequest
d'unIHttpHandler
)
Les autres méthodes sont:
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);
}
Maintenant, j'ai deux problèmes. Tout d'abord, le texte parfois insiste parfois sur l'encapsulation en insérant un saut de ligne dans un mot, alors que cela devrait échouer et que la boucle while devrait à nouveau être décrémentée. Je ne peux pas voir pourquoi c'est Graphics.MeasureCharacterRanges
pense que cela correspond à la boîte quand il ne devrait pas être mot-emballage dans un mot. Ce comportement est exposé quel que soit le jeu de caractères utilisé (je l'obtiens en mots de l'alphabet latin, ainsi que d'autres parties de la gamme Unicode, comme le cyrillique, le grec, le géorgien et l'arménien). Y-a-t-il un réglage que je devrais utiliser pour forcer Graphics.MeasureCharacterRanges
à n'entourer que les caractères blancs (ou traits d'union)? Ce premier problème est le même que post 2499067.
Deuxièmement, en augmentant la taille de la nouvelle image et de la police, Graphics.MeasureCharacterRanges
me donne des hauteurs qui sont follement éteintes. Le RectangleF
Je dessine dedans correspond à une zone visuellement apparente de l'image, donc je peux facilement voir quand le texte est décrémenté plus que nécessaire. Pourtant, quand je lui passe un peu de texte, l'appel GetBounds
me donne une hauteur qui est presque le double de ce qu'il prend réellement.En utilisant l'essai et l'erreur pour définir le __minimumSize
pour forcer une sortie de la boucle while, je peux voir que le texte 24pt tient dans la boîte englobante, mais Graphics.MeasureCharacterRanges
rapporte que la hauteur de ce texte, une fois rendu à l'image, est 122px (lorsque la boîte englobante est de 64px et qu'elle rentre dans cette boîte). En effet, sans forcer la matière, la boucle while se propage à 18pt, point auquel Graphics.MeasureCharacterRanges
renvoie une valeur qui convient.
L'extrait de journal de trace est la suivante:
décrémentation taille de police à 24, que la taille est de 193 × 122 et la limite est de 212 × 64
décrémentation taille de police à 23, que la taille est de 191 × 117 et la limite est de 212 × 64
décrémentation taille de police à 22, que la taille est de 200 × 75 et la limite est de 212 × 64
taille de la police décrémentation à 21, que la taille est de 192 × 71 et la limite est de 212 × 64
police Décrémental taille à 20, car la taille est 198 × 68 et la limite est 212 × 64
Decre Menting taille de police à 19, que la taille est de 185 × 65 et la limite est de 212 × 64
écriture Vennegoor de HESSELINK dans la norme DIN-noir à 18 pt, la taille est de 178 × 61 et la limite est de 212 × 64
Alors pourquoi est Graphics.MeasureCharacterRanges
en me donnant un mauvais résultat? Je pourrais comprendre, disons, la hauteur de ligne de la police si la boucle s'arrêtait autour de 21pt (ce qui correspondrait visuellement, si je capture les résultats et les mesure dans Paint.Net), mais ça va bien au-delà parce que, franchement, il retourne les mauvais résultats.
+1 pour l'une des questions les plus documentées que j'ai vues depuis un moment! – SouthShoreAK