我遇到了Graphics.DrawImage的意外结果

时间:2012-04-11 04:12:00

标签: c# .net gdi+

要重现此问题,请在Microsoft Paint中创建一个2x2像素的黑色图像,保存为D:\small.png。然后在Visual Studio中创建一个新的WinForms应用程序,带有无边距的PictureBox。然后使用以下代码:

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);
}

我希望蓝色边距内的整个矩形为黑色,输出如下:

enter image description here

为什么会这样?


好的,谢谢。我不知道插值。现在,让我们更改代码如下:

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);
}

它产生以下结果:

Result3

这仍然是不可接受的。 我也试过了60x60的图像。问题不在于它是2x2的图像。它们产生同样的效果。问题是为什么GDI +决定不用整个srcRect填充整个destRect?! 最初的问题是我有一个较小的图像。我需要相邻的瓷砖,它们之间既不重叠也不存在接缝。在C ++中,StretchBlt正常工作。但它不会产生平滑的拉伸图像。

2 个答案:

答案 0 :(得分:5)

GDI +对源矩形的定义有点奇怪。

源图像中的

(0,0)实际上是图像中左上角像素的中心。 (width-1,height-1)是图像中右下角像素的中心。

这意味着左上角像素是从(-0.5,-0.5)到(0.5,0.5)的矩形,右下角像素是从(宽度-1.5,高度-1.5)到(宽度-0.5,高度0.5)。因此,您的源矩形实际上位于图像的右侧和底部0.5个像素之外。

所以,你实际上需要一个(-0.5,-0.5,img.Width,img.Height)源矩形。

我猜你也可以尝试设置PixelOffsetMode,就像Hans建议的那样。这实际上会理解行为,但我不希望它适用于源矩形。

答案 1 :(得分:4)

看起来使用双三次插值调整了图像大小。正常的Bicubic大小调整算法通常需要16个像素才能插入一个像素,但图像中只有4个像素,因此剩余的12个像素从未设置,保持白色。

尝试将调整大小方法更改为最近邻居。这是通过将Graphics对象g的InterpolationMode属性设置为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); 
}