Fill a portion of drawn image in canvas - javascript

i drew an image using drawImage() api of html5 canvas. now i want to fill the white spaces of that drew image with different colors (individual box individual color). how can i do it? i am using html5 canvas and jquery.
i want to fill the white spaces with different color and those white spaces are not proper rectangular box.
thanks in advance.

[ changed answer after clarification from questioner ]
Given: an image that has many fully-enclosed transparent areas.
This is a method to fill each transparent area with a different color:
Use context.getImageData to get an array of each canvas pixels [r,g,b,a] value.
Loop thru the array and find the first transparent pixel (the "a" value ==0)
Floodfill the entire transparent area containing that pixel with a new opaque color (replace the r,g,b values with your new color and replace the "a" value ==255).
Repeat step#2 until all the transparent areas have been filled with new unique colors.
To get you started...
William Malone wrote a very nice article on how to get and use canvas's [r,g,b,a] color array.
His article also shows you how to "floodfill" -- replace an existing color with a new color in an entire contiguous area.
In your case, you would replace transparent pixels with a new color.
This is his article:
http://www.williammalone.com/articles/html5-canvas-javascript-paint-bucket-tool/
[Addition to question: insert images into areas ]
You need to make each colorized area transparent again—one at a time
If you save each area's starting pixel from when you originally colorized the areas, you can start with that pixel and re-floodfill an area. This time you’ll set the alpha component of each pixel in that area to 0 (transparent).
As each single area is transparent you use compositing to draw the new image only where the existing pixels are transparent. The composite you want is context.globalCompositeOperation=”source-out”.
These examples show:
After uniquely colorizing each area.
After making 1 area transparent (the top-right area is transparent).
After compositing an image into the transparent area.

//draw some white, green, and blue stripes
for (var i = 0; i < canvas.width; i += 10) {
for (var j = 0; j < canvas.height; j += 10) {
context.fillStyle = (i % 20 === 0) ? "#fff" : ((i % 30 === 0) ? "#0f0" : "#00f");
context.fillRect(i, j, 10, 10);
}
}
var imagedata = context.getImageData(0, 0, canvas.width, canvas.height),
pixels = imagedata.data;
//if found white pixel i.e 255,255,255 changes it to 0,102,204
//you can change it to another color as u wish
for (var offset = 0, len = pixels.length; offset < len; offset += 4) {
if(pixels[offset]==255 &&
pixels[offset+1]==255 &&
pixels[offset+2]==255)
{pixels[offset] = 0; //
pixels[offset + 1] = 102; //
pixels[offset + 2] = 204; //
}
}
context.putImageData(imagedata, 0, 0);

Related

Applying a colour change to a image as an overlay, keeping the orignal texture/shaders Javascript

Performing "getimagedata" to replace the colour of the pixels in a image however, this completely removes the original pixels, want to achieve a overlay on the exisiting pixels to change the colour whilst keeping texture,shaders,and shape if possible.
var imageData = canvasContext.getImageData(video,0,0,canvasOutput.width,canvasOutput.height);
for (j = 0; j < imageData.data.length; j += 4){
imageData.data[j] = rgb[0]; //red pixel
imageData.data[j + 1] = rgb[1]; //green pixel
imageData.data[j + 2] = rgb[2]; //blue pixel
}
canvasContext.putImageData(imageData,0,0)
pixels are being overwritten as opposed to being a colour overlay on the image.
found a solution using OpenCV
cv.rectangle(overlayMat, point1, point2, [rgb[0], rgb[1], rgb[2], rgb[3]], -1); //img,(x,y), (x+width,y+height), scala 4 colour, fill
cv.addWeighted(overlayMat,alpha,vidMat,1 - alpha,0,vidMat);
applies a colour to the x,y position of point1, then the size is calculated using x + width, y + height in point 2, colour is based on RGBA Scalar array, -1 fills the entire area specified in point 2.
add weighted applies the coloured rect saved in another mat to the original mat using transparency of alpha values.

Get Color Data of HTML5 Canvas

I want to get the percentage of a color in a HTML5 Canvas.
I have a Canvas, where you can draw lines in three colors with the mouse or clean it with a white line.
Now I want to get the percentage of a color in the whole canvas.
I try that:
var c = document.getElementById("can");
var ctx = c.getContext("2d");
var imgData = ctx.getImageData(0, 0, c.width, c.height);
var allPixel=0;
for (var i = 0; i < imgData.data.length; i += 4) {
allPixel+=1;
if(imgData.data[i+2]==255)
blue+=1;
else if (imgData.data[i]==255)
red+=1;
else if (imgData.data[i+1]==green)
green +=1;
}
But this seems to be wrong. The values are strange and always go very high. How can I get the right values of the whole canvas and a color to calculate the percentage.
Can you help me?
And how is it possible with another color instead of the full RGB colors , for example Yellow or white?
Thank you!
White is equal to rgb(255,255,255) so you might be counting that as blue. Also it might be easier to loop through each x and y and get the data, where this code gets the data at exactly one pixel.
var col = ctx.getImageData(x,y,1,1).data
var red = col[0];
var green = col[1];
var blue = col[2];
// increment values

html5 how to stroke with the inverted background color?

I want to do a selector tool in HTML5. As the user click and moves the mouse, a rectangle should be drawn from the starting point to the mouse pointer. This is usually done choosing a logical operator for the color of the stroke (so the lines are drawn as the inverse of the background), but it looks like I can only do this in HTML5 manipulating the image pixel by pixel. Wouldn't it be too slow? Is there a direct way to do that?
You can optimize your "inverted stroke" to be fast enough for "live" strokes.
Layer 2 canvases, one on top of another.
Draw the inverted image on the bottom canvas.
Draw the normal image on the top canvas.
Draw your strokes on the top canvas with context.globalCompositeOperation="destination-out".
"destination-out" compositing causes the top canvas pixels to be made transparent where the stroking occurs.
This "reveals" the inverted image below only where the strokes are.
This reveal is very fast since the GPU assists in compositing.
You can do this two ways:
Inverse region in-place and reset by re-drawing image
Keep an inverted version of image in a second canvas and draw clipped version
Option 1
For option 1 you would need to iterate the area each time using JavaScript which will be a relative slow operation compared to option 2.
Example of option 1:
// inside the mouse move code (please see live demo below)
ctx.drawImage(img, 0, 0); // update image (clear prev inv)
//invert the region
if (w !== 0 && h !== 0) {
var idata = ctx.getImageData(x1, y1, w, h), // get buffer
buffer = idata.data,
len = buffer.length,
i = 0;
for(; i < len; i += 4) { // inverse it
buffer[i] = 255 - buffer[i];
buffer[i+1] = 255 - buffer[i+1];
buffer[i+2] = 255 - buffer[i+2];
}
ctx.putImageData(idata, x1, y1);
}
As you can see the performance is not bad at all using just JavaScript and the CPU. The performance threshold is dependent on size of region though.
Live demo of option 1
Option 2
In option 2 you pre-invert the image in the second canvas and draw a clipped version of it to main canvas. This means from that point on you will get the benefit from using the GPU (if available) and performance will be much better.
Example of option 2:
// have a second canvas setup
var ocanvas = document.createElement('canvas'),
octx = ocanvas.getContext('2d'),
//invert the off-screen canvas
var idata = octx.getImageData(0, 0, ocanvas.width, ocanvas.height),
buffer = idata.data,
len = buffer.length,
i = 0;
for(; i < len; i += 4) {
buffer[i] = 255 - buffer[i];
buffer[i+1] = 255 - buffer[i+1];
buffer[i+2] = 255 - buffer[i+2];
}
octx.putImageData(idata, 0, 0);
Now it's a matter of getting the region of that area and update with a clipped version:
if (w !== 0 && h !== 0)
ctx.drawImage(ocanvas, x1, y1, w, h, x1, y1, w, h);
Live demo of option 2

Looping through pixels in an image

My project is to input an image into a canvas tag in an HTML page, and then loop through the pixels and RGBA values of the pixels. While looping through the red values,so every fourth value in the pixel, I want to log the position of the pixels that represent a white pixel. Now, I have the image loading down with some code I got from this blog, http://www.phpied.com/photo-canvas-tag-flip/ .
He has another post in which he gives some code on how to loop through the pixels and log the information I want to log, but I don't understand it, and I don't want to copy his code without knowing what it is I'm doing. So could anybody please either explain the method he's using or perhaps show me another way to do what he's doing? This is the link to the other post http://www.phpied.com/pixel-manipulation-in-canvas/ .
It's straightforward.
All the pixel data for a canvas are stored sequentially in an array.
The first pixel's data occupy array elements #0-3 (red=0/green=1/blue=2/alpha=3).
The second pixel's data occupy array elements #4-7 (red=4/green=5/blue=6/alpha=7).
And so on...
You can load that pixel data by using context.getImageData() and enumerating through the array:
const imgData = context.getImageData(0, 0, canvas.width, canvas.height);
const data = imgData.data;
// enumerate all pixels
// each pixel's r,g,b,a datum are stored in separate sequential array elements
for(let i = 0; i < data.length; i += 4) {
const red = data[i];
const green = data[i + 1];
const blue = data[i + 2];
const alpha = data[i + 3];
}
You can also change those array values and then save the array back to the image using context.putImageData().
// save any altered pixel data back to the context
// the image will reflect any changes you made
context.putImageData(imgData, 0, 0);
The image will then change according to the changes you made to its pixel array.
Each pixel contains 4 components red, green, blue, alpha - each of them is number 0-255. The loop starts from top-left to bottom-right.
I recommend you to use an image processing framework in order to focus on the algorithms instead of manipulating arrays of values. Some frameworks:
fabric.js
processing.js
MarvinJ
In the case of MarvinJ, you can simply loop through pixels iterating column and row coordinates. I use the methods getIntComponentX() to access color components.
for(var y=0; y<image.getHeight(); y++){
for(var x=0; x<image.getWidth(); x++){
var red = image.getIntComponent0(x,y);
var green = image.getIntComponent1(x,y);
var blue = image.getIntComponent2(x,y);
}
}
Therefore you don't need to worry about how the pixel data is represented. In order to check if a pixel is white:
// Is white?
if(red >= 250 && blue >= 250 && green >= 250){
console.log("Pixel at "+x+","+y+" is white");
}
Runnable Example:
var canvas = document.getElementById("canvas");
image = new MarvinImage();
image.load("https://i.imgur.com/eLZVbQG.png", imageLoaded);
function imageLoaded(){
var whitePixels=0;
for(var y=0; y<image.getHeight(); y++){
for(var x=0; x<image.getWidth(); x++){
var red = image.getIntComponent0(x,y);
var green = image.getIntComponent1(x,y);
var blue = image.getIntComponent2(x,y);
var alpha = image.getAlphaComponent(x,y);
// Is white?
if(red >= 250 && green >= 250 && blue >= 250 && alpha > 0){
whitePixels++;
}
}
}
image.draw(canvas);
document.getElementById("result").innerHTML = "white pixels: "+whitePixels;
}
<script src="https://www.marvinj.org/releases/marvinj-0.7.js"></script>
<canvas id="canvas" width="500" height="344"></canvas>
<div id="result"></div>

The implementation of functional "Levels" like in Photoshop

Faced with such a problem. Need to implement the ability to corrections for Levels, as in Photoshop:
The problem is this: there are all the data for each pixel of image, there is data entered by the user InputWhite, InputBlack, OutputWhite, OutputBlack. (as shown in the figure).
I need to change every 3 channel specifically for each pixel (RGB).
How Can I change their ? I can not understand. Thanks in advance.
You can use the imageData of the canvas to modify the RGB values of individual pixels however you please.
For instance to "increase" the green "channel" of all pixels you could do this, which adds 30 to the value of each G in the RGB of every pixel:
var imageData = ctx.getImageData(0,0,can.width, can.height);
var pixels = imageData.data;
var numPixels = pixels.length;
ctx.clearRect(0, 0, can.width, can.height);
for (var i = 0; i < numPixels; i++) {
var average = (pixels[i*4] + pixels[i*4+1] + pixels[i*4+2]) /3;
// set red green and blue pixels to the average value
pixels[i*4] = 0;
pixels[i*4+1] += 30;
pixels[i*4+2] += 0;
}
ctx.putImageData(imageData, 0, 0);
Example:
http://jsfiddle.net/YxYuF/
From there it's just a question of making a nice UI to present to the user.

Categories

Resources