经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » HTML/CSS » HTML5 » 查看文章
canvas实现动态替换人物的背景颜色
来源:cnblogs  作者:南风晚来晚相识  时间:2023/11/17 9:18:46  对本文有异议

起因

  1. 今天遇见一个特别有意思的小功能。
  2. 就是更换人物图像的背景颜色。
  3. 大致操作步骤就是:点击人物-实现背景颜色发生变化

将图片绘画到canvas画布上

  1. 我们需要将图片绘制到canvas画布上。
  2. 这样做的目的是为了方便我们去操作像素点来更改颜色。
  3. 首先创建 Image 的实例。将图片的地址赋值给图片实例src
  4. 当图片加载完成后,onload 事件可以知道图片是否加载完成
  5. 根据 Image的实例将图片大小赋值给画布,让他们大小保持一致。
  6. 最后使用 ctx.drawImage来进行绘画就行
  7. 特别提醒的是:src 属性一定要写到 onload 的后面,否则程序在 IE 中会出错。
  1. <body>
  2. <canvas id="canvas">
  3. </body>
  4. <script type="text/javascript">
  5. // 获取dom节点
  6. const canvas = document.getElementById('canvas')
  7. //获取上下文
  8. const ctx = canvas.getContext('2d');
  9. // 将图片绘制到canvas画布上
  10. function initPic(picInfo){
  11. // 创建一个图片的实例
  12. const img = new Image()
  13. // 引入图片的地址
  14. img.src = picInfo.url
  15. img.onload =()=>{
  16. // 设置画布的宽高与图片的保持一致
  17. canvas.width= img.width
  18. canvas.height= img.height
  19. // 开始绘画
  20. ctx.drawImage(img, 0, 0 );
  21. }
  22. }
  23. initPic({
  24. url: './src/assets/person.png'
  25. })
  26. </script>

drawImage 的简单介绍

  1. canvasdrawImage()提供了更多在canvas上绘制图像的方法。
  2. drawImage() 方法有三种形式:
  3. drawImage(image, dx, dy) 在指定的 (dx, dy) 位置绘制图像。
  4. drawImage(image, dx, dy, width, height) 在指定的 (dx, dy) 位置,并使用指定的宽度和高度绘制图像。
  5. drawImage(image, sourceX, sourceY, sourceWidth, sourceHeight, dx, dy, width, height) 在指定的 (dx, dy) 位置,并使用指定的宽度和高度绘制图像。图像的源坐标和尺寸也指定了。
  6. image:允许任何的画布图像源

注册事件获取点击时的坐标对应的颜色

  1. 我们通过 e.offsetX, e.offsetY 可以轻松拿到点击的坐标x,y
  2. 可以通过 getImageData 获取到图片的所有像素点的颜色。
  3. 但是怎么通过点击的位置(xy)获取到对应的的像素索引呢?
  4. 其实他们的关系是这样的:
  5. // 每个像素占用4个字节(RGBA)
  6. const index = (y * image.width + x) * 4;
  7. 根据上面这个公式,我们可以知道坐标对应的像素索引。
  8. 有了索引,我们可以拿到坐标对应的颜色
  1. function clickMy(e){
  2. // 获取点击时的坐标
  3. let x = e.offsetX
  4. let y = e.offsetY
  5. // 获取所有的像素点颜色
  6. let imagedata = ctx.getImageData(0, 0, canvas.width, canvas.height);
  7. console.log('获取所有的像素点颜色', imagedata)
  8. // 这个坐标点对应的颜色
  9. let clickColor = getColor(x,y, imagedata)
  10. console.log('这个坐标点对应的颜色', clickColor)
  11. }
  12. // 计算点击坐标对应的像素索引
  13. function bgIndex(x,y){
  14. return (y * canvas.width + x) * 4;
  15. }
  16. // 根据索引得到颜色值
  17. function getColor(x,y,imgData){
  18. let i = bgIndex(x,y)
  19. return [
  20. imgData.data[i],
  21. imgData.data[i+1],
  22. imgData.data[i+2],
  23. imgData.data[i+3]
  24. ]
  25. }
  26. // 注册事件
  27. canvas.addEventListener("click", clickMy, false)

更改当前像素点的颜色

  1. 现在我们希望点击的这个点的颜色变成红色。
  2. 现在的我们可以拿到所有像素点,当前的坐标,坐标对应的颜色。
  3. 现在我们的主角出场了(此时灯光闪烁,五彩的光打在他的身上)
  4. context.putImageData(imageData, x, y);
  5. 1个参数:imageData: 包含了图像的所有像素数据,
  6. 通过ctx.getImageData(0, 0, canvas.width, canvas.height)可以获取到;
  7. 2,3个参数表示坐标。
  8. 它用于将图像数据绘制到画布上。
  9. 这个方法允许开发者操作和绘制像素级别的数据,
  10. 从而实现复杂的图像效果和处理。
  1. function clickMy(e){
  2. // 获取点击时的坐标
  3. let x =e.offsetX
  4. let y = e.offsetY
  5. // 获取所有的像素点颜色
  6. let imagedata = ctx.getImageData(0, 0, canvas.width, canvas.height);
  7. console.log('获取所有的像素点颜色', imagedata)
  8. // 这个坐标点对应的颜色
  9. let clickColor = getColor(x,y, imagedata)
  10. console.log('这个坐标点对应的颜色', clickColor)
  11. // 最后更改为红色的rgba值
  12. let targetBgArr = [255,0,0,255]
  13. // 更改颜色
  14. function changeColor(x,y){
  15. let i = bgIndex(x,y)
  16. imagedata.data.set(targetBgArr, i)
  17. }
  18. changeColor(x,y)
  19. // 更改当前像素点的颜色
  20. ctx.putImageData(imagedata, 0, 0);
  21. }

将被点击的点的相似颜色全部变为红色

  1. 我们通过两个颜色的rgba值相减,看rgba的各个绝对值之和。
  2. 来判断颜色的相似。
  3. 同时我页需要注意边界范围与颜色已经变为了目标颜色。
  4. 这个时候我们就需要停止调用函数了

核心代码

  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. <title>Document</title>
  7. </head>
  8. <body>
  9. <canvas id="canvas">
  10. </body>
  11. <script type="text/javascript">
  12. // 获取dom节点
  13. const canvas = document.getElementById('canvas')
  14. // 获取上下文
  15. const ctx = canvas.getContext('2d',{
  16. willReadFrequently:true
  17. });
  18. function initPic(picInfo){
  19. // 创建一个图表的实例
  20. const img = new Image()
  21. img.onload =()=>{
  22. // 设置画布的宽高与图片的保持一致
  23. canvas.width= img.width
  24. canvas.height= img.height
  25. // 开始绘画
  26. ctx.drawImage(img, 0, 0 );
  27. }
  28. // 引入图片的地址
  29. img.src = picInfo.url
  30. }
  31. function clickMy(e){
  32. // 获取点击时的坐标
  33. let x =e.offsetX
  34. let y = e.offsetY
  35. // 获取所有的像素点颜色
  36. let imagedata = ctx.getImageData(0, 0, canvas.width, canvas.height);
  37. console.log('获取所有的像素点颜色', imagedata)
  38. // 这个坐标点对应的颜色
  39. let clickColor = getColor(x,y, imagedata)
  40. console.log('这个坐标点对应的颜色', clickColor)
  41. // 最后更改为红色的rgba值
  42. let targetBgArr = [255,0,0,255]
  43. function changeColor(x,y){
  44. // 边界范围
  45. if(x<0 || x>canvas.width || y<0 || y>canvas.height){
  46. return
  47. }
  48. let color = getColor(x,y,imagedata )
  49. // 相似颜色的相差值
  50. if(diffBg(color,clickColor)>150){
  51. return
  52. }
  53. // 已经变为了目标色(红色)
  54. if(diffBg(color,targetBgArr)==0){
  55. return
  56. }
  57. let i = bgIndex(x,y)
  58. // 在内存中更改像素的颜色
  59. imagedata.data.set(targetBgArr, i)
  60. // 改变周围(上下左右)的颜色
  61. changeColor(x+1,y)
  62. changeColor(x-1,y)
  63. changeColor(x,y+1)
  64. changeColor(x,y-1)
  65. }
  66. changeColor(x,y)
  67. // 将内存中的像素点的颜色(重新绘制在画布上)
  68. ctx.putImageData(imagedata, 0, 0);
  69. }
  70. // 计算点击坐标对应的像素索引
  71. function bgIndex(x,y){
  72. return (y * canvas.width + x) * 4;
  73. }
  74. // 根据索引得到颜色值
  75. function getColor(x,y,imgData){
  76. let i = bgIndex(x,y)
  77. return [
  78. imgData.data[i],
  79. imgData.data[i+1],
  80. imgData.data[i+2],
  81. imgData.data[i+3]
  82. ]
  83. }
  84. // 查看两个颜色的相差值
  85. function diffBg(color1,color2){
  86. // 我们是取两个颜色的绝对值相加
  87. return Math.abs(color1[0] -color2[0]) +
  88. Math.abs(color1[1] -color2[1]) +
  89. Math.abs(color1[2] -color2[2]) +
  90. Math.abs(color1[3] -color2[3])
  91. }
  92. // 注册事件
  93. canvas.addEventListener("click", clickMy, false)
  94. initPic({
  95. url: '../assets/person1.png'
  96. })
  97. </script>
  98. </html>

更改为按钮,背景发生改变

  1. 上面我们实现了,点击背景色,实现颜色的更改。
  2. 但是实际的过程中。
  3. 我们是不知道背景颜色的,怎么去确认背景颜色呢?
  4. 其实,可以默认坐标为(44)是背景颜色。
  5. 在实际的过程中,其实这个位置99.9999%是背景色。
  6. 我们是先选择颜色,然后点击确定,实现颜色的更改
  7. 现在我们来优化一下。让用户自己选择背景色,选择好后。
  8. 点击确定,背景颜色就发生变化
  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. <title>Document</title>
  7. <style>
  8. </style>
  9. </head>
  10. <body>
  11. <div>
  12. <canvas id="canvas">
  13. </div>
  14. <input type="color" id="color" >
  15. <button id="red">确定</button>
  16. </body>
  17. <script type="text/javascript">
  18. // 获取dom节点
  19. const canvas = document.getElementById('canvas')
  20. // 获取上下文
  21. const ctx = canvas.getContext('2d',{
  22. willReadFrequently:true
  23. });
  24. // 将16进制转化为rgba的颜色值
  25. function changeRGBA(hex) {
  26. // 去除 # 开头的第一个字符
  27. hex = hex.slice(1);
  28. // 将16进制字符串转换rgba
  29. let rgba = [];
  30. for (let i = 0; i < 6; i += 2) {
  31. let byte = parseInt(hex.substr(i, 2), 16);
  32. rgba.push(byte);
  33. }
  34. // 添加 alpha 通道
  35. rgba.push(255);
  36. // 返回 RGBA 颜色值
  37. return rgba;
  38. }
  39. function initPic(picInfo){
  40. // 创建一个图表的实例
  41. const img = new Image()
  42. img.onload =()=>{
  43. // 设置画布的宽高与图片的保持一致
  44. canvas.width= img.width
  45. canvas.height= img.height
  46. // 开始绘画
  47. ctx.drawImage(img, 0, 0 );
  48. }
  49. // 引入图片的地址
  50. img.src = picInfo.url
  51. }
  52. function clickMy(e, type){
  53. let color = document.getElementById('color')
  54. // 4,4的地方默认为是背景颜色
  55. let x = 4
  56. let y = 4
  57. // 获取所有的像素点颜色
  58. let imagedata = ctx.getImageData(0, 0, canvas.width, canvas.height);
  59. // 这个坐标点对应的颜色
  60. let clickColor = getColor(x,y, imagedata)
  61. console.log('这个坐标点对应的颜色', clickColor)
  62. // 颜色为用户选择的值
  63. let targetBgArr = changeRGBA(color.value)
  64. function changeColor(x,y){
  65. // 边界范围
  66. if(x<0 || x>canvas.width || y<0 || y>canvas.height){
  67. return
  68. }
  69. let color = getColor(x,y,imagedata )
  70. // 相似颜色的相差值
  71. if(diffBg(color,clickColor)>150){
  72. return
  73. }
  74. // 已经变为了目标色(红色)
  75. if(diffBg(color,targetBgArr)==0){
  76. return
  77. }
  78. let i = bgIndex(x,y)
  79. // 在内存中更改像素的颜色
  80. imagedata.data.set(targetBgArr, i)
  81. // 改变周围(上下左右)的颜色
  82. changeColor(x+1,y)
  83. changeColor(x-1,y)
  84. changeColor(x,y+1)
  85. changeColor(x,y-1)
  86. }
  87. changeColor(x,y)
  88. // 将内存中的像素点的颜色(重新绘制在画布上)
  89. ctx.putImageData(imagedata, 0, 0);
  90. }
  91. // 计算点击坐标对应的像素索引
  92. function bgIndex(x,y){
  93. return (y * canvas.width + x) * 4;
  94. }
  95. // 根据索引得到颜色值
  96. function getColor(x,y,imgData){
  97. let i = bgIndex(x,y)
  98. return [
  99. imgData.data[i],
  100. imgData.data[i+1],
  101. imgData.data[i+2],
  102. imgData.data[i+3]
  103. ]
  104. }
  105. // 查看两个颜色的相差值
  106. function diffBg(color1,color2){
  107. // 我们是取两个颜色的绝对值相加
  108. return Math.abs(color1[0] -color2[0]) +
  109. Math.abs(color1[1] -color2[1]) +
  110. Math.abs(color1[2] -color2[2]) +
  111. Math.abs(color1[3] -color2[3])
  112. }
  113. // 注册事件
  114. canvas.addEventListener("click", clickMy, false)
  115. red.addEventListener("click", clickMy, false)
  116. initPic({
  117. url: '../assets/person1.png'
  118. })
  119. </script>
  120. </html>

最后的功能-下载

  1. 上面我们已经成功实现让用户选择颜色。
  2. 更换用户自己选择的颜色。
  3. 下载我们只需要实现下载功能就好了。
  4. 下载功能主要使用 canvas.toDataURL
  5. 然后利用a标签进行下载
  1. <button id="down">下载</button>
  2. down.addEventListener('click',()=>{
  3. let imgURL = canvas.toDataURL({format: "image/png", quality:1, width:canvas.width, height:canvas.height});
  4. let link = document.createElement('a');
  5. link.download = "人物图片";
  6. link.href = imgURL;
  7. document.body.appendChild(link);
  8. link.click();
  9. document.body.removeChild(link);
  10. })

原文链接:https://www.cnblogs.com/IwishIcould/p/17834419.html

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

本站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号