(For more resources on this topic, see here.)
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!
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.
Follow these steps to draw an image in the center of the canvas:
window.onload = function(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
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";
};
<canvas id="myCanvas" width="600" height="250" style="border:1px
solid black;">
</canvas>
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.
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.
In this recipe, we’ll crop out a section of an image and then draw the result onto the canvas.
Follow these steps to crop out a section of an image and draw the result onto the canvas.
window.onload = function(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
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";
};
<canvas id="myCanvas" width="600" height="250" style="border:1px
solid black;">
</canvas>
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.
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.
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:
window.onload = function(){
// drawing canvas and context
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
// 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);
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
);
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
);
};
<canvas id="myCanvas" width="600" height="250" style="border:1px
solid black;">
</canvas>
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.
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.
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/.
Follow these steps to draw a video onto the canvas:
window.requestAnimFrame = (function(callback){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback){
window.setTimeout(callback, 1000 / 60);
};
})();
function drawFrame(context, video){
context.drawImage(video, 0, 0);
requestAnimFrame(function(){
drawFrame(context, video);
});
}
window.onload = function(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var video = document.getElementById("myVideo");
drawFrame(context, video);
};
<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>
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.
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.
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.
Follow these steps to write out the image data properties of an image:
window.onload = function(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
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);
// 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";
};
<canvas id="myCanvas" width="600" height="250" style="border:1px
solid black;">
</canvas>
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.
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.
Follow these steps to invert the colors of an image:
window.onload = function(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
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;
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)
}
// overwrite original image with
// new image data
context.putImageData(imageData, destX, destY);
};
imageObj.src = "jet_300x214.jpg";
};
<canvas id="myCanvas" width="600" height="250" style="border:1px
solid black;">
</canvas>
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.
I remember deciding to pursue my first IT certification, the CompTIA A+. I had signed…
Key takeaways The transformer architecture has proved to be revolutionary in outperforming the classical RNN…
Once we learn how to deploy an Ubuntu server, how to manage users, and how…
Key-takeaways: Clean code isn’t just a nice thing to have or a luxury in software projects; it's a necessity. If we…
While developing a web application, or setting dynamic pages and meta tags we need to deal with…
Software architecture is one of the most discussed topics in the software industry today, and…