Pixels

It is possible to read and write to individual pixels on a canvas.

The getImageData() function allows us to read rectangular areas from a canvas.

imageData = ctx.getImageData(x, y, width, height);      

 

Example of reading and writting pixels on a canvas (Run Example).

<!-- Author: Derek O Reilly, Dundalk Institute of Technology, Ireland. -->

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>GENIUS worked example</title>
        <style>
            #gameCanvas
            {
                /* the canvas styling usually does not change */
                outline:1px solid darkgrey;
                width:500px;
                height:500px;
            }
        </style>
    </head>

    <body>
        <canvas id = "gameCanvas"></canvas>

        <script>
            let img = new Image(); // note that the offscreen image must be declared OUTSIDE of the window.onload() function 
            img.src = "images/city.png";

            window.onload = function ()
            {
                let canvas = document.getElementById("gameCanvas");
                canvas.width = canvas.clientWidth;
                canvas.height = canvas.clientHeight;
                let ctx = canvas.getContext("2d");

                // draw an image on the canvas
                ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
                
                // get the pixels from the canvas
                // NOTE: getImageData() will only work if the image in drawImage is 
                // on the same server as the webpage

                let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
                let data = imageData.data;

                const RED = 0;
                const GREEN = 1;
                const BLUE = 2;
                const ALPHA = 3;

                for (let i = 0; i < data.length; i += 4)
                {
                    data[i + RED] = 255 - data[i + 0];
                    data[i + GREEN] = 255 - data[i + 1];
                    data[i + BLUE] = 255 - data[i + 2];
                    data[i + ALPHA] = 255;
                }

                ctx.putImageData(imageData, 0, 0);
            };
        </script>
    </body>
</html>
                let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
                let data = imageData.data;

The above two lines of code above copy the selected pixels into a one-dimensional array.

                const RED = 0;
                const GREEN = 1;
                const BLUE = 2;
                const ALPHA = 3;

                for (let i = 0; i < data.length; i += 4)
                {
                    data[i + RED] = 255 - data[i + 0];
                    data[i + GREEN] = 255 - data[i + 1];
                    data[i + BLUE] = 255 - data[i + 2];
                    data[i + ALPHA] = 255;
                }

The for-loop above steps through each of the selected pixels. Each pixel has a red, green, blue and alpha value, each of which is in the range 0-255.

ctx.putImageData(imageData, 0, 0);

The putImageData() function allows us to write the selected pixels on the canvas.

Write code to place coloured text on a grayscale image, as shown here.

Read/Write part of a canvas

The getImageData() and putImageData() functions allow us to read/write onto any rectangular area of a canvas, as shown here.

<!-- Author: Derek O Reilly, Dundalk Institute of Technology, Ireland. -->

<!doctype html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>GENIUS worked example</title>
        <style>
            #gameCanvas
            {
                /* the canvas styling usually does not change */
                outline:1px solid darkgrey;
                width:500px;
                height:500px;
            }
        </style>
    </head>

    <body>
        <canvas id = "gameCanvas"></canvas>

        <script>
            let image = new Image();
            image.src = "images/city.png";

            window.onload = function ()
            {
                let canvas = document.getElementById("gameCanvas");
                canvas.width = canvas.clientWidth;
                canvas.height = canvas.clientHeight;
                let ctx = canvas.getContext("2d");

                ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
                
                // get the pixels from the canvas
                // NOTE: getImageData() will only work if the image in drawImage is 
                // on the same server as the webpage
                let imageData = ctx.getImageData(canvas.width / 3, 0, canvas.width / 3, canvas.height); // x,y position and regtangle width and height
                let data = imageData.data;

                const RED = 0;
                const GREEN = 1;
                const BLUE = 2;
                const ALPHA = 3;
                
                // Manipulate the pixel data
                for (let i = 0; i < data.length; i += 4)
                {
                    imageData.data[i + RED] = 255 - imageData.data[i + RED];
                    imageData.data[i + GREEN] = 255 - imageData.data[i + GREEN];
                    imageData.data[i + BLUE] = 255 - imageData.data[i + BLUE];
                    imageData.data[i + ALPHA] = 255;
                }

                ctx.putImageData(imageData, canvas.width / 3, 0);
            };
        </script>
    </body>
</html>
imageData = ctx.getImageData(canvas.width / 3, 0, canvas.width / 3, canvas.height); // x,y position and regtangle width and height

The code above shows that we only manipulate the middle one-third of the canvas.

Write code to display a greyscaled image with a coloured border, as shown here.

Accessing One Pixel

We can read/write any single canvas pixel by selecting a rectangle of size 1 pixel. The code below reads a single pixel.

let imageData = someOffscreenCanvas.getImageData(x, y, 1, 1); 
let data = imageData.data;

if (data[ALPHA] !== 0)
{
    // This pixel is not transparent
}

We can use an offscreen canvas to test the mouse pointer against the transparent and non-transparent parts of an image. This is especially useful for accurate collision detection. We shall look at this in more detail later.