如何使用c#裁剪图像?
当前回答
比公认的答案更简单的是:
public static Bitmap cropAtRect(this Bitmap b, Rectangle r)
{
using (var nb = new Bitmap(r.Width, r.Height))
{
using (Graphics g = Graphics.FromImage(nb))
{
g.DrawImage(b, -r.X, -r.Y);
return nb;
}
}
}
并且它避免了最简单答案的“内存不足”异常风险。
注意,位图和图形是可分割的,因此使用了using子句。
编辑:我发现这是很好的png保存的位图。Save或Paint.exe,但失败的png保存,如Paint Shop Pro 6 -内容被取代。添加GraphicsUnit。Pixel给出了不同的错误结果。也许只是这些失败的png有问题。
其他回答
我正在寻找一个简单和快速的函数,没有额外的库来做这项工作。我尝试了尼克斯解决方案,但我需要29.4秒来“提取”一个atlas文件的1195张图像。所以后来我用这种方法做了同样的工作,需要2.43秒。也许这个会有帮助。
// content of the Texture class
public class Texture
{
//name of the texture
public string name { get; set; }
//x position of the texture in the atlas image
public int x { get; set; }
//y position of the texture in the atlas image
public int y { get; set; }
//width of the texture in the atlas image
public int width { get; set; }
//height of the texture in the atlas image
public int height { get; set; }
}
Bitmap atlasImage = new Bitmap(@"C:\somepicture.png");
PixelFormat pixelFormat = atlasImage.PixelFormat;
foreach (Texture t in textureList)
{
try
{
CroppedImage = new Bitmap(t.width, t.height, pixelFormat);
// copy pixels over to avoid antialiasing or any other side effects of drawing
// the subimages to the output image using Graphics
for (int x = 0; x < t.width; x++)
for (int y = 0; y < t.height; y++)
CroppedImage.SetPixel(x, y, atlasImage.GetPixel(t.x + x, t.y + y));
CroppedImage.Save(Path.Combine(workingFolder, t.name + ".png"), ImageFormat.Png);
}
catch (Exception ex)
{
// handle the exception
}
}
对于任何愿意使用“不安全”代码的人来说,您可以获得比标准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 |
有一个开源的c#包装器,托管在Codeplex上,叫做Web Image裁剪
注册控件
<%@注册程序集="CS.Web.UI. "CropImage CS.Web“Namespace =”。UI" TagPrefix="cs" %>
调整
<asp:Image ID="Image1" runat="server" ImageUrl="images/328.jpg" />
<cs:CropImage ID="wci1" runat="server" Image="Image1"
X="10" Y="10" X2="50" Y2="50" />
在代码后面裁剪-当按钮点击时调用裁剪方法为例;
wci1.Crop (Server.MapPath(“图像/ sample1.jpg”));
比公认的答案更简单的是:
public static Bitmap cropAtRect(this Bitmap b, Rectangle r)
{
using (var nb = new Bitmap(r.Width, r.Height))
{
using (Graphics g = Graphics.FromImage(nb))
{
g.DrawImage(b, -r.X, -r.Y);
return nb;
}
}
}
并且它避免了最简单答案的“内存不足”异常风险。
注意,位图和图形是可分割的,因此使用了using子句。
编辑:我发现这是很好的png保存的位图。Save或Paint.exe,但失败的png保存,如Paint Shop Pro 6 -内容被取代。添加GraphicsUnit。Pixel给出了不同的错误结果。也许只是这些失败的png有问题。
这里有一个裁剪图像的简单例子
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;
}
}
推荐文章
- 如何从枚举中选择一个随机值?
- 驻留在App_Code中的类不可访问
- 在链式LINQ扩展方法调用中等价于'let'关键字的代码
- dynamic (c# 4)和var之间的区别是什么?
- Visual Studio: ContextSwitchDeadlock
- 返回文件在ASP。Net Core Web API
- 自定义HttpClient请求头
- 如果我使用OWIN Startup.cs类并将所有配置移动到那里,我是否需要一个Global.asax.cs文件?
- VS2013外部构建错误"error MSB4019: The imported project <path> was not found"
- 从另一个列表id中排序一个列表
- 等待一个无效的异步方法
- 无法加载文件或程序集…参数不正确
- c#中枚举中的方法
- 如何从字符串中删除新的行字符?
- 如何设置一个默认值与Html.TextBoxFor?