我已經與這個問題鬥爭了幾天,但在 StackExchange 或任何 Google 搜尋上都沒有成功找到解決方案。
我有以下目錄結構(經過簡化,因為實際上有 20,000 多個檔案)。每年每個月都有目錄。每個月的每一天都有一個目錄。
2017
01
01
...
31
...
12
2018
2019
這些目錄中包含圖像:
123_43e6d929fcdbfa00aee1892893127b34.png
4567_24a847285bae9ddb6d3c33d237c6d481.jpg
我想要實現什麼
我想為保存在同一目標但帶有後綴的每個檔案建立縮圖版本(調整大小和裁剪)。所以上面的例子是:
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
我嘗試過的
for file in *.jpg; do convert $file -set filename:base "%[base]" -resize 120x160^ -gravity center -extent 120x160 -quality 90\> "%[filename:base]-120x160.jpg"; done
我認為這會導致一些循環,因為我們在循環時正在創建新圖像。因此,我創建了一個 PHP 腳本來添加檢查,並得出以下結論:
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]\"");
}
這很有效,但是創建所有 66,000 個縮圖需要很長時間,並且會降低伺服器效能。我想也許mogrify
是答案,但必須在每個目錄中運行,並且有數千個目錄。
有人可以建議一個解決方案 - shell、bash、php 或任何可以實現此目的的解決方案嗎?
謝謝
答案1
我認為這會導致一些循環,因為我們在循環時正在創建新圖像。
不,文件列表會被創建,然後迭代,因此您不會重新處理您創建的文件。如果您想在重新運行腳本時避免重新處理文件,則另當別論:
- 您可以透過使用排除拇指來避免處理拇指負匹配(或更嚴格的正匹配),
- 但是,如果拇指已經存在,您也許還應該有一些邏輯來避免處理文件(我假設源圖像永遠不會更新)
……但據我所知,這就是 PHP 程式碼的作用。
這很有效,但是創建所有 66,000 個縮圖需要很長時間,並且會降低伺服器效能。
從 66K 檔案生成三個拇指確實需要一些時間。但無論你做什麼,你都必須對每個拇指執行縮放和重新編碼,這將佔用一些 CPU。您可以設想避免讀取原始檔案三次,但 Linux 中的檔案快取將解決這個問題。
如果您不希望該進程佔用您的伺服器,您可以在每個映像(或每個每日目錄)後新增 1-2 秒的睡眠命令。
答案2
下面是一個使用 Make 的範例。這裡的優點是它不會嘗試製作您已經擁有的任何東西。因此,運行一段時間然後停止,然後在有時間時再次運行是安全的。您也可以提供 -j 標誌,例如「make -j 4」將一次使用最多 4 個 CPU 核心(這會更快,但會使用更多資源。)
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 $@
將程式碼複製到樹根部名為“Makefile”的檔案中(請注意,縮排必須是製表符!我知道,對吧?)。 cd 到該目錄並輸入“make”(或“make -j 4”等)要使其運行速度更慢,您可以使用“nice”,如“nice make”