web-dev-qa-db-ja.com

HTML5 Canvas toDataURLが空白を返す

画像ファイルをアップロードしてキャンバスに描画し、変更を加えてデータベースに保存したいと思っていました。キャンバスイメージ(Pic)が返すbase64値をテストしようとしましたが、空白です。ただし、キャンバス(Pic)をドキュメントに追加すると、結果が表示されます。ここで何が悪いのですか?

function handleFileSelect(evt) {
  var files = evt.target.files; // FileList object                
  for (var i = 0, f; f = files[i]; i++) {

    if (!f.type.match('image.*')) {
      continue;
    }
    // read contents of files asynchronously
    var reader = new FileReader();

    // Closure to capture the file information.
    reader.onload = (function(theFile) {
      return function(e) {

        var canvas = document.createElement("canvas");

        var datauri = event.target.result,
          ctx = canvas.getContext("2d"),
          img = new Image();

        img.onload = function() {

          canvas.width = width;
          canvas.height = height;
          ctx.drawImage(img, 0, 0, width, height);
        };
        img.src = datauri;
        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({
          // …
        });

      };
    })(f);
    reader.readAsDataURL(f);
  }
}
13
user3399326

私の直感は、var imageData = …からのすべてがimg.onload関数に入る必要があると言います。

つまり、関連する部分でコードは次のようになります。

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;

その理由は、

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

画像が読み込まれた後に正しく実行されます。しかし、残念ながら、この行が実行されたときにロードを待つ必要はありません。

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

以降のすべての行。

画像をキャンバスに描画するには、画像を読み込む必要があります。 getImageDataを呼び出すには、キャンバスに読み込まれた画像を含める必要があります。

17
Sebastian Simon