3

To reproduce this issue, please create a 2x2 pixel black image in Microsoft Paint, saved as D:\small.png. Then create a new WinForms app in Visual Studio, with a no-margin PictureBox. Then use the following code:

void f6(Graphics g)
{
    var img = Image.FromFile(@"d:\small3.png");
    var srcRect = new Rectangle(0, 0, img.Width, img.Height);
    int factor = 400;
    var destRect = new Rectangle(0, 0, img.Width * factor, img.Height * factor);
    g.DrawRectangle(new Pen(Color.Blue), destRect);
    g.DrawImage(img, destRect, srcRect, GraphicsUnit.Pixel);
}

void pictureBox1_Paint(object sender, PaintEventArgs e)
{
    f6(e.Graphics);
}

I expect the entire rectangle inside the blue margins be black while the output is as follows:

enter image description here

Why is this happening?


ok, thanks. i din't know about interpolation. now, let's change the code as following:

void f6(Graphics g)
{
    var img = Image.FromFile(@"d:\small3.png");
    var srcRect = new Rectangle(0, 0, img.Width, img.Height);
    int factor = 200;
    var destRect = new Rectangle(0, 0, img.Width * factor, img.Height * factor);
    g.FillRectangle(new SolidBrush(Color.DarkCyan), pictureBox1.ClientRectangle);
    g.InterpolationMode = InterpolationMode.NearestNeighbor;
    g.DrawRectangle(new Pen(Color.Blue), destRect);
    g.DrawImage(img, destRect, srcRect, GraphicsUnit.Pixel);
}

it produces the following result:

Result3

which is still unacceptable. i've tried 60x60 images too. the problem is not because it's a 2x2 image. they produce the same effect. the problem is that why GDI+ decides not to fill the entire destRect with the entire srcRect?! the original problem is that i've a big image tiled in smaller ones. i need adjacent tiles neither overlap nor seam exist between them. in C++, StretchBlt works properly. but it doesn't produce a smooth stretched image.

4

2 に答える 2

5

GDI+'s definition of the source rectangle is a bit odd.

(0,0) in the source image is actually the center of the upper-left pixel in the image. (width-1,height-1) is the center of the lower-right pixel in the image.

That means that the upper-left pixel is the rectangle from (-0.5,-0.5) to (0.5,0.5), and the lower-right pixel is the rectangle from (width-1.5,height-1.5) to (width-0.5,height-0.5). Thus, your source rectangle is actually outside the image by 0.5 pixels to the right and bottom.

So, you actually need a source rectangle of (-0.5, -0.5, img.Width, img.Height).

I guess you can also try setting PixelOffsetMode as Hans suggests. That would actually make sense of the behavior, but I wouldn't have expected it to apply to source rectangles.

于 2012-04-11T23:41:07.920 に答える
4

Looks like the image was resized using bicubic interpolation. The normal Bicubic sizing algorithm normally requires 16 pixels to interpolate one, but you only have 4 in the image, so the remaining 12 pixels are never set, staying white.

Try changing the resizing method to nearest-neighbor. This is done by setting the InterpolationMode property of your Graphics object g to InterpolationMode.NearestNeighbor:

void f6(Graphics g) 
{ 
    var img = Image.FromFile(@"d:\small3.png"); 
    var srcRect = new Rectangle(0, 0, img.Width, img.Height); 
    int factor = 400; 
    var destRect = new Rectangle(0, 0, img.Width * factor, img.Height * factor);
    g.ImterpolatonMode = InterpolationMode.NearestNeighbor;
    g.DrawRectangle(new Pen(Color.Blue), destRect); 
    g.DrawImage(img, destRect, srcRect, GraphicsUnit.Pixel); 
} 
于 2012-04-11T04:24:26.180 に答える