Page 1 sur 2
SQlite et champs BLOB
Publié : jeu. 17/déc./2015 16:13
par falsam
Dans une base de données SQL ont peut stocker des informations de type TEXT ou INTEGER etc ..... mais aussi de type
BLOB
Cet type de champ permet de stocker par exemple des images et çà sera le thème de ce sujet.
Prérequis : Connaissance de PureBasic (
of course) ainsi que de SQLite ou autres bases de données de type SQL.
Avant de commencer je vous propose cette courte vidéo pour vous montrer le résultat final.
https://www.youtube.com/watch?v=eewRoK9W2sc
Pour commencer nous allons créer une base de données très simple permettant de stocker des images.
Cette base de données contiendra la table
media ayant cette structure
- IdMedia de tpe index auto incrémenté (INTEGER PRIMARY KEY)
- Image de type BLOB
- Filename de type TEXT
Créer un dossier et enregistrer le code de création de la base de données. Exemple :
Medias - Create Database.pbCode : Tout sélectionner
EnableExplicit
Global Database.i
Global DatabaseName.s = "assets.sqlite", ReqSql.s
;Création d'un fichier vierge
If CreateFile(Database, DatabaseName)
CloseFile(Database)
Else
MessageRequester("Erreur", "Impossible de créer un fichier")
End
EndIf
;Ouverture et création de la base de données
UseSQLiteDatabase()
If OpenDatabase(Database, DatabaseName, "", "", #PB_Database_SQLite)
;Préparation de la requête de création de la table des medias
ReqSql = "CREATE TABLE medias (IdMedia INTEGER PRIMARY KEY, Image BLOB, FileName TEXT)"
;Exécution de la requete
DatabaseUpdate(Database, ReqSql)
CloseDatabase(Database)
If DatabaseError() = ""
MessageRequester("Information","Création de la base terminée")
Else
MessageRequester("Information","Erreur lors de la création de la table 'medias'" + #CRLF$ + DatabaseError())
EndIf
Else
MessageRequester("Erreur","Erreur lors de la création de la base de données" + Chr(13) + DatabaseError() )
EndIf
C'est terminée avec la création de la base de données.
Vous pouvez utiliser
SQLite Explorer pour voir la structure de la base.
Passons maintenant à l'exploitation des images ........
Re: SQlite et champs BLOB
Publié : jeu. 17/déc./2015 16:14
par falsam
Expoitation des images.
Enregistrer ce code dans le dossier contenant la base de données que nous venons de créer. Exemple: Medias.pb
Ce code permet
-Sélectionner une image et l'enregistrer dans la base de données.
-Afficher chacune des images dans une fenêtre.
-Supprimer une image.
La base de données est ouverte qu'une seule fois lors de l’exécution et fermer quand on quitte l'application.
Code : Tout sélectionner
; PureBasic 5.70 LTS (x64)
EnableExplicit
Enumeration
#DataBase
#ImageFile
#Buffer
EndEnumeration
Enumeration Window
#MainForm
EndEnumeration
Enumeration Gadget
#Selector
EndEnumeration
;Plan du code
Declare Start() ;Début
Declare ShowMedia(LastSequence = #False) ;Affichage d'une ou des images
Declare OnSelectMedia() ;Sélection d'une image
Declare OnDeleteMedia() ;Suppression d'une image
Declare OnClose() ;Fin
Start()
Procedure Start()
UseJPEGImageDecoder()
UsePNGImageDecoder()
UseSQLiteDatabase()
OpenDatabase(#DataBase, "assets.sqlite", "","", #PB_Database_SQLite)
OpenWindow(#MainForm, 0, 0, 800, 600, "SQLite et les champs de type BLOB", #PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_SizeGadget)
ButtonGadget(#Selector, 10, 10, 180, 32, "Sélectionner une image")
ShowMedia() ;Affichage de toutes les images
;Evenements
BindEvent(#PB_Event_CloseWindow, @OnClose())
BindGadgetEvent(#Selector, @OnSelectMedia())
Repeat : WaitWindowEvent(10) : ForEver
EndProcedure
;Affichage de la derniere image ou toutes les images
Procedure ShowMedia(LastSequence = #False)
Protected Window, IdMedia, ImageEncode.s, FileName.s, *Buffer, Result, Gadget
If LastSequence = #True
;Selection de la derniere image
DatabaseQuery(#DataBase, "SELECT IdMedia, image, filename FROM Medias ORDER BY IdMedia DESC LIMIT 1")
Else
;Selection de toutes les images
DatabaseQuery(#DataBase, "SELECT IdMedia, image, filename FROM Medias")
EndIf
;Affichage du resultat : Chaque image est affichée dans une fenetre
While NextDatabaseRow(#Database)
IdMedia = GetDatabaseLong(#Database, 0)
ImageEncode = GetDatabaseString(#Database, 1)
FileName = GetDatabaseString(#DataBase, 2)
*Buffer = AllocateMemory(Len(ImageEncode)*1.35)
Result = Base64Decoder(ImageEncode, *Buffer, MemorySize(*Buffer))
If Result
ReAllocateMemory(*Buffer, Result)
CatchImage(#Buffer, *Buffer)
Window = OpenWindow(#PB_Any, 0, 0, ImageWidth(#Buffer), ImageHeight(#Buffer) + 50, FileName, #PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_TitleBar)
ImageGadget(#PB_Any, 0, 0, 0, 0, ImageID(#Buffer))
;Ajout du bouton de suppression
;Mémorisatio de l'index d'enregistrement
;Initialisation du Callback de suppression
Gadget = ButtonGadget(#PB_Any, 10, ImageHeight(#Buffer) + 10, 80, 22, "Supprimer")
SetGadgetData(Gadget, IdMedia)
BindGadgetEvent(Gadget, @OnDeleteMedia())
StickyWindow(Window, #True)
EndIf
Wend
EndProcedure
;Selection d'une image
Procedure OnSelectMedia()
Protected Pattern.s = "Image Files (*.bmp, *.jpg, *.png)|*.bmp;*.jpg;*.png"
Protected FileName.s = OpenFileRequester("Sélectionner une image", "", Pattern, 0)
Protected ImageEncode.s, *Buffer, Result.s
If FileName <> ""
;Lecture et encodage de l'image
If ReadFile(#ImageFile, FileName)
*Buffer = AllocateMemory(Lof(#ImageFile))
ReadData(#ImageFile, *Buffer, Lof(#ImageFile))
CloseFile(#ImageFile)
ImageEncode = Space(MemorySize(*Buffer)*1.35)
Result = Base64Encoder(*Buffer, MemorySize(*Buffer))
ImageEncode = RTrim(Result)
EndIf
;Enregistrement de l'image dans la base de données
DatabaseUpdate(#DataBase, "INSERT INTO medias (Image, FileName) VALUES ('" + ImageEncode + "', '" + GetFilePart(FileName) + "')")
;Affichage de la DERNIERE image insérée
ShowMedia(#True)
EndIf
EndProcedure
;Suppression d'une image
Procedure OnDeleteMedia()
Protected IdMedia = GetGadgetData(EventGadget())
DatabaseUpdate(#DataBase, "DELETE FROM Medias WHERE IdMedia=" + IdMedia)
If DatabaseError() <> ""
MessageRequester("Information", "Erreur lors de la suppression" + #CRLF$ + DatabaseError())
Else
CloseWindow(EventWindow())
EndIf
EndProcedure
Procedure OnClose()
Protected Window = EventWindow()
Select Window
Case #MainForm
CloseDatabase(#DataBase)
End
Default
CloseWindow(Window)
EndSelect
EndProcedure
Vous pouvez utiliser
SQLite Explorer pour voir la structure et les données de la base.
Re: SQlite et champs BLOB
Publié : jeu. 17/déc./2015 17:19
par falsam
Modification du code d'exploitation des images : Il est possible de supprimer une image de la base de données.
Re: SQlite et champs BLOB
Publié : sam. 02/mars/2019 16:22
par falsam
Hello. Modification du code d'exploitation des images pour être en conformité avec la version 5.70 de PureBasic.
Ce code a été testé dans un environnement Windows 10 x64 et Mac OS x64.
Re: SQlite et champs BLOB
Publié : sam. 02/mars/2019 16:30
par Fig
Je me demandais pourquoi je n'avais pas eu la notification youtube... Et puis j'ai vu la date du sujet, tout s'explique. ^^
Merci pour cette mise à jour en tout cas.

Re: SQlite et champs BLOB
Publié : sam. 02/mars/2019 16:41
par falsam
Le sujet date un peu et avait besoin d'une bonne mise à jour. Ce qui me désole c'est de ne pas pouvoir lire les bases de données précédentes une fois le code mise à jour.
Suivant les versions de PureBasic, Les fonctions Base64Encoder() et Base64Decoder() ne fonctionnent pas de la même manière. Compiler avec PureBasic 5.70, mon ancienne base de données contenant des images n'est plus exploitable !
Re: SQlite et champs BLOB
Publié : sam. 02/mars/2019 22:09
par Ollivier
Ça donne quoi si tu dématérialises le hachage ?
(pour test j'entends

)
Re: SQlite et champs BLOB
Publié : sam. 02/mars/2019 23:09
par falsam
Ollivier a écrit :Ça donne quoi si tu dématérialises le hachage ?
(pour test j'entends

)
Je te laisse le soin d'essayer et de nous faire part de ton expérimentation !
Re: SQlite et champs BLOB
Publié : dim. 03/mars/2019 17:59
par Ollivier
"Petit Prince", je ne veux pas te piquer, mais ne me demande pas de faire un sprint pour t'aider. Ça sert à rien : c'est toi qui a les jambes.
Au vu de la simplicité de cette fonction, je suppose que c'est le goulot pour permettre une compatibilité infinie des outils de traitement, pas la sécurité.
Je me trompe?
Re: SQlite et champs BLOB
Publié : dim. 03/mars/2019 18:30
par falsam
Ollivier a écrit :"Petit Prince", je ne veux pas te piquer, mais ne me demande pas de faire un sprint pour t'aider. Ça sert à rien
Ca sert à rien ? Evite de me poser des questions dans ce cas quand tu peux obtenir des réponses par toi même !
Re: SQlite et champs BLOB
Publié : dim. 03/mars/2019 20:18
par Mouillard
Bonsoir à tous,

Si Si ça sert à quelque chose ....Bravo Falsam très bonne
Et j'ajoute de très bons codes ""Mériteraient" un recyclage de ce genre, sinon ces codes seront perdus à jamais...
Car derrière il y a l'idée... POUR AVANCER encore et encore

Merci Falsam

Re: SQlite et champs BLOB
Publié : lun. 04/mars/2019 0:44
par Ollivier
Ne t'égare pas Falsam. Et ne m'invente pas je ne sais quel contexte.
Je pose les questions AVANT que ton travail de mise à jour soit fait. Parce qu'on ne va sûrement pas s'amuser en ASM, APRES avec un gagnant qui crie victoire juste pour la gratuité de l'amusement et toi qui doit te REtaper une autre mise à jour (Si j'ai bien saisi ta problématique).
Re: SQlite et champs BLOB
Publié : lun. 04/mars/2019 7:18
par Marc56
Je n'ai pas lu tout le code, mais il n'est plus nécessaire d'encoder les images (Base64Encoder) depuis la v5.40
Le type de données
Blob, c'est du binaire, on peut y mettre n'importe quoi directement.
L'encodage64 c'est pour transformer du binaire en texte quand on est sur un système 7 bits.
À partir de la version 5.40 LTS (16 octobre 2015) on a
SetDatabaseBlob() qui fera le job tout seul.
D'où effectivement l'intérêt de "moderniser" les tutos
Voir les posts de srod
https://www.purebasic.fr/english/viewto ... 12#p498212

Re: SQlite et champs BLOB
Publié : lun. 04/mars/2019 14:12
par Ollivier
Merci Marc56 pour ton aide inlassable et grâcieuse.
Re: SQlite et champs BLOB
Publié : lun. 04/mars/2019 15:11
par Marc56
La procédure OnSelectMedia() peut donc être simplifiée si on a PB >= 5.40 LTS
Code : Tout sélectionner
;Selection d'une image
Procedure OnSelectMedia()
Protected Pattern.s = "Image Files (*.bmp, *.jpg, *.png)|*.bmp;*.jpg;*.png"
Protected FileName.s = OpenFileRequester("Sélectionner une image", "", Pattern, 0)
Protected *Buffer
If FileName <> ""
;Lecture et encodage de l'image
If ReadFile(#ImageFile, FileName)
*Buffer = AllocateMemory(Lof(#ImageFile))
ReadData(#ImageFile, *Buffer, Lof(#ImageFile))
CloseFile(#ImageFile)
SetDatabaseBlob (#DataBase, 0, *Buffer, MemorySize(*Buffer))
SetDatabaseString (#DataBase, 1, GetFilePart(FileName))
EndIf
DatabaseUpdate(#DataBase, "INSERT INTO medias (Image, FileName) VALUES (?, ?)")
;Affichage de la DERNIERE image insérée
;ShowMedia(#True)
EndIf
EndProcedure
On peut vérifier que l'image est bien stockée dans la base avec par exemple
SQLiteStudio qui affiche le champs image (double-clic que le champ image, puis onglet 3)

Reste à modifier ShowMedia() pour que l'exemple soit complet.
C'est quand même bien ces variables de liaison

(
requêtes préparées / Prepared statement)
