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 mogrify
fosse 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"