我怎么知道 HTML5 Canvas 什么时候画完了?

How can I know when HTML5 Canvas finished drawing?

我是 javascript 的初学者。 在将图像上传到我的服务器进行存储之前,我正在尝试在客户端调整图像大小 我找到了一种使用 HTML5 Canvas 的方法:http://hacks.mozilla.org/2011/01/how-to-develop-a-html5-image-uploader/

我的问题:一直上传空白图片。我认为空白图像的原因是当我从 canvas 抓取图像时 canvas 没有完成绘制。 当我在从 canvas 抓取图像之前设置 3 秒 windows.timeout 时,一切正常。 有没有比超时更可靠的方法?或者有没有其他方法可以在客户端调整图像大小?

我进行客户端图像大小调整的原因是因为我正在处理上传不必要的大文件的人,我认为进行客户端图像大小调整是最有效的。

感谢您的任何 hints/answers!

//resize image
Resizeimage.resize(file);

//***if i wrap this part with timeout it works
var canvas = document.getElementById('canvas');
var data = canvas.toDataURL(file.type);

// convert base64/URLEncoded data component to raw binary data held in a string
var bytestring;
if (data.split(',')[0].indexOf('base64') >= 0)
  bytestring = atob(data.split(',')[1]);
else
  bytestring = escape(data.split(',')[1]);

//get imagetype
var mimeString = data.split(',')[0].split(':')[1].split(';')[0];

// write the bytes of the string to a typed array
var ia = new Uint8Array(bytestring.length);
for (var i = 0; i < bytestring.length; i++) {
  ia[i] = bytestring.charCodeAt(i);
}

// create a blob from array
var blob = new Blob([ia], {
  type: mimeString
});

//upload files
$scope.upload = $upload.upload({
  url: 'articles/imageUpload',
  method: 'POST',
  file: blob
    //update progress bar
}).progress(function(event) {
  $scope.uploadInProgress = true;
  $scope.uploadProgress = Math.floor(event.loaded / event.total * 100);
  //file upload success
}).success(function(data, status, headers, config) {
  $scope.uploadInProgress = false;
  $scope.uploadedImage = JSON.parse(data);
  $scope.isDisabled = false;
  //file upload fail
}).error(function(err) {
  $scope.uploadInProgress = false;
  console.log('Error uploading file: ' + err.message || err);
});
//***

angular.module('articles').factory('Resizeimage', [
  function() {

    var imgSelectorStr = null;

    // Resizeimage service logic
    function render(src) {
      var image = new Image();

      image.onload = function() {
        var canvas = document.getElementById('canvas');
        
        //check the greater out of width and height
        if (image.height > image.width) {
          image.width *= 945 / image.height;
          image.height = 945;
        } else {
          image.height *= 945 / image.width;
          image.width = 945;
        }

        //draw (&resize) image to canvas
        var ctx = canvas.getContext('2d');
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        canvas.width = image.width;
        canvas.height = image.height;
        ctx.drawImage(image, 0, 0, image.width, image.height);

      };
      image.src = src;
    }

    function loadImage(src) {
      // Create fileReader and run the result through the render
      var reader = new FileReader();

      reader.onload = function(e) {
        render(e.target.result);
      };
      reader.readAsDataURL(src);
    }

    // Public API
    return {
      resize: function(src) {
        loadImage(src);
        return true;
      }
    };
  }
]);

<script type="text/javascript">
     window.onload = function(){
         //Whatever you want to do when it has finished loading here
     }
</script>

您可以将这段代码放入您的 HTML 或 JavaScript 文件中的某处,然后才没有脚本标签 ;)

希望这对你有用:D

你的问题很简单。

JavaScript 将 运行 一个接一个地声明(你需要这个是因为你希望在抓取图像时执行所有语句)只要你不附加任何事件。

如果您将代码附加到一个事件(例如 image.onload),您的这部分代码将等待该事件,其余代码将继续异步。

所以你是对的 - 当你试图抓住这个时,图像没有被绘制。

通过超时解决它的糟糕风格(大多数inefficient/insecure)最好通过将图像抓取代码包装在一个函数中来解决这个问题,运行在图像调整大小后这个函数是完毕。它就像你用来同步异步事件的回调。

例子

/* setTimeout will behave like an event */
setTimeout(
  function(){
    $('console').append("<div>SetTimeout</div>");
     SynchCodeAfterTimeout();
  }, 1000);

AsynchCodeAfterTimeout();

function AsynchCodeAfterTimeout(){
    $('console').append("<div>AsynchCodeAfterTimeout</div>");
}

function SynchCodeAfterTimeout(){
    $('console').append("<div>SynchCodeAfterTimeout</div>");
}
console{
  font-family: Consolas, monaco, monospace;
}
<script type="text/javascript" src="https://code.jquery.com/jquery-latest.min.js"></script>

<console></console>

您的代码示例

render();

// Resizeimage service logic
function render() {
  var image = new Image();

  image.onload = function() {
    var canvas = document.getElementById('canvas');

    //check the greater out of width and height
    if (image.height > image.width) {
      image.width *= 945 / image.height;
      image.height = 945;
    } else {
      image.height *= 945 / image.width;
      image.width = 945;
    }

    //draw (&resize) image to canvas
    var ctx = canvas.getContext('2d');
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    canvas.width = image.width;
    canvas.height = image.height;
    ctx.drawImage(image, 0, 0, image.width, image.height);
    /*timeout not needed its just there so the browser renders the canvas contents so you can see them when the alert pops up*/
    setTimeout(function() {
      alert('yey all the drawing is done (this is synchronous)');
    });
  };
  image.src = 'https://loremflickr.com/320/240';
}
<canvas id="canvas"></canvas>