Erstellen von Miniaturansichten verschiedener Größen mit Dateinamensuffix

Erstellen von Miniaturansichten verschiedener Größen mit Dateinamensuffix

Ich kämpfe seit einigen Tagen mit diesem Problem und konnte weder auf StackExchange noch bei einer Google-Suche eine Lösung finden.

Ich habe die folgende Verzeichnisstruktur (vereinfacht, da es in Wirklichkeit über 20.000 Dateien gibt). Jedes Jahr hat ein Verzeichnis für jeden Monat. Jeder Monat hat ein Verzeichnis für jeden Tag.

2017
  01
    01
    ...
    31
  ...
  12
2018
2019

In diesen Verzeichnissen befinden sich Bilder:

123_43e6d929fcdbfa00aee1892893127b34.png
4567_24a847285bae9ddb6d3c33d237c6d481.jpg

Was ich erreichen möchte

Ich möchte Miniaturversionen (mit angepasster Größe und zugeschnitten) von jeder Datei erstellen, die am selben Ziel gespeichert ist, jedoch mit Suffixen. Das obige Beispiel wäre also:

123_43e6d929fcdbfa00aee1892893127b34.png
123_43e6d929fcdbfa00aee1892893127b34-120x160.png
123_43e6d929fcdbfa00aee1892893127b34-300x300.png
123_43e6d929fcdbfa00aee1892893127b34-800x800.png
4567_24a847285bae9ddb6d3c33d237c6d481.jpg
4567_24a847285bae9ddb6d3c33d237c6d481-120x160.jpg
4567_24a847285bae9ddb6d3c33d237c6d481-300x300.jpg
4567_24a847285bae9ddb6d3c33d237c6d481-800x800.jpg

Was ich versucht habe

for file in *.jpg; do convert $file -set filename:base "%[base]" -resize 120x160^ -gravity center -extent 120x160 -quality 90\> "%[filename:base]-120x160.jpg"; done

Ich denke, das führt zu einer kleinen Schleife, weil wir während der Schleife neue Bilder erstellen. Also habe ich ein PHP-Skript erstellt, um eine Prüfung hinzuzufügen, und bin auf Folgendes gestoßen:

foreach ($all_files as $file) {
    $path = $file->getPathname();

    $resized = str_replace_last('.', '-120x160.', $path);             
    if (preg_match('/\-\d{3}x\d{3}\./', $path) || file_exists($resized) || substr($path,-4) != '.jpg') continue;

    exec("convert \"$path\" -set filename:base \"%d/%[base]-120x160.jpg\" -resize 120x160^ -gravity center -extent 120x160 -quality 95\> \"%[filename:base]\";
          convert \"$path\" -set filename:base \"%d/%[base]-300x300.jpg\" -resize 300x300^ -gravity center -extent 300x300 -quality 95\> \"%[filename:base]\";
          convert \"$path\" -set filename:base \"%d/%[base]-800x800.jpg\" -resize 800x800^ -gravity center -extent 800x800 -quality 95\> \"%[filename:base]\"");
}

Das funktioniert großartig, aber es wird eine Ewigkeit dauern, alle 66.000 Miniaturansichten zu erstellen und die Serverleistung zu beeinträchtigen. Ich dachte, das mogrifywäre vielleicht die Lösung, aber es muss in jedem Verzeichnis ausgeführt werden und es gibt Tausende von Verzeichnissen.

Kann irgendjemand bitte eine Lösung vorschlagen – Shell, Bash, PHP, irgendetwas, womit sich das erreichen lässt?

Danke

Antwort1

Ich glaube, dass dadurch eine Art Schleife entsteht, weil wir beim Durchlaufen neue Bilder erstellen.

Nein, die Dateiliste wird erstellt und dann iteriert, Sie werden also die erstellten Dateien nicht erneut verarbeiten. Wenn Sie die erneute Verarbeitung der Datei vermeiden möchten, wenn Sie das Skript erneut ausführen, sieht die Sache anders aus:

  • Sie können die Verarbeitung der Vorschaubilder vermeiden, indem Sie diese mit einemnegative Übereinstimmung(oder eine strengere positive Übereinstimmung),
  • Aber Sie sollten vielleicht auch eine Logik haben, um die Verarbeitung einer Datei zu vermeiden, wenn die Vorschaubilder bereits vorhanden sind (ich gehe davon aus, dass das Quellbild nie aktualisiert wird).

... aber soweit ich das beurteilen kann, ist dies, was Ihr PHP-Code macht.

Das funktioniert zwar prima, das Erstellen aller 66.000 Miniaturansichten wird allerdings eine Ewigkeit dauern und die Serverleistung beeinträchtigen.

Das Erstellen von drei Vorschaubildern aus 66-KB-Dateien wird tatsächlich einige Zeit in Anspruch nehmen. Aber was auch immer Sie tun, Sie müssen die Skalierung und Neukodierung für jedes Vorschaubild durchführen, und das ist es, was einiges an CPU-Leistung in Anspruch nehmen wird. Sie könnten sich vorstellen, das dreimalige Lesen der Quelldatei zu vermeiden, aber die Dateizwischenspeicherung in Linux wird sich darum kümmern.

Wenn Sie nicht möchten, dass der Prozess Ihren Server blockiert, können Sie nach jedem Bild (oder jedem Tagesverzeichnis) einen 1–2 Sekunden langen Sleep-Befehl hinzufügen.

Antwort2

Hier ist ein Beispiel mit Make. Der Vorteil dabei ist, dass es nicht versucht, etwas zu erstellen, was Sie bereits haben. Sie können es also problemlos eine Weile laufen lassen, dann anhalten und später erneut ausführen, wenn Sie Zeit haben. Sie können auch das Flag -j angeben, z. B. verwendet „make -j 4“ bis zu 4 CPU-Kerne gleichzeitig (was schneller ist, aber mehr Ressourcen verbraucht).

ifeq (${MAKELEVEL}, 0)
   # path to this Makefile
   mfile = Makefile
endif

subdirs = $(shell find * -type d -print -prune)
files = $(wildcard *.jpg) $(wildcard *.png)
thumbs = $(wildcard *-120x160.*) $(wildcard *-300x300.*) $(wildcard *-800x800.*)
notthumbs = ${basename $(filter-out $(thumbs), $(files) ) }
neededthumbs = $(foreach f, ${notthumbs}, ${f}-120x160.jpg ${f}-300x300.jpg ${f}-800x800.jpg)

all: thumbs recurse

thumbs: ${neededthumbs}

recurse:
        $(foreach f, ${subdirs}, $(MAKE) -C ${f} -f ../${mfile} mfile=../${mfile} all ; )

%-120x160.jpg: %.jpg
        echo convert $< -resize 120x160 $@
%-300x300.jpg: %.jpg
        echo convert $< -resize 300x300 $@
%-800x800.jpg: %.jpg
        echo convert $< -resize 800x800 $@
%-120x160.jpg: %.png
        echo convert $< -resize 120x160 $@
%-300x300.jpg: %.png
        echo convert $< -resize 300x300 $@
%-800x800.jpg: %.png
        echo convert $< -resize 800x800 $@

Kopieren Sie den Code in eine Datei namens „Makefile“ im Stammverzeichnis Ihres Baums (beachten Sie, dass die Einrückungen TABS sein MÜSSEN! Ich weiß, oder?). Wechseln Sie in dieses Verzeichnis und geben Sie „make“ (oder „make -j 4“ usw.) ein. Um es langsamer laufen zu lassen, können Sie „nice“ verwenden, wie in „nice make“.

verwandte Informationen