首页 > 解决方案 > .Net 绘图得到鬼边框并在错误的位置调整大小

问题描述

当在实时服务器上调整图像大小而不是在 localhost 上时,我遇到了一个问题(鬼边框)。这真的很奇怪。我在网上做了一些研究,发现了类似的解决方案:

  1. https://mariusschulz.com/blog/preventing-ghost-borders-when-resizing-images-with-system-drawing
  2. https://www.codeproject.com/Articles/11143/Image-Resizing-outperform-GDI
  3. 在 GDI+ 中调整大小时出现鬼边框(“响铃”)

下面是我正在使用的代码,里面我已经注释了旧代码和新代码。

protected byte[] ApplyResize(byte[] byteArray, int targetSize, Size originalSize = default(Size))
{
    using (MemoryStream ms = new MemoryStream(byteArray))
    {
        if (targetSize <= 0)
        {
            targetSize = 800;
        }

        var image = Image.FromStream(ms);
        var size = default(Size);
        if (originalSize != default(Size))
        {
            size = CalculateDimensions(originalSize, targetSize);
        }
        else
        {
            size = new Size(targetSize, targetSize);
        }

        var resized = new Bitmap(size.Width, size.Height);
        using (var graphics = Graphics.FromImage(resized))
        {
            //old code
            //graphics.CompositingQuality = CompositingQuality.HighSpeed;
            //graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
            //graphics.CompositingMode = CompositingMode.SourceCopy;
            //graphics.DrawImage(image, 0, 0, size.Width, size.Height);

            //new code
            graphics.CompositingQuality = CompositingQuality.HighSpeed;
            graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
            graphics.CompositingMode = CompositingMode.SourceCopy;
            var attributes = new ImageAttributes();
            attributes.SetWrapMode(WrapMode.TileFlipXY);
            var destination = new Rectangle(0, 0, size.Width, size.Height);
            graphics.DrawImage(image, destination, 0, 0, size.Width, size.Height, GraphicsUnit.Pixel, attributes);
        }
        using (var ms2 = new MemoryStream())
        {
            resized.Save(ms2, image.RawFormat);
            return ms2.ToArray();
        }
    }
}

我在直播服务器上测试过,是的,鬼边框消失了,但是图像位置不对。

此图是resize后的预期效果,全部清晰,没问题

这就是在 localhost 和实时服务器上发生的情况,当使用新代码时,图像会以奇怪的位置被剪切

标签: c#.netresizegdi+system.drawing

解决方案


在我看来,调整后图像的 DPI(分辨率)与真实图像不同。这是有道理的,因为新位图的分辨率取决于显示器的分辨率。而且您的服务器可能没有真正的显示器...

为了确保获得预期的结果,您应该在创建新图像之后和绘制到它之前立即使用原始图像的分辨率对其调用 setResolution,如下所示:

var resized = new Bitmap(size.Width, size.Height);
resized.SetResolution(image.HorizontalResolution, image.VerticalResolution);

一般来说,这应该是一个很好的解决方案,因为在本地运行图像时,您可能还会遇到问题,该图像的 DPI 与您正在测试的 DPI 不同。

最重要的是,如上所述,您应该将对 DrawImage 的调用更改为以下内容,因为您忘记指定源矩形:

graphics.DrawImage(image, destination, 0, 0, originalSize.Width, originalSize.Height, GraphicsUnit.Pixel, attributes);

此外,您可能需要解释CalculateDimensions 的作用,因为这可能会产生错误的东西,并且在这里不可见,我们只能猜测。


推荐阅读