canvas.msToBlob() unreliable - returns incorrect stream. RRS feed

  • Question

  • I'm trying to save a svg file to a png image by drawing the svg to a canvas and then saving the canvas as PNG.

    According to another post this can be done via the .msToBlob() method like this:

    var canvas = document.createElement('canvas');
    canvas.width = w;
    canvas.height = h;
    var ctx = canvas.getContext('2d');
    ctx.drawImage(svgImage, 0, 0);
    var blob = canvas.msToBlob();
    var inputStream = blob.msDetachStream().getInputStreamAt(0);
    Windows.Storage.ApplicationData.current.localFolder.createFileAsync('test.png', Windows.Storage.CreationCollisionOption.replaceExisting).then(function (file) {
    	return file.openAsync(Windows.Storage.FileAccessMode.readWrite);
    }, error).then(function (outputStream) {
    	return Windows.Storage.Streams.RandomAccessStream.copyAsync(inputStream, outputStream).then(function () {
    		outputStream.flushAsync().then(function () {
    		}, error);
    	}, error)
    }, error);

    This works when you step through slowly but when executing normally the 

    var blob = canvas.msToBlob();

    method returns a blob where the size is way too small. I can't find any mention that I somehow would need to 'flush' the canvas first so what do I need to do to consistently get a proper stream?

    EDIT:Further testing reveals to be even stranger. If I draw the image twice *and* call .msToBlob() twice then the size is always correct in the second call and always wrong in the first. 

    ctx.drawImage(svgImage, 0, 0);
    canvas.msToBlob(); //incorrect
    ctx.clearRect(0, 0, w, h);
    ctx.drawImage(svgImage, 0, 0);
    var blob = canvas.msToBlob();//correct
    Surely this must be a bug, right?

    • Edited by PatrickKlug Thursday, August 2, 2012 4:24 AM
    Thursday, August 2, 2012 2:40 AM

All replies

  • Patrick,

    JavaScript is single threaded.  My guess is that the Drawing has not completed before you are trying to access it.  You need to yield to allow that thread to process your drawing requests to the canvas.

    Try using setImmediate and placing your code to get the blog and write it out in there:


    Something like this.

    ctx.drawImage(svgImage, 0, 0);
    msSetimmediate( function (){
    var blob = canvas.msToBlob();
    // all the rest of your code.

    Jeff Sanders (MSFT)

    Thursday, August 2, 2012 1:44 PM
  • that would make sense but unfortunately this doesn't work.

    It still returns a wrong result on the msToBlob() call. Also tried a 2 second timeout and it still returns the wrong result so I don't think that the canvas isn't ready yet. There must be something else going on.

    Friday, August 3, 2012 12:01 AM
  • Can you give me more detail and more code?  How are you creating the image to draw, all that so I can repro.

    Jeff Sanders (MSFT)

    Friday, August 3, 2012 6:11 PM
  • I have sent you a full repro code via email.
    Saturday, August 4, 2012 12:18 AM
  • Were you able to debug this, i'm seeing the same issue.

    My repro is almost identical:

    1) SVG image
    2) draw image to canvas

    3) Only repros if I do a fillrect before draw image.

    Tuesday, January 7, 2014 6:09 PM