Fotografie-Workflow
Bilder automatisch sortieren, benennen und taggen
Autor: Wolfgang Lessat
Originalquelle:
lessat.net
https://lessat.net/technik/ki-und-automation/projekte/fotografie-workflow/
Die Idee
Nach jedem Fotoausflug dasselbe: hunderte Dateien
mit nichtssagenden Namen wie DSC_4721.jpg
landen im Import-Ordner und warten darauf,
sortiert und benannt zu werden.
Das manuelle Durchsehen, Umbenennen und Einsortieren kostet mehr Zeit als der Ausflug selbst. Die meisten Fotos folgen dabei einem klaren Muster: Datum, Ort, Motiv – das reicht für einen sinnvollen Dateinamen und eine logische Ordnerstruktur.
Zwei dieser drei Informationen stecken bereits im Foto selbst: Das Datum im EXIF-Header, den Ort eventuell als GPS-Koordinate. Das Motiv – was auf dem Bild zu sehen ist – kann seit dem Aufkommen multimodaler KI-Modelle automatisch beschrieben werden. Ein n8n-Workflow kann das alles zusammenführen.
Vorher:
DSC_4721.jpg im Ordner Import/
Nachher:
2026-04-15_hamburg-alster_spaziergang-mit-hund.jpg
im Ordner Fotos/2026/04_April/Hamburg/
Was das Projekt können soll
Klare Anforderungen – und bewusste Nicht-Ziele.
✓ Neue Dateien im Import-Ordner automatisch erkennen.
✓ Aufnahmedatum aus EXIF-Metadaten auslesen.
✓ Bildinhalt per KI beschreiben lassen.
✓ Neuen Dateinamen aus Datum und Beschreibung erzeugen.
✓ Datei in Unterordner nach Jahr und Monat sortieren.
✓ Nur JPEG und RAW-Dateien verarbeiten, andere ignorieren.
✗ Kein automatisches Löschen von Duplikaten.
✗ Keine Bildbearbeitung oder Komprimierung.
✗ Keine Gesichtserkennung oder Personenmarkierung.
✗ Keine Cloud-Synchronisation.
✗ Keine Änderung von RAW-Dateien – nur Umbenennen.
Die Lösung im Überblick
Fünf Schritte vom Rohdatei-Import bis zur sortierten Bibliothek.
Workflow-Ablauf:
[Watch Folder Trigger] neue Datei im Import-Ordner
↓
[Code Node] EXIF-Metadaten auslesen
↓ Datum, Kamera, GPS
[HTTP Request] Bild an Claude API senden
↓ Bildbeschreibung als Text
[Code Node] Dateinamen + Zielpfad erzeugen
↓
[Move/Rename File] Datei umbenennen und verschieben
Der Ablauf ist für jedes Foto identisch: Metadaten lesen → KI fragen → umbenennen → verschieben. Es gibt keine offenen Entscheidungen, keine Rückfragen und keine variablen Schritte. Ein fester Workflow ist hier die richtige Wahl – zuverlässiger, günstiger und leichter zu debuggen als ein Agent. Die KI übernimmt nur einen klar abgegrenzten Schritt: das Beschreiben des Bildinhalts.
Claude Haiku unterstützt multimodale Eingaben – also Text und Bild in einer Anfrage. Es beschreibt Bildinhalte präzise, auf Deutsch und in kompakter Form, was direkt als Dateinamen-Bestandteil verwendbar ist. Alternativ funktioniert auch GPT-4o mit sehr ähnlicher Qualität.
Voraussetzungen
Was bereit sein muss, bevor der erste Node gesetzt wird.
Dieser Workflow greift auf lokale Ordner zu –
das funktioniert nur mit der Desktop-App
oder einer Docker-Instanz auf dem eigenen Rechner.
n8n Cloud hat keinen Zugriff auf das lokale Dateisystem.
→
n8n installieren
Import-Ordner:
Hierhin werden neue Fotos von der Kamera kopiert.
n8n überwacht diesen Ordner.
Beispiel: C:\Fotos\Import\
bzw. /home/benutzer/Fotos/Import/
Ziel-Ordner:
Hier entstehen die sortierten Unterordner.
Beispiel: C:\Fotos\Archiv\
bzw. /home/benutzer/Fotos/Archiv/
Für die Bildbeschreibung wird ein multimodales
Modell benötigt – Claude Haiku unterstützt Bilder
und ist kostengünstig (unter 1 Cent pro Bild
bei typischen Urlaubsfotos).
→ console.anthropic.com
→
API-Keys verwalten
Für das zuverlässige Auslesen von EXIF-Metadaten
ist exiftool das beste Werkzeug.
Kostenlos und für Windows, macOS und Linux verfügbar:
exiftool.org
Alternativ kann der n8n Code-Node EXIF-Daten
über das npm-Paket exifr auslesen –
ohne externe Installation.
Schritt 1: Trigger – neues Foto erkannt
Der Watch Folder Trigger überwacht den Import-Ordner und startet den Workflow bei jeder neuen Datei sofort.
Node: Local File Trigger
(unter n8n-nodes-base)
Name: „Neues Foto erkannt"
Trigger On:
File Added
Path:
Vollständiger Pfad zum Import-Ordner,
z.B. /home/benutzer/Fotos/Import
Recursive: Aus
(nur der direkte Ordnerinhalt, keine Unterordner)
Ignore:
**/*.db, **/*.ini, **/Thumbs.db
(Systemdateien überspringen)
Nach dem Trigger einen IF-Node einfügen,
der nur Bilddateien durchlässt:
Value 1 (Expression):
{{ $json.name.toLowerCase().match(/\.(jpg|jpeg|raw|cr2|nef|arw)$/) ? true : false }}
Operation: Equal
Value 2: true
Andere Dateitypen (z.B. Videos oder Textdateien)
werden damit stillschweigend ignoriert.
Schritt 2: Metadaten auslesen
Ein Code-Node liest Datum, Kamera und GPS-Koordinaten direkt aus dem EXIF-Header der Bilddatei.
Node: Code
Name: „EXIF auslesen"
Language: JavaScript
const { execSync } = require('child_process');
const path = require('path');
const filePath = $json.path;
const fileName = $json.name;
// EXIF über exiftool auslesen (muss installiert sein)
let exifRaw = '';
try {
exifRaw = execSync(
`exiftool -json -DateTimeOriginal -Make -Model -GPSLatitude -GPSLongitude "${filePath}"`,
{ encoding: 'utf8' }
);
} catch(e) {
exifRaw = '[]';
}
const exif = JSON.parse(exifRaw)[0] ?? {};
// Datum parsen (Format: "2026:04:15 10:23:45")
let datumISO = '';
if (exif.DateTimeOriginal) {
const parts = exif.DateTimeOriginal.split(' ');
datumISO = parts[0].replace(/:/g, '-'); // "2026-04-15"
} else {
// Fallback: Datei-Änderungsdatum
datumISO = new Date($json.mtime).toISOString().split('T')[0];
}
const [jahr, monat] = datumISO.split('-');
const monatsNamen = ['Januar','Februar','März','April','Mai','Juni',
'Juli','August','September','Oktober','November','Dezember'];
const monatsName = monatsNamen[parseInt(monat) - 1];
return [{
json: {
originalPath: filePath,
originalName: fileName,
datumISO,
jahr,
monat,
monatsName,
kamera: `${exif.Make ?? ''} ${exif.Model ?? ''}`.trim(),
gpsLat: exif.GPSLatitude ?? null,
gpsLng: exif.GPSLongitude ?? null,
}
}];
Schritt 3: KI beschreibt das Bild
Das Bild wird als Base64 an die Claude API gesendet. Das Modell beschreibt den Inhalt in 3–5 Wörtern – kompakt genug für einen Dateinamen.
Vor dem API-Aufruf muss die Bilddatei
in Base64 umgewandelt werden.
Dafür einen weiteren Code-Node einfügen:
Node: Code
Name: „Bild kodieren"
const fs = require('fs');
const imageBuffer = fs.readFileSync($json.originalPath);
const base64 = imageBuffer.toString('base64');
// Dateityp bestimmen
const ext = $json.originalName.split('.').pop().toLowerCase();
const mimeType = ext === 'jpg' || ext === 'jpeg'
? 'image/jpeg'
: 'image/png';
return [{ json: { ...$json, base64Image: base64, mimeType } }];
Node: HTTP Request
Name: „Claude: Bild beschreiben"
Method: POST
URL: https://api.anthropic.com/v1/messages
Headers:
x-api-key: Credential (Anthropic API-Key)
anthropic-version: 2023-06-01
content-type: application/json
Body (JSON, Expression):
{
"model": "claude-haiku-4-5",
"max_tokens": 60,
"messages": [
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "{{ $json.mimeType }}",
"data": "{{ $json.base64Image }}"
}
},
{
"type": "text",
"text": "Beschreibe dieses Foto in maximal 5 deutschen Wörtern. Nur Substantive und Adjektive, durch Bindestriche verbunden, keine Großbuchstaben, keine Satzzeichen. Beispiel: sonnenuntergang-nordsee-weite oder stadtpark-spaziergang-herbst"
}
]
}
]
}
Die Antwort der API enthält den Text unter:
$json.content[0].text
Einen Code-Node zur Bereinigung anhängen –
Leerzeichen entfernen, Sonderzeichen ersetzen:
const roh = $json.content[0]?.text ?? 'unbekannt';
// Bereinigen: nur Kleinbuchstaben, Bindestriche, keine Umlaute
const sauber = roh
.toLowerCase()
.trim()
.replace(/ä/g, 'ae').replace(/ö/g, 'oe')
.replace(/ü/g, 'ue').replace(/ß/g, 'ss')
.replace(/[^a-z0-9\-]/g, '-')
.replace(/-+/g, '-')
.replace(/^-|-$/g, '')
.substring(0, 50); // Maximallänge
return [{ json: { ...$input.first().json, beschreibung: sauber } }];
Hinweis zu RAW-Dateien:
Rohdateien (CR2, NEF, ARW) können nicht direkt
als Base64 an die Claude API gesendet werden –
das Modell erwartet JPEG oder PNG.
Für RAW-Dateien den Schritt überspringen
und nur mit Datum und Kameraname arbeiten,
oder vorher mit dcraw oder
LibRaw ein Vorschaubild extrahieren.
Schritt 4: Dateiname und Zielpfad erzeugen
Aus Datum und Bildbeschreibung entsteht der neue Dateiname und der Zielordner.
Node: Code
Name: „Dateiname bauen"
const basisPfad = '/home/benutzer/Fotos/Archiv'; // anpassen
const {
datumISO, jahr, monat, monatsName,
beschreibung, originalName
} = $json;
// Dateiendung beibehalten
const ext = originalName.split('.').pop().toLowerCase();
// Neuer Dateiname: 2026-04-15_alster-spaziergang-hund.jpg
const neuerName = `${datumISO}_${beschreibung}.${ext}`;
// Zielordner: /Archiv/2026/04_April/
const zielOrdner = `${basisPfad}/${jahr}/${monat}_${monatsName}`;
// Vollständiger Zielpfad
const zielPfad = `${zielOrdner}/${neuerName}`;
return [{
json: {
...$json,
neuerName,
zielOrdner,
zielPfad,
}
}];
Namenskonflikte vermeiden:
Falls am selben Tag zwei Fotos denselben
Beschreibungstext bekommen – was selten, aber möglich ist –
entsteht ein Namenskonflikt.
Einfache Lösung: den originalen Dateinamen ohne Erweiterung
als eindeutigen Suffix anhängen:
2026-04-15_alster-spaziergang_DSC4721.jpg
Schritt 5: Datei umbenennen und sortieren
Zielordner anlegen falls nicht vorhanden, Datei verschieben, Original löschen.
Node: Code
Name: „Ordner anlegen"
const fs = require('fs');
fs.mkdirSync($json.zielOrdner, { recursive: true });
// recursive: true legt alle fehlenden Ebenen an
return [$input.first()];
Node: Move/Copy File
(unter n8n-nodes-base)
Name: „Datei verschieben"
Operation: Move
Source Path (Expression):
{{ $json.originalPath }}
Destination Path (Expression):
{{ $json.zielPfad }}
Sicherheitsnetz: erst kopieren, dann prüfen:
Wer auf Nummer sicher gehen möchte,
nutzt als Operation Copy statt Move.
Die Originaldatei bleibt im Import-Ordner,
bis manuell geprüft wurde dass alles korrekt sortiert ist.
Erst dann werden die Originale gelöscht.
Für die erste produktive Version empfohlen.
Workflow exportieren und importieren
Der vollständige Workflow als JSON-Datei zum Download.
1. Import-Ordner-Pfad im Local File Trigger anpassen.
2. Basis-Pfad im Code-Node „Dateiname bauen" anpassen.
3. Anthropic Credential hinterlegen.
4. Erst mit einer Kopie testen –
niemals direkt mit dem Original-Fotoarchiv.
5. Wenn alles korrekt sortiert wird,
von Copy auf Move umstellen.
Alternativ zum Download: Inhalt kopieren und in n8n über Workflows → Import from clipboard einfügen.
Sicherheit & Datenschutz
Bilder enthalten persönliche Daten – das verdient besondere Sorgfalt.
Beim Beschreibungsschritt wird das Bild als Base64-Daten an die Claude API übertragen. Anthropic verarbeitet diese Daten zur Beantwortung der Anfrage; nach Angaben von Anthropic werden API-Eingaben nicht für das Training verwendet. Wer private oder sensible Fotos hat, sollte diesen Schritt für solche Bilder deaktivieren oder den Filter auf „nur Landschaften" im System-Prompt einschränken.
Wer keine Bilder an externe Dienste senden möchte, kann stattdessen ein lokales multimodales Modell über Ollama betreiben – z.B. LLaVA oder MiniCPM-V. n8n kann lokale Ollama-Modelle über den Ollama Chat Model-Node ansprechen. Die Beschreibungsqualität ist etwas geringer, aber alle Daten bleiben auf dem eigenen Rechner.
Der Workflow verschiebt Dateien – er löscht sie nicht. Im schlimmsten Fall landet ein Bild im falschen Ordner, ist aber nicht weg. Trotzdem: Vor dem ersten produktiven Einsatz immer mit einem Test-Ordner mit Kopien arbeiten.
Was ich gelernt habe
Ehrliches Fazit nach der Planung und ersten Tests.
Die Bildbeschreibungen von Claude Haiku sind für Dateinamen-Zwecke erstaunlich brauchbar. „sonnenuntergang-elbe-boote" oder „stadtpark-herbst-laub" treffen den Inhalt präzise genug, um das richtige Foto später wiederzufinden. Der Prompt mit explizitem Format-Beispiel (Wörter durch Bindestriche) funktioniert zuverlässig.
Das Base64-Encoding großer Bilder
erzeugt sehr lange Strings –
ein 10-MB-RAW-Foto als Base64
überschreitet das Kontextfenster des Modells.
Lösung: JPEGs vor dem API-Aufruf auf
maximal 2 MB komprimieren,
z.B. mit dem sharp-Paket im Code-Node.
Der Local File Trigger in n8n meldet manchmal dieselbe Datei mehrfach, wenn das Kopieren länger dauert als erwartet (z.B. bei großen RAW-Dateien über USB). Eine einfache Lösung ist das Führen einer JSON-Datei mit bereits verarbeiteten Dateinamen – der Workflow prüft zu Beginn ob der Name bereits enthalten ist und überspringt ihn ggf.
Troubleshooting
Die häufigsten Probleme beim Aufbau dieses Projekts.
Ursache:
exiftool ist nicht im Systempfad.
Lösung Windows:
Vollständigen Pfad im Code angeben,
z.B. C:\\exiftool\\exiftool.exe
Alternative:
npm-Paket exifr im Code-Node verwenden –
keine externe Installation nötig.
Ursache:
Das Modell hält sich nicht immer
exakt an das Format-Beispiel im Prompt.
Lösung:
Den Bereinigungsschritt nach der API-Antwort
robust gestalten – der Code-Node in Schritt 3
normalisiert bereits Umlaute und Sonderzeichen.
Zusätzlich im Prompt expliziter werden:
„Antworte ausschließlich mit Kleinbuchstaben
und Bindestrichen, ohne Leerzeichen."
Ursache:
Trigger feuert mehrmals während
die Datei noch geschrieben wird.
Lösung:
Einen Wait-Node (2–3 Sekunden) direkt
nach dem Trigger einfügen.
So ist die Datei vollständig geschrieben,
bevor der Workflow sie liest.
Ursache:
n8n hat keine Schreibrechte
im Zielverzeichnis.
Lösung:
Berechtigungen des Zielordners prüfen.
Unter Linux/macOS:
chmod 755 /pfad/zum/archiv
oder den Ordner als Benutzer anlegen,
unter dem n8n läuft.
Ideen für Weiterentwicklung
Was das Projekt in einer späteren Version können könnte.
Die EXIF-Daten enthalten oft GPS-Koordinaten.
Eine Reverse-Geocoding-API (z.B. die kostenlose
Nominatim-API von OpenStreetMap) wandelt
Koordinaten in einen Ortsnamen um –
53.5872, 10.0082 →
hamburg-winterhude.
Das macht Dateinamen noch aussagekräftiger.
Claude kann das Bild auch nach technischer Qualität bewerten – scharf, unscharf, Gegenlicht. So könnten offensichtliche Ausschüsse in einen separaten Ordner verschoben werden, statt ins Hauptarchiv zu kommen.
Den Prompt auf Englisch umstellen für eine internationale Dateinamens-Konvention – hilfreich wenn die Fotos später in Tools wie Lightroom oder Capture One verwaltet werden, die englische Stichwörter bevorzugen.
Nach jeder Import-Session eine Telegram-Nachricht senden: „17 Fotos verarbeitet, 3 in Hamburg, 14 in Cuxhaven." Dafür einen zweiten Zeitplan-Workflow, der die Import-Logs des Tages zusammenfasst.
Zurück zur Übersicht KI & Automation
Titel: Fotografie-Workflow
Druckdatum: 18.07.2026
Domain: www.lessat.net