使用文件名后缀创建各种尺寸的缩略图

使用文件名后缀创建各种尺寸的缩略图

我已经解决这个问题好几天了,但在 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”的文件中(注意缩进必须是 TABS!我知道,对吧?)。cd 到该目录并输入“make”(或“make -j 4”等)。为了使其运行得更慢,您可以使用“nice”,如“nice make”

相关内容