NewLife/Stardust

DPI 规范化处理与单元测试完善

对 StarClient.Linux.cs 中 DPI 获取流程增加 NormalizeDpi 规范化方法,统一过滤异常和规整格式。新增 TryParseDpi 辅助解析。补充 DpiNormalizeTests 单元测试,覆盖异常与合法场景,提升健壮性。
智能大石头 authored at 2026-01-05 14:38:19
728fa23
Tree
1 Parent(s) d3882d2
Summary: 2 changed files with 80 additions and 3 deletions.
Added +41 -0
Modified +39 -3
Added +41 -0
diff --git a/ClientTest/DpiNormalizeTests.cs b/ClientTest/DpiNormalizeTests.cs
new file mode 100644
index 0000000..b8bf2db
--- /dev/null
+++ b/ClientTest/DpiNormalizeTests.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Reflection;
+using Stardust;
+using Xunit;
+
+namespace ClientTest;
+
+public class DpiNormalizeTests
+{
+    private static String? Normalize(String? dpi)
+    {
+        var mi = typeof(StarClient).GetMethod("NormalizeDpi", BindingFlags.NonPublic | BindingFlags.Static);
+        Assert.NotNull(mi);
+
+        return (String?)mi.Invoke(null, [dpi]);
+    }
+
+    [Theory(DisplayName = "DPI 规范化:过滤异常值")]
+    [InlineData(null)]
+    [InlineData("")]
+    [InlineData("0*96")]
+    [InlineData("96*0")]
+    [InlineData("3072*3072")]
+    [InlineData("9999*96")]
+    public void NormalizeDpi_FilterInvalid(String? dpi)
+    {
+        var rs = Normalize(dpi);
+        Assert.Null(rs);
+    }
+
+    [Theory(DisplayName = "DPI 规范化:保留或规整合法值")]
+    [InlineData("96*96", "96*96")]
+    [InlineData("96x96", "96*96")]
+    [InlineData("120*120", "120*120")]
+    [InlineData("96*97", "96*96")]
+    public void NormalizeDpi_NormalizeValid(String input, String expected)
+    {
+        var rs = Normalize(input);
+        Assert.Equal(expected, rs);
+    }
+}
Modified +39 -3
diff --git a/Stardust/StarClient.Linux.cs b/Stardust/StarClient.Linux.cs
index 3850b81..7c07bf6 100644
--- a/Stardust/StarClient.Linux.cs
+++ b/Stardust/StarClient.Linux.cs
@@ -368,19 +368,55 @@ public partial class StarClient
 
             // 方式1:通过 xdpyinfo 获取 DPI
             if (di.Dpi.IsNullOrEmpty())
-                di.Dpi = GetDpiByXdpyinfo();
+                di.Dpi = NormalizeDpi(GetDpiByXdpyinfo());
 
             // 方式2:通过 xrdb 获取 Xft.dpi 设置
             if (di.Dpi.IsNullOrEmpty())
-                di.Dpi = GetDpiByXrdb();
+                di.Dpi = NormalizeDpi(GetDpiByXrdb());
 
             // 方式3:通过 GNOME/KDE 配置获取缩放比例推算 DPI
             if (di.Dpi.IsNullOrEmpty())
-                di.Dpi = GetDpiByGSettings();
+                di.Dpi = NormalizeDpi(GetDpiByGSettings());
         }
         catch { }
     }
 
+    private static String? NormalizeDpi(String? dpi)
+    {
+        if (!TryParseDpi(dpi, out var dx, out var dy)) return null;
+
+        // DPI 极值通常是采集/解析异常(如 CentOS 7.6 出现 3072*3072)
+        // 常见 DPI:96/120/144/192/240/288 等,此处给一个宽松上限
+        if (dx <= 0 || dy <= 0) return null;
+        if (dx > 1000 || dy > 1000) return null;
+
+        // 保持存储格式一致:x*y
+        if (dx == dy) return $"{dx}*{dy}";
+
+        // 少数环境会出现非等比例值(取平均更贴近 UI 缩放感知)
+        var d = (Int32)Math.Round((dx + dy) / 2d);
+        if (d <= 0 || d > 1000) return null;
+
+        return $"{d}*{d}";
+    }
+
+    private static Boolean TryParseDpi(String? text, out Int32 dpiX, out Int32 dpiY)
+    {
+        dpiX = 0;
+        dpiY = 0;
+
+        if (text.IsNullOrEmpty()) return false;
+
+        // 允许 "96*96" 或 "96x96"
+        var m = Regex.Match(text.Trim(), @"^(\d+)\s*[*xX]\s*(\d+)$");
+        if (!m.Success) return false;
+
+        dpiX = m.Groups[1].Value.ToInt();
+        dpiY = m.Groups[2].Value.ToInt();
+
+        return dpiX > 0 && dpiY > 0;
+    }
+
     /// <summary>通过 xrandr 获取当前分辨率</summary>
     private static String? GetResolutionByXrandr()
     {