I have problem with my code, which is quite similar to this CodePen.
var img = new Image();
img.src = 'https://upload.wikimedia.org/wikipedia/commons/thumb/6/63/Diceros_bicornis.jpg/320px-Diceros_bicornis.jpg';
img.crossOrigin = "Anonymous"
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
img.onload = function() {
ctx.drawImage(img, 0, 0);
img.style.display = 'none';
};
var color = document.getElementById('color');
function pick(event) {
var x = event.layerX;
var y = event.layerY;
var pixel = ctx.getImageData(x, y, 1, 1);
var data = pixel.data;
var rgba = 'rgba(' + data[0] + ', ' + data[1] +
', ' + data[2] + ', ' + (data[3] / 255) + ')';
color.style.background = rgba;
color.textContent = rgba;
}
canvas.addEventListener('mousemove', pick);
<!-- Learn about this code on MDN: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas -->
<canvas id="canvas" width="300" height="227" style="float:left"></canvas>
<div id="color" style="width:200px;height:50px;float:left"></div>
It somehow certainly works when the page is first open. But when I refresh the page with F5, it SOMETIMES starts throwing the tainted canvas error. Only when I click x to close the tab, and then click the link again to open a brand new tab will it certainly work again.
I already have img.crossOrigin = "Anonymous".
That sounds like a chrome bug, but easily workaround-able :
Set your crossOrigin attribute first.
The first time the request is made, the crossOrigin attribute is set before the image has loaded, hence your browser will redo the request.
But when you reload the page, the image is already cached, and loads before the crossOrigin attribute is set. Then your canvas will be tainted.
For similar little bugs cases, you should also define your onload event handler before setting this src attribute :
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var img = new Image();
img.crossOrigin = "Anonymous"
img.onload = function() {
ctx.drawImage(img, 0, 0);
img.style.display = 'none';
};
// set the src last
img.src = 'https://upload.wikimedia.org/wikipedia/commons/thumb/6/63/Diceros_bicornis.jpg/320px-Diceros_bicornis.jpg';
var color = document.getElementById('color');
function pick(event) {
var x = event.layerX;
var y = event.layerY;
var pixel = ctx.getImageData(x, y, 1, 1);
var data = pixel.data;
var rgba = 'rgba(' + data[0] + ', ' + data[1] +
', ' + data[2] + ', ' + (data[3] / 255) + ')';
color.style.background = rgba;
color.textContent = rgba;
}
canvas.addEventListener('mousemove', pick);
<!-- Learn about this code on MDN: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas -->
<canvas id="canvas" width="300" height="227" style="float:left"></canvas>
<div id="color" style="width:200px;height:50px;float:left"></div>
right now I am writing a small chrome extension. the extension grabs the Bing Image of the Day and sets it as the body background image, and then the extension also grabs the weather, time, date, etc. The problem is that sometimes the image of the day is for example, bright on one side and dark on the other. So, no matter what color the text is, some of it is illegible. How can I determine what color each text should be depending on the background image color behind a SPECIFIC text?
Thanks in advance.
You can use jQuery's attr() function. For example, if you img tag has an id attribute of 'my_image':
<img id="my_image" src="first.jpg"/>
Jquery
$("#my_image").attr("src","second.jpg");
I got something to work.... It is kind of makeshift and not foolproof, but I found a script that calculates overall brightness, which then allows the script to decide whether it should display black or white text. Seems to work well, as of now. Here it is:
function getImageBrightness(imageSrc) {
var img = document.createElement("img");
img.src = imageSrc;
img.style.display = "none";
document.body.appendChild(img);
var colorSum = 0;
img.onload = function () {
// create canvas
var canvas = document.createElement("canvas");
canvas.width = this.width;
canvas.height = this.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var data = imageData.data;
var r, g, b, avg;
for (var 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;
}
brightness = Math.floor(colorSum / (this.width * this.height));
console.log(brightness);
if (brightness < 150) {
$(".contrast").css("color", "white");
} else {
$(".contrast").css("color", "black");
}
}
}
credit to: https://jsfiddle.net/s7Wx2/
Hello senior developers and programmers,
I am working with a script, that is integrated with jspdf,
basically the script is supposed to convert my website content to pdf,
There are two types of concept to this scripts.
the selectable and canvas,
the canvas been for complex webpages, e.g tables, spaces, background images.
it works successfully but my pdf is not to clear and just stays in the middle
this is the javascript code
//Download as a canvas if contains complex data
$('.wppdf-download-canvas').click(function() {
var pdfname = $(this).attr('name');
var htmlSource = $(this).siblings('.wppdf');
var canvasToImage = function(canvas){
var img = new Image();
var dataURL = canvas.toDataURL('image/png');
img.src = dataURL;
return img;
};
var canvasShiftImage = function(oldCanvas,shiftAmt){
shiftAmt = parseInt(shiftAmt, 10) || 0;
if(!shiftAmt){ return oldCanvas; }
var newCanvas = document.createElement('canvas');
newCanvas.height = oldCanvas.height - shiftAmt;
newCanvas.width = oldCanvas.width;
var ctx = newCanvas.getContext('2d');
var img = canvasToImage(oldCanvas);
ctx.drawImage(img,0, shiftAmt, img.width, img.height, 0, 0, img.width, img.height);
return newCanvas;
};
var canvasToImageSuccess = function(canvas){
var pdf = new jsPDF2('p','pt'),
pdfInternals = pdf.internal,
pdfPageSize = pdfInternals.pageSize,
pdfScaleFactor = pdfInternals.scaleFactor,
pdfPageWidth = pdfPageSize.width,
pdfPageHeight = pdfPageSize.height,
totalPdfHeight = 0,
htmlPageHeight = canvas.height,
htmlScaleFactor = canvas.width / (pdfPageWidth * pdfScaleFactor),
safetyNet = 0;
while(totalPdfHeight < htmlPageHeight && safetyNet < 15){
var newCanvas = canvasShiftImage(canvas, totalPdfHeight);
pdf.addImage(newCanvas, 'png', 15, 15, pdfPageWidth - (pdfPageWidth * .0 ), 0, null, 'NONE');
totalPdfHeight += (pdfPageHeight * pdfScaleFactor * htmlScaleFactor);
safetyNet++;
}
pdf.save(pdfname);
};
i tried changing the size using this var pdf = new jsPDF('p','pt','a4');
because i wanted it bigger, but nothing happns when i try to download my page.
Any advice
so i got this, with a little bit of research online
pdf.addImage(newCanvas, 'png', -120, 10, 700, 580);
and that solved the problem.
I'm trying to make a backend for publishing simple jigsaw-puzzle games. The game uses 12 premade shapes as masks for making the 12 puzzle pieces. I found the excellent Canvas global CompositeOperation tutorial, and tested it.
The application I'm making is using ajax to send each finished piece to the serverside .php-script. The user loads an image (600x400) using SSE and the app moves the original image inside tempCanvas according to the values of the arrays arr_x and arr_y It's supposed to happen in a for-loop:
function drawPieces(){
var canvas = document.getElementById("myCanvas");
var context =canvas.getContext("2d");
var tempCanvas = document.getElementById("tempCanvas");
var tempContext = tempCanvas.getContext("2d");
var img_mask = new Image();
var w;
var h;
var cvd0,cvd1,cvd2,cvd3,cvd4,cvd5,cvd6,cvd7,cvd8,cvd9,cvd10,cvd11;
var arr_data = [cvd0,cvd1,cvd2,cvd3,cvd4,cvd5,cvd6,cvd7,cvd8,cvd9,cvd10,cvd11];
var arr_x = [0,-136,-289,-414,0,-115,-270,-415,0,-118,-288,-415];
var arr_y = [0,0,0,0,-113,-111,-111,-124,-244,-256,-243,-241];
var img_bg = new Image(600, 400);
for (var i = 0; i<arr_x.length; i++) {
img_bg = original;
// get the mask
img_mask.src = "img/mask"+i+".png";
w = img_mask.width;
h = img_mask.height;
console.log("w = ", img_mask.width, " h = ", img_mask.height);
tempCanvas.width = w;
tempCanvas.height = h;
// Her lages maska
tempContext.drawImage(img_mask,0,0);
tempContext.globalCompositeOperation = 'source-in';
tempContext.drawImage(img_bg,arr_x[i],arr_y[i]);
myCanvas.width = w;
myCanvas.height = h;
// Draws tempCanvas on to myCanvas
console.log("tempCanvas: ", tempCanvas, " img_mask.src = ", img_mask.src);
context.drawImage(tempCanvas, 0, 0);
arr_data[i] = myCanvas;
sendData(arr_data[i], [i]);
};
}
Sending the image data to the server:
function sendData(cvd, index){
var imageData = cvd.toDataURL("image/png");
var ajax = new XMLHttpRequest();
ajax.open("POST", "testsave.php", false);
// ajax.onreadystatechange=function(){
// console.log("index = ", index)
// };
ajax.setRequestHeader('Content-Type', 'application/upload');
ajax.send(imageData+"<split>"+index);
};
I got a button to start drawPieces. But I get a number of issues. Firefox throws an error:
InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable: context.drawImage(tempCanvas, 0, 0);
But if I click the button again the loop is run and I get 12 pieces in my folder. (Using xammp for now). But the pieces are cut wrong! The app doesn't seem to load the correct mask each time the loop runs.
So I tested it without using a loop by having 12 different functions where each function is calling the next one. It worked with one function, but started messing up the masks when I added more:
function drawPiece0(){
img_bg = original;
img_mask.src = "img/mask0.png";
tempCanvas.width = 185;
tempCanvas.height = 145;
// Her lages maska
tempContext.drawImage(img_mask,0,0);
tempContext.globalCompositeOperation = 'source-in';
tempContext.drawImage(img_bg,0,0);
myCanvas.width = 185;
myCanvas.height = 145;
// Tegner tempCanvas over på myCanvas
context.drawImage(tempCanvas, 0, 0);
cvd0 = myCanvas;
sendData(cvd0, 0);
// drawPiece1();
};
Something is absolutely wrong in my setup, but I can't figure out what it is. Someone help me please!
By the way, here is my .php-script too:
<?php
if (isset($GLOBALS["HTTP_RAW_POST_DATA"]))
{
// Get the data
$imageData=$GLOBALS['HTTP_RAW_POST_DATA'];
$parts = explode("<split>", $imageData);
$imageData = $parts[0];
$index= $parts[1];
// Remove the headers (data:,) part.
// A real application should use them according to needs such as to check image type
$filteredData=substr($imageData, strpos($imageData, ",")+1);
// Need to decode before saving since the data we received is already base64 encoded
$unencodedData=base64_decode($filteredData);
// Save file.
$fp = fopen( "pieces/".$index.".png", "wb" );
fwrite( $fp, $unencodedData);
fclose( $fp );
}
?>
Problem
The problem is that image loading is asynchronous which means they load in the background while your code is continuing.
That means the images won't be ready (loaded and decoded) when you try to use them with drawImage resulting in the error. The error is indirect here though as w and h do not get valid values for the canvas which means canvas will be 0 width and 0 height which will trigger the actual error when attempted drawn.
The reason why it "works" the second time is because an image exists in the browser's cache and may be able to provide the image before it's used.
Another problem is that in your loop you are overwriting the image variable so only the last image will be used when loaded.
Solution
The solution is to make or use an image loader before you start the loop. It's easy to make one but for simplicity I will use the YAIL loader in this example (disclaimer: author ibid) but any kind of loader will do as long as you use a callback for the images:
function drawPieces(){
var canvas = document.getElementById("myCanvas");
var context =canvas.getContext("2d");
var tempCanvas = document.getElementById("tempCanvas");
var tempContext = tempCanvas.getContext("2d");
var img_mask;
var w;
var h;
var cvd0,cvd1,cvd2,cvd3,cvd4,cvd5,cvd6,cvd7,cvd8,cvd9,cvd10,cvd11;
var arr_data = [cvd0,cvd1,cvd2,cvd3,cvd4,cvd5,cvd6,cvd7,cvd8,cvd9,cvd10,cvd11];
var arr_x = [0,-136,-289,-414,0,-115,-270,-415,0,-118,-288,-415];
var arr_y = [0,0,0,0,-113,-111,-111,-124,-244,-256,-243,-241];
var img_bg;
// using some image(s) loader
var loader = new YAIL({done: draw});
for (var i = 0; i<arr_x.length; i++)
loader.add("img/mask"+i+".png");
loader.load(); // start loading images
// this is called when images has loaded
function draw(e) {
for (var i = 0; i<arr_x.length; i++) {
//img_bg = original; ??
// get the mask
var img_mask = e.images[i]; // loaded images in an array
w = img_mask.width; // now you will have a valid
h = img_mask.height; // dimension here
console.log("w = ", img_mask.width, " h = ", img_mask.height);
tempCanvas.width = w;
tempCanvas.height = h;
// Her lages maska
tempContext.drawImage(img_mask,0,0);
tempContext.globalCompositeOperation = 'source-in';
tempContext.drawImage(img_bg,arr_x[i],arr_y[i]);
myCanvas.width = w;
myCanvas.height = h;
// Draws tempCanvas on to myCanvas
console.log("tempCanvas: ", tempCanvas, " img_mask.src = ", img_mask.src);
context.drawImage(tempCanvas, 0, 0);
arr_data[i] = myCanvas;
sendData(arr_data[i], [i]);
}
};
}
Note: loading images will make your code asynchronous in nature. If the code depends on some other function right after the pieces has been drawn then you must invoke that function from within the inner one after the loop has finished.
Hope this helps. If the pieces still doesn't show correctly please set up a fiddle with the images uploaded to f.ex. imgur.com so we can dig deeper into the problem.
Hope this helps!
Is it possible to use canvas.toDataURL() in Adobe AIR?
When I try I get the following error:
Error: SECURITY_ERR: DOM Exception 18
Adobe AIR enforces same origin for images used in the canvas API. Once you've used something from another domain in your canvas, you can't get pixel data back out of it. However, you can make use of the Loader class to get the pixel data, and convert it into a canvas ImageData.
For example:
function getDataURL(url, callback) {
var loader = new air.Loader();
loader.contentLoaderInfo.addEventListener(air.Event.COMPLETE, function(event) {
var bitmapData = loader.content.bitmapData;
var canvas = document.createElement('canvas');
canvas.width = bitmapData.width;
canvas.height = bitmapData.height;
var context = canvas.getContext('2d');
var imageData = context.createImageData(canvas.width, canvas.height);
var dst = imageData.data;
var src = bitmapData.getPixels(bitmapData.rect);
src.position = 0;
var i = 0;
while (i < dst.length) {
var alpha = src.readUnsignedByte();
dst[i++] = src.readUnsignedByte();
dst[i++] = src.readUnsignedByte();
dst[i++] = src.readUnsignedByte();
dst[i++] = alpha;
}
context.putImageData(imageData, 0, 0);
callback(canvas.toDataURL());
});
loader.load(new air.URLRequest(url));
}
window.addEventListener('load', function() {
getDataURL('http://www.google.com/images/logo.gif', function(dataURL) {
air.trace(dataURL);
});
}, false);