Why is Graphics.DrawImage cropping part of my image?
Asked Answered
C

2

10

If you consider the following image, it's a fairly basic icon, sized at 32x32. Around the icon is a transparent rectangle, although I filled in the four corners with a solid colour while testing.

Source Image

Now consider this code, which simply draws the image, but at a larger scale:

protected override void OnPaint(PaintEventArgs e)
{
  base.OnPaint(e);

  e.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
  e.Graphics.DrawImage(Properties.Resources.icon_32a, new RectangleF(0, 0, 512, 512), new RectangleF(0, 0, 32, 32), GraphicsUnit.Pixel);
}

Note that I'm drawing the full image and I'm not attempting to crop it in any way, just enlarge it.

Finally, this is the output the test gives me:

Painted example

Notice the problem? Half of the pixels in the top row and left column have vanished. If I then try and overlay a grid on top of this, it looks pretty awful as the grid is correctly aligned, but the image is not. Even just doubling the size to 64, 64 introduces this first row/column crop.

Note, I also tried offset the destination rectangle just in case it was drawing before 0,0, but this was not the case.

I also tried using different interpolation modes, but as far as I could tell through the headache inducing blur, the pixels were still cropped, so I don't believe it's due to the interpolation mode.

I also attempted using different graphics modes, but aside from the fact that it didn't seem to help, I need to stick with pixels anyway.

I tried again with a new copy of the image at 96dpi out of curiosity and got the same effect so I don't think it's the resolution of the source images.

Clutching at straws and using Rectangle instead of RectangleF also had no effect.

Can anyone offer any clues as to why this apparent crop is occurring?

Thanks;

Cardialgia answered 28/12, 2012 at 13:32 Comment(0)
L
10

The PixelOffsetMode is set by default to PixelOffsetMode.Half:

Specifies that pixels are offset by -.5 units, both horizontally and vertically, for high speed antialiasing.

In your case half a pixel in the original image is 8 pixels in the resulting image, which is exactly what you are missing.

Try setting it to PixelOffsetMode.None PixelOffsetMode.HighQuality:

protected override void OnPaint(PaintEventArgs e)
{
     base.OnPaint(e);

     e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
     e.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
     e.Graphics.DrawImage(Properties.Resources.icon_32a, new RectangleF(0, 0, 512, 512), new RectangleF(0, 0, 32, 32), GraphicsUnit.Pixel);
}
Later answered 28/12, 2012 at 13:36 Comment(3)
Rotem, thanks for your answer - I wasn't aware of this particular property. I tested it but it still didn't work. However, I found if I set it HighQuality then my image was rendered correctly. Sounds like a silly default value to me, but easy to fix if you know - thanks again!Cardialgia
I had same problem. Also wasn't aware of PixelOffsetMode property. Again, PixelOffsetMode.None did not work for me despite being the obvious setting but PixelOffsetMode.HighQuality did work.Amide
Actually, the default is shifting it half a pixel, but this does not correspond to Half in the enum. In fact, setting it to Half reduces that behaviour by half a pixel, thus solving the problem. I believe HighQuality and Half have the same effect in practice.Auditorium
S
3

Just covering reply comfirmed by users, I tried it myself and the problem was solved with PixelOffsetMode.HighQuality instead none.

c#

e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;

my case c++ managed:

e->graphics->PixelOffsetMode = System::Drawing::Drawing2D::PixelOffsetMode::HighQuality;
Schertz answered 20/10, 2015 at 12:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.