Làm cách nào để cắt ảnh bằng C #?


239

Làm cách nào tôi có thể viết một ứng dụng sẽ cắt ảnh trong C #?

Câu trả lời:


228

Bạn có thể sử dụng Graphics.DrawImageđể vẽ một hình ảnh được cắt lên đối tượng đồ họa từ bitmap.

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);
}

3
Chỉ cần một lưu ý, chữ ký của DrawImage () không hợp lệ. Nó thiếu tham số GraphicsUnit .
Nathan Taylor

2
Ngoài ra đối số thứ hai là trực tràng đích, không phải là trực tràng crop.
axk

8
Là phương pháp DrawImageUnscaledAndClippedhiệu quả hơn DrawImagecho mục đích cắt xén?
Ivan Kochurkin

270

Kiểm tra liên kết này: 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);
}

56
Đồng ý, nhưng lưu ý rằng nếu cropArea vượt qua ranh giới img, nó sẽ đưa ra ngoại lệ "Hết bộ nhớ".
ChrisJJ

1
@KvanTTT, cả hai đều khá chậm nếu bạn muốn cắt một hình ảnh lớn thành những hình nhỏ hơn.
JBeurer

1
@ChrisJJ bạn có thể giải thích thêm? hoặc đưa ra một cách giải quyết cho vấn đề đó?
raym0nd

1
@ raym0nd Tôi đoán cách giải quyết là đảm bảo kích thước hình chữ nhật của bạn không lớn hơn hình ảnh
stuartdotnet

4
Trang web của họ là xuống. Bất cứ ai cũng có được mã từ trang web?
sangam

55

Đơn giản hơn câu trả lời được chấp nhận là đây:

public static Bitmap cropAtRect(this Bitmap b, Rectangle r)
{
    using (Bitmap nb = new Bitmap(r.Width, r.Height))
    using (Graphics g = Graphics.FromImage(nb))
    {
        g.DrawImage(b, -r.X, -r.Y);
        return nb;
    }
}

và nó tránh được rủi ro ngoại lệ "hết bộ nhớ " cho câu trả lời đơn giản nhất.

Lưu ý rằng BitmapGraphicsIDisposabledo đó usingmệnh đề.

EDIT : Tôi thấy điều này tốt với các PNG được lưu bởi Bitmap.Savehoặc Paint.exe, nhưng không thành công với các PNG được lưu bởi vd, ví dụ như Paint Shop Pro 6 - nội dung bị thay thế. Bổ sung GraphicsUnit.Pixelcho một kết quả sai khác nhau. Có lẽ chỉ những PNG thất bại này là bị lỗi.


5
Trả lời tốt nhất ở đây, điều này nên được trao câu trả lời. Tôi đã trải nghiệm "hết bộ nhớ" cũng như các giải pháp khác. Điều này làm việc lần đầu tiên.
c0d3p03t

Tôi không hiểu tại sao việc thêm GraphicsUnit.Pixel lại cho kết quả sai, nhưng chắc chắn là có.
DOKKA

Hình ảnh của tôi được cắt với kích thước chính xác nhưng ở X / Y không chính xác cho đến khi tôi gọi SetResolution trên hình ảnh đích như được đề xuất trong câu trả lời của @IntellyDev.
Brent Keller

6
Câu trả lời này làm rò rỉ đối tượng Grphics.
TaW

2
BitmapGraphicsIDisposable- thêm một usingmệnh đề
dave thieben 17/03/19

7

sử dụng bmp.SetResolution(image.HorizontalResolution, image .VerticalResolution);

điều này có thể cần phải làm ngay cả khi bạn thực hiện câu trả lời tốt nhất ở đây đặc biệt là nếu hình ảnh của bạn thực sự tuyệt vời và độ phân giải không chính xác là 96.0

Ví dụ kiểm tra của tôi:

    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

Nó khá dễ:

  • Tạo một Bitmapđối tượng mới với kích thước cắt.
  • Sử dụng Graphics.FromImageđể tạo một Graphicsđối tượng cho bitmap mới.
  • Sử dụng DrawImagephương pháp để vẽ hình ảnh lên bitmap với tọa độ X và Y âm.

5

Đây là một ví dụ đơn giản về cắt xén hình ảnh

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;
    }            
}

5
Ông là người duy nhất đề cập đến độ phân giải, tất cả các phương pháp trên sẽ thất bại nếu hình ảnh nguồn có độ phân giải không chuẩn.
net_prog

1
sử dụng bmp.SetResolution (hình ảnh .HTHERResolution, hình ảnh .V verticalResolution); để khắc phục vấn đề giải quyết.
Morbia

2
Ngoại trừ điều này sẽ rò rỉ các đối tượng hình ảnh, bmp và gfx. Tại sao không bọc những người trong việc sử dụng báo cáo?
Darius Kucinskas

3

Nếu bạn đang sử dụng AForge.NET :

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

2

Tôi đang tìm kiếm một chức năng dễ dàng và NHANH CHÓNG mà không cần thêm công việc để thực hiện công việc. Tôi đã thử giải pháp Nicks , nhưng tôi cần 29,4 giây để "trích xuất" 1195 hình ảnh của một tập tin bản đồ. Vì vậy, sau đó tôi đã quản lý theo cách này và cần 2,43 giây để làm công việc tương tự. Có lẽ điều này sẽ hữu ích.

// 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
     }
}

1

Cắt một hình ảnh rất dễ dàng trong C #. Tuy nhiên, thực hiện các công cụ như thế nào bạn sẽ quản lý việc cắt xén hình ảnh của bạn sẽ khó hơn một chút.

Mẫu dưới đây là cách cắt ảnh trong 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();

1

Có một trình bao bọc C # cho mã nguồn mở, được lưu trữ trên Codeplex có tên là Cắt ảnh Web

Đăng ký kiểm soát

<%@ Register Assembly="CS.Web.UI.CropImage" Namespace="CS.Web.UI" TagPrefix="cs" %>

Thay đổi kích thước

<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" />

Cắt xén mã phía sau - Gọi phương thức Cắt khi nút bấm chẳng hạn;

wci1.Crop(Server.MapPath("images/sample1.jpg"));


0

Giả sử bạn có nghĩa là bạn muốn lấy một tệp hình ảnh (JPEG, BMP, TIFF, v.v.) và cắt nó ra dưới dạng tệp hình ảnh nhỏ hơn, tôi khuyên bạn nên sử dụng công cụ của bên thứ ba có API .NET. Dưới đây là một vài trong số những cái phổ biến mà tôi thích:

LeadTools
Accusoft Pegasus vì tuyết Imaging SDK


0

Chỉ mẫu này hoạt động mà không có vấn đề:

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)
    {


    }

}

0

Đây là một cách khác. Trong trường hợp của tôi, tôi có:

  • 2 điều khiển cập nhật số (được gọi là LeftMargin và TopMargin)
  • 1 hộp hình ảnh (imageBox1)
  • 1 nút mà tôi gọi là tạo
  • 1 hình ảnh trên C: \ fantenes \ myImage.gif

Bên trong nút tôi có mã này:

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;

Tôi đã thử nó trong Visual studio 2012 bằng C #. Tôi tìm thấy giải pháp này từ trang này


0

đây là bản demo đang hoạt động trên 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>

Logic mã C # để tải lên và cắt.

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);
            }
        }
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.