Dmitri Nesteruk
Dmitri Nesteruk

Reputation: 23789

Why is WinForms drawing my image 4x the size?

I'm using WinForms to create a 512x512 px image with 96dpi resolution. After initialization, I use OnPaint to draw this image using Graphics.DrawImage. What I get as I run the program is the image shown below: essentially a 1024x1024 image which contains some jung vaguely resembling what I want to show, except it's made up of 2x2-pixel blocks all having uniformly identical colors. Which is weird.

Can someone help me figure out what is going on? This is only happening on high-DPI displays, the program works just fine on ordinary ones.

enter image description here

Update 1: I explicitly set the process to be DPI-unaware with SetProcessDpiAwareness(_Process_DPI_Awareness.Process_DPI_Unaware); and explicitly call DrawImage in a rectangle, i.e.,

e.Graphics.DrawImage(bmp, 
      new Rectangle(0, 0, 512, 512), 
      new Rectangle(0, 0, 512, 512), GraphicsUnit.Pixel);

and it did not help.

Edit 2: After turning DPI awareness on, I now get the same junk, but at the right size:

enter image description here

Edit 3: Finally got it, the artifacts were the results of my rendering things incorrectly on the CUDA side. The high-DPI nonsense was just a distraction.

Upvotes: 3

Views: 279

Answers (1)

Hans Passant
Hans Passant

Reputation: 941525

This is only happening on high-DPI displays

That is entirely normal, you are seeing the image getting rescaled to match the DPI of the monitor. Which makes it bigger so the size in inches is the same.

The crude way to get this done is when you rely on DPI virtualization. Windows lets your program behave like it does on 96 DPI monitor, but gets it to draw into a bitmap. And rescales that bitmap to display it on the screen. Pretty crude, but your program is still usable, text quality suffers pretty noticeably.

The not-crude way is when you declared you program to be dpiAware. Now Windows no longer helps and it is Graphics.DrawImage() that takes care of the job. It by itself rescales the image to match the image DPI to the display DPI. Text looks very crisp. The image, meh, you have to move your chair back further.

If you don't want this rescaling to happen then you have to use the Graphics.DrawImage() overload that takes a Rectangle argument. But keep in mind that the image turns into a postage stamp on such a nice display. You'll have to move your chair closer :)

Upvotes: 4

Related Questions