Html5 Canvas Todataurl Returns Blank

HTML5 Canvas toDataURL returns blank

My intuition says that everything from var imageData = … should go into the img.onload function.

That means, at the relevant part the code becomes:

img.onload = function() {
canvas.width = width;
canvas.height = height;
ctx.drawImage(img, 0, 0, width, height);

var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);

document.body.appendChild(canvas); //picture gets uploaded

// Generate the image data

var Pic = canvas.toDataURL("image/png");

console.log(Pic); // => returns base64 value which when tested equivalent to blank
Pic = Pic.replace(/^data:image\/(png|jpg);base64,/, "")

// Sending image to Server
$.ajax({
// …
});
};
img.src = datauri;

The reason is that the line

ctx.drawImage(img, 0, 0, width, height);

correctly executes after the image has been loaded. But unfortunately, you don’t wait for loading when this line gets executed:

var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);

and all subsequent lines.

The image needs to be loaded in order to draw it on the canvas. The canvas needs to contain the loaded image in order to call getImageData.

canvas + drawImage, toDataURL returns blank image

$(document).ready(function() {   var canvas = document.getElementById('canvas');   var context = canvas.getContext('2d');   var imageObj = new Image();
imageObj.onload = function() { context.drawImage(imageObj, 0, 0, 200, 200); var pngUrl = canvas.toDataURL(); console.log(pngUrl); $('#client_avatar').attr('src', pngUrl); };
imageObj.crossOrigin = 'anonymous'; //not necessary, if image hosted on same server imageObj.src = 'https://i.imgur.com/Q6aZlme.jpg';});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><canvas id="canvas" width="200" height="200"></canvas><img id="client_avatar">

Canvas toDataURL() returns blank image

Most likely there's some async event between the time you draw to the canvas and the time you call toDataURL. By default the canvas is cleared after every composite. Either prevent the canvas from being cleared by creating the WebGL context with preserveDrawingBuffer: true as in

var gl = canvas.getContext("webgl", {preserveDrawingBuffer: true});

or make sure toDataURL is called before exiting whatever event you're using to render. For example if you do this

function render() {
drawScene();
requestAnimationFrame(render);
}
render();

And somewhere else do this

someElement.addEventListener('click', function() {
var data = someCanvas.toDataURL();
}, false);

Those 2 events, the animation frame, and the click are not in sync and the canvas may be cleared between calling them. Note: The canvas won't appear cleared as it's double buffered but the buffer toDataURL and other commands that effect that buffer are looking at is cleared.

The solution is either use preserveDrawingBuffer or make your call to toDataURL inside the same event as rendering. For example

var captureFrame = false;

function render() {
drawScene();

if (captureFrame) {
captureFrame = false;
var data = someCanvas.toDataURL();
...
}

requestAnimationFrame(render);
}
render();

someElement.addEventListener('click', function() {
captureFrame = true;
}, false);

What's the point of preserveDrawingBuffer: false which is the default? It can be significantly faster, especially on mobile to not have to preserve the drawing buffer. Another way to look at it is the browser needs 2 copies of your canvas. The one you're drawing to and the one it's displaying. It has 2 ways to deal with these 2 buffers. (A) double buffer. Let you draw to one, display the other, swap the buffers when you're done rendering which is inferred from exiting any event that issued draw commands (B) Copy the contents of the buffer you're drawing to do the buffer that's being displayed. Swapping is much faster than copying. So, swapping is the default. It's up to the browser what actually happens. The only requirement is that if preserveDrawingBuffer is false that the drawing buffer get cleared after a composite (which is yet another async event and therefore unpredictable) if preserveDrawingBuffer is true then it must copy so that the drawingbuffer's contents is preserved.

Note that once a canvas has a context it will always have the same context. So in other words let's say you change the code that initializes the WebGL context but you still want to set preserveDrawingBuffer: true

There are at least 2 ways.

find the canvas first, get a context on it

since the code later will end up with the same context.

<script>
document.querySelector('#somecanvasid').getContext(
'webgl', {preserveDrawingBuffer: true});
</script>
<script src="script/that/will/use/somecanvasid.js"></script>

Because you've already created a context for that canvas whatever script comes after will get the same context.

augment getContext

<script>
HTMLCanvasElement.prototype.getContext = function(origFn) {
return function(type, attributes) {
if (type === 'webgl') {
attributes = Object.assign({}, attributes, {
preserveDrawingBuffer: true,
});
}
return origFn.call(this, type, attributes);
};
}(HTMLCanvasElement.prototype.getContext);
</script>
<script src="script/that/will/use/webgl.js"></script>

In this case any webgl context created after augmenting the getContext will have preserveDrawingBuffer set to true.

html5 canvas toDataURL returns blank image

You are first calling loadImages, then getting the data URL right after that loadImages call. However, as your loadImages implementation shows, calling it merely starts the loading process; the callback is called when all images have been loaded, which is some time in the future.

Currently you're getting a blank image because the images have not been loaded yet, so your callback is not called yet, and as a result your canvas is still empty.

In short, everything that relies on the images having being loaded (e.g. your expected toDataURL result) should be executed when those images are actually loaded - thus in the callback.

loadImages(sources, function(images) {
context.drawImage(images.darthVader, 250, 30, 250, 250);
context.drawImage(images.yoda, 530, 30, 250, 250);

var dataURL = canvas.toDataURL();
document.getElementById("canvasImg").src = dataURL;
});

Canvas toDataURL() returns blank image in Firefox even with .onload and callbacks

There’s a bug open in Firefox about this: drawImage() fails silently when drawing an SVG image without @width or @height.

You can fix it by adding (go figure) width and height to the SVG:

<svg
xmlns="http://www.w3.org/2000/svg"
width="119" height="119" viewBox="0 0 119 119">

Updated Codepen

Blank image when executing canvas.toDataUrl()

So after much trawling through StackOverflow I found the function drawScene() which (somehow?) force toDataURL() to return the image data as required:

var canvas = $("#mandelbox-canvas")[0];
drawScene()
var imgData = canvas.toDataURL("image/png").split(',')[1];
console.log(imgData)

html5 canvas toDataURL returns blank image

Have you seen this comment in the PHP docs for base64_decode?

If you want to save data that is derived from a Javascript
canvas.toDataURL() function, you have to convert blanks into plusses.
If you do not do that, the decoded data is corrupted:

<?php
$encodedData = str_replace(' ','+',$encodedData);
$decocedData = base64_decode($encodedData);
?>


Related Topics



Leave a reply



Submit