Iev*_*ida 12 .net c# scaling image
我在.NET中的图像缩放有问题.我使用标准的Graphics类型来调整图像大小,如下例所示:
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;
}
Run Code Online (Sandbox Code Playgroud)
但是我对调整大小的图像有一个很大的问题:它们有灰色和黑色边框,制作没有图像的图像非常重要.
它们为什么出现以及我能做些什么使它们消失?
样本输出:

尝试:
graphic.CompositingMode = CompositingMode.SourceCopy;
Run Code Online (Sandbox Code Playgroud)
这可能是由于边缘周围的像素被错误插值引起的.我称这是一个错误.
不过这是解决方案:
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.PixelOffsetMode = PixelOffsetMode.Half;
graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
// Draw your image here.
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
// Draw it again.
Run Code Online (Sandbox Code Playgroud)
这样做首先绘制正确填充边缘的"背景",然后再用插值绘制它.如果您不需要插值,那么这不是必需的.
可以从其他一些回答中拼凑出一个正确的答案,但没有一个是完整的,有些还提出了一些非常糟糕的想法(比如画了两次图像)。
您看到的工件有以下三个原因:
Graphics.PixelOffsetMode设置会导致像素值采样不正确,从而导致图像轻微失真,尤其是边缘周围。InterpolationMode.HighQualityBicubic从图像边缘之外采样像素,默认情况下是透明的。这些透明像素通过采样器与边缘像素混合,从而产生半透明边缘。所有这些加起来就是半黑色(即灰色)边缘。
您发布的代码还有其他一些问题:
Bitmap您使用的构造函数Bitmap通过调整原始图像的大小来初始化新图像,因此您要进行两次调整大小操作。您应该使用仅具有所需尺寸的构造函数重载来创建空白画布。
请记住,Bitmap该类表示内存中图像的非托管副本。需要对其进行处理,以便 GDI+ 可以在完成后被告知释放该内存。我假设您在接收 return 的代码中这样做Image,但我指出,以防其他人借用此代码。
CompositingQuality.HighQuality如果其他设置正确,代码中使用的设置将没有视觉效果,并且与默认值CompositingMode.SourceOver. 您可以省略该CompositingQuality设置并设置CompositingMode.SourceCopy为获得相同的结果并具有更好的性能。
SmoothingMode您的代码中使用的设置对 完全没有影响DrawImage(),因此可以将其删除。
去除这些伪影的正确方法是PixelOffsetMode.Half使用一个ImageAttributes对象来指定边缘平铺,这样HighQualityBicubic采样器就可以对透明像素以外的其他东西进行采样。
您可以Graphics在此处阅读有关类设置及其对图像质量和性能的影响的更多信息:http : //photosauce.net/blog/post/image-scaling-with-gdi-part-3-drawimage-and-the-settings-影响它
修改后的代码应该是这样的:
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;
}
Run Code Online (Sandbox Code Playgroud)
真正的解决方案是使用DrawImage允许您传递ImageAttributes对象的重载.
在ImageAttributes实例上,在将其传递给之前调用以下方法DrawImage:
using (var ia = new ImageAttributes())
{
ia.SetWrapMode(WrapMode.TileFlipXY);
aGraphic.DrawImage(..., ia);
}
Run Code Online (Sandbox Code Playgroud)
另见这个答案
问题在于toReturn默认情况下您的位图具有黑色背景.在其上复制新图像会产生黑色或灰色边框.
解决方案是通过调用以下方法删除黑色默认背景:
toReturn.MakeTransparent();
Run Code Online (Sandbox Code Playgroud)
因为在这一行之后你将绘制一个没有任何背景颜色的新图像,边框将消失.