2016-04-14 39 views
1

我想用TextRenderer類測量給定特定字體的字符串的大小。儘管我試着用3種不同的方法(Graphics.MeasureCharacterRanges,Graphics.MeasureString,TextRenderer.MeasureText)來測量它,並且它們都給我不同的結果,但沒有準確,我偶然發現了其他的東西。
使用字體大小爲7和8的相同字體測量相同的字符串START,字體大小7的測量結果比字體大小8的測量結果寬。C#Textrenderer - 測量更小的字體大小導致更大的尺寸

下面是我使用的代碼:

Font f1 = new Font("Arial", 7, FontStyle.Regular); 
Font f2 = new Font("Arial", 8, FontStyle.Regular); 
Size s1 = TextRenderer.MeasureText("START", f1); 
Size s2 = TextRenderer.MeasureText("START", f2); 

的結果是具有41的widths1和13 heights2具有14

爲什麼會40和height一個width更小的字體會導致更大的寬度?

+0

嗯,我不能重現。在這裏,我得到了44,15和53,16。我的顯示器有120dpi。 – TaW

+0

請注意,除了使用StringFormat.TypographicGenic的Graphics.MeasureString之外的所有內容都會添加一些空格,以允許您將輸出串起來而不會重疊單詞。 – TaW

+0

@TaW我的顯示器運行在默認的96dpi上。 TextRenderer不提供任何方法來測量導致SizeF的字符串。 我不介意由於添加填充而使尺寸變大,我只是想知道較小的字體尺寸會導致較大的寬度。 – dm1988

回答

2

爲了解決具體爲什麼將有可能對於較大的字體,以產生更小的寬度,我放在一起此示例控制檯應用程序。值得注意的是,我將字體大小分別調整爲7.5 & 8.25,因爲這是TextRenderer在內部評估它們的大小。

using System; 
using System.Drawing; 
using System.Linq; 
using System.Runtime.InteropServices; 

namespace FontSizeDifference 
{ 
    static class Program 
    { 
     [StructLayout(LayoutKind.Sequential)] 
     struct ABCFLOAT 
     { 
      public float abcfA; 
      public float abcfB; 
      public float abcfC; 
     } 

     [DllImport("gdi32.dll")] 
     static extern bool GetCharABCWidthsFloat(IntPtr hdc, int iFirstChar, int iLastChar, [Out] ABCFLOAT[] lpABCF); 

     [DllImport("gdi32.dll", CharSet = CharSet.Auto, EntryPoint = "SelectObject", SetLastError = true)] 
     static extern IntPtr SelectObject(IntPtr hdc, IntPtr obj); 

     [DllImport("gdi32.dll", EntryPoint = "DeleteObject")] 
     static extern bool DeleteObject([In] IntPtr hObject); 

     [StructLayout(LayoutKind.Sequential)] 
     struct KERNINGPAIR 
     { 
      public ushort wFirst; 
      public ushort wSecond; 
      public int iKernAmount; 
     } 

     [DllImport("gdi32.dll")] 
     static extern int GetKerningPairs(IntPtr hdc, int nNumPairs, [Out] KERNINGPAIR[] lpkrnpair); 

     [STAThread] 
     static void Main() 
     { 
      var fonts = new[] { 
       new Font("Arial", 7.5f, FontStyle.Regular), 
       new Font("Arial", 8.25f, FontStyle.Regular) 
      }; 
      string textToMeasure = "START"; 

      using (Graphics g = Graphics.FromHwnd(IntPtr.Zero)) 
      { 
       IntPtr hDC = g.GetHdc(); 

       foreach (Font font in fonts) 
       { 
        float totalWidth = 0F; 
        IntPtr hFont = font.ToHfont(); 

        // Apply the font to dc 
        SelectObject(hDC, hFont); 

        int pairCount = GetKerningPairs(hDC, short.MaxValue, null); 
        var lpkrnpair = new KERNINGPAIR[pairCount]; 
        GetKerningPairs(hDC, pairCount, lpkrnpair); 

        Console.WriteLine("\r\n" + font.ToString()); 

        for (int ubound = textToMeasure.Length - 1, i = 0; i <= ubound; ++i) 
        { 
         char c = textToMeasure[i]; 
         ABCFLOAT characterWidths = GetCharacterWidths(hDC, c); 
         float charWidth = (characterWidths.abcfA + characterWidths.abcfB + characterWidths.abcfC); 
         totalWidth += charWidth; 

         int kerning = 0; 
         if (i < ubound) 
         { 
          kerning = GetKerningBetweenCharacters(lpkrnpair, c, textToMeasure[i + 1]).iKernAmount; 
          totalWidth += kerning; 
         } 

         Console.WriteLine(c + ": " + (charWidth + kerning) + " (" + charWidth + " + " + kerning + ")"); 
        } 

        Console.WriteLine("Total width: " + totalWidth); 

        DeleteObject(hFont); 
       } 

       g.ReleaseHdc(hDC); 
      } 
     } 

     static KERNINGPAIR GetKerningBetweenCharacters(KERNINGPAIR[] lpkrnpair, char first, char second) 
     { 
      return lpkrnpair.Where(x => (x.wFirst == first) && (x.wSecond == second)).FirstOrDefault(); 
     } 

     static ABCFLOAT GetCharacterWidths(IntPtr hDC, char character) 
     { 
      ABCFLOAT[] values = new ABCFLOAT[1]; 
      GetCharABCWidthsFloat(hDC, character, character, values); 
      return values[0]; 
     } 
    } 
} 

對於每種字體大小,它輸出每個字符的寬度,包括字距。在96 DPI,對我來說,這將導致:

[字體:名稱= Arial字體,大小= 7.5,單元數= 3,GdiCharSet = 1,GdiVerticalFont = FALSE]
S:7(7 + 0)
T:6(7 + -1)
答:7(7 + 0)
R:7(7 + 0)
T:7(7 + 0)
總寬度:34

[Font:Name = Arial,Size = 8。25,單元數= 3,GdiCharSet = 1,GdiVerticalFont = FALSE]
S:7(7 + 0)
T:5(6 + -1)
答:8(8 + 0)
R:7 (7 + 0)
T:6(6 + 0)
總寬度:33

雖然我顯然不捕獲由測量作出TextRenderer確切的配方,它不示出了相同的寬度 - 差異。字體大小爲7時,所有字符的寬度均爲7。然而,在字體大小爲8時,字符寬度開始變化,一些變大,一些變小,最終增加到較小的寬度。

1

看起來好像TextRenderer.MeasureText正在給出正確的值,但較小的字體有一些字形更大的字母間距。

下面你可以看到它是如何看待"TTTTTTTTT"文本。上面一個是Arial 7,最下面一個是Arial 8

對於較大的字體,字母之間沒有空格。

enter image description here