AW: Effi: Skalierung, Untertitel, Wasserzeichen und Dateigröße: Alles in einem Rutsch
Das ist mal eine ausführliche Rückmeldung, vielen Dank dafür! :up:
Sie verdient natürlich auch eine ausführliche Antwort.
Zunächst freue ich mich, dass Du es auf dem Mac laufen lassen konntest. Ich werde den expliziten auf Java 8 in die Dokumentation aufnehmen.
>
Wer es versteht, ist auf der Shell mit den ImageMagick-Befehlen schneller unterwegs, da flexibler scriptbar.
Da sind wohl die Kausalitäten etwas durcheinander geraten
. Flexibler ist nicht schneller. Und was die Tipperei in der Shell anbelangt, habe ich hinsichtlich der Geschwindigkeit auch so meine Zweifel. Diese Kommandos hier (shell-taugliche Anwendung der Log-Einträge) sind von Hand kaum schneller zu erledigen:
convert input/20160920_123842_UTC.JPG -resize 800 \( -size 800x100 -background none -font Arial -fill white -gravity south caption:'watermark ? read the manual!' -channel RGB -shade 125x40 +channel \) -gravity south -compose overlay -define compose.args=0 -composite -size 800x -background black -font Arial -fill yellow -pointsize 16 -gravity southwest caption:'Eins' -append -strip -define jpeg:extent=256kb output/20160920_123842_UTC.JPG
convert input/20160920_132832_UTC.JPG -resize 600 \( -size 600x100 -background none -font Arial -fill white -gravity south caption:'watermark ? read the manual!' -channel RGB -shade 125x40 +channel \) -gravity south -compose overlay -define compose.args=0 -composite -size 600x -background black -font Arial -fill yellow -pointsize 16 -gravity southwest caption:'Bild zwei' -append -strip -define jpeg:extent=256kb output/20160920_132832_UTC.JPG
convert input/20160921_075504_UTC.JPG -resize 700 -size 700x -background black -font Arial -fill yellow -pointsize 16 -gravity southwest caption:'Bild drei' -append -strip -define jpeg:extent=256kb output/20160921_075504_UTC.JPG
convert input/20160921_075524_UTC.JPG -resize 1024 \( -size 800x100 -background none -font Arial -fill white -gravity south caption:'watermark ? read the manual!' -channel RGB -shade 125x40 +channel \) -gravity south -compose overlay -define compose.args=0 -composite -size 800x -background black -font Arial -fill yellow -pointsize 16 -gravity southwest caption:'Zeltplatz am Morgen' -append -strip -define jpeg:extent=256kb output/20160921_075524_UTC.JPG
convert input/20160921_080141_UTC.JPG -resize 800 -size 800x -background black -font Arial -fill yellow -pointsize 16 -gravity southwest caption:'Die Sonne kommt' -append -strip -define jpeg:extent=256kb output/20160921_080141_UTC.JPG
convert input/20160921_103802_UTC.JPG -resize 1200 -size 800x -background black -font Arial -fill yellow -pointsize 16 -gravity southwest caption:'Mit Feuerstelle' -append -strip -define jpeg:extent=256kb output/20160921_103802_UTC.JPG
convert input/20160921_115151_UTC.JPG -resize 800 \( -size 800x100 -background none -font Arial -fill white -gravity south caption:'watermark ? read the manual!' -channel RGB -shade 125x40 +channel \) -gravity south -compose overlay -define compose.args=0 -composite -size 800x -background black -font Arial -fill yellow -pointsize 16 -gravity southwest caption:'Mit Feuerstelle' -append -strip -define jpeg:extent=256kb output/20160921_115151_UTC.JPG
convert input/20160921_115151_UTC.JPG -resize 800 \( -size 800x100 -background none -font Arial -fill white -gravity south caption:'watermark ? read the manual!' -channel RGB -shade 125x40 +channel \) -gravity south -compose overlay -define compose.args=0 -composite -size 800x -background black -font Arial -fill yellow -pointsize 16 -gravity southwest caption:'Technik put' -append -strip -define jpeg:extent=256kb output/20160921_115151_UTC.JPG
convert input/20160921_115151_UTC.JPG -resize 1024 \( -size 800x100 -background none -font Arial -fill white -gravity south caption:'watermark ? read the manual!' -channel RGB -shade 125x40 +channel \) -gravity south -compose overlay -define compose.args=0 -composite -size 960x -background black -font Arial -fill yellow -pointsize 16 -gravity southwest caption:'Technik pur' -append -strip -define jpeg:extent=256kb output/20160921_115151_UTC.JPG
Mit Effi dauerte das 135 Sekunden:
$ time java -jar build/jar/Effi.jar
real 2m15,131s
user 1m10,696s
sys 0m3,036s
Allerdings, und da kommt es auf die von mir fett zitierte Anmerkung "wer es versteht" an, ist man bei wirklich großen Mengen an Bildern dann schneller, wenn man die shell soweit beherrscht, dass man Loops und kombinierte Kommandos auf der Kommandozeile ausführen kann.
So habe ich das zum Beispiel
für das Tlf bei
diesen rund 1300 "Beamshots" gemacht. Für so jemand ist Effi aber nicht geschrieben.
Für o.g. "Beamshots" (sie mussten nicht skaliert werden) brauchte mein Laptop für die Wasserzeichen und Untertitel in 1259 Bildern übrigens knapp drei Minuten.
Bei diesen über tausend Bildern gabs Effi noch nicht, im Gegenteil: Sie waren der Anlass dafür, es überhaupt zu schreiben. Denn der Macher der Beamshot-Liste sollte ja die Möglichkeit haben, auch künftig solche Untertitelungen und Wasserzeichen zu applizieren - und zwar unter Windows. Und da siehts mit profunder Kenntnis einer Shell meist eher düster aus.
Zum Thema Swing: Die Frage ist weniger, wie "schick" die Anwendung aussieht, sondern viel mehr, welche Architektur sie verwendet. JavaFX erfordert schlicht einen anderen Ansatz. Und da ich, um etwas präziser zu werden,
JGoodies verwende, war mir diese Entscheidung ohnehin abgenommen: JGoodies baut (jedenfalls in der frei verfügbaren Version) numal auf Swing auf. Die von Karsten Lentzsch entwickelte Suite ist überdies zweifelsfrei als State of the Art zu bezeichnen. Das als
Legacy-Code zu bezeichnen finde ich deshalb doch etwas kühn.
Im Übrigen ist Effi kein
Client. Da es weder eine n-Tier Architektur implementiert, und vor allem (und glücklicherweise) auch keinen Server benötigt, ist es schlicht und ergreifend eine Desktop-Anwendung.
Zu den Exif-Daten: Sie gehen nicht etwa einfach verloren. Im Gegenteil, sie werden explizit und mit voller Absicht gelöscht, und das -zunächst- aus gutem Grund. Denn Anfangs sollte Effi ja nur Foren-gerechte Bilder produzieren, was so gut wie immer mit einer Beschränkung der finalen Dateigrößen einhergeht. Da ich in diesem Kontext die Priorität
Bildqualität gesetzt habe, hatte ich entschieden, die Exif-Daten aus den Bildern zu löschen. Denn so lässt sich mehr "Platz" für die Bildausgabe gewinnen, weil zum Einhalten der Dateigrößenbeschränkung geringere Kompressionsraten erforderlich sind.
Bei einigen Versuchen dazu habe ich festgestellt, dass die Löschung teilweise über 50KB pro Bild freimacht. Das führt beispielsweise bei der gängigen Begrenzung von 256KB pro Bild im Resultat zu rund 25% mehr Platz für die Bilddaten: Dort stehen dann statt 205KB reiner Bilddaten die vollen 256KB zur Verfügung.
Allerdings nehme ich Deine Kritik gerne zum Anlass, Effi an dieser Stelle etwas smarter zu machen: Im ersten Schritt werde ich die Exif-Daten nicht mehr löschen, wenn der Nutzer keine Dateigrößen-Beschränkung wünscht. Vielleicht mache ich es auf Dauer auch individuell ein/ausschaltbar, das wäre dann etwas mehr Aufwand.
Die Bildorientierung bleibt übrigens auch ohne die Exif-Daten erhalten: Das Flag wird bei der Ausgabe korrekt umgesetzt. Da die Bilder sowieso skaliert werden, macht das für die Bildqualität keinen Unterschied, es findet kein zusätzliches "degrade" statt.
>
Ich konnte das Wasserzeichen nicht ändern : Wie hast Du es denn versucht?
>
und es enthält Leerzeichen: Das darf es. Sie werden korrekt verarbeitet.
Die Anmerkung mit den Leerzeichen lässt mich vermuten, dass an dieser Stelle vielleicht noch eine Hintergrundinformation fehlt was die Einträge in der Log-Datei angeht. Diese lassen sich NICHT eins zu eins in der Shell ausführen, sie dienen nur als das, was sie sind: Als Log.
Jetzt wirds (ein bisschen) technisch für die, die es interessiert: In Effi verwende ich den Java ProcessBuilder. Dieser übergibt, anders als die Kommandozeile oder die Shell, auch Argumente, die Leerzeichen enthalten als "ganze" Parameter. In Entwickler-Sprech sind es schlicht
argv-Werte, und die dürfen eben auch Leerzeichen enthalten. Dasselbe gilt auch für die Klammern: Sie müssen nicht "gequotet" werden, weil der ProzessBuilder sie als normale Argumente übergibt, und keine Shell-Interpretation vornimmt. Alles andere wäre auch nicht portabel: Es wird intern ja keine shell gestartet, sondern letztlich ein
execvpe(const char *file, char *const argv[], char *const envp[]) ausgeführt.
Nochmals Danke für Deine Rückmeldung. Das spornt an, Effi besser zu machen!
PS: Und wenn Du Fehler entdeckst, steht im Handbuch, was ich brauche um die zu beseitigen.