0%

[C#] 在高 DPI 的螢幕上,有些應用程式內的字會模糊的原因以及解決方法!

前言

開啟 Visual Studio C# 的 Windows Form 應用程式來設計,一定曾經注意到雖然在 VS 裡面設計 Form 時,預覽的字是清晰的,結果 Compiler 之後跑出來的字是模糊的!以下圖幫各位回憶一下。

在 C# 視窗程式中模糊的字在 C# 視窗程式中模糊的字

原因

這最主要原因是 DPI 太高的關係,但你可能會想說 DPI 高的話解析度就高呀,為什麼會 DPI 越高越模糊!先來聊聊一些單位的定義。

單位定義

  • DPI:是 dots per inch 的縮寫,即每英吋內的點數量,也叫做螢幕密度,通常一個點 dot 就是一個像素 pixel,所以越大 DPI 的螢幕,可以使用更多像素來顯示一張圖,因此能顯示的更精緻。
  • pt:文字大小的單位是 pt(point),定義為 72 pt 為一英吋(inch),但這是對於全型字來說,例如漢字(下圖);如果是英文半型字,就要看各自的寬度了。 pt 與英吋的關係pt 與英吋的關係

原因說明

現在就來回答問題吧!為什麼在高 DPI 的螢幕會顯示出這麼模糊的文字呢?魔鬼就藏在單位轉換裡面。

程式有分為 DPI 感知非 DPI 感知的應用程式,端看當初程式中是否有加入此功能,在早期的作業系統下螢幕還沒這麼高級,大多為 96 DPI,導致許多程式就沒考慮到現在的高 DPI 螢幕例如現在的 120、144、192 等,因此大部分舊應用程式都為非感知 DPI 的類型。

到後來 Microsoft 發展出 DPI Virtualization,此技術運作模式大概是這樣的,當應用程式沒有先聲明它能支援多少 DPI 時,Windows 會先將它放進沙盒裡,在這裡面沙盒內是先將應用程式渲染成 96 DPI 解析度下的畫面,然後看實際上的解析度多少再進行縮放,也因為如此,非感知 DPI 的應用程式在高 DPI 的螢幕下會出現模糊的情況。

現在先來進行單位換算:

Environment Convert
96 DPI 1.33 dots = 1 pt
120 DPI 1.67 dots = 1 pt
144 DPI 2 dots = 1 pt
192 DPI 2.67 dots = 1 pt

從上面表格來解讀,假設現在要顯示一個字,其大小為 1 pt,在各種解析度的螢幕上需要使用來顯示點數,例如 96 DPI 需要用 1.33 dots,其兩倍解析度的 192 DPI 就需要其兩倍的點數 2.67 dots 來表示。

可以看得出來吧?當一張圖的解析度為 96 DPI,你需要放大兩倍才能在 192 DPI 的螢幕上顯示出一樣大小的畫面,但是圖片本身解析度是不會變高的!所以如果將其放大(點陣圖放大)的話必定會模糊。用講的很難想像,讓我用圖來說明。

高解析度螢幕顯示文字會模糊的原因示意圖高解析度螢幕顯示文字會模糊的原因示意圖

解決方法

到這裡已經知道為何高 DPI 的螢幕會影響到字體的顯示了,接下來就要說說如何讓 C# 設計出來的視窗字體不會模糊,先上程式碼再解釋

1
2
3
4
5
6
7
8
9
10
11
[STAThread]
static void Main()
{
if (Environment.OSVersion.Version.Major >= 6)
SetProcessDPIAware();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern bool SetProcessDPIAware();

原理很簡單,在 Main() 的附近加上 4、5、10、11 行,使程式為 DPI 感知即大功告成,結果如下

DPI 感知程式顯示出清晰文字DPI 感知程式顯示出清晰文字

參考資料

  1. WinForms Scaling at Large DPI Settings–Is It Even Possible?

  2. Windows微信DPI適配

  3. How to fix blurry Windows Forms Windows in high-dpi settings

  4. OSVERSIONINFOA structure

很高興能在這裡幫助到您,歡迎登入 Liker 為我鼓掌 5 次,或者成為我的讚賞公民,鼓勵我繼續創造優質文章。
以最優質的內容回應您的鼓勵