AgentRed
AgentRed

Reputation: 72

Xamarin Forms saving image in sqlite database

How do I save an image I captured directly to sqlite(sqlite-net-pcl) database?

Here's my code but it can only save in "Internal Storage" of the phone.

private async void TakePhotoButton_Clicked(object sender, EventArgs e)
{
    try
    {
        await CrossMedia.Current.Initialize();
        if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
        {
            await DisplayAlert("No Camera", "No Camera Available", "OK");
            return;
        }

        var file = await CrossMedia.Current.TakePhotoAsync(
        new StoreCameraMediaOptions
        {
            SaveToAlbum = true,
            //Directory = "Sample",
            //Name = "Test.jpg"
        });

        if (file == null)
            return;

        PathLabel.Text = file.AlbumPath;
        MainImage.Source = ImageSource.FromStream(() =>
        {
            var stream = file.GetStream();
            file.Dispose();
            return stream;

        });
    }
    catch (Exception ex)
    {
        await DisplayAlert("error", ex.ToString(), "OK");
    }

}

Upvotes: 0

Views: 1513

Answers (2)

Paul Kertscher
Paul Kertscher

Reputation: 9713

Concerning the SaveToAlbum option

This will restult in 2 photos being saved for the photo. One in your private folder and one in a public directory that is shown. The value will be returned at AlbumPath. (Source)

Unless you really need the photo in the camera roll, there is no need to use SaveToAlbum.

Anyway, the file is still saved to your apps sandbox (the part of the devices storage that is reserved exclusively for your app) and you can retrieve the path with file.Path.

Having said that, it's easy to obtain the binary data representing your image

await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
    await DisplayAlert("No Camera", "No Camera Available", "OK");
    return;
}

var file = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions());

if (file == null)
    return;

var imageData = File.ReadAllBytes(file.Path);

Obviously (see here and here) it's possibly to store binary data (BLOBs) in an SQLite database. The simplest conceivable model to store an image in the database would be something like

class Image
{
    [PrimaryKey, AutoIncrement]
    public int ID { get; set; }

    public byte[] Data { get; set; }
}

Assuming that _imageRepository is your repository abstraction you are saving the images in, the data could be saved as

// ...
var file = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions());

if (file == null)
    return;

var imageData = File.ReadAllBytes(file.Path);

_imageRepository.Add(new Image()
                         {
                             Data = imageData
                         });

Later on, to display the image, you can get the Image from the repository and use the Data property, e.g. by passing it to a MemoryStream (if you need a stream)

// example: Loading by ID, loading all images is conceivable, too
var image = _imageRepository.LoadImage(id);
ImageControl.ImageSource = ImageSource.FromStream(() => new MemoryStream(image.Data));

Upvotes: 1

Lucas Zhang
Lucas Zhang

Reputation: 18861

You should convert the stream to Byte array so that you save them to sqlite.

public byte[] GetImageStreamAsBytes(Stream input)
{
  var buffer = new byte[16*1024];
  using (MemoryStream ms = new MemoryStream())
  {
    int read;
    while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
    {
                ms.Write(buffer, 0, read);
    }
      return ms.ToArray();
   }
}
var imgDate = GetImageStreamAsBytes(file.GetStream());

Upvotes: 2

Related Questions