为什么GDI+裁剪缩放图像?

发布于 2024-10-08 04:09:26 字数 1557 浏览 0 评论 0原文

我正在使用 GDI+ (C#) 进行一些图像缩放,并注意到一个问题,即我正在缩放的​​图像沿着左侧和顶部边缘被切断。

http://zctut.com/cutoff.png

要重现此内容,请创建一个新的表单项目,保存将此图像放入 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.

http://zctut.com/cutoff.png

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

驱逐舰岛风号 2024-10-15 04:09:27

将图像的大小设置为比其包含的图形大 2 个像素(在每个维度上)。我也遇到过这种情况,并且发现抗锯齿过冲每侧绝不会超过 1 个像素。

换句话说,要么关闭抗锯齿功能(这将解决此问题),要么将代码的这一部分更改

RectangleF destRect = new RectangleF(0f, 0f, img.Width * scale, img.Height * scale);

为:(

RectangleF destRect = new RectangleF(1f, 1f, img.Width * scale -2, img.Height * scale -2);

或使用使用 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:

RectangleF destRect = new RectangleF(0f, 0f, img.Width * scale, img.Height * scale);

to this:

RectangleF destRect = new RectangleF(1f, 1f, img.Width * scale -2, img.Height * scale -2);

(or use an equivalent work-around that uses srcRect)

Yes, this is normal behavior and is a known issue with GDI+/.Net.

时光瘦了 2024-10-15 04:09:27

这些是:我的高质量设置和我发现适用于像素化图像的设置:

// High Quality
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.SmoothingMode = SmoothingMode.HighQuality;

// Pixel Art
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.PixelOffsetMode = PixelOffsetMode.Half;
g.SmoothingMode = SmoothingMode.None;

These are: my go-to setting for high quality and the one I've found works for pixelated images:

// High Quality
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.SmoothingMode = SmoothingMode.HighQuality;

// Pixel Art
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.PixelOffsetMode = PixelOffsetMode.Half;
g.SmoothingMode = SmoothingMode.None;
攒一口袋星星 2024-10-15 04:09:26

尝试将 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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文