C#已调整大小的图像具有黑色边框

时间:2009-12-07 16:57:21

标签: c# .net image scaling

我在.NET中有图像缩放问题。我使用标准的图形类型来调整图像大小,如下例所示:

public static Image Scale(Image sourceImage, int destWidth, int destHeight)
{
        Bitmap toReturn = new Bitmap(sourceImage, destWidth, destHeight);

        toReturn.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution);

        using (Graphics graphics = Graphics.FromImage(toReturn))
        {
            graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
            graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
            graphics.DrawImage(sourceImage, 0, 0, destWidth, destHeight);
        }
        return toReturn;
    }

但是我对调整大小的图像有一个很大的问题:它们有灰色和黑色边框,制作没有它们的图像非常重要。

为什么它们出现以及我能做些什么让它们消失?

示例输出:

sample output

9 个答案:

答案 0 :(得分:7)

尝试:

graphic.CompositingMode = CompositingMode.SourceCopy;

答案 1 :(得分:7)

这可能是由于边缘周围的像素被错误插值引起的。我称这是一个错误。

以下是解决方案:

graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.PixelOffsetMode = PixelOffsetMode.Half;
graphics.InterpolationMode = InterpolationMode.NearestNeighbor;

// Draw your image here.

graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;

// Draw it again.

这样做首先绘制正确填充边缘的“背景”,然后再用插值绘制它。如果您不需要插值,那么这不是必需的。

答案 2 :(得分:6)

真正的解决方案是使用DrawImage的重载,它允许您传递ImageAttributes对象。

ImageAttributes实例上,在将其传递给DrawImage之前调用以下方法:

using (var ia = new ImageAttributes())
{
    ia.SetWrapMode(WrapMode.TileFlipXY);
    aGraphic.DrawImage(..., ia);
}

另见this answer

答案 3 :(得分:5)

问题在于您的位图toReturn默认情况下为黑色背景。 在其上复制新图像会产生黑色或灰色边框。

解决方法是通过调用:

删除黑色默认背景
toReturn.MakeTransparent();

由于在此行之后您将使用没有任何背景颜色的新图像绘制边框将消失。

答案 4 :(得分:3)

这是因为从照片边缘拍摄了照片。

答案 5 :(得分:2)

以下内容如何为您服务?这是我用来做同样事情的代码。我注意到的主要区别是我没有使用SetResolution(我假设一个方形输入和输出,因为对我来说就是这种情况)。

/// <summary>
/// Resizes a square image
/// </summary>
/// <param name="OriginalImage">Image to resize</param>
/// <param name="Size">Width and height of new image</param>
/// <returns>A scaled version of the image</returns>
internal static Image ResizeImage( Image OriginalImage, int Size )
{
    Image finalImage = new Bitmap( Size, Size );

    Graphics graphic = Graphics.FromImage( finalImage );

    graphic.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
    graphic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;
    graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

    Rectangle rectangle = new Rectangle( 0, 0, Size, Size );

    graphic.DrawImage( OriginalImage, rectangle );

    return finalImage;
}

答案 6 :(得分:1)

这是因为绘制图像时边缘上的平滑(与背景混合)。

你可以画两次,一次没有,一次启用平滑。或者你可以画得更大一些。或者,如果已知原始背景颜色,则可以先使用背景颜色填充图像。

答案 7 :(得分:1)

这些都不适合我。

但是,从

更改格式
System.Drawing.Imaging.PixelFormat.Format24bppRgb

System.Drawing.Imaging.PixelFormat.Format32bppArgb 

确实解决了问题

using (System.Drawing.Bitmap newImage = new System.Drawing.Bitmap(newWidth, newHeight,
                // System.Drawing.Imaging.PixelFormat.Format24bppRgb // OMG bug
                    System.Drawing.Imaging.PixelFormat.Format32bppArgb 
                ))
            {

答案 8 :(得分:1)

正确的答案可以从其他一些答案中拼凑出来,但是没有一个是完整的,有些提出了一些非常糟糕的想法(比如两次绘制图像)。

您看到的工件有三个原因:

  1. 默认Graphics.PixelOffsetMode设置会导致像素值采样不正确,从而导致图像轻微失真,尤其是边缘周围。
  2. InterpolationMode.HighQualityBicubic对图片边缘以外的像素进行采样,默认情况下是透明的。这些透明像素由采样器与边缘像素混合,产生半透明边缘。
  3. 当您以不支持透明度的格式(例如JPEG)保存半透明图像时,透明值将替换为黑色。
  4. 所有这些都加起来是半黑色(即灰色)边缘。

    删除这些工件的正确方法是使用PixelOffsetMode.Half并使用ImageAttributes对象指定边缘平铺,以便HighQualityBicubic采样器具有除透明像素之外的其他内容。< / p>

    您发布的代码还存在其他一些问题:

    您使用的Bitmap构造函数是通过调整原始图像的大小来初始化新的Bitmap,因此您正在进行两次调整大小操作。您应该使用仅具有所需尺寸的构造函数重载来创建空白画布。

    请记住,Bitmap类表示内存中图像的非托管副本。需要对它进行处理,以便GDI +可以在完成后释放该内存。我假设您在接收返回Image的代码中执行此操作,但我指出了以防其他人借用此代码。

    如果您将其他设置设置为正确,则代码中使用的CompositingQuality.HighQuality设置将没有视觉效果,并且与CompositingMode.SourceOver的默认值相结合,实际上会显着损害性能。您可以省略CompositingQuality设置并设置CompositingMode.SourceCopy以获得相同的结果并获得更好的效果。

    代码中使用的SmoothingMode设置对DrawImage()完全没有任何影响,因此可以将其删除。

    您可以在此处详细了解Graphics课程设置及其对图像质量和效果的影响:http://photosauce.net/blog/post/image-scaling-with-gdi-part-3-drawimage-and-the-settings-that-affect-it

    修改后的代码应如下所示:

    public static Image Scale(Image sourceImage, int destWidth, int destHeight)
    {
        var toReturn = new Bitmap(destWidth, destHeight);
    
        using (var graphics = Graphics.FromImage(toReturn))
        using (var attributes = new ImageAttributes())
        {
            toReturn.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution);
    
            attributes.SetWrapMode(WrapMode.TileFlipXY);
    
            graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
            graphics.PixelOffsetMode = PixelOffsetMode.Half;
            graphics.CompositingMode = CompositingMode.SourceCopy;
            graphics.DrawImage(sourceImage, Rectangle.FromLTRB(0, 0, destWidth, destHeight), 0, 0, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel, attributes);
        }
    
        return toReturn;
    }