Próbuję renderować tekst do określonej części obrazu w aplikacji Web Forms. Tekst zostanie wprowadzony przez użytkownika, więc chcę zmienić rozmiar czcionki, aby upewnić się, że pasuje do obwiedni.Graphics.MeasureCharacterRanges podając nieprawidłowe obliczenia rozmiaru
Mam kod, który robił to dobrze na mojej implementacji proof-of-concept, ale teraz próbuję go od aktywów od projektanta, które są większe, i otrzymuję dziwne wyniki.
biegnę obliczenia wielkości w następujący sposób:
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());
Następnie stosujemy poniższy wiersz do renderowania tekstu na obrazie jestem ciągnięcie z systemu plików:
g.DrawString(text, font, __brush, __textBoundingBox, fmt);
gdzie :
__fonts
jestPrivateFontCollection
,PrivateFontCollection.GetFontBySize
jest metoda rozszerzenie, które zwracaFontFamily
RectangleF __textBoundingBox = new RectangleF(150, 110, 212, 64);
int __minimumSize = 8;
int __startingSize = 48;
Brush __brush = Brushes.White;
int size
zaczyna się na 48 i ubytki wewnątrz tej pętliGraphics g
maSmoothingMode.AntiAlias
iTextRenderingHint.AntiAlias
ustawionycontext
jestSystem.Web.HttpContext
(jest to fragment z metody zIHttpHandler
ProcessRequest
)
Inne metody:
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);
}
Teraz dwa problemy.
Po pierwsze, tekst czasami kładzie nacisk na owijanie przez wstawienie łamania linii w słowie, kiedy powinno po prostu nie pasować i spowodować, że pętla while znowu spadnie. Nie rozumiem, dlaczego jest tak, że Graphics.MeasureCharacterRanges
uważa, że pasuje to do pudełka, gdy nie powinno się go zawijać w słowie. To zachowanie jest wyświetlane niezależnie od użytego zestawu znaków (otrzymuję go w alfabecie łacińskim, jak również w innych częściach zakresu Unicode, takich jak cyrylica, grecki, gruziński i ormiański). Czy jest jakieś ustawienie, którego powinienem używać, aby wymusić tylko kodowanie słów na znakach białych spacji (lub myślników)? Ten pierwszy problem jest taki sam jak post 2499067.
Po drugie, przy skalowaniu do nowego obrazu i rozmiaru czcionki, Graphics.MeasureCharacterRanges
daje mi szaleńczą wysokość. RectangleF
Ja rysuję wewnątrz odpowiada wizualnie widocznemu obszarowi obrazu, więc mogę łatwo zobaczyć, kiedy tekst jest zmniejszany bardziej, niż jest to konieczne. Jednak kiedy przekazuję mu trochę tekstu, wywołanie GetBounds
daje mi wysokość, która jest prawie dwukrotnie większa od tego, co faktycznie pobiera.
Przy użyciu prób i błędów, aby ustawić __minimumSize
wymusić wyjście z pętli while, widzę, że tekst 24pt mieści się w ramce ograniczającej, ale Graphics.MeasureCharacterRanges
zgłasza, że wysokość tego tekstu, po renderowaniu do obrazu, ma 122 piksele (gdy ramka ograniczająca ma wysokość 64 pikseli i mieści się w tym polu). Rzeczywiście, bez wymuszania sprawy, pętla while iteruje do 18 punktów, w którym to momencie Graphics.MeasureCharacterRanges
zwraca wartość, która pasuje.
Wyciąg dziennika śledzenia jest następujący:
Zmniejszanie rozmiaru czcionki 24, mają wielkość 193 x 122, a granica wynosi 212 x 64
Zmniejszanie rozmiaru czcionki do 23, mają wielkość 191 x 117 i granica wynosi 212 x 64
Zmniejszanie rozmiaru czcionki 22, wielkości 200 x 75, a granica wynosi 212 x 64
Zmniejszanie rozmiar czcionki, 21, jak wielkość wynosi 192 x 71, a granica wynosi 212 x czcionki 64
Zmniejszanie rozmiar do 20, rozmiar 198 × 68 i limit 212 × 64
Decre wykonawczych rozmiar czcionki na 19, a rozmiar to 185 x 65 a granica to 212 x 64
Pisanie Vennegoor of Hesselink w DIN-Black na 18pt, rozmiar jest 178 × 61 a granica to 212 x 64
Więc dlaczego to jest Graphics.MeasureCharacterRanges
, co daje zły wynik? Mogłem zrozumieć, że jest to, powiedzmy, wysokość linii czcionki, jeśli pętla zatrzymała się około 21pt (co byłoby wizualnie dopasowane, jeśli zrzutu ekranu wyników i zmierzyć go w Paint.Net), ale idzie daleko dalej niż powinno być robi ponieważ, szczerze mówiąc, zwracają one błędne wyniki.
+1 za jedno z najbardziej udokumentowanych pytań, jakie widziałem od dłuższego czasu! – SouthShoreAK