在 C# 中调整位图的大小
Resize a Bitmap in C#
我正在寻找一种方法来调整位图的大小,而不会丢失其实际形状,同时要记住新的大小不能与原始图像尺寸成比例。
确切地说,我想将直立八 (40x110) 的图像调整为 29x29 位图,我正在寻找一个函数来将原始比例相对转换为新图像,同时填充新创建的 space(宽度)为白色,并且从实际八个到其白色基线具有相同的侧间隙。
很遗憾,这不能满足我的要求:
public static Bitmap ResizeImage(Image image, int width, int height)
{
var destRect = new Rectangle(0, 0, width, height);
var destImage = new Bitmap(width, height);
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
更新 1:
按比例调整大小的新功能:
public static Bitmap ResizeImageProportional(Bitmap bitmap, int width, int height)
{
Bitmap destImage;
Rectangle destRect;
int destH, destW, destX, dextY;
if (bitmap.Height > bitmap.Width)
{
destH = height;
destW = bitmap.Width / bitmap.Height * height;
destX = (width - destW) / 2;
dextY = 0;
}
else if (bitmap.Height < bitmap.Width)
{
destH = bitmap.Height / bitmap.Width * width;
destW = width;
destX = 0;
dextY = (height - destH) / 2;
}
else
// if (bitmap.Width == bitmap.Height)
{
destH = height;
destW = width;
destX = 0;
dextY = 0;
}
destRect = new Rectangle(destX, dextY, destW, destH);
destImage = new Bitmap(width, height);
destImage.SetResolution(bitmap.HorizontalResolution, bitmap.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(bitmap, destRect, 0, 0, bitmap.Width, bitmap.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
不幸的是,我总是用这个解决方案得到一个空位图。我首先将原始位图裁剪为一个矩形,我的位图元素恰好适合其中。否则将位图本身的左基线也是其中图形元素的基线,而整个背景为白色。
然后我将这个位图(大约 40x80)放入 "ResizeImageProportional"(原始 post 编辑。)函数中,宽度和高度值为 29.
如果你想保留你需要计算目标矩形的比例。
以下是我想到的措施:
destH = height;
destW = image.Width / image.Height * height;
destX = (width - destW) / 2;
dextY = 0;
你应该先把背景清除成你想要的颜色:Graphics.Clear(someColor);
如果不这样做,您将使用源图像和目标图像的边界,从而扭曲图像。哪个是你似乎拥有的..,不是吗?
那么当然没有新的 space。
计算时,必要时使用浮点数..
更新:
也许您想分析原始图像并保留或删除从前景到边缘的 space。这意味着要么查看像素,要么回到原件的创建方式..
对于示例,我添加了图形的边界。
这是一个简单的裁剪功能;它假定左上角包含背景颜色和 returns 裁剪矩形:
public static Rectangle CropBounds(Image image)
{
Bitmap bmp = (Bitmap)image;
int x0 = 0;
int x1 = bmp.Width - 1;
int y0 = 0;
int y1 = bmp.Height - 1;
Color c = bmp.GetPixel(0, 0);
while (x0==0)
{ for (int x = 0; x < x1; x++)
if ((x0==0)) for (int y = 0; y < y1; y++)
if ( bmp.GetPixel(x,y)!= c) {x0 = x-1; break;} }
while (x1 == bmp.Width - 1)
{
for (int x = bmp.Width - 1; x > 0; x--)
if ((x1 == bmp.Width - 1)) for (int y = 0; y < y1; y++)
if (bmp.GetPixel(x, y) != c) { x1 = x + 1; break; } }
while (y0 == 0)
{
for (int y = 0; y < y1; y++)
if ((y0 == 0)) for (int x = 0; x < bmp.Width; x++)
if (bmp.GetPixel(x, y) != c) { y0 = y - 1; break; }
}
while (y1 == bmp.Height - 1)
{
for (int y = bmp.Height - 1; y > 0; y--)
if ((y1 == bmp.Height - 1)) for (int x = 0; x < bmp.Width; x++)
if (bmp.GetPixel(x, y) != c) { y1 = y + 1; break; }
}
return new Rectangle(x0, y0, x1 - x0, y1 - y0);
}
现在您可以更改代码以像这样使用它:
graphics.DrawImage(image, destRect, CropBounds(image) , GraphicsUnit.Pixel);
如果你真的需要翻转,只需存储矩形并更改为适当的格式..!
更新二:
我写是有原因的,计算时,如果需要的话,使用float..:
在您的 ResizeImageProportional
函数中,您需要避免整数精度损失!将部门更改为:
destW = (int) (1f * bitmap.Width / bitmap.Height * height);
和
destH = (int) (1f *bitmap.Height / bitmap.Width * width);
我正在寻找一种方法来调整位图的大小,而不会丢失其实际形状,同时要记住新的大小不能与原始图像尺寸成比例。
确切地说,我想将直立八 (40x110) 的图像调整为 29x29 位图,我正在寻找一个函数来将原始比例相对转换为新图像,同时填充新创建的 space(宽度)为白色,并且从实际八个到其白色基线具有相同的侧间隙。
很遗憾,这不能满足我的要求:
public static Bitmap ResizeImage(Image image, int width, int height)
{
var destRect = new Rectangle(0, 0, width, height);
var destImage = new Bitmap(width, height);
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
更新 1: 按比例调整大小的新功能:
public static Bitmap ResizeImageProportional(Bitmap bitmap, int width, int height)
{
Bitmap destImage;
Rectangle destRect;
int destH, destW, destX, dextY;
if (bitmap.Height > bitmap.Width)
{
destH = height;
destW = bitmap.Width / bitmap.Height * height;
destX = (width - destW) / 2;
dextY = 0;
}
else if (bitmap.Height < bitmap.Width)
{
destH = bitmap.Height / bitmap.Width * width;
destW = width;
destX = 0;
dextY = (height - destH) / 2;
}
else
// if (bitmap.Width == bitmap.Height)
{
destH = height;
destW = width;
destX = 0;
dextY = 0;
}
destRect = new Rectangle(destX, dextY, destW, destH);
destImage = new Bitmap(width, height);
destImage.SetResolution(bitmap.HorizontalResolution, bitmap.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(bitmap, destRect, 0, 0, bitmap.Width, bitmap.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
不幸的是,我总是用这个解决方案得到一个空位图。我首先将原始位图裁剪为一个矩形,我的位图元素恰好适合其中。否则将位图本身的左基线也是其中图形元素的基线,而整个背景为白色。 然后我将这个位图(大约 40x80)放入 "ResizeImageProportional"(原始 post 编辑。)函数中,宽度和高度值为 29.
如果你想保留你需要计算目标矩形的比例。
以下是我想到的措施:
destH = height;
destW = image.Width / image.Height * height;
destX = (width - destW) / 2;
dextY = 0;
你应该先把背景清除成你想要的颜色:Graphics.Clear(someColor);
如果不这样做,您将使用源图像和目标图像的边界,从而扭曲图像。哪个是你似乎拥有的..,不是吗?
那么当然没有新的 space。
计算时,必要时使用浮点数..
更新:
也许您想分析原始图像并保留或删除从前景到边缘的 space。这意味着要么查看像素,要么回到原件的创建方式..
对于示例,我添加了图形的边界。
这是一个简单的裁剪功能;它假定左上角包含背景颜色和 returns 裁剪矩形:
public static Rectangle CropBounds(Image image)
{
Bitmap bmp = (Bitmap)image;
int x0 = 0;
int x1 = bmp.Width - 1;
int y0 = 0;
int y1 = bmp.Height - 1;
Color c = bmp.GetPixel(0, 0);
while (x0==0)
{ for (int x = 0; x < x1; x++)
if ((x0==0)) for (int y = 0; y < y1; y++)
if ( bmp.GetPixel(x,y)!= c) {x0 = x-1; break;} }
while (x1 == bmp.Width - 1)
{
for (int x = bmp.Width - 1; x > 0; x--)
if ((x1 == bmp.Width - 1)) for (int y = 0; y < y1; y++)
if (bmp.GetPixel(x, y) != c) { x1 = x + 1; break; } }
while (y0 == 0)
{
for (int y = 0; y < y1; y++)
if ((y0 == 0)) for (int x = 0; x < bmp.Width; x++)
if (bmp.GetPixel(x, y) != c) { y0 = y - 1; break; }
}
while (y1 == bmp.Height - 1)
{
for (int y = bmp.Height - 1; y > 0; y--)
if ((y1 == bmp.Height - 1)) for (int x = 0; x < bmp.Width; x++)
if (bmp.GetPixel(x, y) != c) { y1 = y + 1; break; }
}
return new Rectangle(x0, y0, x1 - x0, y1 - y0);
}
现在您可以更改代码以像这样使用它:
graphics.DrawImage(image, destRect, CropBounds(image) , GraphicsUnit.Pixel);
如果你真的需要翻转,只需存储矩形并更改为适当的格式..!
更新二:
我写是有原因的,计算时,如果需要的话,使用float..:
在您的 ResizeImageProportional
函数中,您需要避免整数精度损失!将部门更改为:
destW = (int) (1f * bitmap.Width / bitmap.Height * height);
和
destH = (int) (1f *bitmap.Height / bitmap.Width * width);