locked
How can I save canvas to imagen (jpg)

    Question

  • Hello,

    I have an application where I paint some images in a canvas. I want to save this canvas to file, and I want to save it in a specific folder (with path).How can I do it?

    Thanks!

    Saturday, November 19, 2011 12:29 PM

Answers

  • I just wrote some code for that. The function below saves to the pictures library, but you can replace the pictures variable blow, from Windows.Storage.KnownFolders.picturesLibrary, with a a different StorageFolder item either from KnownFolders, one in your app data (Windows.Storage.ApplicationData.current.localFolder/roamingFolder/tempFolder--see http://msdn.microsoft.com/en-us/library/windows/apps/br241587.aspx), or one obtained from the file picker. Everything else is the same, and you can adjust the parameters in encoder.setPixelData.

        function saveCanvas(filename, canvas) {
            //Open an output stream for filename in the pictures library
            var pictures = Windows.Storage.KnownFolders.picturesLibrary;
    
            var ctx, imgData;
            var Imaging = Windows.Graphics.Imaging;
    
            //Create the file
            pictures.createFileAsync(filename, Windows.Storage.CreationCollisionOption.replaceExisting).then(function (file) {
                if (file) {
                    //Open the created file
                    return file.openAsync(Windows.Storage.FileAccessMode.readWrite);
                }
            })
            .then(function (stream) {
                //Get the canvas data
                ctx = canvas.getContext("2d");
                imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);            
    
                //Create imageencoder object
                return Imaging.BitmapEncoder.createAsync(Imaging.BitmapEncoder.pngEncoderId, stream);
            })
            .then(function (encoder) {
                //Set the pixel data in the encoder
                encoder.setPixelData(Imaging.BitmapPixelFormat.rgba8, Imaging.BitmapAlphaMode.straight,
                    canvas.width, canvas.height, 96, 96, new Uint8Array(imgData.data));
    
                //Go do the encoding
                return encoder.flushAsync();
            })
            .then(null, function (error) { });
    
            return true;
        }
    
    

     .Kraig

    Saturday, November 19, 2011 4:28 PM
  • By the way, there's another way to do this as found in this sample:  http://code.msdn.microsoft.com/windowsapps/Blob-Sample-0e35889e 

    It uses an added method on the canvas element, msToBlob(), from which you can get a stream, and then copy that stream to a file stream without going through the encoder. Here's an excerpt:

            // Convert Canvas to blob, gets the data out of the canvas
            var blob = canvas.msToBlob();  
    
            var filename = ...; 
    <br/>        // Open the picker to create a file to save the blob  
            Windows.Storage.KnownFolders.picturesLibrary.createFileAsync(filename).then(function (file) { 
                // Open the returned file in order to copy the data 
                file.openAsync(Windows.Storage.FileAccessMode.readWrite).then(function (stream) { 
                    var output = stream.getOutputStreamAt(0); 
                   // Get the IInputStream stream from the blob object 
                    var input = blob.msRandomAccessStream.getInputStreamAt(0); 
                     
                    // Copy the stream from the blob to the File stream  
                    Windows.Storage.Streams.RandomAccessStream.copy(input, output); 
                    output.flushAsync().then();
                }); 
            }); 
    
    
    .Kraig

    Tuesday, November 22, 2011 5:14 PM

All replies

  • I just wrote some code for that. The function below saves to the pictures library, but you can replace the pictures variable blow, from Windows.Storage.KnownFolders.picturesLibrary, with a a different StorageFolder item either from KnownFolders, one in your app data (Windows.Storage.ApplicationData.current.localFolder/roamingFolder/tempFolder--see http://msdn.microsoft.com/en-us/library/windows/apps/br241587.aspx), or one obtained from the file picker. Everything else is the same, and you can adjust the parameters in encoder.setPixelData.

        function saveCanvas(filename, canvas) {
            //Open an output stream for filename in the pictures library
            var pictures = Windows.Storage.KnownFolders.picturesLibrary;
    
            var ctx, imgData;
            var Imaging = Windows.Graphics.Imaging;
    
            //Create the file
            pictures.createFileAsync(filename, Windows.Storage.CreationCollisionOption.replaceExisting).then(function (file) {
                if (file) {
                    //Open the created file
                    return file.openAsync(Windows.Storage.FileAccessMode.readWrite);
                }
            })
            .then(function (stream) {
                //Get the canvas data
                ctx = canvas.getContext("2d");
                imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);            
    
                //Create imageencoder object
                return Imaging.BitmapEncoder.createAsync(Imaging.BitmapEncoder.pngEncoderId, stream);
            })
            .then(function (encoder) {
                //Set the pixel data in the encoder
                encoder.setPixelData(Imaging.BitmapPixelFormat.rgba8, Imaging.BitmapAlphaMode.straight,
                    canvas.width, canvas.height, 96, 96, new Uint8Array(imgData.data));
    
                //Go do the encoding
                return encoder.flushAsync();
            })
            .then(null, function (error) { });
    
            return true;
        }
    
    

     .Kraig

    Saturday, November 19, 2011 4:28 PM
  • By the way, there's another way to do this as found in this sample:  http://code.msdn.microsoft.com/windowsapps/Blob-Sample-0e35889e 

    It uses an added method on the canvas element, msToBlob(), from which you can get a stream, and then copy that stream to a file stream without going through the encoder. Here's an excerpt:

            // Convert Canvas to blob, gets the data out of the canvas
            var blob = canvas.msToBlob();  
    
            var filename = ...; 
    <br/>        // Open the picker to create a file to save the blob  
            Windows.Storage.KnownFolders.picturesLibrary.createFileAsync(filename).then(function (file) { 
                // Open the returned file in order to copy the data 
                file.openAsync(Windows.Storage.FileAccessMode.readWrite).then(function (stream) { 
                    var output = stream.getOutputStreamAt(0); 
                   // Get the IInputStream stream from the blob object 
                    var input = blob.msRandomAccessStream.getInputStreamAt(0); 
                     
                    // Copy the stream from the blob to the File stream  
                    Windows.Storage.Streams.RandomAccessStream.copy(input, output); 
                    output.flushAsync().then();
                }); 
            }); 
    
    
    .Kraig

    Tuesday, November 22, 2011 5:14 PM
  • Great!! It's working perfectly, thanks!

    I modified your code, now you can select a folder to save the image, here is the code:

     

    function guardar() { //------------------------- PICKER: FOLDER SELECTION ------------------------------------------- var folderPicker = new Windows.Storage.Pickers.FolderPicker; folderPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.desktop; // Users expect to have a filtered view of their folders depending on the scenario. // For example, when choosing a documents folder, restrict the filetypes to documents for your application. folderPicker.fileTypeFilter.replaceAll([".bmp", ".jpg",]); folderPicker.pickSingleFolderAsync().then(function (folder) { if (folder) { // Application now has read/write access to all contents in the picked folder (including sub-folder contents) // Cache folder so the contents can be accessed at a later time Windows.Storage.AccessCache.StorageApplicationPermissions.futureAccessList.addOrReplace("PickedFolderToken", folder); //------------------ SAVING FILE ---------------------------------------- //Open an output stream for filename in the pictures library //var pictures = Windows.Storage.KnownFolders.picturesLibrary; var filename = "fotocanvas.jpg"; var ctx, imgData; var Imaging = Windows.Graphics.Imaging; var canvas = document.getElementById('canvas2'); //Create the file folder.createFileAsync(filename, Windows.Storage.CreationCollisionOption.replaceExisting).then(function (file) { if (file) { //Open the created file return file.openAsync(Windows.Storage.FileAccessMode.readWrite); } }) .then(function (stream) { //Get the canvas data ctx = canvas.getContext("2d"); imgData = ctx.getImageData(0, 0, canvas.width, canvas.height); //Create imageencoder object return Imaging.BitmapEncoder.createAsync(Imaging.BitmapEncoder.pngEncoderId, stream); }) .then(function (encoder) { //Set the pixel data in the encoder encoder.setPixelData(Imaging.BitmapPixelFormat.rgba8, Imaging.BitmapAlphaMode.straight, canvas.width, canvas.height, 96, 96, new Uint8Array(imgData.data)); //Go do the encoding return encoder.flushAsync(); }) .then(null, function (error) { }); return true; } else { msg.content = "Folder was not returned"; msg.showAsync().then(); } }); }

    ;

     

     

     




    • Edited by Sergisenna Tuesday, November 29, 2011 8:24 PM
    Tuesday, November 29, 2011 8:20 PM
  • Hi Kraig:

    May I use C# to save canvas to image?

     

    Thanks,

    Hardi 

    Tuesday, January 10, 2012 7:20 AM
  • Canvas is only an HTML5 concept, so there's no context for this in C#. However, you can look at the WriteableBitmap class for C#.

    Tuesday, January 10, 2012 11:49 PM
  • i think he means is there a way to make this or something similar work from within a webview control in a xaml based app. currently, writeablebitmap has no render method, so there isnt any way to rasterize xaml to an image file, like canvas can.

    i was wondering about this myself. the idea being that the JavaScript running in the webview control would save the image to disk, or to a web service (like SkyDrive), or somehow pass the image through to the xaml code behind.

    Wednesday, January 18, 2012 3:57 AM