Використовуйте mogrify, щоб змінити розмір великих файлів, ігноруючи невеликі


10

Я виконую наступну команду:

mogrify -resize '400x400>' *.png

Зауважте ">". Імовірно, він буде ігнорувати менші файли, але, хоча він не змінює їх розмір, він редагує їх (дата модифікації та розмір файлу змінені).

Чи є спосіб зробити це фактично просто залишити менші файли в спокої? Я хотів би уникнути кількох тисяч непотрібних операцій з написанням.

Відповіді:


15

Я думаю, що mogrifyсистематично переписує файл, тому ваша єдина надія - спочатку відфільтрувати список, як це запропонував jippie . Ось як це можна зробити (неперевірено): роздрукуйте список файлів зображень із зазначенням розміру, збережіть лише імена, асоційований розмір яких знаходиться в межах діапазону, і обробіть цей список.

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) У кожному рядку, якщо ширина ( $1) та висота ( $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
@Mike Ах, зрозумів. Деякі версії 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.