Couchdb python - Upload Attachment mit put_attachment

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
sophe_9
User
Beiträge: 34
Registriert: Dienstag 7. Mai 2019, 10:40

Hallo,

ich versuche an ein bereits existierendes Document ein Bild bzw. Plot als png anzuhängen. Es wird auch angehängt, aber es erscheint folgender Fehler: " Die Grafik kann nicht angezeigt werden, weil sie Fehler enthält".
Ich vermute die Codierung ist fehlerhaft, da auch die Länge in dem Dokument ebenfalls nicht korrekt ist.

Wenn ich das Bild direkt über Futon anhänge sieht der Anhang folgendermaßen aus:

"_attachments": {
"Scan.png": {
"content_type": "image/png",
"revpos": 35,
"digest": "md5-t20y23eHOJOMDAwCcrTjOw==",
"length": 199281,
"stub": true
}
}

Über Python ist "length": 8

Wie kann ich das korrigieren?

Code: Alles auswählen

import couchdb 
couch = couchdb.Server('http://a73657.berlin.de:5984')
db = couch['vl'] # existing

json_file = "test_file"

doc = db.get(json_file) 


db.put_attachment(doc, 'Scan.png', 'Scan.png', content_type="image/png;base64")
__deets__
User
Beiträge: 14544
Registriert: Mittwoch 14. Oktober 2015, 14:29

Also ohne da jetzt tiefer eingestiegen zu sein: wo uebergibst du denn die Bilddaten, und wer kodiert die base64? Ich sehe zweimal den Dateinamen, der dann auch noch zufaellig 8 Zeichen lang ist. Einer davon muss doch garantiert die Bilddaten sein. Wahlweise raw, oder als base64-enkodierte Daten.
sophe_9
User
Beiträge: 34
Registriert: Dienstag 7. Mai 2019, 10:40

Danke für die Antwort,
ich habe bei den Beschreibungen " put_attachment(doc, content, filename=None, content_type=None)" gefunden, mit einer Textdatei hat es wunderbar funktioniert. Nur pdfs oder images sind ein Problem.

Wahrscheinlich ist mein Ansatz falsch, wahrscheinlich muss ich den Plot laden, codieren und dann anhängen??

Hier das Beispiel, dass funktioniert:

Code: Alles auswählen

from matplotlib import pyplot as plt
import couchdb 
couch = couchdb.Server('http://a73434.berlin.ptb.de:5984')
db = couch['vl_db'] # existing

json_file = "cal_test"

doc = db.get(json_file) 


with open('test.txt','r') as fp:
    datatxt = fp.read()
    print(datatxt)
    
db.put_attachment(doc, datatxt, "datatxt.txt" , content_type="text/plain")
Hier ist mein Plot - Beispiel, dass nicht funktioniert:

Code: Alles auswählen

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import couchdb 
couch = couchdb.Server('http://a73434.berlin.ptb.de:5984')
db = couch['vl_db'] # existing
json_file = "cal_test"
doc = db.get(json_file) 


img = mpimg.imread('Scan.png')
imgplot = plt.imshow(img)
plt.show()


db.put_attachment(doc, img, "scan_plot.png" , content_type="image/png")

Jetzt erhalte ich diesen Fehler:

TypeError: Object of type ndarray is not JSON serializable
__deets__
User
Beiträge: 14544
Registriert: Mittwoch 14. Oktober 2015, 14:29

Also ich weiss nicht, was du bei der Textdatei gemacht hast. Aber content ist der Inhalt, nicht der Name der Datei, die den Inhalt enthaelt. So wuerde ich das jedenfalls sehen. Und die Hypothese wird ja auch von der Dateilaenge "8" gestuetzt, die ja nun genau die Laenge des Namens, nicht des Inhaltes, ist.

Und statt numpy solltest du das PNG einfach als Bytes einlesen, und uebergeben, oder eben noch base64 enkodieren.

Code: Alles auswählen

content = pathlib.Path("pfad-zum-png").read_bytes()  # ggf noch durch base64 jagen.
Diese ganzen relativen Pfade (cal_test, scan_plot.png) werden dir auch irgendwann mal auf die Fuesse fallen, sowas sollte als Argumente uebergeben oder relativ zum Skript mit __file__ aufgeloest werden.
sophe_9
User
Beiträge: 34
Registriert: Dienstag 7. Mai 2019, 10:40

So ganz habe ich es noch nicht verstanden.
content ist der Inhalt, den ich anhängen möchte. In meinem Fall "img".

Es funktioniert leider noch nicht.

Code: Alles auswählen

with open("Scan.png", "rb") as img_file:
    img = base64.b64encode(img_file.read())
img = img.decode('utf-8')

db.put_attachment(doc, img, "scan_plot.png" , content_type="image/png")

__deets__
User
Beiträge: 14544
Registriert: Mittwoch 14. Oktober 2015, 14:29

Was heisst "funktioniert nicht"? Und warum hast du hier das base64 im content_type entfernt, aber enkodierst damit?
sophe_9
User
Beiträge: 34
Registriert: Dienstag 7. Mai 2019, 10:40

Auch damit habe ich keinen Erfolg.

Code: Alles auswählen

db.put_attachment(doc, img, "scan_plot.png", content_type="image/png;base64")
Benutzeravatar
sparrow
User
Beiträge: 4195
Registriert: Freitag 17. April 2009, 10:28

@sophe9: was heißt denn kein Erfolg?
Fehlermeldung? Hinweise? Woran machst du fest, dass es nicht geht?

Warum enkodierst du den Inhalt der Datei, nur um sie abschließend wieder zu dekorieren?
__deets__
User
Beiträge: 14544
Registriert: Mittwoch 14. Oktober 2015, 14:29

@sparrow: das wird sein um aus Bytes einen String zu machen. Schadet denke ich eher nicht.
sophe_9
User
Beiträge: 34
Registriert: Dienstag 7. Mai 2019, 10:40

Beim Öffnen des Attachments in der CouchDB erhalte ich folgende Fehlermeldung:

" Die Grafik kann nicht angezeigt werden, weil sie Fehler enthält".

Laut Beschreibung von dem Paket "couch-python", sollte es mit "put_attachment(doc, content, filename=None, content_type=None)" funktionieren.


Ich sehe folgendes in der Datenbank: Beide Attachments beziehen sich auf das gleiche Bild.

image1 per Futon, das ist supi -- scan, leider nicht

Code: Alles auswählen

"_attachments": {
    "image1.png": {
      "content_type": "image/png",
      "revpos": 26,
      "digest": "md5-lZl1QyGtwhkLdWtltIo2og==",
      "length": 62890,
      "stub": true
    },
    "scan.png": {
      "content_type": "image/png",
      "revpos": 22,
      "digest": "md5-RU3QV7mPpcr9VjQ2C02B6A==",
      "length": 83976,
      "stub": true
    }
    
    
__deets__
User
Beiträge: 14544
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dann wuerde ich mal sagen musst du die base64-enkodierung sein lassen, denn offensichtlich ist das Bild genau die 33% groesser, die man bei einem base64-enkodierten Sack Bytes erwarten wuerde.

Also das Ding loeschen, und in deinem Code oben base64 sowohl als Aufruf als auch als encoding weg.
sophe_9
User
Beiträge: 34
Registriert: Dienstag 7. Mai 2019, 10:40

Code: Alles auswählen

img = mpimg.imread('Scan.png')

db.put_attachment(doc, img, "scan.png" , content_type="image/png")
Dann erhalte ich folgenden Fehler:

File ~\AppData\Local\Programs\Python\Python312\Lib\json\encoder.py:180 in default
raise TypeError(f'Object of type {o.__class__.__name__} '

TypeError: Object of type ndarray is not JSON serializable
__deets__
User
Beiträge: 14544
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich wiederhole mich: du sollst nicht numpy benutzen, um dein Bild einzulesen. Gibt es einen Grund, warum den den Code, den ich dir in Beitrag #4 gezeigt habe, nicht verwendest?

Nachtrag: laut https://couchdb-python.readthedocs.io/e ... attachment kannst du sogar einfach nur einen geoeffneten File uebergeben, das wuerde ich machen.
sophe_9
User
Beiträge: 34
Registriert: Dienstag 7. Mai 2019, 10:40

Vielen Dank.

das war die Lösung!

Jetzt habe ich es verstanden, eine base64 Enkodierung ist nicht mehr nötig.

:lol: :lol: :lol:
Antworten