• Willkommen im Linux Club - dem deutschsprachigen Supportforum für GNU/Linux. Registriere dich kostenlos, um alle Inhalte zu sehen und Fragen zu stellen.

IPTC Daten aus .csv Datei in Bilder integrieren?

Andrea70

Newbie
Hallo zusammen,

ich habe einen riesigen Ordner mit Bildern und eine mit Libre Office Calc erstellte .csv-Datei in welcher sich alle Bildnamen (Spalte A) und alle Schlagwörter für Agenturen (Spalte B) befinden.
Jetzt bin ich nicht besonders bewandert mit dem Umgang des Terminals, lese jedoch immer wieder, wie leicht es damit sei, sich Arbeit durch den Computer abnehmen zu lassen, indem man gewisse Vorgänge automatisiert...
Meine Frage ist nun: Kann man mit dem Terminal / Konsole eine csv-Datei einlesen lassen und die Schlagwörter aus Spalte B den Bildern deren Bildnamen in Spalte A stehen automatisch zuweisen? Und falls ja, wie? Und falls nein, welche andere Möglichkeit gäbe es hier?
Vielleicht sollte ich noch zusätzlich erwähnen, dass es auch eine Spalte C gibt, in der die Bildnamen stehen, die später für die Agenturen sind. Diese sind nicht identisch mit meinen Bildnamen. Diese müssten dann bestenfalls gleich mit geändert werden...

Ich bin für jede Unterstützung sehr dankbar
Andrea
 

abgdf

Guru
Ohne das schomal gemacht zu haben, ergibt die Suche, daß es möglich ist.

Metadaten von Bildern können im Exif-Format dazugespeichert werden.

Es gibt Module für die Sprachen Perl:
https://metacpan.org/pod/Image::ExifTool

und Python:
https://pypi.org/project/exif/

Damit kann man Exif-Informationen in Bilddateien schreiben. Einlesen von csv-Dateien und deren Verarbeitung in einem Skript ist kein Problem.

Auch der Shell-Befehl "exif" kann offenbar Exif-Informationen schreiben. Also auch die bash-Fraktion kommt wieder zum Zug.
Ich würde aber eine Lösung in Perl oder Python bevorzugen, da mE flexibler.
 
OP
A

Andrea70

Newbie
@abgdf

vielen Dank für deine Antwort.
Python klingt schon mal gut. Ich hatte irgendwann mal angefangen es zu erlernen, bin aber nicht besonders weit gekommen und würde es mir heute nicht zutrauen, darin etwas zu programmieren.
Perl kenne ich ehrlich gesagt nur vom Namen her...

Vielleicht gibt es ja schon fertige Skripte in Python für meinen Fall?!?
 

abgdf

Guru
Andrea70 schrieb:
Python klingt schon mal gut. Ich hatte irgendwann mal angefangen es zu erlernen
Das ist doch schonmal gut, dann hast Du zumindest eine Vorstellung. Gut, gehen wir mal in Richtung Python.
Andrea70 schrieb:
Vielleicht gibt es ja schon fertige Skripte in Python für meinen Fall?!?
Das glaube ich nicht, weil ja niemand wissen kann, wie Deine Tabelle angeordnet ist. Deshalb schreibt man für sowas ja spezielle Skripte.
Eine (csv-)Datei einlesen (und auf der Konsole ausgeben) würde man in Python so machen:
Code:
#!/usr/bin/python
# coding: utf-8

import os

filename = "dein_dateiname"

fh = open(filename, "r")
a = fh.readlines()
fh.close()

for i in a:
    i = i.rstrip("\n")
    print i
Würde das bei Dir gehen?

- Ein Backup Deiner Dateien machen. Skripte sollten nur auf einer Kopie wichtiger Dateien ausgeführt werden.
- Skripttext in Editor pasten und als "skript.py" speichern.
Dabei beachten, daß die Einrückungen stimmen, die sind in Python von Bedeutung.
Dateinamen im Skript anpassen.
- Skript ausführbar machen:
Code:
chmod +x skript.py
- Skript starten:
Code:
./skript.py
Ach so, was sagt
Code:
python -V
(Python-Version)?
 
OP
A

Andrea70

Newbie
Danke erstmal für die Unterstützung,

also noch bekomme ich es nicht zum laufen.
Installiert habe ich Python 3.8.6.
Habe Skript als skript.py gespeichert und ausführbar gemacht. Bekomme jedoch folgende Meldung ins Terminal:

Code:
studio@studio-hppaviliondesktoppc570p0xx:~/test$ ./skript.py
bash: ./skript.py: /usr/bin/python: Defekter Interpreter: Datei oder Verzeichnis nicht gefunden
 
OP
A

Andrea70

Newbie
So, jetzt läuft es. Hat ein bisschen gedauert, bis ich meine Fehler bemerkt hatte.
Die erste Zeile habe ich von:
Code:
#!/usr/bin/python
in:
Code:
#!/usr/bin/python3
geändert.
Dann habe ich noch Zeile 14 geändert von:
Code:
print i
in
Code:
print (i)
.
Manchmal sieht man den Wald vor lauter Bäumen nicht.
Als Ergebnis bekomme ich jetzt also eine Liste der Bildnamen in der Konsole angezeigt...
 

abgdf

Guru
Andrea70 schrieb:
Als Ergebnis bekomme ich jetzt also eine Liste der Bildnamen in der Konsole angezeigt...
Sehr gut!

Sind es nur die Bildnamen? Ich stelle mir eher Zeilen vor mit
Code:
Dateiname_Bild	Bildbezeichnung
Die müßte man dann jeweils trennen, mit 'b = i.split("\t")' oder was der csv-Trenner ist (das müßte man herausfinden, "\t" wäre das Tabulatorzeichen). So daß man einerseits den Dateinamen des Bildes hat, und andererseits das, was man als exif-Information in das Bild hineinschreiben will.

Wäre es möglich, Beispieldaten zu posten, wie diese Zeilen genau aussehen?
Andrea70 schrieb:
Hat ein bisschen gedauert, bis ich meine Fehler bemerkt hatte.
Das waren übrigens nicht Deine, sondern eher meine Fehler. Ich war von Python 2.7 ausgegangen (das ich meist benutze).

Wahrscheinlich werde ich nicht schaffen, dieses Modul, das für Python3 ist, bei mir zu installieren. Aber das macht nichts: Man kann auch aus einem Python-Skript heraus Shell-Befehle wie "exif" aufrufen. Dann braucht man das Modul nicht.

Was ist das übrigens für ein Bildformat? Der "exif"-Befehl geht angeblich nur für jpg. Mal gucken, wie man das bei anderen Formaten machen würde.
 

abgdf

Guru
exif scheint nicht so das gute Programm zu sein. Besser wird es mit "exiv2".

Oder "exiftool", das offenbar das Perl-Modul aufruft. Das geht auch mit anderen Formaten als jpg. Ist aber kompliziert in der Syntax.

exiv2 ist da auch nicht so ohne. Man muß wissen, in welchen Tag man hineinschreiben will.
Und das Encoding könnte ein (großes) Problem werden, wenn man da deutsche Umlaute reinschreiben will.
Also, dieses geht soweit, es schreibt das Wort "Test" als Exif-Information in eine Bilddatei "01.jpg" (mit IPTC bin ich mir noch nicht so sicher, aber das gehört da auch irgendwie dazu):
Code:
exiv2 -M "set Exif.Photo.UserComment Comment charset=Undefined Test" 01.jpg
In eine Stelle für Kommentare.
Wenn man den Autor des Bildes reinschreiben will, sollte man eine andere Stelle wählen.
Kommt darauf an, was man reinschreiben. Im Zweifel "Fischer hat schuld." :)

-------------

Aber wenn da nicht noch die Sache mit den Umlauten ist, ist man dann schon fast da.
Ein bißchen Datenverarbeitung mit den csv-Dateien, dann die exiv2-Befehle zusamenstellen. Dann drüberlaufenlassen, testen, und das müßte es sein.
 
OP
A

Andrea70

Newbie
Hallo abgdf,

also ich hatte jetzt mal eine andere Beispieldatei erstellt und komme bis jetzt zu folgendem Ergebnis:

Code:
studio@studio-hppaviliondesktoppc570p0xx:~/test$ ./skript.py
Bildname,Schlagwörter,Titel für Agentur
IMG_001.jpeg,"Gitarre, Saiten, Korpus, Musikinstrument, Musik, Klang, Korpus, Holz, Konzert",Spanische Konzertgitarre. Freigestellt vor weißem Hintergrund.
IMG_002.jpeg,"Violine, Hintergrund, Instrument, Musik, Musikalisch, Hölzern, Melodie",Violine. Freigestellt vor schwarzem Hintergrund. Nahaufnahme.
IMG_003.jpeg,"Piano, Konzert, Komponist, Antik, Gesang, Jazz, Melodie",Grand Piano vor schwarzem Hintergrund. Frontalansicht.
IMG_004.jpeg,"Schlagzeug, Trommel, Musik, Rock, Chrom, Becken, Konzert, Stuhl",Schlagzeug. Vogelperspektive. Freigestellt.
IMG_005.jpeg,"Elektrisch, Gitarre, Musik, Rock, Instrument, Modern, Saiten",E-Gitarre. Nahaufnahme.
IMG_006.jpeg,"Triangel, Musik, Musikinstrument, Dreieck, Hobby",Triangel. Freigestellt vor weißem Hintergrund.
IMG_007.jpeg,"Kopfhörer, Musik, Erholung, Entspannung, Hobby",Kopfhörer. Makroaufnahme. Freigestellt.
IMG_008.jpeg,"Laute, Klassisch, Musik, Historisch, Mittelalter, Unterhaltung",Klassische Laute. Frontalansicht. Freigestellt.
IMG_009.jpeg,"Ukulele, Musik, Klassisch, Saiten, Gitarre, Traditionell, Bespannt",Traditionelle Ukulele. Tiefenschärfe
IMG_010.jpeg,"Geige, Musikinstrument, Holz, Hintergrund, Konzert, Klassizismus",Zwei Geigen auf hölzernem Untergrund.

Das schaut jetzt schon mal so aus, wie du es beschrieben hattest, wenn ich nicht irre.
Das mit den Umlauten ist kein Problem. Da würde ich einfach "Suchen und Ersetzen" machen.

Da es sich bei meinen Bildern grundsätzlich um jpeg handelt tendiere ich am ehesten zu exiv2.
Das mit den Tags ist tatsächlich so eine Sache. Ich hatte das früher mal mit Gimp gemacht (Bildtitel und Schlagwörter) und da waren es bei unterschiedlichen Agenturen auch unterschiedliche Felder, in die ich schreiben musste.
Heute geht es mir aber nur noch um eine Agentur und so müsste ich wissen, welche (Tags) es überhaupt gibt, und das dann mit der Agentur ausprobieren.

Bis hierhin auf jeden Fall schon mal vielen Dank für die Unterstützung.

PS. Wo finde ich in der Zeile den oder die (Tags)?
Code:
exiv2 -M "set Exif.Photo.UserComment Comment charset=Undefined Test" 01.jpg
 
OP
A

Andrea70

Newbie
Also mit exif2 mal ausprobiert und ich finde "test" in den exif Metadaten bei Gimp.
So weit so gut...
Bis hierhin läuft alles schon mal.
 

abgdf

Guru
Andrea70 schrieb:
Also mit exif2 mal ausprobiert und ich finde "test" in den exif Metadaten bei Gimp.
So weit so gut...
Bis hierhin läuft alles schon mal.
Ja. Jetzt muß man (im Python-Skript) noch die Daten aus Deiner Tabelle ziehen, sie (mit "split()") so zerteilen, daß man Dateinamen und Exif-Text(e) bekommt.
Also z.B. so (das sind jetzt nur Code-Bruchstücke als Beispiel, wie man das prinzipiell macht):
Code:
separator = "\t"
data = "dateiname\tbildtext"
print(data)

b = data.split(separator)
filename = b[0]
text     = b[1]

print("Filename: " + filename)
print("Text: " + text)
Dann mit diesen (String-)Variablen in einer Schleife für jede Bilddatei Strings für die exiv2-Befehle formulieren.
Also z.B. so:
Code:
filename = "meine_datei"
text     = "meine_text"
execstr  = 'exiv2 -M "set Exif.Photo.UserComment Comment charset=Undefined ' + text + '" ' + filename
print(execstr)
Schließlich die exiv2-Befehle im Python-Skript über " os.system() " ausführen.
Code:
os.system(execstr)
Das wäre der Weg.

Wie gesagt, wenn ich helfen soll, wären ein paar Beispieldaten aus der Tabelle von Vorteil.
Es müssen nicht die echten Daten sein, es können auch (ausgedachte) Dummy-Daten sein, es kommt nur auf den genauen Aufbau der Tabelle an, also z.B. darauf, welches das csv-Trennzeichen für die Spalten ist ("separator" oben). Oder halt, in welcher Spalte sich der Dateiname befindet und welchen Text aus welcher Spalte Du in den Metadaten der Bilder haben möchtest.
Oder kommst Du schon allein zurecht?
 
OP
A

Andrea70

Newbie
Das sieht ja schon wahnsinnig toll und vielversprechend aus.
Wie kann ich dir eine Dummy-csv zukommen lassen.
Irgendwie finde ich hier keine Möglichkeit eine Datei hochzuladen, außer als Bild
 

abgdf

Guru
Andrea70 schrieb:
Das sieht ja schon wahnsinnig toll und vielversprechend aus.
Dankeschön! :)
Andrea70 schrieb:
Wie kann ich dir eine Dummy-csv zukommen lassen.
Irgendwie finde ich hier keine Möglichkeit eine Datei hochzuladen, außer als Bild
Das ist ja Nur-Text ("csv" heißt "comma-separated values"). Den kann man in [code und [/code -Tags posten.
Dürfte ja nicht so lang sein, denke ich.

Sonst könnte ich Dir auch per PN meine Email-Adresse senden.
 
OP
A

Andrea70

Newbie
Ich denke Zeilenweise:

Code:
Bildname	Schlagwörter	Titel für Agentur
Code:
IMG_001.jpeg	Gitarre, Saiten, Korpus, Musikinstrument, Musik, Klang, Korpus, Holz, Konzert	Spanische Konzertgitarre. Freigestellt vor weißem Hintergrund.
Code:
IMG_002.jpeg	Violine, Hintergrund, Instrument, Musik, Musikalisch, Hölzern, Melodie	Violine. Freigestellt vor schwarzem Hintergrund. Nahaufnahme.
Code:
IMG_003.jpeg	Piano, Konzert, Komponist, Antik, Gesang, Jazz, Melodie	Grand Piano vor schwarzem Hintergrund. Frontalansicht.
Code:
IMG_004.jpeg	Schlagzeug, Trommel, Musik, Rock, Chrom, Becken, Konzert, Stuhl	Schlagzeug. Vogelperspektive. Freigestellt.
Code:
IMG_005.jpeg	Elektrisch, Gitarre, Musik, Rock, Instrument, Modern, Saiten	E-Gitarre. Nahaufnahme.
Soweit also mal für fünf Bilder:
Ich hoffe, dass ich es so richtig gemacht habe, damit du was damit anfangen kannst.
 

abgdf

Guru
Ok.

Hab' mir statt exiv2 nochmal exiftool angesehen, und das scheint mir noch besser zu sein.
Es scheint auch Umlaute verarbeiten zu können.
Offenbar gibt es unzählige Tag-Formate und feste Untertags, so daß man festlegen muß, in welche man hineinschreibt.
Bei
Code:
exiftool -author="Van Gogh" -Comment="Schönes Bild" 01.jpg
z.B. würde der Autor bei gimp in "Datei/Eigenschaften/Erweitert" angezeigt, der Kommentar dagegen in "Bild/Bildeigenschaften/Kommentar". Was irgendwie cool wäre.
IPTC-Tags werden in gimp dagegen nur im Metadaten-Viewer angezeigt - den es offenbar erst seit gimp 2.9 gibt (ich habe hier leider nur 2.8 ). Aber ich kann sie z.B. im Bildbetrachter geeqie sehen.
Welche Untertags IPTC zuläßt, wäre hier beschrieben. Es gibt wie gesagt unzählige andere Optionen als IPTC. Z.B. führt "-author" oben anscheinend zu "PDF".

Also: Ich bin erstmal bei IPTC geblieben, und da bei den Tags "Headline" und "Keywords". Die Tagnamen sind wie gesagt vorgegeben.
exiftool müßtest Du installieren (sollte aber eigentlich kein Problem sein).
Mein Skript erzeugt dann ein Unterverzeichnis "output" und schreibt da die neuen Bilder rein. So daß von den ursprünglichen Dateien nur gelesen wird.
Die Bilddateien und die Datendatei sollten im aktuellen Verzeichnis zusammen mit dem Skript sein (es sei denn, die Dateinamen in der Datendatei weisen woanders hin).
Die "Dummy-Daten" hatte ich der Einfachheit halber im Skript gelassen. Wenn es läuft, kann man die Funktion "getDummyData()" auch herausnehmen:
Code:
#!/usr/bin/python
# coding: utf-8

import os, sys

DATAFILE = "your_datafile"

OUTDIR = "output"
IPTC_TAGS = {"headline" : "IPTC:Headline", "keywords" : "IPTC:Keywords"}

separator = "\t"

def getDummyData():
    data= """IMG_001.jpeg	Gitarre, Saiten, Korpus, Musikinstrument, Musik, Klang, Korpus, Holz, Konzert	Spanische Konzertgitarre. Freigestellt vor weißem Hintergrund.
IMG_002.jpeg	Violine, Hintergrund, Instrument, Musik, Musikalisch, Hölzern, Melodie	Violine. Freigestellt vor schwarzem Hintergrund. Nahaufnahme.
IMG_003.jpeg	Piano, Konzert, Komponist, Antik, Gesang, Jazz, Melodie	Grand Piano vor schwarzem Hintergrund. Frontalansicht.
IMG_004.jpeg	Schlagzeug, Trommel, Musik, Rock, Chrom, Becken, Konzert, Stuhl	Schlagzeug. Vogelperspektive. Freigestellt.
IMG_005.jpeg	Elektrisch, Gitarre, Musik, Rock, Instrument, Modern, Saiten	E-Gitarre. Nahaufnahme."""
    return data.split("\n")

def getDataFromFile():
    fh = open(DATAFILE, "r")
    data = fh.readlines()
    fh.close()
    return data

# data = getDummyData()

data = getDataFromFile()

outdir = os.path.join(os.getcwd(), OUTDIR)
if os.path.exists(outdir):
    print
    print "Error: Output path '" + outdir +"' already exists. Nothing done."
    print
    sys.exit(1)
else:
    os.mkdir(outdir)

for i in data:
    i = i.rstrip("\n")
    (filename, keywords, headline) = i.split(separator)
    execstr  = "exiftool "
    execstr += "-" + IPTC_TAGS["headline"] + "=\"" + headline + "\" "
    execstr += "-" + IPTC_TAGS["keywords"] + "=\"" + keywords + "\" "
    execstr += "-o \"" + outdir + "\" "
    execstr += filename
    print execstr
    print
    os.system(execstr)
Hoffe, es funktioniert irgendwie. ;)

Ach ja, die Anfangszeile und die print-Befehle müßtest Du wieder auf Python3 anpassen.
 
OP
A

Andrea70

Newbie
Also du machst dir echt viel Arbeit mit mir. Vielen Dank dafür.
Ich habe jetzt exiftool installiert, den Programmcode im selben Verzeichnis wie die Bilder gespeichert, die Datei ausführbar gemacht und die Befehle auf python3 geändert.
Doch jetzt gibt es eine Meldung in der Konsole, die ich nicht verstehe.
Code:
studio@studio-hppaviliondesktoppc570p0xx:~/test$ ./iptc.py
Traceback (most recent call last):
  File "./iptc.py", line 42, in <module>
    (filename, keywords, headline) = i.split(separator)
ValueError: not enough values to unpack (expected 3, got 1)
Da wüsste ich jetzt spontan nicht, was ich zu tun hätte?!?
 

abgdf

Guru
Ja, jetzt geht's ans Debuggen. Man muß sich da langsam herantasten und dabeibleiben, dann klappt es wahrscheinlich irgendwann. Man muß hartnäckig sein.
Die Zeile
Code:
(filename, keywords, headline) = i.split(separator)
war etwas kurz, normalerweise schreibe ich es lieber aus - bin dafür in einem Python-Forum aber mal scharf kritisiert und schließlich sogar rausgeschmissen worden. Also eigentlich bedeutet das eben:
Code:
b = i.split(separator)
filename = b[0]
keywords = b[1]
headline = b[2]
Ok. Die Fehlermeldung sagt, er müßte eigentlich durch die Trennung der Zeile mit dem Separator 3 Werte erhalten (b[0], b[1] und b[2]). Er erhält aber nur einen.
Das heißt, in den Daten ist entweder ein anderer Separator als "\t" oder die Daten sind nicht präzise aufgebaut.
Was da genau das Problem ist, kann ich von hier ohne die Daten nicht reproduzieren. Vielleicht eine anders aufgebaute Überschriftszeile?
Vielleicht sollte man vor die "for i .." Schleife ein
Code:
x = 1
einfügen, und in die Schleife an den Anfang ein
Code:
    print(x)
    x += 1
Dann gibt er Dir wenigstens die Zeile aus, in der das Problem in Deinen Daten auftritt.

Als Probe kannst Du auch mal die Dummy-Daten laufenlassen, indem Du
Code:
# data = getDummyData()
data = getDataFromFile()
änderst zu
Code:
data = getDummyData()
# data = getDataFromFile()
Wenn Du da die 5 Bilder IMG_001.jpeg, usw. im Verzeichnis hast, solltest Du sehen, daß das Skript mit den Dummy-Daten läuft.
Von da muß man sich dann an die echten Daten herantasten.

Skripte laufen meist nie beim ersten Mal. Man muß da eigentlich immer noch etwas anpassen.
Das ist natürlich schwieriger, wenn man das aus der Ferne in Bezug auf Daten machen muß, die man nicht selbst vorliegen hat.
Andrea70 schrieb:
Also du machst dir echt viel Arbeit mit mir. Vielen Dank dafür.
Gern. Bei größeren Projekten im kommerziellen Bereich (Agentur, usw.) würde man auch jemanden bezahlen, man könnte z.B. hier einen Perl-Programmierer anheuern.
Aber ich wußte, daß es im Prinzip nur ein ganz kleines Skript wird, da kann man das schonmal als Gefälligkeit über dieses Forum machen.
Und wenn beide Seiten mitmachen, macht es ja auch Spaß. Mir zumindest.
 

abgdf

Guru
Das ist eine gute Idee, werte Gräfin! Das sollte man so einbauen, und auch noch mehr solche Überprüfungen machen.

Inzwischen habe ich eine Email mit einigen Daten erhalten.
Die Zeilen der csv-Datei sehen zur Zeit so aus:
Code:
text,"text, text, text",text, text
Trennzeichen ist bisher also das Komma, was ich nicht optimal finde, weil ja auch Kommata innerhalb der Spaltentexte sind. Seltsam finde ich auch, daß im Mittelteil Anführungszeichen sind, in den Außenspalten aber nicht.
Man könnte jetzt bei ',"' und '",' trennen, aber das finde ich nicht optimal, denn dazu müßten ja in wirklich jeder Zeile diese Anführungszeichen sein, was ich nicht direkt überprüfen kann.
Ich habe also per Email darum gebeten, die csv-Datei nochmal mit "\t" als Trenner zu speichern (wenn das möglich ist).
In OpenOffice gibt es da beim Abspeichern links das Kästchen "Filtereinstellungen bearbeiten". Ist es angewählt, erscheint ein besonderes Dialogfenster, in dem man unter "Feldtrenner" das Zeichen zum Trennen der Spalten auswählen kann.

Möglicherweise sind meine Emails im Spamordner untergegangen? Bitte prüfe das noch einmal, Andrea70.
 
Oben