Use o mogrify para redimensionar arquivos grandes e ignorar os pequenos

9

Estou executando o seguinte comando:

mogrify -resize '400x400>' *.png

Observe o ">". Supostamente, ele ignorará arquivos menores, mas, embora não os redimensione, ele os edita (a data de modificação e o tamanho do arquivo são alterados).

Existe uma maneira de deixar apenas os arquivos menores sozinhos? Eu gostaria de evitar milhares de operações de gravação desnecessárias.

    
por Mike 18.05.2012 / 16:38

7 respostas

12

Acho que mogrify reescreve sistematicamente o arquivo, portanto, sua única esperança é filtrar a lista primeiro, como sugerido pelo jippie . Veja como você pode fazer isso (não testado): imprima uma lista de arquivos de imagem com uma indicação de tamanho, mantenha apenas os nomes cujo tamanho associado esteja dentro do intervalo e processe essa lista.

identify -format '%w %h %i\n' ./*.png |
awk '$1 > 400 || $2 > 400 {sub(/^[^ ]* [^ ]* /, ""); print}' |
tr '\n' '
identify -format '%w %h %i\n' ./*.png |
awk '$1 > 400 || $2 > 400 {sub(/^[^ ]* [^ ]* /, ""); print}' |
tr '\n' '%pre%' |
xargs -0 mogrify -resize '400x400'
' | xargs -0 mogrify -resize '400x400'

Explicação de script:

  • Para cada arquivo, imprima uma linha com a largura, um espaço, a altura, um espaço e o nome do arquivo. Dependendo da sua versão de identify , o \n para adicionar uma nova linha final pode ser necessário (ImageMagick 6.6.0) ou supérfluo, mas inofensivo (GraphicsMagick 1.1.11).
  • ( awk ) Em cada linha, se a largura ( $1 ) e a altura ( $2 ) corresponderem às condições necessárias, então:
    • Remove todo o texto até o segundo caractere de espaço. Isso retira a largura e a altura.
    • Imprima o que resta da linha, que é o nome do arquivo.
  • Substituir novas linhas por caracteres nulos.
  • Chame xargs -0 para executar o comando mogrify nos nomes dos arquivos. (Não podemos usar xargs simples porque não é possível lidar com entrada contendo espaço em branco ou \'" .)

Os nomes dos arquivos podem conter qualquer caractere, exceto novas linhas.

    
por 18.05.2012 / 17:35
6

Eu enfrentei o mesmo problema que você descreveu. Aqui está a minha solução:

#!/bin/bash
files=*.jpg
minimumWidth=640
minimumHeight=640

for f in $files
do
    imageWidth=$(identify -format "%w" "$f")
    imageHeight=$(identify -format "%h" "$f")

    if [ "$imageWidth" -gt "$minimumWidth" ] || [ "$imageHeight" -gt "$minimumHeight" ]; then
        mogrify -resize ''"$minimumWidth"x"$minimumHeight"'' $f
    fi
done

Eu testei em várias imagens JPEG em uma máquina virtualizada do CentOS 6.5. O script apenas redimensionou e compactou as imagens cuja largura ou altura era maior que 640 pixels. Isso fez com que funcionasse para imagens com dimensões como 800 x 600 (paisagem, redimensionando para 640 x 480) e dimensões como 600 x 800 (retrato, redimensionando para 480 x 640).

PS: uma observação sobre o parâmetro 400x400 : mogrify processará o arquivo, mesmo que suas dimensões sejam iguais ou menores que 400x400, mas redimensionará somente se suas dimensões forem maiores que 400x400 . É por isso que o tempo e o tamanho da modificação dos arquivos são alterados (no meu caso, mogrify fez com que esses arquivos fossem maiores do que eram).

    
por 26.09.2014 / 01:12
4

Você também pode usar o operador fx para filtrar imagens com base na altura / largura, por exemplo.

identify -format '%[fx:(h>400 && w>400)]\n' image.png

produzirá 1 se a imagem for maior que 400x400 e 0 se for igual ou menor que 400x400 ...

Assumindo nomes de arquivos sãos (sem novas linhas / espaços / guias etc.) você pode usar identify para imprimir nomes de imagens precedidos por 1: ou 0: , processar a saída excluindo linhas que começam com 0: e removendo o primeiro 1: no resto das linhas, então apenas os nomes dos arquivos permanecem, um por linha, então canalize essa lista para mogrify ... @- (o @ syntax foi adicionado em imagemagick v6.5.2 ):

identify -format '%[fx:(h>400 && w>400)]:%i\n' ./*.png | \
sed '/^1:/!d;//s///' | mogrify -resize '400x400' -- @-

Caso contrário, com find você pode imprimir apenas os arquivos com tamanho > 400x400 e, em seguida, canaliza o resultado para xargs + mogrify (é menos eficiente, pois executa um shell para cada arquivo, mas deve funcionar com todos os tipos de nomes de arquivos):

find . -maxdepth 1 -type f -name '*.png' -exec sh -c \
'identify -format "%[fx:(h>400 && w>400)]\n" "$0" | grep -q 1' {} \; -print0 \
| xargs -0 mogrify -resize '400x400'

Se você é um usuário de zsh , consulte também esta resposta .

    
por 06.08.2015 / 21:21
2

Que tal usar identificar para encontrar o tamanho da sua imagem e decidir de um pequeno script, se você quiser editá-lo ou não:

identify -format "width=%w heigth=%h" bootchart.png 
width=3853 heigth=10092

Não deve ser muito difícil editar o formato de saída para usar em um script simples.

    
por 18.05.2012 / 17:08
0

Eu uso esse script PHP, ele usa o ImageMagick:

<?php
$dir = ".";
$exts = array('jpg', 'jpeg', 'png', 'gif');
$max_size = is_numeric($argv[1]) ? $argv[1] : 3000;
$morgify = "mogrify -verbose -scale \"${max_size}x${max_size}>\" -quality 85";
$identify = "identify -format \"%wx%h\"";

$dh = opendir($dir);
while (($file = readdir($dh)) !== false) {
    $path = "$dir/$file";
    // skip no images
    $dot = strrpos($file, '.');
    $ext = strtolower(substr($file, $dot + 1));
    if (!in_array($ext, $exts)) continue;
    // large size?
    $size = exec("$identify \"$path\"");
    list($width, $height) = explode('x', trim($size));
    if (max($width, $height) > $max_size) {
        // scale!
        print "scale $file ${width}x${height}";
        exec("$morgify \"$path\"");
        print "\n";
    }
}
closedir($dh);
?>

Ele escala todas as imagens no diretório atual maior que 3000 em alguma borda.

Executar comando: php scale.php OR php scale.php 2000

    
por 06.08.2015 / 09:04
0

Aqui está minha opinião sobre isso, incorporando idéias do @ArionKrause e @don_crissti:

#!/bin/bash
# adapted from http://unix.stackexchange.com/a/157594/110635
# and http://unix.stackexchange.com/a/220619/110635
W=1024
H=768
SIZE_TEST="%[fx:(h>$H && w>$W)]"'\n'

for f in $*; do
  if [ $(identify -format "$SIZE_TEST" "$f") = 1 ]; then
    echo "Resize: $f"
    mogrify -resize ''"$W"x"$H"'' "$f"
  else
    echo "Do not resize: $f"
  fi
done

(Eu precisava disso porque o meu processador Phatch favorito não funciona com o Ubuntu 16.04.)

    
por 24.04.2016 / 10:53
0

Minhas funções para redimensionar e otimizar

resize_and_optimize_images () {
  resize_images 700 $PWD
  optimize_images 85 $PWD
}

resize_images () {
  max="$1"
  dir="$2"

  echo "Resizing dir $dir, max size - $max"

  shopt -s globstar

  for f in $dir/**/*.jpg $dir/**/*.jpeg $dir/**/*.png ; do
    echo "Checking $f"
    s='identify -format "%w" $f'

    if [ $s -gt $max ]; then
      echo "Resizing..."
      mogrify -verbose -resize $max $f
    fi
    echo
  done

  echo "Done resizing dir $dir"
}

optimize_images () {
  quality="$1"
  dir="$2"

  echo "Optimizing dir $dir, quality - $quality"

  docker run -it --rm --name optimize_images_foo \
    -v $dir:/usr/src/app \
    -w /usr/src/app ruby:2.4-stretch bash -c \
    "gem install image_optim image_optim_pack && \
    (curl -L \"http://static.jonof.id.au/dl/kenutils/pngout-20150319-linux.tar.gz\" | tar -xz -C /usr/bin --strip-components 2 --wildcards \"*/x86_64/pngout\") && \
    image_optim --verbose --allow-lossy --jpegoptim-allow-lossy true --jpegoptim-max-quality $quality --pngquant-allow-lossy true --pngquant-quality 0..$quality -r ."

  echo "Done optimizing dir $dir"
}
    
por 15.05.2018 / 21:18

Tags