Criando miniaturas de vários tamanhos com sufixo de nome de arquivo

Criando miniaturas de vários tamanhos com sufixo de nome de arquivo

Estou lutando contra esse problema há alguns dias e não consegui encontrar uma solução no StackExchange nem em nenhuma pesquisa do Google.

Eu tenho a seguinte estrutura de diretórios (simplificada porque na realidade existem mais de 20.000 arquivos). Cada ano tem um diretório para cada mês. Cada mês tem um diretório para cada dia.

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

Dentro desses diretórios estão as imagens:

123_43e6d929fcdbfa00aee1892893127b34.png
4567_24a847285bae9ddb6d3c33d237c6d481.jpg

O que eu quero alcançar

Gostaria de criar versões em miniatura (redimensionadas e cortadas) de cada arquivo salvo no mesmo destino, mas com sufixos. Então o exemplo acima seria:

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

O que eu tentei

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

Acho que isso causa um certo loop porque estamos criando novas imagens à medida que fazemos o loop. Então criei um script PHP para adicionar uma verificação e descobri isto:

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]\"");
}

Isso funciona muito bem, mas levará uma eternidade para criar todas as 66.000 miniaturas e também para eliminar o desempenho do servidor. Achei que talvez mogrifyfosse a resposta, mas tem que ser executado em cada diretório e existem milhares de diretórios.

Alguém poderia sugerir uma solução - shell, bash, php, qualquer coisa que possa conseguir isso?

Obrigado

Responder1

Acho que isso causa um certo loop porque estamos criando novas imagens à medida que fazemos o loop.

Não, a lista de arquivos é criada e depois iterada, portanto você não irá reprocessar os arquivos criados. Se você quiser evitar o reprocessamento do arquivo se executar novamente o script, é outra questão:

  • Você pode evitar o processamento dos polegares excluindo-os com umcorrespondência negativa(ou uma correspondência positiva mais rigorosa),
  • Mas talvez você também deva ter alguma lógica para evitar o processamento de um arquivo se os polegares já estiverem lá (presumo que a imagem de origem nunca seja atualizada)

... mas até onde eu sei, isso é o que seu código PHP faz.

Isso funciona muito bem, mas levará uma eternidade para criar todas as 66.000 miniaturas e também para eliminar o desempenho do servidor.

Produzir três miniaturas a partir de arquivos de 66K realmente levará algum tempo. Mas faça o que fizer, você terá que dimensionar e recodificar cada polegar e é isso que vai exigir um pouco de CPU. Você poderia evitar a leitura do arquivo de origem três vezes, mas o cache de arquivos no Linux cuidará disso.

Se não quiser que o processo sobrecarregue seu servidor, você pode adicionar um comando sleep de 1 a 2 segundos após cada imagem (ou diretório de cada dia).

Responder2

Aqui está um exemplo usando Make. A vantagem aqui é que ele não tentará fazer nada que você já tenha. Portanto, é seguro executá-lo um pouco e depois interrompê-lo e executá-lo novamente mais tarde, quando tiver tempo. Você também pode fornecer o sinalizador -j, por exemplo, "make -j 4" usará até 4 núcleos de CPU por vez (o que será mais rápido, mas usará mais recursos).

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 $@

Copie o código em um arquivo (observe que os recuos DEVEM ser TABS! Eu sei, certo?) chamado "Makefile" na raiz da sua árvore. cd para esse diretório e digite "make" (ou "make -j 4" etc.) Para torná-lo mais lento, você pode usar "nice" como em "nice make"

informação relacionada