Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Python/MySQLdb] Ajout / Récupération d'images

Sujet résolu
    21 juillet 2015 à 22:43:20

    Bonsoir,

    J'essaye depuis ce matin en vain d'ajouter une image dans la base de donnée qui contient un champ de type LONGBLOB.

    Mais j'ai cette erreur récurante quand j'utilise MySQLdb.escape_string(photoA) ou même sans l'utiliser : 

    UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte

    La table en question : 

    CREATE TABLE Pieces(
    	id INT(11) NOT NULL AUTO_INCREMENT,
    	photoA LONGBLOB,
    	photoR LONGBLOB,
    	valeur INT(11) NOT NULL,
    	type INT(11) NOT NULL,
    	date VARCHAR(15) NOT NULL,
    	periode INT(11) NOT NULL,
    	etat INT(11) NOT NULL,
    	estimation DECIMAL(12,4),
    	quantite INT(11) NOT NULL,
    	PRIMARY KEY(id),
    	FOREIGN KEY(valeur) REFERENCES Valeurs(id),
    	FOREIGN KEY(type) REFERENCES Types(id),
    	FOREIGN KEY(periode) REFERENCES Periodes(id),
    	FOREIGN KEY(etat) REFERENCES Etats(id)
    	);

    Et le bout de code gérant l'ouverture de l'image puis la requête d'insertion : 

    		try :
    			with open("1c_DUPRE_1848_A-TTB.jpg", 'rb') as f:
    				photoA = f.read()
    				f.close()
    
    			print(self.path_fullA)
    		except:
    			traceback.print_exc();
    			photoA = None
    
    		try : 
    			with open("1c_DUPRE_1848_A-TTB.jpg", 'rb') as f:
    				photoR = f.read()
    				f.close()
    
    			print(self.path_fullR)
    		except :
    			traceback.print_exc();
    			photoR = None
    
    		db = self.connectToDatabase()
    		cur = db.cursor()
    
    		print(photoA[:10])
    		
    		args = (photoA, photoR)
    
    		req = "INSERT INTO Pieces (photoA, photoR, valeur, type, date, periode, etat, estimation, quantite)\
    		 			values (%s, %s, (SELECT id FROM Valeurs WHERE valeur = '{}'), (SELECT id FROM Types WHERE type ='{}'),\
    		 			'{}', (SELECT id FROM Periodes WHERE periode = '{}'), (SELECT id FROM Etats WHERE etat = '{}'),\
    		 			'{}', '{}');".format(valeur, type, date, periode, etat, estimation, quantite)
    
    		try:
    			# Execute the SQL command
    			cur.execute(req, args)
    			# Commit your changes in the database
    			db.commit()
    		except:
    			traceback.print_exc();
    			# Rollback in case there is any error
    			db.rollback()
    
    		db.close()

    Quelqu'un à déjà planché sur ce genre de cas? Car j'ai beau me renseigner sur internet, faire des test, rien n'y fait ...

    J'ai suivis ce bout de code explicatif : 

    Merci de votre attention :euh:


    • Partager sur Facebook
    • Partager sur Twitter
      27 juillet 2015 à 13:32:26

      Personne n'a été confronté à ce problème d'encodage ? :o
      • Partager sur Facebook
      • Partager sur Twitter
        27 juillet 2015 à 16:46:41

        T'es sûr qu'en ligne 29 c'est bien values (%s, %s, ? Alors que tu utilises format ensuite...

        • Partager sur Facebook
        • Partager sur Twitter
          29 juillet 2015 à 17:43:05

          Même avec la requête comme ceci :

          req = "INSERT INTO Pieces (photoA, photoR, valeur, type, date, periode, etat, estimation, quantite)\
          		 			values (%s, %s, (SELECT id FROM Valeurs WHERE valeur = %s), (SELECT id FROM Types WHERE type = %s),\
          		 			%s, (SELECT id FROM Periodes WHERE periode = %s), (SELECT id FROM Etats WHERE etat = %s),\
          		 			%s, %s);"
          
          		args = (photoA, photoR, valeur, type, date, periode, etat, estimation, quantite)
          
          		try:
          			cur.execute(req, args) #Ligne de l'erreur UnicodeDecodeError
          			db.commit()
          		except:
          			traceback.print_exc()
          			db.rollback()
          
          		db.close()

          Erreur : 

          line 166, in add
              cur.execute(req, args)
            File "/usr/local/Cellar/python3/3.4.1_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/MySQL_python-1.2.4-py3.4-macosx-10.9-x86_64.egg/MySQLdb/cursors.py", line 183, in execute
              query = query.format( *db.literal(args) )
            File "/usr/local/Cellar/python3/3.4.1_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/MySQL_python-1.2.4-py3.4-macosx-10.9-x86_64.egg/MySQLdb/connections.py", line 256, in literal
              return self.escape(o, self.encoders)
            File "/usr/local/Cellar/python3/3.4.1_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/MySQL_python-1.2.4-py3.4-macosx-10.9-x86_64.egg/MySQLdb/converters.py", line 118, in quote_tuple
              return escape_sequence(t, d)
            File "/usr/local/Cellar/python3/3.4.1_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/MySQL_python-1.2.4-py3.4-macosx-10.9-x86_64.egg/MySQLdb/connections.py", line 197, in bytes_literal
              return db.literal(u.decode(bytes_literal.charset))
          UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte




          • Partager sur Facebook
          • Partager sur Twitter
            29 juillet 2015 à 22:36:37

            Heu ... tu utilises MySQLdb, non? Ce n'est pas compatible avec Python 3. Tu peux essayer à la place mysqlclient ou PyMySQL.

            • Partager sur Facebook
            • Partager sur Twitter
              31 juillet 2015 à 14:13:47

              J'ai installé mysqlclient et ça ne change rien :

              https://github.com/PyMySQL/mysqlclient-python/blob/master/doc/user_guide.rst

              Déjà je comprends pas pourquoi il essaye de convertir des bytes en UTF-8..

              J'ai fais un autre test juste sur l'ouverture d'image : 

              			with open("2F_FRANCISQUE_1943_A-TTB.jpg") as f:
              				photoA = f.read()
              				f.close()

              Et l'erreur correspondante : 

              Traceback (most recent call last):
                File "/Users/Joaquim/Desktop/Travaux en cours/Monnaies Database/addEntry.py", line 138, in add
                  photoA = f.read()
                File "/usr/local/Cellar/python3/3.4.1_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/codecs.py", line 313, in decode
                  (result, consumed) = self._buffer_decode(data, self.errors, final)
              UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte




              -
              Edité par CactusTribe 31 juillet 2015 à 14:32:40

              • Partager sur Facebook
              • Partager sur Twitter
                31 juillet 2015 à 14:36:46

                Dans ton petit exemple, tu ouvres le fichier en mode text. Essaie à la place

                with open("2F_FRANCISQUE_1943_A-TTB.jpg", "rb") as f:
                    photoA = f.read()
                    # Et puisqu'on a utilisé with..., il n'est plus nécessaire de fermer le fichier
                # Ici il se ferme automatiquement.
                

                Il essaie de convertir les bytes en texte. Et par défaut il essaie avec l'encodage UTF-8. Il aurait pu essayer avec de l'ASCII ou autre, mais ça ne change rien à ton problème.

                • Partager sur Facebook
                • Partager sur Twitter
                  31 juillet 2015 à 15:09:08

                  Oui avec "rb" il n'y à pas ce problème, du coup pour le moment le code en est là : 

                  import pymysql
                  import pymysql.cursors
                  
                  def add(self):
                  
                  		valeur = self.comboBoxValeur.currentText()
                  		type = self.comboBoxType.currentText()
                  		date = self.lineEditDate.text()
                  		periode = self.comboBoxPeriode.currentText()
                  		etat = self.comboBoxEtat.currentText()
                  		estimation = self.doubleSpinBoxEstimation.value()
                  		quantite = self.spinBoxQuantite.value()
                  
                  		try :
                  			with open("2F_FRANCISQUE_1943_A-TTB.jpg", 'rb') as f:
                  				photoA = f.read()
                  
                  			print(self.path_fullA)
                  		except:
                  			traceback.print_exc();
                  			photoA = None
                  
                  		try : 
                  			with open("2F_FRANCISQUE_1943_R-TTB.jpg", 'rb') as f:
                  				photoR = f.read()
                  
                  			print(self.path_fullR)
                  		except :
                  			traceback.print_exc();
                  			photoR = None
                  
                  		db = self.connectToDatabase()
                  		cur = db.cursor()
                  
                  		print(photoA[:10]) #Test d'affichage des 10 permiers bytes
                  
                  		req = "INSERT INTO Pieces (photoA, photoR, valeur, type, date, periode, etat, estimation, quantite)\
                  		 			values (%s, %s, (SELECT id FROM Valeurs WHERE valeur = %s), (SELECT id FROM Types WHERE type = %s),\
                  		 			%s, (SELECT id FROM Periodes WHERE periode = %s), (SELECT id FROM Etats WHERE etat = %s),\
                  		 			%s, %s);"
                  
                  		args = (photoA, photoR, valeur, type, date, periode, etat, estimation, quantite)
                  
                  		try:
                  			cur.execute(req, args) #Ligne de l'erreur UnicodeDecodeError
                  			db.commit()
                  		except:
                  			traceback.print_exc()
                  			db.rollback()
                  
                  		db.close()

                  Avec toujours la même erreur même en pymysql..

                  None
                  None
                  b'\xff\xd8\xff\xe0\x00\x10JFIF'
                  Traceback (most recent call last):
                    File "/Users/Joaquim/Desktop/Travaux en cours/Monnaies Database/addEntry.py", line 170, in add
                      cur.execute(req, args) #Ligne de l'erreur UnicodeDecodeError
                    File "/usr/local/lib/python3.4/site-packages/pymysql/cursors.py", line 97, in execute
                      escaped_args = tuple(conn.escape(arg) for arg in args)
                    File "/usr/local/lib/python3.4/site-packages/pymysql/cursors.py", line 97, in <genexpr>
                      escaped_args = tuple(conn.escape(arg) for arg in args)
                    File "/usr/local/lib/python3.4/site-packages/pymysql/connections.py", line 579, in escape
                      return escape_item(obj, self.charset)
                    File "/usr/local/lib/python3.4/site-packages/pymysql/converters.py", line 30, in escape_item
                      val = val.decode(charset)
                  UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte




                  • Partager sur Facebook
                  • Partager sur Twitter
                    31 juillet 2015 à 16:14:43

                    Alors j'ai pas testé de mon côté car je n'ai pas de drivers mysql. Mais dans le principe, tu dois decoder les bytes de photoA en utf-8, mais en utilisant surrogateescape. Donc ça donnerait

                    import pymysql
                    import pymysql.cursors
                    

                    def add(self):

                        valeur = self.comboBoxValeur.currentText()
                        type = self.comboBoxType.currentText()
                        date = self.lineEditDate.text()
                        periode = self.comboBoxPeriode.currentText()
                        etat = self.comboBoxEtat.currentText()
                        estimation = self.doubleSpinBoxEstimation.value()
                        quantite = self.spinBoxQuantite.value()
                    
                        with open("2F_FRANCISQUE_1943_A-TTB.jpg", 'rb') as f:
                            photoA = f.read()
                    
                        print(self.path_fullA)
                    
                        with open("2F_FRANCISQUE_1943_R-TTB.jpg", 'rb') as f:
                            photoR = f.read()
                    
                        print(self.path_fullR)
                    
                        db = self.connectToDatabase()
                        cur = db.cursor()
                    
                        print(photoA[:10]) #Test d'affichage des 10 permiers bytes
                    
                        req = "INSERT INTO Pieces (photoA, photoR, valeur, type, date, periode, etat, estimation, quantite)\
                                    values (%s, %s, (SELECT id FROM Valeurs WHERE valeur = %s), (SELECT id FROM Types WHERE type = %s),\
                                    %s, (SELECT id FROM Periodes WHERE periode = %s), (SELECT id FROM Etats WHERE etat = %s),\
                                    %s, %s);"
                        photoA_str = photoA.decode('utf8', 'surrogateescape')
                        photoR_str = photoR.decode('utf8', 'surrogateescape')
                        args = (photoA_str, photoR_str, valeur, type, date, periode, etat, estimation, quantite)
                    
                        try:
                            cur.execute(req, args) #Ligne de l'erreur UnicodeDecodeError
                            db.commit()
                        except:
                            traceback.print_exc()
                            db.rollback()
                    
                        db.close()
                    
                    </pre>

                    Et bien entendu, lorsque tu liras les données de ta base de données, il faudra alors retransformer ce que te donne les champs photoA et photoR en utilisant photoA.encode('utf8', 'surrogateescape').

                    -
                    Edité par Dan737 31 juillet 2015 à 16:15:28

                    • Partager sur Facebook
                    • Partager sur Twitter
                      31 juillet 2015 à 18:15:48

                      Merci mais j'ai une autre erreur du coup :euh:

                      None
                      None
                      b'\xff\xd8\xff\xe0\x00\x10JFIF'
                      Traceback (most recent call last):
                        File "/Users/Joaquim/Desktop/Travaux en cours/Monnaies Database/addEntry.py", line 172, in add
                          cur.execute(req, args) #Ligne de l'erreur UnicodeDecodeError
                        File "/usr/local/lib/python3.4/site-packages/pymysql/cursors.py", line 108, in execute
                          query = query.encode(charset)
                      UnicodeEncodeError: 'utf-8' codec can't encode character '\udcff' in position 107: surrogates not allowed
                      • Partager sur Facebook
                      • Partager sur Twitter
                        31 juillet 2015 à 18:30:27

                        Te connectes-tu bien à la db avec Connection(host="localhost", user='blah', password='12345', charset='utf-8', ...)? Le charset est important!

                        Aussi assures-toi bien que dans ta définition de ta table, tu aies ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci.

                        Et as-tu bien la dernière version de pymysql? Un petit pip install -U pymysqlfera l'affaire.

                        -
                        Edité par Dan737 31 juillet 2015 à 18:32:30

                        • Partager sur Facebook
                        • Partager sur Twitter
                          31 juillet 2015 à 19:58:58

                          Parfait merci ça marche ! Effectivement ça venait de la définition de table.

                          Par contre pour la lecture la création de l'image avorte.

                          Le code : 

                          					image_data_str = str(row[e])
                          					image_data = image_data_str.encode('utf8', 'surrogateescape')
                          					img = QImage.fromData(image_data)
                          					imgscaled = img.scaled(100, 100, Qt.KeepAspectRatio);
                          
                          					item = QTableWidgetItem()
                          					item.setData(Qt.DecorationRole, QPixmap.fromImage(imgscaled))

                          Erreur : 

                          QImage::scaled: Image is a null image

                          Je suppose que img = QImage.fromData(image_data) n'arrive pas à lire les données de image_data ?

                          EDIT : Résolu, enfait pas besoin de décoder pour lire, la création de l'image se fait comme ceci : 

                          					image_data_str = row[e]
                          					img = QImage.fromData(image_data_str)
                          					imgscaled = img.scaled(100, 100, Qt.KeepAspectRatio);
                          
                          					item = QTableWidgetItem()
                          					item.setData(Qt.DecorationRole, QPixmap.fromImage(imgscaled))




                          -
                          Edité par CactusTribe 31 juillet 2015 à 20:12:30

                          • Partager sur Facebook
                          • Partager sur Twitter

                          [Python/MySQLdb] Ajout / Récupération d'images

                          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                          × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                          • Editeur
                          • Markdown