建立帶有檔案名稱後綴的各種尺寸的縮圖

建立帶有檔案名稱後綴的各種尺寸的縮圖

我已經與這個問題鬥爭了幾天,但在 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”

相關內容