经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » HTML/CSS » HTML5 » 查看文章
使用canvas一步步实现图片打码功能的方法
来源:jb51  时间:2019/6/18 8:38:19  对本文有异议

原文地址
https://github.com/MY729/front-common-funtion/blob/master/picture-code-demo/README.md

预览地址
https://my729.github.io/front-common-funtion/picture-code-demo/picture-code.html

准备工作

demo 基于 vue + elelment-ui

首先创建一个html文件, 并引入 vue 和 elelment-ui(注意还有样式文件)

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>Document</title>
  8. <!-- elelment-ui样式 -->
  9. <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
  10. </head>
  11. <body>
  12. </body>
  13. <!-- 引入vue -->
  14. <script src="https://cdn.jsdelivr.net/npm/vue"></script>
  15. <!-- 引入element-ui -->
  16. <script src="https://unpkg.com/element-ui/lib/index.js"></script>
  17. </html>

接下来就可以写我们的打码功能啦

实现思路

  • 创建canvas画布,并将要打码的图片绘制上去
  • 监听鼠标在图片上的点击,移动、松开事件,在canvas画布上绘制要打码的区域
  • 处理绘制的打码区域
  • 保存打码后的图片

将要打码的图片绘制到canvas画布上

  1. // 初始化 绘制图片
  2. toCode (currentImg) {
  3. this.$nextTick(() => {
  4. // 获取将要绘制的canvas的父元素节点
  5. let parentId = document.getElementById('parentId')
  6. // 初始化图片
  7. let drawImg = new Image()
  8. drawImg.setAttribute('crossOrigin', 'anonymous')
  9. drawImg.crossOrigin = 'Anonymous'
  10. drawImg.src = currentImg
  11. // 创建canvas元素并添加到父节点中
  12. let addCanvas = document.createElement('canvas')
  13. parentId.appendChild(addCanvas)
  14. let canvas = parentId.lastElementChild
  15. canvas.id = 'imgCanvas'
  16. if (canvas.getContext) {
  17. let ctx = canvas.getContext('2d')
  18. // 绘制图片
  19. drawImg.onload = function () {
  20. canvas.width = 720
  21. canvas.height = 500
  22. ctx.drawImage(drawImg, 0, 0, 720, 500)
  23. }
  24. }
  25. })
  26. }

点击打码按钮,绘制打码区域

思路:

  • 鼠标点击,获取点击时的坐标,每次点击前可能会存在打过码的区域,先清除画布,重新绘制图片
  • 鼠标移动,开始绘制打码的矩形,通过移动的坐标和上面点击的点坐标确定绘制的矩形坐标和宽高
  • 将绘制的打码矩形,分割成一个个宽高15像素的小正方形,并给每个小正方形生产随机颜色
  • 鼠标松开,停止绘制矩形
  1. // 打码
  2. dialogCode (img) {
  3. let parentId = document.getElementById('parentId')
  4. let canvas = document.getElementById('imgCanvas')
  5. if (canvas.getContext) {
  6. let ctx = canvas.getContext('2d')
  7. let drawImage = new Image()
  8. drawImage.crossOrigin = 'Anonymous'
  9. drawImage.src = img
  10. drawImage.onload = () => {
  11. ctx.drawImage(drawImage, 0, 0, 720, 500)
  12. }
  13. // 鼠标点击
  14. parentId.onmousedown = e => {
  15. ctx.clearRect(0, 0, canvas.width, canvas.height)
  16. ctx.drawImage(drawImage, 0, 0, 720, 500)
  17. this.flag = true
  18. this.clickX = e.offsetX // 鼠标点击时的X
  19. this.clickY = e.offsetY // 鼠标点击时的Y
  20. }
  21. // 鼠标松开
  22. parentId.onmouseup = () => {
  23. this.flag = false
  24. }
  25. // 鼠标按下
  26. parentId.onmousemove = e => {
  27. if (this.flag) {
  28. ctx.clearRect(0, 0, canvas.width, canvas.height)
  29. ctx.drawImage(drawImage, 0, 0, 720, 500)
  30. ctx.beginPath()
  31. let pixels = [] // 二维数组,每个子数组有5个值(绘制矩形左上角的X坐标、y坐标,矩形的宽、高,生成的4位随机数用于颜色值)
  32. for (let x = 0; x < (e.offsetX - this.clickX) / 15; x++) {
  33. for (let y = 0; y < (e.offsetY - this.clickY) / 15; y++) {
  34. pixels.push([(x * 15 + this.clickX), (y * 15 + this.clickY), 15, 15, Math.floor(Math.random() * 9999)])
  35. }
  36. for (let y = 0; y > (e.offsetY - this.clickY) / 15; y--) {
  37. pixels.push([(x * 15 + this.clickX), (y * 15 + this.clickY), 15, 15, Math.floor(Math.random() * 9999)])
  38. }
  39. }
  40. for (let x = 0; x > (e.offsetX - this.clickX) / 15; x--) {
  41. for (let y = 0; y > (e.offsetY - this.clickY) / 15; y--) {
  42. pixels.push([(x * 15 + this.clickX), (y * 15 + this.clickY), 15, 15, Math.floor(Math.random() * 9999)])
  43. }
  44. for (let y = 0; y < (e.offsetY - this.clickY) / 15; y++) {
  45. pixels.push([(x * 15 + this.clickX), (y * 15 + this.clickY), 15, 15, Math.floor(Math.random() * 9999)])
  46. }
  47. }
  48. // 遍历数组绘制小正方形块
  49. for (let i = 0; i < pixels.length; i++) {
  50. ctx.fillStyle = '#bf' + pixels[i][4]
  51. ctx.fillRect(pixels[i][0], pixels[i][1], pixels[i][2], pixels[i][3])
  52. }
  53. ctx.fill()
  54. ctx.closePath()
  55. }
  56. }
  57. }
  58. }

保存

  1. // 保存
  2. dialogUpload () {
  3. let canvas = document.getElementById('imgCanvas')
  4. let tempImg = canvas.toDataURL('image/png')
  5. let imgURL = document.getElementById('imgURL')
  6. imgURL.crossOrigin = 'Anonymous'
  7. imgURL.src = tempImg
  8. }

源码

复制到html文件可预览

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>使用canvas一步步实现图片打码功能</title>
  8. <!-- elelment-ui样式 -->
  9. <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
  10. <style type="text/css">
  11. .rc-code__buttons {
  12. margin: 20px;
  13. }
  14. </style>
  15. </head>
  16. <body>
  17. <div id="app">
  18. <div class="rc-code__buttons">
  19. <h1>vue项目中使用canvas一步步实现图片打码功能</h1>
  20. <el-button type="primary" @click="dialogCode(data.img_url)">打码</el-button>
  21. <el-button type="success" @click="dialogUpload()">保存</el-button>
  22. </div>
  23. <el-row>
  24. <el-col :span="12"><h3>点击打码按钮,在图片上绘制打码区域; 点击保存,生成打码后的图片</h3></el-col>
  25. <el-col :span="12"><h3>保存后的图片</h3></el-col>
  26. <el-col :span="12"><div id="parentId"></div></el-col>
  27. <el-col :span="12"><img id="imgURL"/></el-col>
  28. </el-row>
  29. </div>
  30. </body>
  31. <!-- 引入vue -->
  32. <script src="https://cdn.jsdelivr.net/npm/vue"></script>
  33. <!-- 引入element-ui -->
  34. <script src="https://unpkg.com/element-ui/lib/index.js"></script>
  35. <script>
  36. new Vue({
  37. el: '#app',
  38. data () {
  39. return {
  40. data: {
  41. img_url: 'https://avatars0.githubusercontent.com/u/26196557?s=460&v=4'
  42. },
  43. flag: false, // 是否绘制矩形
  44. clickX: '', // 开始绘制矩形时,鼠标点击时的x坐标
  45. clickY: '' // 开始绘制矩形时,鼠标点击时的y坐标
  46. }
  47. },
  48. mounted() {
  49. this.toCode(this.data.img_url)
  50. },
  51. methods: {
  52. // 初始化 绘制图片
  53. toCode (currentImg) {
  54. this.$nextTick(() => {
  55. let parentId = document.getElementById('parentId')
  56. let drawImg = new Image()
  57. drawImg.setAttribute('crossOrigin', 'anonymous')
  58. drawImg.crossOrigin = 'Anonymous'
  59. drawImg.src = currentImg
  60. let addCanvas = document.createElement('canvas')
  61. parentId.appendChild(addCanvas)
  62. let canvas = parentId.lastElementChild
  63. canvas.id = 'imgCanvas'
  64. if (canvas.getContext) {
  65. let ctx = canvas.getContext('2d')
  66. drawImg.onload = function () {
  67. canvas.width = 720
  68. canvas.height = 500
  69. ctx.drawImage(drawImg, 0, 0, 720, 500)
  70. }
  71. }
  72. })
  73. },
  74. // 打码
  75. dialogCode (img) {
  76. let parentId = document.getElementById('parentId')
  77. let canvas = document.getElementById('imgCanvas')
  78. if (canvas.getContext) {
  79. let ctx = canvas.getContext('2d')
  80. let drawImage = new Image()
  81. drawImage.crossOrigin = 'Anonymous'
  82. drawImage.src = img
  83. drawImage.onload = () => {
  84. ctx.drawImage(drawImage, 0, 0, 720, 500)
  85. }
  86. parentId.onmousedown = e => {
  87. ctx.clearRect(0, 0, canvas.width, canvas.height)
  88. ctx.drawImage(drawImage, 0, 0, 720, 500)
  89. this.flag = true
  90. this.clickX = e.offsetX // 鼠标点击时的X
  91. this.clickY = e.offsetY // 鼠标点击时的Y
  92. }
  93. parentId.onmouseup = () => {
  94. this.flag = false
  95. }
  96. parentId.onmousemove = e => {
  97. if (this.flag) {
  98. ctx.clearRect(0, 0, canvas.width, canvas.height)
  99. ctx.drawImage(drawImage, 0, 0, 720, 500)
  100. ctx.beginPath()
  101. let pixels = [] // 二维数组,每个子数组有5个值(绘制矩形左上角的X坐标、y坐标,矩形的宽、高,生成的4位随机数用于颜色值)
  102. for (let x = 0; x < (e.offsetX - this.clickX) / 15; x++) {
  103. for (let y = 0; y < (e.offsetY - this.clickY) / 15; y++) {
  104. pixels.push([(x * 15 + this.clickX), (y * 15 + this.clickY), 15, 15, Math.floor(Math.random() * 9999)])
  105. }
  106. for (let y = 0; y > (e.offsetY - this.clickY) / 15; y--) {
  107. pixels.push([(x * 15 + this.clickX), (y * 15 + this.clickY), 15, 15, Math.floor(Math.random() * 9999)])
  108. }
  109. }
  110. for (let x = 0; x > (e.offsetX - this.clickX) / 15; x--) {
  111. for (let y = 0; y > (e.offsetY - this.clickY) / 15; y--) {
  112. pixels.push([(x * 15 + this.clickX), (y * 15 + this.clickY), 15, 15, Math.floor(Math.random() * 9999)])
  113. }
  114. for (let y = 0; y < (e.offsetY - this.clickY) / 15; y++) {
  115. pixels.push([(x * 15 + this.clickX), (y * 15 + this.clickY), 15, 15, Math.floor(Math.random() * 9999)])
  116. }
  117. }
  118. for (let i = 0; i < pixels.length; i++) {
  119. ctx.fillStyle = '#bf' + pixels[i][4]
  120. ctx.fillRect(pixels[i][0], pixels[i][1], pixels[i][2], pixels[i][3])
  121. }
  122. ctx.fill()
  123. ctx.closePath()
  124. }
  125. }
  126. }
  127. },
  128. // 保存
  129. dialogUpload () {
  130. let canvas = document.getElementById('imgCanvas')
  131. let tempImg = canvas.toDataURL('image/png')
  132. let imgURL = document.getElementById('imgURL')
  133. imgURL.crossOrigin = 'Anonymous'
  134. imgURL.src = tempImg
  135. }
  136. }
  137. })
  138. </script>
  139. </html>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持w3xue。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号