background

I read an article about picture filters before, and I was interested in it, so I made this small DEMO, which can switch between a variety of picture filters and provide image download function.

Without further ado, first go to demo and Github address.

implementation

  • Tools:vue iview canvas
  • Realization function: picture drawing, filter modification, picture download
  • Key points:ctx.getImageData() ctx.putImageData() ctx.drawImage()Filter logic

1. The introduction ofiviewvue

<link rel="stylesheet" type="text/css" href="https://unpkg.com/view-design/dist/styles/iview.css" />
<script type="text/javascript" src="https://vuejs.org/js/vue.min.js"></script>
<script type="text/javascript" src="https://unpkg.com/view-design/dist/iview.min.js"></script>
Copy the code

2. Design an overall static page

First, the page must have two canvas tags, one to draw the original picture and the other to draw the picture with filter effect. Of course, there are image upload and download buttons and filter selection boxes, as follows:

 <div class="text-center">
    <div>
        <i-select
            v-model="pictureMode"
            style="width:200px"
            placeholder="Please select image mode"
            @on-change="selectMode"
        >
            <i-option v-for="item in selectList" :value="item.value" :key="item.value"
                >{{ item.label }}</i-option
            >
        </i-select>
    </div>
    <div style="margin: 24px 0">
        <i-button icon="ios-cloud-upload-outline" type="primary" @click="$refs.input.click()"</i-button > <i-button icon="ios-cloud-download-outline" type="primary" @click="downloadImage"</i-button > <inputtype="file" ref="input" @change="uploadImage" style="display: none;"/> </div> <div> <! -- User raw image --> <canvas ID ="origin" :width="width" :height="height" v-show="image"></canvas> <! -- Target image --> <canvas ID ="new" :width="width" :height="height" v-show="image"></canvas>
    </div>
</div>
Copy the code

3. Select an image and draw it

Obtain the selected file file through the input label, convert it into a Base64 string and assign it to the SRC attribute of the image. After the image is loaded, it will be drawn in the two canvas, which is the original image.

methods: {
    // Upload the image
    uploadImage(e) {
        var that = this;
        var file = e.target.files[0];
        if (typeof FileReader === 'undefined') {
            alert('Your browser does not support picture uploading, please upgrade your browser');
            return false;
        }
        var image = new Image(); // Create the image
        image.crossOrigin = 'Anonymous'; // Resolve some cross-domain issues
        image.onload = function() {
            that.width = image.width; // Set the canvas width
            that.height = image.height; // Set the canvas height
            that.image = image;
            // Wait for the canvas's width and height properties to finish rendering
            that.$nextTick((a)= >{ that.drawOriginImage(image); })};let reader = new FileReader();
        reader.readAsDataURL(file); / / generated base64
        reader.onload = e= > {
            image.src = e.target.result;
        };
    },
    // Draw the original image
    drawOriginImage(image) {
        var canvasOrigin = document.getElementById('origin');
        var ctxOrigin = canvasOrigin.getContext('2d');
        var canvasNew = document.getElementById('new');
        var ctxNew = canvasNew.getContext('2d');
        ctxOrigin.drawImage(image, 0.0, image.width, image.height);
        ctxNew.drawImage(image, 0.0, image.width, image.height); }},Copy the code

4. Select the filter and draw a new image

The canvas CTX object provides a method, getImageData(), that returns an array of values for each pixel in a region (for example: ImageData {width: 100, height: 100, data: Uint8ClampedArray[40000]}), 4 elements in the data array represent the RGBA value of a pixel point. By modifying the values of each of the four elements of this array, and then redrawing to a new canvas, we get our target image.

// Draw the target image
drawImage() {
    var canvasOrigin = document.getElementById('origin');
    var ctxOrigin = canvasOrigin.getContext('2d');
    var canvasNew = document.getElementById('new');
    var ctxNew = canvasNew.getContext('2d'); 
    var imageData = ctxOrigin.getImageData(0.0.this.width, this.height);
    var data = imageData.data; // Get every pixel of the original image
    this.chooseFilter(data, canvasNew, imageData); // Process the array according to the selected filter
    ctxNew.putImageData(imageData, 0.0); // Draw the data of the original image to the canvas of the new image
},
Copy the code

5. Download pictures

By calling toDataURL() on the new canvas to return a data URI containing the image display, assign it the new SRC attribute of the image and trigger the click download event to download the image function

// Download the image
downloadImage(image, name) {
    if (!this.image) {
        this.$Modal.error({
            title: 'wrong'.content: 'Please upload pictures first!! '});return;
    }
    var image = new Image();
    var canvas = document.getElementById('new');
    image.src = canvas.toDataURL();
    this.downLoad(image, 'suporka-image-filter.jpg');
},
/ / download
downLoad(image, name) {
    const dataURL = image.src;
    const link = document.createElement('a');
    link.download = name;
    link.href = dataURL;
    link.dispatchEvent(new MouseEvent('click'));
},
Copy the code

Image filter

this.chooseFilter(data, canvasNew, imageData); The image is processed according to different filters. Here are a few image filters:

Gray filter

Set the RGB of the color to the same value to make the picture gray. The general processing methods are as follows:

1. Take the average of the three colors

2. Take the maximum (minimum) value of the three colors

3. Weighted average value: 0.3r + 0.59g + 0.11*B

The first method is used in this paper

for(var i = 0; i < data.length; i+=4) {
     var grey = (data[i] + data[i+1] + data[i+2]) / 3;
     data[i] = data[i+1] = data[i+2] = grey;
}
Copy the code

Black and white filter

As the name implies, is the color of the picture only black and white, can calculate the average VALUE of RGB ARG, ARG >=100, r=g=b=255, otherwise all 0

for(var i = 0; i < data.length; i += 4) {
     var avg = (data[i] + data[i+1] + data[i+2) /3;
     data[i] = data[i+1] = data[i+2] = avg >= 100 ? 255 : 0;
}
Copy the code

Reverse filter

Take the difference of 255 between the RGB three colors.

for(var i = 0; i < data.length; i+= 4) {
      data[i] = 255 - data[i];
      data[i + 1] = 255 - data[i + 1];
      data[i + 2] = 255 - data[i + 2];
}
Copy the code

To color filter

RGB three colors take the average of the maximum values of the three colors.

for(var i = 0; i < data.length; i++) {
   var avg = Math.floor((Math.min(data[i], data[i+1], data[i+2]) + Math.max(data[i], data[i+1], data[i+2) /])2 );
   data[i] = data[i+1] = data[i+2] = avg;
}
Copy the code

Monochromatic filter

Keep only one color and set the other colors to 0

for(var i = 0; i < canvas.height * canvas.width; i++) {
    data[i*4 + 2] = 0;
    data[i*4 + 1] = 0;
}
Copy the code

Newton said, “I am only standing on the shoulders of giants.” For more detailed filters, please step on the shoulders of giants: “Image processing filter algorithm” ( ̄▽ ̄)~*

conclusion

This case is mainly on the canvas CTX. GetImageData, CTX. PutImageData () ‘; And the use of picture data processing to achieve the effect we want. There will be related articles of Canvas series in the future, stay tuned!

More recommended

Advanced_front_end

Daily question

Webpack4 Build Vue application (createVue)

Canvas Advanced (1) Generation of two-dimensional code and scan code recognition

Canvas advanced (2) Write a NPM plug-in to generate a TWO-DIMENSIONAL code with logo

Canvas advanced (3) TS + Canvas rewrite “color discrimination” small game

Canvas advanced (four) to achieve a “scratch-off” game