Can't display a base64 image like a thumbnail


#1

Hi,
I’m trying to display a base64Image but I can’t make it work.
Here’s my html code :

<ion-content padding>

    <ion-list>
        <ion-item-sliding id="refresh" #slidingItem *ngFor="let signal of listeSignalements">
            <button ion-item (click)="openSignal()">
                <ion-thumbnail item-start>
                    <img id="image" [src]="signal.base64Image" />
                </ion-thumbnail>
                <h2>{{signal.signalement}}</h2>
                <p>{{signal.categorie}}</p>
            </button>

            <ion-item-options>
                <button ion-button color="primary" (tap)="openSignal(signal)">
                    Détails
                </button>
                <button ion-button color="danger" (tap)="delete(signal)">
                    Supprimer
                </button>
            </ion-item-options>
        </ion-item-sliding>
    </ion-list>
...

I don’t really understand why, because I’ve a cameraPage where I could take a photo or retrieve a photo from the gallery, and the display works fine.
Here is my functionnal snippet (edited 7/7/17)

public base64Image : string;

takePhoto() {
  const options : CameraOptions = {
    quality: 90,
    destinationType: this.camera.DestinationType.DATA_URL,
    encodingType: this.camera.EncodingType.JPEG,
    mediaType: this.camera.MediaType.PICTURE,
  }
  this.camera.getPicture(options) .then((imageData) => {
      this.signal.base64Image = "data:image/jpeg;base64," + imageData;
    }, (err) => {
    console.log(err);
    });
}

//méthode pour récupérer photo à partir des photos stockées sur le terminal
getPhotoFromLibrary() {
  const options : CameraOptions = {
    quality: 90,
    correctOrientation: true,
    destinationType: this.camera.DestinationType.DATA_URL,
    sourceType : this.camera.PictureSourceType.PHOTOLIBRARY,
    mediaType: this.camera.MediaType.PICTURE,
  }
  this.camera.getPicture(options) .then((imageData) => {
      this.signal.base64Image = "data:image/jpeg;base64," + imageData;
    }, (err) => {
    console.log(err);
    });
}

And here is the part of my html file

<ion-card class="blockImage">
        <ion-icon name="trash" class="deleteIcon" (click)="deletePhoto()"></ion-icon>
        <img id="image" [src]="base64Image" />
    </ion-card>

Could anyone help me please ?
Thanks


#2

Not sure if relevant, but you’re asking the plugin to give you PNG, but then declaring in the URL that it’s JPEG.


#3

I tried JPEG and PNG before posting my problem, but no change.
I could display the picture in my PhotoPage without any problems, but no way to display it in my HomePage…


#4

At the minimum, we need to see the code you are using to build the listeSignalements array to understand your problem.


#5

Here is the complete code

import { Signal } from '../../models/signal';
import { SqliteCrudProvider } from './../../providers/sqlite-crud/sqlite-crud';
import { Component } from '@angular/core';
import { NavController, NavParams, IonicPage } from 'ionic-angular';

@IonicPage()
@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  //variables formulaire récuperées
  public signalementFinal = new Signal();
  public listeSignalements : Array<Signal> = [ ];

  constructor(public navCtrl: NavController, public navParams: NavParams, private dbService: SqliteCrudProvider ) {
  }

  ionViewDidLoad(){
    //création de la base de données et de la table si non existantes
    this.dbService.createDatabase();
    
    //transfert des données SQLite vers le tableau 'listeSignalements' et Affichage
    this.dbService.selectAll(this.listeSignalements);

    /*  
    *   Vérification de la présence de données saisies en cours
    *   afin d'éviter d'insérer des données 'vides' dans la base 
    */
    let temp = this.navParams.get('signal.signalement');
    if (temp!='') {
      this.signalementFinal = this.navParams.get('signal');
      
      //insertion des données récupérées duu formaulaire dans la base de données locale SQLite
      this.dbService.insertInto(this.signalementFinal);
    }
  }

  //méthode pour naviguer vers la page formulaire
  addSignal() {
    this.navCtrl.push('FormulairePage');
 }

  //méthode d'ouverture de la page détaillant les principales infos du signalement
  openSignal(signal) {
    this.navCtrl.push('SignaldetailsPage', {
      signalement: signal
    });
  }

  //suppression du signalement...
  delete(signal) {
    //...dans la base de données
    this.dbService.deleteSignal(signal);

    //...de la liste des signalements
    let index = this.listeSignalements.indexOf(signal);
    if (index > -1) {
      this.listeSignalements.splice(index, 1);
    }
  }
}

and the Signal Model imported in the HomePage

export class Signal {  
    idSignalement: number;
    signalement: string;
    categorie: string;
    commentaires: string;
    date: string;
    base64Image: string;
    latitude: number;
    longitude: number;

    constructor() {
        this.idSignalement = null;
        this.signalement = '';
        this.categorie = '';
        this.commentaires = '';
        this.date = '';
        this.base64Image = '';
        this.latitude = null;
        this.longitude = null;
    }
}

And in the case you will need my SQLite queries request provider code, here he is :wink:

/*
  Generated class for the SqliteCrudProvider provider.

  See https://angular.io/docs/ts/latest/guide/dependency-injection.html
  for more info on providers and Angular DI.
*/

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { SQLite, SQLiteObject } from '@ionic-native/sqlite';

const DATABASE_NAME: string = 'signalementsDatabase.db';
const TABLE_SIGNALEMENTS = 'CREATE TABLE IF NOT EXISTS "signalements" ( `idsignalement` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `signalement` TEXT NOT NULL, `commentaires` TEXT NOT NULL, `date` TEXT NOT NULL, `base64image` BLOB NOT NULL, `longitude` INTEGER NOT NULL, `latitude` INTEGER NOT NULL, `categorie` TEXT NOT NULL )';

@Injectable()
export class SqliteCrudProvider {

  constructor(public http: Http, public sqlite: SQLite) {
  }

  //création de la base de données 'signalsDatabase.db' et des tables 'signalements' et 'categories'
  public createDatabase() {
    this.sqlite.create({name: DATABASE_NAME,
                        location: 'default'
    })
    .then((db: SQLiteObject) => {
      console.log('Connecté à la base de données...');
      db.executeSql(TABLE_SIGNALEMENTS, {})
      .then(() => 
        console.log('Création de la table SIGNALEMENTS réussie'))
      .catch(e => console.log('erreur création table' + e));
      })
    .catch(e => console.log('erreur connexion BD : ' + e));
  }
  
  //méthode d'insertion des données dans la base
  public insertInto(signal_details) {
    let insert_query = 'INSERT INTO `signalements` (signalement, categorie, commentaires, date, base64Image, longitude, latitude) VALUES (?, ?, ?, ?, ?, ?, ?)';
    let tabCategorie: Array<string> = signal_details.categorie;
    let categorie: string ='';

    //conversion du tableau catégorie en string en vue du stockage sqlite
    categorie = this.convertArrayToString(tabCategorie);

    this.sqlite.create({name: DATABASE_NAME,
                        location: 'default'
    })
    .then((db: SQLiteObject) => {
      db.executeSql(insert_query, [signal_details.signalement,
                                   categorie,
                                   signal_details.commentaires,
                                   signal_details.date, 
                                   signal_details.base64Image,
                                   signal_details.longitude,
                                   signal_details.latitude
                                   ])
      .then((data) => alert("Insert Into OK"))
      .catch((e) => alert('erreur insert Into : ' + e));
      })
    .catch(e => alert('erreur connexion BD : ' + e));
  }
  
  //méthode permettant de convertir un Array en String car SQLite ne permet pas de sauvegarder des variables de type Array
  convertArrayToString(tabCategorie: Array<string>) {
    let nomsArray : string = '';
    for (let i = 0; i < tabCategorie.length; i++) {
      nomsArray = nomsArray + tabCategorie[i];
      if (i < tabCategorie.length - 1) {
        nomsArray = nomsArray + ",";
      }
    }
  return nomsArray;
  }

  //méthode de mise à jour du signalement
  public updateSignal(signal_details) {
    let update_query = 'UPDATE `signalements` SET signalement = ?, categorie = ?, commentaires = ?, date = ?, base64Image = ?, longitude = ?, latitude = ? WHERE idsignalement = ?';
    let tabCategorie: Array<string> = signal_details.categorie;
    let categorie: string ='';
    categorie = this.convertArrayToString(tabCategorie);

    this.sqlite.create({name: DATABASE_NAME,
                        location: 'default'
    })
    .then((db: SQLiteObject) => {
      db.executeSql(update_query, [signal_details.signalement,
                                   categorie,
                                   signal_details.commentaires,
                                   signal_details.date, 
                                   signal_details.base64Image,
                                   signal_details.longitude,
                                   signal_details.latitude,
                                   signal_details.idSignalement
                                   ])
      .then((data) => alert("update query OK"))
      .catch((e) => alert('erreur update : ' + e));
      })
    .catch(e => alert('erreur connexion BD : ' + e));
  }

  //méthode de lecture des données de la base
  public selectAll(tabSignalements){   
    this.sqlite.create({name: DATABASE_NAME,
                        location: 'default'
    })
    .then((db: SQLiteObject) => {
      db.executeSql('SELECT * FROM `signalements`', [])
      .then((data) => {
        if (data == null) {
          console.log('aucune données dans la base');
          return;
        }
        if (data.rows) {
          if (data.rows.length > 0) {
            for (var i=0; i < data.rows.length; i++) {
              tabSignalements.push(data.rows.item(i))
              console.log('données exportées');
            } 
          }
        }})
    .catch(e => console.log(e));
  })
  .catch(e => console.log(e));
  }

  //méthode de suppression de la table
  public dropDatabase(){
    this.sqlite.deleteDatabase({name: DATABASE_NAME,      
                                location: 'default'
                              })
  }
 
  //méthode de suppression d'un signalement
  public deleteSignal(signal_details) {
    let deleteQuery = 'DELETE FROM `signalements` WHERE idsignalement = ?';
    
    this.sqlite.create({name: DATABASE_NAME,
                        location: 'default'
    })
    .then((db: SQLiteObject) => {
      db.executeSql(deleteQuery, [signal_details.idSignalement
                                 ])
      .then((data) => alert("Suppression des données réussie"))
      .catch((e) => alert('erreur delete from: ' + e));
      })
      .catch(e => alert('erreur connexion BD : ' + e));
  }
}

#6

If that’s the limit of your database interaction, I think you could make your life a lot easier by switching to ionic-storage. You’re only ever referencing records by id, so direct interaction with SQLite isn’t necessary.


#7

Please heed to the advice @rapropos is giving.

Thanks for sharing your code, although it has some language mix, I tried to understand as much as I could. I see that you’ve provided everything but not the actual call where the populated Signal object is being set in the navParams for the home page to use. That’s where I could have checked whether the base64 image is being properly set or not.

Anyways, until you can share that code or let me know exactly how the Signal object is being set in the navParams, you can try the following. Change the sequence of calls in the ionViewDidLoad of the homepage like this:

ionViewDidLoad(){
   //création de la base de données et de la table si non existantes
   this.dbService.createDatabase();

   /*  
   *   Vérification de la présence de données saisies en cours
   *   afin d'éviter d'insérer des données 'vides' dans la base 
   */
   let temp = this.navParams.get('signal.signalement');
   if (temp!='') {
      this.signalementFinal = this.navParams.get('signal');

      //insertion des données récupérées duu formaulaire dans la base de données locale SQLite
      this.dbService.insertInto(this.signalementFinal);
   }

   //transfert des données SQLite vers le tableau 'listeSignalements' et Affichage
   this.dbService.selectAll(this.listeSignalements);
}

This is because I felt currently you are populating the listeSignalements array before even inserting the data into the database and hence not getting the records perhaps.