如何使用 C# 裁剪图像?

Posted

技术标签:

【中文标题】如何使用 C# 裁剪图像?【英文标题】:How to crop an image using C#? 【发布时间】:2010-10-18 14:35:51 【问题描述】:

如何编写一个可以在 C# 中裁剪图像的应用程序?

【问题讨论】:

【参考方案1】:

查看此链接:http://www.switchonthecode.com/tutorials/csharp-tutorial-image-editing-saving-cropping-and-resizing

private static Image cropImage(Image img, Rectangle cropArea)

   Bitmap bmpImage = new Bitmap(img);
   return bmpImage.Clone(cropArea, bmpImage.PixelFormat);

【讨论】:

同意,但请注意,如果cropArea 越过img 边界,则会出现“内存不足”异常。 @KvanTTT,如果您想将大图像裁剪成较小的图像,它们都非常慢。 @ChrisJJ 你能解释更多吗?或为该问题提供解决方法? 他们的网站已关闭。有人从网站上得到代码吗? 这是性能最差的解决方案。 Graphics.DrawImage 解决方案要好得多。【参考方案2】:

您可以使用Graphics.DrawImage 从位图中将裁剪后的图像绘制到图形对象上。

Rectangle cropRect = new Rectangle(...);
Bitmap src = Image.FromFile(fileName) as Bitmap;
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);

【讨论】:

请注意,DrawImage() 的签名无效。 It's missing the GraphicsUnit parameter. 第二个参数也是目标矩形,而不是裁剪矩形。 方法DrawImageUnscaledAndClipped是否比DrawImage更有效?【参考方案3】:

比公认的答案更简单的是:

public static Bitmap cropAtRect(this Bitmap b, Rectangle r)

    Bitmap nb = new Bitmap(r.Width, r.Height);
    using (Graphics g = Graphics.FromImage(nb))
    
        g.DrawImage(b, -r.X, -r.Y);
        return nb;
    

它避免了最简单答案的“内存不足”异常风险。

请注意,BitmapGraphicsIDisposable,因此是 using 子句。

编辑:我发现这对于Bitmap.Save 或 Paint.exe 保存的 PNG 来说很好,但对于通过例如保存的 PNG 则失败。 Paint Shop Pro 6 - 内容被替换。添加GraphicsUnit.Pixel 会给出不同的错误结果。也许只是这些失败的 PNG 是错误的。

【讨论】:

最佳回复在这里,这应该被授予答案。我在其他解决方案上也遇到了“内存不足”。这是第一次工作。 我不明白为什么添加 GraphicsUnit.Pixel 会给出错误的结果,但它确实如此。 这个答案泄露了 Grphics 对象。 BitmapGraphicsIDisposable - 添加 using 子句【参考方案4】:

使用bmp.SetResolution(image.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");
            
        
    

【讨论】:

【参考方案5】:

这是一个关于裁剪图像的简单示例

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;
                

【讨论】:

他是唯一一个提到分辨率的,如果源图像的分辨率不标准,上述所有方法都会失败。 使用 bmp.SetResolution(image .Horizo​​ntalResolution, image .VerticalResolution);解决分辨率问题。 在异常情况下,这将泄漏图像、bmp 和 gfx 对象。为什么不将它们包装在 using 语句中?【参考方案6】:

很简单:

使用裁剪后的大小创建一个新的Bitmap 对象。 使用Graphics.FromImage 为新位图创建Graphics 对象。 使用DrawImage 方法将图像绘制到具有负X 和Y 坐标的位图上。

【讨论】:

最好添加一些示例代码以供参考。不是每个人都像你我一样是编码专家!【参考方案7】:

如果您使用的是AForge.NET:

using(var croppedBitmap = new Crop(new Rectangle(10, 10, 10, 10)).Apply(bitmap))

    // ...

【讨论】:

【参考方案8】:

我一直在寻找一个简单而快速的功能,无需额外的库来完成这项工作。我试过Nicks solution,但我需要 29.4 秒来“提取”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
     

【讨论】:

【参考方案9】:

在 C# 中裁剪图像非常简单。但是,您将如何管理图像的裁剪会有点困难。

下面的示例是如何在 C# 中裁剪图像。

var filename = @"c:\personal\images\horizon.png";
var img = Image.FromFile(filename);
var rect = new Rectangle(new Point(0, 0), img.Size);
var cloned = new Bitmap(img).Clone(rect, img.PixelFormat);
var bitmap = new Bitmap(cloned, new Size(50, 50));
cloned.Dispose();

【讨论】:

【参考方案10】:

有一个开源的 C# 包装器,托管在 Codeplex 上,名为 Web Image Cropping

注册控件

&lt;%@ Register Assembly="CS.Web.UI.CropImage" Namespace="CS.Web.UI" TagPrefix="cs" %&gt;

调整大小

<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("images/sample1.jpg"));

【讨论】:

【参考方案11】:

假设您的意思是要获取图像文件(JPEG、BMP、TIFF 等)并对其进行裁剪,然后将其保存为较小的图像文件,我建议使用具有 .NET API 的第三方工具。以下是我喜欢的一些流行的:

LeadToolsAccusoft Pegasus Snowbound Imaging SDK

【讨论】:

【参考方案12】:

只有这个样本没有问题:

var crop = new Rectangle(0, y, bitmap.Width, h);
var bmp = new Bitmap(bitmap.Width, h);
var tempfile = Application.StartupPath+"\\"+"TEMP"+"\\"+Path.GetRandomFileName();


using (var gr = Graphics.FromImage(bmp))

    try
    
        var dest = new Rectangle(0, 0, bitmap.Width, h);
        gr.DrawImage(image,dest , crop, GraphicsUnit.Point);
        bmp.Save(tempfile,ImageFormat.Jpeg);
        bmp.Dispose();
    
    catch (Exception)
    


    


【讨论】:

【参考方案13】:

这是另一种方式。就我而言,我有:

2 个数字上下控件(称为 LeftMargin 和 TopMargin) 1个图片框(pictureBox1) 我称之为 generate 的 1 个按钮 C:\imagenes\myImage.gif 上有 1 张图片

在按钮里面我有这个代码:

Image myImage = Image.FromFile(@"C:\imagenes\myImage.gif");
Bitmap croppedBitmap = new Bitmap(myImage);
croppedBitmap = croppedBitmap.Clone(
            new Rectangle(
                (int)LeftMargin.Value, (int)TopMargin.Value,
                myImage.Width - (int)LeftMargin.Value,
                myImage.Height - (int)TopMargin.Value),
            System.Drawing.Imaging.PixelFormat.DontCare);
pictureBox1.Image = croppedBitmap;

我在 Visual Studio 2012 中使用 C# 进行了尝试。我从这个page找到了这个解决方案

【讨论】:

【参考方案14】:

这里是github上的工作演示

https://github.com/SystematixIndore/Crop-SaveImageInCSharp

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebApplication1.WebForm1" %>

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title></title>
 <link href="css/jquery.Jcrop.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>
<script type="text/javascript" src="js/jquery.Jcrop.js"></script>
</head>
<body>
  <form id="form2" runat="server">
  <div>
    <asp:Panel ID="pnlUpload" runat="server">
      <asp:FileUpload ID="Upload" runat="server" />
      <br />
      <asp:Button ID="btnUpload" runat="server" OnClick="btnUpload_Click" Text="Upload" />
      <asp:Label ID="lblError" runat="server" Visible="false" />
    </asp:Panel>
    <asp:Panel ID="pnlCrop" runat="server" Visible="false">
      <asp:Image ID="imgCrop" runat="server" />
      <br />
      <asp:HiddenField ID="X" runat="server" />
      <asp:HiddenField ID="Y" runat="server" />
      <asp:HiddenField ID="W" runat="server" />
      <asp:HiddenField ID="H" runat="server" />
      <asp:Button ID="btnCrop" runat="server" Text="Crop" OnClick="btnCrop_Click" />
    </asp:Panel>
    <asp:Panel ID="pnlCropped" runat="server" Visible="false">
      <asp:Image ID="imgCropped" runat="server" />
    </asp:Panel>
  </div>
  </form>
    <script type="text/javascript">
  jQuery(document).ready(function() 
    jQuery('#imgCrop').Jcrop(
      onSelect: storeCoords
    );
  );

  function storeCoords(c) 
    jQuery('#X').val(c.x);
    jQuery('#Y').val(c.y);
    jQuery('#W').val(c.w);
    jQuery('#H').val(c.h);
  ;

</script>
</body>
</html>

用于上传和裁剪的 C# 代码逻辑。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;
using SD = System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;

namespace WebApplication1

    public partial class WebForm1 : System.Web.UI.Page
    
        String path = HttpContext.Current.Request.PhysicalApplicationPath + "images\\";
        protected void Page_Load(object sender, EventArgs e)
        

        
        protected void btnUpload_Click(object sender, EventArgs e)
        
            Boolean FileOK = false;
            Boolean FileSaved = false;

            if (Upload.HasFile)
            
                Session["WorkingImage"] = Upload.FileName;
                String FileExtension = Path.GetExtension(Session["WorkingImage"].ToString()).ToLower();
                String[] allowedExtensions =  ".png", ".jpeg", ".jpg", ".gif" ;
                for (int i = 0; i < allowedExtensions.Length; i++)
                
                    if (FileExtension == allowedExtensions[i])
                    
                        FileOK = true;
                    
                
            

            if (FileOK)
            
                try
                
                    Upload.PostedFile.SaveAs(path + Session["WorkingImage"]);
                    FileSaved = true;
                
                catch (Exception ex)
                
                    lblError.Text = "File could not be uploaded." + ex.Message.ToString();
                    lblError.Visible = true;
                    FileSaved = false;
                
            
            else
            
                lblError.Text = "Cannot accept files of this type.";
                lblError.Visible = true;
            

            if (FileSaved)
            
                pnlUpload.Visible = false;
                pnlCrop.Visible = true;
                imgCrop.ImageUrl = "images/" + Session["WorkingImage"].ToString();
            
        

        protected void btnCrop_Click(object sender, EventArgs e)
        
            string ImageName = Session["WorkingImage"].ToString();
            int w = Convert.ToInt32(W.Value);
            int h = Convert.ToInt32(H.Value);
            int x = Convert.ToInt32(X.Value);
            int y = Convert.ToInt32(Y.Value);

            byte[] CropImage = Crop(path + ImageName, w, h, x, y);
            using (MemoryStream ms = new MemoryStream(CropImage, 0, CropImage.Length))
            
                ms.Write(CropImage, 0, CropImage.Length);
                using (SD.Image CroppedImage = SD.Image.FromStream(ms, true))
                
                    string SaveTo = path + "crop" + ImageName;
                    CroppedImage.Save(SaveTo, CroppedImage.RawFormat);
                    pnlCrop.Visible = false;
                    pnlCropped.Visible = true;
                    imgCropped.ImageUrl = "images/crop" + ImageName;
                
            
        

        static byte[] Crop(string Img, int Width, int Height, int X, int Y)
        
            try
            
                using (SD.Image OriginalImage = SD.Image.FromFile(Img))
                
                    using (SD.Bitmap bmp = new SD.Bitmap(Width, Height))
                    
                        bmp.SetResolution(OriginalImage.HorizontalResolution, OriginalImage.VerticalResolution);
                        using (SD.Graphics Graphic = SD.Graphics.FromImage(bmp))
                        
                            Graphic.SmoothingMode = SmoothingMode.AntiAlias;
                            Graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
                            Graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
                            Graphic.DrawImage(OriginalImage, new SD.Rectangle(0, 0, Width, Height), X, Y, Width, Height, SD.GraphicsUnit.Pixel);
                            MemoryStream ms = new MemoryStream();
                            bmp.Save(ms, OriginalImage.RawFormat);
                            return ms.GetBuffer();
                        
                    
                
            
            catch (Exception Ex)
            
                throw (Ex);
            
        
    

【讨论】:

以上是关于如何使用 C# 裁剪图像?的主要内容,如果未能解决你的问题,请参考以下文章

C#如何在不使用大量内存的情况下裁剪图像? [复制]

C# 使用 Emgu 按像素颜色裁剪图像

如何在c#中用多边形裁剪图像

如何使用 C# 中的代码进行颜色提取?

有没有很好的例子说明如何在 selenium webdriver C# 中截取屏幕截图,然后裁剪并保存图像?

没有 .net 库的图像裁剪 C#