Użyj mogrify, aby zmienić rozmiar dużych plików, ignorując małe

10

Korzystam z następującego polecenia:

mogrify -resize '400x400>' *.png

Zwróć uwagę na „>”. Podobno zignoruje mniejsze pliki, ale chociaż nie zmienia ich rozmiaru, edytuje je (data modyfikacji i rozmiar pliku są zmieniane).

Czy istnieje sposób, aby faktycznie zostawić mniejsze pliki w spokoju? Chciałbym uniknąć kilku tysięcy niepotrzebnych operacji zapisu.

Mikrofon
źródło

Odpowiedzi:

15

Myślę, że mogrifysystematycznie przepisuje plik, więc jedyną nadzieją jest, aby najpierw przefiltrować listę, jak sugeruje jippie . Oto, jak możesz to zrobić (niesprawdzone): wydrukuj listę plików graficznych ze wskazaniem rozmiaru, zachowaj tylko nazwy, których powiązany rozmiar jest w zasięgu, i przetworz tę listę.

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

Objaśnienie skryptu:

  • Dla każdego pliku wydrukuj linię o szerokości, spacji, wysokości, spacji i nazwie pliku. W zależności od wersji identify, \ndodać końcowy znak nowej linii może być albo konieczne (ImageMagick 6.6.0) lub zbędne ale nieszkodliwe (GraphicsMagick 1.1.11).
  • ( awk) W każdej linii, jeśli szerokość ( $1) i wysokość ( $2) odpowiadają wymaganym warunkom, wówczas:
    • Usuń cały tekst do drugiego znaku spacji. To usuwa szerokość i wysokość.
    • Wydrukuj resztki wiersza, czyli nazwę pliku.
  • Zamień znaki nowej linii na znaki puste.
  • Zadzwoń, xargs -0aby wykonać mogrifypolecenie na nazwach plików. (Nie możemy używać zwykłego, xargsponieważ nie radzi sobie z danymi wejściowymi zawierającymi białe znaki lub \'".)

Nazwy plików mogą zawierać dowolny znak oprócz nowego wiersza.

Gilles „SO- przestań być zły”
źródło
czy możesz wyjaśnić ten skrypt? W szczególności część „podrzędna”. Drukuje nazwy plików bez spacji lub wstawia nowy wiersz. mogrify: nie można otworzyć pliku `22 553.png308 400 0134 2.png '@ error / png.c / ReadPNGImage / 2951. Nie mam pojęcia, skąd pochodzi ten „308 400”. Powinienem wspomnieć, że pliki mają spacje w nazwach. Dziękujemy.
Mike
Mam problemy: nie mogę otworzyć pliku `340 271 22 553.png308 400 0134 2.png '@ error / png.c / ReadPNGImage / 2951. Uruchomiłem polecenie przy użyciu 200 x 200 na dwóch przykładowych plikach. Widzę, że rozmiar 308 x 400 jest wielkości jednego z plików
Mike
2
@ Mike Ah, rozumiem. Niektóre wersje identifyautomatycznie umieszczają nowy wiersz po każdym rekordzie, inne muszą mieć go wyraźnie. Dodaj \nna końcu argumentu do -format(patrz moja edycja).
Gilles „SO- przestań być zły”
8

Napotkałem ten sam problem, który opisałeś. Oto moje rozwiązanie:

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

Przetestowałem to na kilku obrazach JPEG na zwirtualizowanym komputerze CentOS 6.5. Skrypt zmienił tylko rozmiar i skompresował obrazy, których szerokość lub wysokość była większa niż 640 pikseli. Dzięki temu działa dla obrazów o wymiarach takich jak 800 x 600 (poziomy, zmiana rozmiaru na 640 x 480) i wymiarach takich jak 600 x 800 (pionowy, zmiana rozmiaru na 480 x 640).

PS: Uwaga na temat 400x400parametru: mogrifyprzetworzy plik, nawet jeśli jego wymiary są równe lub mniejsze niż 400 x 400, ale zmieni rozmiar, tylko jeśli jego wymiary są większe niż 400 x 400. Dlatego czas i rozmiar modyfikacji plików są zmieniane (w moim przypadku mogrifypliki te są jeszcze większe niż były).

Arion Krause
źródło
5

Możesz także użyć fxoperatora do filtrowania obrazów na podstawie wysokości / szerokości, np

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

wyświetli się, 1jeśli obraz jest większy niż 400x400i 0jeśli jest równy lub mniejszy niż 400x400...


Zakładając, że przy zdrowych nazwach plików (bez nowych linii / spacji / tabulatorów itp.) Możesz użyć identifydo wydrukowania nazw obrazów poprzedzonych jednym z nich 1:lub 0:przetworzyć wyjściowe linie usuwające, które zaczynają się od 0:i usuwając wiodące 1:linie na pozostałych liniach, aby pozostały tylko nazwy plików, jeden w wierszu, a następnie potokuj tę listę do mogrify ... @-( dodano @składnięimagemagick v6.5.2 ):

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

W przeciwnym razie findmożesz wydrukować tylko pliki o rozmiarze> 400x400, a następnie potokować wynik do xargs+ mogrify(jest mniej wydajny, ponieważ uruchamia powłokę dla każdego pliku, ale powinien działać z wszystkimi rodzajami nazw plików):

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'

Jeśli jesteś zshużytkownikiem, zobacz również tę odpowiedź .

don_crissti
źródło
3

Co powiesz na użycie identyfikatora, aby znaleźć rozmiar obrazu i zdecydować na podstawie małego skryptu, czy chcesz go edytować, czy nie:

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

Edytowanie formatu wyjściowego do użycia w prostym skrypcie nie powinno być trudne.

jippie
źródło
Biorąc pod uwagę moje ograniczone umiejętności i fakt, że rozmiary obrazów są tak nieregularne, potrzebuję prostszej metody. Wolę przetwarzać je wszystkie z niedowierzaniem.
Mike
0

Używam takiego skryptu PHP, używa 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);
?>

Na pewnym brzegu skaluje wszystkie obrazy w bieżącym katalogu większe niż 3000.

Uruchom polecenie: php scale.phpORphp scale.php 2000

Andrew Barhatov
źródło
0

Oto moje zdanie na ten temat, zawierające pomysły z @ArionKrause i @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

(Potrzebowałem tego, ponieważ mój ulubiony procesor wsadowy Phatch nie działa z Ubuntu 16.04.)

Bovender
źródło
0

Moje funkcje do zmiany rozmiaru i optymalizacji

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
źródło