Demonstrate address code repository

The key technology

Canvas API, Element-UI (el-color-picker, el-upload)

The principle of analytic

1. The user uploads a picture from the local PC

We take the image data and render it on the page, using elementUi’s El-upload

el-upload.avatar-uploader(
  ref="logoUpload",
  accept="image/*",
  action="#",
  :auto-upload="false",
  :on-change="handleStatusChange"
)
  el-button(size="small", type="primary") Click uploadCopy the code

You don’t actually need to upload to the server, you just need to get the in-memory URL of the image

handleStatusChange(file) {
  // console.log(file);
  this.originImg = URL.createObjectURL(file.raw);
},
Copy the code

After getting the URL, we can first render the image on the page with the IMG tag. The purpose of doing this is to get the actual size of the image, and we will scale it on our canvas.

// The image is loaded
    loadImg(e) {
      const img = e.target;
      const width = img.offsetWidth;
      const height = img.offsetHeight;
      this.imgWidth = width;
      this.imgHeight = height;
      this.canHeight = (height / width) * this.canWidth;
    }
Copy the code

The width of the canvas can be obtained based on the outer container

this.$nextTick(() = > {
      const contentWidth = document.querySelector(".origin-box").offsetWidth;
      this.canWidth = Math.min(contentWidth - 12.this.canWidth);
});
Copy the code

2. The drawing canvas

Drawing an image to a canvas is a relatively easy step,

// We need to scale here because our canvas is already scaled
this.originCtx.scale(this.canWidth / width, this.canWidth / width);
this.originCtx.drawImage(img, 0.0);
Copy the code

3. Select a color

Click on canvas, we can get the color value of the point, and get the method

ctx.getImageData(targetX,targetY,1.1)
Copy the code

We get the imagedate object, {data, width, height}, and data is the color we want.

4. Iterate over the color value of the original image and replace the selected color with the corresponding color

Core API: getImageData putImageData

/ / get the data
const data = this.imageData.data || [];
// Iterate over and replace
for (let i = 0; i < data.length; i += 4) {
        const similar = this.isSimilar(_fromColor, data.slice(i, i + 4));
        if (similar) {
          data[i] = _toColor[0];
          data[i + 1] = _toColor[1];
          data[i + 2] = _toColor[2];
          data[i + 3] = _toColor[3] * 255; }}// Draw to the target container
 this.transCtx.putImageData(this.imageData, 0.0);
Copy the code

The isSimilar method is used to determine whether two colors are similar or equal. This can be adjusted by parameters (similar to the tolerance concept of PS). The smaller the tolerance value, the more accurate the match.

The color values are IN RGBA format, that is, a group of four arrays with values between [0,255]. Since el-Picker returns rGBA, transparency is represented by [0, 1], so convert to 0-255

5. undo&redo

Undo, forward, and backward functions are still necessary. Repeat the replacement operation to return to the historical operation steps. Create a queue (using arrays instead), and each time a new change is added to the queue, unshift is used to indicate that the entry pop is removed from the back of the queue. You can set the upper limit to 10. A large number of queues occupy large memory resources. Do not set the upper limit to 10. Maintains an index, understood as a pointer, representing the position of the current rollback data in the queue.

undo() {
  this.index++;
  this.redrawImg();
},
redo() {
  this.index--;
  this.redrawImg();
},
redrawImg() {
  const preImageData = JSON.parse(this.imgStock[this.index]).data;
  this.imageData = this.transCtx.createImageData(
    this.canWidth,
    this.canHeight
  );
  for (let i = 0; i < this.imageData.data.length; i++) {
    this.imageData.data[i] = preImageData[i];
  }
  this.transCtx.putImageData(this.imageData, 0.0);
},
Copy the code

Note the details: When you go back to a certain historical record, such as index=5, and then perform manual replacement, you will “traversal”, and need to remove all history before index=5. (Maybe the description is a little convoluted ~)

At this point, the core function is complete

TODO LIST

  1. Increase edge recognition and remove burrs
  2. Add tolerance options
  3. Try video matting and replacement
  4. .

Demonstrate address code repository

Welcome your comments & STAR!