没有 Graphics.MeasureString 的 C# 中的自定义度量字符串

Custom Measure String in C# without Graphics.MeasureString

我正在尝试为 Youtube-Thumbnails 创建一个带有 Caption/Text 的图像。

定义了以下规则:

所以我的想法是我会使用 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