爲了解決具體爲什麼將有可能對於較大的字體,以產生更小的寬度,我放在一起此示例控制檯應用程序。值得注意的是,我將字體大小分別調整爲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時,字符寬度開始變化,一些變大,一些變小,最終增加到較小的寬度。
嗯,我不能重現。在這裏,我得到了44,15和53,16。我的顯示器有120dpi。 – TaW
請注意,除了使用StringFormat.TypographicGenic的Graphics.MeasureString之外的所有內容都會添加一些空格,以允許您將輸出串起來而不會重疊單詞。 – TaW
@TaW我的顯示器運行在默認的96dpi上。 TextRenderer不提供任何方法來測量導致SizeF的字符串。 我不介意由於添加填充而使尺寸變大,我只是想知道較小的字體尺寸會導致較大的寬度。 – dm1988