How to Convert Images to Grayscale with JavaScript and HTML5 Canvas
Grayscale images are composed exclusively of shades of gray. They are commonly stored with 8 bits per sampled pixel, which allows 256 different intensities to be recorded.
Converting an image to grayscale has some usages:
- File size reduction: an 8-bit grayscale image often requires less data for storage than a 24-bit color image.
- Image processing: many image processing algorithms work on grayscale images rather than color images.
- Aesthetics: a monochrome grayscale image can evoke a special feeling which a color image cannot give.
A sample image converted to grayscale:

In this article, we are going to talk about three ways to convert an image to grayscale with JavaScript.
- CSS
- Canvas
- Dynamic Web TWAIN, a document-scanning SDK
What you’ll build: A browser-based tool that converts any image to grayscale using three JavaScript methods — CSS filters, HTML5 Canvas pixel manipulation, and the Dynamic Web TWAIN SDK.
Key Takeaways
- JavaScript offers three practical approaches to grayscale conversion: CSS
filter: grayscale(1)for display-only changes, HTML5 CanvasgetImageData()for pixel-level conversion, and Dynamic Web TWAINConvertToGrayScalefor batch processing with optimized file output. - The Canvas approach uses Rec. 709 luma coefficients (
0.2126 R + 0.7152 G + 0.0722 B) to calculate perceptually accurate gray values, with bit-shifting optimization for performance. - CSS filters affect rendering only — they do not modify actual image data, so you cannot export a CSS-grayscaled image.
- Dynamic Web TWAIN processes images natively, producing smaller output files and supporting high-volume batch conversion in the browser.
Common Developer Questions
- How do I convert an image to grayscale using JavaScript and HTML5 Canvas?
- What is the difference between CSS grayscale filter and Canvas pixel manipulation for image conversion?
- How can I batch convert images to grayscale in a web application?
Prerequisites
- A modern web browser (Chrome, Firefox, Edge, or Safari)
- Basic knowledge of HTML5, CSS, and JavaScript
- Get a 30-day free trial license for Dynamic Web TWAIN if you want to try the SDK-based conversion method
Step 1: Create the HTML5 Grayscale Conversion Page
Create a new HTML5 page with the following template and then let’s add the color conversion function to it.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Convert an Image to Grayscale</title>
<style>
</style>
</head>
<body>
<div class="home">
<h2>Convert an Image to Grayscale</h2>
<button id="convertButton">Convert</button>
</div>
<script>
</script>
</body>
</html>
Step 2: Load an Image File into the Browser
Add an input element for selecting files and use a button element to trigger it. The image file will be loaded into two image elements, one for displaying the converted result and one for storing the original image.
HTML:
<button id="loadFileButton">Load a File</button>
<input style="display:none;" type="file" id="file" onchange="loadImageFromFile();" accept=".jpg,.jpeg,.png,.bmp" />
<div class="imageContainer">
<img id="image"/>
<img id="imageHidden"/>
</div>
<style>
.imageContainer {
max-width: 50%;
}
#image {
max-width: 100%;
}
#imageHidden {
display: none;
}
</style>
JavaScript:
function loadImageFromFile(){
let fileInput = document.getElementById("file");
let files = fileInput.files;
if (files.length == 0) {
return;
}
let file = files[0];
fileReader = new FileReader();
fileReader.onload = function(e){
document.getElementById("image").src = e.target.result;
document.getElementById("imageHidden").src = e.target.result;
};
fileReader.onerror = function () {
console.warn('oops, something went wrong.');
};
fileReader.readAsDataURL(file);
}
Step 3: Display a Grayscale Image with CSS Filters
We can use the CSS property filter to make an HTML element display in grayscale:
document.getElementById("image").style.filter = "grayscale(1)";
It can make any HTML element in grayscale but if we need to save the image in grayscale, we cannot use this approach.
Step 4: Convert Image Pixels to Grayscale with HTML5 Canvas
HTML5 provides a canvas element which provides a way to manipulate image data. Unlike CSS which only changes the visual effect, we can use it to actually get an image converted in grayscale.
-
Add a hidden
canvaselement to the page.<canvas id="canvasHidden"></canvas> <style> #canvasHidden { display: none; } </style> -
Add a
selectelement to select which conversion method to use.<label> Method: <select id="methodSelect"> <option>CSS</option> <option>Canvas</option> </select> </label> -
Convert an image to grayscale with
canvaswhen the selected method is “Canvas”.let method = document.getElementById("methodSelect").selectedIndex; if (method == 0) { convertWithCSS(); }else if (method == 1){ document.getElementById("image").style.filter = ""; convertWithCanvas(); }
Details of converting an image to grayscale with canvas.
-
Set the canvas’s size to match the image’s size.
const image = document.getElementById("image"); const canvas = document.getElementById("canvasHidden"); canvas.width = image.naturalWidth; canvas.height = image.naturalHeight; -
Get the context of the canvas to perform actions.
const context = canvas.getContext("2d"); -
Draw the image onto the canvas.
context.drawImage(image, 0, 0); -
Get the
ImageDataof the image:const imageData = context.getImageData(0, 0, canvas.width, canvas.height);ImageDatastores the pixel values in aUint8ClampedArrayin the RGBA order, with integer values between 0 and 255 (inclusive). The order goes by rows from the top-left pixel to the bottom-right. -
Create a function to get the gray value from the RGB values.
//https://github.com/image-js/image-js/blob/9ab86a86f6c13a9a7d14c62566c1396c3c6f54f4/src/image/transform/greyAlgorithms.js function RGBToGrayScale(red,green,blue){ //return red * 0.2126 + green * 0.7152 + blue * 0.0722; return (red * 6966 + green * 23436 + blue * 2366) >> 15; }There are many ways to calculate the gray value. Here, we use
Rec. 709 luma coefficientsfor the conversion. The calculation speed is optimized using multiplication with integer and bit shifting. -
Iterate all the pixels and set the RGB values as the gray value we calculated.
const pixels = imageData.data; //[r,g,b,a,...] for (var i = 0; i < pixels.length; i += 4) { const red = pixels[i]; const green = pixels[i + 1]; const blue = pixels[i + 2]; const grayscale = RGBToGrayScale(red, green, blue) pixels[i] = grayscale; pixels[i + 1] = grayscale; pixels[i + 2] = grayscale; } -
Put back the
ImageData.context.putImageData(imageData, 0, 0); -
Display the converted image.
document.getElementById("image").src = canvas.toDataURL();
Step 5: Batch Convert Images to Grayscale with Dynamic Web TWAIN
Dynamic Web TWAIN is a document scanning SDK making it possible to scan documents in the browser. It provides various image processing methods. We can use its ConvertToGrayScale method to convert an image to grayscale.
The advantage of using it is that it can be used to batch process a large volume of images as the processing is done using a native process. The output image file also has a smaller size as native image libraries like libpng are used to optimize the size.
Here are the steps to use it:
-
Include Dynamic Web TWAIN in the page.
<script src="https://unpkg.com/dwt@18.4.2/dist/dynamsoft.webtwain.min.js"></script> -
Initialize an instance of Web TWAIN and use it to convert the images. You can apply for its license here.
let DWObject; Dynamsoft.DWT.AutoLoad = false; Dynamsoft.DWT.ProductKey = "LICENSE-KEY"; Dynamsoft.DWT.ResourcesPath = "https://unpkg.com/dwt@18.4.2/dist"; async function convertWithDWT(){ if (!DWObject) { await initDWT(); } DWObject.RemoveAllImages(); let response = await fetch(document.getElementById("imageHidden").src); let buffer = await response.arrayBuffer(); DWObject.LoadImageFromBinary(buffer, function(){ DWObject.ConvertToGrayScale(0, function(){ document.getElementById("image").src = DWObject.GetImageURL(0); }, function(errorCode, errorString){ console.log(errorString); }); }, function(errorCode, errorString){ console.log(errorString); }) } function initDWT(){ return new Promise((resolve, reject) => { const title = document.querySelector("h2").innerText; document.querySelector("h2").innerText = "Loading Dynamic Web TWAIN..."; Dynamsoft.DWT.CreateDWTObjectEx( { WebTwainId: 'dwtcontrol' }, function(obj) { DWObject = obj; document.querySelector("h2").innerText = title; resolve(); }, function(err) { console.log(err); document.querySelector("h2").innerText = "Failed to load Dynamic Web TWAIN"; reject(err); } ); }) }
Common Issues and Edge Cases
- Canvas
getImageData()throws aSecurityErroron cross-origin images. If the image is loaded from a different domain without proper CORS headers, the canvas becomes “tainted” and you cannot read pixel data. Serve images from the same origin or ensure the server sendsAccess-Control-Allow-Originheaders and setcrossOrigin = "anonymous"on the image element. - CSS
filter: grayscale(1)is display-only. The underlying pixel data remains unchanged, so you cannot save or export the grayscale result. Use the Canvas or Dynamic Web TWAIN approach when you need an actual grayscale image file. - Large images may cause performance lag with Canvas pixel manipulation. Iterating every pixel in a high-resolution image (e.g., 4000 × 3000) can block the main thread. Consider using a Web Worker or the Dynamic Web TWAIN native process for large-scale or batch conversions.
Source Code
You can find all the code and an online demo in the following repo: