1. Der Anlass
Ein- oder zweimal im Jahr brauche ich eine Collage aus Bildern, so wie hier:

Dafür habe ich kein geeignetes Werkzeug mehr, also habe ich mir eines gebaut, sozusagen einen eigenen Linux-Befehl, der mir aus Bildern in einem Verzeichnis eine Collage erstellt.
2. Das Anwenden
Das Anwenden sieht so aus: Ich öffne die Kommandozeile in einem Verzeichnis mit Bildern drin und tippe „collage“ ein, oder auch mit Details „collage -m 10 -s 200“. Dann wird mir aus den Bildern in dem Verzeichnis, in dem ich gerade bin, eine Collage erzeugt und in dem Verzeichnis gespeichert.

(Weiter unten steht noch, wie man das auch per Mausklick statt mit der Texteingbe macht.)
Das Skript begann als vom Chatboy erzeugte Datei ohne Komfort und Kommandozeilen-Möglichkeiten. Nach und nach habe ich den Code verstanden, verbessert, erweitert, so dass ich jetzt auf der Kommandozeile diese Varianten eingeben kann:
collage | erstellt eine Collage mit Standardeinstellungen aus den Bildern im aktuellen Verzeichnis, das Ergebnis gespeichert im aktuellen Verzeichnis | |
collage -c | heißt: beschneidet die Bilder in quadratische Form mit dem Bildschwerpunkt in der Mitte (das ist ohnehin Standardeinstellung) | |
collage -u | wie oben, beschneidet die Bilder aber nicht quadratisch | |
collage -s 300 | legt Seitenlänge der einzelnen Bilder fest, hier: 300 Pixel | |
collage -m 10 | legt Rahmendicke um jedes Bild fest, hier: 10 Pixel | |
collage -b white | legt Rahmenfarbe fest, hier: white | |
collage -h | ruft Hilfe/Usage auf | |
collage | legt absolut oder relativ Quellverzeichnis für die Bilder fest (wenn keines da ist, wird das aktuelle Verzeichnis genommen) | |
collage /mnt/NAS/Bilder /home/rau | legt zusätzlich zum Quellverzeichnis auch das Zielverzeichnis fest, in das die Collage gespeichert wird (wenn keines da ist, wird das aktuelle Verzeichnis genommen) | |
collage -s 200 -m 15 -b red /mnt/NAS/Bilder /home/rau | Kombination von Optionen und Argumenten |
Alle Optionen müssen vor den Argumenten kommen und sind ansonsten frei kombinierbar.
Den Befehl überall verfügbar machen
Tatsächlich kann ich erst einmal das Skript nicht einfach mit seinem Namen aufrufen, sondern muss diesen mit einer absoluten oder relativen Pfadangabe versehen, selbst wenn ich mich im Verzeichnis befinde, in dem das Skript liegt, also ./collage.sh, eventuell gefolgt von Optionen und Argumenten.
Ich will das Skript aber wie jeden anderen Befehl von überall und ohne Pfadangabe verwenden. Das geht, indem ich eine Kopie davon, oder eine Verknüpfung darauf – gerne auch als „collage“ ohne „.sh“ umbenannt – in ein Verzeichnis lege, das für solche Befehle vorgesehen ist. Bei mir habe ich zu diesem Zweck das Verzeichnis ~/.local/bin angelegt, und das System angewiesen, dieses Verzeichnis hinzuzuziehen, wenn es darum geht, einen Befehl zu suchen. Das geht, indem ich in der Datei ~/.profile die folgenden Zeilen ergänze:
if [ -d "$HOME/.local/bin" ] ; then
PATH="$HOME/.local/bin:$PATH"
fi
(Heißt: Wenn das Verzeichnis ~/.local/bin existiert, dann füge es zu den überwachten Verzeichnissen hinzu. Diese Zeilen gab es bei mir schon, weil in ~/.local/bin auch andere Skripte liegen-)
Wenn ich jetzt einen Befehl eingebe, werden nicht nur die voreingestellten Verzeichnisse danach untersucht, sondern eben auch mein eigenes.
Ins Explorer-Menü integrieren
Ich möchte die Collage nicht nur über die Kommandozeile, sondern auch per Mausklick erstellen; erst einmal, indem ich auf ein Verzeichnis rechtsklicke und dann als Menüoption die Collage erhalten. Das gilt für den Linux-Explorer namens Nemo, den ich verwende.

Damit das geht, habe ich Im Verzeichnis ~/.local/share/nemo/actions eine Datei ergänzt, die collage.nemo_action heißt (nur das hinter dem Punkt ist wichtig) und aus folgenden Zeilen besteht:
[Nemo Action]
Active=true
Name=!Collage erstellen
Comment=Erstelle Collage aus den Bilder in %f
Exec=/bin/bash collage %F %P
Selection=s
Extensions=dir
Quote=double
Damit habe ich den Menüeintrag erzeugt. Das war nicht mein erster; ich hatte schon mit anderen gespielt. Die Zeilen bedeuten:
- es soll einen Menüpunkt geben namens „!Collage erstellen“
- der nur angezeigt wird, wenn man Verzeichnisse ausgewählt hat (Extensions=dir), und zwar auch nur exakt eines davon (Selection=s für single) und nicht etwa mehrere
- bei dessen Aufruf das Collage-Skript aufgerufen wird, und zwar mit zwei Argumenten, nämlich Quellverzeichnis (%F, das angeklickte Element) und Zielverzeichnis (%P, das Eltern-Verzeichnis des angeklickten) – das Skript übernimmt die beiden Argumente dann wie vorgesehen
Sicher könnte ich das erweitern auf mehrere Verzeichnisse, oder die manuelle Auswahl von Bilddateien in einem Verzeichnis, aber dafür, dass ich das eben nur ein- oder zweimal im Jahr brauche, habe ich jetzt schon genug Aufwand getrieben. Das amortisiert sich ja erst in… einer ganzen Weile. Aber beim Programmieren geht es ja um Prinzip. Theoretisch ist das ja eine Arbeits- und Zeitersparnis.
Anhang: Das Skript
Eigentlich ist das nur viel Drumherum um verschiedene Aufrufe der bestehenden Programme convert (um zumeist quadratisch beschnittene Kopien der Bilder zu erstellen) und montage (um diese Dann zu einer Collage zusammenzubauen). Beide Programme sind Teil der verbreiteten Suite imagemagick. Für die Auswertung der Kommandozeile wird außerdem getopts benutzt. Geht das alles auch einfacher oder sauberer? Wahrscheinlich; ich lerne erst noch.
#!/bin/bash
## Print usage
usage() {
echo -e "\nCreate collage \n"
echo -e "Usage: $0 -c -u -b <border size> -s <size> -b <color> source_folder destination_folder"
echo -e "Options:"
echo -e "-h \t show usage"
echo -e "-c \t crop images to squares"
echo -e "-u \t do not crop images to squares"
echo -e "-m \t margin, must be followed by value"
echo -e "-b \t margin, must be followed by color value"
echo -e "-s \t size, must be followed by value"
exit 1
}
# 1. Vorbereitungen
## Setze Standardwerte
CROP=true
SPACING=10
TARGET_SIZE=400
BACKGROUND=white
TEMP_LOCATION=$HOME # Entscheidungen...
TEMP_LOCATION="/tmp" # Entscheidungen...
OUTPUT_LOCATION=$(pwd) # Entscheidungen...
OUTPUT_LOCATION=$HOME # Entscheidungen...
TEMP_DIR="${TEMP_LOCATION}/temp_thumbs" # Temporärer Ordner für skalierte Bilder
# 2. Auswertung der Kommandozeilen-Eingabe
## Werte die möglichen Optionen aus
while getopts chum:b:s: OPTION; do
case $OPTION in
c)
;;
h)
usage
;;
u)
CROP=false
;;
m)
SPACING="$OPTARG"
;;
b)
BACKGROUND="$OPTARG"
;;
s)
TARGET_SIZE="$OPTARG"
;;
\?)
exit
;;
esac
done
## Werte die Argumente aus
### Passe Argument-Zähler an Anzahl der Optionen an
shift $(($OPTIND - 1))
### Verwende erstes Argument als Input-Location
INPUT_LOCATION="$1"
#### Wenn ein zweites Argument vorhanden, setze als Output-Location
if [ "$#" -gt 1 ]; then
OUTPUT_LOCATION="$2"
fi
OUTPUT="${OUTPUT_LOCATION}/collage_ergebnis.jpg"
# 3. Hauptteil
## Erstelle temporären Ordner
mkdir -p "$TEMP_DIR"
## Wechsle in Bilderverzeichnis
cd "${INPUT_LOCATION}"
echo "Schritt 1: Bilder skalieren und eventuell quadratisch zuschneiden..."
## Zähler für die Verarbeitung
count=0
## Verarbeite Bilder in einer Schleife über die gängigen Bildformate im Verzeichnis
for img in *.{jpg,jpeg,png,JPG,JPEG,PNG}; do
# Prüfe, ob Dateien existieren, um Fehler bei leeren Treffern zu vermeiden
[ -e "$img" ] || continue
echo "Verarbeite: $img"
if [ $CROP == true ]; then
# Skalieren und Zuschneiden:
# -resize: Skaliert so, dass die kürzeste Seite TARGET_SIZE entspricht (^)
# -gravity center: Zentriert den Fokus
# -extent: Schneidet den Überhang ab, um ein exaktes Quadrat zu erhalten
convert "$img" \
-resize "${TARGET_SIZE}x${TARGET_SIZE}^" \
-gravity center \
-extent "${TARGET_SIZE}x${TARGET_SIZE}" \
"$TEMP_DIR/thumb_$count.jpg"
else
convert "$img" \
-gravity center \
"$TEMP_DIR/thumb_$count.jpg"
fi
((count++))
done
if [ "$count" -eq 0 ]; then
echo "Keine Bilder gefunden!"
rm -rf "$TEMP_DIR"
exit 1
fi
echo "Schritt 2: Collage erstellen..."
## Montiere zwischengespeicherte Bilder zusammen
## -tile: Ohne Angabe (z.B. 4x) berechnet montage das Raster automatisch quadratisch
montage "$TEMP_DIR"/*.jpg \
-background "$BACKGROUND" \
-geometry "+${SPACING}+${SPACING}" \
"$OUTPUT"
## Ergänze einen Rahmen drumherum, damit der den Rahmen der Einzelbilder ergänzt
convert -bordercolor ${BACKGROUND} -border ${SPACING} "$OUTPUT" "$OUTPUT"
## Lösche das temporäre Verzeichnis
rm -rf "$TEMP_DIR"
echo "-------------------------------------------"
echo "Erfolg! Collage erstellt: $OUTPUT"
echo "Verarbeitete Bilder: $count"
Schreibe einen Kommentar