5

I have the following two methods that handles taking photos from a camera and picking photos from a library. They're both similar methods as at the end of each method, I get an ImageSource back from the Stream and I pass it onto another page which has an ImageSource binding ready to be set. These two method work perfectly. The next step now is to save the Image in SQLite so I can show the images in a ListView later on. My question for the XamGods (Xamarin Pros =), what is the best way to save image in SQLite in 2019? I have been in the forums for hours and I still don't have a tunnel vision on what I want to do. I can either

  • Convert Stream into an array of bytes to save in Sqlite.
  • Convert ImageSource into an array of bytes (messy/buggy).
  • Somehow retrieve the actual Image selected/taken and convert that into an array of bytes into SQLite

I'm sorry if my question is general, but Xamarin does not provide a clear-cut solution on how to save images in SQLite and you can only find bits and pieces of solutions throughout the forums listed below.

Thank you in advance!

    private async Task OnAddPhotoFromCameraSelected()
    {
        Console.WriteLine("OnAddPhotoFromCameraSelected");

        var photo = await Plugin.Media.CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions() { });
        var stream = photo.GetStream();
        photo.Dispose();
        if (stream != null)
        {
            ImageSource cameraPhotoImage = ImageSource.FromStream(() => stream);
            var parms = new NavigationParameters();
            parms.Add("image", cameraPhotoImage);
            var result = await NavigationService.NavigateAsync("/AddInspectionPhotoPage?", parameters: parms);

            if (!result.Success)
            {
                throw result.Exception;
            }
        }
    }

    private async Task OnAddPhotoFromLibrarySelected()
    {
        Console.WriteLine("OnAddPhotoFromLibrarySelected");
        Stream stream = await DependencyService.Get<IPhotoPickerService>().GetImageStreamAsync();
        if (stream != null)
        {
            ImageSource selectedImage = ImageSource.FromStream(() => stream);

            var parms = new NavigationParameters();
            parms.Add("image", selectedImage);
            parms.Add("stream", stream);
            var result = await NavigationService.NavigateAsync("/AddInspectionPhotoPage?", parameters: parms);

            if (!result.Success)
            {
                throw result.Exception;
            }
        }
    }
Mochi
  • 1,059
  • 11
  • 26
  • 2
    Don't. Save the image in the file system and save the path of the image in SQLite. – Jason Jul 25 '19 at 02:37
  • 2
    SQLite is a light weight file based databased. If you store images in database, it will make your database operations havier. And as Jason said, its not a good idea to store whole image into database. You should use the device's file system and store image name or full image path in the database. It will keep your sqlite lighter. – MilanG Jul 25 '19 at 04:21

1 Answers1

8

As Jason said that you can save image path into sqlite database, but if you still want to save byte[] into sqlite database, you need to convert stream into byte[] firstly:

 private byte[] GetImageBytes(Stream stream)
    {
        byte[] ImageBytes;
        using (var memoryStream = new System.IO.MemoryStream())
        {              
            stream.CopyTo(memoryStream);             
            ImageBytes = memoryStream.ToArray();
        }
        return ImageBytes;
    }

Then load byte[] from sqlite, converting into stream.

 public Stream BytesToStream(byte[] bytes)
    {
        Stream stream = new MemoryStream(bytes);
        return stream;
    }

For simple sample, you can take a look: Insert byte[] in sqlite:

 private void insertdata()
    {
        var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "sqlite1.db3");
        using (var con = new SQLiteConnection(path))
        {
            Image image = new Image();
            image.Content = ConvertStreamtoByte();
            var result = con.Insert(image);

            sl.Children.Add(new Label() { Text = result > 0 ? "insert successful insert" : "fail insert" });
        }
    }

Loading image from sqlite:

 private void getdata()
    {
        var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "sqlite1.db3");
        using (var con = new SQLiteConnection(path))
        {
            var image= con.Query<Image>("SELECT content FROM Image ;").FirstOrDefault();

            if(image!=null)
            {
                byte[] b = image.Content;
                Stream ms = new MemoryStream(b);
                image1.Source = ImageSource.FromStream(() => ms);                   
            }

        }
    }

Model:

public class Image
{
    [PrimaryKey, AutoIncrement]
    public int Id { get; set; }
    public string FileName { get; set; }   
    public byte[] Content { get; set; }
}
Cherry Bu - MSFT
  • 10,160
  • 1
  • 10
  • 16