0

I have a html code as follow:

<canvas id="canvas1" width="200" height="200"></canvas>

and a javaScript code as follow:

var can = document.getElementById('canvas1');
var ctx = can.getContext('2d');
var src="https://vignette2.wikia.nocookie.net/mint524/images/d/d7/Sky.jpg/revision/latest?cb=20160706152654.jpg"

var image = new Image();
image.onload = function(){
  ctx.drawImage(image,0,0,50,50);  
}
ctx.fillRect(50,50,50,50);
image.src = src

var img = new Image();
img.src = can.toDataURL();
document.body.appendChild(img);

I want to convert canvas to a img element, but I found I can not append the image in canvas to the img element. Detialed code is in here. Can anyone give some advises?

JustinGong
  • 41
  • 1
  • 8
  • Possible duplicate of [Tainted canvases may not be exported](https://stackoverflow.com/questions/22710627/tainted-canvases-may-not-be-exported) – Halim Sep 27 '17 at 11:41

3 Answers3

1

If you make sure that your image is not tainted - see this question and answer: Tainted canvases may not be exported, you can then change your code so you create the new image after your old image has loaded:

var can = document.getElementById('canvas1');
var ctx = can.getContext('2d');
var src = "//i.imgur.com/fHyEMsl.jpg";

var image = new Image();
image.crossOrigin = "anonymous";  

image.onload = function() {
  ctx.drawImage(image, 0, 0, 200, 200);

  var img = new Image();    // move this into the onload of the image to make sure the canvas has been drawn
  img.src = can.toDataURL("image/png");
  document.body.appendChild(img);
}
image.src = src;
<p>Canvas:</p>
<canvas id="canvas1" width="200" height="200"></canvas>
<p>Image should appear below:</p>
Pete
  • 57,112
  • 28
  • 117
  • 166
  • hello, I encounter another problem, When I use a high-resolution image rather than the small image. It shows error:"No 'Access-Control-Allow-Origin' header is present on the requested resource. ". How to solve it? see my new code here: https://jsfiddle.net/AndrewGong/mkx7f8un/9/ – JustinGong Sep 28 '17 at 06:39
0

The canvas acts very similar to an image.

When you use canvas.toDataURL and assign it to the image.src you are wasting a lot of memory. The image will be decoded from the dataURL and use up the same amount of RAM for pixels as the canvas, but the dataURL will also remain in memory.

Base64 Encoding is not designed for compactness. Each Base64 character encodes 6 bits but each Javascript character uses 16 bits. This makes the dataURL 2.667 times larger than if stored on disk, and in some extreme cases can be larger than the raw pixel data.

You could use canvas.toBlob() and construct the image from the blob and you would avoid the memory overhead of the redundent dataURL. But you are still left with the problem of tained canvas not being encoded to an image.

The easiest solution is to treat the canvas as an image. Add it to the DOM like you would an image and save yourself the hassle of trying to encode and decode an image format. What would you want from the image that the canvas will not do? The src? well that's the problem is it not.

const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
ctx.fillRect(0,0,300,150);
ctx.fillStyle = "white";
ctx.fillRect(10,10,280,130);
ctx.fillStyle = "Blue";
ctx.fillRect(15,15,270,120);
ctx.fillStyle = "white";
ctx.font = "28px arial";
ctx.fillText("Look like an Image", 20, 40);
ctx.fillText("Acts like an Image", 20, 70);
ctx.font = "20px arial";
ctx.fillText("Who cares if it's a Canvas", 20, 100);
ctx.textAlign = "right";
ctx.fillText("", 270, 125);


function copyCanvas(canvas){
    const c = canvas.cloneNode();
    c.getContext("2d").drawImage(canvas,0,0);
    return c;
}
document.body.appendChild(copyCanvas(canvas));
Blindman67
  • 51,134
  • 11
  • 73
  • 136
-2

For security reasons, your local drive is declared to be "other-domain" and will taint the canvas.

(That's because your most sensitive info is likely on your local drive!).

While testing try these workarounds:

  • wrap with time out the img export from canvas
  • Put all page related files (.html, .jpg, .js, .css, etc) on your desktop (not in sub-folders).
  • Post your images to a site that supports cross-domain sharing (like dropbox.com). Be sure you put your images in dropbox's public folder and also set the cross origin flag when downloading the image (var img=new Image(); img.crossOrigin="anonymous" ...)

setTimeout(
  function(){
  var can = document.getElementById('canvas1');
  var img = new Image();
  img.src = can.toDataURL();
  document.body.appendChild(img);
},2000);
ShlomyN
  • 426
  • 2
  • 5
  • 1
    Remember to credit [answers you use](https://stackoverflow.com/questions/22710627/tainted-canvases-may-not-be-exported) parts off. All content on SO is licensed under [cc by-sa 3.0 with attribution required](https://creativecommons.org/licenses/by-sa/3.0/). The other part of your answer doesn't make much sense in this context with the exception of the last bullet-point. –  Sep 27 '17 at 13:15
  • you are right, the last part is just to show the tainted img response – ShlomyN Sep 27 '17 at 13:54