图片撕纸效果处理
/// <summary> /// 撕纸效果 /// </summary> public class TearHelper { private static SolidBrush out_sb = new SolidBrush(Color.FromArgb(80, 110, 105, 109)); private static Pen out_pen = new Pen(Color.FromArgb(220, 128, 128, 128)); /// <summary> /// 撕纸 /// </summary> /// <param name="img">要处理的图片</param> /// <param name="tearOrientation">撕裂方位</param> /// <param name="shadowOrientation">撕裂阴影方位</param> /// <param name="avulsion">撕纸效果厚度(默认值8)</param> /// <param name="shadow">撕纸效果阴影厚度(默认值4)</param> /// <param name="interval">撕纸效果间距(默认值4)</param> /// <returns></returns> public static Bitmap TearIamge(Image img, TearOrientation tearOrientation = TearOrientation.Bottom|TearOrientation.Right, ShadowOrientation shadowOrientation = ShadowOrientation.Bottom|ShadowOrientation.Right, int avulsion = 8, int shadow = 4, int interval = 4) { Bitmap bmp = new Bitmap(img.Width, img.Height); Graphics bmp_g = Graphics.FromImage(bmp); Region r = bmp_g.Clip; int x = 0; #region 内图大小 Rectangle bmp_in_rect = new Rectangle(0, 0, img.Width, img.Height); if (tearOrientation.HasFlag(TearOrientation.Bottom)) { bmp_in_rect.Height -= avulsion; if (shadowOrientation.HasFlag(ShadowOrientation.Bottom)) { bmp_in_rect.Height -= shadow; } } if (tearOrientation.HasFlag(TearOrientation.Right)) { bmp_in_rect.Width -= avulsion; if (shadowOrientation.HasFlag(ShadowOrientation.Right)) { bmp_in_rect.Width -= shadow; } } if (tearOrientation.HasFlag(TearOrientation.Left)) { bmp_in_rect.Width -= avulsion; bmp_in_rect.X += avulsion; if (shadowOrientation.HasFlag(ShadowOrientation.Left)) { bmp_in_rect.Width -= shadow; bmp_in_rect.X += shadow; } } if (tearOrientation.HasFlag(TearOrientation.Top)) { bmp_in_rect.Height -= avulsion; bmp_in_rect.Y += avulsion; if (shadowOrientation.HasFlag(ShadowOrientation.Top)) { bmp_in_rect.Height -= shadow; bmp_in_rect.Y += shadow; } } #endregion #region 计算撕纸路径 #region int bottom_in_len = 0; Point[] bottom_in_point; int bottom_out_len = 0; Point[] bottom_out_point; if (tearOrientation.HasFlag(TearOrientation.Bottom)) { bottom_in_len = (int)Math.Round((double)bmp_in_rect.Width / interval, 0); bottom_in_point = new Point[bottom_in_len]; for (int i = 0; i < bottom_in_len; i++) { x++; bottom_in_point[i] = new Point(bmp_in_rect.X + i * interval, bmp_in_rect.Bottom + (int)(RandomNumber(x * interval) * avulsion)); } if (bottom_in_point[bottom_in_len - 1].X > bmp_in_rect.Right) { bottom_in_point[bottom_in_len - 1].X = bmp_in_rect.Right; } if (shadowOrientation.HasFlag(ShadowOrientation.Bottom)) { bottom_out_len = bottom_in_len; bottom_out_point = new Point[bottom_out_len]; for (int i = 0; i < bottom_out_len; i++) { bottom_out_point[i] = new Point(bottom_in_point[i].X, bottom_in_point[i].Y + shadow); } } else { bottom_out_len = 2; bottom_out_point = new Point[bottom_out_len]; bottom_out_point[0] = new Point(bmp_in_rect.Left, bmp_in_rect.Bottom); bottom_out_point[1] = new Point(bmp_in_rect.Right, bmp_in_rect.Bottom); } } else { bottom_in_len = 2; bottom_in_point = new Point[bottom_in_len]; bottom_in_point[0] = new Point(bmp_in_rect.Left, bmp_in_rect.Bottom); bottom_in_point[1] = new Point(bmp_in_rect.Right, bmp_in_rect.Bottom); bottom_out_len = 2; bottom_out_point = new Point[bottom_out_len]; bottom_out_point[0] = new Point(bmp_in_rect.Left, bmp_in_rect.Bottom); bottom_out_point[1] = new Point(bmp_in_rect.Right, bmp_in_rect.Bottom); } #endregion #region int right_in_len = 0; Point[] right_in_point; int right_out_len = 0; Point[] right_out_point; if (tearOrientation.HasFlag(TearOrientation.Right)) { right_in_len = (int)Math.Round((double)bmp_in_rect.Height / interval, 0); right_in_point = new Point[right_in_len]; for (int i = 0; i < right_in_len; i++) { x++; right_in_point[i] = new Point(bmp_in_rect.Right + (int)(RandomNumber(x * interval) * avulsion), bmp_in_rect.Bottom - i * interval); } if (right_in_point[right_in_len - 1].Y < bmp_in_rect.Top) { right_in_point[right_in_len - 1].Y = bmp_in_rect.Top; } if (shadowOrientation.HasFlag(ShadowOrientation.Right)) { right_out_len = right_in_len; right_out_point = new Point[right_out_len]; for (int i = 0; i < right_out_len; i++) { right_out_point[i] = new Point(right_in_point[i].X + shadow, right_in_point[i].Y); } } else { right_out_len = 2; right_out_point = new Point[right_out_len]; right_out_point[0] = new Point(bmp_in_rect.Right, bmp_in_rect.Bottom); right_out_point[1] = new Point(bmp_in_rect.Right, bmp_in_rect.Top); } } else { right_in_len = 2; right_in_point = new Point[right_in_len]; right_in_point[0] = new Point(bmp_in_rect.Right, bmp_in_rect.Bottom); right_in_point[1] = new Point(bmp_in_rect.Right, bmp_in_rect.Top); right_out_len = 2; right_out_point = new Point[right_out_len]; right_out_point[0] = new Point(bmp_in_rect.Right, bmp_in_rect.Bottom); right_out_point[1] = new Point(bmp_in_rect.Right, bmp_in_rect.Top); } #endregion #region int top_in_len = 0; Point[] top_in_point; int top_out_len = 0; Point[] top_out_point; if (tearOrientation.HasFlag(TearOrientation.Top)) { top_in_len = (int)Math.Round((double)bmp_in_rect.Width / interval, 0); top_in_point = new Point[top_in_len]; for (int i = 0; i < top_in_len; i++) { x++; top_in_point[i] = new Point(bmp_in_rect.Right - i * interval, bmp_in_rect.Y - (int)(RandomNumber(x * interval) * avulsion)); } if (top_in_point[top_in_len - 1].X < bmp_in_rect.Left) { top_in_point[top_in_len - 1].X = bmp_in_rect.Left; } if (shadowOrientation.HasFlag(ShadowOrientation.Top)) { top_out_len = top_in_len; top_out_point = new Point[top_out_len]; for (int i = 0; i < top_out_len; i++) { top_out_point[i] = new Point(top_in_point[i].X, top_in_point[i].Y - shadow); } } else { top_out_len = 2; top_out_point = new Point[top_out_len]; top_out_point[0] = new Point(bmp_in_rect.Right, bmp_in_rect.Top); top_out_point[1] = new Point(bmp_in_rect.Left, bmp_in_rect.Top); } } else { top_in_len = 2; top_in_point = new Point[top_in_len]; top_in_point[0] = new Point(bmp_in_rect.Right, bmp_in_rect.Top); top_in_point[1] = new Point(bmp_in_rect.Left, bmp_in_rect.Top); top_out_len = 2; top_out_point = new Point[top_out_len]; top_out_point[0] = new Point(bmp_in_rect.Right, bmp_in_rect.Top); top_out_point[1] = new Point(bmp_in_rect.Left, bmp_in_rect.Top); } #endregion #region int left_in_len = 0; Point[] left_in_point; int left_out_len = 0; Point[] left_out_point; if (tearOrientation.HasFlag(TearOrientation.Left)) { left_in_len = (int)Math.Round((double)bmp_in_rect.Height / interval, 0); left_in_point = new Point[left_in_len]; for (int i = 0; i < left_in_len; i++) { x++; left_in_point[i] = new Point(bmp_in_rect.X - (int)(RandomNumber(x * interval) * avulsion), bmp_in_rect.Y + i * interval); } if (left_in_point[left_in_len - 1].Y > bmp_in_rect.Bottom) { left_in_point[left_in_len - 1].Y = bmp_in_rect.Bottom; } if (shadowOrientation.HasFlag(ShadowOrientation.Left)) { left_out_len = left_in_len; left_out_point = new Point[left_out_len]; for (int i = 0; i < left_out_len; i++) { left_out_point[i] = new Point(left_in_point[i].X - shadow, left_in_point[i].Y); } } else { left_out_len = 2; left_out_point = new Point[left_out_len]; left_out_point[0] = new Point(bmp_in_rect.Left, bmp_in_rect.Top); left_out_point[1] = new Point(bmp_in_rect.Left, bmp_in_rect.Bottom); } } else { left_in_len = 2; left_in_point = new Point[left_in_len]; left_in_point[0] = new Point(bmp_in_rect.Left, bmp_in_rect.Top); left_in_point[1] = new Point(bmp_in_rect.Left, bmp_in_rect.Bottom); left_out_len = 2; left_out_point = new Point[left_out_len]; left_out_point[0] = new Point(bmp_in_rect.Left, bmp_in_rect.Top); left_out_point[1] = new Point(bmp_in_rect.Left, bmp_in_rect.Bottom); } #endregion #endregion #region 撕纸效果阴影 if (shadowOrientation != ShadowOrientation.None) { GraphicsPath out_gp = new GraphicsPath(); out_gp.AddLines(bottom_out_point); out_gp.AddLines(right_out_point); out_gp.AddLines(top_out_point); out_gp.AddLines(left_out_point); Region out_r = new System.Drawing.Region(out_gp); bmp_g.Clip = out_r; bmp_g.FillRegion(out_sb, out_r); out_r.Dispose(); out_gp.Dispose(); } #endregion #region 撕纸效果 GraphicsPath in_gp = new GraphicsPath(); in_gp.AddLines(bottom_in_point); in_gp.AddLines(right_in_point); in_gp.AddLines(top_in_point); in_gp.AddLines(left_in_point); Region in_r = new System.Drawing.Region(in_gp); bmp_g.Clip = in_r; int in_x = bmp_in_rect.X - (tearOrientation.HasFlag(TearOrientation.Left) ? (shadowOrientation.HasFlag(ShadowOrientation.Left) ? avulsion + shadow : avulsion) : 0); int in_y = bmp_in_rect.Y - (tearOrientation.HasFlag(TearOrientation.Top) ? (shadowOrientation.HasFlag(ShadowOrientation.Top) ? avulsion + shadow : avulsion) : 0); bmp_g.DrawImage(img, in_x, in_y); bmp_g.Clip = r; bmp_g.DrawPath(out_pen, in_gp); in_gp.Dispose(); #endregion in_r.Dispose(); bmp_g.Dispose(); return bmp; } /// <summary> ///返回0.0-1.0的随机数 /// </summary> /// <param name="x"></param> /// <returns></returns> private static double RandomNumber(int x) { x = (x << 13) ^ x; return Math.Abs((1.0 - ((x * (x * x * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0)); } /// <summary> /// 撕裂方位 /// </summary> [Flags] [Description("撕裂方位")] public enum TearOrientation { None = 0, /// <summary> /// 上边 /// </summary> Top = 2, /// <summary> /// 下边 /// </summary> Bottom = 4, /// <summary> /// 左边 /// </summary> Left = 8, /// <summary> /// 右边 /// </summary> Right = 16 } /// <summary> /// 撕裂阴影方位 /// </summary> [Flags] [Description("撕裂阴影方位")] public enum ShadowOrientation { None = 0, /// <summary> /// 上边 /// </summary> Top = 2, /// <summary> /// 下边 /// </summary> Bottom = 4, /// <summary> /// 左边 /// </summary> Left = 8, /// <summary> /// 右边 /// </summary> Right = 16 } }
源码下载:撕纸效果.zip
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现