简体   繁体   中英

How can I know when HTML5 Canvas finished drawing?

I'm a beginner to javascript. I'm trying to resize images on client side before uploading them to my server for storage I have found a way to do it using HTML5 Canvas: http://hacks.mozilla.org/2011/01/how-to-develop-a-html5-image-uploader/

My problem : It kept on uploading blank image. I think the reason for the blank image is that canvas is not done drawing when I grabbed the image from canvas. When I set a 3 second windows.timeout before grabbing image from canvas everything works fine. Is there a more reliable method than a timeout? Or is there any other method to do client-side image resizing?

The reason I'm doing client-side image resizing is because I'm dealing with people who uploads unnecessary big files and I think it is most efficient to do a client side image resizing.

Thank you for any 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; } }; } ]); 

Your problem is quite a simple one.

JavaScript will run one statement after another (and you need this because you want all statements executed when grabbing the image) as long as you dont attach to any events.

If you attach your code to an event ( image.onload for example) this part of your code will wait for the event and the rest of your code will continue asynchronous.

So you are right - the image isn't drawn when you try to grab this.

Its bad style to solve it by a timeout (most inefficient/insecure) better solve this by wrapping your image-grabbing code in a function and run this function after your image re-size is done. It's like a callback you use to synchronize the asynchronous event.

Example

 /* 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> 

Example with your code

 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> 

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

You can place this piece of code inside your HTML or somewhere in your JavaScript files only then without the script tags ;)

Hope this works for you :D

I had a problem , the canvas to image always blank.

Then I put a delay, now works fine.

setTimeout(function () {
    var da = document.getElementById("canvasFabric").toDataURL("png", "1");
    $('#FInalImage').attr("src", canvasFabric.toDataURL("png", "1"));
    window.open(da);
}, 100);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM