我如何知道 HTML5 Canvas 何时完成绘制?

Dan*_*nil 5 html javascript resize canvas image

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

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

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

感谢您的任何提示/答案!

//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);
});
//***
Run Code Online (Sandbox Code Playgroud)

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;
      }
    };
  }
]);
Run Code Online (Sandbox Code Playgroud)

Mx.*_*Mx. 3

你的问题很简单。

只要您不附加任何事件,JavaScript 将运行一个又一个语句(您需要这个,因为您希望在抓取图像时执行所有语句)。

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

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

通过超时(最低效/不安全)来解决这个问题的糟糕风格更好地解决这个问题,方法是将图像抓取代码包装在一个函数中,并在图像调整大小完成后运行该函数。它就像用于同步异步事件的回调。

例子

/* 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>");
}
Run Code Online (Sandbox Code Playgroud)
console{
  font-family: Consolas, monaco, monospace;
}
Run Code Online (Sandbox Code Playgroud)
<script type="text/javascript" src="https://code.jquery.com/jquery-latest.min.js"></script>

<console></console>
Run Code Online (Sandbox Code Playgroud)

您的代码示例

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';
}
Run Code Online (Sandbox Code Playgroud)
<canvas id="canvas"></canvas>
Run Code Online (Sandbox Code Playgroud)