J'ai mis en place une base de données SQLite qui lit et écrit parfaitement NSString
s. Je souhaite également stocker une image dans la base de données et la rappeler ultérieurement. J'ai un peu lu sur l'utilisation de NSData
et le codage de l'image, mais je ne suis pas tout à fait sûr de la syntaxe de ce que je veux faire. Des extraits de code ou des exemples seraient grandement appréciés.
Mon processus actuel est le suivant: UIImagePickerController
-> L'utilisateur choisit une image dans Photos -> ChoisiImage est défini sur une instance de UIImageView
-> Je souhaite maintenant prendre cette image et la stocker dans la base de données
Je devrais mentionner que cet appel sera éventuellement remplacé par un appel à un serveur distant. Vous ne savez pas si cela fait une différence en termes de performances.
Une option (et généralement préférable lorsque vous travaillez en SQL) consiste à écrire l'image dans un fichier du système et à stocker le chemin d'accès (ou un autre type d'identificateur) dans la base de données.
Vous devez convertir UIImage hébergé dans votre UIImageView en un BLOB binaire pour le stockage dans SQLite. Pour ce faire, vous pouvez utiliser les éléments suivants:
NSData *dataForImage = UIImagePNGRepresentation(cachedImage);
sqlite3_bind_blob(yourSavingSQLStatement, 2, [dataForImage bytes], [dataForImage length], SQLITE_TRANSIENT);
Cela va générer une représentation PNG de votre image, la stocker dans une instance de NSData, puis lier les octets de NSData en tant que BLOB pour le second argument de votre requête SQL. Utilisez UIImageJPEGRepresentation dans ce qui précède pour stocker dans ce format, si vous le souhaitez. Une colonne BLOB doit être ajoutée à la table appropriée dans votre base de données SQLite.
Pour récupérer cette image, vous pouvez utiliser les éléments suivants:
NSData *dataForCachedImage = [[NSData alloc] initWithBytes:sqlite3_column_blob(yourLoadingSQLStatement, 2) length: sqlite3_column_bytes(yourLoadingSQLStatement, 2)];
self.cachedImage = [UIImage imageWithData:dataForCachedImage];
[dataForCachedImage release];
Apple recommande de ne pas stocker les BLOB dans des bases de données SQLite supérieures à environ 2 kilo-octets.
SQLite organise les bases de données en pages. Chaque page a une taille de 4 kilo-octets. Lorsque vous lisez des données à partir du fichier de base de données SQLite, ces pages sont chargées dans un cache de page interne. Sur l’iPhone, la taille par défaut du cache est de 1 Mo par défaut. Cela rend la lecture des enregistrements adjacents très rapide car ils seront probablement déjà dans le cache de pages.
Lorsque SQLite lit votre enregistrement de base de données en mémoire, il lit l'intégralité de l'enregistrement et toutes les pages qu'il occupe. Ainsi, si votre enregistrement contient un BLOB, celui-ci pourrait occuper de nombreuses pages et vous éjecterez les pages existantes du cache en les remplaçant par les pages de votre enregistrement BLOB.
Ce n’est pas si grave si vous ne faites que scanner et charger tous vos BLOBs pour en faire quelque chose (affichez-les par exemple). Mais si vous avez fait une requête dans laquelle vous vouliez simplement que certaines données se trouvent dans la même ligne que le BLOB, cette requête serait beaucoup plus lente que si l'enregistrement ne contenait pas le grand BLOB.
Donc, au minimum, vous devriez stocker vos données BLOB dans un tableau séparé. Par exemple:
CREATE TABLE blobs ( id INTEGER PRIMARY KEY, data BLOB );
CREATE TABLE photos ( id INTEGER PRIMARY KEY, name TEXT, blob_id INTEGER,
FOREIGN KEY(blob_id) REFERENCES blobs(id) );
Ou mieux encore, stockez les données BLOB en tant que fichiers en dehors de la base de données SQLite.
Notez qu'il peut être possible de modifier la taille du cache de page avec les instructions SQL PRAGMA (si vous n'utilisez pas CoreData).
Écrire une image dans une base de données SQLite
if(myImage != nil){
NSData *imgData = UIImagePNGRepresentation(myImage);
sqlite3_bind_blob(update_stmtement, 6, [imgData bytes], [imgData length], NULL);
}
else {
sqlite3_bind_blob(update_stmtement, 6, nil, -1, NULL);
}
Lecture à partir de la base de données SQLite:
NSData *data = [[NSData alloc] initWithBytes:sqlite3_column_blob(init_statement, 6) length:sqlite3_column_bytes(init_statement, 6)];
if(data == nil)
NSLog(@"No image found.");
else
self.pictureImage = [UIImage imageWithData:data];
La meilleure pratique consiste à compresser l'image et à la stocker dans la base de données ou le système de fichiers. Si vous ne vous souciez pas de la résolution de l'image, vous pouvez continuer et même redimensionner l'image en utilisant:
UIGraphicsBeginImageContext(newSize);
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Après cela, vous pouvez utiliser UIImageJPEGRepresentation
pour les images JPEG avec une valeur de "0" pour une compression maximale. Ou vous pouvez utiliser UIImagePNGRepresentation
pour les images png
vous devriez d’abord écrire une image sur le système de fichiers. puis prenez le chemin de l'image et stockez ce chemin de l'image (URL) sous forme de texte dans sqlite.