不规则形状的剪切

转自http://blog.csdn.net/lexiaoyao20/article/details/6607225

原理:根据选择的区域(区域的选择需要用到GraphicsPath),根据区域可以得到这部分区域的边境矩形,从而不需要循环整张图片,只需要循环边境矩形,将矩形中的选择区域复制到另一种图片,这样大大提高了效率。根据选择的区域,可以得到复制出位于GraphicsPath中的这部分图片,同时设置这部分图片为透明,同时还要设置另一种图片不在GraphicsPath内的区域为透明,这样看起来的效果就是从图片中扣出来的一样,意思和PhotoShop的套索工具差不多。

说得有点晕了,还是看效果图吧:(左边是剪裁出来的图)

 下面说说关键的代码。

方法一:像素级的处理,循环整张图片,一个一个像素复制出来,效率比较低。

  1. /// <summary>   
  2.         /// 图片剪裁(像素级的处理,效率比较低)   
  3.         /// </summary>   
  4.         /// <param name="bitmap">原图</param>   
  5.         /// <param name="path">选择的路径</param>   
  6.         /// <param name="outputBitmap">输出的图片(即剪裁出来的图片)</param>   
  7.         /// <returns></returns>   
  8.         public static Bitmap BitmapCrop(Bitmap bitmap, GraphicsPath path, out Bitmap outputBitmap)  
  9.         {  
  10.             RectangleF rect = path.GetBounds();  
  11.             int left = (int)rect.Left;  
  12.             int top = (int)rect.Top;  
  13.             int width = (int)rect.Width;  
  14.             int height = (int)rect.Height;  
  15.             Bitmap image = (Bitmap)bitmap.Clone();  
  16.             outputBitmap = new Bitmap(width, height);  
  17.             for (int i = left; i < left + width; i++)  
  18.             {  
  19.                 for (int j = top; j < top + height; j++)  
  20.                 {  
  21.                     //判断坐标是否在路径中   
  22.                     if (path.IsVisible(i, j))  
  23.                     {  
  24.                         //复制原图区域的像素到输出图片   
  25.                         outputBitmap.SetPixel(i - left , j - top , image.GetPixel(i, j));  
  26.                         //设置原图这部分区域为透明   
  27.                         image.SetPixel(i, j, Color.FromArgb(0, image.GetPixel(i, j)));  
  28.                     }  
  29.                     else  
  30.                     {  
  31.                         outputBitmap.SetPixel(i - left, j - top, Color.FromArgb(0, 255, 255, 255));                             
  32.                     }  
  33.                 }  
  34.             }  
  35.             bitmap.Dispose();  
  36.             return image;  
  37.         }  
/// <summary>
        /// 图片剪裁(像素级的处理,效率比较低)
        /// </summary>
        /// <param name="bitmap">原图</param>
        /// <param name="path">选择的路径</param>
        /// <param name="outputBitmap">输出的图片(即剪裁出来的图片)</param>
        /// <returns></returns>
        public static Bitmap BitmapCrop(Bitmap bitmap, GraphicsPath path, out Bitmap outputBitmap)
        {
            RectangleF rect = path.GetBounds();
            int left = (int)rect.Left;
            int top = (int)rect.Top;
            int width = (int)rect.Width;
            int height = (int)rect.Height;
            Bitmap image = (Bitmap)bitmap.Clone();
            outputBitmap = new Bitmap(width, height);
            for (int i = left; i < left + width; i++)
            {
                for (int j = top; j < top + height; j++)
                {
                    //判断坐标是否在路径中
                    if (path.IsVisible(i, j))
                    {
                        //复制原图区域的像素到输出图片
                        outputBitmap.SetPixel(i - left , j - top , image.GetPixel(i, j));
                        //设置原图这部分区域为透明
                        image.SetPixel(i, j, Color.FromArgb(0, image.GetPixel(i, j)));
                    }
                    else
                    {
                        outputBitmap.SetPixel(i - left, j - top, Color.FromArgb(0, 255, 255, 255));                           
                    }
                }
            }
            bitmap.Dispose();
            return image;
        }


方法二:将图片锁定在内存中,在内存处理,效率得到提升。

  1. /// <summary>   
  2.       /// 剪裁选定区域的图片   
  3.       /// </summary>   
  4.       /// <param name="bitmap">原图</param>   
  5.       /// <param name="path">用户选定的区域</param>   
  6.       /// <param name="outputBitmap">剪裁出来的图(输出图)</param>   
  7.       /// <returns></returns>   
  8.       public static Bitmap BitmapCrop(Bitmap bitmap, GraphicsPath path, out Bitmap outputBitmap)  
  9.       {  
  10.           Rectangle rect = Rectangle.Round(path.GetBounds());  
  11.           outputBitmap = new Bitmap(rect.Width, rect.Height);  
  12.           if (bitmap == nullreturn null;  
  13.   
  14.           Bitmap bmp = (Bitmap)bitmap.Clone();  
  15.           bitmap.Dispose();  
  16.           BitmapData data = bmp.LockBits(rect,  
  17.               ImageLockMode.ReadWrite, bmp.PixelFormat);  
  18.           BitmapData outData = outputBitmap.LockBits(new Rectangle(0, 0, rect.Width, rect.Height),  
  19.               ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);  
  20.           unsafe  
  21.           {  
  22.               byte* q = (byte*)outData.Scan0;  
  23.               int offset = outData.Stride - rect.Width * 4;  
  24.               int PixelSize = 4;  
  25.               for (int y = rect.Top; y < rect.Top + rect.Height; y++)  
  26.               {  
  27.                   //每一行内存中的位置   
  28.                   byte* row = (byte*)data.Scan0 + ((y - rect.Top) * data.Stride);  
  29.                   for (int x = rect.Left; x < rect.Left + rect.Width; x++)  
  30.                   {  
  31.                       //判断坐标点是否在路径中   
  32.                       //在路径中,则复制原图这部分给输出图,同时设置原图这部分透明   
  33.                       //坐标点和内存中值的对应   
  34.                       if (path.IsVisible(x, y))    
  35.                       {  
  36.                           q[0] = row[(x - rect.Left) * PixelSize];  
  37.                           q[1] = row[(x - rect.Left) * PixelSize + 1];  
  38.                           q[2] = row[(x - rect.Left) * PixelSize + 2];  
  39.                           q[3] = row[(x - rect.Left) * PixelSize + 3];  
  40.   
  41.                           row[(x - rect.Left) * PixelSize + 3] = 0;  
  42.                       }  
  43.                       else //不在路径中,则设置输出图这部分为透明   
  44.                       {  
  45.                           q[3] = 0;  
  46.                       }  
  47.                       q += 4;  
  48.                   }  
  49.                   q += offset;  
  50.               }  
  51.           }  
  52.           bmp.UnlockBits(data);  
  53.           outputBitmap.UnlockBits(outData);  
  54.   
  55.           return bmp;  
  56.       }  
  /// <summary>
        /// 剪裁选定区域的图片
        /// </summary>
        /// <param name="bitmap">原图</param>
        /// <param name="path">用户选定的区域</param>
        /// <param name="outputBitmap">剪裁出来的图(输出图)</param>
        /// <returns></returns>
        public static Bitmap BitmapCrop(Bitmap bitmap, GraphicsPath path, out Bitmap outputBitmap)
        {
            Rectangle rect = Rectangle.Round(path.GetBounds());
            outputBitmap = new Bitmap(rect.Width, rect.Height);
            if (bitmap == null) return null;

            Bitmap bmp = (Bitmap)bitmap.Clone();
            bitmap.Dispose();
            BitmapData data = bmp.LockBits(rect,
                ImageLockMode.ReadWrite, bmp.PixelFormat);
            BitmapData outData = outputBitmap.LockBits(new Rectangle(0, 0, rect.Width, rect.Height),
                ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            unsafe
            {
                byte* q = (byte*)outData.Scan0;
                int offset = outData.Stride - rect.Width * 4;
                int PixelSize = 4;
                for (int y = rect.Top; y < rect.Top + rect.Height; y++)
                {
                    //每一行内存中的位置
                    byte* row = (byte*)data.Scan0 + ((y - rect.Top) * data.Stride);
                    for (int x = rect.Left; x < rect.Left + rect.Width; x++)
                    {
                        //判断坐标点是否在路径中
                        //在路径中,则复制原图这部分给输出图,同时设置原图这部分透明
                        //坐标点和内存中值的对应
                        if (path.IsVisible(x, y))  
                        {
                            q[0] = row[(x - rect.Left) * PixelSize];
                            q[1] = row[(x - rect.Left) * PixelSize + 1];
                            q[2] = row[(x - rect.Left) * PixelSize + 2];
                            q[3] = row[(x - rect.Left) * PixelSize + 3];

                            row[(x - rect.Left) * PixelSize + 3] = 0;
                        }
                        else //不在路径中,则设置输出图这部分为透明
                        {
                            q[3] = 0;
                        }
                        q += 4;
                    }
                    q += offset;
                }
            }
            bmp.UnlockBits(data);
            outputBitmap.UnlockBits(outData);

            return bmp;
        }


 注意:因为有不安全代码,所以要设置项目的属性 ->生成,勾选允许不安全代码。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值