I am following the tutorial on WC3 found here: .asp
I have my image loaded up and next to this is the canvas which I have a nice boarder and I'm intending to display side-by-side images. I am attempting to invert the color of the pixel as the demonstration but I cannot get the colors to change I don't understand why.
Here is my code pen where I separated the HTML from the JS:
document.getElementById("team").onload = function() {
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
var img=document.getElementById("team");
ctx.drawImage(img, 0, 0);
var imgData = ctx.getImageData(0, 0, c.width, c.height);
// invert colors
var i;
for (i = 0; i < imgData.data.length; i += 4) {
imgData.data[i] = 255 - imgData.data[i];
imgData.data[i+1] = 255 - imgData.data[i+1];
imgData.data[i+2] = 255 - imgData.data[i+2];
imgData.data[i+3] = 255;
}
ctx.putImageData(imgData, 0, 0);
};
It appears that ctx.drawImage(img, 0, 0); is drawing my image inside the canvas. For some reason the function that works on the WC3 tutorial is not working properly on my image because when it draws the image after the function there are no changes.
Can anyone help me solve this please?
I am following the tutorial on WC3 found here: http://www.w3schools.com/tags/canvas_getimagedata.asp
I have my image loaded up and next to this is the canvas which I have a nice boarder and I'm intending to display side-by-side images. I am attempting to invert the color of the pixel as the demonstration but I cannot get the colors to change I don't understand why.
Here is my code pen where I separated the HTML from the JS: http://codepen.io/kKasper/pen/zBXWOZ
document.getElementById("team").onload = function() {
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
var img=document.getElementById("team");
ctx.drawImage(img, 0, 0);
var imgData = ctx.getImageData(0, 0, c.width, c.height);
// invert colors
var i;
for (i = 0; i < imgData.data.length; i += 4) {
imgData.data[i] = 255 - imgData.data[i];
imgData.data[i+1] = 255 - imgData.data[i+1];
imgData.data[i+2] = 255 - imgData.data[i+2];
imgData.data[i+3] = 255;
}
ctx.putImageData(imgData, 0, 0);
};
It appears that ctx.drawImage(img, 0, 0); is drawing my image inside the canvas. For some reason the function that works on the WC3 tutorial is not working properly on my image because when it draws the image after the function there are no changes.
Can anyone help me solve this please?
Share Improve this question asked Aug 19, 2016 at 21:58 Kasper_SkyKasper_Sky 1071 gold badge1 silver badge3 bronze badges 2- 1 Your code works on my side. Make sure the image you are loading is actually available and being loaded. – ASDFGerte Commented Aug 19, 2016 at 22:15
- 1 I needed to do exactly this, except preserve transparency for a drawn image. By adding a conditional check within the loop for imgData.data[i] > 0, you avoid all transparent pixels. – EvilJordan Commented Dec 4, 2016 at 3:08
4 Answers
Reset to default 26You can use compositing to invert your image as long as your browser supports blending.
Advantages:
- This is faster than
getImageData
- The canvas won't object with cross-origin security restrictions
ctx.drawImage(img,0,0);
ctx.globalCompositeOperation='difference';
ctx.fillStyle='white';
ctx.fillRect(0,0,canvas.width,canvas.height);
Similar to markE's answer, but maintains transparency / alpha channel during draw.
ctx.filter = 'invert(1)'
ctx.drawImage(img, 0, 0)
There's loads of other filters you can apply as well
if you want to save to a base64
data url, you can use the following after drawing to your canvas
const dataUrl = canvas.toDataURL()
If you're getting error messages about a tainted canvas, before you set your image.src, set the crossOrigin
property to 'Anonymous'
:
const img = new Image()
img.crossOrigin = 'Anonymous'
img.onload = myLoadFn
img.src = myImgUrl
ctx.filter = 'invert(1)'
is best but has limited browser support, so check if it is supported, otherwise use ctx.globalCompositeOperation = 'difference'
which alone does not maintain transparency, but a clipping mask can be created and used to reset that. As some old browsers like IE do not support difference
also check if that is supported and revert to using the ImageData and if the image does not have CORS support catch any error caused by tainted canvas.
if (ctx.filter) {
ctx.filter = 'invert(1)';
ctx.drawImage(img, 0, 0);
} else {
ctx.drawImage(img, 0, 0);
ctx.globalCompositeOperation = 'difference';
if (ctx.globalCompositeOperation === 'difference') {
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, img.width, img.height);
var canvas2 = document.createElement('canvas');
var ctx2 = canvas2.getContext('2d');
canvas2.width = img.width;
canvas2.height = img.height;
ctx2.drawImage(img, 0, 0);
ctx2.globalCompositeOperation = 'source-in';
ctx2.fillStyle = 'black';
ctx2.fillRect(0, 0, img.width, img.height);
ctx.globalCompositeOperation = 'destination-in';
ctx.drawImage(canvas2, 0, 0);
} else {
try {
var imgData = ctx.getImageData(0, 0, img.width, img.height);
var data = imgData.data;
for (var i = 0; i < data.length; i += (i % 4 === 2 ? 2 : 1)) {
data[i] = 255 - data[i];
}
ctx.putImageData(imgData, 0, 0);
} catch (e) {}
}
}
Try opening your browser's developer console on your Codepen. I'm getting this error:
Uncaught SecurityError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.
This means that you've drawn an image from another domain (i.e. not codepen.io
) onto the canvas. As a security feature to prevent malicious scripts from communicating with external domains, browsers will disallow JS from accessing such data. See the MDN article on the same-origin policy.
Try running your code from a local file, or using an image from the same domain as the page. I bet it will work.
The dev console is your friend!