Utilisez mogrify pour redimensionner des fichiers volumineux tout en ignorant les petits

10

J'exécute la commande suivante:

mogrify -resize '400x400>' *.png

Remarquez le ">". Soi-disant, il ignorera les fichiers plus petits, mais bien qu'il ne les redimensionne pas, il les modifie (la date de modification et la taille du fichier sont modifiées).

Existe-t-il un moyen de faire en sorte de laisser les petits fichiers seuls? Je voudrais éviter plusieurs milliers d'opérations d'écriture inutiles.

Mike
la source

Réponses:

15

Je pense que mogrifyréécrit systématiquement le fichier, donc votre seul espoir est de filtrer la liste en premier, comme suggéré par jippie . Voici comment vous pouvez le faire (non testé): imprimez une liste de fichiers image avec une indication de taille, ne conservez que les noms dont la taille associée est dans la plage et traitez cette liste.

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

Explication du script:

  • Pour chaque fichier, imprimez une ligne avec la largeur, un espace, la hauteur, un espace et le nom du fichier. Selon votre version de identify, l' \najout d'une nouvelle ligne finale peut être nécessaire (ImageMagick 6.6.0) ou superflu mais inoffensif (GraphicsMagick 1.1.11).
  • ( awk) Sur chaque ligne, si la largeur ( $1) et la hauteur ( $2) correspondent aux conditions requises, alors:
    • Supprimez tout le texte jusqu'au deuxième caractère d'espace. Cela enlève la largeur et la hauteur.
    • Imprimez ce qui reste de la ligne, qui est le nom du fichier.
  • Remplacez les retours à la ligne par des caractères nuls.
  • Appelez xargs -0pour exécuter la mogrifycommande sur les noms de fichiers. (Nous ne pouvons pas utiliser plain xargscar il ne peut pas traiter les entrées contenant des espaces ou \'".)

Les noms de fichiers peuvent contenir n'importe quel caractère sauf les sauts de ligne.

Gilles 'SO- arrête d'être méchant'
la source
pouvez-vous expliquer ce script? Plus précisément la partie "sous". Il s'agit d'imprimer les noms de fichiers sans espace ou d'insérer une nouvelle ligne. mogrify: impossible d'ouvrir le fichier `22 553.png308 400 0134 2.png '@ error / png.c / ReadPNGImage / 2951. Je ne sais pas d'où vient ce "308 400". Je dois mentionner que les fichiers ont des espaces dans leurs noms Merci.
Mike
Je reçois Mogrify: impossible d'ouvrir le fichier `340271 22 553.png308 400 0134 2.png '@ error / png.c / ReadPNGImage / 2951. J'ai exécuté la commande en utilisant 200x200 sur deux fichiers d'exemple. Je vois que 308x400 est la taille d'un des fichiers
Mike
2
@ Mike Ah, j'ai compris. Certaines versions de identifymettent automatiquement une nouvelle ligne après chaque enregistrement, d'autres doivent en avoir une explicitement. Ajoutez \nà la fin de l'argument à -format(voir ma modification).
Gilles 'SO- arrête d'être méchant'
8

J'ai fait face au même problème que vous avez décrit. Voici ma solution:

#!/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

Je l'ai testé sur plusieurs images JPEG sur une machine CentOS 6.5 virtualisée. Le script a uniquement redimensionné et compressé les images dont la largeur ou la hauteur était supérieure à 640 pixels. Cela l'a fait fonctionner pour des images avec des dimensions comme 800 x 600 (paysage, le redimensionnement à 640 x 480) et des dimensions comme 600 x 800 (portrait, le redimensionnement à 480 x 640).

PS: Remarque sur le 400x400paramètre: mogrifytraitera le fichier même si ses dimensions sont égales ou inférieures à 400x400, mais ne sera redimensionné que si ses dimensions sont supérieures à 400x400. C'est pourquoi le temps et la taille de modification des fichiers sont modifiés (dans mon cas, ont mogrifyrendu ces fichiers encore plus grands qu'ils ne l'étaient).

Arion Krause
la source
5

Vous pouvez également utiliser l' fxopérateur pour filtrer les images en fonction de la hauteur / largeur, par exemple

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

sortira 1si l'image est plus grande que 400x400et 0si elle est égale ou inférieure à 400x400...


En supposant des noms de fichiers sensés (pas de sauts de ligne / espaces / tabulations, etc.), vous pouvez utiliser identifypour imprimer les noms d'images précédés de 1:ou 0:, traiter la sortie en supprimant les lignes qui commencent par 0:et en supprimant le début 1:des autres lignes afin que seuls les noms de fichiers restent, un par ligne, puis dirigez cette liste vers mogrify ... @-(la @syntaxe a été ajoutée imagemagick v6.5.2):

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

Sinon, avec findvous pourriez imprimer uniquement les fichiers avec une taille> 400x400 puis diriger le résultat vers xargs+ mogrify(c'est moins efficace car il exécute un shell pour chaque fichier mais cela devrait fonctionner avec toutes sortes de noms de fichiers):

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'

Si vous êtes un zshutilisateur, voyez également cette réponse .

don_crissti
la source
3

Que diriez-vous d'utiliser identifier pour trouver la taille de votre image et décider à partir d'un petit script si vous souhaitez la modifier ou non:

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

Il ne devrait pas être trop difficile de modifier le format de sortie pour l'utiliser dans un script simple.

jippie
la source
Compte tenu de mes compétences limitées et du fait que les tailles des images sont si irrégulières, j'ai besoin d'une méthode plus simple. Je préfère les traiter tous avec mogrify.
Mike
0

J'utilise un tel script PHP, il utilise 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);
?>

Il met à l'échelle toutes les images du répertoire actuel supérieures à 3000 sur un certain bord.

Exécuter la commande: php scale.phpOUphp scale.php 2000

Andrew Barhatov
la source
0

Voici mon point de vue, intégrant les idées de @ArionKrause et @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

(J'en avais besoin parce que mon processeur par lots préféré Phatch ne fonctionne pas avec Ubuntu 16.04.)

bovender
la source
0

Mes fonctions pour redimensionner et optimiser

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"
}
srghma
la source