I have a function to get pixel data from a 14x14px png. I tested to see if img.src was valid, which it is. Any pixel coordinate I use returns an array filled with 0's.
var RGB = getPixel('spectrum2D.png', 5, 5)
console.log(RGB) // Uint8ClampedArray(4) [0, 0, 0, 0]
function getPixel(url, x, y) {
var img = new Image();
img.src = url;
var canvas = document.createElement('canvas');
canvas.width = 14
canvas.height = 14
var context = canvas.getContext('2d');
context.drawImage(img, 0, 0);
return context.getImageData(x, y, 1, 1).data;
}
Related
I have a function that loops through an image's pixels to determine the average "brightness" of the image as a number between 0 (black) - 255 (white).
The problem is during testing I found that while an image that's entirely black (#000000) will correctly return 0, an image that's entirely white (#FFFFFF) returns a number around 200 instead of 255. Am I missing something?
Here's my function, any help would be appreciated!
function getBrightness(imageSrc, callback) {
const img = document.createElement("img");
img.src = imageSrc;
img.style.display = "none";
document.body.appendChild(img);
let colorSum = 0;
img.onload = function() {
const canvas = document.createElement("canvas");
canvas.width = this.width;
canvas.height = this.height;
const ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
let r, g, b, avg;
for(let x=0, len=data.length; x<len; x+=4) {
r = data[x];
g = data[x+1];
b = data[x+2];
avg = Math.floor((r+g+b) / 3);
colorSum += avg;
}
const brightness = Math.floor(colorSum / (this.width * this.height));
callback(brightness);
}
}
Sorry, but as the snippet below proves, the result for the image you mentioned is 255.
Maybe you want to check out what file you were using in the tests ? you're probably using a wrong file...
function getBrightness(imageSrc, callback) {
const img = document.createElement("img");
img.src = imageSrc;
img.crossOrigin = 'anonymous';
img.style.display = "none";
document.body.appendChild(img);
let colorSum = 0;
img.onload = function() {
const canvas = document.createElement("canvas");
canvas.width = this.width;
canvas.height = this.height;
const ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
let r, g, b, avg;
for(let x=0, len=data.length; x<len; x+=4) {
r = data[x];
g = data[x+1];
b = data[x+2];
avg = Math.floor((r+g+b) / 3);
colorSum += avg;
}
const brightness = Math.floor(colorSum / (this.width * this.height));
callback(brightness);
}
};
getBrightness(
'https://upload.wikimedia.org/wikipedia/commons/thumb/7/70/Solid_white.svg/768px-Solid_white.svg.png',
(b)=>console.log(b));
I just included the line img.crossOrigin = 'anonymous'; in order to avoid the cors security message.
I have a canvas, which is filled with the fillText function of canvas..
now i want to get the image data of this canvas.
var texttodraw = "hello world";
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
ctx.font = '16px serif';
ctx.fillStyle = "#00ff00";
ctx.fillText(txttodraw, 0, 0);
console.log('the text is: ' + txttodraw);
canvas.width = ctx.measureText(txttodraw).width;
canvas.height = 16;
console.log('the image size is: ' + canvas.width + ' x ' + canvas.height);
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
console.log(imageData);
The array "imageData" conains the height and the width and a array which contains the pixel data which i need.
But unfortuantely with this code i get a array full of zeros. the console output is:
ImageData { width: 24, height: 16, data: Uint8ClampedArray[1536] }
when i click on the data array i see that this is only containing zero values..
'Uint8ClampedArray [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1526 more… ] '
I have similar code with an canvas which have an image drawed with canvas.drawImage() inside, and this is working (the data array contains rgb values of each pixel in the canvas...).
What i am doing wrong?
You would have to set textBaseline property to top for the context, as the texts are drawn with a baseline set to bottom by default, making the text not visible within the canvas area if its drawn at 0, 0 position.
You'd also need to set the canvas's width and height before drawing the text.
var texttodraw = "hello world";
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
ctx.font = '20px Verdana';
canvas.width = ctx.measureText(texttodraw).width;
canvas.height = 20;
ctx.font = '20px Verdana';
ctx.textBaseline="top";
ctx.fillText(texttodraw, 0, 0);
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
// check if image data array contains values other than 0
var data = imageData.data.filter(function(e) {
return e !== 0;
});
console.log(data);
I would like to use threshold filter on base64 string (data:image/png;base64,iVBOR...) using javaScript like this:
function threshold(base64) {
some action whith base64 string...
return base64; //base64 is updated by threshold filter
}
Is it possible and if it is, how can I do this?
var base64string = "data:image/png;base64,iVBOR..........",
threshold = 180, // 0..255
ctx = document.createElement("canvas").getContext("2d"),
image = new Image();
image.onload = function() {
var w = ctx.canvas.width = image.width,
h = ctx.canvas.height = image.height;
ctx.drawImage(image, 0, 0, w, h); // Set image to Canvas context
var d = ctx.getImageData(0, 0, w, h); // Get image Data from Canvas context
for (var i=0; i<d.data.length; i+=4) { // 4 is for RGBA channels
// R=G=B=R>T?255:0
d.data[i] = d.data[i+1] = d.data[i+2] = d.data[i+1] > threshold ? 255 : 0;
}
ctx.putImageData(d, 0, 0); // Apply threshold conversion
document.body.appendChild(ctx.canvas); // Show result
};
image.src = base64string;
MDN - putImageData
MDN - getImageData
I'm loading a PNG and try to check, whether it is fully opaque, meaning alpha channel is near 100% over the whole image. Therefore, I use the canvas and 2D-Context to get the pixel data and loop through it checking the alpha value.
To my surprise i get whole areas of zeros (RGBA = [0000]) where it obviously shouldn't.
Browser in focus: chrome 50.0.2661.87
Here is my code, it is embedded in a ThreeJS environment:
var imageData = zipHandler.zip.file(src); // binary image data
var texture = new THREE.Texture();
var img = new Image();
img.addEventListener( 'load', function ( event ) {
texture.imageHasTransparency = false; // extend THREEJS Texture by a flag
if (img.src.substring(imgSrc.length-4).toLowerCase().indexOf("png") > -1
|| img.src.substring(0, 15).toLowerCase().indexOf("image/png") > -1) {
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
context.drawImage(img, 0, 0, img.width, img.height );
var pixDataContainer = context.getImageData(0, 0, img.width, img.height);
var pixData = pixDataContainer.data;
// search for pixel.alpha < 250
for (var pix = 0, pixDataLen = pixData.length; pix < pixDataLen; pix += 4) {
if (pixData[pix+3] < 250) {
texture.imageHasTransparency = true;
break;
}
}
}
texture.image = img;
texture.needsUpdate = true;
this.removeEventListener('load', arguments.callee, false);
}, false );
var fileExtension = src.substr(src.lastIndexOf(".") + 1);
img.src = "data:image/"+fileExtension+";base64,"+ btoa(imageData.asBinary());
The order is correct: first define new Image(), then the onload function and then the source.
Solved. The image was larger than the canvas, so when context.drawImage() was started, only parts of the area was filled. I've set the canvas dimensions according to the image size, so now it works and we have
// ...
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
canvas.width = img.width; // !!!!!
canvas.height = img.height; // !!!!
context.drawImage(img, 0, 0, img.width, img.height );
var pixDataContainer = context.getImageData(0, 0, img.width, img.height);
var pixData = pixDataContainer.data;
// ...
I got it working using crop as recommended. Here is how I got it with the plugin. The if statement is only because I have multiple crop sizes, the circular crop is only for square images.
canvas.width = width;
canvas.height = height;
var context = canvas.getContext("2d");
context.drawImage(this.image, 0, 0, sw, sh, dx, dy, dw, dh);
if (width==height){
context.globalCompositeOperation='destination-in';
context.beginPath();
context.arc(width/2,height/2,height/2,0,Math.PI*2);
context.closePath();
context.fill();
}
var imageData = canvas.toDataURL('image/png');
return imageData;
},
-- Original Question --
I'm using a jQuery plugin called CropBox which I have set up to export a 300x300 image. I am trying to take the square image and add an overlay that will make the image appear round, adding white corners or subtracting the overlay and have transparent corners.
What I'm going for.
The plugin uses a portion of the canvas to create the image. Once the image is captured I'm looking to add the overlay.
Adding my image and trying to draw the image.
var overlay = new Image();
overlay.src = 'MyOverlay.png';
context.drawImage(overlay, 0, 0);
Then I get lost on how to add this to imageData. It should start at 0, 0 too, any input would be appreciated.
Part of the plugin:
(function ($) {
var cropbox = function(options, el){
var el = el || $(options.imageBox),
obj =
{
state : {},
ratio : 1,
options : options,
imageBox : el,
thumbBox : el.find(options.thumbBox),
spinner : el.find(options.spinner),
image : new Image(),
getDataURL: function ()
{
var width = this.thumbBox.width(),
height = this.thumbBox.height(),
canvas = document.createElement("canvas"),
dim = el.css('background-position').split(' '),
size = el.css('background-size').split(' '),
dx = parseInt(dim[0]) - el.width()/2 + width/2,
dy = parseInt(dim[1]) - el.height()/2 + height/2,
dw = parseInt(size[0]),
dh = parseInt(size[1]),
sh = parseInt(this.image.height),
sw = parseInt(this.image.width);
canvas.width = width;
canvas.height = height;
var context = canvas.getContext("2d");
context.drawImage(this.image, 0, 0, sw, sh, dx, dy, dw, dh);
var imageData = canvas.toDataURL('image/png');
return imageData;
},
getBlob: function()
{
var imageData = this.getDataURL();
var b64 = imageData.replace('data:image/png;base64,','');
var binary = atob(b64);
var array = [];
for (var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {type: 'image/png'});
},