Переименовываем изображение с указанием разрешения

28-03-2016 @ 17:24


Немногие знают, хотя я это уже неоднократно упоминал, что я собираю коллекцию обоев на рабочий стол с помощью сервиса Desktoppr. Это такой сайт, который синхронизируется с Dropbox и позволяет из определенной папки расшаривать на всех пользователей данного сервиса коллекцию обоев. Если обоина понравилась – ее можно синхронизировать в один клик со своим Dropbox’ом ну или просто поставить лайк.
Сервису уже пара лет точно и за это время я поднабрал больше 2000 разнообразных обоинок из разных источников. Однако, сохранение картинок в Dropbox каждый раз происходило по принципу: смотрим какой порядковый номер в исходной папке с картинками, копируем разрешение картинки, сохраняем файл указывая порядковый номер и разрешение. Хорошо, если разрешение без пробелов, в противном случае приходилось делать дополнительную корректировку имени сохраняемого файла. В итоге мне поднадоела данная процедура и далее я раскажу как автоматизировал данный процесс до минимума действий с моей стороны. Лень и правда двигатель прогресса :)

Сразу скажу, что я знаю по поводу IrfanView и его возможностей, которые отвечают моим требованиям. Но с Irfan’ом приходилось бы каждый раз указывать где брать изображения, какие из них добавлять, указывать маску переименовывания и т.п. Попробовал, работало, но меня не устраивало в силу множества действий. Хотелось их еще больше минимизировать. А где? А как? В командной строке!
Учитывая, что я задумал автоматизировать процесс переименования файлов с помощью CMD/Batch, мне было нужно найти консольный редактор, способный читать информацию об изображениях. Сначала я пробовал Mediainfo в исполнении CLI, но мы с ним не договорились. Далее я находил еще пару небольших программулинок, одна из них была частной разработки, но и они тоже не смогли выдать необходимое мне. Частная так вовсе выдавала всё что угодно, но только не разрешение.
В итоге, я остановился на консольной identify, входящей в пакет ImageMagick. Под Windows она вполне прекрасно завертелась.
Идем дальше, пишем “говнокод”.

Первое что мне было нужно – вручную указывать порядковый номер изображения. Это вполне быстро решилось на уровне школьной программы – объявлением запрашиваемой переменной, скажем, num:
set /p num="Start from: "
Допустим, что изображений больше двух. Тогда переменная должна изменять свое значение на +1.
Напишем простенький цикл:

set /p num="Start from: "
	for	/L %%a in (1,1,10) do (
		set /a num=num+1
		echo %num%
		)

Кратко, для понимания, в цикле, в скобках, мы указываем (начало, шаг, конец). Результатом выполнения будет:

Переменная осталась без изменений. Почему? Потому что мы не объявили дополнительные параметры:
SetLocal – Локализация переменных
SetLocal EnableExtensions – Использование дополнительных ключей
SetLocal EnableDelayedExpansion – Раскрытие переменных через знаки (!)
Изменим код на этот:

setlocal enableextensions enabledelayedexpansion
set /p num="Start from: "
	for	/L %%a in (1,1,10) do (
		set /a num=num+1
		echo !num!
		)

Результат выполнения:

То что надо!
В обычном случае, чтобы узнать значение переменной окружения, надо воспользоваться конструкцией %переменная%. Однако, если значение переменной меняется внутри цикла и читается там же, то для корректной работы нужно использовать команду setlocal enabledelayedexpansion и вместо символа “%”, использовать символ “!”. Иначе, значение переменной в цикле будет всегда одним и тем же – таким, каким было до входа в цикл.
Идем дальше. Приступим к использованию identify

Не стану утомлять рассказом о переборе команд, которые я проделал, чтобы вывести нужную мне операцию вызова, покажу что получилось:
identify -ping – format “%w %h” %imagename%.jpg
Данная команда выведет только ширину и высоту картинки %imagename%.jpg через пробел. Собственно, большего и не нужно:

Вернемся к варианту того что картинок может быть несколько и нужно использовать цикл. Передадим данные о картинках в переменные, используя токены:

for /f "tokens=1,2" %%i in ('identify -ping -format "%%w %%h" "%%A"')

Параметр tokens командной стоки цикла for позволяет указать, какие номера полей строки, полученных из заданного текста, нужно передать для обработки в цикл. Полученные поля будут храниться в отдельной переменной. Фактически, если принимать каждое слово строки как отдельный элемент, то параметр tokens позволяет указать, какие именно слова по счету нужно обработать. Стандартным разделителем является пробел и табуляция.

Итак, по сути: получается два цикла. Если точнее – цикл в цикле. В первом мы увеличиваем переменную порядкового номера изображения, во втором – считываем данные с изображения и переименовываем картинку.
Вот как будет в итоге выглядеть код. Приведу с комментариями, чтобы было понятнее:

setlocal enableextensions enabledelayedexpansion
set /p num="Start from: " rem Задаем порядковый номер изображения
for %%A in ("*.jpg") do ( rem Для всех jpg в исходной папке...
	for /f "tokens=1,2" %%i in ('identify -ping -format "%%w %%h" "%%A"') do ( rem ...забираем ширину и высоту
		ren "%%A" "!num!-%%ix%%j.jpg" rem и переименовываем начальный файл в нужный формат
		set /a num=num+1 rem после увеличиваем порядковый номер на 1 и повторяем
		)
	)

Таким образом, при вызове данного батника, всего лишь указав начальное значение нумерации можно за две-три секунды получить нужное.

Конечно, код не лишен недостатков. Например в обработке участвуют только файлы формата JPG, а бывают обои и в PNG. А также, нет возможности использовать нумерацию, начинающуюся с 00 или нет обработки входящих данных в части ввода начального значения. Да много всего… Пока я так не решил эти вопросы, ибо кодер из меня так-себе, да и написанное не блещет красотой, но зато работает как я задумывал, что для меня важно.
Если Вы знаете как можно улучшить – буду рад перенять опыт :)