¿Cómo guardar una imagen en SQLite para WinRT?


Muestra de almacenamiento en SQLite

Cuando se está trabajando con bases de datos de lado del cliente o locales, muchas veces se desea guardar una imagen, ya sea un avatar, una imagen representativa, lo que sea. Por lo que suponiendo que ya se cuenta con el entorno de desarrollo configurado incluso SQLite (click aquí por si no sabes como instalarlo), seré breve.

El mecanismo es sencillo siempre y cuando se sabe como hacer las cosas, y hay que aclarar que SQLite no permite guardar imágenes como tal, la razón la desconozco porque si no me tocaría leerme la documentación oficial😛 por lo que toca buscar una medida alternativa para guardar una imagen, una primera forma es usar el API de algún hosting de imágenes y guardar la URL (así como Imgur), pero si pensamos un poco mejor consumiría mucho plan de datos móviles o Internet Móvil de parte del usuario; así que a mi manera de ver la situación no es una manera viable de guardar una imagen en SQLite, para resolver esto existe algo que se llama Base64, la cual invito a que investigues ya que es un sistema bastante interesante que se podría aplicar para muchas otras cosas como la criptografía, comunicaciones, enviar correos electrónicos, entre otros.

En este caso se usará la Base64 para convertir una imagen en un string, lo que en WinRT fue un poco complejo a la hora de implementar debido a que se cambió la documentación muy seguido y fue un problema, pero entonces queda resumido a lo siguiente:

  1. Se capturará una imagen de la WebCam y de un archivo con un FilePicker.
  2. Se obtendrá un Stream para convertirlo en un Array de Bytes.
  3. Se convierte el Array de Bytes en Base64 y se guarda en SQLite.

Así que manos a la obra.

En mi lógica tengo 2 botones, uno para la WebCam y otro para abrir la foto.

Declaro de manera global a la clase la siguiente variable, para diferentes usos.

private StorageFile file;

Declaro los botonces en XAML y les hago sus respectivos eventos de click:
Botones
En el evento de la WebCam hice lo siguiente:

private async void CamaraBoton_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
 {
 #region Uso de la cámara para tomar una foto
 CameraCaptureUI dialog = new CameraCaptureUI();
 Size aspectRatio = new Size(16, 9);
 dialog.PhotoSettings.CroppedAspectRatio = aspectRatio;

file = await dialog.CaptureFileAsync(CameraCaptureUIMode.Photo);
 if (file != null)
 {
 BitmapImage bitmapImage = new BitmapImage();
 using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.Read))
 {
 bitmapImage.SetSource(fileStream);
 }
 Foto.Source = bitmapImage;

}
 else
 {
 // Si la foto no ha sido tomada
 }
 #endregion
 Elegir.Visibility = Visibility.Collapsed;
 CamaraBoton.Visibility = Visibility.Collapsed;
 Cerrar.Visibility = Visibility.Visible;
 }

Las últimas líneas de código son de estética pero son opcionales. Para el botón de seleccionar la imagen con el picker:

private async void Elegir_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
 {
 #region Uso del Picker para cargar la foto
 var picker = new FileOpenPicker();

picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
 picker.ViewMode = PickerViewMode.Thumbnail;
 picker.FileTypeFilter.Add(".jpg");
 picker.FileTypeFilter.Add(".jpeg");
 file = await picker.PickSingleFileAsync();
 if (file == null) return;

var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
 Elegir.Visibility = Visibility.Collapsed;
 CamaraBoton.Visibility = Visibility.Collapsed;
 Cerrar.Visibility = Visibility.Visible;
 BitmapImage image = new BitmapImage();
 image.SetSource(stream);

 Foto.Source = image;
 #endregion

}

Cabe aclarar que el objeto Image se llama “Foto” y la variable “file” es global a la clase.

Por lo que sigue es bastante fácil y agradable de hacer:

Según la lógica de cada aplicación se validan los datos y suponiendo que todo está validado:

// Hago una instancia de la clase
 MiCompra mc = new MiCompra();

 // Guardo los valores en sus atributos
 mc.regalo = Regalo.Text;
 mc.descripcion = Descripcion.Text;
 mc.ubicacion = Ubicacion.Text;

//Convierto a base64 la imagen previamente cargada

var bytes = await GetBtyeFromFile(file);
 string base64String = Convert.ToBase64String(bytes);

mc.foto = base64String;

// Hago la inserción en la base de datos previamente cargada
 int insertedItems = await _db.InsertAsync(mc);

// Si no ocurrió un error o por ende el item es mayor a cero
 if (insertedItems > 0)
 {
 // Hago una búsqueda como si hiciera SQL Injection
 var Compras = _db.Table().Where(cust => 1 == 1);

// Si hay algún regalo
 if (Compras != null)
 {
 //BuscarBDD();
 }

}

El método GetByteFromFile:

private async Task<Byte[]> GetBtyeFromFile(StorageFile storageFile)
 {
 var stream = await storageFile.OpenReadAsync();

using (var dataReader = new DataReader(stream))
 {
 var bytes = new byte[stream.Size];
 await dataReader.LoadAsync((uint)stream.Size);
 dataReader.ReadBytes(bytes);

return bytes;
 }
 }

Y el método Base64StringToBitmap:

private static BitmapImage Base64StringToBitmap(string source)
 {
 var ims = new InMemoryRandomAccessStream();
 var bytes = Convert.FromBase64String(source);
 var dataWriter = new DataWriter(ims);
 dataWriter.WriteBytes(bytes);
 dataWriter.StoreAsync();
 ims.Seek(0);
 var img = new BitmapImage();
 img.SetSource(ims);
 return img;
 }

Finalmente dejo la estructura de la clase MiCompra para despejar dudas:

public class MiCompra
 {
 [PrimaryKey, AutoIncrement]
 public int id { get; set; }

public string regalo { get; set; }

public string descripcion { get; set; }

public string foto { get; set; }

public string ubicacion { get; set; }
 }

Con eso basta para guardar una imagen, el proceso de recuperación es leer en la base de datos el string en Base64 y usar el método Base64StringToBitmap para poner la imagen donde debería ir😀 .

9 comentarios en “¿Cómo guardar una imagen en SQLite para WinRT?

  1. Una pregunta más, sabes como realizar la inserción de la imagen utilizando binding, tanto como para insertar y consultar?
    si pudieras ayudarme te lo agradecería!!

Los comentarios están cerrados.