Using Canvas to Change Photo Colors
This topic explains how to use HTML5 Canvas to change one or more colors in a photograph, which creates dramatic images to enhance webpage designs.
- Canvas Cross-Domain Security Issues
- Canvas Code Sample
- Canvas Code Sample Discussion
- Body Code
- Script Code
- displayImage Function
- getColorData Function
- putColorData Function
- noPhoto Function
- Code Requirements
- Related topics
This topic includes a stand-alone annotated code sample that shows how to change a multicolor photo of an American kestral falcon into a photo composed of blue and green only. The code sample demonstrates how to use Canvas to load the falcon photograph into a webpage and display it on the screen. Then it shows how to remove the red values from each pixel, leaving only the blue and green values. This sample removes one color (red) from a photograph, but you can also remove two colors, or even modify the amount you remove. For example, you can lower the red values to 50% to get a unique color palette. The discussion material at the end of this sample explains more about how the code works to develop this technique. It also includes information about how Canvas assigns color values to pixels. For more information, see the getColorData function discussion.
Canvas Cross-Domain Security Issues
The Using Canvas to Make Photos into Shapes and the Using Canvas to Add Texture to Photos topics show you how to create photographic special effects by reading and writing pixels to the Canvas. The special effects technique covered in this topic uses the getImageData method to read pixels directly from an image. This method has an important security requirement that does not apply to the previous two topics. This security requirement stops a Canvas program from copying pixels from one computer domain to another and is necessary to prevent Internet forgery.
In order to comply with this security requirement, you can only read pixels from an image that is in the same domain as the code sample in this topic. To run the code sample, place a photo named Kestral.png in the same folder as the html code you are running. This puts the image in the same domain as the program, making it possible to run the program. If your original image is on another domain and you attempt to read pixels using the getImageData or toDataURL methods, your program might stop responding and cause an error. However, if your image is on a server or in the cloud, and your code is on the same domain as the image, getImageData or toDataURL reads the pixels without a problem. For more information about these security issues, see the documentation for getImageData and toDataURL.
Canvas Code Sample
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
//Global variables
var picWidth = 200; // width of the canvas
var picHeight = 200; // height of the canvas
var picLength = picWidth * picHeight; // number of chunks
var myImage = new Image(); // Create a new blank image.
// Load the image and display it.
function displayImage() {
// Get the canvas element.
canvas = document.getElementById("myCanvas");
// Make sure you got it.
if (canvas.getContext) {
// Specify 2d canvas type.
ctx = canvas.getContext("2d");
// When the image is loaded, draw it.
myImage.onload = function() {
// Load the image into the context.
ctx.drawImage(myImage, 0, 0);
// Get and modify the image data.
getColorData();
// Put the modified image back on the canvas.
putColorData();
}
// Define the source of the image.
// This file must be on your machine in the same folder as this web page.
myImage.src = "kestral.png";
}
}
function getColorData() {
myImage = ctx.getImageData(0, 0, 200, 200);
// Loop through data.
for (var i = 0; i < picLength * 4; i += 4) {
// First bytes are red bytes.
// Remove all red.
myImage.data[i] = 0;
// Second bytes are green bytes.
// Third bytes are blue bytes.
// Fourth bytes are alpha bytes
}
}
function putColorData() {
ctx.putImageData(myImage, 0, 0);
}
function noPhoto() {
alert("Please put a .png file in this folder and name it kestral.png.");
}
</script>
</head>
<body onload="displayImage()">
<h1>
American Kestral
</h1>
<p>
The original image is on the left and the modified image is on the right.
</p>
<img id="myPhoto" src="kestral.png" onerror="noPhoto()">
<canvas id="myCanvas" width="200" height="200">
</canvas>
<p>
Public domain image courtesy of U.S. Fish and Wildlife Service.
</p>
</body>
</html>
Canvas Code Sample Discussion
This discussion explains the design and structure of this Canvas code sample and how all the parts work together. The sample uses a standard HTML5 header, <!doctype html>, so that browsers can distinguish it as part of the HTML5 specification. This code is divided into two major parts:
- Body Code
- Script Code
Body Code
The body tag uses the onload function to call the displayImage function when the page is loaded. An original image of a kestral is loaded into the body so you can compare it to the one that will be modified by Canvas. The onerror event is added to the img element to determine if the image is loaded. The canvas element is part of the body. The initial width and height of the Canvas is specified, as is the id attribute. The ID is required so that the canvas element can be added to the object model of the page.
Script Code
The script code includes four functions: displayImage, getColorData, putColorData, and noPhoto. The displayImage function is called when the page is loaded. The getColorData and putColorData functions are called from displayImage. The noPhoto function is called if there is an error when the photo is loaded. Global variables are created at the beginning of the script section of the code to create an empty image file, which will be used later, as well as variables that define the height and width of the canvas. In addition, the length of the image array is calculated, determining the number of 4-byte values in the array.
displayImage Function
This function is called on page load. It gets the canvas by using the ID of the canvas element in the body code. It then gets the CanvasRenderingContext2D Object of the canvas, making it ready to accept drawing and uses DrawImage to load the image into the context. After the context is initialized as a 2D canvas, the canvas is ready to be drawn on.
The last thing the function does is to specify the source of the image by supplying a path. Because images might not load instantly, an event is set up that will call a function when the image actually gets loaded. After the image is loaded, it is displayed, and a call is made to the getColorData and putColorData functions, which will complete the drawing work.
Unlike the first two topics in this tutorial, you must place the kestral image on your own computer. You cannot call it from another domain. If the pixels on the canvas are from another domain, the image is considered a security threat, and you cannot modify it. For more information about cross-domain security threats, see the canvas documentation. Any file named "kestral.png" will work. If you want to use the original kestral image, right-click the left image of the kestral in the first topic of this scenario and click Save picture as ... and save it to your machine, placing it in the same folder as your webpage.
getColorData Function
The image is copied with getImageData to myImage and processed by moving through the image data array and modifying the red bytes, changing them to 0 (zero). The array is 200 x 200 pixels, making it 40,000 cells. Each cell is 4 bytes, making the array a total of 160,000 bytes. The program goes through a loop 160,000 times, reading 4 bytes at a time. Each time it changes the first byte by making it 0 (zero). The result is that all the red has been removed, but the green and blue bytes are still the same.
In order to read or write colored pixels on the screen, each pixel must be assigned a color value. This value consists of four parts: red, green, blue, and alpha. For example, a white pixel is made up of 100% red, 100% green, 100% blue, and 100% alpha. (Alpha refers to the amount of transparency a color displays.) Each canvas pixel color value is stored as a four byte array, and all the pixels in the canvas are stored in one array, starting at the top left and running down to the bottom right. The array size is calculated by the height times the width of the canvas, and each array value is 4 bytes long.
The four bytes correspond to the percent of red, green, blue, and alpha in each pixel. (Bytes range from 0 to 255 for decimal numbers and from #0 to #FF in hexadecimal.) The code in this sample shows you how Canvas uses immediate mode to write color pixel to the screen.
putColorData Function
This function simply writes the changed image data back to the canvas using putImageData. It is often useful to have a second image to do the actual processing and display the result only when the processing is finished.
noPhoto Function
This function is called if the img element is not able to load a file called Kestral.png. An alert appears, telling the reader that the correct file is not loaded.
Code Requirements
This code runs in Windows Internet Explorer 9. It does not work in earlier versions of Windows Internet Explorer, but might run in other browsers that support HTML5 Canvas.