我发现在使用System.Drawing.Graphics类调整图像大小时,结果图像从右边框和下边框错过了一个像素。这是我的代码或.Net问题中的某个地方的错误? 测试代码:
public static void Resize(string imagePath,int width) {
InterpolationMode[] interpolationModes = new InterpolationMode[]{InterpolationMode.Bicubic, InterpolationMode.Bilinear, InterpolationMode.Default, InterpolationMode.High,
InterpolationMode.HighQualityBicubic, InterpolationMode.HighQualityBilinear, InterpolationMode.Low, InterpolationMode.NearestNeighbor};
SmoothingMode[] smoothingModes = new SmoothingMode[]{SmoothingMode.AntiAlias, SmoothingMode.Default, SmoothingMode.HighQuality, SmoothingMode.HighSpeed,
SmoothingMode.None};
for(int i = 0; i < interpolationModes.Length; i++) {
for(int j = 0; j < smoothingModes.Length; j++) {
Resize(imagePath, width, interpolationModes[i], smoothingModes[j]);
}
}
}
public static void Resize(string imagePath,int width, InterpolationMode interpolationMode, SmoothingMode smoothingMode) {
Image imgPhoto = Image.FromFile(imagePath);
float percent = (float)width / (float)imgPhoto.Width;
int height = (int)(imgPhoto.Height * percent);
Bitmap bmPhoto = new Bitmap(width, height, PixelFormat.Format24bppRgb);
bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);
Graphics grPhoto = Graphics.FromImage(bmPhoto);
grPhoto.InterpolationMode = interpolationMode;
grPhoto.SmoothingMode = smoothingMode;
grPhoto.DrawImage(imgPhoto,
new Rectangle(0, 0, width, height),
new Rectangle(0, 0, imgPhoto.Width, imgPhoto.Height ),
GraphicsUnit.Pixel);
grPhoto.Dispose();
string fileName = Path.GetFileName(imagePath);
string path = Path.GetDirectoryName(imagePath)+"\\resized";
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
bmPhoto.Save(String.Format("{0}\\{1}_{2}_{3}", path, interpolationMode.ToString(), smoothingMode.ToString(),fileName));
}
来源图片: Source image http://img110.imageshack.us/img110/4876/sampleaa2.jpg
结果: Result http://img110.imageshack.us/img110/2050/resizedsamplesy4.png
P.S。我曾尝试过InterpolationMode和SmoothingMode的所有现有组合。他们都没有给出可接受的结果。
答案 0 :(得分:2)
这是.NET图形中的一个错误,非常令人讨厌。它不是舍入误差或算法问题。如果创建100x100位图,然后使用100x100矩形作为参数之一调用DrawRectangle,则可以看到相同问题的变体:您将看不到绘制矩形的底部或右侧。
答案 1 :(得分:2)
无耻地从this question解除答案,我发现这个问题解决了这个问题:
using (ImageAttributes wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
g.DrawImage(input, rect, 0, 0, input.Width, input.Height, GraphicsUnit.Pixel, wrapMode);
}
答案 2 :(得分:1)
如果您的线条在原始线条中仅为1像素宽,则会发生这种情况。当它调整大小时,算法会使右边和底边的边框显示为“修剪掉”,实际上,正在发生的是算法根据像素色调/颜色/饱和度/位置放置一定程度的重要性。它认为内部细胞优先,边界丢失。各种图形应用程序,如Adobe Photoshop和Corel PaintShop Pro为您提供各种调整大小选项[插值模式],以帮助避免这样的事情。您需要将interpolationMode更改为不同的东西。我有一段时间没有使用GDI +,所以我忘记了可用的模式。尝试每种模式,看看哪种模式最容易被接受。
我可能会做的是保证边界的完整性:
这样您的边框将保持不变 - 围绕调整大小的图像的单个红色像素。
答案 3 :(得分:0)
鉴于您缩放的百分比并不总是会产生整数结果,这将导致舍入错误,从而产生边界。
您将不得不确定任何尺寸的圆角是否会添加像素边框(您可以检查舍入)。如果是,则可以创建一个新的位图,然后复制不包含边框的图片部分。
答案 4 :(得分:0)
我在open-source image resizing library中已经很难解决这个问题。
我找到的最佳解决方案是使用HighQualityBicubic,WrapMode.TileFlipXY,并使用DrawImage的平行四边形重载。结果仍显示外部像素略有下降,但不会修剪掉任何内容。通过将图形对象的背景颜色设置为接近外边缘颜色的颜色,您甚至可以最大限度地减少该问题。
来源摘录:
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
g.CompositingMode = CompositingMode.SourceOver;
s.copyAttibutes.SetWrapMode(WrapMode.TileFlipXY);
s.destGraphics.DrawImage(s.sourceBitmap, PolygonMath.getParallelogram(s.layout["image"]), s.copyRect, GraphicsUnit.Pixel, s.copyAttibutes);
如果这没有帮助,我建议禁用SetResolution调用,因为那是剩下的最后一个变量。