HTML5: Working with Images and Videos

18 min read

(For more resources on this topic, see here.)

Introduction

This article focuses on yet another very exciting topic of the HTML5 canvas, images and videos. Along with providing basic functionality for positioning, sizing, and cropping images and videos, the HTML5 canvas API also allows us to access and modify the color and transparency of each pixel for both mediums. Let’s get started!

Drawing an image

Let’s jump right in by drawing a simple image. In this recipe, we’ll learn how to load an image and draw it somewhere on the canvas.

How to do it…

Follow these steps to draw an image in the center of the canvas:

  1. Define the canvas context:

    window.onload = function(){
        var canvas = document.getElementById("myCanvas");
        var context = canvas.getContext("2d");

  2. Create an image object, set the onload property to a function that draws the image, and then set the source of the image:

        var imageObj = new Image();
        imageObj.onload = function(){
            var destX = canvas.width / 2 - this.width / 2;
            var destY = canvas.height / 2 - this.height / 2;
           
            context.drawImage(this, destX, destY);
        };
        imageObj.src = "jet_300x214.jpg";
    };

  3. Embed the canvas tag inside the body of the HTML document:

    <canvas id="myCanvas" width="600" height="250" style="border:1px
    solid black;">
    </canvas>

How it works…

To draw an image, we first need to create an image object using new Image(). Notice that we’ve set the onload property of the image object before defining the source of the image.

It’s good practice to define what we want to do with the image when it loads before setting its source. Theoretically, if we were to define the source of the image before we define the onload property; the image could possibly load before the definition is complete (although, it’s very unlikely).

The key method in this recipe is the drawImage() method:

context.drawImage(imageObj,destX,destY);

Where imageObj is the image object, and destX and destY is where we want to position the image.

There’s more…

In addition to defining an image position with destX and destY, we can also add two additional parameters, destWidth and destHeight to define the size of our image:

context.drawImage(imageObj,destX,destY,destWidth,destHeight);

For the most part, it’s a good idea to stay away from resizing an image with the drawImage() method, simply because the quality of the scaled image will be noticeably reduced, similar to the result when we resize an image with the width and height properties of an HTML image element. If image quality is something you’re concerned about (why on earth wouldn’t you be?), it’s usually best to work with thumbnail images alongside bigger images if you’re creating an application that needs scaled images. If, on the other hand, your application dynamically shrinks and expands images, using the drawImage() method with destWidth and destHeight to scale images is a perfectly acceptable approach.

Cropping an image

In this recipe, we’ll crop out a section of an image and then draw the result onto the canvas.

How to do it…

Follow these steps to crop out a section of an image and draw the result onto the canvas.

  1. Define the canvas context:

    window.onload = function(){
        var canvas = document.getElementById("myCanvas");
        var context = canvas.getContext("2d");

  2. Create an image object, set the onload property to a function that crops the image, and then set the source of the image:

        var imageObj = new Image();
        imageObj.onload = function(){
        // source rectangular area
            var sourceX = 550;
            var sourceY = 300;
            var sourceWidth = 300;
            var sourceHeight = 214;
           
        // destination image size and position
            var destWidth = sourceWidth;
            var destHeight = sourceHeight;
            var destX = canvas.width / 2 - destWidth / 2;
            var destY = canvas.height / 2 - destHeight / 2;
           
            context.drawImage(this, sourceX, sourceY, sourceWidth,
    sourceHeight, destX, destY, destWidth, destHeight);
        };
        imageObj.src = "jet_1000x714.jpg";
    };

  3. Embed the canvas tag inside the body of the HTML document:

    <canvas id="myCanvas" width="600" height="250" style="border:1px
    solid black;">
    </canvas>

How it works…

In the last recipe, we discussed two different ways that we can use the drawImage() method to draw images on the canvas. In the first case, we can pass an image object and a position to simply draw an image at the given position. In the second case, we can pass an image object, a position, and a size to draw an image at the given position with the given size. Additionally, we can also add six more parameters to the drawImage() method if we wanted to crop an image:

Context.drawImage(imageObj,sourceX,sourceY,sourceWidth, sourceHight, sourceHeight,
sourceHeight, destX, destY, destWidth, destHeight);

Take a look at the following diagram:

As you can see, sourceX and sourceY refer to the top-left corner of the cropped region in the source image. sourceWidth and sourceHeight refer to the width and height of the cropped image from the source. destX and destY refer to the position of the cropped image on the canvas, and destWidth and destHeight refer to the width and height of the resulting cropped image.

If you don’t intend to scale a cropped image, then destWidth equals sourceWidth and destHeight equals sourceHeight.

Copying and pasting sections of the canvas

In this recipe, we’ll cover yet another interesting usage of the drawImage() method—copying sections of the canvas. First, we’ll draw a spade in the center of the canvas, then we’ll copy the right side of the spade and then paste it to the left, and then we’ll copy the left side of the spade and then paste it to the right.

How to do it…

Follow these steps to draw a spade in the center of the canvas and then copy-and-paste sections of the shape back onto the canvas:

  1. Define the canvas context:

    window.onload = function(){
        // drawing canvas and context
        var canvas = document.getElementById("myCanvas");
        var context = canvas.getContext("2d");

  2. Draw a spade in the center of the canvas using the drawSpade() function:

        // draw spade
        var spadeX = canvas.width / 2;
        var spadeY = 20;
        var spadeWidth = 140;
        var spadeHeight = 200;
       
        // draw spade in center of canvas
        drawSpade(context, spadeX, spadeY, spadeWidth, spadeHeight);

  3. Copy the right half of the spade and then paste it on the canvas to the left of the spade using the drawImage() method:

        context.drawImage(
        canvas,        
        spadeX,         // source x
        spadeY,         // source y
        spadeWidth / 2,     // source width
        spadeHeight,       // source height
        spadeX - spadeWidth,  // dest x
        spadeY,         // dest y
        spadeWidth / 2,     // dest width
        spadeHeight        // dest height
      );

  4. Copy the left half of the spade and then paste it on the canvas to the right of the spade using the drawImage() method:

        context.drawImage(
        canvas,
        spadeX - spadeWidth / 2,  // source x  
        spadeY,           // source y
        spadeWidth / 2,       // source width
        spadeHeight,         // source height
        spadeX + spadeWidth / 2,   // dest x
        spadeY,           // dest y
        spadeWidth / 2,       // dest width
        spadeHeight          // dest height
      );
    };

  5. Embed the canvas inside the body of the HTML document:

    <canvas id="myCanvas" width="600" height="250" style="border:1px
    solid black;">
    </canvas>

How it works…

To copy a section of the canvas, we can pass the canvas object to the drawImage() method instead of an image object:

Context.drawImage(canvas,sourceX,sourceY,sourceWidth, sourceHight,
sourceHeight,sourceHeight, destX, destY, destWidth, destHeight);

As we’ll see in the next recipe, not only can we copy sections of an image or a canvas with drawImage(), we can also copy sections of HTML5 video.

Working with video

Although the HTML5 canvas API doesn’t provide a direct method for drawing videos on the canvas like it does for images, we can certainly work with videos by capturing frames from a hidden video tag and then copying them onto the canvas with a loop.

Getting ready…

Before we get started, let’s talk about the supported HTML5 video formats for each browser. At the time of writing, the video format war continues to rage on, in which all of the major browsers—Chrome, Firefox, Opera, Safari, and IE—continue to drop and add support for different video formats. To make things worse, each time a major browser adds or drops support for a particular video format, developers have to once again re-formulate the minimal set of video formats that’s required for their applications to work across all browsers. At the time of writing, the three major video formats are Ogg Theora, H.264, and WebM.
For the video recipes in this article, we’ll be using a combination of Ogg Theora and H.264. When working with video, it’s strongly advised that you do a search online to see what the current status is for video support as it is a subject to change at any moment.
There’s more! Once you’ve decided which video formats to support, you’ll probably need a video format converter to convert the video file that you have on hand to other video formats. One great option for converting video formats is the Miro Video Converter, which supports video format conversions for just about any video format including Ogg Theora, H.264, or WebM formats.
Miro Video Converter is probably the most common video converter available at the time of writing, although you can certainly use any other video format converter of your liking. You can download Miro Video Converter from: http://www.mirovideoconverter.com/.

How to do it…

Follow these steps to draw a video onto the canvas:

  1. Create a cross-browser method that requests an animation frame:

    window.requestAnimFrame = (function(callback){
        return window.requestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.oRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        function(callback){
            window.setTimeout(callback, 1000 / 60);
        };
    })();

  2. Define the drawFrame() function which copies the current video frame, pastes it onto the canvas using the drawImage() method, and then requests a new animation frame to draw the next frame:

    function drawFrame(context, video){
        context.drawImage(video, 0, 0);
        requestAnimFrame(function(){
            drawFrame(context, video);
        });
    }

  3. Define the canvas context, get the video tag, and draw the first video frame:

    window.onload = function(){
        var canvas = document.getElementById("myCanvas");
        var context = canvas.getContext("2d");
        var video = document.getElementById("myVideo");
        drawFrame(context, video);
    };

  4. Embed the canvas and the video tag inside the body of the HTML document:

    <video id="myVideo" autoplay="true" loop="true"
    style="display:none;">
        <source src="BigBuckBunny_640x360.ogv"
    type="video/ogg"/><source src="BigBuckBunny_640x360.mp4"
    type="video/mp4"/>
    </video>
    <canvas id="myCanvas" width="600" height="360" style="border:1px
    solid black;">
    </canvas>

How it works…

To draw a video on an HTML5 canvas, we first need to embed a hidden video tag in the HTML document. In this recipe, and in future video recipes, I’ve used the Ogg Theora and H.264 (mp4) video formats.
Next, when the page loads, we can use our cross-browser requestAnimFrame() method to capture the video frames as fast as the browser will allow and then draw them onto the canvas.

Getting image data

Now that we know how to draw images and videos, let’s try accessing the image data to see what kind of properties we can play with.

WARNING: This recipe must run on a web server due to security constraints with the getImageData() method.

Getting ready…

Before we get started working with image data, it’s important that we cover canvas security and the RGBA color space.
So why is canvas security important with respect to accessing image data? Simply put, in order to access image data, we need to use the getImateData() method of the canvas context which will throw a SECURITY_ERR exception if we try accessing image data from an image residing on a non-web server file system, or if we try accessing image data from an image on a different domain. In other words, if you’re going to try out these demos for yourself, they won’t work if your files reside on your local file system. You’ll need to run the rest of the recipes in this article on a web server.
Next, since pixel manipulation is all about altering the RGB values of pixels, we should probably cover the RGB color model and the RGBA color space while we’re at it. RGB represents the red, green, and blue components of a pixel’s color. Each component is an integer between 0 and 255, where 0 represents no color and 255 represents full color. RGB values are often times represented as follows:

rgb(red,green,blue)

Here are some common color values represented with the RGB color model:

rgb(0,0,0) = black
rgb(255,255,255) = white
rgb(255,0,0) = red
rgb(0,255,0) = green
rgb(0,0,255) = blue
rgb(255,255,0) = yellow
rgb(255,0,255) = magenta
rgb(0,255,255) = cyan

In addition to RGB, pixels can also have an alpha channel which refers to its opacity. An alpha channel of 0 is a fully transparent pixel, and an alpha channel of 255 is a fully opaque pixel. RGBA color space simply refers to the RGB color model (RGB) plus the alpha channel (A).

Be careful not to confuse the alpha channel range of HTML5 canvas pixels, which are integers 0 to 255, and the alpha channel range of CSS colors, which are decimals 0.0 to 1.0.

How to do it…

Follow these steps to write out the image data properties of an image:

  1. Define a canvas context:

    window.onload = function(){
        var canvas = document.getElementById("myCanvas");
        var context = canvas.getContext("2d");

  2. Create an image object, set the onload property to a function which draws the image:

        var imageObj = new Image();
        imageObj.onload = function(){
            var sourceWidth = this.width;
            var sourceHeight = this.height;
            var destX = canvas.width / 2 - sourceWidth / 2;
            var destY = canvas.height / 2 - sourceHeight / 2;
            var sourceX = destX;
            var sourceY = destY;
           
        // draw image on canvas
            context.drawImage(this, destX, destY);

  3. Get the image data, write out its properties, and then set the source of the image object outside of the onload definition:

        // get image data from the rectangular area
        // iof the canvas containing the image
            var imageData = context.getImageData(sourceX, sourceY,
    sourceWidth, sourceHeight);
            var data = imageData.data;
       
        // write out the image data properties
            var str = "width=" + imageData.width + ", height=" +
    imageData.height + ", data length=" + data.length;
            context.font = "12pt Calibri";
            context.fillText(str, 4, 14);
        };
        imageObj.src = "jet_300x214.jpg";
    };

  4. Embed the canvas tag into the body of the HTML document:

    <canvas id="myCanvas" width="600" height="250" style="border:1px
    solid black;">
    </canvas>

How it works…

The idea behind this recipe is to draw an image, get its image data, and then write out the image data properties to the screen. As you can see from the preceding code, we can get the image data using the getImageData() method of the canvas context:

context.getImageData(sourceX,sourceY,sourceWidth,sourceHeight);

Notice that the getImageData() method only works with the canvas context and not the image object itself. As a result, in order to get image data, we must first draw an image onto the canvas and then use getImageData() method of the canvas context.
The ImageData object contains three properties: width, height, and data. As you can see from the screenshot in the beginning of this recipe, our ImageData object contains a width property of 300, a height property of 214, and a data property which is an array of pixel information, which in this case has a length of 256,800 elements. The key to the ImageData object, in all honesty, is the data property. The data property contains the RGBA information for each pixel in our image. Since our image is made up of 300 * 214 = 64,200 pixels, the length of this array is 4 * 64,200 = 256,800 elements.

Introduction to pixel manipulation: inverting image colors

Now that we know how to access image data, including the RGBA for every pixel in an image or video, our next step is to explore the possibilities of pixel manipulation. In this recipe, we’ll invert the colors of an image by inverting the color of each pixel.

WARNING: This recipe must be run on a web server due to security constraints with the getImageData() method.

How to do it…

Follow these steps to invert the colors of an image:

  1. Define the canvas context:

    window.onload = function(){
        var canvas = document.getElementById("myCanvas");
        var context = canvas.getContext("2d");

  2. Create an image object and set the onload property to a function that draws the image and gets the image data:

        var imageObj = new Image();
        imageObj.onload = function(){
            var sourceWidth = this.width;
            var sourceHeight = this.height;
            var sourceX = canvas.width / 2 - sourceWidth / 2;
            var sourceY = canvas.height / 2 - sourceHeight / 2;
            var destX = sourceX;
            var destY = sourceY;
           
            context.drawImage(this, destX, destY);
           
            var imageData = context.getImageData(sourceX, sourceY,
    sourceWidth, sourceHeight);
            var data = imageData.data;

  3. Loop through all of the pixels in the image and invert the colors:

            for (var i = 0; i < data.length; i += 4) {
                data[i] = 255 - data[i]; // red
                data[i + 1] = 255 - data[i + 1]; // green
                data[i + 2] = 255 - data[i + 2]; // blue
                // i+3 is alpha (the fourth element)
            }

  4. Overwrite the original image with the manipulated image, and then set the source of the image outside of the onload definition:

            // overwrite original image with
            // new image data
            context.putImageData(imageData, destX, destY);
        };
        imageObj.src = "jet_300x214.jpg";
    };

  5. Embed the canvas tag into the body of the HTML document:

    <canvas id="myCanvas" width="600" height="250" style="border:1px
    solid black;">
    </canvas>

How it works…

To invert the color of an image using HTML5 canvas, we can simply loop through all of the pixels in an image and then invert each pixel using a color inverting algorithm. Don’t worry it’s easier than it sounds. To invert a pixel’s color, we can invert each of its RGB components by subtracting each value from 255 as follows:

data[i  ] = 255 - data[i  ]; // red
data[i+1] = 255 - data[i+1]; // green
data[i+2] = 255 - data[i+2]; // blue

Once the pixels have been updated, we can redraw the image using the putImageData() method of the canvas context:

context.putImageData(imageData, destX, destY); 

This method basically allows us to draw an image using image data instead of a source image with the drawImage() method.

Packt

Share
Published by
Packt

Recent Posts

Top life hacks for prepping for your IT certification exam

I remember deciding to pursue my first IT certification, the CompTIA A+. I had signed…

3 years ago

Learn Transformers for Natural Language Processing with Denis Rothman

Key takeaways The transformer architecture has proved to be revolutionary in outperforming the classical RNN…

3 years ago

Learning Essential Linux Commands for Navigating the Shell Effectively

Once we learn how to deploy an Ubuntu server, how to manage users, and how…

3 years ago

Clean Coding in Python with Mariano Anaya

Key-takeaways:   Clean code isn’t just a nice thing to have or a luxury in software projects; it's a necessity. If we…

3 years ago

Exploring Forms in Angular – types, benefits and differences   

While developing a web application, or setting dynamic pages and meta tags we need to deal with…

3 years ago

Gain Practical Expertise with the Latest Edition of Software Architecture with C# 9 and .NET 5

Software architecture is one of the most discussed topics in the software industry today, and…

3 years ago