Canvas replaces the background color of the picture

  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="select file" 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">Generate</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 & amp; & amp; cvs. getContext('2d', {<!-- --> willReadFrequently: true });
const ctxHandler = cvsHandler & amp; & amp; 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);
  // Clear the canvas, otherwise the pictures will overlap
  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 () {<!-- -->
    //Picture zoom ratio, small pictures are enlarged, large pictures are reduced
    let scale = image.width / cvs.width;
    // image centering
    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 returns the corresponding color value in imageData according to x and y
 * @param { Number } x
 * @param { Number } y
 * @returns {Number} index clicked position index
 */
function point2Index(x, y) {<!-- -->
  return (y * cvs. width + x) * 4;
}

/**
 * @desc Get the color value of the clicked point through the index
 * @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 modify similar imageData item data,
 * @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 hex to rgba
 * @param {string} hex
 * @returns {boolean} return value is 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 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. preview address

gitee code address, click to view