0

I have used Xamarin Media Plugin for image upload and i want to save that image in Sqlite and retrieve it back from Sqlite. How can i do that ?

Store: Convert the Image bitmap into a Base64String and store it to SQLite.

public static string Base64Encode(string plainText) {
  var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
  return System.Convert.ToBase64String(plainTextBytes);
}

Retrieve: Fetch the Base64String and convert that to Bitmap again.

public static string Base64Decode(string base64EncodedData) {
  var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
  return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
}

And how to select image from gallery and save to sql database in xamarin -- if like this, where I to implement these Base64Encode?

using Plugin.Media;
using Plugin.Media.Abstractions;
using System;
using Xamarin.Forms;
using SQLite;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace PersonListData
{
    public class Person
    {   
        [PrimaryKey, AutoIncrement]
        public int IdSis { get; set; }
        public string NamePerson { get; set; }
        public byte[] PersonImg { get; set; }
    }
    
    async void SaveOnClik(object sender, EventArgs e)
    {
        var person = (Person)BindingContext;
        await App.Database.SavePersonAsync(person);
        await Navigation.PopAsync();
    }

    async void PickPhotos(object sender, EventArgs e)
    {
        if (CrossMedia.Current.IsPickPhotoSupported)
        {
            var file = await CrossMedia.Current.PickPhotoAsync(new Plugin.Media.Abstractions.PickMediaOptions
            {
                PhotoSize = PhotoSize.Medium,
            });
            if (file == null)
                return;

            image.Source = ImageSource.FromStream(() =>
            {
                var stream = file.GetStream();
                file.Dispose();
                return stream;
            });          
        }
        else
        {
            await DisplayAlert("Image error", ":( Hcant do thid.", "Ok");
            return;
        }

    }
    readonly SQLiteAsyncConnection _database;
    public DataPerson(string dbPath)
    {
        _database = new SQLiteAsyncConnection(dbPath);
        _database.CreateTableAsync<Person>().Wait();
    }
    public Task<List<Person>> GetPersonListAsync()
    {
        return _database.Table<Person>().ToListAsync();
    }
    public Task<Person> GetPersonAsync(int id)
    {
        return _database.Table<Person>()
        .Where(i => i.IdSis == id)
        .FirstOrDefaultAsync();
    }
    public Task<int> SavePersonAsync(Person person)
    {
        if (person.IdSis != 0)
        {
            return _database.UpdateAsync(person);
        }
        else
        {
            return _database.InsertAsync(person);
        }
    }
    public Task<int> DeletePersonAsync(Person person)
    {
        return _database.DeleteAsync(person);
    }
}

I am confused in this placement

  • do you really need to store the actual image in sqlite? It's generally more efficient to store the image as a file and just put the path or id in the database. – Jason Jan 02 '21 at 14:37
  • If there is something better and lighter, why not give it a try. is there any reference to this? – Yan LimaBenua Jan 02 '21 at 15:46
  • in my mind with an arrangement like this: - load image from gallery - save / delete: in string format such as link to database. - can reload the image link to the device interface. want to be like that, but I lack experience in understanding C# – Yan LimaBenua Jan 02 '21 at 15:59
  • all I am suggesting is that the image data be stored as a file and the path or file name be stored as a string in the db. Actually storing the image data in the db adds complexity with little benefit. – Jason Jan 02 '21 at 16:11
  • in the end it is, if you keep a long list of people. database definitely swells :). then I will start from where to write the file name to the database, will all the above code be changed? – Yan LimaBenua Jan 02 '21 at 16:16

2 Answers2

1

You could try to save image path into sqlite database.

Create a path property into the model.

 public class Person
{   
    [PrimaryKey, AutoIncrement]
    public int IdSis { get; set; }
    public string NamePerson { get; set; }
    public string Path{ get; set; }
    public byte[] PersonImg { get; set; }
}

And then save the string into the database.

   public Task<int> SaveItemAsync(Person item)
    {
        if (item.ID != 0)
        {
            return Database.UpdateAsync(item);
        }
        else
        {
            return Database.InsertAsync(item);
        }
    }

You could check the link below with the code sample about how to save string into sqlite databsae. https://learn.microsoft.com/en-us/xamarin/xamarin-forms/data-cloud/data/databases

If you still want to save byte[] into sqlite database, you need to convert stream into byte[]. Please check the way about how to convert image from stream to bytes. How to save an image in SQLite in Xamarin Forms?

Wendy Zang - MSFT
  • 10,509
  • 1
  • 7
  • 17
  • thanks for the great response. generally I will store entries in the database. it's just that to place some code that integrates with `Base64` I'm still confused. in the time frame of this question, I tried to find other alternatives for example by taking the string file location and save to the database without having to change to `byte []`. well, hopefully this problem is solved :) – Yan LimaBenua Jan 04 '21 at 07:17
  • Any update for this issue? Does the file path work for you? – Wendy Zang - MSFT Jan 05 '21 at 08:52
  • The file path stays in place and works, my focus is to convert the image file and load it to the database – Yan LimaBenua Jan 06 '21 at 19:43
0

I no longer think about saving photos in base64

in c#

using Plugin.Media;
....

async void GetPersonImage(object sender, EventArgs e)
    {
        if (!CrossMedia.Current.IsPickPhotoSupported)
        {
            await DisplayAlert("Foto tidak didukung", ":( Hak akses dibatasi.", "Oke deh ..");
            return;
        }
        var file = await Plugin.Media.CrossMedia.Current.PickPhotoAsync(new Plugin.Media.Abstractions.PickMediaOptions
        {
            PhotoSize = Plugin.Media.Abstractions.PhotoSize.Medium,
    
        });
    
        if (file == null)
            return;
    
        string path = file.Path;
        FtSiswa.Text = path; //this label hide
    
        await DisplayAlert("Foto disimpan di: ", file.Path, "OK");
    
        KameraFotos.Source = ImageSource.FromStream(() =>
        {
            var stream = file.GetStream();
            file.Dispose();
            return stream;
        });
    }

in xaml

.... <Image x:Name="KameraFotos" BackgroundColor="Bisque" Grid.Column="2" Grid.RowSpan="2" Aspect="AspectFit"> <Image.Source> <FileImageSource File="{Binding PersonImg}" /> </Image.Source> <TapGestureRecognizer Tapped="GetPersonImage" NumberOfTapsRequired="1" /> </Image.GestureRecognizers> </Image> ....

I think it is more efficient to save the image in the path and the address of the file that is recorded in the database