How can I get the DPI in WPF?

How can I get the DPI in WPF?

How can I get the DPI in WPF?

How can I get the DPI in WPF?

How to get dpi/ppi of UIImage?

How to get dpi/ppi of image in iOS? Maybe raw image file contains this information, so I can get ppi/dpi from NSData? Thank you.

How do I create dpi aware wpf application? [duplicate]

Possible Duplicate: How do I enable dpiAware? I have few WPF application window with Height=768 Width=1024 When user change the DPI to 125%, they won’t be able to view bottom half of the window?

How to Get DPI of Image in C#

hi how can i get dpi of an image using asp.net c#

How I can get the “pointer resolution” (or mouse DPI) on Windows?

experts. How I can query the mouse DPI (pointer resolution) on Windows? I read the article Pointer Ballistics for Windows XP. It says the typical pointer resolution is 400 mickey/inch. But how I can

How do I get the screen DPI using wxPython?

I can get the screen resolution in with wx.DisplaySize() but I don’t see a method which gives me the DPI.

iTextSharp get PDF DPI

How can I get the DPI of the PDF that I am reading from my hard drive into iTextSharp?

How to get screen DPI

I’m trying to get the screen’s dpi but so far it isn’t working. I tried: DisplayMetrics dm = new DisplayMetrics(); mainContext.getWindowManager().getDefaultDisplay().getMetrics(dm); SCREEN_DPI = dm.d

How to get screen width dpi in ANDROID?

How can I get the screen width dpi? DisplayMetrics metrics = getResources().getDisplayMetrics(); int f = metrics.densityDpi; // getWindowManager().getDefaultDisplay().getMetrics(metrics); int wid

How can I detect the dpi on an ipad mini?

I’ve got an ipad app with some pretty small touch points that are just barely acceptable on the 10 inch screen of a normal ipad. I’d like to be able to get the device dpi so I can scale up the size of

Answers

http://blogs.msdn.com/jaimer/archive/2007/03/07/getting-system-dpi-in-wpf-app.aspx seems to work

PresentationSource source = PresentationSource.FromVisual(this);

double dpiX, dpiY;
if (source != null) {
    dpiX = 96.0 * source.CompositionTarget.TransformToDevice.M11;
    dpiY = 96.0 * source.CompositionTarget.TransformToDevice.M22;
}
var dpiXProperty = typeof(SystemParameters).GetProperty("DpiX", BindingFlags.NonPublic | BindingFlags.Static);
var dpiYProperty = typeof(SystemParameters).GetProperty("Dpi", BindingFlags.NonPublic | BindingFlags.Static);

var dpiX = (int)dpiXProperty.GetValue(null, null);
var dpiY = (int)dpiYProperty.GetValue(null, null);

The only way I found to get the “real” monitor dpi is the following. All other mentioned techniques just say 96 which is not correct for the most monitors.

 public class ScreenInformations
{
    public static uint RawDpi { get; private set; }

    static ScreenInformations()
    {
        uint dpiX;
        uint dpiY;
        GetDpi(DpiType.RAW, out dpiX, out dpiY);
        RawDpi = dpiX;
    }

    /// <summary>
    /// Returns the scaling of the given screen.
    /// </summary>
    /// <param name="dpiType">The type of dpi that should be given back..</param>
    /// <param name="dpiX">Gives the horizontal scaling back (in dpi).</param>
    /// <param name="dpiY">Gives the vertical scaling back (in dpi).</param>
    private static void GetDpi(DpiType dpiType, out uint dpiX, out uint dpiY)
    {
        var point = new System.Drawing.Point(1, 1);
        var hmonitor = MonitorFromPoint(point, _MONITOR_DEFAULTTONEAREST);

        switch (GetDpiForMonitor(hmonitor, dpiType, out dpiX, out dpiY).ToInt32())
        {
            case _S_OK: return;
            case _E_INVALIDARG:
                throw new ArgumentException("Unknown error. See https://msdn.microsoft.com/en-us/library/windows/desktop/dn280510.aspx for more information.");
            default:
                throw new COMException("Unknown error. See https://msdn.microsoft.com/en-us/library/windows/desktop/dn280510.aspx for more information.");
        }
    }

    //https://msdn.microsoft.com/en-us/library/windows/desktop/dd145062.aspx
    [DllImport("User32.dll")]
    private static extern IntPtr MonitorFromPoint([In]System.Drawing.Point pt, [In]uint dwFlags);

    //https://msdn.microsoft.com/en-us/library/windows/desktop/dn280510.aspx
    [DllImport("Shcore.dll")]
    private static extern IntPtr GetDpiForMonitor([In]IntPtr hmonitor, [In]DpiType dpiType, [Out]out uint dpiX, [Out]out uint dpiY);

    const int _S_OK = 0;
    const int _MONITOR_DEFAULTTONEAREST = 2;
    const int _E_INVALIDARG = -2147024809;
}

/// <summary>
/// Represents the different types of scaling.
/// </summary>
/// <seealso cref="https://msdn.microsoft.com/en-us/library/windows/desktop/dn280511.aspx"/>
public enum DpiType
{
    EFFECTIVE = 0,
    ANGULAR = 1,
    RAW = 2,
}

Here is a method that relies on the Direct2D technology (supported on Windows Vista with SP2 and higher and servers), so it works fine in WPF (which is based on the same grounds). It uses the ID2D1Factory::GetDesktopDpi method

  public static class DpiUtilities
  {
      private static Lazy<Tuple<float, float>> _dpi = new Lazy<Tuple<float, float>>(ReadDpi);

      public static float DesktopDpiX
      {
          get
          {
              return _dpi.Value.Item1;
          }
      }

      public static float DesktopDpiY
      {
          get
          {
              return _dpi.Value.Item2;
          }
      }

      public static void Reload()
      {
          ID2D1Factory factory;
          int hr = D2D1CreateFactory(D2D1_FACTORY_TYPE.D2D1_FACTORY_TYPE_SINGLE_THREADED, typeof(ID2D1Factory).GUID, IntPtr.Zero, out factory);
          if (hr != 0)
              Marshal.ThrowExceptionForHR(hr);

          factory.ReloadSystemMetrics();
          Marshal.ReleaseComObject(factory);
      }

      private static Tuple<float, float> ReadDpi()
      {
          ID2D1Factory factory;
          int hr = D2D1CreateFactory(D2D1_FACTORY_TYPE.D2D1_FACTORY_TYPE_SINGLE_THREADED, typeof(ID2D1Factory).GUID, IntPtr.Zero, out factory);
          if (hr != 0)
              Marshal.ThrowExceptionForHR(hr);

          float x;
          float y;
          factory.GetDesktopDpi(out x, out y);
          Marshal.ReleaseComObject(factory);
          return new Tuple<float, float>(x, y);
      }

      [DllImport("d2d1.dll")]
      private static extern int D2D1CreateFactory(D2D1_FACTORY_TYPE factoryType, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, IntPtr pFactoryOptions, out ID2D1Factory ppIFactory);

      private enum D2D1_FACTORY_TYPE
      {
          D2D1_FACTORY_TYPE_SINGLE_THREADED = 0,
          D2D1_FACTORY_TYPE_MULTI_THREADED = 1,
      }

      [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
      [Guid("06152247-6f50-465a-9245-118bfd3b6007")]
      private interface ID2D1Factory
      {
          int ReloadSystemMetrics();

          [PreserveSig]
          void GetDesktopDpi(out float dpiX, out float dpiY);

          // the rest is not implemented as we don't need it
      }
  }

With .NET 4.6.2 Preview and higher, there are new APIs added which allow you to call VisualTreeHelper.GetDpi(Visual visual) on any visual. It returns a DpiScale object which tells you the DPI at which a given Visual will be or has been rendered.

https://msdn.microsoft.com/en-us/library/system.windows.media.visualtreehelper.getdpi(v=vs.110).aspx