[Winform] 了解並修正 AddString 路徑與原矩形偏移的問題

在 GDI+ 功能中, 如果要在圖片中加上文字, 最簡單的方法就是使用 Graphics.DrawString() 方法。但是 DrawString() 方法固然簡單好用, 它的功能卻十分的不強; 光是想要描出文字的框線, 我們就得採用迂迴的方法才能辦得到, 效果還不見得好。上網查了很久之後, 發現絕大多數同好都建議改用 GraphicsPath.AddString()...

在 GDI+ 功能中, 如果要在圖片中加上文字, 最簡單的方法就是使用 Graphics.DrawString() 方法。但是 DrawString() 方法固然簡單好用, 它的功能卻十分的不強; 光是想要描出文字的框線, 我們就得採用迂迴的方法才能辦得到, 效果還不見得好。上網查了很久之後, 發現絕大多數同好都建議改用 GraphicsPath.AddString()。

AddString() 方法跟 DrawString() 方法差不多, 但是 DrawString() 是直接在一張畫布上作業, 而 AddString() 方法卻會把文字描成向量點路徑。換句話說, 我們可以對這個描出來的 GraphicsPath 物件進行各式各樣的動作, 包括套用筆 (Pen) 和筆刷 (Brush) 等等。

 

問題來了

綜合來講, 其實 AddString() 方法好用歸好用, 但並不容易駕馭。我前前後後找到三個問題, 幸好陸續都克服了。

當我終於把文字的外框加了上去, 正在幸高彩列之際, 我發現好像要把文字擺在畫面的正中央並不是那麼容易。本來我可以使用 Graphics.MeasureString() 來算出 Graphics.DrawString() 之後文字的 Size, 但是若採用 GraphicsPath.AddString() 方法時, 似乎並沒有這種工具可用。

或許你會想, 反正要畫出來的字串是一樣的, 字型也一樣, 那就把 Graphics.MeasureString() 拿來用, 不也可以?

偏偏不可以! 因為結果顯示二者得出來的值並不一樣。換句話說, 即使是同樣的字串、同樣的字體和大小, 兩者的大小還是不一樣。

 

尋求解決之道

山不轉路轉。我把文字路徑描出來之後, 使用 GetBound() 方法把路徑轉成矩形, 我不就得出實際的 Size 了嗎? 如下例:

GraphicsPath textPath = new GraphicsPath();
textPath.AddString(inputText, font.FontFamily,(int)font.Style, font.Size, 
    new PointF(0,0), StringFormat.GenericDefault);
RectangleF recTextBound = textPath.GetBounds();
SizeF textSize = recTextBound.Size;

得到 Size 之後, 我就可以計算出置中的位置了。但矛盾的是, 我必須先給 path 的起始位置 (這裡我使用 (0,0)) 才能計算其大小尺寸, 但我又需要先知道它的大小才能知道要把路徑描在哪裡 (絕對不是 (0,0)); 這就是雞生蛋、蛋生雞的問題了。

沒關係, 我就把剛才描出來的文字作廢, 重描一遍! 拎杯時間多, 怎樣?

textPath.Reset();
textPath.AddString(inputText, font.FontFamily, (int)font.Style, font.Size,
    new PointF(X, Y), StringFormat.GenericDefault);

上面的 (X, Y) 就是重新計算後得出來的新座標值。

正當我正愉快的享受著成果時, 這個圖卻愈看愈令人覺得奇怪; 它不在正中央啊!

這就是我遇到的第三個問題了。

我確信我算出來的 (X, Y) 是對的, 但是在畫面上看起來它就是歪的。我把 GetBounds() 得出來的矩形也描述框來了, 很顯然沒有看到它有留白 (就是這個錯誤的結論害我白白多花了一個小時)。

在我無數次重覆檢查並驗證我那根本沒有錯誤的程式之後, 最後我還是把問題點找出來了! 簡而言之, 那就是 AddString() 描出來的字, 會比你給的起始點往右下角偏移! 字體愈大, 偏移愈大。如果你使用 GetBound() 的話, 它並不會框住留白的部份。看看以下這張圖就很清楚了:

文字的位置有往右下自動偏移的現象

知道問題之後就很容易解決了。我們可以使用轉置矩去把 GraphicsPath 的位置平移過來, 不然就像我一樣採取偷懶的方法 - 再重畫一次。

如果有時間的話, 我會再繼續找找看有沒有更好的解法。


Dev 2Share @ 點部落