22

How do you convert a color image to black/white using only Javascript?

AND, also make it cross compatible in most browsers because I hear Internet Explorer has a "filter" mechanism but no other browsers support it.

andynormancx
  • 13,421
  • 6
  • 36
  • 52

11 Answers11

16

Despite my initial scepticism it appears that such magic is indeed possible, using the new Canvas functionality in some browsers.

This page shows how to do it using browsers that support Canvas:

http://www.permadi.com/tutorial/jsCanvasGrayscale/index.html

For IE you need to use filters, there is an example of doing greyscale here:

http://www.javascriptkit.com/filters/basicimage.shtml

andynormancx
  • 13,421
  • 6
  • 36
  • 52
  • I am impressed, and I think this is the closest you'll get to a pure client-side solution. – James Socol Feb 18 '09 at 18:29
  • Unfortunately the permadi.com script does not work for cross-domain images (at least with Chrome 12) see http://stackoverflow.com/questions/6066365/javascript-grayscale-script-for-images-hosted-in-the-cloud – Ian Hunter Jul 21 '11 at 23:25
8

The way I would do it is to set the src of the img to point to a server-side PHP script

eg.,

<img src="http://mysite/grayscale.php?url='...'

That script fetches the image, runs some GD code, and returns a JPG. Something like this

Scott Evernden
  • 39,136
  • 15
  • 78
  • 84
8

This jquery plugin seems to work cross browser. I haven't tested it thouroughly though.

https://github.com/GianlucaGuarini/jQuery.BlackAndWhite

K B
  • 81
  • 2
  • 4
7

Using HTML5 Canvas and JavaScript

 ctx.drawImage(img, 0, 0, w, h);

    var imgPixels = ctx.getImageData(0, 0, w, h);
    for(var y = 0; y < imgPixels.height; y++){
     for(var x = 0; x < imgPixels.width; x++){
          var i = (y * 4) * imgPixels.width + x * 4;
          var avg = (imgPixels.data[i] + imgPixels.data[i + 1] + imgPixels.data[i + 2]) / 3;
          imgPixels.data[i] = avg;
          imgPixels.data[i + 1] = avg;
          imgPixels.data[i + 2] = avg;
     }
}
ctx.putImageData(imgPixels, 0, 0, 0, 0, imgPixels.width, imgPixels.height);
varun
  • 4,522
  • 33
  • 28
5

Modern browsers can now do this in CSS – on any HTML element, not just images. Combined with IE's old filter CSS, you can get pretty good compatibility:

image.grayscale {
  /* IE */
  filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);

  /* Chrome, Safari */
  -webkit-filter: grayscale(1);

  /* Firefox */
  filter: grayscale(1);
}

OP specifies "only JavaScript" but also mentions that IE's filter would be acceptable if it were more widely supported, which it now (effectively) is, so I believe this is the best solution in 2015. If you really must have JavaScript:

element.style.filter = 'grayscale(1)';

Sources:

Don McCurdy
  • 10,975
  • 2
  • 37
  • 75
4

i think this code will run perfect with you no need to nested loops or any additional libraries

var image = document.getElementById("image");

var canvas=document.createElement("canvas");
var ctx=canvas.getContext("2d");

canvas.width= image.width;
canvas.height= image.height;

ctx.drawImage(image,0,0);

var imageData=ctx.getImageData(0,0, image.width, image.height);

for (var i=0;i<imageData.data.length;i+=4) {
    var avg = (imageData.data[i]+imageData.data[i+1]+imageData.data[i+2])/3;

    imageData.data[i] = avg;
    imageData.data[i+1] = avg;
    imageData.data[i+2] = avg;

}

ctx.putImageData(imageData, 0, 0, 0, 0, imageData.width, imageData.height);
document.getElementById("grayscale").appendChild(canvas);
Karim Omaya
  • 841
  • 7
  • 7
2

Some image filters are available in CSS and supported by all major browsers, but you can have much more options using the HTML5 Canvas and Javascript.

However, when using Canvas based image filtering, you don't need implement the filters algorithm by yourself. Just use an image processing or Canvas manipulation library.

Examples:

In the examples below I used MarvinJ.

Loading image:

image = new MarvinImage();
image.load("https://i.imgur.com/B33rKWi.png", imageLoaded);

Gray Scale:

Marvin.grayScale(image.clone(), image);

enter image description here

Black and White:

Marvin.blackAndWhite(image.clone(), image, 5);

enter image description here

Black and White 2:

Marvin.blackAndWhite(image.clone(), image, 40);

enter image description here

Halftone:

Marvin.halftoneErrorDiffusion(image.clone(), image);

enter image description here

Runnable Example:

var canvas = document.getElementById("canvas");
image = new MarvinImage();
image.load("https://i.imgur.com/B33rKWi.png", imageLoaded);

function imageLoaded(){
 // GrayScale
 //Marvin.grayScale(image.clone(), image);
 //image.draw(canvas);
 
 // Black and White
 Marvin.blackAndWhite(image.clone(), image, 5);
 image.draw(canvas);
 
 // Black and White 2
 //Marvin.blackAndWhite(image.clone(), image, 40);
 //image.draw(canvas);
 
 // Error Diffusion
 //Marvin.halftoneErrorDiffusion(image.clone(), image);
 //image.draw(canvas);
}
<script src="https://www.marvinj.org/releases/marvinj-0.7.js"></script>
<canvas id="canvas" width="400" height="400"></canvas>
Gabriel Archanjo
  • 4,547
  • 2
  • 34
  • 41
1

Nowadays you can also apply filter before rendering image into canvas. Browser support data here.

const image = document.getElementById("image");
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = image.width;
canvas.height = image.height;
ctx.filter = "grayscale()";
ctx.drawImage(image, 0, 0);
polkovnikov.ph
  • 6,256
  • 6
  • 44
  • 79
1

I've found this (http://spyrestudios.com/html5-canvas-image-effects-black-white/) solution to work rather well outside of IE, which, as others have noted, you'll need to use filters for.

chaselee
  • 326
  • 3
  • 6
0

Canvas is indeed the best client-side solution to this problem, and I just wanted to point out that, for IE, you can actually use the google exCanvas project which translate canvas commands into the proprietary Microsoft XML-based vector language, VML.

http://excanvas.sourceforge.net/

Gavin
  • 603
  • 4
  • 8
0

A fast way to grey out the image is by swapping color channels

ctx.drawImage(gdImage, 0, 0);
let imgdata = ctx.getImageData(0, 0, w, h);
for (var i = 0; i < imgdata.data.length; i += 4) {
    imgdata.data[i  ] = imgdata.data[i+2];
    imgdata.data[i+1] = imgdata.data[i];
}
ctx.putImageData(imgdata, 0, 0);
Eiad Samman
  • 397
  • 4
  • 15