views:

5278

answers:

3

I am looking to convert pixes to inches and vice versa. I understand that I need DPI, but I am not sure how to get this information (e.g. I don't have the Graphics object, so that's not an option).

Is there a way?

+4  A: 

There's, physically, no real way without knowing the DPI. Pixels are discrete, inches are not, if you're talking inches on your monitor, you need to know (at the very least) the resolution (and pixel aspect ratio) and the size of the visible monitor area in order to calculate your DPI. The resolution is usually possible to fetch somewhere (I'm not a C# or .NET programmer, so I can't help you there), but the size of the monitor is usually not available. If an estimate is good enough then have the user enter the size of the monitor (i.e. 21" or whatever) and solve for DPI:

(resX/DPI)^2 + (resY/DPI)^2 = screenDiagonal^2

giving (assuming you know the diagonal and the resolution)

DPI = sqrt(resX^2+resY^2)/screenDiagonal

This is just an estimate, as monitors are never exactly 21" (.. or whatever), and the pixel aspect ratio is hardly ever exactly 1:1.

If you're talking inches on paper, then, quite naturally you need to know the DPI of your printer (or, more accurately, the current printer settings).

roe
So given that I don't have access to the Graphics object, how do I calculate the DPI?
AngryHacker
Solve the equation for DPI, assuming the rest is known.
roe
How would I know the diagonal length of the monitor? My app will run on computers I don't control.
AngryHacker
Either you make a rough estimate and assume everyone has a 19" or 21" or something; if it's really important, then you have to ask the user, no one else knows (see answer commenting on projectors), but in this case you'll probably want to use some other technology to get a more accurate answer.
roe
This is a pretty useless answer. He's looking for a system call to tell him what windows is assuming is the DPI (as am I).
mmr
@mmr - check the answer below.
codekaizen
+1  A: 

You can create the Graphics object simply by calling this.CreateGraphics() (or more generally Control.CreateGraphics()) and then use the DpiX and DpiY properties as you seem to know. Just remember to dispose the graphics object after creating it (ideally with a Using statement).

If you're not using WinForms, then please let us know what sort of application it is.

Noldorin
I can't. I am writing code in a code-behind file of an ActiveReports report sheet. It does not have these properties.
AngryHacker
He did state that he's using WPF, which is not WinForms. Using the two together can cause serious headaches.
mmr
@mmr: No, he did not state he is using WPF. In fact, the reference to the `Graphic` seems to strongly imply WinForms. Thanks for the down-vote, anyway.
Noldorin
+5  A: 

On a video device, any answer to this question is typically not very accurate. The easiest example to use to see why this is the case is a projector. The output resolution is, say, 1024x768, but the DPI varies by how far away the screen is from the projector apeture. WPF, for example, always assumes 96 DPI on a video device.

Presuming you still need an answer, regardless of the accuracy, and you don't have a Graphics object, you can create one from the screen with some P/Invoke and get the answer from it.

Single xDpi, yDpi;

IntPtr dc = GetDC(IntPtr.Zero);

using(Graphics g = Graphics.FromHdc(dc))
{
    xDpi = g.DpiX;
    yDpi = g.DpiY;
}

if (ReleaseDC(IntPtr.Zero) != 0)
{
    // GetLastError and handle...
}


[DllImport("user32.dll")]
private static extern IntPtr GetDC(IntPtr hwnd);    
[DllImport("user32.dll")]
private static extern Int32 ReleaseDC(IntPtr hwnd);
codekaizen
Based on what the user was asking for, this ought to be the accepted answer.
epotter