裁剪注意传入的负坐标,注释是我个人的理解 。凹槽的形状通过CalcHoleShape实现的,原理是一行行扫描图像,每行连续不透明区域(包含半透明)形成一个或多个n*1的矩形 。最后将所有小矩形组合形成一个组合形状ComplexPolygon
Func<Image<Rgba32>, ComplexPolygon> CalcHoleShape = (holeTemplateImage) => {int temp = 0;var pathList = new List<IPath>();holeTemplateImage.ProcessPixelRows(accessor =>{for (int y = 0; y < holeTemplateImage.Height; y++){var rowSpan = accessor.GetRowSpan(y);for (int x = 0; x < rowSpan.Length; x++){ref Rgba32 pixel = ref rowSpan[x];if (pixel.A != 0){if (temp == 0){temp = x;}}else{if (temp != 0){pathList.Add(new RectangularPolygon(temp, y, x - temp, 1));temp = 0;}}}}});return new ComplexPolygon(new PathCollection(pathList));};运行,形成out_holeMatting.jpg
dotnet run

文章插图
b. 将slider.png"叠加"到抠图holeMattingImage,代码比较简单
// 叠加拖块模板holeMattingImage.Mutate(x => x.DrawImage(sliderTemplateImage, new Point(0, 0), 1));holeMattingImage.SaveAsJpegAsync("out_holeMatting2.jpg");运行,形成out_holeMatting2.jpgdotnet run 
文章插图
c. 将out_holeMatting2叠加到"叠加"到一个高为344,宽为110的透明区域
using var sliderBarImage = new Image<Rgba32>(sliderTemplateImage.Width, backgroundImage2.Height);// 绘制拖块条sliderBarImage.Mutate(x => x.DrawImage(holeMattingImage, new Point(0, randomY), 1));sliderBarImage.SaveAsJpegAsync("out_slider.jpg");运行,形成out_slider.jpgdotnet run 
文章插图
全部代码
using SixLabors.ImageSharp;using SixLabors.ImageSharp.Drawing;using SixLabors.ImageSharp.PixelFormats;using SixLabors.ImageSharp.Processing;using SixLabors.ImageSharp.Drawing.Processing;// 生成随机坐标int randomX = 100, randomY = 120;// 加载图片using var backgroundImage = Image.Load<Rgba32>("images/bg.jpg");using var holeTemplateImage = Image.Load<Rgba32>("images/hole.png");using var sliderTemplateImage = Image.Load<Rgba32>("images/slider.png");// "叠加"holeTemplateImage到backgroundImagebackgroundImage.Mutate(x => x.DrawImage(holeTemplateImage, new Point(randomX, randomY), 1));backgroundImage.SaveAsJpegAsync("out_bg.jpg");Func<Image<Rgba32>, ComplexPolygon> CalcHoleShape = (holeTemplateImage) => {int temp = 0;var pathList = new List<IPath>();holeTemplateImage.ProcessPixelRows(accessor =>{for (int y = 0; y < holeTemplateImage.Height; y++){var rowSpan = accessor.GetRowSpan(y);for (int x = 0; x < rowSpan.Length; x++){ref Rgba32 pixel = ref rowSpan[x];if (pixel.A != 0){if (temp == 0){temp = x;}}else{if (temp != 0){pathList.Add(new RectangularPolygon(temp, y, x - temp, 1));temp = 0;}}}}});return new ComplexPolygon(new PathCollection(pathList));};// backgroundImage已做修改,这里重新加载背景using var backgroundImage2 = Image.Load<Rgba32>("images/bg.jpg");using var holeMattingImage = new Image<Rgba32>(sliderTemplateImage.Width, sliderTemplateImage.Height); // 110 * 110// 根据透明度计算凹槽图轮廓形状(形状由不透明区域形成)var holeShape = CalcHoleShape(holeTemplateImage);// 生成凹槽抠图holeMattingImage.Mutate(x =>{// 可以这样理解://将holeShape想象成一幅110X110的图片//p => p.DrawImage(backgroundImage2, new Point(-randomX, -randomY), 1)则表示//从holeShape的-randomX, -randomY开始绘制backgroundImage2(相当于backgroundImage2左移randomX,上移randomY)//然后将holeShape绘制结果叠加到holeMattingImage上x.Clip(holeShape, p => p.DrawImage(backgroundImage2, new Point(-randomX, -randomY), 1));});holeMattingImage.SaveAsJpegAsync("out_holeMatting.jpg");// 叠加拖块模板holeMattingImage.Mutate(x => x.DrawImage(sliderTemplateImage, new Point(0, 0), 1));holeMattingImage.SaveAsJpegAsync("out_holeMatting2.jpg");using var sliderBarImage = new Image<Rgba32>(sliderTemplateImage.Width, backgroundImage2.Height);// 绘制拖块条sliderBarImage.Mutate(x => x.DrawImage(holeMattingImage, new Point(0, randomY), 1));sliderBarImage.SaveAsJpegAsync("out_slider.jpg");最后完整的滑动验证,可以参考LazySlideCaptcha 。写的比较水,欢迎Star 。- 本文作者: 破剑冰
- 本文链接: https://www.cnblogs.com/readafterme/p/16110788.html
【一步一步生成滑动验证码图片】
推荐阅读
- 女生的这些表现,就是想要和你有进一步的交往,别错过
- 网页版 Nginx 配置文件生成器!NginxWebUI 1.0.0 发布
- 交换机生成树安全特性解析
- 开网店第一步怎么操作 网上开店的基本流程要点
- 怎么样开网店?网上开店流程-新手必备 开网店第一步怎么操作
- 困惑你很久的滑动验证码,破解方案来啦
- 淘宝开店第一步做什么 淘宝开店的具体操作流程
- python生成exe
- 做辣椒油时不要直接泼油,多加这一步,香气扑鼻,色泽红亮
- 做焖面不要直接下锅焖,多加这一步,面条劲道又入味,一碗不够吃
