不规则形状的剪切
来源:互联网 发布:淘宝卖女装好吗 编辑:程序博客网 时间:2024/04/28 05:30
转自http://blog.csdn.net/lexiaoyao20/article/details/6607225
原理:根据选择的区域(区域的选择需要用到GraphicsPath),根据区域可以得到这部分区域的边境矩形,从而不需要循环整张图片,只需要循环边境矩形,将矩形中的选择区域复制到另一种图片,这样大大提高了效率。根据选择的区域,可以得到复制出位于GraphicsPath中的这部分图片,同时设置这部分图片为透明,同时还要设置另一种图片不在GraphicsPath内的区域为透明,这样看起来的效果就是从图片中扣出来的一样,意思和PhotoShop的套索工具差不多。
说得有点晕了,还是看效果图吧:(左边是剪裁出来的图)
下面说说关键的代码。
方法一:像素级的处理,循环整张图片,一个一个像素复制出来,效率比较低。
- /// <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;
- }
/// <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; }
方法二:将图片锁定在内存中,在内存处理,效率得到提升。
- /// <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;
- }
/// <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; }
注意:因为有不安全代码,所以要设置项目的属性 ->生成,勾选允许不安全代码。
- 不规则形状的剪切
- 生成不规则的形状
- 创建不规则形状的Control
- 不规则窗体形状的ToolTip
- 不规则窗体形状的ToolTip .
- 不规则形状的碰撞检测
- VC---创建一个不规则形状的窗口
- 如何创建一个不规则形状的窗口
- box2d中创建不规则的形状
- 创建“不规则形状”的Air透明窗体
- 获取图片中不规则形状的一部分
- 不规则窗体形状的ToolTip (二)
- iphone开发生成不规则的形状
- 任意不规则形状的图片剪裁
- setMask()与实现不规则形状的窗口
- UIImage任意形状的不规则裁剪
- WPF创建不规则形状的按钮
- iOS图片不规则剪切
- 利用三个源码包libnet、libnids、libpcap轻松搭建Linux网络入侵检测系统
- SAP 中生产口令的含义
- linux下 /根目录下面的子目录介绍
- java的UDP进行通信的一个小案例
- 从url显示图片
- 不规则形状的剪切
- CLisp 5:用Socket包建立TCP/IP连接
- WPF图标拾取器
- 用python的BeautifulSoup分析html
- 歌到这个份上,足矣
- POJ 1696 Space Ant
- sql反模式分析2
- 黑马程序员-容易忽视的问题
- python-memcached 安装