Reputation: 109
Im loading a few images to my canvas and then after they load I want to click a button that saves that canvas image to my server. I can see the script works fine until it gets to the 'toDataURL' part and my function stops executing. What am I doing wrong? Here is my code:
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578"
height="200"></canvas>
<div>
<button onClick="saveCards();">Save</button>
</div>
<script>
function loadImages(sources, callback)
{
var images = {};
var loadedImages = 0;
var numImages = 0;
// get num of sources
for(var src in sources) {
numImages++;
}
for(var src in sources) {
images[src] = new Image();
images[src].onload = function() {
if(++loadedImages >= numImages)
{
callback(images);
}
};
images[src].src = sources[src];
}
}
var canvas =
document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var sources = {
great:
'images/great.jpg',
star:
'images/1Star.jpg', good:
'images/good.jpg'
};
loadImages(sources, function(images) {
context.drawImage(images.great,
0, 0, 80, 120);
context.drawImage(images.star, 80,
0, 80, 120);
context.drawImage(images.good, 160, 0, 80,
120);
});
</script>
<script type="text/javascript">
function saveCards()
{
var canvas=
document.getElementById("myCanvas");
alert("stops");
var theString= canvas.toDataURL();
var postData= "CanvasData="+theString;
var ajax= new XMLHttpRequest();
ajax.open("POST", 'saveCards.php', true);
ajax.setRequestHeader('Content-Type',
'canvas/upload');
ajax.onreadystatechange=function()
{
if(ajax.readyState == 4)
{
alert("image was saved");
}else{
alert("image was not saved");
}
}
ajax.send(postData);
}
</script>
</body>
</html>
Thank you for any help is it because the images are not loaded before toDataUrl is called? If so can you please help me fix it.
This is the php script:
<?php
if(isset($GLOBALS['HTTP_RAW_POST_DATA']));
{
$rawImage=$GLOBALS['HTTP_RAW_POST_DATA'];
$removeHeaders=
substr($rawImage,strpos($rawImage, ",")+1);
$decode=base64_decode($removeHeaders);
$fopen= fopen('images/image.png', 'wb');
fwrite($fopen, $decode);
fclose($fopen);
}
?>
I am getting a security error though.
Upvotes: 2
Views: 4999
Reputation: 109
I figured what I did wrong, but not really sure why it works now. In my actual code that I am using instead of images/image.png I was using the full url https://www.mywebsite.com/images/image.png For some reason when I just write the shortened images/image.png . It works fine. Thank you for all the help debugging and for your alternative solutions.
Upvotes: 0
Reputation: 470
In the specification for the canvas element it states:
Information leakage can occur if scripts from one origin can access information (e.g. read pixels) from images from another origin (one that isn't the same).
To mitigate this, bitmaps used with canvas elements are defined to have a flag indicating whether they are origin-clean. All bitmaps start with their origin-clean set to true. The flag is set to false when cross-origin images or fonts are used.
The toDataURL(), toDataURLHD(), toBlob(), getImageData(), and getImageDataHD() methods check the flag and will throw a SecurityError exception rather than leak cross-origin data.
The flag can be reset in certain situations; for example, when a CanvasRenderingContext2D is bound to a new canvas, the bitmap is cleared and its flag reset.
Since you are loading images from a different server into a canvas element, the work-around to be able to use toDataURL() is to "copy" the canvas into a new canvas element to reset the origin-clean flag to "true".
You can see an example of this here
Upvotes: 1