canvas替换图片背景色

  1. html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link href="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.13/theme-chalk/index.css" rel="stylesheet" />
    <link rel="stylesheet" href="./css/index.css" />
    <title>Document</title>
  </head>
  <body>
    <div class="header">
      <input type="file" placeholder="选择文件" id="imageUpload" accept="image/*" />
    </div>
    <div class="main">
      <div class="main-left main-width">
        <canvas id="canvas"></canvas>
      </div>
      <div class="main-mid">
        <input type="color" id="picker" />
        <button id="generate" class="el-button el-button--primary el-button--mini">生成</button>
      </div>
      <div class="main-right main-width">
        <canvas id="canvas-handle"></canvas>
      </div>
    </div>
    <script src="./js/canvas.js"></script>
  </body>
</html>

  1. css
html,
body {
  padding: 0;
  margin: 0;
}

.main {
  width: 100%;
  margin-top: 50px;
  display: flex;
  justify-content: space-around;
}

.main-width {
  width: 500px;
  height: 500px;
  /* background-color: pink; */
  border-radius: 5px;
  overflow: hidden;
  border: 1px solid #409eff;
}

.main-left {
}
.main-mid {
  width: 200px;
  height: auto;
  /* background-color: aliceblue; */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.main-right {
}

.header {
  height: 60px;
  text-align: center;
  line-height: 60px;
}

#picker {
  margin-bottom: 10px;
}

  1. javascript
const cvs = document.getElementById('canvas');
const cvsHandler = document.getElementById('canvas-handle');
const fileUpload = document.getElementById('imageUpload');
const ctx = cvs && cvs.getContext('2d', { willReadFrequently: true });
const ctxHandler = cvsHandler && cvsHandler.getContext('2d', { willReadFrequently: true });
const picker = document.getElementById('picker');
const generateBtn = document.getElementById('generate');

cvs.width = cvsHandler.width = cvs.parentNode.clientWidth;
cvs.height = cvsHandler.height = cvs.parentNode.clientHeight;

let url = '';
let clickColor = [];

fileUpload.addEventListener('change', function (e) {
  const file = e.target.files[0];
  url = URL.createObjectURL(file);
  // 清空画布,不然图片会重叠
  ctx.clearRect(0, 0, cvs.width, cvs.height);
  ctxHandler.clearRect(0, 0, cvs.width, cvs.height);
  init();
});

function init() {
  const image = new Image();
  image.src = url;
  image.onload = function () {
    //图片缩放比例,小图片放大,大图片缩小
    let scale = image.width / cvs.width;
    //图片居中处理
    let x = image.width / scale >= cvs.width ? 0 : (cvs.width - image.width / scale) / 2;
    let y = image.height / scale >= cvs.height ? 0 : (cvs.height - image.height / scale) / 2;

    ctx.drawImage(image, 0, 0, image.width, image.height, x, y, image.width / scale, image.height / scale);
    ctxHandler.drawImage(image, 0, 0, image.width, image.height, x, y, image.width / scale, image.height / scale);
  };
}

/**
 * @desc 根据x,y返回imageData里面对应的颜色值
 * @param { Number } x
 * @param { Number } y
 * @returns {Number} index 点击的位置索引
 */
function point2Index(x, y) {
  return (y * cvs.width + x) * 4;
}

/**
 * @desc 通过索引获取点击点的颜色数值
 * @param {boolean} a
 */
function getColorByIndex(index, imageData) {
  const r = imageData.data[index];
  const g = imageData.data[index + 1];
  const b = imageData.data[index + 2];
  const a = imageData.data[index + 3];
  return [r, g, b, a];
}

/**
 * @desc 修改相近的imageData item 数据,
 * @param { Array } clickColor
 * @param { Array } toChangeColorToRgba
 * @param { Object } imageData
 * @returns { Object } new imageData object
 */
function getImageData(clickColor, toChangeColorToRgba, imageData) {
  const data = imageData.data || [];

  for (let i = 0, len = data.length; i < len; i += 4) {
    const isSim = isSimilar(clickColor, data.slice(i, i + 4), 30);
    if (isSim) {
      data[i] = toChangeColorToRgba[0];
      data[i + 1] = toChangeColorToRgba[1];
      data[i + 2] = toChangeColorToRgba[2];
      data[i + 3] = toChangeColorToRgba[3];
    }
  }

  return imageData;
}

/**
 * @desc 十六进制转rgba
 * @param {string} hex 
 * @returns {boolean} 返回值为true
 */
function hexToRgba(hex, opacity = 255) {
  hex = hex.replace('#', '');
  let r = parseInt(hex.substring(0, 2), 16);
  let g = parseInt(hex.substring(2, 4), 16);
  let b = parseInt(hex.substring(4, 6), 16);

  return [r, g, b, opacity];
}

/**
 * @desc
 * @param {Arrary} color1
 * @param {Arrary} color2
 * @param {Number} difference 差值
 * @returns {boolean} return boolean
 */
function isSimilar(color1, color2, difference) {
  let diff = Math.abs(color1[0] - color2[0]) + Math.abs(color1[1] - color2[1]) + Math.abs(color1[2] - color2[2]) + Math.abs(color1[3] - color2[3]);
  return diff < difference;
}

generateBtn.addEventListener('click', function () {
  if (!clickColor.length) return;
  const imageData = ctx.getImageData(0, 0, cvs.width, cvs.height);
  const toChangeColorToRgba = hexToRgba(picker.value);
  const newImageData = getImageData(clickColor, toChangeColorToRgba, imageData);

  ctxHandler.putImageData(newImageData, 0, 0);
});

cvs.addEventListener('click', function (e) {
  if (!url) return;
  const x = e.offsetX;
  const y = e.offsetY;
  const imageData = ctx.getImageData(0, 0, cvs.width, cvs.height);
  const index = point2Index(x, y);
  clickColor = getColorByIndex(index, imageData);
});

  1. 预览地址

gitee代码地址,点击即可查看

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值