Seite 1 von 1

jpg in Postgres Datenbank zu QImage

Verfasst: Sonntag 6. Dezember 2020, 12:58
von myoggradio
Guten Tag,
ich habe Bilder im jpg format in einer Postgres Datenbank als bytea abgespeichert.
Wie bekommt man nun diese Daten in eine QImage um sie anzeigen zu können?
Ausprobiert habe ich folgendes, aber es kommt:
TypeError: QImage(): argument 1 has unexpected type 'memoryview'

Code: Alles auswählen

    def listener(self):
        row = self.currentRow()
        name = self.kommentare[row][0]
        print(name)
        content = []
        try:
            connection = psycopg2.connect(user = "user",
                                  password = "xxx",
                                  host = "115.115.115.115",
                                  port = "5432",
                                  database = "scanner")

            cursor = connection.cursor()
            sql = "select content from images"
            sql += " where name = %s"
            cursor.execute(sql,[name])
            records = cursor.fetchall()
            for row in records:
                content.append(row)   
        except (Exception, psycopg2.Error) as error :
            print ("Error PostgreSQL", error)
        finally:
            if(connection):
                cursor.close()
                connection.close()
        bild = content[0][0]  
        self.b = Bild(bild)
        self.b.show()
class Bild(QWidget):
    def __init__(self,bild):
        QWidget.__init__(self)
        self.bild = bild 
        self.initUI()
    def initUI(self):
        self.sid = QImage(self.bild)
        self.w = self.sid.width()
        self.h = self.sid.height()
        self.setGeometry(50,50,600,900)
        self.setWindowTitle("Bild")
    def paintEvent(self,event):
        painter = QPainter()
        painter.begin(self)
        self.drawBild(painter)
        painter.end()
    def drawBild(self,painter):
        painter.drawImage(5,5,self.sid)   


Re: jpg in Postgres Datenbank zu QImage

Verfasst: Sonntag 6. Dezember 2020, 14:57
von __deets__
Deine Fehlerbehandlung ist Fehlerhaft. Wenn du einen Datenbankfehler bekommst, veruchst du danach trotzdem ein Bild-Objekt zu erzeugen. Das ist zwar nicht ursaechlich fuer das Problem hier, aber Grund fuer spaetere Probleme.

Du bindest auch zu viele Attribute an deine Bild-Klasse. Die Daten brauchst du nach dem erzeugen von QImage nicht mehr, aber die leben als self.bild munter weiter. Stattdessen solltest du

- initUI wegwerfen.
- die darin enthaltenen Statements direkt in __init__ platzieren
- bild (was besser bild_daten hiesse) einfach direkt verwenden

Ohne es jetzt selbst auszuprobieren ist es ein bisschen schwierig, dir da verlaesslich etwas zu sagen, aber ich wuerde raten, mal ein QImage zu erzeugen, und dann eine der Methoden hier https://doc.qt.io/qt-5/qimage.html#loadFromData zu verwenden. Falls das immer noch Typfehler wirft, dann mal das memoryview-Objekt zu einem bytes-Objekt zu wandeln. https://docs.python.org/3/library/stdty ... ew.tobytes

Re: jpg in Postgres Datenbank zu QImage

Verfasst: Sonntag 6. Dezember 2020, 16:04
von __blackjack__
Der ``finally``-Zweig ist auch Murks. ``if connection`` ist immer wahr beziehungsweise ein `NameError` falls `connection` überhaupt nicht existiert wenn der Verbindungsaufbau zu einer Ausnahme geführt hat. Und falls die Verbindung existiert ist dadurch nicht garantiert, dass `cursor` existiert. Das kann da auch zu einem `NameError` führen.

Am besten macht man das mit ``with`` und `contextlib.closing()`.

Re: jpg in Postgres Datenbank zu QImage

Verfasst: Sonntag 6. Dezember 2020, 17:07
von myoggradio
Die loadFromData Methoden funktionieren bei mir nicht. Bin wohl zu dusselig.
Habe jetzt die Daten in eine Datei geschrieben und sie von da aus ins QImage befördert.
Das klappt wenigstens.

Code: Alles auswählen

class Bild(QWidget):
    def __init__(self,bild):
        QWidget.__init__(self)
        with open("temp.jpg","wb") as file:
            file.write(bild)
            file.close()
        self.sid = QImage("temp.jpg").scaled(595,842)
        self.setGeometry(50,50,600,900)
        self.setWindowTitle("Bild")
    def paintEvent(self,event):
        painter = QPainter()
        painter.begin(self)
        painter.drawImage(5,5,self.sid)   
        painter.end()

Re: jpg in Postgres Datenbank zu QImage

Verfasst: Sonntag 6. Dezember 2020, 17:10
von __deets__
Durch das with-statement brauchst du kein close. Und du solltest deine temporaere Datei mit dem tempfile-Modul erstellen, sonst bekommst du ggf. Probleme.

Re: jpg in Postgres Datenbank zu QImage

Verfasst: Sonntag 6. Dezember 2020, 19:03
von __blackjack__
@myoggradio: Was heisst ”funktionieren nicht”? Bei mir funktioniert das. Auch mit einem `memoryview()`. Was kann man da denn falsch machen bei dem Methodenaufruf?

Code: Alles auswählen

#!/usr/bin/env python3
from pathlib import Path

from PyQt5.QtGui import QImage


def main():
    image_data = memoryview(Path("test.jpg").read_bytes())

    image = QImage()
    if not image.loadFromData(image_data):
        raise ValueError("Can't load image from data.")
    
    print(image.size())


if __name__ == "__main__":
    main()
Ausgabe:

Code: Alles auswählen

PyQt5.QtCore.QSize(1920, 1080)
Was zu dem "test.jpg" passt was ich da verwendet habe.

Re: jpg in Postgres Datenbank zu QImage

Verfasst: Sonntag 6. Dezember 2020, 19:56
von myoggradio
@__blackjack__
Habe deinen Code eingebaut. Jetzt funktioniert es auch bei mir. Kann gar nicht mehr sagen, was ich da falsch gemacht hatte.

Jedenfalls vielen Dank Euch beiden für Eure Mühe :-)

Re: jpg in Postgres Datenbank zu QImage

Verfasst: Montag 7. Dezember 2020, 07:43
von Sirius3
Noch Anmerkungen zur Datenbankabfrage:
host und port und password gehören nicht mitten in einen Listener, sondern als Konstanten an den Anfang der Datei. Das Erzeugen einer Connection am besten in eine Funktion auslagern.
fetchall liefert als Ergebnis schon eine Liste, das mit einer for-Schleife nochmal in eine Liste umzuwandeln ist unnötig.
Wenn man aber nur ein Element von der SQL-Abfrage erwartet, ist fetchone das richtige.

Code: Alles auswählen

DB_USER = "user"
DB_PASSWORD = "xxx"
DB_HOST = "115.115.115.115"
DB_PORT = "5432"
DB_DATABASE = "scanner"

def get_db_connection():
    return psycopg2.connect(user=DB_USER, password=DB_PASSWORD,
        host=DB_HOST, port=DB_PORT, database=DB_DATABASE)

[...]
        try:
            with contextlib.closing(get_db_connection()) as connection:
                with contextlib.closing(conncetion.cursor()) as cursor:
                    cursor.execute("SELECT content FROM images WHERE name = %s", [name])
                    content = cursor.fetchone()
        except Exception as error:
            print("Error PostgreSQL", error)
        else:
            if content is None:
                print("Bild nicht gefunden")
            else:
                bild = content[0]
[...]