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
- Increase edge recognition and remove burrs
- Add tolerance options
- Try video matting and replacement
- .
Demonstrate address code repository
Welcome your comments & STAR!