I am generating the image from the entered text in the text box. I need to get the pixel from the generated image. Right now I am doing the following
tCtx.fillText(entered_text, 20, 40);
imageElem.src = tCtx.canvas.toDataURL("image/png");
var imageData = tCtx.getImageData(0, 0, tCtx.canvas.width, tCtx.canvas.height);
var px = imageData.data;
var len = px.length;
for (var i = 0; i < len; i+=4) {
var redPx = px[i];
var greenPx = px[i+1];
var bluePx = px[i+2];
var alphaPx = px[i+3];
console.log(redPx,greenPx,bluePx);
}
Here the console prints the all 0's only for each pixel. But in the Canvas I am seeing the image, when I gave that toDataURL(), in image tag also I am seeing the Image. Don't know how.
When I use the custom images other than the text, then I am getting the pixel data like,
34 45 255 255
54 56 210 255 ...
You need to print Alpha channel to console as well. I also received 0,0,0 for all pixels. Since default canvas's background is (0,0,0,0) which is transparent. And black font is (0,0,0,noneZeroValue): (could be not 255 because of antialising). If you won't print alpha channel all of them will be 0,0,0.
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="100" height="20" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<script>
window.onload = function() {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
//ctx.font = "48px serif";
ctx.fillText("A lot of text", 0, 10);
//ctx.drawImage(ocanvas,0,0,c.width,c.height);
var imageData = ctx.getImageData(0, 0, c.width, c.height);
var px = imageData.data;
var len = px.length;
for (var i = 0; i < len; i+=4) {
var redPx = px[i];
var greenPx = px[i+1];
var bluePx = px[i+2];
var alphaPx = px[i+3];
//if (redPx!=0 || greenPx!=0 ||bluePx!=0 || alphaPx!=0){
console.log(redPx,greenPx,bluePx,alphaPx);
}
};
</script>
</body>
</html>
I found the solution.
What i did right now is
tCtx.putImageData(imageData, 0, 0, 0, 0, imageData.width, imageData.height);
because of this I am displaying the image out side of the canvas. So, it is not visible. Then I changed it to
tCtx.putImageData(imageData, 0, 0);
now, it is fine. Able to get the pixel data
Related
I'm drawing an image on my canvas and trying to use getImageData() from canvas to get the image data but I got all 0's in return. From my understanding, the image hasn't finished a load so I get the 0's. From this issue: getImageData always returning 0 seems like I need to wait by using onload. Is there another way to get the data by not use onload function? I want to declare an image tag in my html. Here is my code:
<html>
<head>
</head>
<body>
<script>
var bgMap = {
"bg1": "image1.JPG",
"bg2": "image2.JPG"
}
</script>
<center>
<select id="selectBg" onchange="document.getElementById('bgImage').src = bgMap[this.value]">
<option value="bg1">Bg1</option>
<option value="bg2">Bg2</option>
</select>
</center>
<img id='bgImage' src='image1.JPG' width=500 height=500 />
<canvas id='bgCanvas'></canvas>
<script>
var canvas = document.getElementById('bgCanvas')
var bgImage = document.getElementById('bgImage')
canvas.width = 500
canvas.height = 500
var ctx = canvas.getContext("2d")
ctx.drawImage(bgImage, 0, 0, 500, 500)
var imageData = ctx.getImageData(0, 0, 500, 500)
var rgba = imageData.data;
for (var px = 0, ct = 500 * 500 * 4; px < ct; px += 4) {
var r = rgba[px];
var g = rgba[px + 1];
var b = rgba[px + 2];
var a = rgba[px + 3];
console.log(r,g,b,a)
}
console.log(rgba)
</script>
</body>
</html>
I'm getting in JS code a 2D matrix of bytes (integer values between 0-255) from a camera and I want to display it in a <canvas> element. Is there a way to convert this matrix to an image?
I have tried to use window.atob() but it fails and stopped to execute the code.
Yes, it is possible. You need to to something like this (example for a 120x120 image):
Html:
<canvas id="canvas" width=120 height=120></canvas>
JS:
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext("2d");
var imgData = ctx.createImageData(120, 120);
// Now you need to assign values to imgData array into groups of four (R-G-B-A)
let j = 0;
iterate your object {
imgData.data[j] = R value;
imgData.data[j + 1] = G value;
imgData.data[j + 2] = B value;
imgData.data[j + 3] = 255 (if greyscale);
j += 4;
}
ctx.putImageData(imgData, 0, 0);
Can someone help me to fix the issue?
I want to apply alpha layer mask to make some of the image transparent using canvas.
Thanks a lot.
var redImageData = redCanvas.getContext("2d").getImageData(0, 0, 200, 200); //overlay
var ImageData = imageCanvas.getContext("2d").getImageData(0, 0, 200, 200);
var px = redImageData.data;
var px2 = ImageData.data;
for(var i = 0; i < px.length; i += 4) {
if(px[i + 0] == 0 && px[i + 1] == 0 && px[i+2] == 0){
px[i + 3] = 0;
} else {
px[i + 0] = px2[i + 0];
px[i + 1] = px2[i + 1];
px[i + 2] = px2[i + 2];
px[i + 3] = px2[i + 3];
}
}
ctx.imageSmoothingEnabled = true;
ctx.putImageData(redImageData, 0, 0);
alpha mask overly https://i.stack.imgur.com/zCzOf.png
The linked image is not really an alpha mask but a matte image. The difference is that a matte image represent what would be an alpha-channel but showing it as RGB (or gray-scale) components. It doesn't actually have an alpha-channel. Matte images are common in video-compositing software but not so useful on web.
Canvas, or the Porter-Duff methods it uses, does not support matte images directly so they have to first be converted to an actual alpha-channel. To do this you have to iterate over each pixel and move one of the component values (from red, green or blue - doesn't matter which) into the alpha-channel.
When that is done you can use the canvas object that now has proper alpha-channel with composite operations which only uses the alpha information (blending modes is a different chapter).
The better approach is of course to provide the images as PNG with a proper alpha channel. But in any case, to show it's possible to also work with matte images, although not as efficient, we can do the following:
Converting matte image into alpha channel
First step: this code section shows how you can efficiently do the pre-step of converting the matte image into an alpha channel. The resulting colors are not important for the main compositing step as it will only use the alpha-channel, as already mentioned.
Just make sure the image has loaded properly before trying to use the image by either using the image's onload callback or running the script after everything has loaded.
This code will simply shift a component (blue in this case) using the full 32-bit value of the pixel (for efficiency) into the alpha-channel which leaves the image looking cyan but with proper alpha as you can see with the orange background showing through (most of the code is to handle loading and setup though).
window.onload = function() {
// at this stage the image has loaded:
var img = document.getElementById("img");
var canvas = document.getElementById("c");
var ctx = canvas.getContext("2d");
// - setup canvas to match image
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
// - draw image
ctx.drawImage(img, 0, 0);
// CONV. STEP: move a component channel to alpha-channel
var idata = ctx.getImageData(0, 0, canvas.width, canvas.height);
var data32 = new Uint32Array(idata.data.buffer);
var i = 0, len = data32.length;
while(i < len) {
data32[i] = data32[i++] << 8; // shift blue channel into alpha (little-endian)
}
// update canvas
ctx.putImageData(idata, 0, 0);
};
body {background: #f72; font-size:44px; color:rgba(0,0,0,0.5)}
<img id="img" crossorigin="anonymous" src="https://i.imgur.com/QRGYuWg.png"> ►
<canvas id="c"></canvas>
Compositing
The second part then becomes about compositing using the new alpha-channel.
In this case the matte image's black becomes fully transparent while the white becomes fully opaque. You could have reversed this in the conversion step but it does not really matte as long as you're aware of the how the matte image looks.
To replace the interior content we use compositing mode source-in. This will replace the content depending on the alpha value while keeping the alpha-channel as it is.
Dealing with the interior part first using the same mode allows us to do additional things with the content before drawing the frame (think vignette, shadows etc.).
As the final step we fill in the transparent areas, the frame itself, by using the composite mode destination-over which replaces the more transparent ares with the content being drawn to canvas (conceptually it draws "behind" the existing content).
The code below uses simple colored boxes - just replace those with whatever you want to draw.
window.onload = function() {
var img = document.getElementById("img");
var canvas = document.getElementById("c");
var ctx = canvas.getContext("2d");
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
ctx.drawImage(img, 0, 0);
var idata = ctx.getImageData(0, 0, canvas.width, canvas.height);
var data32 = new Uint32Array(idata.data.buffer);
var i = 0, len = data32.length;
while(i < len) data32[i] = data32[i++] << 8;
ctx.putImageData(idata, 0, 0);
// COMP. STEPS: use the mask with composite operation. Since our frame
// is black (= transparent as alpha) we can use the following mode:
ctx.globalCompositeOperation = "source-in";
// draw something, here a blue box, replace with whatever you want
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// to fill the frame area, still transparent, use this mode:
ctx.globalCompositeOperation = "destination-over";
ctx.fillStyle = "yellow";
ctx.fillRect(0, 0, canvas.width, canvas.height);
};
body {background: #f72; font-size:44px; color:rgba(0,0,0,0.5)}
<img id="img" crossorigin="anonymous" src="https://i.imgur.com/QRGYuWg.png"> ►
<canvas id="c"></canvas>
I have a large amount of images with a black background, here is one for example:
Is it possible through Javascript to have to ignore the black (#000000) and have it draw on canvas? to appear like this?
Basically trying to take the black pixels and make it an alpha channel.
So you'll need to run through all the pixels and change the alpha value of all the black pixels.
https://jsfiddle.net/0kuph15a/2/
This code creates a buffer (empty canvas) to draw the original image to. Once thats done, it takes all the pixels of this buffer canvas and then iterates over all the pixels and checks their values. I add up the Red, Blue, and Green values to see if they are less then 10 (just incase some pixels aren't pure black 0), but would visually appear black to the human eye. If it is less then 10 it simply turns the alpha value of that pixel to 0.
var canvas = document.getElementById('main');
var ctx = document.getElementById('main').getContext('2d');
var tile = new Image();
tile.src = document.getElementById('image').src;
tile.onload = function() {
draw(tile);
}
function draw(img) {
var buffer = document.createElement('canvas');
var bufferctx = buffer.getContext('2d');
bufferctx.drawImage(img, 0, 0);
var imageData = bufferctx.getImageData(0,0,buffer.width, buffer.height);
var data = imageData.data;
var removeBlack = function() {
for (var i = 0; i < data.length; i += 4) {
if(data[i]+ data[i + 1] + data[i + 2] < 10){
data[i + 3] = 0; // alpha
}
}
ctx.putImageData(imageData, 0, 0);
};
removeBlack();
}
You can easily change this line if(data[i]+ data[i + 1] + data[i + 2] < 10){ to if(data[i]+ data[i+1] + data[i+2]==0){ if you know for a fact only #000 blacks are used.
You can accomplish that using blend modes.
Change the context globalCompositeOperation to screen, and you can get that result. Here's an example:
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var image = new Image();
image.src = "https://images.blogthings.com/thecolorfulpatterntest/pattern-4.png";
image.onload = function() {
context.drawImage(image, 0, 0, canvas.width, canvas.height);
var blackImage = new Image();
blackImage.src="http://www.printmag.com/wp-content/uploads/Sillitoe-black-white.gif";
blackImage.onload = function(){
context.globalCompositeOperation = "screen";
context.drawImage(blackImage, 0, 0, canvas.width, canvas.height);
}
};
<canvas id="canvas" width="300" height="250"></canvas>
<hr/>
<h1>Images used:</h1>
<img src="https://images.blogthings.com/thecolorfulpatterntest/pattern-4.png"/>
<img src="http://www.printmag.com/wp-content/uploads/Sillitoe-black-white.gif"/>
How about saving the picture as an .svg file...from there you can change all colors and other settings
Felipe's answer addressed my issue. Alpha pixel manipulation does not work
(eg, setting every 4th pixel to 0) for preserving alphatransparency with multiple images added into the same context at the same time.
eg:
this.ctx1.putImageData(output, 0, 0); // without setting the context's globalCompositeOperation, this image is written over by the next putImage operation
this.ctx1.putImageData(output, 20, 0);
Go here to review the blending options. https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation
I know questions like this have been asked several time, but I have yet to find just what I'm looking for. I am reading an image into a canvas object (in javascript) and trying to manipulate some specific pixels. For example, I am looking for the color RGB: 224 64 102, and trying to change this to a different color.
I can apply greyscale to the image, so I know the manipulation works, but the code is not finding any pixels with this color (that Adobe Illustrator said was the RGB color). I'm hoping I'm just missing a small detail. The code is below, hopefully someone will see it.
Thanks!
var canvas = document.getElementById("testcanvas");
var canvasContext = canvas.getContext('2d');
imgObj = new Image();
imgObj.src = "ss.jpg";
//imgObj.width = 200;
//imgObj.height = 200;
var imgW = imgObj.width;
var imgH = imgObj.height;
canvas.width = imgW;
canvas.height = imgH;
canvasContext.drawImage(imgObj, 0, 0);
var imgPixels = canvasContext.getImageData(0, 0, imgW, imgH);
//hash_table = {};
for (var x = 0; x < imgPixels.width; x++) {
for (var y = 0; y < imgPixels.height; y++)
{
var i = (y * imgPixels.width + x) * 4;
//Want to go from:
//E04066
//224 64 102 -> to
//134 135 185
if(imgPixels.data[i] == 224 && imgPixels.data[i+1] == 64 && imgPixels.data[i+2] == 102) {
imgPixels.data[i] = 134;
imgPixels.data[i+1] = 135;
imgPixels.data[i+2] = 185;
}
//To greyscale:
/*
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;
imgPixels.data[i + 3] = 255;
*/
}
}
canvasContext.putImageData(imgPixels, 0, 0, 0, 0, imgPixels.width, imgPixels.height);
//color_count = 0;
//for(key in hash_table) {
// color_count++;
//}
//console.log(color_count);
//console.log(hash_table);
return canvas.toDataURL();
});
});
</script>
</head>
<body>
<canvas id="testcanvas"></canvas>
<img src="ss.jpg" id="testimage"/>
You are probably unable to get image data from canvas because the canvas has been tainted by cross-origin data.
If that file, ss.jpg is local then it won't work. I imagine that's the case.
Search for canvas cross-origin on SO or Google for more information on that. There's a lot out there. Here's a bit of an explanation:
http://simonsarris.com/blog/480-understanding-the-html5-canvas-image-security-rules
Here's a site about enabling it on your server:
http://enable-cors.org/
Otherwise, your code works. Here is the same code converting a tiny red dot into a tiny green dot:
http://jsfiddle.net/RBaxt/
Canvas really don't work with .JPG format. You have to convert your image into .PNG using any picture editing tool like Photoshop. Your code works well.
I think you are loading an Image that is not ready to be painted. Below I have updated your code above, though I have not test it but I feel it could lead you somewhere
var canvas = document.getElementById("testcanvas");
var canvasContext = canvas.getContext('2d');
imgObj = new Image();
imgObj.src = "ss.jpg";
//imgObj.width = 200;
//imgObj.height = 200;
var imgW = imgObj.width;
var imgH = imgObj.height;
imgObj.onload = function(){
//Put the pixel manipulation code here;
// This ensures the image has been loaded before it is accessed.
}