0

I have canvas and an <img> element in my page and I am simply trying to clone/copy what ever is drawn on the canvas to the img element. I don't have problem as long as I use drawing commands alone and clone the image but when I draw an image then it won't clone anything.

html:

<canvas id="canvas" width="600" height="400">Default Text (No JS)</canvas>

<img id="img" alt="This is dynamic image" src="https://www.gravatar.com/avatar/c585e7964ff782b11a41d19679e43e9d?s=48&d=identicon&r=PG&f=1" style="position:fixed;top:0;right:400px">

A simple HTML page with a canvas in the left and image element in the right side.

js:

var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var todo = 0;

drawImage(); //commenting this would clone the canvas
drawCloud(); 
checkAllDone();

function checkAllDone(){

  if (this.todo ==0) copyCanvas();

}
function drawImage(){
  this.todo++;
  var img = new Image();
  img.onload = function(){ 
                  context.drawImage(img,0,0,200,200);
                  this.todo--;
                  checkAllDone();
                };
  img.src = 'https://i.stack.imgur.com/RxFwQ.png?s=64&g=1';

}

function drawCloud(){
      context.beginPath();
      context.moveTo(170, 80);
      context.bezierCurveTo(130, 100, 130, 150, 230, 150);
      context.bezierCurveTo(250, 180, 320, 180, 340, 150);
      context.bezierCurveTo(420, 150, 420, 120, 390, 100);
      context.bezierCurveTo(430, 40, 370, 30, 340, 50);
      context.bezierCurveTo(320, 5, 250, 20, 250, 50);
      context.bezierCurveTo(200, 5, 150, 20, 170, 80);
      context.closePath();
      context.lineWidth = 5;
      context.fillStyle = '#8ED6FF';
      context.fill();
      context.strokeStyle = '#0000ff';
      context.stroke();
      checkAllDone();
}

function copyCanvas(){
  var img = document.getElementById('img');
  img.src = canvas.toDataURL();
  //img.src = context.getImageData();


}

Now this is very simple script where there are mainly three functions

drawImage(): This will draw an image into the context drawCloud(): This draws a shape using drawing commands which looks like cloud copyCanvas(): This one liner is expected to clone the image and what ever raster drawings drawon on the canvas is put as an image and works as source to the <img> element.

Twist is that when I draw both Image and Cloud, copyCanvas won't work as expected. The image element doesn't copy canvas content. Where as if I comment out drawImage then it properly copies canvas contents. Why is that?

LJᛃ
  • 7,655
  • 2
  • 24
  • 35
dejjub-AIS
  • 1,501
  • 2
  • 24
  • 50

1 Answers1

0

Regarding your code, these two this are actually window:

function checkAllDone(){
  if (this.todo ==0) copyCanvas();
}


function drawImage(){
  this.todo++;
  // ......

While the one inside img.onload is indeed img:

img.onload = function(){ 
  context.drawImage(img,0,0,200,200);
  this.todo--;
  checkAllDone();
};

So window.todo (todo you declared in line 3) is always 1 when checkAllDone runs, and it obviously fails.

Read more about this, notice the difference between function context variations.

Since you have declared a global todo indicator, the simplest fix is to use todo instead of this.todo.

However, after fix you will encounter another problem:

Uncaught SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.

which you could find an answer here.

Community
  • 1
  • 1
Leo
  • 13,428
  • 5
  • 43
  • 61