Добрый вечер, хабровчане!
Начну с того, что работаю я в непростой школе простым лаборантом. На мне висит много всяких обязанностей, одной из которых является пополнение школьного сайта и ресурса oshkole.ru контентом.
Часто приходится выкладывать на этот ресурс фотографии. Но так как написан он о-очень криво (к слову, ведение там странички школы обязательно и контролируется прокуратурой), фотографии конечному пользователю подгружаются в полном размере. Вот и приходится ресайзить по ~30 штук в неделю.
Так как я любительница unix-way, быстро пришла идея написать bash скрипт.
Была поставлена цель: легко и непринужденно изменять размер всех изображений в директории. Задача достаточно тривиальная, скриптик был набросан за 5 минут, и… Тут меня осенило: я ведь так давно хотела написать статью на хабр, только было неочем. И вот я здесь =)
Всем, кому еще не стало скучно, добро пожаловать под кат.
Итак, приступим.
Само изменение размера будем осуществлять утилитой convert из набора ImageMagick. Сразу оговорюсь, что эта утилитка очень мощная (а сам ImageMagick и того мощнее) и с ее помощью можно делать очень
много всего.
> convert image_in.jpg -resize 1228800@ image_out.jpg
Здесь я использую опцию -resize 1228800@. Она означает, что изображение будет иметь площадь в 1228800 пикселей (соответствует разрешению 1280х960). Разумнее использовать здесь именно эту опцию потому, что фотографии могут быть как вертикальной ориентации, так и горизонтальной. Подробнее о возможностях изменения размера изображений можно посмотреть
здесь.
На этом этапе возникла мысль делать это не только для себя =).
Так, для начала нужно проверить, есть ли на машине convert. Сделаем это так:
convert > /dev/null
if [ $? -ne 0 ]; then echo "Error: convert is needed, it's a part of ImageMagick"; fi;
Поясню запись «if [ $? -ne 0 ]»:
Скобка "[" соответствует команде test, и про нее можно почитать в man test (1). В $? хранится результат выполнения предыдущей команды. Например, если выполнение было успешно, там будет 0, а если команда не была найдена — 127. Закрывающая скобка "]" выполняет лишь эстетическую функцию.
Далее. Существует небольшая проблемка — бывает, пользователь указывает в конце адреса "/", например: /home/user/. Как этот слэш убрать человеческим методом, я не нашла, поэтому придумала детский трехколесный:
if [ -z $1 ]; then $DIR=`pwd`;
else
TEMP=`pwd`;
cd $DIR; TEMP2=`pwd`;
cd $TEMP;
DIR=$TEMP2;
echo $TEMP2;
fi;
Заодно здесь решаем использовать текущую директорию, если аргумент не дан.
Копируем старые файлы...:
mkdir "$DIR.old";
for i in `ls $DIR`;
do
cp $DIR/$i $DIR.old;
done
Для тех, кто не очень понимает «for i in...» советую посмотреть
тут.
Ну и самое главное:
for i in `ls $DIR`;
do
convert $DIR/$i -resize 1228800@ $DIR/$i;
if [ $? -eq 0 ]; then
echo "$i successfully resized";
else k=$[$k+1]; #считаем ошибки
fi;
done
Думаю, на этом этапе все должно быть понятно.
Итак, долгожданный момент: собираем все вместе. Файл можно скачать
здесь.
#!/bin/sh
#проверяем, установлен ли convert
convert > /dev/null
if [ $? -ne 0 ] ; then
echo "Error: convert is needed, it's a part of ImageMagick" ;
fi;
DIR=$1;
# велосипед, убирающий "/" в конце
if [ -z $1 ]; then $DIR=`pwd`;
else
TEMP=`pwd`;
cd $DIR; TEMP2=`pwd`;
cd $TEMP;
DIR=$TEMP2;
echo $TEMP2;
fi;
#наши старые файлы копируем в DIR.old
mkdir "$DIR.old";
for i in `ls $DIR`;
do
cp $DIR/$i $DIR.old;
done;
ERR=0;
echo "Start resizing to 1280x960...."
for i in `ls $DIR`;
do
convert $DIR/$i -resize 1228800@ $DIR/$i;
if [ $? -eq 0 ]; then
echo "$i successfully resized";
else ERR=$[$ERR+1]; #считаем ошибки
fi;
done;
if [ $ERR -eq 0 ]; then
echo "Job done!";
else echo "Job done with some errors.";
fi;
echo "You can find your old files in $DIR.old"
#end
Как запустить скрипт
Допустим, скрипт с именем «image» лежит у вас в папке /data/scripts, а фотографии, подлежащие обработке — в /data/foto.
Тогда выполняем команду
> /data/scripts/image /data/foto
И, ура!
Только не забываем дать скрипту права на исполнение:
> chmod +x /data/scripts/image
Выводы
Все, как видим, очень легко и просто. В unix-way нет ничего плохого. Да что там, есть много чего хорошего! Я пользуюсь этим скриптом (теперь) каждый день, плюс еще несколькими скриптами для работы с сетью. И дам вам добрый женский совет: автоматизируйте! =)
Пишу на хабр впервые, сильно не бейте
комментарии (165)
Nuff said.
но, учитывая то, что я активно пользуюсь консолью, мой вариант быстрее :)
convert > /dev/null
if [ $? -ne 0 ]; then echo «Error: convert is needed, it's a part of ImageMagick»; fi;
зачем здесь convert > /dev/null и ;fi;? я в скриптах ноль но знаю С++ поэтому синтксис еще не очень
Операция ">" означает перенаправление потока вывода. То есть результат выполнения (например, сообщение о том, что команда не найдена) будет не выведено на экран, а направлено на специализированное устройство /dev/null, о котором, я думаю, пояснять не нужно :)
Опция -ne у команды test означает «not equal».
fi; означает завершение условного оператора. В баш-скриптах нет способа выделения блоков команд (если ошибаюсь, поправьте), кроме как do-done; и if-else-fi.
./scri: line 6: convert: command not found
./scri: line 7: [127: command not found
./scri: line 14: syntax error near unexpected token `then'
./scri: line 14: `if[-z $1]; then $DIR='pwd';'
он как раз проверяет чере трюк с > /dev/null наличие этого самого имеджмаджика.
convert 2>&1 > /dev/null действительно не выведет ничего на экран. В Вашем случае выведет всё равно, так как в девнулл отправили только stdout, забыв про stderr.
Если же convert не установлен, то опять же на stderr про это напишет баш. Можно например вот так:
BIN=`which convert`
if [ -x "$BIN" ]; then echo «convert is here: $BIN»; fi
DIR=`echo $1 |sed -e 's,\(.\)/$,\1,'`
пока у меня убунту не стала рабочей системой тоже не понимал этого всего, но сейчас замечаю, что некоторые вещи намного сделать быстрее в консоли, чем в использовать гуи, чего под виндой не хватает.
нужно решить задачу — решаете. параллельно с этим обретаете определенный опыт и навыки.
первое время…
зато девушка получила АВТОМАТИЗИРОВАННЫЙ способ ресайза, потратив 1 раз пусть хоть 3 часа.
а вы предлагаете каждый раз открывать acdsee, переходить в папку, выделять, делать ресайз и тд.
в итоге со временем кто еще выиграет — большой вопрос.
… к тому же скрипты можно объединять, получая то же самое константное время выполнения процесса, а нажатия мышки нет.
Ваш же путь — снова и снова изо дня в день повторять бессмысленное машевозилово. Это, безусловно, очень сильно экономит время, ага! Скилы от этого — только кистевой туннельный синдром… :(
Одни раз — хорошо сделать гуем. Каждый день — извините, гуем в этом случае будет пользоваться только идиот или мазохист.
Возможно. Но изучение и написание скрипта — это делается один раз, а «сделать а-ля виндоус-уэй традиционным гуишным способом» — это делается каждый раз.
Почувствуйте разницу.
echo '/bugaga/aaa/SLASH/' | sed -e 's/\/$//'
Выведет: "/bugaga/aaa/SLASH". =)))
Было дело, когда писала конфиг для conky, нужно было выводить ip адрес интерфейса. Пока заметила, что у меня нифига не работает из-за какой-то лишней скобочки, успела написать вырезающий из ifconfig'а скрипт :)
А после ресайза бывает полезно немного увеличить четкость, тогда снимки выглядят намного приятней (-sharpen, кажется)
"(а сам ImageMaick и того мощнее)", забыли «g» в слове Magick:)
Вместо for i можно использовать xargs.
у меня вся публикация занимала одну строчку
ls -1 *.JPG | xargs -I '{}' convert -despeckle -noise 3 -resize 25% -equalize -normalize -font helvetica -draw «text 10,10 KARTz.ru» -box white -blur 1 '{}' '/mnt/server/photo/p_{}'
если задумаете использовать — замените ковычки
Скажите уж тогда, что непривычно…
здесь же все для наглядности сделано.
which -s convert || { echo "convert is not installed"; exit; }Полный linux-way, если бы после создания миниатюр все бы фотки закачивались по ftp на сервак. Ну и дальше можно много всего вкусного придумать :)
простите отвлекся. интересное решение, но к сожалению я любитель windows-way решений, поэтому оценить не могу.
недавно стояла задача заресайзить знакомому большую тучу картинок под небольшое разрешение нашлось гуевое решение, ctrl+A и в контекстном меню нужное разрешение(под win естественно)
вообще-то, это тривиально, но женский род от первого лица все меняет — _для девушки_ — весьма похвальные достижения в bash-е!
про for… — да, люблю я его )
так сразу всплывают детские воспоминания — basic и все такое…
хоть это и правда… но не очень приятно, если честно.
странная у нас тут эмансипация цветёт.
PS: может я, конечно, зря так выделил _для девушки_ (на деле тональность комментария была скорее одобрительной) — извините, я не имел в виду что все бабы дуры, скорее что их склонность к доминированию эмоционального интеллекта, редко дает им возможность достичь результатов в математике, и тем приятнее нам видеть эти результаты.
как это? я написала, что мне это неприятно: habrahabr.ru/blogs/linux/82394/#comment_2445329
Намекаете, что любой _девушке_ нужна куча времени для освоения тривиальных вещей? Думаю, за это неплохо было бы и извиниться, тов. Siddthartha.
а толковать и перетолковывать мои слова — не надо.
Извините за нескромный вопрос, а вы женаты? =)
Про велосипед со слешем: либо через sed, как было выше, либо вообще не заморачиваться. Сравните результат:
ls -l /var//tmp
ls -l /var/tmp
> for i in `ls $DIR`;
> do
> cp $DIR/$i $DIR.old;
> done
Лучше так:
cp "$DIR/*" "$DIR.old/"
Кавычки на случай, если в имени встретится, например, пробел.
> for i in `ls $DIR`;
> do
> convert $DIR/$i -resize 1228800@ $DIR/$i;
> if [ $? -eq 0 ]; then
> echo "$i successfully resized";
> else ERR=$[$ERR+1]; #считаем ошибки
> fi;
> done;
лучше так
for i in $DIR/*;
do
convert "$i" -resize 1228800@ "$i";
if [ $? -eq 0 ]; then
echo "$i successfully resized";
else ERR=$[$ERR+1]; #считаем ошибки
fi;
done;
а во всем остальном, конечно, согласна, просто писалось это «на скорую руку».
Выходи за меня!
Photo 1
Photo 1
Photo 2
bit.ly/4GhHSM
При красоте такой и петь ты мастерица,-
Ведь ты б у нас была царь-птица!»
ЗЫ Извините — не удержался ;)))
И далее в наутилусе выбираем все фотографии которые хотим изменить, в меню выбираем масштабирование:
Так что любое количество фотографий можно изменить все в пару кликов.
linux != ubuntu.
Для меня вот, самый популярный дистрибутив — arch.
2) «Так как ничего сказано не было считаем что» — ? Это только Вы считаете.
3) «один из самых популярных дистров — убунта» :D (извините)
4) «не хочется парится со скриптами». Простите, если я написала эту статью, то эта фраза априори не обо мне. Особенно если бы Вы ее дочитали.
2. если это серверный вариант, тогда можно было еще больше автоматизировать, резайзить и сразу лить на сервак в нужную папку.
3. что есть, то есть
4. ни кто не говорит, что что то не так со скриптом. Речь лишь о том что его или аналогичный можно использовать так же из гуи, что дает большую гибкость в работе.
Почему решили что все должны работать из консоли? Гуй такой же инструмент для работы как и консоль. Если он не нравится вам не значит что он не нравится остальным.
Гуй неудобен и большую гибкость в работе не даёт, т.к. гуй — это *только* уй (UI), т.е. пользовательский интерфейс. Консоль с текстовыми потоками — это и пользовательский интерфейс и интерфейс для огромного количества утилит по обработке данных. О какой гибкости может идти речь?
Почему должен быть только один способ?
1. открыть консоль
2. перейти в папку с картинками
3. запустить его
;)
Ну вот ты перешел в дирикторию с картинками, понял что надо изменить размер. Просто выделил нужные и по клику правой кнопки выбрал из меню масштабирование.
Ну скажем если 3-5тыщ, то
1. можно тот же скрипт пустить из консоли
2. отключить предпросмотр
Опять же для того и написал этот метод, что иногда бывает проще из консоли, иногда проще кликнуть правой кнопкой.
Так же можно не заходит в эту директорию, а прям кликнуть по ней и скормить ее скрипту через правый клик.
Проблема в том, что, вот, у вас, например, всегда запущен наутилус, а у меня urxvt с zsh.
В bash есть reverse-i-search на Ctrl+R. Очень удобно если скрипт далеко, чтобы на нажимать стрелку вверх 20 раз.
То есть если ты сидишь в консольке, то хватать мышку что бы ресайзнуть одну картинку будет ленно.
Так же как если ты работаешь с картинками в гимпе/инкскейпе, то что бы конвернуть одну картинку надо выполнить кучу действий, то согласись что по правой кнопке будет горазддо быстрее.
Кстати если у вас гном, то описанный в шапке скрипт можно кинуть в наутилус скриптс, и так же выполнять его по правой кнопке на любом количестве картинок.
тема треда «Скрипт для....», так что, оставьте нас со своими гуями.
Никто не заставляет вас пользоваться консолью…
И да простят меня Боги, но от оффтопа создалось ощущение, что кто-то где-то ВНЕЗАПНО крикнул «Девушка на хабре!» и, сметая все на своем пути, в тему ломанулись сотни человек, которые девушку видели только на фотографии.
с xnview.com
Плюсы по сравнению с ImageMagick:
маленькая, но такая же мощная,
всё своё носит с собой, от библиотечного окружения почти не зависит
работает с огромным количеством форматов
Ан нет, настоящий freeware windows-way — это прога Easy Graphic Converter, инсталятор весит 813kb, и умеет она ровно две вещи — конвертацию популярнейших форматов без особых настроек и ресайз, как отдельных файлов, так и папок. Единственный минус — ресайз там не очень умный, придётся отдельно ресайзить горизонтальные и вертикальные фото.
В общем, на статью на хабре не тянет, в отличие от unix-way, но кому-то может быть полезно.
Впрочем, можно считать, что это unix-way, портированный под Windows :)
#!/bin/sh function die { echo $1 exit } #проверяем, установлен ли convert which convert >& /dev/null || die "Error: convert is needed, it's a part of ImageMagick" DIR=$1 #наши старые файлы копируем в DIR.old mkdir "$DIR.old" cp $DIR/* $DIR.old/ echo "Start resizing to 1280x960...." mogrify -resize 1280x960 $DIR/* || die "Job done with some errors." echo "Job done!"; echo "You can find your old files in $DIR.old">& работает в csh и bash.
* не забывай про случайный слеш в конце
* фотка может быть и вертикальная
*…
только я еще с помощью утилиты exiftool выяняю «Оринтацию снимка» — и если надо «convert -rotate ...»
А слеш легко убирается командой realpath. Она ещё и проверит существует ли путь:
$ realpath /home/ ; echo $?/home
0
$ realpath /home ; echo $?
/home
0
$ realpath /404 ; echo $?
/404: No such file or directory
1
which convert >/dev/null || { echo 'Error: ImageMagick is not installed!' >&2 ; exit 10 ; }Так и короче, и правильнее :)
Ошибки, конечно же, нужно выводить в stderr
конечно нужно, но этот скрипт «домашний», так сказать =)
current_dir=old_path new_dir=new_path && for i in $current_dir; do convert --all-your-options $i $new_dir; done
Так быстрее выйдет, и модифицировать опции легче, сразу при наборе. А наличие конверт пользователю наполняющему сайты контентом и так известно. :)
[...]do convert --all-your-options $i $new_dir/$i [...]велосипед, действительно. есть команда dirname для этого :)
PS ещё можно изучить её противоположность — basename.
настолько любить windows — паранойя.