0

I have an image displayed in an Image Control and I need to save that Image using FileSavePicker

This is what I have done:

 Dim fileSavePicker As New FileSavePicker()
        fileSavePicker.FileTypeChoices.Add("PNG", New String() {".png"})
        fileSavePicker.FileTypeChoices.Add("JPG", New String() {".jpg"})
        fileSavePicker.FileTypeChoices.Add("BMP", New String() {".bmp"})
        fileSavePicker.FileTypeChoices.Add("TIFF", New String() {".tiff"})
        fileSavePicker.FileTypeChoices.Add("EXIF", New String() {".exif"})
        fileSavePicker.FileTypeChoices.Add("ICO", New String() {".ico"})
        Dim saveFile As StorageFile = Await fileSavePicker.PickSaveFileAsync()
        If saveFile IsNot Nothing Then
          //Here I need to save that Image
        End If

It is saving the image but with "0 KB" and showing me the blank Image.

What should I be doing?

Edit:

This is the error I'm getting:

SaveToFile is not a memeber of Windows.UI.XAML.Media.Imaging.WriteableBitmap'.

And similarly for 'Load'

Edit:

This is how I am trying to load image:

Private Async Sub Scenario1Button_Click(sender As Object, e As RoutedEventArgs) Handles Scenario1Button.Click
    Image1.Visibility = Windows.UI.Xaml.Visibility.Visible
    LayoutRoot.Visibility = Windows.UI.Xaml.Visibility.Collapsed
    grdImages.Visibility = Windows.UI.Xaml.Visibility.Collapsed
    Dim openPicker As New FileOpenPicker
    openPicker.ViewMode = PickerViewMode.List
    openPicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary
    openPicker.FileTypeFilter.Add("*")
    Dim files As IReadOnlyList(Of StorageFile) = Await openPicker.PickMultipleFilesAsync
    If files.Count > 0 Then
        'Application now has read/write access to the picked file(s)
        For Each file In files
            Dim stream = Await file.OpenAsync(Windows.Storage.FileAccessMode.Read)
            Dim image As New BitmapImage()
            image.SetSource(stream)
            Image1.Source = image
            LayoutRoot.Visibility = Windows.UI.Xaml.Visibility.Collapsed
        Next file
    Else
    End If
End Sub

enter image description here

coder
  • 13,002
  • 31
  • 112
  • 214
  • 1
    How did you associate the FileSavePicker with the Image control? In other words, how did you tell the FileSavePicker what you are saving? – Bill Sempf Mar 19 '12 at 13:29
  • @Bill-That's what I would like to know.I am unable to know how the FileSavePicker is behaving but for the above code it's just saving a dummy image. – coder Mar 19 '12 at 15:01

1 Answers1

1

According to the documentation:

When the call to this method completes successfully, it returns a storageFile object that was created to represent the saved file. The file name, extension, and location of this storageFile match those specified by the user, but the file has no content. To save the content of the file, your app must write the content to this storageFile.

So you get a storage file and you need to write to it.

Saving a BitmapImage is not possible, so you would need to start off by loading the image into a WriteableBitmap. If you are just copying the original file - you can just load it to a stream and save it back to the new storage file. If you want to go the WriteableBitmap route - here is a set of extension methods you could use to load/save the image if you used C#:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Text;
using System.Threading.Tasks;
using Windows.ApplicationModel;
using Windows.Graphics.Imaging;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.Xaml.Media.Imaging;

namespace Xyzzer.WinRT.Extensions
{
    public static class WriteableBitmapSaveExtensions
    {
        public static async Task<WriteableBitmap> Load(string relativePath)
        {
            return await new WriteableBitmap(1, 1).Load(relativePath);
        }

        public static async Task<WriteableBitmap> Load(this WriteableBitmap writeableBitmap, string relativePath)
        {
            var storageFile = await Package.Current.InstalledLocation.GetFileAsync(relativePath.Replace('/', '\\'));
            return await writeableBitmap.Load(storageFile);
        }

        public static async Task<WriteableBitmap> Load(this WriteableBitmap writeableBitmap, StorageFile storageFile)
        {
            var stream = await storageFile.OpenReadAsync();
            var wb = new WriteableBitmap(1, 1);
            wb.SetSource(stream);
            return wb;
        }

        public static async Task SaveToFile(this WriteableBitmap writeableBitmap)
        {
            await writeableBitmap.SaveToFile(
                KnownFolders.PicturesLibrary,
                string.Format(
                    "{0}_{1}.png",
                    DateTime.Now.ToString("yyyyMMdd_HHmmss_fff"),
                    Guid.NewGuid()));
        }

        public static async Task SaveToFile(this WriteableBitmap writeableBitmap, StorageFolder storageFolder)
        {
            await writeableBitmap.SaveToFile(
                storageFolder,
                string.Format(
                    "{0}_{1}.png",
                    DateTime.Now.ToString("yyyyMMdd_HHmmss_fff"),
                    Guid.NewGuid()));
        }

        public static async Task SaveToFile(this WriteableBitmap writeableBitmap, StorageFolder storageFolder, string fileName)
        {
            StorageFile outputFile = await storageFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);

            Guid encoderId;

            var ext = Path.GetExtension(fileName);

            if (new[] { ".bmp", ".dib" }.Contains(ext))
            {
                encoderId = BitmapEncoder.BmpEncoderId;
            }
            else if (new[] { ".tiff", ".tif" }.Contains(ext))
            {
                encoderId = BitmapEncoder.TiffEncoderId;
            }
            else if (new[] { ".gif" }.Contains(ext))
            {
                encoderId = BitmapEncoder.TiffEncoderId;
            }
            else if (new[] { ".jpg", ".jpeg", ".jpe", ".jfif", ".jif" }.Contains(ext))
            {
                encoderId = BitmapEncoder.TiffEncoderId;
            }
            else if (new[] { ".hdp", ".jxr", ".wdp" }.Contains(ext))
            {
                encoderId = BitmapEncoder.JpegXREncoderId;
            }
            else //if (new [] {".png"}.Contains(ext))
            {
                encoderId = BitmapEncoder.PngEncoderId;
            }

            await writeableBitmap.SaveToFile(outputFile, encoderId);
        }

        public static async Task SaveToFile(this WriteableBitmap writeableBitmap, StorageFile outputFile, Guid encoderId)
        {
            try
            {
                Stream stream = writeableBitmap.PixelBuffer.AsStream();
                byte[] pixels = new byte[(uint)stream.Length];
                await stream.ReadAsync(pixels, 0, pixels.Length);

                int offset;

                for (int row = 0; row < (uint)writeableBitmap.PixelHeight; row++)
                {
                    for (int col = 0; col < (uint)writeableBitmap.PixelWidth; col++)
                    {
                        offset = (row * (int)writeableBitmap.PixelWidth * 4) + (col * 4);
                        byte B = pixels[offset];
                        byte G = pixels[offset + 1];
                        byte R = pixels[offset + 2];
                        byte A = pixels[offset + 3];

                        // convert to RGBA format for BitmapEncoder
                        pixels[offset] = R; // Red
                        pixels[offset + 1] = G; // Green
                        pixels[offset + 2] = B; // Blue
                        pixels[offset + 3] = A; // Alpha
                    }
                }

                IRandomAccessStream writeStream = await outputFile.OpenAsync(FileAccessMode.ReadWrite);
                BitmapEncoder encoder = await BitmapEncoder.CreateAsync(encoderId, writeStream);
                encoder.SetPixelData(BitmapPixelFormat.Rgba8, BitmapAlphaMode.Premultiplied, (uint)writeableBitmap.PixelWidth, (uint)writeableBitmap.PixelHeight, 96, 96, pixels);
                await encoder.FlushAsync();
                await writeStream.GetOutputStreamAt(0).FlushAsync();
            }
            catch (Exception ex)
            {
                string s = ex.ToString();
            }
        }
    }
}
Filip Skakun
  • 31,624
  • 6
  • 74
  • 100
  • @Filip-Thanks for your detailed explanation and If I convert it to VB.Net and I am getting the above mentioned errors. – coder Mar 19 '12 at 17:22
  • I think your conversion did not go well. I don't do too much VB development, but a quick search on extension methods in VB says you need to prefix the extension methods with attribute. Most of the methods in my code were extension methods (all the ones with "this WriteableBitmap" as the first parameter. – Filip Skakun Mar 19 '12 at 17:31
  • @Filip-No problem.I will look in to that. – coder Mar 19 '12 at 17:33
  • Or you can create a C# class library with the C# code and then reference, import and use it from your VB project. – Filip Skakun Mar 19 '12 at 17:35
  • @Fiilip-That did the trick and how do I call it on the button click event. – coder Mar 19 '12 at 18:00
  • Well, you have your saveFile from fileSavePicker.PickSaveFileAsync(). If you have a WriteableBitmap called myBitmap that you want saved - just do myBitmap.Save(saveFile) – Filip Skakun Mar 19 '12 at 18:38
  • @Filip-Sorry for troubling you.As I am new to this writeable Bitmap and XAML it takes some time to get accustomed with this.I have added the code for Loading the image from that how do I get the writeable bitmap. – coder Mar 19 '12 at 18:46