没有 Graphics.MeasureString 的 C# 中的自定义度量字符串
Custom Measure String in C# without Graphics.MeasureString
我正在尝试为 Youtube-Thumbnails 创建一个带有 Caption/Text 的图像。
定义了以下规则:
- 文本是视频的标题,总是从缩略图变为缩略图。
- 该程序使用 pre-defined Text-Width,图像上的文字不得触及。
- 文本应尽可能靠近 pre-defined。
所以我的想法是我会使用 Graphics.MeasureString
来跟踪图像上字符串的宽度并增加 Font-Size 并重复此操作直到 pre-defined 宽度近在咫尺却未触及
但我用 MeasureString
测试过它,发现它不是那么准确。并且还在这里找到了确认:Graphics.MeasureCharacterRanges giving wrong size calculations
我尝试了他们推荐的方法,但没有成功,因为我的字符串的最终宽度总是淹没图像边界。即使我的 pre-defined 宽度比图像宽度小得多。 (图片宽度:1920;Pre-Defined宽度:1600)
所以我想到了创建自定义测量方法的想法,并根据需要在新位图上写入字符串,并计算字符串在高度和宽度方面的最大像素。 (高度只是为了将来的东西)
我当前的代码是:
public static SizeF MeasuredStringSize(string text, Bitmap originBitmap, FontFamily fontFamily, StringFormat strformat)
{
int currentFontSize = 10;
SizeF measuredSize = new();
var highestWidth = 0;
var highestHeight = 0;
while (highestWidth < maximumTextWidth)
{
Bitmap bitmap = new(originBitmap);
Bitmap _bitmap = new(bitmap.Width, bitmap.Height);
using Graphics graphics = Graphics.FromImage(bitmap);
if (graphics != null)
{
graphics.TranslateTransform(bitmap.Width / 2, bitmap.Height / 2);
currentFontSize++;
graphics.Clear(Color.White);
using GraphicsPath path = new();
using SolidBrush brush = new(Color.Red);
using Pen pen = new(Color.Red, 6)
{
LineJoin = LineJoin.Round
};
path.AddString(text, fontFamily, (int)fontStyle, currentFontSize, new Point(0, 0), strformat);
graphics.DrawPath(pen, path);
graphics.FillPath(brush, path);
Dictionary<int, List<int>> redPixelMatrix = new();
for (int i = 0; i < bitmap.Width; i++)
{
for (int j = 0; j < bitmap.Height; j++)
{
var currentPixelColor = bitmap.GetPixel(i, j);
if (currentPixelColor.B != 255 && currentPixelColor.G != 255 && currentPixelColor.R == 255)
{
if (!redPixelMatrix.ContainsKey(i))
{
redPixelMatrix.Add(i, new());
}
redPixelMatrix[i].Add(j);
}
}
}
highestWidth = redPixelMatrix.Keys.Count;
highestHeight = redPixelMatrix.Aggregate((l, r) => l.Value.Count > r.Value.Count ? l : r).Value.Count;
Console.WriteLine($"X:{highestWidth};Y:{highestHeight}");
//Debugging the final Image with Text to see the Result
bitmap.Save(ResultPath);
}
}
measuredSize = new SizeF(highestWidth, highestHeight);
return measuredSize;
}
当字符串到达图像边界时,bitmap.Save(ResultPath);
生成的图像如下所示:
但确切的字符串宽度是 1742
而不是我的图像的宽度 1920
,此时应该大致相同。
那么,为什么文本几乎与图像一样宽,但宽度却不同?
highestWidth = redPixelMatrix.Keys.Count;
这将只计算包含红色像素的列数,不包括文本中的任何空格。您可能需要最小和最大索引。
即
var minX = int.MaxValue;
var maxX = int.MinValue;
// Loops over rows & columns
// Check if pixel is red
if(i > maxX) maxX = i;
if(i < minX) minX = i;
如果您只想要文本宽度而不想要边界,您可以这样做 maxX - minX
。
我正在尝试为 Youtube-Thumbnails 创建一个带有 Caption/Text 的图像。
定义了以下规则:
- 文本是视频的标题,总是从缩略图变为缩略图。
- 该程序使用 pre-defined Text-Width,图像上的文字不得触及。
- 文本应尽可能靠近 pre-defined。
所以我的想法是我会使用 Graphics.MeasureString
来跟踪图像上字符串的宽度并增加 Font-Size 并重复此操作直到 pre-defined 宽度近在咫尺却未触及
但我用 MeasureString
测试过它,发现它不是那么准确。并且还在这里找到了确认:Graphics.MeasureCharacterRanges giving wrong size calculations
我尝试了他们推荐的方法,但没有成功,因为我的字符串的最终宽度总是淹没图像边界。即使我的 pre-defined 宽度比图像宽度小得多。 (图片宽度:1920;Pre-Defined宽度:1600)
所以我想到了创建自定义测量方法的想法,并根据需要在新位图上写入字符串,并计算字符串在高度和宽度方面的最大像素。 (高度只是为了将来的东西)
我当前的代码是:
public static SizeF MeasuredStringSize(string text, Bitmap originBitmap, FontFamily fontFamily, StringFormat strformat)
{
int currentFontSize = 10;
SizeF measuredSize = new();
var highestWidth = 0;
var highestHeight = 0;
while (highestWidth < maximumTextWidth)
{
Bitmap bitmap = new(originBitmap);
Bitmap _bitmap = new(bitmap.Width, bitmap.Height);
using Graphics graphics = Graphics.FromImage(bitmap);
if (graphics != null)
{
graphics.TranslateTransform(bitmap.Width / 2, bitmap.Height / 2);
currentFontSize++;
graphics.Clear(Color.White);
using GraphicsPath path = new();
using SolidBrush brush = new(Color.Red);
using Pen pen = new(Color.Red, 6)
{
LineJoin = LineJoin.Round
};
path.AddString(text, fontFamily, (int)fontStyle, currentFontSize, new Point(0, 0), strformat);
graphics.DrawPath(pen, path);
graphics.FillPath(brush, path);
Dictionary<int, List<int>> redPixelMatrix = new();
for (int i = 0; i < bitmap.Width; i++)
{
for (int j = 0; j < bitmap.Height; j++)
{
var currentPixelColor = bitmap.GetPixel(i, j);
if (currentPixelColor.B != 255 && currentPixelColor.G != 255 && currentPixelColor.R == 255)
{
if (!redPixelMatrix.ContainsKey(i))
{
redPixelMatrix.Add(i, new());
}
redPixelMatrix[i].Add(j);
}
}
}
highestWidth = redPixelMatrix.Keys.Count;
highestHeight = redPixelMatrix.Aggregate((l, r) => l.Value.Count > r.Value.Count ? l : r).Value.Count;
Console.WriteLine($"X:{highestWidth};Y:{highestHeight}");
//Debugging the final Image with Text to see the Result
bitmap.Save(ResultPath);
}
}
measuredSize = new SizeF(highestWidth, highestHeight);
return measuredSize;
}
当字符串到达图像边界时,bitmap.Save(ResultPath);
生成的图像如下所示:
但确切的字符串宽度是 1742
而不是我的图像的宽度 1920
,此时应该大致相同。
那么,为什么文本几乎与图像一样宽,但宽度却不同?
highestWidth = redPixelMatrix.Keys.Count;
这将只计算包含红色像素的列数,不包括文本中的任何空格。您可能需要最小和最大索引。
即
var minX = int.MaxValue;
var maxX = int.MinValue;
// Loops over rows & columns
// Check if pixel is red
if(i > maxX) maxX = i;
if(i < minX) minX = i;
如果您只想要文本宽度而不想要边界,您可以这样做 maxX - minX
。