using System; using System.Windows; using System.Windows.Media; using HandyControl.Expression.Drawing; using HandyControl.Tools.Interop; namespace HandyControl.Tools; internal static class DpiHelper { private const double LogicalDpi = 96.0; [ThreadStatic] private static Matrix _transformToDip; static DpiHelper() { var dC = InteropMethods.GetDC(IntPtr.Zero); if (dC != IntPtr.Zero) { // 沿着屏幕宽度每逻辑英寸的像素数。在具有多个显示器的系统中,这个值对所有显示器都是相同的 const int logicPixelsX = 88; // 沿着屏幕高度每逻辑英寸的像素数 const int logicPixelsY = 90; DeviceDpiX = InteropMethods.GetDeviceCaps(dC, logicPixelsX); DeviceDpiY = InteropMethods.GetDeviceCaps(dC, logicPixelsY); InteropMethods.ReleaseDC(IntPtr.Zero, dC); } else { DeviceDpiX = LogicalDpi; DeviceDpiY = LogicalDpi; } var identity = Matrix.Identity; var identity2 = Matrix.Identity; identity.Scale(DeviceDpiX / LogicalDpi, DeviceDpiY / LogicalDpi); identity2.Scale(LogicalDpi / DeviceDpiX, LogicalDpi / DeviceDpiY); TransformFromDevice = new MatrixTransform(identity2); TransformFromDevice.Freeze(); TransformToDevice = new MatrixTransform(identity); TransformToDevice.Freeze(); } public static MatrixTransform TransformFromDevice { get; } public static MatrixTransform TransformToDevice { get; } public static double DeviceDpiX { get; } public static double DeviceDpiY { get; } public static double LogicalToDeviceUnitsScalingFactorX => TransformToDevice.Matrix.M11; public static double LogicalToDeviceUnitsScalingFactorY => TransformToDevice.Matrix.M22; public static Point DevicePixelsToLogical(Point devicePoint, double dpiScaleX, double dpiScaleY) { _transformToDip = Matrix.Identity; _transformToDip.Scale(1d / dpiScaleX, 1d / dpiScaleY); return _transformToDip.Transform(devicePoint); } public static Size DeviceSizeToLogical(Size deviceSize, double dpiScaleX, double dpiScaleY) { var pt = DevicePixelsToLogical(new Point(deviceSize.Width, deviceSize.Height), dpiScaleX, dpiScaleY); return new Size(pt.X, pt.Y); } public static Rect LogicalToDeviceUnits(this Rect logicalRect) { var result = logicalRect; result.Transform(TransformToDevice.Matrix); return result; } public static Rect DeviceToLogicalUnits(this Rect deviceRect) { var result = deviceRect; result.Transform(TransformFromDevice.Matrix); return result; } public static double RoundLayoutValue(double value, double dpiScale) { double newValue; if (!MathHelper.AreClose(dpiScale, 1.0)) { newValue = Math.Round(value * dpiScale) / dpiScale; if (double.IsNaN(newValue) || double.IsInfinity(newValue) || MathHelper.AreClose(newValue, double.MaxValue)) { newValue = value; } } else { newValue = Math.Round(value); } return newValue; } }