Используйте mogrify для изменения размера больших файлов, игнорируя при этом маленькие


10

Я запускаю следующую команду:

mogrify -resize '400x400>' *.png

Обратите внимание на «>». Предположительно, он будет игнорировать файлы меньшего размера, но, хотя и не изменяет их размер, он их редактирует (дата изменения и размер файла изменяются).

Есть ли способ сделать это на самом деле просто оставить меньшие файлы в покое? Я хотел бы избежать нескольких тысяч ненужных операций записи.

Ответы:


15

Я думаю, что mogrifyсистематически переписывает файл, поэтому ваша единственная надежда состоит в том, чтобы сначала отфильтровать список, как предлагает Джиппи . Вот как вы можете это сделать (не проверено): распечатайте список файлов изображений с указанием размера, сохраните только имена, размер которых связан с диапазоном, и обработайте этот список.

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

Сценарий объяснения:

  • Для каждого файла выведите строку с шириной, пробелом, высотой, пробелом и именем файла. В зависимости от версии identify, то \nдобавить окончательный символ новой строки может быть необходимо (ImageMagick 6.6.0) или лишняя , но безвредный (GraphicsMagick 1.1.11).
  • ( awk) В каждой строке, если width ( $1) и height ( $2) соответствуют требуемым условиям, тогда:
    • Удалить весь текст до второго пробела. Это полоски ширины и высоты.
    • Выведите то, что осталось от строки, которая является именем файла.
  • Заменить символы новой строки на нулевые символы.
  • Звоните, xargs -0чтобы выполнить mogrifyкоманду с именами файлов. (Мы не можем использовать простой, xargsпотому что он не может работать с вводом, содержащим пробел или \'".)

Имена файлов могут содержать любые символы, кроме символов новой строки.


Вы можете объяснить этот сценарий? В частности, «суб» часть. Это печать имен файлов без пробела или вставка новой строки. mogrify: невозможно открыть файл `22 553.png308 400 0134 2.png '@ error / png.c / ReadPNGImage / 2951. Я понятия не имею, откуда взялись эти «308 400». Я должен упомянуть, что у файлов есть пробелы в их именах. Спасибо.
Майк

Я получаю mogrify: не могу открыть файл `340 271 22 553.png308 400 0134 2.png '@ error / png.c / ReadPNGImage / 2951. Я выполнил команду, используя 200x200 на двух файлах с примерами. Я вижу, что 308x400 - это размер одного из файлов
Майк

2
@ Майк Ах, понял. Некоторые версии identifyавтоматически ставят новую строку после каждой записи, другие должны иметь ее явно. Добавьте \nв конце аргумента -format(см. Мое редактирование).
Жиль "ТАК - перестань быть злым"

8

Я столкнулся с той же проблемой, что вы описали. Вот мое решение:

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

Я протестировал его на нескольких изображениях JPEG на виртуальной машине CentOS 6.5. Сценарий только изменял размеры и сжимал изображения, ширина или высота которых превышала 640 пикселей. Это позволяло работать с изображениями с размерами, такими как 800 x 600 (альбомная, изменение размера до 640 x 480) и размерами, такими как 600 x 800 (портретная, изменение размера до 480 x 640).

PS: примечание к 400x400параметру: mogrifyобработает файл, даже если его размеры равны или меньше, чем 400x400, но изменит размер, только если его размеры больше, чем 400x400. Вот почему время и размер файла изменяются (в моем случае mogrifyэти файлы стали еще больше, чем были).


5

Вы также можете использовать fxоператор для фильтрации изображений на основе высоты / ширины, например

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

выведет, 1если изображение больше чем 400x400и 0если оно равно или меньше чем 400x400...


Предполагая, что вменяемые имена файлов (без новых строк / пробелов / табуляции и т. Д.) Можно использовать identifyдля печати имен изображений, которым предшествует либо 1:либо 0:, либо , обрабатывать вывод, удаляя строки, начинающиеся с, 0:и удаляя ведущие 1:в остальных строках, чтобы остались только имена файлов, один в строке, затем направьте этот список в mogrify ... @-( @синтаксис был добавлен в imagemagick v6.5.2):

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

В противном случае findвы можете распечатать только файлы размером> 400x400 и затем передать результат в xargs+ mogrify(это менее эффективно, так как запускает оболочку для каждого файла, но должно работать со всеми видами имен файлов):

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'

Если вы zshпользователь, посмотрите также этот ответ .


3

Как насчет использования идентификатора, чтобы найти размер вашего изображения и решить из небольшого сценария, хотите ли вы редактировать его или нет:

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

Не должно быть слишком сложно отредактировать выходной формат для использования в простом скрипте.


Учитывая мои ограниченные навыки и тот факт, что размеры изображений нерегулярны, мне нужен более простой метод. Я предпочел бы обработать их все с могуществом.
Майк

0

Я использую такой PHP-скрипт, он использует 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);
?>

Он масштабирует все изображения в текущем каталоге больше 3000 по некоторому краю.

Запустить команду: php scale.phpИЛИphp scale.php 2000


0

Вот мое мнение, включающее идеи @ArionKrause и @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

(Мне это нужно, потому что мой любимый пакетный процессор Phatch не работает с Ubuntu 16.04.)


0

Мои функции для изменения размера и оптимизации

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"
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.