3

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

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

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

在此处输入图像描述

为什么会这样?


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

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

它产生以下结果:

结果3

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

4

2 回答 2

5

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

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

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

因此,您实际上需要一个 (-0.5, -0.5, img.Width, img.Height) 的源矩形。

我想您也可以尝试按照 Hans 的建议设置 PixelOffsetMode。这实际上可以理解这种行为,但我没想到它会应用于源矩形。

于 2012-04-11T23:41:07.920 回答
4

看起来图像是使用双三次插值调整大小的。正常的双三次尺寸算法通常需要 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); 
} 
于 2012-04-11T04:24:26.180 回答