Enrico
Enrico

Reputation: 6266

Xamarin forms UWP: how can I save an jpg from ImageSource?

I can save a picture in iOS and Android but I can't find a way to save an image in UWP. Any ideas?

Thank you in advance.

Upvotes: 0

Views: 1938

Answers (2)

Enrico
Enrico

Reputation: 6266

maybe someone needs a solution for iOS and Android (below). Meanwhile I'm waiting an idea for UWP.

iOS

     /// <summary>
    /// Saves the picture to disk.
    /// </summary>
    /// <returns>The picture to disk.</returns>
    /// <param name="imgSrc">Image source.</param>
    /// <param name="id">Identifier.</param>
    /// <param name="overwriteIfExist">if set to <c>true</c> overwrite if exist.</param>
    /// <returns>The picture to disk.</returns>
    public async void SaveImage(ImageSource imgSrc, string id, bool overwriteIfExist = false)
    {
        var renderer = new StreamImagesourceHandler();
        var photo = await renderer.LoadImageAsync(imgSrc);

        string jpgFilename = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), id + ".jpg");

        if (File.Exists(jpgFilename))
        {
            File.Delete(jpgFilename);
        }

        NSData imgData = photo.AsJPEG();
        NSError err;
        if (imgData.Save(jpgFilename, false, out err))
        {
            Console.WriteLine("saved as " + jpgFilename);
        }
        else
        {
            Console.WriteLine("NOT saved as " + jpgFilename
                                + " because" + err.LocalizedDescription);
        }

    }

Good to know, when iOS saves an image as jpg, the image header says png.

Android

    /// <summary>
    /// Saves the picture to disk.
    /// </summary>
    /// <param name="imgSrc">Image source.</param>
    /// <param name="id">The image identifier.</param>
    /// <param name="overwriteIfExist">if set to <c>true</c> overwrite if exist.</param>
    /// <returns>The picture to disk.</returns>
    public async void SaveImage(ImageSource imgSrc, string id,
                                        bool overwriteIfExist = false)
    {
        var renderer = new StreamImagesourceHandler();
        var photo = await renderer.LoadImageAsync(imgSrc, Forms.Context);

        string jpgFilename = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), id + ".jpg");

        if (File.Exists(jpgFilename))
        {
            File.Delete(jpgFilename);
        }

        using (FileStream fs = new FileStream(jpgFilename, FileMode.OpenOrCreate))
        {
            photo.Compress(Bitmap.CompressFormat.Jpeg, 100, fs);
        }
     }

Upvotes: 1

Franklin Chen - MSFT
Franklin Chen - MSFT

Reputation: 4923

I can't find a way to save an image in UWP

No, we can't extract the image data from an Xamarin ImageSource object.

There is StreamImagesourceHandler class implementation in UWP, see here

public sealed class StreamImageSourceHandler : IImageSourceHandler
{
    public async Task<Windows.UI.Xaml.Media.ImageSource> LoadImageAsync(ImageSource imagesource, CancellationToken cancellationToken = new CancellationToken())
    {
        BitmapImage bitmapimage = null;

        //Omitted

        return bitmapimage;
    }
}

So we need to extract data from BitmapImage.

Actually the BitmapImage class is inherited from ImageSource class, while we can't extract the image data from ImageSource, for the reason, please see these two questions:


The solution here is to use different way for Windows Runtime(W/WP8.1 & UWP) app, extracting image data from System.IO.Stream class is supported in UWP.

We can use DependencyService to access native platform features, firstly, create an interface in PCL:

public interface ISaveImage
{
    void SavePictureToDisk(ImageSource imgSrc, string Id, bool OverwriteIfExist = false);
    void SavePictureToDiskWINRT(System.IO.Stream imgStream, string Id, bool OverwriteIfExist = false);
}

In the code behind of Xamarin page:

    var memoryStream = new MemoryStream(Convert.FromBase64String("iVBOxxxxxxxxxxMVEX/uQOAuwPzUxxxxxxxxxxxx="));
    ImageSource imgsource = ImageSource.FromStream(() => memoryStream);

    if (Device.OS == TargetPlatform.Windows|| Device.OS == TargetPlatform.WinPhone)
         DependencyService.Get<ISaveImage>().SavePictureToDiskWINRT(memoryStream, "1");
    else
         DependencyService.Get<ISaveImage>().SavePictureToDisk(imgsource, "1");

Implement the interface in UWP platform:

using Xamarin.Forms;
using WorkingWithImages.WinUniversal;
using System.IO;
using System;
using Windows.Storage.Streams;

[assembly: Xamarin.Forms.Dependency(typeof(SaveImageImplementation))]
namespace WorkingWithImages.WinUniversal
{
    public class SaveImageImplementation : ISaveImage
    {
        public SaveImageImplementation() { }

        public void SavePictureToDisk(ImageSource imgSrc, string Id, bool OverwriteIfExist = false)
        {
            throw new NotImplementedException();
        }

        public async void SavePictureToDiskWINRT(Stream imgStream, string Id, bool OverwriteIfExist = false)
        {
            var inStream = imgStream.AsRandomAccessStream();
            var fileBytes = new byte[inStream.Size];
            using (DataReader reader = new DataReader(inStream))
            {
                await reader.LoadAsync((uint)inStream.Size);
                reader.ReadBytes(fileBytes);
            }

            var file = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync(Id+".jpg", Windows.Storage.CreationCollisionOption.ReplaceExisting);
            using (var fs = await file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite))
            {
                var outStream = fs.GetOutputStreamAt(0);
                var dataWriter = new DataWriter(outStream);
                dataWriter.WriteBytes(fileBytes);
                await dataWriter.StoreAsync();
                dataWriter.DetachStream();
                await outStream.FlushAsync();
                outStream.Dispose();
                fs.Dispose();
            }
        }
    }
}

Please check my completed demo in here

About UWP File storage guidance, please see Create, write, and read a file

Upvotes: 2

Related Questions