C# 使用 GDI+ 給圖片添加文字,并使文字自適應矩形區(qū)域

PS:這篇文章是 GDI+ 總結系列的第二篇,如果對 GDI+ 的基礎使用不熟悉的朋友可以先看第一篇文章《C# 使用 GDI+ 畫圖》。


需求

需求是要做一個編輯文字的頁面。用戶在網(wǎng)頁端寫文字,文字區(qū)域是個矩形框,用戶可以通過下方的拖動條調節(jié)文字大小。
如下圖:

1.png

提交數(shù)據(jù)的時候前端傳文字區(qū)域的左上角和右下角定位給后臺。因為前端的字體大小單位與后端沒什么關系,所以不能直接傳字體大小,也就是后端要根據(jù)矩形區(qū)域以及文字內容來自己推算用什么樣的字體大小合適。

簡單說就是知道文字的矩形區(qū)域,以及文字內容,要讓文字內容根據(jù)矩形區(qū)域大小調整到適合的字體大小能比較合適地填滿這個區(qū)域。


分析&思路

Graphics 類有個 MeasureString 方法,可以用來計算以當前字體寫出來的文字會占據(jù)多少像素。
如下:

//
// 摘要:
//     測量用指定的 System.Drawing.Font 繪制的指定字符串。
//
// 參數(shù):
//   text:
//     要測量的字符串。
//
//   font:
//     System.Drawing.Font,它定義字符串的文本格式。
//
// 返回結果:
//     此方法返回 System.Drawing.SizeF 結構,該結構表示 text 參數(shù)指定的、使用 font 參數(shù)繪制的字符串的大小,單位由 System.Drawing.Graphics.PageUnit
//     屬性指定。
//
// 異常:
//   T:System.ArgumentException:
//     font 為 null。
public SizeF MeasureString(string text, Font font);

這個方法返回的 SizeF 包含 WidthHeight 屬性,讀取這兩個屬性可以獲取到文字內容所占的寬高(以像素為單位)。

//
// 摘要:
//     獲取或設置此 System.Drawing.SizeF 結構的水平分量。
//
// 返回結果:
//     此 System.Drawing.SizeF 結構的水平分量,通常以像素為單位進行度量。
public float Width { get; set; }

// 摘要:
//     獲取或設置此 System.Drawing.SizeF 結構的垂直分量。
//
// 返回結果:
//     此 System.Drawing.SizeF 結構的垂直分量,通常以像素為單位進行度量。
public float Height { get; set; }

于是我們可以先根據(jù)前端傳過來的文字左上角與右下角定位,算出文字的矩形區(qū)域,然后估計一個字體大小,再用 MeasureString 方法計算出估算的文字所占區(qū)域,比較和實際的文字區(qū)域大小,大了則縮小字體,小了則增大字體。這樣即可大約找出合適的文字大小。


具體實現(xiàn)

  • 添加文字方法
/// <summary>
/// 圖片添加文字,文字大小自適應
/// </summary>
/// <param name="imgPath">圖片路徑</param>
/// <param name="locationLeftTop">左上角定位(x1,y1)</param>
/// <param name="locationRightBottom">右下角定位(x2,y2)</param>
/// <param name="text">文字內容</param>
/// <param name="fontName">字體名稱</param>
/// <returns>添加文字后的Bitmap對象</returns>
public static Bitmap AddText(string imgPath, string locationLeftTop, string locationRightBottom, string text, string fontName = "華文行楷")
{
    Image img = Image.FromFile(imgPath);

    int width = img.Width;
    int height = img.Height;
    Bitmap bmp = new Bitmap(width, height);
    Graphics graph = Graphics.FromImage(bmp);

    // 計算文字區(qū)域
    // 左上角
    string[] location = locationLeftTop.Split(',');
    float x1 = float.Parse(location[0]);
    float y1 = float.Parse(location[1]);
    // 右下角
    location = locationRightBottom.Split(',');
    float x2 = float.Parse(location[0]);
    float y2 = float.Parse(location[1]);
    // 區(qū)域寬高
    float fontWidth = x2 - x1;
    float fontHeight = y2 - y1;

    float fontSize = fontHeight;  // 初次估計先用文字區(qū)域高度作為文字字體大小,后面再做調整,單位為px

    Font font = new Font(fontName, fontSize, GraphicsUnit.Pixel);
    SizeF sf = graph.MeasureString(text, font);

    int times = 0;

    // 調整字體大小以適應文字區(qū)域
    if (sf.Width > fontWidth)
    {
        while (sf.Width > fontWidth)
        {
            fontSize -= 0.1f;
            font = new Font(fontName, fontSize, GraphicsUnit.Pixel);
            sf = graph.MeasureString(text, font);

            times++;
        }

        Console.WriteLine("一開始估計大了,最終字體大小為{0},循環(huán)了{1}次", font.ToString(), times);
    }
    else if (sf.Width < fontWidth)
    {
        while (sf.Width < fontWidth)
        {
            fontSize += 0.1f;
            font = new Font(fontName, fontSize, GraphicsUnit.Pixel);
            sf = graph.MeasureString(text, font);

            times++;
        }

        Console.WriteLine("一開始估計小了,最終字體大小為{0},循環(huán)了{1}次", font.ToString(), times);
    }

    // 最終的得出的字體所占區(qū)域一般不會剛好等于實際區(qū)域
    // 所以根據(jù)兩個區(qū)域的相差之處再把文字開始位置(左上角定位)稍微調整一下
    x1 += (fontWidth - sf.Width) / 2;
    y1 += (fontHeight - sf.Height) / 2;

    graph.DrawImage(img, 0, 0, width, height);
    graph.DrawString(text, font, new SolidBrush(Color.Black), x1, y1);

    graph.Dispose();
    img.Dispose();

    return bmp;
}
  • 測試調用
private static void Main(string[] args)
{
    try
    {
        DrawingEntity drawing = new DrawingEntity();

        Console.WriteLine("Start drawing ...");
        System.Drawing.Bitmap bmp = drawing.AddText(@"D:\test\39585148.png", "177.75,63.84", "674.73, 141.6", "大海啊,全是浪");
        bmp.Save(@"D:\test\output.png");
        bmp.Dispose();
        Console.WriteLine("Done!");
    }
    catch (System.Exception ex)
    {
        Console.WriteLine("出錯了??!\n" + ex.ToString());
    }
    finally
    {
        System.Console.WriteLine("\nPress any key to continue ...");
        System.Console.ReadKey();
    }
}

最終效果:


2.png

系列其他文章:
C# 使用 GDI+ 畫圖
C# 使用 GDI+ 實現(xiàn)添加中心旋轉(任意角度)的文字

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容