web-dev-qa-db-ja.com

ファイル名の接尾辞を使用してさまざまなサイズのサムネイルを作成する

私はこの問題と数日間戦ってきましたが、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が答えになると思いましたが、各ディレクトリで実行する必要があり、何千ものディレクトリがあります。

誰かが解決策を提案できますか?シェル、bash、php、これを達成できるものは何ですか?

ありがとう

1
kinggs

ループしながら新しいイメージを作成しているため、これにより少しループが発生すると思います。

いいえ、ファイルのリストが作成されてから繰り返されるため、作成したファイルを再処理する必要はありません。スクリプトを再実行した場合にファイルの再処理を回避したい場合は、別の問題です。

  • 負の一致 (またはより厳密な正の一致)で親指を除外することにより、親指の処理を回避できます。
  • ただし、親指がすでに存在する場合は、ファイルの処理を回避するためのロジックも必要です(ソースイメージは更新されないと思います)

...しかし、私が知る限り、これはあなたがPHPコードが行うことです。

これはうまく機能しますが、66,000のサムネイルをすべて作成し、サーバーのパフォーマンスを低下させるには、永遠に時間がかかります。

66Kファイルから3つの親指を作成するには、確かに時間がかかります。しかし、何をするにしても、親指ごとにスケーリングと再エンコードを実行する必要があります。これにより、CPUがいくらか必要になります。ソースファイルを3回読み取らないようにすることも考えられますが、Linuxのファイルキャッシュがそれを処理します。

プロセスがサーバーを占有したくない場合は、各イメージ(または毎日のディレクトリ)の後に1〜2秒のスリープコマンドを追加できます。

1
xenoid

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-j4」など)と入力します。実行速度を遅くするには、「Nicemake」のように「Nice」を使用します。

0
Andrew Kay