I am trying to get the RGB array of img using canvas like this:
Teplate
<!DOCTYPE html>
<html>
<head>
<title>Parcel Sandbox</title>
<meta charset="UTF-8" />
</head>
<body>
<div id="display"></div>
<img id="face" src="./220px-Leonhard_Euler.jpg" />
<canvas
id="face2"
width="112"
height="112"
style="border: 1px solid #d3d3d3;"
></canvas>
<script src="src/index.js"></script>
</body>
</html>
Script
const img = document.getElementById("face");
img.crossOrigin = "anonymous";
const canvas = document.getElementById("face2");
const context = canvas.getContext("2d");
context.drawImage(img, 0, 0);
let pix = context.getImageData(0, 0, 112, 112).data;
pix = Array.from(pix);
const pix2 = [];
for (let i = 0; i < pix.length; i += 4) {
pix2.push(pix[i + 0]);
pix2.push(pix[i + 1]);
pix2.push(pix[i + 2]);
}
const imgData = context.createImageData(112, 112);
for (let i = 0; i < imgData.data.length; i += 4) {
imgData.data[i + 0] = pix2[i + 0];
imgData.data[i + 1] = pix2[i + 1];
imgData.data[i + 2] = pix2[i + 2];
imgData.data[i + 3] = 255;
}
context.putImageData(imgData, 10, 10);
As you can see in the first part of the code I try to extract the 4d array of the image RGBA, and try to remove the alpha channel.
After that, I tried to set again the image with a default alpha channel like 255 only to check that I got the RGB data only.
But I got the following image:
The input image is 112x112 and the canvas is 112x112, any idea about why I could get only the RGB of the img?
EDIT2
The @tracktor response worked but I still get error with another image like this:
Same code the only difference is that I load this image using http://localhost:8080/face.jpg instead of crossorigin.
Thanks
crossorigin
attributePut a crossorigin
attribute on the img
tag in HTML to ensure the browser requests the image with headers for a CORS operation, such as
Origin: http://localhost Sec-Fetch-Mode: cors Sec-Fetch-Site: cross-site
In return the site responding with the image data must include an "Access-Control-Allow-Origin" header set from the "origin" request header, such as
Access-Control-Allow-Origin: http://localhost
or the wildcard version:
Access-Control-Allow-Origin: *
to enable javascript access to the data returned.
Note https://i.stack.imgur.com
does not return access control headers, so images returned from that domain will taint canvas objects. I highly recommend reading http://expressjs.com/resources/middleware/cors.html if you are are writing or modifying a node/express server to support CORS.
load
eventWait until after the window load
event fires to process image data. If processed earlier image loading may not be available.
The incorrect image data shown in the updated post is caused by not alligning the 3-tuples of rgb data in pix2
with the 4-tuples of rgba data required in imageData.data
. To transpose the pixel data successfully try something equivalent to:
for (let i = 0, j = 0; i < imgData.data.length; i += 4) {
imgData.data[i + 0] = pix2[j++];
imgData.data[i + 1] = pix2[j++];
imgData.data[i + 2] = pix2[j++];
imgData.data[i + 3] = 128; // test value
}
The following snippet creates two canvas elements: one to show the image loaded and another to show the result of canvas data manipulation. The code uses localhost servers on different ports and won't run successfully without them:
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>cross origin</title></head>
<body>
<h2>Image</h2>
<img id="face" crossorigin src="http://localhost:8080/share/imperial.jpg" />
<h2>Canvas</h2>
<canvas
id="face2"
width="112"
height="112"
style="border: 1px solid blue"
></canvas>
<canvas
id="modified"
width="112"
height="112"
style="border: 1px solid red"
></canvas>
<script type="text/javascript">"use strict";
window.addEventListener("load", ()=> {
const img = document.getElementById("face");
const canvas = document.getElementById("face2");
const context = canvas.getContext("2d");
context.drawImage(img, 0, 0);
let imgData1 = context.getImageData(0, 0, 112, 112)
let pix;
try {
pix = imgData1.data;
}
catch( err) {
console.warn( err.message);
}
pix = Array.from(pix);
const pix2 = [];
for (let i = 0; i < pix.length; i += 4) {
pix2.push(pix[i + 0]);
pix2.push(pix[i + 1]);
pix2.push(pix[i + 2]);
}
const imgData = context.createImageData(112, 112);
for (let i = 0, j = 0; i < imgData.data.length; i += 4) {
imgData.data[i + 0] = pix2[j++];
imgData.data[i + 1] = pix2[j++];
imgData.data[i + 2] = pix2[j++];
imgData.data[i + 3] = 128; // test value
}
const canvas2 = document.getElementById("modified");
const context2 = canvas2.getContext("2d");
context2.putImageData(imgData, 10, 10);
});
</script></body>
</html>