locked
canvas.msToBlob() unreliable - returns incorrect stream.

    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 () {
    			outputStream.close();
    			inputStream.close();
    			blob.msClose();
    		}, 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 02, 2012 4:24 AM
    Thursday, August 02, 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:

    http://msdn.microsoft.com/en-us/library/windows/apps/hh453394.aspx

    Something like this.

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

    Jeff Sanders (MSFT)

    Thursday, August 02, 2012 1:44 PM
    Moderator
  • 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.


    • Edited by PatrickKlug Friday, August 03, 2012 2:26 AM
    Friday, August 03, 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 03, 2012 6:11 PM
    Moderator
  • I have sent you a full repro code via email.
    Saturday, August 04, 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 07, 2014 6:09 PM