context.drawImage behaving weirdly - javascript

I have:
<canvas id='canvas' width="300" height="409" style="border:2px solid darkblue" >
</canvas>
And then:
<script type="text/javascript">
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var image = new Image();
image.src = 'http://4.bp.blogspot.com/...-21+Kingfisher.JPG';
alert(image.src);
context.drawImage(image, 0, 0, 300, 400);
</script>
In IE 10, the image is painted as "to be expected". However, when I remove that alert statement, the picture is not painted!
In Chrome, no image is painted on my local PC, whether with or without the alert statement.
What could be happening? The fiddle is here

That is because loading images is an asynchronous operation. The alert call helps the browser to wait a bit so the image loading can finish. Therefor the image will be available at drawImage that follows.
The correct way to implement this is to use the code this way:
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var image = new Image(); //document.createElement('img'); for Chrome due to issue
// add a onload handler that gets called when image is ready
image.onload = function () {
context.drawImage(this, 0, 0, 300, 400);
}
// set source last so onload gets properly initialized
image.src = 'http://4.bp.blogspot.com/...-21+Kingfisher.JPG';
The draw operation inside the callback for onload could just as easily have been a function call:
image.onload = nextStep;
// ...
function nextStep() {
/// draw image and other things...
}

Related

image height displays 0, requestAnimationFrame(); javascript html5 game

I'm programming a game
I have the next settings:
HTML game.html
<canvas id="canvas" width="288" height="512"></canvas>
<script src="game.js"></script>
JAVASCRIPT game.js
var document;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
//load images
var pipeNorth = new Image();
pipeNorth.src = "images/pipeNorth.png";
function draw(){
/*code */
alert(pipeNorth.height);
requestAnimationFrame(draw);
}
draw();
PROBLEM
If I set an alert displaying the image height, it shows 0 during the first two or three alerts, then it starts showing the real height.
Why does this happen? How do I fix this? I think it means the image is not fully loaded when the game begins?
From my experience this happens because the document rendering takes some time. My technique for this case is a time delay:
function draw(){
var delay = 200;//Your delay in milliseconds
setTimeout(function(){
/*code */
alert(pipeNorth.height);
requestAnimationFrame(draw);
},delay);
}
Is it usable for you?
Yes you are right the image is not fully loaded when the game begins.to fix this you simply have to use the "load" event :
var document;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
//load images
var pipeNorth = new Image();
pipeNorth.src = "images/pipeNorth.png";
function draw(){
/*code */
alert(pipeNorth.height);
requestAnimationFrame(draw);
}
pipeNorth.addEventListener("load",function(){
//this function will execute when the image is fully loaded
draw();
});

Execute Function After Canvas toDataURL() Function is Complete

I'm converting images to base64 using canvas. What i need to do is convert those images and then show the result to the user (original image and base64 version). Everything works as expected with small images, but when i try to convert large images (>3MB) and the conversion time increases, the base64 version is empty.
This might be is caused because the result is shown before the toDataURL() function is completed.
I need to show the result after all the needed processing has ended, for testing purposes.
Here's my code:
var convertToBase64 = function(url, callback)
{
var image = new Image();
image.onload = function ()
{
//create canvas and draw image...
var imageData = canvas.toDataURL('image/png');
callback(imageData);
};
image.src = url;
};
convertToBase64('img/circle.png', function(imageData)
{
window.open(imageData);
});
Even though i'm using image.onload() with a callback, i'm unable to show the result after the toDataURL() has been processed.
What am i doing wrong?
UPDATE: I tried both the solutions below and they didn't work. I'm using AngularJS and Electron in this project. Any way i can force the code to be synchronous? Or maybe some solution using Promises?
UPDATE #2: #Kaiido pointed out that toDataURL() is in fact synchronous and this issue is more likely due to maximum URI length. Since i'm using Electron and the image preview was for testing purposes only, i'm going to save the file in a folder and analise it from there.
Your code seems absolutely fine. Not sure why isn't working you. Maybe, there are some issues with your browser. Perhaps try using a different one. Also you could use a custom event, which gets triggered when the image conversion is competed.
// using jQuery for custom event
function convertToBase64(url) {
var image = new Image();
image.src = url;
image.onload = function() {
var canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
var ctx = canvas.getContext('2d');
ctx.drawImage(image, 0, 0);
var imageData = canvas.toDataURL();
$(document).trigger('conversionCompleted', imageData);
};
};
convertToBase64('4mb.jpg');
$(document).on('conversionCompleted', function(e, d) {
window.open(d);
});
This approach might work for you. It shows the image onscreen using the native html element, then draws it to a canvas, then converts the canvas to Base64, then clears the canvas and draws the converted image onto the canvas. You can then scroll between the top image (original) and the bottom image (converted). I tried it on large images and it takes a second or two for the second image to draw but it seems to work...
Html is here:
<img id="imageID">
<canvas id="myCanvas" style="width:400;height:400;">
</canvas>
Script is here:
var ctx;
function convertToBase64(url, callback)
{
var image = document.getElementById("imageID");
image.onload = function() {
var canvas = document.getElementById("myCanvas");
canvas.width = image.naturalWidth;
canvas.height = image.naturalHeight;
ctx = canvas.getContext("2d");
ctx.drawImage(image,0,0);
var imageData = canvas.toDataURL('image/png');
ctx.fillStyle ="#FFFFFF";
ctx.fillRect(0,0,canvas.width,canvas.height);
callback(imageData);
};
image.src = url;
};
var imagename = 'images/bigfiletest.jpg';
window.onload = function () {
convertToBase64(imagename, function(imageData) {
var myImage = new Image();
myImage.src = imageData;
ctx.drawImage(myImage,0,0);
});
}
Note that I also tried it without the callback and it worked fine as well...

Fetching image from url with javascript

I am trying to show an image on my page from a different url.
<body>
<div id="container">
<br />
<canvas width="500px" height="375px" id="canvas">
</canvas>
<img src="http://yinoneliraz-001-site1.smarterasp.net/MyPicture.png" />
</div>
<script>
var img = new Image;
img.src = "http://yinoneliraz-001-site1.smarterasp.net/MyPicture.png";
var timer = setInterval(function () { MyTimer() }, 200);
function MyTimer() {
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0,500,675);
img = new Image;
img.src = "http://yinoneliraz-001-site1.smarterasp.net/MyPicture.png";
}
</script>
The image on the other site is being saved every 1.5 seconds.
The result is that I cant view the image.
Any ideas why?
Thanks!
1. Cache issue
Your MyPicture.png returns Cache-Control: max-age=31536000 in HTTP response. So browser may get image from its cache on second time. You need to add query string something like thie:
img.src = "http://yinoneliraz-001-site1.smarterasp.net/MyPicture.png?time=" + (new Date()).getTime();
2. Too short fetching period.
I think fetching period 200msec is too short. It's better to bind onload event handler to the image object. See How to fetch a remote image to display in a canvas?.
function copyCanvas(img) {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
}
function loadImage() {
var img = new Image();
img.onload = function () {
copyCanvas(img);
};
img.src = "http://yinoneliraz-001-site1.smarterasp.net/MyPicture.png?time=" + (new Date()).getTime();
}
3. Double buffering
I think your script intend to pre-load image. So it's better to make a double buffering.
Single Buffering version: http://jsfiddle.net/tokkonoPapa/dSJmy/1/
Double Buffering version: http://jsfiddle.net/tokkonoPapa/dSJmy/2/
You have not defined canvas. Define it first with:
var canvas = document.getElementById('canvas');
Then, use load event to draw image on to the canvas.
Checkout the fiddle, LoadImgURL which demonstrates the whole process.

canvas to image shows as no image (blank)

I'm working on converting a canvas to an image using dataurl. I have the following code that outputs no error in console. Seems to work somewhat, but when i access the dataurl it shows a blank image.
window.onload = function() {
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var imageObj = new Image();
imageObj.onload = function() {
var myImage = context.drawImage(imageObj, 0, 0);
var myImg = canvas.toDataURL("image/png");
document.getElementById("canvasimg").setAttribute("src", myImg);
};
imageObj.src = "http://img801.imageshack.us/img801/5641/3cc67ca1a74049ce99bc92b.png";
};
<canvas id="myCanvas" width="578" height="400"></canvas>
<img id="canvasimg" alt="" src="">
Look at what you are doing. You are drawing the image when the image loads, but you are converting it to a data url before the image has been drawn! Move that toDataURL call and the setAttribute call INSIDE the onload function.
Testing the code you have posted, I get a Security Error raised. Which is to be expected. The canvas has a clean-origin flag, and once that flag is false, you can't pull data out of it.
Here's a more detailed, related question
Documentation linked to in the answer

Why doesn't image show on load, but shows on refresh?

I'm playing with the canvas element in HTML5 and I have noticed a peculiar behavior. On initial load, an image I'm displaying does not show. However, when I refresh the browser, it displays appropriately. I've used IE9 and Chrome. Both behave identically. The JavaScript code looks like this:
window.onload = load;
function load() {
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
context.fillRect(0, 0, 640, 400);
var image = new Image();
image.src = "Images/smiley.png";
context.drawImage(image, 50, 50);
}
The rectangle draws correctly both times, it's the smiley that only shows on a browser refresh.
I'm in the process of learning HTML5 and JavaScript. I'm sure I'm just doing something stupid, but I can't figure it out.
Images load asynchronously, so only after refresh it loads early enough because it's cached. Normally it isn't loaded yet at the time you call drawImage. Use onload:
var image = new Image();
image.src = "Images/smiley.png";
image.onload = function() {
context.drawImage(image, 50, 50);
};
This happened with me as well (only for IE9 for me) anyways, i found a simple solution.
Set the background of the canvas to the initial image you wish to display.
var canvas = document.getElementById("canvas");
canvas.style.background="url('image.png')";
That should work!
Actually, even just using image.onload = function() {}, you can still run into problems. Do use this technique (that's not at all what I'm saying), but move it to the bottom of your page.
As an example, I have a social networking site that uses canvas to show the profile photo (URI stored to the DB), and print it to canvas, then overlay a logo.
<section id="content">
<article id="personalbox" >
<h2>Hi! My name is {profile_name}</h2>
<a id="friendbutton" href=""><img src="views/default/images/friend.png" width="12" height="12" /><span>Add {profile_name} as a friend?</span></a>
<video id="profilevideo" width="240" height="144">DEBUG: Video is not supported.</video>
<canvas id="profilecanvas" width="240" height="144" >DEBUG: Canvas is not supported.</canvas>
<a id="gallerytextlink" href="gallery.html" >Click to visit {profile_name} Gallery</a>
<table id="profileinfotable1">
...
</section>
<script type="text/javascript">
function init() {
var cvs = document.getElementById("profilecanvas");
var ctx = cvs.getContext("2d");
var img = new Image();
img.src = "uploads/profile/{profile_photo}";
img.onload = function() {
// Ignore. I was playing with the photo.
ctx.drawImage(img, 42, 32, 186, 130, cvs.width/2 - (186-42)/2, cvs.height/2 - (130-32)/2, 186-42, 130-32);
drawLogo(cvs,ctx);
}
}
function drawLogo(cvs,ctx) {
var logo = "Enter Logo Here.";
ctx.fillStyle = "rgba(36,36,36,0.6)";
ctx.strokeStyle = "rgba(255,255,255,0.3)";
ctx.font = "bold italic 6pt Serif";
ctx.textAlign = "left";
ctx.textBaseline = "middle" ;
ctx.save();
ctx.strokeText(logo, 4, cvs.height-11);
ctx.strokeText(logo, 6, cvs.height-11);
ctx.strokeText(logo, 4, cvs.height-9);
ctx.strokeText(logo, 6, cvs.height-9);
ctx.fillText(logo, 5, cvs.height-10);
ctx.restore();
}
window.onload = init;
</script>
Ideally, this would go all the way at the bottom before the end </body> tag, but I put it up higher because of my template system. Apparently, this gives the image time to load after the canvas element has been drawn to the screen and is ready to receive input.
I can't rely on setting the background of the canvas, and I have no desire to contend with refreshes. For whatever reason, just including the script with img.onload = function() {} was not enough. Move it lower, and save yourself the headaches.

Categories