html5 canvas+js实现ps钢笔抠图

1. 项目要求需要用js实现photoshop中钢笔抠图功能,就用了近三四天的时间去解决它,最终还是基本上把他实现了。

做的过程中走了不少弯路,最终一同事找到了canvans以比较核心的属性globalCompositeOperation = "destination-out",

属性可以实现通过由多个点构成的闭合区间设置成透明色穿透画布背景色或是背景图片,这样省了许多事。

2.实现效果:

鼠标点完之后会将所有的点连成闭合区间,并可自由拖拉任一点,当形成闭合区间后,可在任意两点之间添加新点进行拖拉。

3.实现思路:

设置两层p,底层设置图片,顶层设置canvas画布(如果将图片渲染到画布上,抠图时会闪烁,所以至于底层),在画布上监视

鼠标事件反复渲染点及之间连线,形成闭合区间后将整体画布渲染小块背景图片,并将闭合区间渲染透明色。并把点的相对画布

坐标记录或更新到数组中去。截完图后,将点的坐标集合传回后台,由后台代码实现根据坐标点及图片宽度高度实现截图,并设

至背景色为透明色(canvas也可以实现截图,但需要处理像素点实现背景透明,暂时还没实现,计划用C#后台代码实现)。

4.js(写的不规范比较乱,大家就当参考吧)

复制代码

1

2         $(function () {

3             var a = new tailorImg();

4             a.iniData();

5         });

6         //

7         var tailorImg=function()

8         {

9             this.iniData = function () {

10                 //画布

11                 this.can.id = "canvas";

12                 this.can.w = 400;

13                 this.can.h = 400;

14                 this.can.roundr = 7;

15                 this.can.roundrr = 3;

16                 this.can.curPointIndex = 0;

17                 this.can.imgBack.src = "gzf.png";

18                 this.can.canvas = document.getElementById(this.can.id).getContext("2d");

19                 //图片

20                 this.img.w = 400;

21                 this.img.h = 400;

22                 this.img.image.src = "flower.jpg";

23                 //加载事件:

24                 //初始化事件:

25                 var a = this;

26                 var p = a.can.pointList;

27                 $("#" + a.can.id).mousemove(function (e) {

28                     if (a.can.paint) {//是不是按下了鼠标

29                         if (p.length > 0) {

30                             a.equalStartPoint(p[p.length - 1].pointx, p[p.length - 1].pointy);

31                         }

32                         a.roundIn(e.offsetX, e.offsetY);

33                     }

34                     //判断是否在直线上

35                     //光标移动到线的附近如果是闭合的需要重新划线,并画上新添加的点

36                     a.AddNewNode(e.offsetX, e.offsetY);

37                 });

38                 $("#" + a.can.id).mousedown(function (e) {

39                     a.can.paint = true;

40                     //点击判断是否需要在线上插入新的节点:

41                     if (a.can.tempPointList.length > 0) {

42                         a.can.pointList.splice(a.can.tempPointList[1].pointx, 0, new a.point(a.can.tempPointList[0].pointx, a.can.tempPointList[0].pointy));

43                         //清空临时数组

44                         a.can.tempPointList.length = 0;

45                     }

46                 });

47                 $("#" + a.can.id).mouseup(function (e) {

48                     //拖动结束

49                     a.can.paint = false;

50                     //拖动结束;

51                     if (a.can.juPull) {

52                         a.can.juPull = false;

53                         a.can.curPointIndex = 0;

54                         //验证抠图是否闭合:闭合,让结束点=开始点;添加标记

55                         a.equalStartPoint(p[p.length - 1].pointx, p[p.length - 1].pointy);

56                         //判断是否闭合:

57                         if (a.can.IsClose) {

58

59                         }

60                     }

61                     else {

62                         //如果闭合:禁止添加新的点;

63                         if (!a.can.IsClose) {//没有闭合

64                             p.push(new a.point(e.offsetX, e.offsetY));

65                             //验证抠图是否闭合:闭合,让结束点=开始点;添加标记

66                             a.equalStartPoint(p[p.length - 1].pointx, p[p.length - 1].pointy);

67                             //判断是否闭合:

68                             //重新画;

69                             if (p.length > 1) {

70                                 a.drawLine(p[p.length - 2].pointx, p[p.length - 2].pointy, p[p.length - 1].pointx, p[p.length - 1].pointy);

71                                 a.drawArc(p[p.length - 1].pointx, p[p.length - 1].pointy);

72                             } else {

73                                 a.drawArc(p[p.length - 1].pointx, p[p.length - 1].pointy);

74                             }

75                         }

76                         else {

77                             //闭合

78                         }

79                     }

80                     //验证是否填充背景:

81                     if (a.can.IsClose) {

82                         a.fillBackColor();

83                         a.drawAllLine();

84                     }

85                 });

86                 $("#" + a.can.id).mouseleave(function (e) {

87                     a.can.paint = false;

88                 });

89                 //鼠标点击事件:

90                 $("#" + a.can.id).click(function (e) {

91                     //空

92                 });

93             }

94             this.point = function (x, y) {

95                 this.pointx = x;

96                 this.pointy = y;

97             };

98             //图片

99             this.img = {

100                 image:new Image(),

101                 id: "",

102                 w:0,

103                 h:0

104             };

105             //画布;

106             this.can = {

107                 canvas:new Object(),

108                 id: "",

109                 w: 0,

110                 h: 0,

111                 //坐标点集合

112                 pointList: new Array(),

113                 //临时存储坐标点

114                 tempPointList: new Array(),

115                 //圆点的触发半径:

116                 roundr: 7,

117                 //圆点的显示半径:

118                 roundrr: 7,

119                 //当前拖动点的索引值;

120                 curPointIndex : 0,

121                 //判断是否点击拖动

122                 paint : false,

123                 //判断是否点圆点拖动,并瞬间离开,是否拖动点;

124                 juPull : false,

125                 //判断是否闭合

126                 IsClose: false,

127                 imgBack: new Image()

128

129             };

130             //函数:

131             //更新画线

132             this.drawAllLine=function () {

133                 for (var i = 0; i < this.can.pointList.length - 1; i++) {

134                     //画线

135                     var p = this.can.pointList;

136                     this.drawLine(p[i].pointx, p[i].pointy, p[i + 1].pointx, p[i + 1].pointy);

137                     //画圈

138                     this.drawArc(p[i].pointx, p[i].pointy);

139                     if (i == this.can.pointList.length - 2) {

140                         this.drawArc(p[i+1].pointx, p[i+1].pointy);

141                     }

142                 }

143             }

144             //画线

145             this.drawLine = function (startX, startY, endX, endY) {

146                 //var grd = this.can.canvas.createLinearGradient(0, 0,2,0); //坐标,长宽

147                 //grd.addColorStop(0, "black"); //起点颜色

148                 //grd.addColorStop(1, "white");

149                 //this.can.canvas.strokeStyle = grd;

150                 this.can.canvas.strokeStyle = "blue"

151                 this.can.canvas.lineWidth =1;

152                 this.can.canvas.moveTo(startX, startY);

153                 this.can.canvas.lineTo(endX, endY);

154                 this.can.canvas.stroke();

155             }

156             //画圈:

157             this.drawArc=function(x, y) {

158                this.can.canvas.fillStyle = "blue";

159                 this.can.canvas.beginPath();

160                 this.can.canvas.arc(x, y,this.can.roundrr, 360, Math.PI * 2, true);

161                 this.can.canvas.closePath();

162                 this.can.canvas.fill();

163             }

164             //光标移到线上画大圈:

165             this.drawArcBig = function (x, y) {

166                 this.can.canvas.fillStyle = "blue";

167                 this.can.canvas.beginPath();

168                 this.can.canvas.arc(x, y, this.can.roundr+2, 360, Math.PI * 2, true);

169                 this.can.canvas.closePath();

170                 this.can.canvas.fill();

171             }

172             //渲染图片往画布上

173             this.showImg=function() {

174                 this.img.image.onload = function () {

175                     this.can.canvas.drawImage(this.img.image, 0, 0, this.img.w,this.img.h);

176                 };

177             }

178             //填充背景色

179             this.fillBackColor = function () {

180                 for (var i = 0; i

181                     for (var j = 0; j <= this.img.h; j += 96) {

182                         this.can.canvas.drawImage(this.can.imgBack, i, j, 96, 96);

183                     }

184                 }

185                 this.can.canvas.globalCompositeOperation = "destination-out";

186                 this.can.canvas.beginPath();

187                 for (var i = 0; i

188                     this.can.canvas.lineTo(this.can.pointList[i].pointx,this.can.pointList[i].pointy);

189                 }

190                 this.can.canvas.closePath();

191                 this.can.canvas.fill();

192                 this.can.canvas.globalCompositeOperation = "destination-over";

193                 this.drawAllLine();

194             }

195             //去掉pointlist最后一个坐标点:

196             this.clearLastPoint=function () {

197                 this.can.pointList.pop();

198                 //重画:

199                 this.clearCan();

200                 this.drawAllLine();

201             }

202             //判断结束点是否与起始点重合;

203             this.equalStartPoint = function (x,y) {

204                 var p = this.can.pointList;

205                 if (p.length > 1 && Math.abs((x - p[0].pointx) * (x - p[0].pointx)) + Math.abs((y - p[0].pointy) * (y - p[0].pointy)) <= this.can.roundr * this.can.roundr) {

206                     //如果闭合

207                     this.can.IsClose = true;

208                     p[p.length - 1].pointx = p[0].pointx;

209                     p[p.length - 1].pointy = p[0].pointy;

210                 }

211                 else {

212                     this.can.IsClose = false;

213                 }

214             }

215             //清空画布

216             this.clearCan=function (){

217                 this.can.canvas.clearRect(0, 0, this.can.w, this.can.h);

218             }

219             //剪切区域

220             this.CreateClipArea=function () {

221                 this.showImg();

222                 this.can.canvas.beginPath();

223                 for (var i = 0; i

224                     this.can.canvas.lineTo(this.can.pointList[i].pointx,this.can.pointList[i].pointy);

225                 }

226                 this.can.canvas.closePath();

227                 this.can.canvas.clip();

228             }

229             //

230             this.CreateClipImg=function()

231             {

232

233             }

234             //判断鼠标点是不是在圆的内部:

235             this.roundIn = function (x, y) {

236                 //刚开始拖动

237                 var p = this.can.pointList;

238                 if (!this.can.juPull) {

239                     for (var i = 0; i < p.length; i++) {

240

241                         if (Math.abs((x - p[i].pointx) * (x - p[i].pointx)) + Math.abs((y - p[i].pointy) * (y - p[i].pointy)) <= this.can.roundr * this.can.roundr) {

242                             //说明点击圆点拖动了;

243                             this.can.juPull = true;//拖动

244                             //

245                             this.can.curPointIndex = i;

246                             p[i].pointx = x;

247                             p[i].pointy = y;

248                             //重画:

249                             this.clearCan();

250                             //showImg();

251                             if (this.can.IsClose) {

252                                 this.fillBackColor();

253                             }

254                             this.drawAllLine();

255                             return;

256                         }

257                     }

258                 }

259                 else {//拖动中

260                     p[this.can.curPointIndex].pointx = x;

261                     p[this.can.curPointIndex].pointy = y;

262                     //重画:

263                     this.clearCan();

264                     if (this.can.IsClose) {

265                         this.fillBackColor();

266                     }

267                     this.drawAllLine();

268                 }

269             };

270

271             //光标移到线上,临时数组添加新的节点:

272            this.AddNewNode=function(newx, newy) {

273                //如果闭合

274                var ii=0;

275                 if (this.can.IsClose) {

276                     //判断光标点是否在线上:

277                     var p = this.can.pointList;

278                     for (var i = 0; i < p.length - 1; i++) {

279                         //计算a点和b点的斜率

280                         var k = (p[i + 1].pointy - p[i].pointy) / (p[i + 1].pointx - p[i].pointx);

281                         var b = p[i].pointy - k * p[i].pointx;

282                         //if (parseInt((p[i + 1].pointy - p[i].pointy) / (p[i + 1].pointx - p[i].pointx)) ==parseInt((p[i + 1].pointy - newy) / (p[i + 1].pointx - newx)) && newx*2-p[i+1].pointx-p[i].pointx<0 && newy*2-p[i+1].pointy-p[i].pointy<0) {

283                         //    //如果在直线上

284                         //    alert("在直线上");

285                         //}

286                         $("#txtone").val(parseInt(k * newx + b));

287                         $("#txttwo").val(parseInt(newy));

288                         if (parseInt(k * newx + b) == parseInt(newy) && (newx - p[i + 1].pointx) * (newx - p[i].pointx) <= 2 && (newy - p[i + 1].pointy) * (newy - p[i].pointy) <= 2) {

289                             //

290                             //parseInt(k * newx + b) == parseInt(newy)

291                             //添加临时点:

292                             this.can.tempPointList[0] = new this.point(newx, newy);//新的坐标点

293                             this.can.tempPointList[1] = new this.point(i+1, i+1);//需要往pointlist中插入新点的索引;

294                             i++;

295                             //alert();

296                             //光标移动到线的附近如果是闭合的需要重新划线,并画上新添加的点;

297                             if (this.can.tempPointList.length > 0) {

298                                 //重画:

299                                 this.clearCan();

300                                 //showImg();

301                                 if (this.can.IsClose) {

302                                     this.fillBackColor();

303                                 }

304                                 this.drawAllLine();

305                                 this.drawArcBig(this.can.tempPointList[0].pointx, this.can.tempPointList[0].pointy);

306                                 return;

307                             }

308                             return;

309                         }

310                         else {

311                            // $("#Text1").val("");

312                         }

313                     }

314                     if (ii == 0) {

315                         if (this.can.tempPointList.length > 0) {

316                             //清空临时数组;

317                             this.can.tempPointList.length = 0;

318                             //重画:

319                             this.clearCan();

320                             //showImg();

321                             if (this.can.IsClose) {

322                                 this.fillBackColor();

323                             }

324                             this.drawAllLine();

325                             //this.drawArc(this.can.tempPointList[0].pointx, this.can.tempPointList[0].pointy);

326                         }

327                     }

328                 }

329                 else {

330                     //防止计算误差引起的添加点,当闭合后,瞬间移动起始点,可能会插入一个点到临时数组,当再次执行时,

331                     //就会在非闭合情况下插入该点,所以,时刻监视:

332                     if (this.can.tempPointList.length > 0) {

333                         this.can.tempPointList.length = 0;

334                     }

335                 }

336            }

337

338         };

339

340

复制代码

复制代码

1

2         .canvasDiv {

3             position: relative;

4             border: 1px solid red;

5             height: 400px;

6             width: 400px;

7             top: 50px;

8             left: 100px;

9             z-index: 0;

10         }

11

12         img {

13             width: 400px;

14             height: 400px;

15             z-index: 1;

16             position: absolute;

17         }

18

19         #canvas {

20             position: absolute;

21             border: 1px solid green;

22             z-index: 2;

23         }

24         .btnCollection {

25             margin-left: 100px;

26         }

27

复制代码

1

2            

3

4

html5 自动扣图,html5 canvas+js实现ps钢笔抠图相关推荐

  1. html5 canvas+js实现ps钢笔抠图(速抠图 www.sukoutu.com)

    html5 canvas+js实现ps钢笔抠图(速抠图 www.sukoutu.com)   根据html5 canvas+js实现ps钢笔抠图的实现,aiaito 开发者开发了一套在线抠图工具,速抠 ...

  2. html5 canvas+js实现ps钢笔抠图

    html5 canvas+js实现ps钢笔抠图 原文:https://www.cnblogs.com/guozefeng/p/3719915.html 1. 项目要求需要用js实现photoshop中 ...

  3. html5 自动扣图,html5利用canvas实现颜色容差抠图功能

    利用canvas的getImageData,我们可以获取到一张图片每一个像素的信息,而通过对每一个像素信息的对比,我们就可以找到需要消去的像素点.比如下面这一张图片,如果我们想要扣去白色部分(粉色是b ...

  4. html5 自动扣图,利用canvas实现一个抠图小工具

    本文作者:IMWeb 孙世吉 未经同意,禁止转载 利用canvas实现一个抠图小工具 0 前言 作为新一代的前端开发工程师,PS抠图切图已经不是必备技能了,我们有UI/交互/视觉等更专业的设计同学帮我 ...

  5. PS学习记录6--html5 canvas+js实现ps钢笔抠图

    APP在微信的推广下载转化率一直是困扰开发者和推广者的一大难题,那么如何提高APP的下载转化率呢?微信作为一款国内最大的社交类APP.有着非常大的开发潜力.但是我们如何在推广过程中能够高效.有针对性的 ...

  6. html5 自动扣图,js+html5 canvas实现ps钢笔抠图

    html5 canvas+js实现ps钢笔抠图 1. 项目要求需要用js实现photoshop中钢笔抠图功能,就用了近三四天的时间去解决它,最终还是基本上把他实现了. 做的过程中走了不少弯路,最终一同 ...

  7. html5 自动扣图,canvas像素点操作之视频绿幕抠图

    本文介绍了canvas像素点操作之视频绿幕抠图,分享给大家,具体如下: 用法: context.putimagedata(imgdata, x, y, dx, dy, dwidth, dheight) ...

  8. html5 自动扣图,5 秒实现自动抠图?见过 remove.bg 这款神器

    雷锋网(公众号:雷锋网) AI 科技评论按:是否为了简单的抠图功能,还在苦苦修炼 Photoshop 大法?即使修炼成功了,是否觉得在抠图这件事情上花费的时间依然太多?如今一个名叫 remove.bg ...

  9. html5 自动扣图,Remove.bg – 只需5秒!一键自动抠图移除背景工具 人工智能代替PhotoShop...

    无论是专业的设计师.摄影师还是普通办公者,可能都经历过用 PS 抠图去除背景的苦难日子吧.简单来说,抠图就是将照片的主体人或物品从图片中抠出来,以便贴到别处使用. 然而抠图虽然是 PhotoShop ...

  10. 图片自动切图java源代码_Sketch 和 PS中的设计图如何实现“自动切图”?

    切图是很多UI设计师的一项日常工作.平时做完设计图,要将设计稿切成便于制作成页面的图片,并标注好尺寸和间距,交付给前端来完成html+css布局的静态页面,有利于交互,形成良好的视觉感. 但有的认为前 ...

最新文章

  1. JAVA 中 string 和 int 互相转化
  2. socket的三次握手
  3. 自学习 与 无监督特征学习
  4. linux C如何获取服务器节点上所有网口的ip地址
  5. Java调优:Mybaitis的缓存优化
  6. Matlab 数学建模算法大全
  7. win10分辨率设置_win10分辨率设置方法教程
  8. input限制上传数量,规定图片上传数量
  9. Oralce数据库断电之ORA-00600: 内部错误代码, 参数: [kcratr_nab_less_than_odr], [1], [37]
  10. 转载:简明 GPG 概念
  11. 【概率论】4-5:均值和中值(The Mean and the Median)
  12. 什么是异常,如何进行异常处理?
  13. ureport2 vue版本实现
  14. [转载] 硬汉2奉陪到底
  15. 使用Apache HttpClient4.x 发送 GET POST 请求
  16. 【文献学习】文献分类、查询、阅读及管理
  17. PADS布线问题【同网络不能够连线】【不能够任意放置过孔】
  18. signature=238bc634dea41b329480120e2b242d0b,dea-8k_20191106.htm
  19. 3D.处女座的训练(C++)
  20. oracle 全面预算,财辅全面预算管理系统的设计与实现(Eclipse,Oracle)

热门文章

  1. [原创][Java]一个简单高效的线程安全队列的JAVA实现
  2. 随笔三(触动心灵的那些话)
  3. epic注册什么服务器最好,epic国内有服务器吗(epic服务器在哪)
  4. The current epoch, 79 is less than the accepted epoch, 5b
  5. 360校招 求立方体表面积
  6. 2020 蓝桥杯大学模拟赛(三) - 程序设计:养猫题解
  7. 自编一个从指定位置开始查找字符串的Python代码
  8. ecshop模板支持php,让ecshop模板支持php运算
  9. Google IO 2022——CSS 状态
  10. 文本分类(0)——scrapy爬新浪滚动新闻