如何使用c#裁剪图像?
当前回答
对于任何愿意使用“不安全”代码的人来说,您可以获得比标准System.Drawing.Graphics方法更好的性能,如果使用Bitmap.Clone()则更好。
请记住,32bpp是该方法支持的唯一格式。(其他格式可以工作,只要1像素存储为4字节)
我包含了两个版本,一个使用Span,它在裁剪到较小的图像时性能稍好。 如果裁剪到1000x1000的图像,它们的速度差不多。
如果感兴趣,基准在下面。
public static class BitmapExtension
{
unsafe public static Bitmap Crop(this Bitmap bitmap, int left, int top, int width, int height)
{
Bitmap cropped = new Bitmap(width, height);
BitmapData originalData = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
BitmapData croppedData = cropped.LockBits(new System.Drawing.Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bitmap.PixelFormat);
int* srcPixel = (int*)originalData.Scan0 + (left + originalData.Width * top);
int nextLine = originalData.Width - width;
for (int y = 0, i = 0; y < height; y++, srcPixel += nextLine)
{
for (int x = 0; x < width; x++, i++, srcPixel++)
{
*((int*)croppedData.Scan0 + i) = *srcPixel;
}
}
bitmap.UnlockBits(originalData);
cropped.UnlockBits(croppedData);
return cropped;
}
unsafe public static Bitmap CropSmall(this Bitmap bitmap, int left, int top, int width, int height)
{
Bitmap cropped = new Bitmap(width, height);
BitmapData originalData = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
BitmapData croppedData = cropped.LockBits(new System.Drawing.Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bitmap.PixelFormat);
Span<int> srcPixels = new Span<int>((void*)originalData.Scan0, originalData.Width * originalData.Height);
int nextLine = originalData.Width - width;
for (int y = 0, i = 0, s = left + originalData.Width * top; y < height; y++, s += nextLine)
{
for (int x = 0; x < width; x++, i++, s++)
{
*((int*)croppedData.Scan0 + i) = srcPixels[s];
}
}
bitmap.UnlockBits(originalData);
cropped.UnlockBits(croppedData);
return cropped;
}
}
裁剪3440x1440到1000x1000
Method | Ns |
---|---|
My Method | 1108 |
My Method(Span) | 1141 |
Graphics | 9975 |
Clone() | 21514 |
裁剪3440x1440到256x256
Method | Ns |
---|---|
My Method | 131 |
My Method(Span) | 95 |
Graphics | 1289 |
Clone() | 19680 |
裁剪3440x1440到1440x1440
Method | Ns |
---|---|
My Method | 2237 |
My Method(Span) | 2592 |
Graphics | 9999 |
Clone() | 25925 |
其他回答
对于任何愿意使用“不安全”代码的人来说,您可以获得比标准System.Drawing.Graphics方法更好的性能,如果使用Bitmap.Clone()则更好。
请记住,32bpp是该方法支持的唯一格式。(其他格式可以工作,只要1像素存储为4字节)
我包含了两个版本,一个使用Span,它在裁剪到较小的图像时性能稍好。 如果裁剪到1000x1000的图像,它们的速度差不多。
如果感兴趣,基准在下面。
public static class BitmapExtension
{
unsafe public static Bitmap Crop(this Bitmap bitmap, int left, int top, int width, int height)
{
Bitmap cropped = new Bitmap(width, height);
BitmapData originalData = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
BitmapData croppedData = cropped.LockBits(new System.Drawing.Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bitmap.PixelFormat);
int* srcPixel = (int*)originalData.Scan0 + (left + originalData.Width * top);
int nextLine = originalData.Width - width;
for (int y = 0, i = 0; y < height; y++, srcPixel += nextLine)
{
for (int x = 0; x < width; x++, i++, srcPixel++)
{
*((int*)croppedData.Scan0 + i) = *srcPixel;
}
}
bitmap.UnlockBits(originalData);
cropped.UnlockBits(croppedData);
return cropped;
}
unsafe public static Bitmap CropSmall(this Bitmap bitmap, int left, int top, int width, int height)
{
Bitmap cropped = new Bitmap(width, height);
BitmapData originalData = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
BitmapData croppedData = cropped.LockBits(new System.Drawing.Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bitmap.PixelFormat);
Span<int> srcPixels = new Span<int>((void*)originalData.Scan0, originalData.Width * originalData.Height);
int nextLine = originalData.Width - width;
for (int y = 0, i = 0, s = left + originalData.Width * top; y < height; y++, s += nextLine)
{
for (int x = 0; x < width; x++, i++, s++)
{
*((int*)croppedData.Scan0 + i) = srcPixels[s];
}
}
bitmap.UnlockBits(originalData);
cropped.UnlockBits(croppedData);
return cropped;
}
}
裁剪3440x1440到1000x1000
Method | Ns |
---|---|
My Method | 1108 |
My Method(Span) | 1141 |
Graphics | 9975 |
Clone() | 21514 |
裁剪3440x1440到256x256
Method | Ns |
---|---|
My Method | 131 |
My Method(Span) | 95 |
Graphics | 1289 |
Clone() | 19680 |
裁剪3440x1440到1440x1440
Method | Ns |
---|---|
My Method | 2237 |
My Method(Span) | 2592 |
Graphics | 9999 |
Clone() | 25925 |
你可以使用[图形。使用DrawImage][1]将裁剪图像从位图绘制到图形对象上。
Rectangle cropRect = new Rectangle(...);
using (Bitmap src = Image.FromFile("") as Bitmap)
{
using (Bitmap target = new Bitmap(cropRect.Width, cropRect.Height))
{
using (Graphics g = Graphics.FromImage(target))
{
g.DrawImage(src, new Rectangle(0, 0, target.Width, target.Height),
cropRect,
GraphicsUnit.Pixel);
}
}
}
使用bmp.SetResolution(形象。HorizontalResolution, image .VerticalResolution);
这可能是必要的,即使你在这里实现了最佳答案 特别是如果你的图像真的很好,分辨率不是96.0
我的测试示例:
static Bitmap LoadImage()
{
return (Bitmap)Bitmap.FromFile( @"e:\Tests\d_bigImage.bmp" ); // here is large image 9222x9222 pixels and 95.96 dpi resolutions
}
static void TestBigImagePartDrawing()
{
using( var absentRectangleImage = LoadImage() )
{
using( var currentTile = new Bitmap( 256, 256 ) )
{
currentTile.SetResolution(absentRectangleImage.HorizontalResolution, absentRectangleImage.VerticalResolution);
using( var currentTileGraphics = Graphics.FromImage( currentTile ) )
{
currentTileGraphics.Clear( Color.Black );
var absentRectangleArea = new Rectangle( 3, 8963, 256, 256 );
currentTileGraphics.DrawImage( absentRectangleImage, 0, 0, absentRectangleArea, GraphicsUnit.Pixel );
}
currentTile.Save(@"e:\Tests\Tile.bmp");
}
}
}
这里有一个裁剪图像的简单例子
public Image Crop(string img, int width, int height, int x, int y)
{
try
{
Image image = Image.FromFile(img);
Bitmap bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
bmp.SetResolution(80, 60);
Graphics gfx = Graphics.FromImage(bmp);
gfx.SmoothingMode = SmoothingMode.AntiAlias;
gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
gfx.PixelOffsetMode = PixelOffsetMode.HighQuality;
gfx.DrawImage(image, new Rectangle(0, 0, width, height), x, y, width, height, GraphicsUnit.Pixel);
// Dispose to free up resources
image.Dispose();
bmp.Dispose();
gfx.Dispose();
return bmp;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return null;
}
}
如果你在使用AForge。NET:
using(var croppedBitmap = new Crop(new Rectangle(10, 10, 10, 10)).Apply(bitmap))
{
// ...
}
推荐文章
- 实体框架核心:在上一个操作完成之前,在此上下文中开始的第二个操作
- 如何为构造函数定制Visual Studio的私有字段生成快捷方式?
- 如何使用JSON确保字符串是有效的JSON。网
- AppSettings从.config文件中获取值
- 通过HttpClient向REST API发布一个空体
- 如何检查IEnumerable是否为空或空?
- 自动化invokerrequired代码模式
- 在c#代码中设置WPF文本框的背景颜色
- 在c#中,什么是单子?
- c#和Java中的泛型有什么不同?和模板在c++ ?
- c#线程安全快速(est)计数器
- 如何将此foreach代码转换为Parallel.ForEach?
- 如何分裂()一个分隔字符串到一个列表<字符串>
- 如何转换列表<字符串>列表<int>?
- c#对象列表,我如何得到一个属性的和