DpiHelper.cs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. using System;
  2. using System.Windows;
  3. using System.Windows.Media;
  4. using HandyControl.Expression.Drawing;
  5. using HandyControl.Tools.Interop;
  6. namespace HandyControl.Tools;
  7. internal static class DpiHelper
  8. {
  9. private const double LogicalDpi = 96.0;
  10. [ThreadStatic]
  11. private static Matrix _transformToDip;
  12. static DpiHelper()
  13. {
  14. var dC = InteropMethods.GetDC(IntPtr.Zero);
  15. if (dC != IntPtr.Zero)
  16. {
  17. // 沿着屏幕宽度每逻辑英寸的像素数。在具有多个显示器的系统中,这个值对所有显示器都是相同的
  18. const int logicPixelsX = 88;
  19. // 沿着屏幕高度每逻辑英寸的像素数
  20. const int logicPixelsY = 90;
  21. DeviceDpiX = InteropMethods.GetDeviceCaps(dC, logicPixelsX);
  22. DeviceDpiY = InteropMethods.GetDeviceCaps(dC, logicPixelsY);
  23. InteropMethods.ReleaseDC(IntPtr.Zero, dC);
  24. }
  25. else
  26. {
  27. DeviceDpiX = LogicalDpi;
  28. DeviceDpiY = LogicalDpi;
  29. }
  30. var identity = Matrix.Identity;
  31. var identity2 = Matrix.Identity;
  32. identity.Scale(DeviceDpiX / LogicalDpi, DeviceDpiY / LogicalDpi);
  33. identity2.Scale(LogicalDpi / DeviceDpiX, LogicalDpi / DeviceDpiY);
  34. TransformFromDevice = new MatrixTransform(identity2);
  35. TransformFromDevice.Freeze();
  36. TransformToDevice = new MatrixTransform(identity);
  37. TransformToDevice.Freeze();
  38. }
  39. public static MatrixTransform TransformFromDevice { get; }
  40. public static MatrixTransform TransformToDevice { get; }
  41. public static double DeviceDpiX { get; }
  42. public static double DeviceDpiY { get; }
  43. public static double LogicalToDeviceUnitsScalingFactorX => TransformToDevice.Matrix.M11;
  44. public static double LogicalToDeviceUnitsScalingFactorY => TransformToDevice.Matrix.M22;
  45. public static Point DevicePixelsToLogical(Point devicePoint, double dpiScaleX, double dpiScaleY)
  46. {
  47. _transformToDip = Matrix.Identity;
  48. _transformToDip.Scale(1d / dpiScaleX, 1d / dpiScaleY);
  49. return _transformToDip.Transform(devicePoint);
  50. }
  51. public static Size DeviceSizeToLogical(Size deviceSize, double dpiScaleX, double dpiScaleY)
  52. {
  53. var pt = DevicePixelsToLogical(new Point(deviceSize.Width, deviceSize.Height), dpiScaleX, dpiScaleY);
  54. return new Size(pt.X, pt.Y);
  55. }
  56. public static Rect LogicalToDeviceUnits(this Rect logicalRect)
  57. {
  58. var result = logicalRect;
  59. result.Transform(TransformToDevice.Matrix);
  60. return result;
  61. }
  62. public static Rect DeviceToLogicalUnits(this Rect deviceRect)
  63. {
  64. var result = deviceRect;
  65. result.Transform(TransformFromDevice.Matrix);
  66. return result;
  67. }
  68. public static double RoundLayoutValue(double value, double dpiScale)
  69. {
  70. double newValue;
  71. if (!MathHelper.AreClose(dpiScale, 1.0))
  72. {
  73. newValue = Math.Round(value * dpiScale) / dpiScale;
  74. if (double.IsNaN(newValue) || double.IsInfinity(newValue) || MathHelper.AreClose(newValue, double.MaxValue))
  75. {
  76. newValue = value;
  77. }
  78. }
  79. else
  80. {
  81. newValue = Math.Round(value);
  82. }
  83. return newValue;
  84. }
  85. }