Webフォームアプリで画像の特定の部分にテキストをレンダリングしようとしています。テキストはユーザーが入力するので、バウンディングボックス内に収まるようにフォントサイズを変更したいと思います。
概念実証の実装でこれをうまく行っていたコードがありますが、現在、より大きなデザイナーからのアセットに対してそれを試しているため、奇妙な結果が得られています。
私は次のようにサイズ計算を実行しています:
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());
次に、次の行を使用して、ファイルシステムからプルしている画像にテキストをレンダリングします。
g.DrawString(text, font, __brush, __textBoundingBox, fmt);
どこ:
__fonts
はPrivateFontCollection
、PrivateFontCollection.GetFontBySize
を返す拡張メソッドですFontFamily
RectangleF __textBoundingBox = new RectangleF(150, 110, 212, 64);
int __minimumSize = 8;
int __startingSize = 48;
Brush __brush = Brushes.White;
int size
48から始まり、そのループ内で減少しますGraphics g
持っSmoothingMode.AntiAlias
てTextRenderingHint.AntiAlias
設定context
は(これはのメソッドSystem.Web.HttpContext
からの抜粋です)ProcessRequest
IHttpHandler
他の方法は次のとおりです。
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);
}
今、私は2つの問題を抱えています。
まず、テキストが単語内に改行を挿入して折り返すことを要求することがありますが、これはちょうど収まらず、whileループが再びデクリメントする必要があります。Graphics.MeasureCharacterRanges
単語内でワードラップするべきではないのに、これがボックス内に収まると考える理由がわかりません。この動作は、使用されている文字セットに関係なく示されます(ラテンアルファベットの単語、およびキリル文字、ギリシャ文字、グルジア文字、アルメニア文字などのUnicode範囲の他の部分で取得します)。Graphics.MeasureCharacterRanges
空白文字(またはハイフン)でのみワードラップするように強制するために使用する必要がある設定はありますか?この最初の問題は、ポスト2499067と同じです。
第二に、新しい画像とフォントサイズにスケールアップすると、Graphics.MeasureCharacterRanges
高さが大幅にずれてしまいます。私が描いているのRectangleF
は画像の視覚的に見える領域に対応しているので、テキストが必要以上にデクリメントされていることを簡単に確認できます。しかし、私がそれにいくつかのテキストを渡すとき、GetBounds
呼び出しは私にそれが実際に取っているもののほぼ2倍の高さを与えています。
試行錯誤を使用し__minimumSize
て、whileループを強制的に終了するように設定すると、24ポイントのテキストがバウンディングボックス内に収まることがわかりますGraphics.MeasureCharacterRanges
が、画像にレンダリングされたテキストの高さは122px(バウンディング時)であると報告されていますボックスの高さは64ピクセルで、そのボックス内に収まります)。実際、問題を強制することなく、whileループは18ptまで繰り返され、その時点で適切Graphics.MeasureCharacterRanges
な値が返されます。
トレースログの抜粋は次のとおりです。
サイズが193×122で制限が212×64であるため、フォントサイズを24に
デクリメントします。サイズが191×117で制限が212×64であるため、フォントサイズを23に
デクリメントします。サイズが200×75で制限があるため、フォントサイズを22にデクリメントします。は212×64
フォントサイズを21にデクリメントします。サイズは192×71で制限は212×64
です。フォントサイズを20にデクリメントします。サイズは198×68で制限は212×64
です。フォントサイズを19にデクリメントします。サイズは185です。 ×65、制限は212×64
です。HESSELINKのVENNEGOORをDIN-Blackで18ptで書き込み、サイズは178×61、制限は212×64です。
では、なぜGraphics.MeasureCharacterRanges
私に間違った結果を与えるのですか?たとえば、ループが21ポイント前後で停止した場合のフォントの行の高さは理解できますが(結果をスクリーンショットしてPaint.Netで測定すると、視覚的にフィットします)、本来よりもはるかに進んでいます。率直に言って、それは間違った気の結果を返しているからです。