如何使用c#裁剪图像?


当前回答

在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();

其他回答

使用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");
            }
        }
    }

这很简单:

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

如果你在使用AForge。NET:

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

这里有一个裁剪图像的简单例子

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

对于任何愿意使用“不安全”代码的人来说,您可以获得比标准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