为什么GDI+裁剪缩放图像?
我正在使用 GDI+ (C#) 进行一些图像缩放,并注意到一个问题,即我正在缩放的图像沿着左侧和顶部边缘被切断。
要重现此内容,请创建一个新的表单项目,保存将此图像放入 bin\debug 文件夹中,并将以下代码添加到表单中(以及相应的事件):
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
int scale = 1;
Image img = Image.FromFile("circle.png");
private void Form1_Paint(object sender, PaintEventArgs e) {
//this makes the glitch easier to see
e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
RectangleF srcRect = new RectangleF(0f, 0f, img.Width, img.Height);
RectangleF destRect = new RectangleF(0f, 0f, img.Width * scale, img.Height * scale);
e.Graphics.DrawImage(img, destRect, srcRect, GraphicsUnit.Pixel);
}
private void Form1_Click(object sender, EventArgs e) {
scale++;
if (scale > 8) scale = 1;
Invalidate();
}
}
如您所见,左侧和右侧最上面的像素行被切断,就像缩放矩形在像素的中间开始一样。
编辑:请注意,我还尝试使用缩放变换而不是使用上面的矩形,并且它呈现完全相同。
现在,也就是说,我确实发现了一种解决方法。如果您像这样更改上面示例中的矩形声明:
RectangleF srcRect = new RectangleF(-0.5f, -0.5f, img.Width, img.Height);
这样我们就可以纠正“中途”的情况,然后图像就会正确渲染。
基本上,虽然这很容易解决,但我是否做错了什么,或者这是正常行为?
编辑:根据 Andrei Pana 的建议,我尝试在绘图调用之前添加此代码:
e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.None;
而且,不幸的是,它并没有影响渲染。边缘还是被切掉了。
I am doing some image scaling using GDI+ (C#), and have noticed a problem where the image I am scaling is being cut off along the left and top edges.
To reproduce this, create a new form project, save this image into the bin\debug folder, and add the following code to the form (and, the corresponding events):
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
int scale = 1;
Image img = Image.FromFile("circle.png");
private void Form1_Paint(object sender, PaintEventArgs e) {
//this makes the glitch easier to see
e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
RectangleF srcRect = new RectangleF(0f, 0f, img.Width, img.Height);
RectangleF destRect = new RectangleF(0f, 0f, img.Width * scale, img.Height * scale);
e.Graphics.DrawImage(img, destRect, srcRect, GraphicsUnit.Pixel);
}
private void Form1_Click(object sender, EventArgs e) {
scale++;
if (scale > 8) scale = 1;
Invalidate();
}
}
As you can see, the left- and top-most rows of pixels are being cut off, as if the scaling rectangle is starting half-way in the pixel.
Edit: For note, I also tried using a Scale transform instead of using rectangles as above, and it rendered exactly the same.
Now, that said, I did discover a work around. If you change the rectangle declarations in sample above like this:
RectangleF srcRect = new RectangleF(-0.5f, -0.5f, img.Width, img.Height);
So that we correct for the "half-way" thing, then the image renders correctly.
Basically, while this is easy to work around, am I doing something wrong, or is this normal behaviour?
Edit: As per Andrei Pana's suggestion, I tried adding this code before the drawing call:
e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.None;
And, unfortunately, it did not affect the rendering. The edge was still cut off.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
将图像的大小设置为比其包含的图形大 2 个像素(在每个维度上)。我也遇到过这种情况,并且发现抗锯齿过冲每侧绝不会超过 1 个像素。
换句话说,要么关闭抗锯齿功能(这将解决此问题),要么将代码的这一部分更改
为:(
或使用使用 srcRect 的等效解决方法)
是的,这是正常行为,并且是GDI+/.Net 的已知问题。
Set the size of the image to be 2 pixels larger (in each dimension) than the graphic that it contains. I have encountered this as well, and have found that the antialiasing over-shoot is never more than 1 pixel on each side.
In other words, either turn off the anti-aliasing (which will fix this), or change this section of your code:
to this:
(or use an equivalent work-around that uses srcRect)
Yes, this is normal behavior and is a known issue with GDI+/.Net.
这些是:我的高质量设置和我发现适用于像素化图像的设置:
These are: my go-to setting for high quality and the one I've found works for pixelated images:
尝试将 PixelOffsetMode 设置为 PixelOffsetMode.Half。默认情况下,对于高速抗锯齿,像素偏移 -0.5
Try setting the PixelOffsetMode to PixelOffsetMode.Half. By default, for high speed anti aliasing, pixels are offset by -0.5