Canvas series starting at 0

Canvas series 1 – Canvas canvas

Canvas series 2 – Text and images from 0

Canvas series 3 – pixel level manipulation of images from 0

Canvas series 4 – Motion animation drawing from 0

Canvas series 5 – Animation from 0

Canvas Series 6 from 0 – Composition and clipping

Starting from 0, the final chapter of Canvas series — create cool particle effects

Image pixel level manipulation

ImageData object

As we all know, pictures are composed of many pixels. Canvas operates on images based on pixels, and all pixel information can be stored in imageData instance

The ImageData() constructor returns a newly instantiated ImageData object consisting of the given typed array and the specified width and height

new ImageData([array], width, height);

/* array contains a Uint8ClampedArray array of image hiding pixels. If the array is not given, a black rectangular image of the specified size will be created. Width An unsigned long value describing the width of the image. Height An unsigned long value describing the height of an image. * /
Copy the code

Uint8ClampedArray

Uint8ClampedArray** a typed array represents an array of 8-bit unsigned integers whose values are fixed between 0 and 255, with the following properties

  • If you specify a value outside the range [0,255], it will be replaced with 0 or 255;

  • If you specify a non-integer, it will be set to the nearest integer.

  • The contents are initialized to 0

To get a deeper understanding of the Uint8ClampedArray let’s see what’s in the imageData instance where width/height =1 (1 pixel)

You can see the 4 digits of Uint8ClampedArray, which store the RGBA attribute value of each pixel of the image, which can be obtained through imagedata.data

Pixel operations

Pixel acquisition (getImageData)

  • getImageData
ctx.getImageData(x, y, w, h);

/* x The upper-left x-coordinate of the rectangular region of the image data to be extracted. Y The upper-left y-coordinate of the rectangular region of the image data to be extracted. W The width of the rectangular region of image data to be extracted. H The height of the rectangular region of the image data to be extracted. * /
Copy the code

Pixel Restore image (putImageData)

  • putImageData
ctx.putImageData(imagedata, 
                 dx, dy, // Image position relative to origin
                 X, Y, // Clipping the starting coordinates
                 W, H// Crop the size
                );
Copy the code

The schematic diagram is as follows:

    const canvas=document.getElementById('canvas');
    // Canvas fills the window
    canvas.width=window.innerWidth;
    canvas.height=window.innerHeight;
    const ctx=canvas.getContext('2d');

    const img=new Image();
    img.src='./images/dog.jpg';
    img.onload=function(){
        // Get the image width and height
        const {width,height}=img;

        /*1. Draw an image on canvas */
        ctx.drawImage(img,0.0);

        /*2. Get the image's ImageData*/ from the canvas
        const imgDt=ctx.getImageData(0.0,width,height);

        console.log(imgDt)
        /*3. Display ImageData*/ in canvas
        ctx.putImageData(
            imgDt,
            // Image position
            0,height,
            // Clipping area
            width/2,height/2,width/2,height/2
        );
    };
Copy the code

Pixel processing

What if we want to process for individual pixels, remember that the Uint8ClampedArray array has RGBA information that we can use to traverse pixels

  • Traverse pixel by pixel

    for(let i=0; i<arr.length; i+=4) {let r=data[i+0];
            let g=data[i+1];
            let b=data[i+2];
            let a=data[i+3];
            console.log(r,g,b,a)
    }
    Copy the code
  • The ranks of traverse

    for(let y=0; y<h; y++){for(let x=0; x<w; x++){let ind=(y*w+x)*4;
            let r=data[ind];
            let g=data[ind+1];
            let b=data[ind+2];
            let a=data[ind+3];
            console.log(r,g,b,a)
        }
    }
    Copy the code

Image gray

Const lm =0.299r + 0.587g + 0.114*b;

    const canvas=document.getElementById('canvas');
    // Canvas fills the window
    canvas.width=window.innerWidth;
    canvas.height=window.innerHeight;
    const ctx=canvas.getContext('2d');

    const img=new Image();
    img.src='./images/lena.jpg';
    img.onload=draw;

    /* Grayscale algorithm: 0.299*r+0.587*g+0.114*b */

    function draw(){
        // Image size
        const {width,height}=img;
        console.log("draw -> width,height", width,height)

        /*1. Draw an image on canvas */
        ctx.drawImage(img,0.0);

        /*2. Get the image's ImageData*/ from the canvas
        const imgDt=ctx.getImageData(0.0,width,height);
        const data=imgDt.data;

        /* Pixel traversal */
        for(let i=0; i<data.length; i+=4) {const [r,g,b]=[
                data[i],
                data[i+1],
                data[i+2]]const lm=0.299*r+0.587*g+0.114*b;
            data[i]=lm;
            data[i+1]=lm;
            data[i+2]=lm;
        }

        /*3. Display ImageData*/ in canvas
        ctx.putImageData(imgDt,width,0);

    }
Copy the code

Mosaic

Main point: Get the pixel color of an area and assign the color to all pixels in that area.

    const canvas=document.getElementById('canvas');
    // Canvas fills the window
    canvas.width=window.innerWidth;
    canvas.height=window.innerHeight;
    const ctx=canvas.getContext('2d');

    / / the source image
    const img=new Image();
    img.src='./images/lena.jpg';
    img.onload=render;

    // Color block size
    let size=5;

    function render() {
        // Image size
        const {width,height}=img;

        /*1. Draw an image on canvas */
        ctx.drawImage(img,0.0);

        /*2. Get the image's ImageData*/ from the canvas
        const imgDt=ctx.getImageData(0.0,width,height);
        const data=imgDt.data;

        /* Row traversal */
        for(let y=0; y<height; y+=size){for(let x=0; x<width; x+=size){const i=(y*width+x)*4;
                const [r,g,b]=[
                    data[i],
                    data[i+1],
                    data[i+2],
                ]
                ctx.fillStyle=`RGB(${r}.${g}.${b}) `; ctx.fillRect(x,y,size,size); }}}Copy the code

【 Supplement 】 Canvas transformation

Rotate and CTX. Transform are similar to cSS3’s transform. The changes of canvas are much less complex than those of CSS3

  • Mobile: translate (x, y)

  • Rotation: rotate (Angle)

  • Zoom: scale (x, y)

All three properties are relative to the origin coordinates

translate(x,y) rotate(angle) scale(x,y)

Note: the state before the transformation must be saved, and the state before the transformation should be restored after the transformation. This operation is just like the layer in PS, which exists independently in the transformation operation

Take a look at the following example, if it’s a little bit interesting

canvas.width = 500;
canvas.height = 500;
const ctx = canvas.getContext('2d');


ctx.fillStyle = 'green';
ctx.fillRect(50.50.100.100);

ctx.fillStyle = 'blue';
// ctx.save() // what difference does it make
ctx.translate(100.100);
ctx.fillRect(50.50.100.100);
// ctx.restore() // What difference does it make

ctx.fillStyle = 'blue';
// ctx.save() // what difference does it make
ctx.translate(100.200);
ctx.fillRect(50.50.100.100);
// ctx.restore() // What difference does it make
Copy the code
Ctx.save () and ctx.restore() are not added either time Ctx.save () and ctx.restore() are added both times